зеркало из https://github.com/microsoft/git.git
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:
Коммит
ee969693c5
|
@ -11,6 +11,7 @@ git-apply
|
||||||
git-archimport
|
git-archimport
|
||||||
git-archive
|
git-archive
|
||||||
git-bisect
|
git-bisect
|
||||||
|
git-bisect--helper
|
||||||
git-blame
|
git-blame
|
||||||
git-branch
|
git-branch
|
||||||
git-bundle
|
git-bundle
|
||||||
|
@ -35,6 +36,8 @@ git-diff
|
||||||
git-diff-files
|
git-diff-files
|
||||||
git-diff-index
|
git-diff-index
|
||||||
git-diff-tree
|
git-diff-tree
|
||||||
|
git-difftool
|
||||||
|
git-difftool--helper
|
||||||
git-describe
|
git-describe
|
||||||
git-fast-export
|
git-fast-export
|
||||||
git-fast-import
|
git-fast-import
|
||||||
|
@ -78,6 +81,7 @@ git-merge-recursive
|
||||||
git-merge-resolve
|
git-merge-resolve
|
||||||
git-merge-subtree
|
git-merge-subtree
|
||||||
git-mergetool
|
git-mergetool
|
||||||
|
git-mergetool--lib
|
||||||
git-mktag
|
git-mktag
|
||||||
git-mktree
|
git-mktree
|
||||||
git-name-rev
|
git-name-rev
|
||||||
|
|
|
@ -129,3 +129,6 @@ For C programs:
|
||||||
used in the git core command set (unless your command is clearly
|
used in the git core command set (unless your command is clearly
|
||||||
separate from it, such as an importer to convert random-scm-X
|
separate from it, such as an importer to convert random-scm-X
|
||||||
repositories to git).
|
repositories to git).
|
||||||
|
|
||||||
|
- When we pass <string, length> pair to functions, we should try to
|
||||||
|
pass them in that order.
|
||||||
|
|
|
@ -41,7 +41,8 @@ man7dir=$(mandir)/man7
|
||||||
|
|
||||||
ASCIIDOC=asciidoc
|
ASCIIDOC=asciidoc
|
||||||
ASCIIDOC_EXTRA =
|
ASCIIDOC_EXTRA =
|
||||||
MANPAGE_XSL = callouts.xsl
|
MANPAGE_XSL = manpage-normal.xsl
|
||||||
|
XMLTO_EXTRA =
|
||||||
INSTALL?=install
|
INSTALL?=install
|
||||||
RM ?= rm -f
|
RM ?= rm -f
|
||||||
DOC_REF = origin/man
|
DOC_REF = origin/man
|
||||||
|
@ -59,13 +60,52 @@ endif
|
||||||
-include ../config.mak.autogen
|
-include ../config.mak.autogen
|
||||||
-include ../config.mak
|
-include ../config.mak
|
||||||
|
|
||||||
|
#
|
||||||
|
# For asciidoc ...
|
||||||
|
# -7.1.2, no extra settings are needed.
|
||||||
|
# 8.0-, set ASCIIDOC8.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# For docbook-xsl ...
|
||||||
|
# -1.68.1, set ASCIIDOC_NO_ROFF? (based on changelog from 1.73.0)
|
||||||
|
# 1.69.0, no extra settings are needed?
|
||||||
|
# 1.69.1-1.71.0, set DOCBOOK_SUPPRESS_SP?
|
||||||
|
# 1.71.1, no extra settings are needed?
|
||||||
|
# 1.72.0, set DOCBOOK_XSL_172.
|
||||||
|
# 1.73.0-, set ASCIIDOC_NO_ROFF
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# If you had been using DOCBOOK_XSL_172 in an attempt to get rid
|
||||||
|
# of 'the ".ft C" problem' in your generated manpages, and you
|
||||||
|
# instead ended up with weird characters around callouts, try
|
||||||
|
# using ASCIIDOC_NO_ROFF instead (it works fine with ASCIIDOC8).
|
||||||
|
#
|
||||||
|
|
||||||
ifdef ASCIIDOC8
|
ifdef ASCIIDOC8
|
||||||
ASCIIDOC_EXTRA += -a asciidoc7compatible
|
ASCIIDOC_EXTRA += -a asciidoc7compatible
|
||||||
endif
|
endif
|
||||||
ifdef DOCBOOK_XSL_172
|
ifdef DOCBOOK_XSL_172
|
||||||
ASCIIDOC_EXTRA += -a docbook-xsl-172
|
ASCIIDOC_EXTRA += -a git-asciidoc-no-roff
|
||||||
MANPAGE_XSL = manpage-1.72.xsl
|
MANPAGE_XSL = manpage-1.72.xsl
|
||||||
|
else
|
||||||
|
ifdef ASCIIDOC_NO_ROFF
|
||||||
|
# docbook-xsl after 1.72 needs the regular XSL, but will not
|
||||||
|
# pass-thru raw roff codes from asciidoc.conf, so turn them off.
|
||||||
|
ASCIIDOC_EXTRA += -a git-asciidoc-no-roff
|
||||||
|
endif
|
||||||
endif
|
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.
|
# Please note that there is a minor bug in asciidoc.
|
||||||
|
@ -76,6 +116,32 @@ endif
|
||||||
# yourself - yes, all 6 characters of it!
|
# yourself - yes, all 6 characters of it!
|
||||||
#
|
#
|
||||||
|
|
||||||
|
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
|
||||||
|
QUIET_SUBDIR1 =
|
||||||
|
|
||||||
|
ifneq ($(findstring $(MAKEFLAGS),w),w)
|
||||||
|
PRINT_DIR = --no-print-directory
|
||||||
|
else # "make -w"
|
||||||
|
NO_SUBDIR = :
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(findstring $(MAKEFLAGS),s),s)
|
||||||
|
ifndef V
|
||||||
|
QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@;
|
||||||
|
QUIET_XMLTO = @echo ' ' XMLTO $@;
|
||||||
|
QUIET_DB2TEXI = @echo ' ' DB2TEXI $@;
|
||||||
|
QUIET_MAKEINFO = @echo ' ' MAKEINFO $@;
|
||||||
|
QUIET_DBLATEX = @echo ' ' DBLATEX $@;
|
||||||
|
QUIET_XSLTPROC = @echo ' ' XSLTPROC $@;
|
||||||
|
QUIET_GEN = @echo ' ' GEN $@;
|
||||||
|
QUIET_STDERR = 2> /dev/null
|
||||||
|
QUIET_SUBDIR0 = +@subdir=
|
||||||
|
QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
|
||||||
|
$(MAKE) $(PRINT_DIR) -C $$subdir
|
||||||
|
export V
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
all: html man
|
all: html man
|
||||||
|
|
||||||
html: $(DOC_HTML)
|
html: $(DOC_HTML)
|
||||||
|
@ -116,10 +182,10 @@ install-pdf: pdf
|
||||||
$(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir)
|
$(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir)
|
||||||
|
|
||||||
install-html: html
|
install-html: html
|
||||||
sh ./install-webdoc.sh $(DESTDIR)$(htmldir)
|
'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
|
||||||
|
|
||||||
../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
||||||
$(MAKE) -C ../ GIT-VERSION-FILE
|
$(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) GIT-VERSION-FILE
|
||||||
|
|
||||||
-include ../GIT-VERSION-FILE
|
-include ../GIT-VERSION-FILE
|
||||||
|
|
||||||
|
@ -127,8 +193,8 @@ install-html: html
|
||||||
# Determine "include::" file references in asciidoc files.
|
# Determine "include::" file references in asciidoc files.
|
||||||
#
|
#
|
||||||
doc.dep : $(wildcard *.txt) build-docdep.perl
|
doc.dep : $(wildcard *.txt) build-docdep.perl
|
||||||
$(RM) $@+ $@
|
$(QUIET_GEN)$(RM) $@+ $@ && \
|
||||||
$(PERL_PATH) ./build-docdep.perl >$@+
|
$(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \
|
||||||
mv $@+ $@
|
mv $@+ $@
|
||||||
|
|
||||||
-include doc.dep
|
-include doc.dep
|
||||||
|
@ -146,102 +212,105 @@ cmds_txt = cmds-ancillaryinterrogators.txt \
|
||||||
$(cmds_txt): cmd-list.made
|
$(cmds_txt): cmd-list.made
|
||||||
|
|
||||||
cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
|
cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
|
||||||
$(RM) $@
|
$(QUIET_GEN)$(RM) $@ && \
|
||||||
$(PERL_PATH) ./cmd-list.perl ../command-list.txt
|
$(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \
|
||||||
date >$@
|
date >$@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7
|
$(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7
|
||||||
$(RM) *.texi *.texi+ git.info gitman.info
|
$(RM) *.texi *.texi+ *.texi++ git.info gitman.info
|
||||||
$(RM) howto-index.txt howto/*.html doc.dep
|
$(RM) howto-index.txt howto/*.html doc.dep
|
||||||
$(RM) technical/api-*.html technical/api-index.txt
|
$(RM) technical/api-*.html technical/api-index.txt
|
||||||
$(RM) $(cmds_txt) *.made
|
$(RM) $(cmds_txt) *.made
|
||||||
|
|
||||||
$(MAN_HTML): %.html : %.txt
|
$(MAN_HTML): %.html : %.txt
|
||||||
$(RM) $@+ $@
|
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
|
||||||
$(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \
|
$(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \
|
||||||
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $<
|
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \
|
||||||
mv $@+ $@
|
mv $@+ $@
|
||||||
|
|
||||||
%.1 %.5 %.7 : %.xml
|
%.1 %.5 %.7 : %.xml
|
||||||
$(RM) $@
|
$(QUIET_XMLTO)$(RM) $@ && \
|
||||||
xmlto -m $(MANPAGE_XSL) man $<
|
xmlto -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
|
||||||
|
|
||||||
%.xml : %.txt
|
%.xml : %.txt
|
||||||
$(RM) $@+ $@
|
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
|
||||||
$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
|
$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
|
||||||
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $<
|
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $< && \
|
||||||
mv $@+ $@
|
mv $@+ $@
|
||||||
|
|
||||||
user-manual.xml: user-manual.txt user-manual.conf
|
user-manual.xml: user-manual.txt user-manual.conf
|
||||||
$(ASCIIDOC) -b docbook -d book $<
|
$(QUIET_ASCIIDOC)$(ASCIIDOC) $(ASCIIDOC_EXTRA) -b docbook -d book $<
|
||||||
|
|
||||||
technical/api-index.txt: technical/api-index-skel.txt \
|
technical/api-index.txt: technical/api-index-skel.txt \
|
||||||
technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS))
|
technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS))
|
||||||
cd technical && sh ./api-index.sh
|
$(QUIET_GEN)cd technical && '$(SHELL_PATH_SQ)' ./api-index.sh
|
||||||
|
|
||||||
$(patsubst %,%.html,$(API_DOCS) technical/api-index): %.html : %.txt
|
$(patsubst %,%.html,$(API_DOCS) technical/api-index): %.html : %.txt
|
||||||
$(ASCIIDOC) -b xhtml11 -f asciidoc.conf \
|
$(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 -f asciidoc.conf \
|
||||||
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) $*.txt
|
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) $*.txt
|
||||||
|
|
||||||
XSLT = docbook.xsl
|
XSLT = docbook.xsl
|
||||||
XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
|
XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
|
||||||
|
|
||||||
user-manual.html: user-manual.xml
|
user-manual.html: user-manual.xml
|
||||||
xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
|
$(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
|
||||||
|
|
||||||
git.info: user-manual.texi
|
git.info: user-manual.texi
|
||||||
$(MAKEINFO) --no-split -o $@ user-manual.texi
|
$(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ user-manual.texi
|
||||||
|
|
||||||
user-manual.texi: user-manual.xml
|
user-manual.texi: user-manual.xml
|
||||||
$(RM) $@+ $@
|
$(QUIET_DB2TEXI)$(RM) $@+ $@ && \
|
||||||
$(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout | \
|
$(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \
|
||||||
$(PERL_PATH) fix-texi.perl >$@+
|
$(PERL_PATH) fix-texi.perl <$@++ >$@+ && \
|
||||||
|
rm $@++ && \
|
||||||
mv $@+ $@
|
mv $@+ $@
|
||||||
|
|
||||||
user-manual.pdf: user-manual.xml
|
user-manual.pdf: user-manual.xml
|
||||||
$(RM) $@+ $@
|
$(QUIET_DBLATEX)$(RM) $@+ $@ && \
|
||||||
$(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $<
|
$(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \
|
||||||
mv $@+ $@
|
mv $@+ $@
|
||||||
|
|
||||||
gitman.texi: $(MAN_XML) cat-texi.perl
|
gitman.texi: $(MAN_XML) cat-texi.perl
|
||||||
$(RM) $@+ $@
|
$(QUIET_DB2TEXI)$(RM) $@+ $@ && \
|
||||||
($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \
|
($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \
|
||||||
--to-stdout $(xml);)) | $(PERL_PATH) cat-texi.perl $@ >$@+
|
--to-stdout $(xml) &&) true) > $@++ && \
|
||||||
|
$(PERL_PATH) cat-texi.perl $@ <$@++ >$@+ && \
|
||||||
|
rm $@++ && \
|
||||||
mv $@+ $@
|
mv $@+ $@
|
||||||
|
|
||||||
gitman.info: gitman.texi
|
gitman.info: gitman.texi
|
||||||
$(MAKEINFO) --no-split --no-validate $*.texi
|
$(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi
|
||||||
|
|
||||||
$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
|
$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
|
||||||
$(RM) $@+ $@
|
$(QUIET_DB2TEXI)$(RM) $@+ $@ && \
|
||||||
$(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@+
|
$(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@+ && \
|
||||||
mv $@+ $@
|
mv $@+ $@
|
||||||
|
|
||||||
howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
|
howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
|
||||||
$(RM) $@+ $@
|
$(QUIET_GEN)$(RM) $@+ $@ && \
|
||||||
sh ./howto-index.sh $(wildcard howto/*.txt) >$@+
|
'$(SHELL_PATH_SQ)' ./howto-index.sh $(wildcard howto/*.txt) >$@+ && \
|
||||||
mv $@+ $@
|
mv $@+ $@
|
||||||
|
|
||||||
$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
|
$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
|
||||||
$(ASCIIDOC) -b xhtml11 $*.txt
|
$(QUIET_ASCIIDOC)$(ASCIIDOC) $(ASCIIDOC_EXTRA) -b xhtml11 $*.txt
|
||||||
|
|
||||||
WEBDOC_DEST = /pub/software/scm/git/docs
|
WEBDOC_DEST = /pub/software/scm/git/docs
|
||||||
|
|
||||||
$(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
|
$(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
|
||||||
$(RM) $@+ $@
|
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
|
||||||
sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+
|
sed -e '1,/^$$/d' $< | $(ASCIIDOC) $(ASCIIDOC_EXTRA) -b xhtml11 - >$@+ && \
|
||||||
mv $@+ $@
|
mv $@+ $@
|
||||||
|
|
||||||
install-webdoc : html
|
install-webdoc : html
|
||||||
sh ./install-webdoc.sh $(WEBDOC_DEST)
|
'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
|
||||||
|
|
||||||
quick-install: quick-install-man
|
quick-install: quick-install-man
|
||||||
|
|
||||||
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:
|
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
|
.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"
|
- check for unnecessary whitespace with "git diff --check"
|
||||||
before committing
|
before committing
|
||||||
- do not check in commented out code or unneeded files
|
- 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
|
- the first line of the commit message should be a short
|
||||||
description and should skip the full stop
|
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
|
- if you want your work included in git.git, add a
|
||||||
"Signed-off-by: Your Name <you@example.com>" line to the
|
"Signed-off-by: Your Name <you@example.com>" line to the
|
||||||
commit message (or just use the option "-s" when
|
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
|
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.
|
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
|
Oh, another thing. I am picky about whitespaces. Make sure your
|
||||||
changes do not trigger errors with the sample pre-commit hook shipped
|
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
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
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
|
Submitting properly formatted patches via Gmail is simple now that
|
||||||
IMAP support is available. First, edit your ~/.gitconfig to specify your
|
IMAP support is available. First, edit your ~/.gitconfig to specify your
|
||||||
account settings:
|
account settings:
|
||||||
|
@ -503,6 +521,9 @@ account settings:
|
||||||
port = 993
|
port = 993
|
||||||
sslverify = false
|
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
|
Next, ensure that your Gmail settings are correct. In "Settings" the
|
||||||
"Use Unicode (UTF-8) encoding for outgoing messages" should be checked.
|
"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
|
Go to your Gmail account, open the Drafts folder, find the patch email, fill
|
||||||
in the To: and CC: fields and send away!
|
in the To: and CC: fields and send away!
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ ifdef::backend-docbook[]
|
||||||
endif::backend-docbook[]
|
endif::backend-docbook[]
|
||||||
|
|
||||||
ifdef::backend-docbook[]
|
ifdef::backend-docbook[]
|
||||||
ifndef::docbook-xsl-172[]
|
ifndef::git-asciidoc-no-roff[]
|
||||||
# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
|
# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
|
||||||
# v1.72 breaks with this because it replaces dots not in roff requests.
|
# v1.72 breaks with this because it replaces dots not in roff requests.
|
||||||
[listingblock]
|
[listingblock]
|
||||||
|
@ -42,16 +42,16 @@ ifdef::doctype-manpage[]
|
||||||
endif::doctype-manpage[]
|
endif::doctype-manpage[]
|
||||||
</literallayout>
|
</literallayout>
|
||||||
{title#}</example>
|
{title#}</example>
|
||||||
endif::docbook-xsl-172[]
|
endif::git-asciidoc-no-roff[]
|
||||||
|
|
||||||
ifdef::docbook-xsl-172[]
|
ifdef::git-asciidoc-no-roff[]
|
||||||
ifdef::doctype-manpage[]
|
ifdef::doctype-manpage[]
|
||||||
# The following two small workarounds insert a simple paragraph after screen
|
# The following two small workarounds insert a simple paragraph after screen
|
||||||
[listingblock]
|
[listingblock]
|
||||||
<example><title>{title}</title>
|
<example><title>{title}</title>
|
||||||
<screen>
|
<literallayout>
|
||||||
|
|
|
|
||||||
</screen><simpara></simpara>
|
</literallayout><simpara></simpara>
|
||||||
{title#}</example>
|
{title#}</example>
|
||||||
|
|
||||||
[verseblock]
|
[verseblock]
|
||||||
|
@ -59,10 +59,11 @@ ifdef::doctype-manpage[]
|
||||||
{title%}<literallayout{id? id="{id}"}>
|
{title%}<literallayout{id? id="{id}"}>
|
||||||
{title#}<literallayout>
|
{title#}<literallayout>
|
||||||
|
|
|
|
||||||
</literallayout><simpara></simpara>
|
</literallayout>
|
||||||
{title#}</para></formalpara>
|
{title#}</para></formalpara>
|
||||||
|
{title%}<simpara></simpara>
|
||||||
endif::doctype-manpage[]
|
endif::doctype-manpage[]
|
||||||
endif::docbook-xsl-172[]
|
endif::git-asciidoc-no-roff[]
|
||||||
endif::backend-docbook[]
|
endif::backend-docbook[]
|
||||||
|
|
||||||
ifdef::doctype-manpage[]
|
ifdef::doctype-manpage[]
|
||||||
|
|
|
@ -70,6 +70,14 @@ of lines before or after the line given by <start>.
|
||||||
tree copy has the contents of the named file (specify
|
tree copy has the contents of the named file (specify
|
||||||
`-` to make the command read from the standard input).
|
`-` 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>|::
|
-M|<num>|::
|
||||||
Detect moving lines in the file as well. When a commit
|
Detect moving lines in the file as well. When a commit
|
||||||
moves a block of lines in a file (e.g. the original file
|
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 </xsl:text>
|
|
||||||
<xsl:apply-templates/>
|
|
||||||
<xsl:text> </xsl:text>
|
|
||||||
</xsl:template>
|
|
||||||
<xsl:template match="callout">
|
|
||||||
<xsl:value-of select="concat('\fB',substring-after(@arearefs,'-'),'. \fR')"/>
|
|
||||||
<xsl:apply-templates/>
|
|
||||||
<xsl:text>.br </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> </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 configuration file contains a number of variables that affect
|
||||||
the git command's behavior. `.git/config` file for each repository
|
the git command's behavior. The `.git/config` file in each repository
|
||||||
is used to store the information for that repository, and
|
is used to store the configuration for that repository, and
|
||||||
`$HOME/.gitconfig` is used to store per user information to give
|
`$HOME/.gitconfig` is used to store a per-user configuration as
|
||||||
fallback values for `.git/config` file. The file `/etc/gitconfig`
|
fallback values for the `.git/config` file. The file `/etc/gitconfig`
|
||||||
can be used to store system-wide defaults.
|
can be used to store a system-wide default configuration.
|
||||||
|
|
||||||
They can be used by both the git plumbing
|
The configuration variables are used by both the git plumbing
|
||||||
and the porcelains. The variables are divided into sections, where
|
and the porcelains. The variables are divided into sections, wherein
|
||||||
in the fully qualified variable name the variable itself is the last
|
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-separated segment and the section name is everything before the last
|
||||||
dot. The variable names are case-insensitive and only alphanumeric
|
dot. The variable names are case-insensitive and only alphanumeric
|
||||||
characters are allowed. Some variables may appear multiple times.
|
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 file consists of sections and variables. A section begins with
|
||||||
the name of the section in square brackets and continues until the next
|
the name of the section in square brackets and continues until the next
|
||||||
section begins. Section names are not case sensitive. Only alphanumeric
|
section begins. Section names are not case sensitive. Only alphanumeric
|
||||||
characters, '`-`' and '`.`' are allowed in section names. Each variable
|
characters, `-` and `.` are allowed in section names. Each variable
|
||||||
must belong to some section, which means that there must be section
|
must belong to some section, which means that there must be a section
|
||||||
header before first setting of a variable.
|
header before the first setting of a variable.
|
||||||
|
|
||||||
Sections can be further divided into subsections. To begin a subsection
|
Sections can be further divided into subsections. To begin a subsection
|
||||||
put its name in double quotes, separated by space from the section name,
|
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"]
|
[section "subsection"]
|
||||||
|
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Subsection names can contain any characters except newline (doublequote
|
Subsection names are case sensitive and can contain any characters except
|
||||||
'`"`' and backslash have to be escaped as '`\"`' and '`\\`',
|
newline (doublequote `"` and backslash have to be escaped as `\"` and `\\`,
|
||||||
respectively) and are case sensitive. Section header cannot span multiple
|
respectively). Section headers cannot span multiple
|
||||||
lines. Variables may belong directly to a section or to a given subsection.
|
lines. Variables may belong directly to a section or to a given subsection.
|
||||||
You can have `[section]` if you have `[section "subsection"]`, but you
|
You can have `[section]` if you have `[section "subsection"]`, but you
|
||||||
don't need to.
|
don't need to.
|
||||||
|
|
||||||
There is also (case insensitive) alternative `[section.subsection]` syntax.
|
There is also a case insensitive alternative `[section.subsection]` syntax.
|
||||||
In this syntax subsection names follow the same restrictions as for section
|
In this syntax, subsection names follow the same restrictions as for section
|
||||||
name.
|
names.
|
||||||
|
|
||||||
All the other lines are recognized as setting variables, in the form
|
All the other lines are recognized as setting variables, in the form
|
||||||
'name = value'. If there is no equal sign on the line, the entire line
|
'name = value'. If there is no equal sign on the line, the entire line
|
||||||
is taken as 'name' and the variable is recognized as boolean "true".
|
is taken as 'name' and the variable is recognized as boolean "true".
|
||||||
The variable names are case-insensitive and only alphanumeric
|
The variable names are case-insensitive and only alphanumeric
|
||||||
characters and '`-`' are allowed. There can be more than one value
|
characters and `-` are allowed. There can be more than one value
|
||||||
for a given variable; we say then that variable is multivalued.
|
for a given variable; we say then that variable is multivalued.
|
||||||
|
|
||||||
Leading and trailing whitespace in a variable value is discarded.
|
Leading and trailing whitespace in a variable value is discarded.
|
||||||
|
@ -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
|
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,
|
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;
|
converting value to the canonical form using '--bool' type specifier;
|
||||||
'git-config' will ensure that the output is "true" or "false".
|
'git-config' will ensure that the output is "true" or "false".
|
||||||
|
|
||||||
String values may be entirely or partially enclosed in double quotes.
|
String values may be entirely or partially enclosed in double quotes.
|
||||||
You need to enclose variable value in double quotes if you want to
|
You need to enclose variable values in double quotes if you want to
|
||||||
preserve leading or trailing whitespace, or if variable value contains
|
preserve leading or trailing whitespace, or if the variable value contains
|
||||||
beginning of comment characters (if it contains '#' or ';').
|
comment characters (i.e. it contains '#' or ';').
|
||||||
Double quote '`"`' and backslash '`\`' characters in variable value must
|
Double quote `"` and backslash `\` characters in variable values must
|
||||||
be escaped: use '`\"`' for '`"`' and '`\\`' for '`\`'.
|
be escaped: use `\"` for `"` and `\\` for `\`.
|
||||||
|
|
||||||
The following escape sequences (beside '`\"`' and '`\\`') are recognized:
|
The following escape sequences (beside `\"` and `\\`) are recognized:
|
||||||
'`\n`' for newline character (NL), '`\t`' for horizontal tabulation (HT, TAB)
|
`\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB)
|
||||||
and '`\b`' for backspace (BS). No other char escape sequence, nor octal
|
and `\b` for backspace (BS). No other char escape sequence, nor octal
|
||||||
char sequences are valid.
|
char sequences are valid.
|
||||||
|
|
||||||
Variable value ending in a '`\`' is continued on the next line in the
|
Variable values ending in a `\` are continued on the next line in the
|
||||||
customary UNIX fashion.
|
customary UNIX fashion.
|
||||||
|
|
||||||
Some variables may require special value format.
|
Some variables may require a special value format.
|
||||||
|
|
||||||
Example
|
Example
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
@ -221,6 +221,11 @@ core.gitProxy::
|
||||||
Can be overridden by the 'GIT_PROXY_COMMAND' environment variable
|
Can be overridden by the 'GIT_PROXY_COMMAND' environment variable
|
||||||
(which always applies universally, without the special "for"
|
(which always applies universally, without the special "for"
|
||||||
handling).
|
handling).
|
||||||
|
+
|
||||||
|
The special string `none` can be used as the proxy command to
|
||||||
|
specify that no proxy be used for a given domain pattern.
|
||||||
|
This is useful for excluding servers inside a firewall from
|
||||||
|
proxy use, while defaulting to a common proxy for external domains.
|
||||||
|
|
||||||
core.ignoreStat::
|
core.ignoreStat::
|
||||||
If true, commands which modify both the working tree and the index
|
If true, commands which modify both the working tree and the index
|
||||||
|
@ -384,9 +389,9 @@ core.pager::
|
||||||
to override git's default settings this way, you need
|
to override git's default settings this way, you need
|
||||||
to be explicit. For example, to disable the S option
|
to be explicit. For example, to disable the S option
|
||||||
in a backward compatible manner, set `core.pager`
|
in a backward compatible manner, set `core.pager`
|
||||||
to "`less -+$LESS -FRX`". This will be passed to the
|
to `less -+$LESS -FRX`. This will be passed to the
|
||||||
shell by git, which will translate the final command to
|
shell by git, which will translate the final command to
|
||||||
"`LESS=FRSX less -+FRSX -FRX`".
|
`LESS=FRSX less -+FRSX -FRX`.
|
||||||
|
|
||||||
core.whitespace::
|
core.whitespace::
|
||||||
A comma separated list of common whitespace problems to
|
A comma separated list of common whitespace problems to
|
||||||
|
@ -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
|
index comparison to the filesystem data in parallel, allowing
|
||||||
overlapping IO's.
|
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.*::
|
alias.*::
|
||||||
Command aliases for the linkgit:git[1] command wrapper - e.g.
|
Command aliases for the linkgit:git[1] command wrapper - e.g.
|
||||||
after defining "alias.last = cat-file commit HEAD", the invocation
|
after defining "alias.last = cat-file commit HEAD", the invocation
|
||||||
|
@ -470,10 +484,14 @@ branch.autosetuprebase::
|
||||||
This option defaults to never.
|
This option defaults to never.
|
||||||
|
|
||||||
branch.<name>.remote::
|
branch.<name>.remote::
|
||||||
When in branch <name>, it tells 'git-fetch' which remote to fetch.
|
When in branch <name>, it tells 'git-fetch' and 'git-push' which
|
||||||
If this option is not given, 'git-fetch' defaults to remote "origin".
|
remote to fetch from/push to. It defaults to `origin` if no remote is
|
||||||
|
configured. `origin` is also used if you are not on any branch.
|
||||||
|
|
||||||
branch.<name>.merge::
|
branch.<name>.merge::
|
||||||
|
Defines, together with branch.<name>.remote, the upstream branch
|
||||||
|
for the given branch. It tells 'git-fetch'/'git-pull' which
|
||||||
|
branch to merge and can also affect 'git-push' (see push.default).
|
||||||
When in branch <name>, it tells 'git-fetch' the default
|
When in branch <name>, it tells 'git-fetch' the default
|
||||||
refspec to be marked for merging in FETCH_HEAD. The value is
|
refspec to be marked for merging in FETCH_HEAD. The value is
|
||||||
handled like the remote part of a refspec, and must match a
|
handled like the remote part of a refspec, and must match a
|
||||||
|
@ -550,6 +568,25 @@ color.diff.<slot>::
|
||||||
whitespace errors). The values of these variables may be specified as
|
whitespace errors). The values of these variables may be specified as
|
||||||
in color.branch.<slot>.
|
in color.branch.<slot>.
|
||||||
|
|
||||||
|
color.grep::
|
||||||
|
When set to `always`, always highlight matches. When `false` (or
|
||||||
|
`never`), never. When set to `true` or `auto`, use color only
|
||||||
|
when the output is written to the terminal. Defaults to `false`.
|
||||||
|
|
||||||
|
color.grep.external::
|
||||||
|
The string value of this variable is passed to an external 'grep'
|
||||||
|
command as a command line option if match highlighting is turned
|
||||||
|
on. If set to an empty string, no option is passed at all,
|
||||||
|
turning off coloring for external 'grep' calls; this is the default.
|
||||||
|
For GNU grep, set it to `--color=always` to highlight matches even
|
||||||
|
when a pager is used.
|
||||||
|
|
||||||
|
color.grep.match::
|
||||||
|
Use customized color for matches. The value of this variable
|
||||||
|
may be specified as in color.branch.<slot>. It is passed using
|
||||||
|
the environment variables 'GREP_COLOR' and 'GREP_COLORS' when
|
||||||
|
calling an external 'grep'.
|
||||||
|
|
||||||
color.interactive::
|
color.interactive::
|
||||||
When set to `always`, always use colors for interactive prompts
|
When set to `always`, always use colors for interactive prompts
|
||||||
and displays (such as those used by "git-add --interactive").
|
and displays (such as those used by "git-add --interactive").
|
||||||
|
@ -567,6 +604,12 @@ color.pager::
|
||||||
A boolean to enable/disable colored output when the pager is in
|
A boolean to enable/disable colored output when the pager is in
|
||||||
use (default is true).
|
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::
|
color.status::
|
||||||
A boolean to enable/disable color in the output of
|
A boolean to enable/disable color in the output of
|
||||||
linkgit:git-status[1]. May be set to `always`,
|
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
|
A boolean to inhibit the standard behavior of printing a space
|
||||||
before each empty output line. Defaults to false.
|
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::
|
diff.wordRegex::
|
||||||
A POSIX Extended Regular Expression used to determine what is a "word"
|
A POSIX Extended Regular Expression used to determine what is a "word"
|
||||||
when performing word-by-word difference calculations. Character
|
when performing word-by-word difference calculations. Character
|
||||||
|
@ -658,6 +722,13 @@ fetch.unpackLimit::
|
||||||
especially on slow filesystems. If not set, the value of
|
especially on slow filesystems. If not set, the value of
|
||||||
`transfer.unpackLimit` is used instead.
|
`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::
|
format.numbered::
|
||||||
A boolean which can enable or disable sequence numbers in patch
|
A boolean which can enable or disable sequence numbers in patch
|
||||||
subjects. It defaults to "auto" which enables it only if there
|
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
|
Additional email headers to include in a patch to be submitted
|
||||||
by mail. See linkgit:git-format-patch[1].
|
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::
|
format.suffix::
|
||||||
The default for format-patch is to output files with the suffix
|
The default for format-patch is to output files with the suffix
|
||||||
`.patch`. Use this variable to change that suffix (make sure to
|
`.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],
|
See linkgit:git-log[1], linkgit:git-show[1],
|
||||||
linkgit:git-whatchanged[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::
|
gc.aggressiveWindow::
|
||||||
The window size parameter used in the delta compression
|
The window size parameter used in the delta compression
|
||||||
algorithm used by 'git-gc --aggressive'. This defaults
|
algorithm used by 'git-gc --aggressive'. This defaults
|
||||||
|
@ -1153,7 +1249,7 @@ pager.<cmd>::
|
||||||
particular git subcommand when writing to a tty. If
|
particular git subcommand when writing to a tty. If
|
||||||
`\--paginate` or `\--no-pager` is specified on the command line,
|
`\--paginate` or `\--no-pager` is specified on the command line,
|
||||||
it takes precedence over this option. To disable pagination for
|
it takes precedence over this option. To disable pagination for
|
||||||
all commands, set `core.pager` or 'GIT_PAGER' to "`cat`".
|
all commands, set `core.pager` or `GIT_PAGER` to `cat`.
|
||||||
|
|
||||||
pull.octopus::
|
pull.octopus::
|
||||||
The default merge strategy to use when pulling multiple branches
|
The default merge strategy to use when pulling multiple branches
|
||||||
|
@ -1162,6 +1258,23 @@ pull.octopus::
|
||||||
pull.twohead::
|
pull.twohead::
|
||||||
The default merge strategy to use when pulling a single branch.
|
The default merge strategy to use when pulling a single branch.
|
||||||
|
|
||||||
|
push.default::
|
||||||
|
Defines the action git push should take if no refspec is given
|
||||||
|
on the command line, no refspec is configured in the remote, and
|
||||||
|
no refspec is implied by any of the options given on the command
|
||||||
|
line. Possible values are:
|
||||||
|
+
|
||||||
|
* `nothing` do not push anything.
|
||||||
|
* `matching` push all matching branches.
|
||||||
|
All branches having the same name in both ends are considered to be
|
||||||
|
matching. This is the default.
|
||||||
|
* `tracking` push the current branch to 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::
|
receive.fsckObjects::
|
||||||
If it is set to true, git-receive-pack will check all received
|
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
|
objects. It will abort in the case of a malformed object or a
|
||||||
|
|
|
@ -16,6 +16,7 @@ body blockquote {
|
||||||
html body {
|
html body {
|
||||||
margin: 1em 5% 1em 5%;
|
margin: 1em 5% 1em 5%;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
|
font-family: sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
body div {
|
body div {
|
||||||
|
@ -128,6 +129,15 @@ body pre {
|
||||||
|
|
||||||
tt.literal, code.literal {
|
tt.literal, code.literal {
|
||||||
color: navy;
|
color: navy;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
code.literal:before { content: "'"; }
|
||||||
|
code.literal:after { content: "'"; }
|
||||||
|
|
||||||
|
em {
|
||||||
|
font-style: italic;
|
||||||
|
color: #064;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.literallayout p {
|
div.literallayout p {
|
||||||
|
@ -137,7 +147,6 @@ div.literallayout p {
|
||||||
|
|
||||||
div.literallayout {
|
div.literallayout {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
# margin: 0.5em 10% 0.5em 1em;
|
|
||||||
margin: 0em;
|
margin: 0em;
|
||||||
color: navy;
|
color: navy;
|
||||||
border: 1px solid silver;
|
border: 1px solid silver;
|
||||||
|
@ -187,7 +196,8 @@ dt {
|
||||||
}
|
}
|
||||||
|
|
||||||
dt span.term {
|
dt span.term {
|
||||||
font-style: italic;
|
font-style: normal;
|
||||||
|
color: navy;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.variablelist dd p {
|
div.variablelist dd p {
|
||||||
|
|
|
@ -9,7 +9,7 @@ SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
|
'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>...
|
[--refresh] [--ignore-errors] [--] <filepattern>...
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
|
@ -76,6 +76,15 @@ OPTIONS
|
||||||
bypassed and the 'patch' subcommand is invoked using each of
|
bypassed and the 'patch' subcommand is invoked using each of
|
||||||
the specified filepatterns before exiting.
|
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::
|
-u::
|
||||||
--update::
|
--update::
|
||||||
Update only files that git already knows about, staging modified
|
Update only files that git already knows about, staging modified
|
||||||
|
|
|
@ -10,6 +10,7 @@ SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
|
'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
|
||||||
|
[--output=<file>] [--worktree-attributes]
|
||||||
[--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
|
[--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
|
||||||
[path...]
|
[path...]
|
||||||
|
|
||||||
|
@ -47,6 +48,12 @@ OPTIONS
|
||||||
--prefix=<prefix>/::
|
--prefix=<prefix>/::
|
||||||
Prepend <prefix>/ to each filename in the archive.
|
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>::
|
<extra>::
|
||||||
This can be any options that the archiver backend understands.
|
This can be any options that the archiver backend understands.
|
||||||
See next section.
|
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:
|
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
|
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
|
$ 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:
|
* 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,
|
outside the repository to prevent interactions between the bisect,
|
||||||
make and test processes and the scripts.
|
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
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org>
|
Written by Linus Torvalds <torvalds@osdl.org>
|
||||||
|
|
|
@ -76,8 +76,8 @@ OPTIONS
|
||||||
based sha1 expressions such as "<branchname>@\{yesterday}".
|
based sha1 expressions such as "<branchname>@\{yesterday}".
|
||||||
|
|
||||||
-f::
|
-f::
|
||||||
Force the creation of a new branch even if it means deleting
|
Reset <branchname> to <startpoint> if <branchname> exists
|
||||||
a branch that already exists with the same name.
|
already. Without `-f` 'git-branch' refuses to change an existing branch.
|
||||||
|
|
||||||
-m::
|
-m::
|
||||||
Move/rename a branch and the corresponding reflog.
|
Move/rename a branch and the corresponding reflog.
|
||||||
|
@ -100,7 +100,9 @@ OPTIONS
|
||||||
|
|
||||||
-v::
|
-v::
|
||||||
--verbose::
|
--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>::
|
--abbrev=<length>::
|
||||||
Alter the sha1's minimum display length in the output listing.
|
Alter the sha1's minimum display length in the output listing.
|
||||||
|
@ -109,20 +111,24 @@ OPTIONS
|
||||||
--no-abbrev::
|
--no-abbrev::
|
||||||
Display the full sha1s in the output listing rather than abbreviating them.
|
Display the full sha1s in the output listing rather than abbreviating them.
|
||||||
|
|
||||||
|
-t::
|
||||||
--track::
|
--track::
|
||||||
When creating a new branch, set up the configuration so that 'git-pull'
|
When creating a new branch, set up configuration to mark the
|
||||||
will automatically retrieve data from the start point, which must be
|
start-point branch as "upstream" from the new branch. This
|
||||||
a branch. Use this if you always pull from the same upstream branch
|
configuration will tell git to show the relationship between the
|
||||||
into the new branch, and if you do not want to use "git pull
|
two branches in `git status` and `git branch -v`. Furthermore,
|
||||||
<repository> <refspec>" explicitly. This behavior is the default
|
it directs `git pull` without arguments to pull from the
|
||||||
when the start point is a remote branch. Set the
|
upstream when the new branch is checked out.
|
||||||
branch.autosetupmerge configuration variable to `false` if you want
|
+
|
||||||
'git-checkout' and 'git-branch' to always behave as if '--no-track' were
|
This behavior is the default when the start point is a remote branch.
|
||||||
given. Set it to `always` if you want this behavior when the
|
Set the branch.autosetupmerge configuration variable to `false` if you
|
||||||
start-point is either a local or remote branch.
|
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::
|
--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>::
|
--contains <commit>::
|
||||||
Only list branches which contain the specified 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
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
|
[verse]
|
||||||
'git check-ref-format' <refname>
|
'git check-ref-format' <refname>
|
||||||
|
'git check-ref-format' [--branch] <branchname-shorthand>
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
@ -23,6 +25,10 @@ imposes the following rules on how references are named:
|
||||||
grouping, but no slash-separated component can begin with a
|
grouping, but no slash-separated component can begin with a
|
||||||
dot `.`.
|
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 two consecutive dots `..` anywhere.
|
||||||
|
|
||||||
. They cannot have ASCII control characters (i.e. bytes whose
|
. 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 `*`,
|
caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
|
||||||
or open bracket `[` anywhere.
|
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
|
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
|
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
|
It may also be used to select a specific object such as with
|
||||||
'git-cat-file': "git cat-file blob v1.3.3:refs.c".
|
'git-cat-file': "git cat-file blob v1.3.3:refs.c".
|
||||||
|
|
||||||
|
. 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
|
GIT
|
||||||
---
|
---
|
||||||
|
|
|
@ -8,28 +8,28 @@ git-checkout - Checkout a branch or paths to the working tree
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[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>...
|
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
When <paths> are not given, this command switches branches by
|
When <paths> are not given, this command switches branches by
|
||||||
updating the index and working tree to reflect the specified
|
updating the index, working tree, and HEAD to reflect the specified
|
||||||
branch, <branch>, and updating HEAD to be <branch> or, if
|
branch.
|
||||||
specified, <new_branch>. Using -b will cause <new_branch> to
|
|
||||||
be created; in this case you can use the --track or --no-track
|
|
||||||
options, which will be passed to `git branch`.
|
|
||||||
|
|
||||||
As a convenience, --track will default to create a branch whose
|
If `-b` is given, a new branch is created and checked out, as if
|
||||||
name is constructed from the specified branch name by stripping
|
linkgit:git-branch[1] were called; in this case you can
|
||||||
the first namespace level.
|
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
|
When <paths> are given, this command does *not* switch
|
||||||
branches. It updates the named paths in the working tree from
|
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
|
the index file, or from a named <tree-ish> (most often a commit). In
|
||||||
this case, the `-b` options is meaningless and giving
|
this case, the `-b` and `--track` options are meaningless and giving
|
||||||
either of them results in an error. <tree-ish> argument can be
|
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)
|
used to specify a specific tree-ish (i.e. commit, tag or tree)
|
||||||
to update the index for the given paths before updating the
|
to update the index for the given paths before updating the
|
||||||
working tree.
|
working tree.
|
||||||
|
@ -62,27 +62,16 @@ entries; instead, unmerged entries are ignored.
|
||||||
|
|
||||||
-b::
|
-b::
|
||||||
Create a new branch named <new_branch> and start it at
|
Create a new branch named <new_branch> and start it at
|
||||||
<branch>. The new branch name must pass all checks defined
|
<start_point>; see linkgit:git-branch[1] for details.
|
||||||
by linkgit:git-check-ref-format[1]. Some of these checks
|
|
||||||
may restrict the characters allowed in a branch name.
|
|
||||||
|
|
||||||
-t::
|
-t::
|
||||||
--track::
|
--track::
|
||||||
When creating a new branch, set up configuration so that 'git-pull'
|
When creating a new branch, set up "upstream" configuration. See
|
||||||
will automatically retrieve data from the start point, which must be
|
"--track" in linkgit:git-branch[1] for details.
|
||||||
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.
|
|
||||||
+
|
+
|
||||||
If no '-b' option was given, the name of the new branch will be
|
If no '-b' option is given, the name of the new branch will be
|
||||||
derived from the remote branch, by attempting to guess the name
|
derived from the remote branch. If "remotes/" or "refs/remotes/"
|
||||||
of the branch on remote system. If "remotes/" or "refs/remotes/"
|
is prefixed it is stripped away, and then the part up to the
|
||||||
are prefixed, it is stripped away, and then the part up to the
|
|
||||||
next slash (which would be the nickname of the remote) is removed.
|
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
|
This would tell us to use "hack" as the local branch when branching
|
||||||
off of "origin/hack" (or "remotes/origin/hack", or even
|
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.
|
explicitly give a name with '-b' in such a case.
|
||||||
|
|
||||||
--no-track::
|
--no-track::
|
||||||
Ignore the branch.autosetupmerge configuration variable.
|
Do not set up "upstream" configuration, even if the
|
||||||
|
branch.autosetupmerge configuration variable is true.
|
||||||
|
|
||||||
-l::
|
-l::
|
||||||
Create the new branch's reflog. This activates recording of
|
Create the new branch's reflog; see linkgit:git-branch[1] for
|
||||||
all changes made to the branch ref, enabling use of date
|
details.
|
||||||
based sha1 expressions such as "<branchname>@\{yesterday}".
|
|
||||||
|
|
||||||
-m::
|
-m::
|
||||||
--merge::
|
--merge::
|
||||||
|
@ -124,23 +113,28 @@ the conflicted merge in the specified paths.
|
||||||
"merge" (default) and "diff3" (in addition to what is shown by
|
"merge" (default) and "diff3" (in addition to what is shown by
|
||||||
"merge" style, shows the original contents).
|
"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>::
|
<new_branch>::
|
||||||
Name for the 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-ish>::
|
||||||
Tree to checkout from (when paths are given). If not specified,
|
Tree to checkout from (when paths are given). If not specified,
|
||||||
the index will be used.
|
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
|
Detached HEAD
|
||||||
|
@ -156,12 +150,12 @@ $ git checkout v2.6.18
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Earlier versions of git did not allow this and asked you to
|
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
|
version 1.5.0, the above command 'detaches' your HEAD from the
|
||||||
current branch and directly point at the commit named by the tag
|
current branch and directly points at the commit named by the tag
|
||||||
(`v2.6.18` in the above example).
|
(`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
|
`git reset --hard $othercommit` to further move around, for
|
||||||
example. You can make changes and create a new commit on top of
|
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
|
a detached HEAD. You can even create a merge by using `git
|
||||||
|
@ -206,7 +200,7 @@ You should instead write:
|
||||||
$ git checkout -- hello.c
|
$ 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:
|
branch would be done using:
|
||||||
+
|
+
|
||||||
------------
|
------------
|
||||||
|
@ -214,7 +208,7 @@ $ git checkout mytopic
|
||||||
------------
|
------------
|
||||||
+
|
+
|
||||||
However, your "wrong" branch and correct "mytopic" branch may
|
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:
|
the above checkout would fail like this:
|
||||||
+
|
+
|
||||||
------------
|
------------
|
||||||
|
|
|
@ -12,14 +12,17 @@ SYNOPSIS
|
||||||
|
|
||||||
DESCRIPTION
|
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
|
Cleans the working tree by recursively removing files that are not
|
||||||
specified, ignored files are also removed, allowing to remove all
|
under version control, starting from the current directory.
|
||||||
build products.
|
|
||||||
|
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
|
If any optional `<path>...` arguments are given, only those paths
|
||||||
are affected.
|
are affected.
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
-d::
|
-d::
|
||||||
|
|
|
@ -149,7 +149,7 @@ then the cloned repository will become corrupt.
|
||||||
part of the source repository is used if no directory is
|
part of the source repository is used if no directory is
|
||||||
explicitly given ("repo" for "/path/to/repo.git" and "foo"
|
explicitly given ("repo" for "/path/to/repo.git" and "foo"
|
||||||
for "host.xz:foo/.git"). Cloning into an existing directory
|
for "host.xz:foo/.git"). Cloning into an existing directory
|
||||||
is not allowed.
|
is only allowed if the directory is empty.
|
||||||
|
|
||||||
:git-clone: 1
|
:git-clone: 1
|
||||||
include::urls.txt[]
|
include::urls.txt[]
|
||||||
|
|
|
@ -11,7 +11,7 @@ SYNOPSIS
|
||||||
[verse]
|
[verse]
|
||||||
'git config' [<file-option>] [type] [-z|--null] name [value [value_regex]]
|
'git config' [<file-option>] [type] [-z|--null] name [value [value_regex]]
|
||||||
'git config' [<file-option>] [type] --add name value
|
'git config' [<file-option>] [type] --add name value
|
||||||
'git config' [<file-option>] [type] --replace-all name [value [value_regex]]
|
'git config' [<file-option>] [type] --replace-all name value [value_regex]
|
||||||
'git config' [<file-option>] [type] [-z|--null] --get name [value_regex]
|
'git config' [<file-option>] [type] [-z|--null] --get name [value_regex]
|
||||||
'git config' [<file-option>] [type] [-z|--null] --get-all name [value_regex]
|
'git config' [<file-option>] [type] [-z|--null] --get-all name [value_regex]
|
||||||
'git config' [<file-option>] [type] [-z|--null] --get-regexp name_regex [value_regex]
|
'git config' [<file-option>] [type] [-z|--null] --get-regexp name_regex [value_regex]
|
||||||
|
@ -22,6 +22,7 @@ SYNOPSIS
|
||||||
'git config' [<file-option>] [-z|--null] -l | --list
|
'git config' [<file-option>] [-z|--null] -l | --list
|
||||||
'git config' [<file-option>] --get-color name [default]
|
'git config' [<file-option>] --get-color name [default]
|
||||||
'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
|
'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
|
||||||
|
'git config' [<file-option>] -e | --edit
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
@ -68,7 +69,8 @@ OPTIONS
|
||||||
|
|
||||||
--add::
|
--add::
|
||||||
Adds a new line to the option without altering any existing
|
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::
|
||||||
Get the value for a given key (optionally filtered by a regex
|
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
|
When the color setting for `name` is undefined, the command uses
|
||||||
`color.ui` as fallback.
|
`color.ui` as fallback.
|
||||||
|
|
||||||
--get-color name default::
|
--get-color name [default]::
|
||||||
|
|
||||||
Find the color configured for `name` (e.g. `color.diff.new`) and
|
Find the color configured for `name` (e.g. `color.diff.new`) and
|
||||||
output it as the ANSI color escape sequence to the standard
|
output it as the ANSI color escape sequence to the standard
|
||||||
output. The optional `default` parameter is used instead, if
|
output. The optional `default` parameter is used instead, if
|
||||||
there is no color configured for `name`.
|
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]]
|
||||||
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'.
|
Splitting the CVS log into patch sets is done by 'cvsps'.
|
||||||
At least version 2.1 is required.
|
At least version 2.1 is required.
|
||||||
|
|
||||||
|
*WARNING:* for certain situations the import leads to incorrect results.
|
||||||
|
Please see the section <<issues,ISSUES>> for further reference.
|
||||||
|
|
||||||
You should *never* do any work of your own on the branches that are
|
You should *never* do any work of your own on the branches that are
|
||||||
created by 'git-cvsimport'. By default initial import will create and populate a
|
created by 'git-cvsimport'. By default initial import will create and populate a
|
||||||
"master" branch from the CVS repository's main branch which you're free
|
"master" branch from the CVS repository's main branch which you're free
|
||||||
|
@ -164,6 +167,39 @@ If '-v' is specified, the script reports what it is doing.
|
||||||
Otherwise, success is indicated the Unix way, i.e. by simply exiting with
|
Otherwise, success is indicated the Unix way, i.e. by simply exiting with
|
||||||
a zero exit status.
|
a zero exit status.
|
||||||
|
|
||||||
|
[[issues]]
|
||||||
|
ISSUES
|
||||||
|
------
|
||||||
|
Problems related to timestamps:
|
||||||
|
|
||||||
|
* If timestamps of commits in the cvs repository are not stable enough
|
||||||
|
to be used for ordering commits changes may show up in the wrong
|
||||||
|
order.
|
||||||
|
* If any files were ever "cvs import"ed more than once (e.g., import of
|
||||||
|
more than one vendor release) the HEAD contains the wrong content.
|
||||||
|
* If the timestamp order of different files cross the revision order
|
||||||
|
within the commit matching time window the order of commits may be
|
||||||
|
wrong.
|
||||||
|
|
||||||
|
Problems related to branches:
|
||||||
|
|
||||||
|
* Branches on which no commits have been made are not imported.
|
||||||
|
* All files from the branching point are added to a branch even if
|
||||||
|
never added in cvs.
|
||||||
|
* This applies to files added to the source branch *after* a daughter
|
||||||
|
branch was created: if previously no commit was made on the daughter
|
||||||
|
branch they will erroneously be added to the daughter branch in git.
|
||||||
|
|
||||||
|
Problems related to tags:
|
||||||
|
|
||||||
|
* Multiple tags on the same revision are not imported.
|
||||||
|
|
||||||
|
If you suspect that any of these issues may apply to the repository you
|
||||||
|
want to import consider using these alternative tools which proved to be
|
||||||
|
more stable in practice:
|
||||||
|
|
||||||
|
* cvs2git (part of cvs2svn), `http://cvs2svn.tigris.org`
|
||||||
|
* parsecvs, `http://cgit.freedesktop.org/~keithp/parsecvs`
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
|
|
@ -3,52 +3,54 @@ git-difftool(1)
|
||||||
|
|
||||||
NAME
|
NAME
|
||||||
----
|
----
|
||||||
git-difftool - compare changes using common merge tools
|
git-difftool - Show changes using common diff tools
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git difftool' [--tool=<tool>] [--no-prompt] ['git diff' options]
|
'git difftool' [--tool=<tool>] [-y|--no-prompt|--prompt] [<'git diff' options>]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
'git-difftool' is a git command that allows you to compare and edit files
|
'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,
|
between revisions using common diff tools. 'git difftool' is a frontend
|
||||||
'git-difftool' does what 'git-mergetool' does but its use is for non-merge
|
to 'git-diff' and accepts the same options and arguments.
|
||||||
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.
|
|
||||||
|
|
||||||
OPTIONS
|
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>::
|
-t <tool>::
|
||||||
--tool=<tool>::
|
--tool=<tool>::
|
||||||
Use the merge resolution program specified by <tool>.
|
Use the diff tool specified by <tool>.
|
||||||
Valid merge tools are:
|
Valid merge tools are:
|
||||||
kdiff3, kompare, tkdiff, meld, xxdiff, emerge,
|
kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff,
|
||||||
vimdiff, gvimdiff, ecmerge, and opendiff
|
ecmerge, diffuse and opendiff
|
||||||
+
|
+
|
||||||
If a merge resolution program is not specified, 'git-difftool'
|
If a diff tool is not specified, 'git-difftool'
|
||||||
will use the configuration variable `merge.tool`. If the
|
will use the configuration variable `diff.tool`. If the
|
||||||
configuration variable `merge.tool` is not set, 'git difftool'
|
configuration variable `diff.tool` is not set, 'git-difftool'
|
||||||
will pick a suitable default.
|
will pick a suitable default.
|
||||||
+
|
+
|
||||||
You can explicitly provide a full path to the tool by setting the
|
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
|
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.
|
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
|
'git-difftool' can be customized to run an alternative program
|
||||||
by specifying the command line to invoke in a configuration
|
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
|
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
|
the configured command line will be invoked with the following
|
||||||
variables available: `$LOCAL` is set to the name of the temporary
|
variables available: `$LOCAL` is set to the name of the temporary
|
||||||
file containing the contents of the diff pre-image and `$REMOTE`
|
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
|
of the diff post-image. `$BASE` is provided for compatibility
|
||||||
with custom merge tool commands and has the same value as `$LOCAL`.
|
with custom merge tool commands and has the same value as `$LOCAL`.
|
||||||
|
|
||||||
--no-prompt::
|
See linkgit:git-diff[1] for the full list of supported options.
|
||||||
Do not prompt before launching a diff tool.
|
|
||||||
|
|
||||||
CONFIG VARIABLES
|
CONFIG VARIABLES
|
||||||
----------------
|
----------------
|
||||||
merge.tool::
|
'git-difftool' falls back to 'git-mergetool' config variables when the
|
||||||
The default merge tool to use.
|
difftool equivalents have not been defined.
|
||||||
+
|
|
||||||
See the `--tool=<tool>` option above for more details.
|
|
||||||
|
|
||||||
merge.keepBackup::
|
diff.tool::
|
||||||
The original, unedited file content can be saved to a file with
|
The default diff tool to use.
|
||||||
a `.orig` extension. Defaults to `true` (i.e. keep the backup files).
|
|
||||||
|
|
||||||
mergetool.<tool>.path::
|
difftool.<tool>.path::
|
||||||
Override the path for the given tool. This is useful in case
|
Override the path for the given tool. This is useful in case
|
||||||
your tool is not in the PATH.
|
your tool is not in the PATH.
|
||||||
|
|
||||||
mergetool.<tool>.cmd::
|
difftool.<tool>.cmd::
|
||||||
Specify the command to invoke the specified merge tool.
|
Specify the command to invoke the specified diff tool.
|
||||||
+
|
+
|
||||||
See the `--tool=<tool>` option above for more details.
|
See the `--tool=<tool>` option above for more details.
|
||||||
|
|
||||||
|
difftool.prompt::
|
||||||
|
Prompt before each invocation of the diff tool.
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
|
@ -94,7 +94,9 @@ OPTIONS
|
||||||
--index-filter <command>::
|
--index-filter <command>::
|
||||||
This is the filter for rewriting the index. It is similar to the
|
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
|
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>::
|
--parent-filter <command>::
|
||||||
This is the filter for rewriting the commit's parent list.
|
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.
|
a simple `rm filename` will fail for that tree and commit.
|
||||||
Thus you may instead want to use `rm -f filename` as the script.
|
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.
|
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
|
To rewrite the repository to look as if `foodir/` had been its project
|
||||||
root, and discard all other history:
|
root, and discard all other history:
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,8 @@ For all objects, the following names can be used:
|
||||||
refname::
|
refname::
|
||||||
The name of the ref (the part after $GIT_DIR/).
|
The name of the ref (the part after $GIT_DIR/).
|
||||||
For a non-ambiguous short name of the ref append `:short`.
|
For a non-ambiguous short name of the ref append `:short`.
|
||||||
|
The option core.warnAmbiguousRefs is used to select the strict
|
||||||
|
abbreviation mode.
|
||||||
|
|
||||||
objecttype::
|
objecttype::
|
||||||
The type of the object (`blob`, `tree`, `commit`, `tag`).
|
The type of the object (`blob`, `tree`, `commit`, `tag`).
|
||||||
|
@ -85,6 +87,11 @@ objectsize::
|
||||||
objectname::
|
objectname::
|
||||||
The object name (aka SHA-1).
|
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
|
In addition to the above, for commit and tag objects, the header
|
||||||
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
|
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
|
||||||
be used to specify the value in the header field.
|
be used to specify the value in the header field.
|
||||||
|
|
|
@ -9,9 +9,10 @@ git-format-patch - Prepare patches for e-mail submission
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git format-patch' [-k] [-o <dir> | --stdout] [--thread]
|
'git format-patch' [-k] [(-o|--output-directory) <dir> | --stdout]
|
||||||
[--attach[=<boundary>] | --inline[=<boundary>]]
|
[--thread[=<style>]]
|
||||||
[-s | --signoff] [<common diff options>]
|
[(--attach|--inline)[=<boundary>] | --no-attach]
|
||||||
|
[-s | --signoff]
|
||||||
[-n | --numbered | -N | --no-numbered]
|
[-n | --numbered | -N | --no-numbered]
|
||||||
[--start-number <n>] [--numbered-files]
|
[--start-number <n>] [--numbered-files]
|
||||||
[--in-reply-to=Message-Id] [--suffix=.<sfx>]
|
[--in-reply-to=Message-Id] [--suffix=.<sfx>]
|
||||||
|
@ -19,6 +20,7 @@ SYNOPSIS
|
||||||
[--subject-prefix=Subject-Prefix]
|
[--subject-prefix=Subject-Prefix]
|
||||||
[--cc=<email>]
|
[--cc=<email>]
|
||||||
[--cover-letter]
|
[--cover-letter]
|
||||||
|
[<common diff options>]
|
||||||
[ <since> | <revision range> ]
|
[ <since> | <revision range> ]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
|
@ -112,15 +114,27 @@ include::diff-options.txt[]
|
||||||
which is the commit message and the patch itself in the
|
which is the commit message and the patch itself in the
|
||||||
second part, with "Content-Disposition: attachment".
|
second part, with "Content-Disposition: attachment".
|
||||||
|
|
||||||
|
--no-attach::
|
||||||
|
Disable the creation of an attachment, overriding the
|
||||||
|
configuration setting.
|
||||||
|
|
||||||
--inline[=<boundary>]::
|
--inline[=<boundary>]::
|
||||||
Create multipart/mixed attachment, the first part of
|
Create multipart/mixed attachment, the first part of
|
||||||
which is the commit message and the patch itself in the
|
which is the commit message and the patch itself in the
|
||||||
second part, with "Content-Disposition: inline".
|
second part, with "Content-Disposition: inline".
|
||||||
|
|
||||||
--thread::
|
--thread[=<style>]::
|
||||||
Add In-Reply-To and References headers to make the second and
|
Add In-Reply-To and References headers to make the second and
|
||||||
subsequent mails appear as replies to the first. Also generates
|
subsequent mails appear as replies to the first. Also generates
|
||||||
the Message-Id header to reference.
|
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::
|
--in-reply-to=Message-Id::
|
||||||
Make the first mail (or all the mails with --no-thread) appear as a
|
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
|
Add a "Cc:" header to the email headers. This is in addition
|
||||||
to any configured headers, and may be used multiple times.
|
to any configured headers, and may be used multiple times.
|
||||||
|
|
||||||
|
--add-header=<header>::
|
||||||
|
Add an arbitrary header to the email headers. This is in addition
|
||||||
|
to any configured headers, and may be used multiple times.
|
||||||
|
For example, --add-header="Organization: git-foo"
|
||||||
|
|
||||||
--cover-letter::
|
--cover-letter::
|
||||||
In addition to the patches, generate a cover letter file
|
In addition to the patches, generate a cover letter file
|
||||||
containing the shortlog and the overall diffstat. You can
|
containing the shortlog and the overall diffstat. You can
|
||||||
|
@ -152,18 +171,17 @@ include::diff-options.txt[]
|
||||||
--suffix=.<sfx>::
|
--suffix=.<sfx>::
|
||||||
Instead of using `.patch` as the suffix for generated
|
Instead of using `.patch` as the suffix for generated
|
||||||
filenames, use specified suffix. A common alternative is
|
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
|
Note that the leading character does not have to be a dot; for example,
|
||||||
want a filename like `0001-description-of-my-change.patch`, and
|
you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`.
|
||||||
the first letter does not have to be a dot. Leaving it empty would
|
|
||||||
not add any suffix.
|
|
||||||
|
|
||||||
--no-binary::
|
--no-binary::
|
||||||
Don't output contents of changes in binary files, just take note
|
Do not output contents of changes in binary files, instead
|
||||||
that they differ. Note that this disable the patch to be properly
|
display a notice that those files changed. Patches generated
|
||||||
applied. By default the contents of changes in those files are
|
using this option cannot be applied properly, but they are
|
||||||
encoded in the patch.
|
still useful for code review.
|
||||||
|
|
||||||
--root::
|
--root::
|
||||||
Treat the revision argument as a <revision range>, even if it
|
Treat the revision argument as a <revision range>, even if it
|
||||||
|
@ -174,9 +192,10 @@ not add any suffix.
|
||||||
|
|
||||||
CONFIGURATION
|
CONFIGURATION
|
||||||
-------------
|
-------------
|
||||||
You can specify extra mail header lines to be added to each message
|
You can specify extra mail header lines to be added to each message,
|
||||||
in the repository configuration, new defaults for the subject prefix
|
defaults for the subject prefix and file suffix, number patches when
|
||||||
and file suffix, and number patches when outputting more than one.
|
outputting more than one patch, add "Cc:" headers, configure attachments,
|
||||||
|
and sign off patches with configuration variables.
|
||||||
|
|
||||||
------------
|
------------
|
||||||
[format]
|
[format]
|
||||||
|
@ -185,6 +204,8 @@ and file suffix, and number patches when outputting more than one.
|
||||||
suffix = .txt
|
suffix = .txt
|
||||||
numbered = auto
|
numbered = auto
|
||||||
cc = <email>
|
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
|
Additionally, it detects and handles renames and complete rewrites
|
||||||
intelligently to produce a renaming patch. A renaming patch reduces
|
intelligently to produce a renaming patch. A renaming patch reduces
|
||||||
the amount of text output, and generally makes it easier to review it.
|
the amount of text output, and generally makes it easier to review.
|
||||||
Note that the "patch" program does not understand renaming patches, so
|
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.
|
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
|
* Extract three topmost commits from the current branch and format them
|
||||||
|
|
|
@ -17,6 +17,7 @@ SYNOPSIS
|
||||||
[-l | --files-with-matches] [-L | --files-without-match]
|
[-l | --files-with-matches] [-L | --files-without-match]
|
||||||
[-z | --null]
|
[-z | --null]
|
||||||
[-c | --count] [--all-match]
|
[-c | --count] [--all-match]
|
||||||
|
[--color | --no-color]
|
||||||
[-A <post-context>] [-B <pre-context>] [-C <context>]
|
[-A <post-context>] [-B <pre-context>] [-C <context>]
|
||||||
[-f <file>] [-e] <pattern>
|
[-f <file>] [-e] <pattern>
|
||||||
[--and|--or|--not|(|)|-e <pattern>...] [<tree>...]
|
[--and|--or|--not|(|)|-e <pattern>...] [<tree>...]
|
||||||
|
@ -105,6 +106,13 @@ OPTIONS
|
||||||
Instead of showing every matched line, show the number of
|
Instead of showing every matched line, show the number of
|
||||||
lines that match.
|
lines that match.
|
||||||
|
|
||||||
|
--color::
|
||||||
|
Show colored matches.
|
||||||
|
|
||||||
|
--no-color::
|
||||||
|
Turn off match highlighting, even when the configuration file
|
||||||
|
gives the default to color output.
|
||||||
|
|
||||||
-[ABC] <context>::
|
-[ABC] <context>::
|
||||||
Show `context` trailing (`A` -- after), or leading (`B`
|
Show `context` trailing (`A` -- after), or leading (`B`
|
||||||
-- before), or both (`C` -- context) lines, and place a
|
-- before), or both (`C` -- context) lines, and place a
|
||||||
|
|
|
@ -64,6 +64,13 @@ imap.sslverify::
|
||||||
used by the SSL/TLS connection. Default is `true`. Ignored when
|
used by the SSL/TLS connection. Default is `true`. Ignored when
|
||||||
imap.tunnel is set.
|
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
|
Examples
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,8 @@ include::merge-options.txt[]
|
||||||
include::merge-strategies.txt[]
|
include::merge-strategies.txt[]
|
||||||
|
|
||||||
|
|
||||||
If you tried a merge which resulted in a complex conflicts and
|
If you tried a merge which resulted in complex conflicts and
|
||||||
would want to start over, you can recover with 'git-reset'.
|
want to start over, you can recover with 'git-reset'.
|
||||||
|
|
||||||
CONFIGURATION
|
CONFIGURATION
|
||||||
-------------
|
-------------
|
||||||
|
@ -146,7 +146,7 @@ And here is another line that is cleanly resolved or unmodified.
|
||||||
------------
|
------------
|
||||||
|
|
||||||
The area where a pair of conflicting changes happened is marked with markers
|
The area where a pair of conflicting changes happened is marked with markers
|
||||||
"`<<<<<<<`", "`=======`", and "`>>>>>>>`". The part before the "`=======`"
|
`<<<<<<<`, `=======`, and `>>>>>>>`. The part before the `=======`
|
||||||
is typically your side, and the part afterwards is typically their side.
|
is typically your side, and the part afterwards is typically their side.
|
||||||
|
|
||||||
The default format does not show what the original said in the conflicting
|
The default format does not show what the original said in the conflicting
|
||||||
|
@ -173,8 +173,8 @@ Git makes conflict resolution easy.
|
||||||
And here is another line that is cleanly resolved or unmodified.
|
And here is another line that is cleanly resolved or unmodified.
|
||||||
------------
|
------------
|
||||||
|
|
||||||
In addition to the "`<<<<<<<`", "`=======`", and "`>>>>>>>`" markers, it uses
|
In addition to the `<<<<<<<`, `=======`, and `>>>>>>>` markers, it uses
|
||||||
another "`|||||||`" marker that is followed by the original text. You can
|
another `|||||||` marker that is followed by the original text. You can
|
||||||
tell that the original just stated a fact, and your side simply gave in to
|
tell that the original just stated a fact, and your side simply gave in to
|
||||||
that statement and gave up, while the other side tried to have a more
|
that statement and gave up, while the other side tried to have a more
|
||||||
positive attitude. You can sometimes come up with a better resolution by
|
positive attitude. You can sometimes come up with a better resolution by
|
||||||
|
|
|
@ -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>::
|
--tool=<tool>::
|
||||||
Use the merge resolution program specified by <tool>.
|
Use the merge resolution program specified by <tool>.
|
||||||
Valid merge tools are:
|
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'
|
If a merge resolution program is not specified, 'git-mergetool'
|
||||||
will use the configuration variable `merge.tool`. If the
|
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
|
When dealing with 'git-diff-tree' output, it takes advantage of
|
||||||
the fact that the patch is prefixed with the object name of the
|
the fact that the patch is prefixed with the object name of the
|
||||||
commit, and outputs two 40-byte hexadecimal string. The first
|
commit, and outputs two 40-byte hexadecimal strings. The first
|
||||||
string is the patch ID, and the second string is the commit ID.
|
string is the patch ID, and the second string is the commit ID.
|
||||||
This can be used to make a mapping from patch ID to commit ID.
|
This can be used to make a mapping from patch ID to commit ID.
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,8 @@ every time you push into it, by setting up 'hooks' there. See
|
||||||
documentation for linkgit:git-receive-pack[1].
|
documentation for linkgit:git-receive-pack[1].
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS[[OPTIONS]]
|
||||||
-------
|
------------------
|
||||||
<repository>::
|
<repository>::
|
||||||
The "remote" repository that is destination of a push
|
The "remote" repository that is destination of a push
|
||||||
operation. This parameter can be either a URL
|
operation. This parameter can be either a URL
|
||||||
|
@ -187,6 +187,28 @@ reason::
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
git push::
|
||||||
|
Works like `git push <remote>`, where <remote> is the
|
||||||
|
current branch's remote (or `origin`, if no remote is
|
||||||
|
configured for the current branch).
|
||||||
|
|
||||||
|
git push origin::
|
||||||
|
Without additional configuration, works like
|
||||||
|
`git push origin :`.
|
||||||
|
+
|
||||||
|
The default behavior of this command when no <refspec> is given can be
|
||||||
|
configured by setting the `push` option of the remote.
|
||||||
|
+
|
||||||
|
For example, to default to pushing only the current branch to `origin`
|
||||||
|
use `git config remote.origin.push HEAD`. Any valid <refspec> (like
|
||||||
|
the ones in the examples below) can be configured as the default for
|
||||||
|
`git push origin`.
|
||||||
|
|
||||||
|
git push origin :::
|
||||||
|
Push "matching" branches to `origin`. See
|
||||||
|
<refspec> in the <<OPTIONS,OPTIONS>> section above for a
|
||||||
|
description of "matching" branches.
|
||||||
|
|
||||||
git push origin master::
|
git push origin master::
|
||||||
Find a ref that matches `master` in the source repository
|
Find a ref that matches `master` in the source repository
|
||||||
(most likely, it would find `refs/heads/master`), and update
|
(most likely, it would find `refs/heads/master`), and update
|
||||||
|
|
|
@ -192,6 +192,13 @@ Alternatively, you can undo the 'git-rebase' with
|
||||||
|
|
||||||
git rebase --abort
|
git rebase --abort
|
||||||
|
|
||||||
|
CONFIGURATION
|
||||||
|
-------------
|
||||||
|
|
||||||
|
rebase.stat::
|
||||||
|
Whether to show a diffstat of what changed upstream since the last
|
||||||
|
rebase. False by default.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
<newbase>::
|
<newbase>::
|
||||||
|
@ -224,15 +231,22 @@ OPTIONS
|
||||||
|
|
||||||
-s <strategy>::
|
-s <strategy>::
|
||||||
--strategy=<strategy>::
|
--strategy=<strategy>::
|
||||||
Use the given merge strategy; can be supplied more than
|
Use the given merge strategy.
|
||||||
once to specify them in the order they should be tried.
|
|
||||||
If there is no `-s` option, a built-in list of strategies
|
If there is no `-s` option, a built-in list of strategies
|
||||||
is used instead ('git-merge-recursive' when merging a single
|
is used instead ('git-merge-recursive' when merging a single
|
||||||
head, 'git-merge-octopus' otherwise). This implies --merge.
|
head, 'git-merge-octopus' otherwise). This implies --merge.
|
||||||
|
|
||||||
-v::
|
-v::
|
||||||
--verbose::
|
--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::
|
--no-verify::
|
||||||
This option bypasses the pre-rebase hook. See also linkgit:githooks[5].
|
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
|
context exist they all must match. By default no context is
|
||||||
ever ignored.
|
ever ignored.
|
||||||
|
|
||||||
|
-f::
|
||||||
|
--force-rebase::
|
||||||
|
Force the rebase even if the current branch is a descendant
|
||||||
|
of the commit you are rebasing onto. Normally the command will
|
||||||
|
exit with the message "Current branch is up to date" in such a
|
||||||
|
situation.
|
||||||
|
|
||||||
--whitespace=<option>::
|
--whitespace=<option>::
|
||||||
This flag is passed to the 'git-apply' program
|
This flag is passed to the 'git-apply' program
|
||||||
(see linkgit:git-apply[1]) that applies the patch.
|
(see linkgit:git-apply[1]) that applies the patch.
|
||||||
Incompatible with the --interactive option.
|
Incompatible with the --interactive option.
|
||||||
|
|
||||||
|
--committer-date-is-author-date::
|
||||||
|
--ignore-date::
|
||||||
|
These flags are passed to 'git-am' to easily change the dates
|
||||||
|
of the rebased commits (see linkgit:git-am[1]).
|
||||||
|
|
||||||
-i::
|
-i::
|
||||||
--interactive::
|
--interactive::
|
||||||
Make a list of the commits which are about to be rebased. Let the
|
Make a list of the commits which are about to be rebased. Let the
|
||||||
|
|
|
@ -13,9 +13,10 @@ SYNOPSIS
|
||||||
'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
|
'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
|
||||||
'git remote rename' <old> <new>
|
'git remote rename' <old> <new>
|
||||||
'git remote rm' <name>
|
'git remote rm' <name>
|
||||||
|
'git remote set-head' <name> [-a | -d | <branch>]
|
||||||
'git remote show' [-n] <name>
|
'git remote show' [-n] <name>
|
||||||
'git remote prune' [-n | --dry-run] <name>
|
'git remote prune' [-n | --dry-run] <name>
|
||||||
'git remote update' [group]
|
'git remote update' [-p | --prune] [group | remote]...
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
@ -53,8 +54,7 @@ is created. You can give more than one `-t <branch>` to track
|
||||||
multiple branches without grabbing all branches.
|
multiple branches without grabbing all branches.
|
||||||
+
|
+
|
||||||
With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set
|
With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set
|
||||||
up to point at remote's `<master>` branch instead of whatever
|
up to point at remote's `<master>` branch. See also the set-head command.
|
||||||
branch the `HEAD` at the remote repository actually points at.
|
|
||||||
+
|
+
|
||||||
In mirror mode, enabled with `\--mirror`, the refs will not be stored
|
In mirror mode, enabled with `\--mirror`, the refs will not be stored
|
||||||
in the 'refs/remotes/' namespace, but in 'refs/heads/'. This option
|
in the 'refs/remotes/' namespace, but in 'refs/heads/'. This option
|
||||||
|
@ -76,6 +76,30 @@ the configuration file format.
|
||||||
Remove the remote named <name>. All remote tracking branches and
|
Remove the remote named <name>. All remote tracking branches and
|
||||||
configuration settings for the remote are removed.
|
configuration settings for the remote are removed.
|
||||||
|
|
||||||
|
'set-head'::
|
||||||
|
|
||||||
|
Sets or deletes the default branch (`$GIT_DIR/remotes/<name>/HEAD`) for
|
||||||
|
the named remote. Having a default branch for a remote is not required,
|
||||||
|
but allows the name of the remote to be specified in lieu of a specific
|
||||||
|
branch. For example, if the default branch for `origin` is set to
|
||||||
|
`master`, then `origin` may be specified wherever you would normally
|
||||||
|
specify `origin/master`.
|
||||||
|
+
|
||||||
|
With `-d`, `$GIT_DIR/remotes/<name>/HEAD` is deleted.
|
||||||
|
+
|
||||||
|
With `-a`, the remote is queried to determine its `HEAD`, then
|
||||||
|
`$GIT_DIR/remotes/<name>/HEAD` is set to the same branch. e.g., if the remote
|
||||||
|
`HEAD` is pointed at `next`, "`git remote set-head origin -a`" will set
|
||||||
|
`$GIT_DIR/refs/remotes/origin/HEAD` to `refs/remotes/origin/next`. This will
|
||||||
|
only work if `refs/remotes/origin/next` already exists; if not it must be
|
||||||
|
fetched first.
|
||||||
|
+
|
||||||
|
Use `<branch>` to set `$GIT_DIR/remotes/<name>/HEAD` explicitly. e.g., "git
|
||||||
|
remote set-head origin master" will set `$GIT_DIR/refs/remotes/origin/HEAD` to
|
||||||
|
`refs/remotes/origin/master`. This will only work if
|
||||||
|
`refs/remotes/origin/master` already exists; if not it must be fetched first.
|
||||||
|
+
|
||||||
|
|
||||||
'show'::
|
'show'::
|
||||||
|
|
||||||
Gives some information about the remote <name>.
|
Gives some information about the remote <name>.
|
||||||
|
@ -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
|
remotes.default is not defined, all remotes which do not have the
|
||||||
configuration parameter remote.<name>.skipDefaultUpdate set to true will
|
configuration parameter remote.<name>.skipDefaultUpdate set to true will
|
||||||
be updated. (See linkgit:git-config[1]).
|
be updated. (See linkgit:git-config[1]).
|
||||||
|
+
|
||||||
|
With `--prune` option, prune all the remotes that are updated.
|
||||||
|
|
||||||
|
|
||||||
DISCUSSION
|
DISCUSSION
|
||||||
|
|
|
@ -26,10 +26,15 @@ OPTIONS
|
||||||
--parseopt::
|
--parseopt::
|
||||||
Use 'git-rev-parse' in option parsing mode (see PARSEOPT section below).
|
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
|
Only meaningful in `--parseopt` mode. Tells the option parser to echo
|
||||||
out the first `--` met instead of skipping it.
|
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::
|
--revs-only::
|
||||||
Do not output flags and parameters not meant for
|
Do not output flags and parameters not meant for
|
||||||
'git-rev-list' command.
|
'git-rev-list' command.
|
||||||
|
@ -64,7 +69,8 @@ OPTIONS
|
||||||
properly quoted for consumption by shell. Useful when
|
properly quoted for consumption by shell. Useful when
|
||||||
you expect your parameter to contain whitespaces and
|
you expect your parameter to contain whitespaces and
|
||||||
newlines (e.g. when using pickaxe `-S` with
|
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::
|
--not::
|
||||||
When showing object names, prefix them with '{caret}' and
|
When showing object names, prefix them with '{caret}' and
|
||||||
|
@ -84,6 +90,11 @@ OPTIONS
|
||||||
unfortunately named tag "master"), and show them as full
|
unfortunately named tag "master"), and show them as full
|
||||||
refnames (e.g. "refs/heads/master").
|
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::
|
--all::
|
||||||
Show all refs found in `$GIT_DIR/refs`.
|
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.
|
commit, following the commit ancestry chain.
|
||||||
|
|
||||||
To exclude commits reachable from a commit, a prefix `{caret}`
|
To exclude commits reachable from a commit, a prefix `{caret}`
|
||||||
notation is used. E.g. "`{caret}r1 r2`" means commits reachable
|
notation is used. E.g. `{caret}r1 r2` means commits reachable
|
||||||
from `r2` but exclude the ones reachable from `r1`.
|
from `r2` but exclude the ones reachable from `r1`.
|
||||||
|
|
||||||
This set operation appears so often that there is a shorthand
|
This set operation appears so often that there is a shorthand
|
||||||
for it. When you have two commits `r1` and `r2` (named according
|
for it. When you have two commits `r1` and `r2` (named according
|
||||||
to the syntax explained in SPECIFYING REVISIONS above), you can ask
|
to the syntax explained in SPECIFYING REVISIONS above), you can ask
|
||||||
for commits that are reachable from r2 excluding those that are reachable
|
for commits that are reachable from r2 excluding those that are reachable
|
||||||
from r1 by "`{caret}r1 r2`" and it can be written as "`r1..r2`".
|
from r1 by `{caret}r1 r2` and it can be written as `r1..r2`.
|
||||||
|
|
||||||
A similar notation "`r1\...r2`" is called symmetric difference
|
A similar notation `r1\...r2` is called symmetric difference
|
||||||
of `r1` and `r2` and is defined as
|
of `r1` and `r2` and is defined as
|
||||||
"`r1 r2 --not $(git merge-base --all r1 r2)`".
|
`r1 r2 --not $(git merge-base --all r1 r2)`.
|
||||||
It is the set of commits that are reachable from either one of
|
It is the set of commits that are reachable from either one of
|
||||||
`r1` or `r2` but not from both.
|
`r1` or `r2` but not from both.
|
||||||
|
|
||||||
|
@ -401,6 +412,33 @@ C? option C with an optional argument"
|
||||||
eval `echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?`
|
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
|
EXAMPLES
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|
|
@ -39,13 +39,13 @@ OPTIONS
|
||||||
Composing
|
Composing
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
--bcc::
|
--bcc=<address>::
|
||||||
Specify a "Bcc:" value for each email. Default is the value of
|
Specify a "Bcc:" value for each email. Default is the value of
|
||||||
'sendemail.bcc'.
|
'sendemail.bcc'.
|
||||||
+
|
+
|
||||||
The --bcc option must be repeated for each user you want on the bcc list.
|
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.
|
Specify a starting "Cc:" value for each email.
|
||||||
Default is the value of 'sendemail.cc'.
|
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
|
Use $GIT_EDITOR, core.editor, $VISUAL, or $EDITOR to edit an
|
||||||
introductory message for the patch series.
|
introductory message for the patch series.
|
||||||
+
|
+
|
||||||
When '--compose' is used, git send-email gets less interactive will use the
|
When '--compose' is used, git send-email will use the From, Subject, and
|
||||||
values of the headers you set there. If the body of the email (what you type
|
In-Reply-To headers specified in the message. If the body of the message
|
||||||
after the headers and a blank line) only contains blank (or GIT: prefixed)
|
(what you type after the headers and a blank line) only contains blank
|
||||||
lines, the summary won't be sent, but git-send-email will still use the
|
(or GIT: prefixed) lines the summary won't be sent, but From, Subject,
|
||||||
Headers values if you don't removed them.
|
and In-Reply-To headers will be used unless they are removed.
|
||||||
+
|
+
|
||||||
If it wasn't able to see a header in the summary it will ask you about it
|
Missing From or In-Reply-To headers will be prompted for.
|
||||||
interactively after quitting your editor.
|
|
||||||
|
|
||||||
--from::
|
--from=<address>::
|
||||||
Specify the sender of the emails. This will default to
|
Specify the sender of the emails. If not specified on the command line,
|
||||||
the value GIT_COMMITTER_IDENT, as returned by "git var -l".
|
the value of the 'sendemail.from' configuration option is used. If
|
||||||
The user will still be prompted to confirm this entry.
|
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.
|
Specify the contents of the first In-Reply-To header.
|
||||||
Subsequent emails will refer to the previous email
|
Subsequent emails will refer to the previous email
|
||||||
instead of this if --chain-reply-to is set (the default)
|
instead of this if --chain-reply-to is set (the default)
|
||||||
Only necessary if --compose is also set. If --compose
|
Only necessary if --compose is also set. If --compose
|
||||||
is not set, this will be prompted for.
|
is not set, this will be prompted for.
|
||||||
|
|
||||||
--subject::
|
--subject=<string>::
|
||||||
Specify the initial subject of the email thread.
|
Specify the initial subject of the email thread.
|
||||||
Only necessary if --compose is also set. If --compose
|
Only necessary if --compose is also set. If --compose
|
||||||
is not set, this will be prompted for.
|
is not set, this will be prompted for.
|
||||||
|
|
||||||
--to::
|
--to=<address>::
|
||||||
Specify the primary recipient of the emails generated. Generally, this
|
Specify the primary recipient of the emails generated. Generally, this
|
||||||
will be the upstream maintainer of the project involved. Default is the
|
will be the upstream maintainer of the project involved. Default is the
|
||||||
value of the 'sendemail.to' configuration value; if that is unspecified,
|
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
|
Sending
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
|
||||||
--envelope-sender::
|
--envelope-sender=<address>::
|
||||||
Specify the envelope sender used to send the emails.
|
Specify the envelope sender used to send the emails.
|
||||||
This is useful if your default address is not the address that is
|
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
|
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
|
the 'sendemail.envelopesender' configuration variable; if that is
|
||||||
unspecified, choosing the envelope sender is left to your MTA.
|
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
|
Specify the encryption to use, either 'ssl' or 'tls'. Any other
|
||||||
value reverts to plain SMTP. Default is the value of
|
value reverts to plain SMTP. Default is the value of
|
||||||
'sendemail.smtpencryption'.
|
'sendemail.smtpencryption'.
|
||||||
|
|
||||||
--smtp-pass::
|
--smtp-pass[=<password>]::
|
||||||
Password for SMTP-AUTH. The argument is optional: If no
|
Password for SMTP-AUTH. The argument is optional: If no
|
||||||
argument is specified, then the empty string is used as
|
argument is specified, then the empty string is used as
|
||||||
the password. Default is the value of 'sendemail.smtppass',
|
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
|
specified (with '--smtp-pass' or 'sendemail.smtppass'), then the
|
||||||
user is prompted for a password while the input is masked for privacy.
|
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.
|
If set, specifies the outgoing SMTP server to use (e.g.
|
||||||
`smtp.example.com` or a raw IP address). Alternatively it can
|
`smtp.example.com` or a raw IP address). Alternatively it can
|
||||||
specify a full pathname of a sendmail-like program instead;
|
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
|
`/usr/lib/sendmail` if such program is available, or
|
||||||
`localhost` otherwise.
|
`localhost` otherwise.
|
||||||
|
|
||||||
--smtp-server-port::
|
--smtp-server-port=<port>::
|
||||||
Specifies a port different from the default port (SMTP
|
Specifies a port different from the default port (SMTP
|
||||||
servers typically listen to smtp port 25 and ssmtp port
|
servers typically listen to smtp port 25 and ssmtp port
|
||||||
465). This can be set with 'sendemail.smtpserverport'.
|
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::
|
--smtp-ssl::
|
||||||
Legacy alias for '--smtp-encryption ssl'.
|
Legacy alias for '--smtp-encryption ssl'.
|
||||||
|
|
||||||
--smtp-user::
|
--smtp-user=<user>::
|
||||||
Username for SMTP-AUTH. Default is the value of 'sendemail.smtpuser';
|
Username for SMTP-AUTH. Default is the value of 'sendemail.smtpuser';
|
||||||
if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'),
|
if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'),
|
||||||
then authentication is not attempted.
|
then authentication is not attempted.
|
||||||
|
@ -150,13 +152,13 @@ user is prompted for a password while the input is masked for privacy.
|
||||||
Automating
|
Automating
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
--cc-cmd::
|
--cc-cmd=<command>::
|
||||||
Specify a command to execute once per patch file which
|
Specify a command to execute once per patch file which
|
||||||
should generate patch file specific "Cc:" entries.
|
should generate patch file specific "Cc:" entries.
|
||||||
Output of this command must be single email address per line.
|
Output of this command must be single email address per line.
|
||||||
Default is the value of 'sendemail.cccmd' configuration value.
|
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
|
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
|
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
|
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'
|
entire patch series. Default is the value of the 'sendemail.chainreplyto'
|
||||||
configuration value; if that is unspecified, default to --chain-reply-to.
|
configuration value; if that is unspecified, default to --chain-reply-to.
|
||||||
|
|
||||||
--identity::
|
--identity=<identity>::
|
||||||
A configuration identity. When given, causes values in the
|
A configuration identity. When given, causes values in the
|
||||||
'sendemail.<identity>' subsection to take precedence over
|
'sendemail.<identity>' subsection to take precedence over
|
||||||
values in the 'sendemail' section. The default identity is
|
values in the 'sendemail' section. The default identity is
|
||||||
|
@ -175,7 +177,7 @@ Automating
|
||||||
cc list. Default is the value of 'sendemail.signedoffbycc' configuration
|
cc list. Default is the value of 'sendemail.signedoffbycc' configuration
|
||||||
value; if that is unspecified, default to --signed-off-by-cc.
|
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
|
Specify an additional category of recipients to suppress the
|
||||||
auto-cc of:
|
auto-cc of:
|
||||||
+
|
+
|
||||||
|
@ -212,6 +214,22 @@ specified, as well as 'body' if --no-signed-off-cc is specified.
|
||||||
Administering
|
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::
|
--dry-run::
|
||||||
Do everything except actually send the emails.
|
Do everything except actually send the emails.
|
||||||
|
|
||||||
|
@ -247,7 +265,7 @@ sendemail.aliasesfile::
|
||||||
|
|
||||||
sendemail.aliasfiletype::
|
sendemail.aliasfiletype::
|
||||||
Format of the file(s) specified in sendemail.aliasesfile. Must be
|
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::
|
sendemail.multiedit::
|
||||||
If true (default), a single editor instance will be spawned to edit
|
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
|
summary when '--compose' is used). If false, files will be edited one
|
||||||
after the other, spawning a new editor each time.
|
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
|
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
|
The commands can be executed only by the '-c' option; the shell is not
|
||||||
interactive.
|
interactive.
|
||||||
|
|
||||||
Currently, only three commands are permitted to be called, 'git-receive-pack'
|
Currently, only four commands are permitted to be called, 'git-receive-pack'
|
||||||
'git-upload-pack' with a single required argument or 'cvs server' (to invoke
|
'git-upload-pack' and 'git-upload-archive' with a single required argument, or
|
||||||
'git-cvsserver').
|
'cvs server' (to invoke 'git-cvsserver').
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
|
|
@ -10,6 +10,7 @@ SYNOPSIS
|
||||||
[verse]
|
[verse]
|
||||||
'git show-branch' [--all] [--remotes] [--topo-order] [--current]
|
'git show-branch' [--all] [--remotes] [--topo-order] [--current]
|
||||||
[--more=<n> | --list | --independent | --merge-base]
|
[--more=<n> | --list | --independent | --merge-base]
|
||||||
|
[--color | --no-color]
|
||||||
[--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
|
[--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
|
||||||
'git show-branch' (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]
|
'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
|
When no explicit <ref> parameter is given, it defaults to the
|
||||||
current branch (or `HEAD` if it is detached).
|
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
|
Note that --more, --list, --independent and --merge-base options
|
||||||
are mutually exclusive.
|
are mutually exclusive.
|
||||||
|
|
||||||
|
@ -148,9 +157,10 @@ $ git show-branch master fixes mhf
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
These three branches all forked from a common commit, [master],
|
These three branches all forked from a common commit, [master],
|
||||||
whose commit message is "Add 'git show-branch'. "fixes" branch
|
whose commit message is "Add \'git show-branch\'". The "fixes"
|
||||||
adds one commit 'Introduce "reset type"'. "mhf" branch has many
|
branch adds one commit "Introduce "reset type" flag to "git reset"".
|
||||||
other commits. The current branch is "master".
|
The "mhf" branch adds many other commits. The current branch
|
||||||
|
is "master".
|
||||||
|
|
||||||
|
|
||||||
EXAMPLE
|
EXAMPLE
|
||||||
|
|
|
@ -9,10 +9,12 @@ git-submodule - Initialize, update or inspect submodules
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[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] status [--cached] [--] [<path>...]
|
||||||
'git submodule' [--quiet] init [--] [<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] summary [--summary-limit <n>] [commit] [--] [<path>...]
|
||||||
'git submodule' [--quiet] foreach <command>
|
'git submodule' [--quiet] foreach <command>
|
||||||
'git submodule' [--quiet] sync [--] [<path>...]
|
'git submodule' [--quiet] sync [--] [<path>...]
|
||||||
|
@ -177,6 +179,14 @@ OPTIONS
|
||||||
This option is only valid for the update command.
|
This option is only valid for the update command.
|
||||||
Don't fetch new objects from the remote site.
|
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>...::
|
<path>...::
|
||||||
Paths to submodule(s). When specified this will restrict the command
|
Paths to submodule(s). When specified this will restrict the command
|
||||||
to only operate on the submodules found at the specified paths.
|
to only operate on the submodules found at the specified paths.
|
||||||
|
|
|
@ -85,6 +85,10 @@ COMMANDS
|
||||||
specified, the prefix must include a trailing slash.
|
specified, the prefix must include a trailing slash.
|
||||||
Setting a prefix is useful if you wish to track multiple
|
Setting a prefix is useful if you wish to track multiple
|
||||||
projects that share a common repository.
|
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'::
|
||||||
Fetch unfetched revisions from the Subversion remote we are
|
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
|
makes 'git-log' (even without --date=local) show the same times
|
||||||
that `svn log` would in the local timezone.
|
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
|
This doesn't interfere with interoperating with the Subversion
|
||||||
repository you cloned from, but if you wish for your local Git
|
repository you cloned from, but if you wish for your local Git
|
||||||
repository to be able to interoperate with someone else's 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.
|
the same local timezone.
|
||||||
|
|
||||||
--ignore-paths=<regex>;;
|
--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.
|
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"
|
If the ignore-paths config key is set and the command
|
||||||
and "tags" of first level directories.
|
line option is also given, both regular expressions
|
||||||
|
will be used.
|
||||||
|
|
||||||
Regular expression is not persistent, you should specify
|
Examples:
|
||||||
it every time when fetching.
|
|
||||||
|
--ignore-paths="^doc" - skip "doc*" directory for every
|
||||||
|
fetch.
|
||||||
|
|
||||||
|
--ignore-paths="^[^/]+/(?:branches|tags)" - skip
|
||||||
|
"branches" and "tags" of first level directories.
|
||||||
|
|
||||||
'clone'::
|
'clone'::
|
||||||
Runs 'init' and 'fetch'. It will automatically create a
|
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
|
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::
|
-q::
|
||||||
--quiet::
|
--quiet::
|
||||||
Make 'git-svn' less verbose.
|
Make 'git-svn' less verbose. Specify a second time to make it
|
||||||
|
even less verbose.
|
||||||
|
|
||||||
--repack[=<n>]::
|
--repack[=<n>]::
|
||||||
--repack-flags=<flags>::
|
--repack-flags=<flags>::
|
||||||
|
@ -672,14 +696,14 @@ listed below are allowed:
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
[svn-remote "project-a"]
|
[svn-remote "project-a"]
|
||||||
url = http://server.org/svn
|
url = http://server.org/svn
|
||||||
|
fetch = trunk/project-a:refs/remotes/project-a/trunk
|
||||||
branches = branches/*/project-a:refs/remotes/project-a/branches/*
|
branches = branches/*/project-a:refs/remotes/project-a/branches/*
|
||||||
tags = tags/*/project-a:refs/remotes/project-a/tags/*
|
tags = tags/*/project-a:refs/remotes/project-a/tags/*
|
||||||
trunk = trunk/project-a:refs/remotes/project-a/trunk
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
Keep in mind that the '*' (asterisk) wildcard of the local ref
|
Keep in mind that the '\*' (asterisk) wildcard of the local ref
|
||||||
(right of the ':') *must* be the farthest right path component;
|
(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
|
independent path component (surrounded by '/' or EOL). This
|
||||||
type of configuration is not automatically created by 'init' and
|
type of configuration is not automatically created by 'init' and
|
||||||
should be manually entered with a text-editor or using 'git-config'.
|
should be manually entered with a text-editor or using 'git-config'.
|
||||||
|
|
|
@ -39,12 +39,6 @@ what they are for:
|
||||||
* info/refs
|
* info/refs
|
||||||
|
|
||||||
|
|
||||||
BUGS
|
|
||||||
----
|
|
||||||
When you remove an existing ref, the command fails to update
|
|
||||||
info/refs file unless `--force` flag is given.
|
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Junio C Hamano <gitster@pobox.com>
|
Written by Junio C Hamano <gitster@pobox.com>
|
||||||
|
|
|
@ -9,7 +9,7 @@ git - the stupid content tracker
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git' [--version] [--exec-path[=GIT_EXEC_PATH]]
|
'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]
|
||||||
[-p|--paginate|--no-pager]
|
[-p|--paginate|--no-pager]
|
||||||
[--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
|
[--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
|
||||||
[--help] COMMAND [ARGS]
|
[--help] COMMAND [ARGS]
|
||||||
|
@ -43,9 +43,14 @@ unreleased) version of git, that is available from 'master'
|
||||||
branch of the `git.git` repository.
|
branch of the `git.git` repository.
|
||||||
Documentation for older releases are available here:
|
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
|
* 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:RelNotes-1.6.2.txt[1.6.2].
|
||||||
|
|
||||||
* link:v1.6.1.3/git.html[documentation for release 1.6.1.3]
|
* 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
|
environment variable. If no path is given, 'git' will print
|
||||||
the current setting and then exit.
|
the current setting and then exit.
|
||||||
|
|
||||||
|
--html-path::
|
||||||
|
Print the path to wherever your git HTML documentation is installed
|
||||||
|
and exit.
|
||||||
|
|
||||||
-p::
|
-p::
|
||||||
--paginate::
|
--paginate::
|
||||||
Pipe all output into 'less' (or if set, $PAGER).
|
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:
|
scripting git:
|
||||||
|
|
||||||
* it's preferred to use the non dashed form of git commands, which means that
|
* it's preferred to use the non dashed form of git commands, which means that
|
||||||
you should prefer `"git foo"` to `"git-foo"`.
|
you should prefer `git foo` to `git-foo`.
|
||||||
|
|
||||||
* splitting short options to separate words (prefer `"git foo -a -b"`
|
* splitting short options to separate words (prefer `git foo -a -b`
|
||||||
to `"git foo -ab"`, the latter may not even work).
|
to `git foo -ab`, the latter may not even work).
|
||||||
|
|
||||||
* when a command line option takes an argument, use the 'sticked' form. In
|
* when a command line option takes an argument, use the 'sticked' form. In
|
||||||
other words, write `"git foo -oArg"` instead of `"git foo -o Arg"` for short
|
other words, write `git foo -oArg` instead of `git foo -o Arg` for short
|
||||||
options, and `"git foo --long-opt=Arg"` instead of `"git foo --long-opt Arg"`
|
options, and `git foo --long-opt=Arg` instead of `git foo --long-opt Arg`
|
||||||
for long options. An option that takes optional option-argument must be
|
for long options. An option that takes optional option-argument must be
|
||||||
written in the 'sticked' form.
|
written in the 'sticked' form.
|
||||||
|
|
||||||
* when you give a revision parameter to a command, make sure the parameter is
|
* when you give a revision parameter to a command, make sure the parameter is
|
||||||
not ambiguous with a name of a file in the work tree. E.g. do not write
|
not ambiguous with a name of a file in the work tree. E.g. do not write
|
||||||
`"git log -1 HEAD"` but write `"git log -1 HEAD --"`; the former will not work
|
`git log -1 HEAD` but write `git log -1 HEAD --`; the former will not work
|
||||||
if you happen to have a file called `HEAD` in the work tree.
|
if you happen to have a file called `HEAD` in the work tree.
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,17 +99,17 @@ usage: git-describe [options] <committish>*
|
||||||
|
|
||||||
Negating options
|
Negating options
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
Options with long option names can be negated by prefixing `"--no-"`. For
|
Options with long option names can be negated by prefixing `--no-`. For
|
||||||
example, `"git branch"` has the option `"--track"` which is 'on' by default. You
|
example, `git branch` has the option `--track` which is 'on' by default. You
|
||||||
can use `"--no-track"` to override that behaviour. The same goes for `"--color"`
|
can use `--no-track` to override that behaviour. The same goes for `--color`
|
||||||
and `"--no-color"`.
|
and `--no-color`.
|
||||||
|
|
||||||
|
|
||||||
Aggregating short options
|
Aggregating short options
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
Commands that support the enhanced option parser allow you to aggregate short
|
Commands that support the enhanced option parser allow you to aggregate short
|
||||||
options. This means that you can for example use `"git rm -rf"` or
|
options. This means that you can for example use `git rm -rf` or
|
||||||
`"git clean -fdx"`.
|
`git clean -fdx`.
|
||||||
|
|
||||||
|
|
||||||
Separating argument from the option
|
Separating argument from the option
|
||||||
|
|
|
@ -151,6 +151,10 @@ indicating whether the checkout was a branch checkout (changing branches,
|
||||||
flag=1) or a file checkout (retrieving a file from the index, flag=0).
|
flag=1) or a file checkout (retrieving a file from the index, flag=0).
|
||||||
This hook cannot affect the outcome of 'git-checkout'.
|
This hook cannot affect the outcome of 'git-checkout'.
|
||||||
|
|
||||||
|
It is also run after 'git-clone', unless the --no-checkout (-n) option is
|
||||||
|
used. The first parameter given to the hook is the null-ref, the second the
|
||||||
|
ref of the new HEAD and the flag is always 1.
|
||||||
|
|
||||||
This hook can be used to perform repository validity checks, auto-display
|
This hook can be used to perform repository validity checks, auto-display
|
||||||
differences from the previous HEAD if different, or set working dir metadata
|
differences from the previous HEAD if different, or set working dir metadata
|
||||||
properties.
|
properties.
|
||||||
|
|
|
@ -262,7 +262,7 @@ This commit is referred to as a "merge commit", or sometimes just a
|
||||||
'origin' is used for that purpose. New upstream updates
|
'origin' is used for that purpose. New upstream updates
|
||||||
will be fetched into remote <<def_tracking_branch,tracking branches>> named
|
will be fetched into remote <<def_tracking_branch,tracking branches>> named
|
||||||
origin/name-of-upstream-branch, which you can see using
|
origin/name-of-upstream-branch, which you can see using
|
||||||
"`git branch -r`".
|
`git branch -r`.
|
||||||
|
|
||||||
[[def_pack]]pack::
|
[[def_pack]]pack::
|
||||||
A set of objects which have been compressed into one file (to save space
|
A set of objects which have been compressed into one file (to save space
|
||||||
|
@ -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
|
An <<def_object,object>> which is not <<def_reachable,reachable>> from a
|
||||||
<<def_branch,branch>>, <<def_tag,tag>>, or any other reference.
|
<<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::
|
[[def_working_tree]]working tree::
|
||||||
The tree of actual checked out files. The working tree is
|
The tree of actual checked out files. The working tree is
|
||||||
normally equal to the <<def_HEAD,HEAD>> plus any local changes
|
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 -->
|
<!-- manpage-1.72.xsl:
|
||||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
special settings for manpages rendered from asciidoc+docbook
|
||||||
|
handles peculiarities in docbook-xsl 1.72.0 -->
|
||||||
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
version="1.0">
|
||||||
|
|
||||||
<xsl:param name="man.output.quietly" select="1"/>
|
<xsl:import href="manpage-base.xsl"/>
|
||||||
<xsl:param name="refentry.meta.get.quietly" select="1"/>
|
|
||||||
|
|
||||||
<xsl:template match="co">
|
<!-- these are the special values for the roff control characters
|
||||||
<xsl:value-of select="concat('▓fB(',substring-after(@id,'-'),')▓fR')"/>
|
needed for docbook-xsl 1.72.0 -->
|
||||||
</xsl:template>
|
<xsl:param name="git.docbook.backslash">▓</xsl:param>
|
||||||
<xsl:template match="calloutlist">
|
<xsl:param name="git.docbook.dot" >⌂</xsl:param>
|
||||||
<xsl:text>⌂sp </xsl:text>
|
|
||||||
<xsl:apply-templates/>
|
|
||||||
<xsl:text> </xsl:text>
|
|
||||||
</xsl:template>
|
|
||||||
<xsl:template match="callout">
|
|
||||||
<xsl:value-of select="concat('▓fB',substring-after(@arearefs,'-'),'. ▓fR')"/>
|
|
||||||
<xsl:apply-templates/>
|
|
||||||
<xsl:text>⌂br </xsl:text>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
</xsl:stylesheet>
|
</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 </xsl:text>
|
||||||
|
<xsl:apply-templates/>
|
||||||
|
<xsl:text> </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 </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> </xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
|
@ -22,7 +22,8 @@ merge.stat::
|
||||||
merge.tool::
|
merge.tool::
|
||||||
Controls which merge resolution program is used by
|
Controls which merge resolution program is used by
|
||||||
linkgit:git-mergetool[1]. Valid built-in values are: "kdiff3",
|
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
|
"opendiff". Any other value is treated is custom merge tool
|
||||||
and there must be a corresponding mergetool.<tool>.cmd option.
|
and there must be a corresponding mergetool.<tool>.cmd option.
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@ MERGE STRATEGIES
|
||||||
|
|
||||||
resolve::
|
resolve::
|
||||||
This can only resolve two heads (i.e. the current branch
|
This can only resolve two heads (i.e. the current branch
|
||||||
and another branch you pulled from) using 3-way merge
|
and another branch you pulled from) using a 3-way merge
|
||||||
algorithm. It tries to carefully detect criss-cross
|
algorithm. It tries to carefully detect criss-cross
|
||||||
merge ambiguities and is considered generally safe and
|
merge ambiguities and is considered generally safe and
|
||||||
fast.
|
fast.
|
||||||
|
|
||||||
recursive::
|
recursive::
|
||||||
This can only resolve two heads using 3-way merge
|
This can only resolve two heads using a 3-way merge
|
||||||
algorithm. When there are more than one common
|
algorithm. When there is more than one common
|
||||||
ancestors that can be used for 3-way merge, it creates a
|
ancestor that can be used for 3-way merge, it creates a
|
||||||
merged tree of the common ancestors and uses that as
|
merged tree of the common ancestors and uses that as
|
||||||
the reference tree for the 3-way merge. This has been
|
the reference tree for the 3-way merge. This has been
|
||||||
reported to result in fewer merge conflicts without
|
reported to result in fewer merge conflicts without
|
||||||
|
@ -22,11 +22,11 @@ recursive::
|
||||||
pulling or merging one branch.
|
pulling or merging one branch.
|
||||||
|
|
||||||
octopus::
|
octopus::
|
||||||
This resolves more than two-head case, but refuses to do
|
This resolves cases with more than two heads, but refuses to do
|
||||||
complex merge that needs manual resolution. It is
|
a complex merge that needs manual resolution. It is
|
||||||
primarily meant to be used for bundling topic branch
|
primarily meant to be used for bundling topic branch
|
||||||
heads together. This is the default merge strategy when
|
heads together. This is the default merge strategy when
|
||||||
pulling or merging more than one branches.
|
pulling or merging more than one branch.
|
||||||
|
|
||||||
ours::
|
ours::
|
||||||
This resolves any number of heads, but the result of the
|
This resolves any number of heads, but the result of the
|
||||||
|
|
|
@ -121,6 +121,7 @@ The placeholders are:
|
||||||
- '%d': ref names, like the --decorate option of linkgit:git-log[1]
|
- '%d': ref names, like the --decorate option of linkgit:git-log[1]
|
||||||
- '%e': encoding
|
- '%e': encoding
|
||||||
- '%s': subject
|
- '%s': subject
|
||||||
|
- '%f': sanitized subject line, suitable for a filename
|
||||||
- '%b': body
|
- '%b': body
|
||||||
- '%Cred': switch color to red
|
- '%Cred': switch color to red
|
||||||
- '%Cgreen': switch color to green
|
- '%Cgreen': switch color to green
|
||||||
|
@ -152,3 +153,12 @@ $ git log -2 --pretty=tformat:%h 4da45bef \
|
||||||
4da45be
|
4da45be
|
||||||
7134973
|
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>']::
|
--pretty[='<format>']::
|
||||||
|
--format[='<format>']::
|
||||||
|
|
||||||
Pretty-print the contents of the commit logs in a given format,
|
Pretty-print the contents of the commit logs in a given format,
|
||||||
where '<format>' can be one of 'oneline', 'short', 'medium',
|
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
|
This should make "--pretty=oneline" a whole lot more readable for
|
||||||
people using 80-column terminals.
|
people using 80-column terminals.
|
||||||
|
|
||||||
|
--oneline::
|
||||||
|
This is a shorthand for "--pretty=oneline --abbrev-commit"
|
||||||
|
used together.
|
||||||
|
|
||||||
--encoding[=<encoding>]::
|
--encoding[=<encoding>]::
|
||||||
The commit objects record the encoding used for the log message
|
The commit objects record the encoding used for the log message
|
||||||
in their encoding header; this option can be used to tell the
|
in their encoding header; this option can be used to tell the
|
||||||
|
|
|
@ -140,38 +140,38 @@ limiting may be applied.
|
||||||
--
|
--
|
||||||
|
|
||||||
-n 'number'::
|
-n 'number'::
|
||||||
--max-count='number'::
|
--max-count=<number>::
|
||||||
|
|
||||||
Limit the number of commits output.
|
Limit the number of commits output.
|
||||||
|
|
||||||
--skip='number'::
|
--skip=<number>::
|
||||||
|
|
||||||
Skip 'number' commits before starting to show the commit output.
|
Skip 'number' commits before starting to show the commit output.
|
||||||
|
|
||||||
--since='date'::
|
--since=<date>::
|
||||||
--after='date'::
|
--after=<date>::
|
||||||
|
|
||||||
Show commits more recent than a specific date.
|
Show commits more recent than a specific date.
|
||||||
|
|
||||||
--until='date'::
|
--until=<date>::
|
||||||
--before='date'::
|
--before=<date>::
|
||||||
|
|
||||||
Show commits older than a specific date.
|
Show commits older than a specific date.
|
||||||
|
|
||||||
ifdef::git-rev-list[]
|
ifdef::git-rev-list[]
|
||||||
--max-age='timestamp'::
|
--max-age=<timestamp>::
|
||||||
--min-age='timestamp'::
|
--min-age=<timestamp>::
|
||||||
|
|
||||||
Limit the commits output to specified time range.
|
Limit the commits output to specified time range.
|
||||||
endif::git-rev-list[]
|
endif::git-rev-list[]
|
||||||
|
|
||||||
--author='pattern'::
|
--author=<pattern>::
|
||||||
--committer='pattern'::
|
--committer=<pattern>::
|
||||||
|
|
||||||
Limit the commits output to ones with author/committer
|
Limit the commits output to ones with author/committer
|
||||||
header lines that match the specified pattern (regular expression).
|
header lines that match the specified pattern (regular expression).
|
||||||
|
|
||||||
--grep='pattern'::
|
--grep=<pattern>::
|
||||||
|
|
||||||
Limit the commits output to ones with log message that
|
Limit the commits output to ones with log message that
|
||||||
matches the specified pattern (regular expression).
|
matches the specified pattern (regular expression).
|
||||||
|
|
|
@ -66,6 +66,12 @@ Steps to parse options
|
||||||
non-option arguments in `argv[]`.
|
non-option arguments in `argv[]`.
|
||||||
`argc` is updated appropriately because of the assignment.
|
`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:
|
Flags are the bitwise-or of:
|
||||||
|
|
||||||
`PARSE_OPT_KEEP_DASHDASH`::
|
`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
|
Using this flag, processing is stopped at the first non-option
|
||||||
argument.
|
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
|
Data Structure
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
@ -109,6 +137,10 @@ There are some macros to easily define options:
|
||||||
Introduce a boolean option.
|
Introduce a boolean option.
|
||||||
If used, `int_var` is bitwise-ored with `mask`.
|
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)`::
|
`OPT_SET_INT(short, long, &int_var, description, integer)`::
|
||||||
Introduce a boolean option.
|
Introduce a boolean option.
|
||||||
If used, set `int_var` to `integer`.
|
If used, set `int_var` to `integer`.
|
||||||
|
@ -138,6 +170,14 @@ There are some macros to easily define options:
|
||||||
`OPT_ARGUMENT(long, description)`::
|
`OPT_ARGUMENT(long, description)`::
|
||||||
Introduce a long-option argument that will be kept in `argv[]`.
|
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()`.
|
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:
|
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`.
|
given by `opt` is the void pointer `opt->value`.
|
||||||
`\*opt->value` will be the value that is saved into `var`, if you
|
`\*opt->value` will be the value that is saved into `var`, if you
|
||||||
use `OPT_CALLBACK()`.
|
use `OPT_CALLBACK()`.
|
||||||
|
|
|
@ -188,7 +188,7 @@ As you can see, a commit shows who made the latest change, what they
|
||||||
did, and why.
|
did, and why.
|
||||||
|
|
||||||
Every commit has a 40-hexdigit id, sometimes called the "object name" or the
|
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
|
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
|
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
|
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
|
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
|
accept an arbitrary commit; for example, you can check out the commit
|
||||||
referenced by a tag:
|
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
|
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:
|
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].
|
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
|
Updating a repository with git fetch
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
|
||||||
Eventually the developer cloned from will do additional work in her
|
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
|
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
|
$ git branch -r
|
||||||
|
@ -516,7 +516,7 @@ $ git bisect reset
|
||||||
|
|
||||||
to return you to the branch you were on before.
|
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
|
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,
|
version if you think it would be a good idea. For example,
|
||||||
occasionally you may land on a commit that broke something unrelated;
|
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:
|
commits:
|
||||||
|
|
||||||
Merges (to be discussed later), as well as operations such as
|
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.
|
set ORIG_HEAD to the value HEAD had before the current operation.
|
||||||
|
|
||||||
The git-fetch operation always stores the head of the last fetched
|
The `git fetch` operation always stores the head of the last fetched
|
||||||
branch in FETCH_HEAD. For example, if you run git fetch without
|
branch in FETCH_HEAD. For example, if you run `git fetch` without
|
||||||
specifying a local branch as the target of the operation
|
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
|
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:
|
of all the given commits:
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
@ -1073,9 +1073,9 @@ $ git diff
|
||||||
|
|
||||||
shows the difference between the working tree and the index file.
|
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
|
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
|
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.
|
A project will often generate files that you do 'not' want to track with git.
|
||||||
This typically includes files generated by a build process or temporary
|
This typically includes files generated by a build process or temporary
|
||||||
backup files made by your editor. Of course, 'not' tracking files with git
|
backup files made by your editor. Of course, 'not' tracking files with git
|
||||||
is just a matter of 'not' calling "`git-add`" on them. But it quickly becomes
|
is just a matter of 'not' calling `git add` on them. But it quickly becomes
|
||||||
annoying to have these untracked files lying around; e.g. they make
|
annoying to have these untracked files lying around; e.g. they make
|
||||||
"`git add .`" practically useless, and they keep showing up in the output of
|
`git add .` practically useless, and they keep showing up in the output of
|
||||||
"`git status`".
|
`git status`.
|
||||||
|
|
||||||
You can tell git to ignore certain files by creating a file called .gitignore
|
You can tell git to ignore certain files by creating a file called .gitignore
|
||||||
in the top level of your working directory, with contents such as:
|
in the top level of your working directory, with contents such as:
|
||||||
|
@ -1349,7 +1349,7 @@ $ git add file.txt
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
the different stages of that file will be "collapsed", after which
|
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]]
|
||||||
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
|
If the problematic commit is the most recent commit, and you have not
|
||||||
yet made that commit public, then you may just
|
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
|
Alternatively, you
|
||||||
can edit the working directory and update the index to fix your
|
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
|
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
|
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
|
branches, but it has quite different behavior if it is given a path
|
||||||
name: the command
|
name: the command
|
||||||
|
|
||||||
|
@ -1542,7 +1542,7 @@ $ git gc
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
to recompress the archive. This can be very time-consuming, so
|
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]]
|
[[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
|
suppose you delete a branch, then realize you need the history it
|
||||||
contained. The reflog is also deleted; however, if you have not yet
|
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
|
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.
|
<<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
|
Getting updates with git pull
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
After you clone a repository and make a few changes of your own, you
|
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
|
<<fast-forwards,fast forward>>; instead, your branch will just be
|
||||||
updated to point to the latest commit from the upstream branch.)
|
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
|
in which case it just merges in a branch from the current repository; so
|
||||||
the commands
|
the commands
|
||||||
|
|
||||||
|
@ -1795,7 +1795,7 @@ Public git repositories
|
||||||
Another way to submit changes to a project is to tell the maintainer
|
Another way to submit changes to a project is to tell the maintainer
|
||||||
of that project to pull the changes from your repository using
|
of that project to pull the changes from your repository using
|
||||||
linkgit:git-pull[1]. In the section "<<getting-updates-With-git-pull,
|
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
|
updates from the "main" repository, but it works just as well in the
|
||||||
other direction.
|
other direction.
|
||||||
|
|
||||||
|
@ -1847,7 +1847,7 @@ Setting up a public repository
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Assume your personal repository is in the directory ~/proj. We
|
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:
|
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
|
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
|
listen on port 9418. By default, it will allow access to any directory
|
||||||
that looks like a git directory and contains the magic file
|
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.
|
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
|
linkgit:git-daemon[1] man page for details. (See especially the
|
||||||
examples section.)
|
examples section.)
|
||||||
|
|
||||||
|
@ -1942,7 +1942,7 @@ or just
|
||||||
$ git push ssh://yourserver.com/~you/proj.git master
|
$ 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
|
<<fast-forwards,fast forward>>; see the following section for details on
|
||||||
handling this case.
|
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
|
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!
|
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
|
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:
|
This can happen, for example, if you:
|
||||||
|
|
||||||
- use `git-reset --hard` to remove already-published commits, or
|
- use `git reset --hard` to remove already-published commits, or
|
||||||
- use `git-commit --amend` to replace already-published commits
|
- use `git commit --amend` to replace already-published commits
|
||||||
(as in <<fixing-a-mistake-by-rewriting-history>>), or
|
(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>>).
|
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:
|
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
|
- Git's ability to quickly import and merge patches allows a
|
||||||
single maintainer to process incoming changes even at very
|
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
|
an easy way for that maintainer to delegate this job to other
|
||||||
maintainers while still allowing optional review of incoming
|
maintainers while still allowing optional review of incoming
|
||||||
changes.
|
changes.
|
||||||
|
@ -2404,7 +2404,7 @@ use them, and then explain some of the problems that can arise because
|
||||||
you are rewriting history.
|
you are rewriting history.
|
||||||
|
|
||||||
[[using-git-rebase]]
|
[[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
|
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
|
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
|
to update the index with those contents, and then, instead of
|
||||||
running git-commit, just run
|
running `git commit`, just run
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
$ git rebase --continue
|
$ git rebase --continue
|
||||||
|
@ -2508,7 +2508,7 @@ with
|
||||||
$ git tag bad mywork~5
|
$ 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
|
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
|
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,
|
and browse through the list of patches in the mywork branch using gitk,
|
||||||
applying them (possibly in a different order) to mywork-new using
|
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
|
The linkgit:git-gui[1] command may also help as it allows you to
|
||||||
individually select diff hunks for inclusion in the index (by
|
individually select diff hunks for inclusion in the index (by
|
||||||
right-clicking on the diff hunk and choosing "Stage Hunk for Commit").
|
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:
|
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
|
linkgit:git-bisect[1] identifies C as the culprit, how will you
|
||||||
figure out that the problem is due to this change in semantics?
|
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.
|
normally be able to discover the problem by examining just that commit.
|
||||||
Developers can make this easy by breaking their changes into small
|
Developers can make this easy by breaking their changes into small
|
||||||
self-contained commits. That won't help in the case above, however,
|
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
|
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
|
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 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
|
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
|
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
|
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
|
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.
|
them.
|
||||||
|
|
||||||
[[forcing-fetch]]
|
[[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
|
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
|
We already saw in <<understanding-commits>> that all commits are stored
|
||||||
under a 40-digit "object name". In fact, all the information needed to
|
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.
|
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
|
In each case the name is calculated by taking the SHA-1 hash of the
|
||||||
contents of the object. The SHA1 hash is a cryptographic hash function.
|
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
|
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
|
objects with the same name. This has a number of advantages; among
|
||||||
others:
|
others:
|
||||||
|
@ -2877,10 +2877,10 @@ others:
|
||||||
same content stored in two repositories will always be stored under
|
same content stored in two repositories will always be stored under
|
||||||
the same name.
|
the same name.
|
||||||
- Git can detect errors when it reads an object, by checking that the
|
- 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
|
(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
|
There are four different types of objects: "blob", "tree", "commit", and
|
||||||
"tag".
|
"tag".
|
||||||
|
@ -2926,9 +2926,9 @@ committer Junio C Hamano <gitster@pobox.com> 1187591163 -0700
|
||||||
|
|
||||||
As you can see, a commit is defined by:
|
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.
|
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
|
immediately previous step(s) in the history of the project. The
|
||||||
example above has one parent; merge commits may have more than
|
example above has one parent; merge commits may have more than
|
||||||
one. A commit with no parents is called a "root" commit, and
|
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
|
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 contents of a single directory tree.
|
||||||
|
|
||||||
The object type may be a blob, representing the contents of a file, or
|
The object type may be a blob, representing the contents of a file, or
|
||||||
another tree, representing the contents of a subdirectory. Since trees
|
another tree, representing the contents of a subdirectory. Since trees
|
||||||
and blobs, like all other objects, are named by the SHA1 hash of their
|
and blobs, like all other objects, are named by the SHA-1 hash of their
|
||||||
contents, two trees have the same SHA1 name if and only if their
|
contents, two trees have the same SHA-1 name if and only if their
|
||||||
contents (including, recursively, the contents of all subdirectories)
|
contents (including, recursively, the contents of all subdirectories)
|
||||||
are identical. This allows git to quickly determine the differences
|
are identical. This allows git to quickly determine the differences
|
||||||
between two related tree objects, since it can ignore any entries with
|
between two related tree objects, since it can ignore any entries with
|
||||||
|
@ -3029,15 +3029,15 @@ currently checked out.
|
||||||
Trust
|
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
|
from another (possibly untrusted) source, you can still trust that those
|
||||||
contents are correct as long as the SHA1 name agrees. This is because
|
contents are correct as long as the SHA-1 name agrees. This is because
|
||||||
the SHA1 is designed so that it is infeasible to find different contents
|
the SHA-1 is designed so that it is infeasible to find different contents
|
||||||
that produce the same hash.
|
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
|
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
|
can easily verify the entire history of commits reachable through
|
||||||
parents of that commit, and all of those contents of the trees referred
|
parents of that commit, and all of those contents of the trees referred
|
||||||
to by those commits.
|
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.
|
commits tells others that they can trust the whole history.
|
||||||
|
|
||||||
In other words, you can easily validate a whole archive by just
|
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
|
of the top commit, and digitally sign that email using something
|
||||||
like GPG/PGP.
|
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
|
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
|
Unfortunately this system becomes inefficient once a project has a
|
||||||
lot of objects. Try this on an old project:
|
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
|
to remove any of the "loose" objects that are now contained in the
|
||||||
pack. This will also remove any unreferenced objects (which may be
|
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
|
You can verify that the loose objects are gone by looking at the
|
||||||
.git/objects directory or by running
|
.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.
|
pointer itself just doesn't, since you replaced it with another one.
|
||||||
|
|
||||||
There are also other situations that cause dangling objects. For
|
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
|
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
|
bigger picture, you changed something else in that file and committed
|
||||||
that *updated* thing--the old state that you added originally ends up
|
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
|
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
|
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
|
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
|
leaving _some_ of the new objects in the object database, but just
|
||||||
dangling and useless.
|
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
|
repository--it's kind of like doing a filesystem fsck recovery: you
|
||||||
don't want to do that while the filesystem is mounted.
|
don't want to do that while the filesystem is mounted.
|
||||||
|
|
||||||
(The same is true of "git-fsck" itself, btw, but since
|
(The same is true of "git fsck" itself, btw, but since
|
||||||
git-fsck never actually *changes* the repository, it just reports
|
`git fsck` never actually *changes* the repository, it just reports
|
||||||
on what it found, git-fsck itself is never "dangerous" to run.
|
on what it found, `git fsck` itself is never 'dangerous' to run.
|
||||||
Running it while somebody is actually changing the repository can cause
|
Running it while somebody is actually changing the repository can cause
|
||||||
confusing and scary messages, but it won't actually do anything bad. In
|
confusing and scary messages, but it won't actually do anything bad. In
|
||||||
contrast, running "git prune" while somebody is actively changing the
|
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
|
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
|
extremely lucky it might be 4b9458b3786228369c63936db65827de3cc06200, in
|
||||||
which case you've guessed right, and the corruption is fixed!
|
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
|
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:
|
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!
|
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
|
$ ls -a
|
||||||
. .. .git .gitmodules a b c d
|
. .. .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
|
- It clones the submodule from <repo> to the given <path> under the
|
||||||
current directory and by default checks out the master branch.
|
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
|
$ 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:
|
commits specified in the superproject:
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
@ -3552,8 +3552,8 @@ $ ls -a
|
||||||
. .. .git a.txt
|
. .. .git a.txt
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
One major difference between `git-submodule update` and `git-submodule add` is
|
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
|
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
|
of a branch. It's like checking out a tag: the head is detached, so you're not
|
||||||
working on a branch.
|
working on a branch.
|
||||||
|
|
||||||
|
@ -3754,7 +3754,7 @@ unsaved state that you might want to restore later!) your current
|
||||||
index. Normal operation is just
|
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
|
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
|
files. This is not a very common operation, since normally you'd just
|
||||||
keep your files updated, and rather than write to your working
|
keep your files updated, and rather than write to your working
|
||||||
directory, you'd tell the index files about the changes in your
|
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
|
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
|
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`.
|
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
|
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
|
need to use the "-f" flag ('before' the "-a" flag or the filename) to
|
||||||
'force' the checkout.
|
'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
|
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).
|
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,
|
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
|
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
|
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
|
to show its contents. NOTE! Trees have binary content, and as a result
|
||||||
there is a special helper for showing that content, called
|
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.
|
readable form.
|
||||||
|
|
||||||
It's especially instructive to look at "commit" objects, since those
|
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
|
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
|
filename. The 'stage number' is git's way to say which tree it
|
||||||
came from: stage 1 corresponds to `$orig` tree, stage 2 `HEAD`
|
came from: stage 1 corresponds to `$orig` tree, stage 2 `HEAD`
|
||||||
tree, and stage3 `$target` tree.
|
tree, and stage3 `$target` tree.
|
||||||
|
|
||||||
Earlier we said that trivial merges are done inside
|
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` nor `$target`, or if the file changed
|
||||||
from `$orig` to `HEAD` and `$orig` to `$target` the same way,
|
from `$orig` to `HEAD` and `$orig` to `$target` the same way,
|
||||||
obviously the final outcome is what is in `HEAD`. What the
|
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
|
$ 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.
|
that path tells git to mark the path resolved.
|
||||||
|
|
||||||
The above is the description of a git merge at the lowest level,
|
The above is the description of a git merge at the lowest level,
|
||||||
to help you understand what conceptually happens under the hood.
|
to help you understand what conceptually happens under the hood.
|
||||||
In practice, nobody, not even git itself, runs `git-cat-file` three times
|
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
|
for this. There is a `git merge-index` program that extracts the
|
||||||
stages to temporary files and calls a "merge" script on it:
|
stages to temporary files and calls a "merge" script on it:
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
$ git merge-index git-merge-one-file hello.c
|
$ 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]]
|
||||||
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
|
Regardless of object type, all objects share the following
|
||||||
characteristics: they are all deflated with zlib, and have a header
|
characteristics: they are all deflated with zlib, and have a header
|
||||||
that not only specifies their type, but also provides size information
|
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
|
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
|
plus this header, so `sha1sum` 'file' does not match the object name
|
||||||
for 'file'.
|
for 'file'.
|
||||||
(Historical note: in the dawn of the age of git the hash
|
(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
|
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
|
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
|
The structured objects can further have their structure and
|
||||||
connectivity to other objects verified. This is generally done with
|
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
|
of all objects, and verifies their internal consistency (in addition
|
||||||
to just verifying their superficial consistency through the hash).
|
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:
|
This is just to get you into the groove for the most libified part of Git:
|
||||||
the revision walker.
|
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 "$@") | \
|
$ 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?
|
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,
|
_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
|
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
|
options that were relevant for the different plumbing commands that were
|
||||||
called by the script.
|
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
|
`revision.h`. It wraps the options in a struct named `rev_info`, which
|
||||||
controls how and what revisions are walked, and more.
|
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
|
`setup_revisions()`, which parses the revisions and the common command line
|
||||||
options for the revision walker. This information is stored in the struct
|
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
|
`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
|
`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).
|
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
|
command `git`. The source side of a builtin is
|
||||||
|
|
||||||
- a function called `cmd_<bla>`, typically defined in `builtin-<bla>.c`,
|
- 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
|
_not_ named like the `.c` file in which they live have to be listed in
|
||||||
`BUILT_INS` in the `Makefile`.
|
`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.
|
but that allows for a much greater flexibility and performance.
|
||||||
|
|
||||||
Here again it is a good point to take a pause.
|
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
|
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
|
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
|
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
|
- is plumbing, and
|
||||||
|
|
||||||
|
@ -4198,7 +4198,7 @@ it does.
|
||||||
------------------------------------------------------------------
|
------------------------------------------------------------------
|
||||||
git_config(git_default_config);
|
git_config(git_default_config);
|
||||||
if (argc != 3)
|
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))
|
if (get_sha1(argv[2], sha1))
|
||||||
die("Not a valid object name %s", argv[2]);
|
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,
|
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.
|
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
|
do not remember where it was (yes, you _could_ `git grep bundle t/`, but that
|
||||||
does not illustrate the point!):
|
does not illustrate the point!):
|
||||||
|
|
||||||
|
@ -4530,7 +4530,7 @@ The basic requirements:
|
||||||
- Whenever possible, section headings should clearly describe the task
|
- Whenever possible, section headings should clearly describe the task
|
||||||
they explain how to do, in language that requires no more knowledge
|
they explain how to do, in language that requires no more knowledge
|
||||||
than necessary: for example, "importing patches into a project" rather
|
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
|
Think about how to create a clear chapter dependency graph that will
|
||||||
allow people to get to important topics without necessarily reading
|
allow people to get to important topics without necessarily reading
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
GVF=GIT-VERSION-FILE
|
GVF=GIT-VERSION-FILE
|
||||||
DEF_VER=v1.6.2.5
|
DEF_VER=v1.6.3.GIT
|
||||||
|
|
||||||
LF='
|
LF='
|
||||||
'
|
'
|
||||||
|
|
129
Makefile
129
Makefile
|
@ -126,6 +126,12 @@ all::
|
||||||
# randomly break unless your underlying filesystem supports those sub-second
|
# randomly break unless your underlying filesystem supports those sub-second
|
||||||
# times (my ext3 doesn't).
|
# times (my ext3 doesn't).
|
||||||
#
|
#
|
||||||
|
# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
|
||||||
|
# "st_ctim"
|
||||||
|
#
|
||||||
|
# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
|
||||||
|
# available. This automatically turns USE_NSEC off.
|
||||||
|
#
|
||||||
# Define USE_STDEV below if you want git to care about the underlying device
|
# Define USE_STDEV below if you want git to care about the underlying device
|
||||||
# change being considered an inode change from the update-index perspective.
|
# change being considered an inode change from the update-index perspective.
|
||||||
#
|
#
|
||||||
|
@ -139,6 +145,8 @@ all::
|
||||||
# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
|
# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
|
||||||
# MakeMaker (e.g. using ActiveState under Cygwin).
|
# 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.
|
# Define NO_TCLTK if you do not want Tcl/Tk GUI.
|
||||||
#
|
#
|
||||||
# The TCL_PATH variable governs the location of the Tcl interpreter
|
# 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
|
# 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
|
# 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).
|
# 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
|
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
||||||
@$(SHELL_PATH) ./GIT-VERSION-GEN
|
@$(SHELL_PATH) ./GIT-VERSION-GEN
|
||||||
|
@ -209,6 +228,7 @@ ETC_GITCONFIG = etc/gitconfig
|
||||||
endif
|
endif
|
||||||
lib = lib
|
lib = lib
|
||||||
# DESTDIR=
|
# DESTDIR=
|
||||||
|
pathsep = :
|
||||||
|
|
||||||
# default configuration for gitweb
|
# default configuration for gitweb
|
||||||
GITWEB_CONFIG = gitweb_config.perl
|
GITWEB_CONFIG = gitweb_config.perl
|
||||||
|
@ -257,14 +277,28 @@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
|
||||||
BASIC_CFLAGS =
|
BASIC_CFLAGS =
|
||||||
BASIC_LDFLAGS =
|
BASIC_LDFLAGS =
|
||||||
|
|
||||||
|
# Guard against environment variables
|
||||||
|
BUILTIN_OBJS =
|
||||||
|
BUILT_INS =
|
||||||
|
COMPAT_CFLAGS =
|
||||||
|
COMPAT_OBJS =
|
||||||
|
LIB_H =
|
||||||
|
LIB_OBJS =
|
||||||
|
PROGRAMS =
|
||||||
|
SCRIPT_PERL =
|
||||||
|
SCRIPT_SH =
|
||||||
|
TEST_PROGRAMS =
|
||||||
|
|
||||||
SCRIPT_SH += git-am.sh
|
SCRIPT_SH += git-am.sh
|
||||||
SCRIPT_SH += git-bisect.sh
|
SCRIPT_SH += git-bisect.sh
|
||||||
|
SCRIPT_SH += git-difftool--helper.sh
|
||||||
SCRIPT_SH += git-filter-branch.sh
|
SCRIPT_SH += git-filter-branch.sh
|
||||||
SCRIPT_SH += git-lost-found.sh
|
SCRIPT_SH += git-lost-found.sh
|
||||||
SCRIPT_SH += git-merge-octopus.sh
|
SCRIPT_SH += git-merge-octopus.sh
|
||||||
SCRIPT_SH += git-merge-one-file.sh
|
SCRIPT_SH += git-merge-one-file.sh
|
||||||
SCRIPT_SH += git-merge-resolve.sh
|
SCRIPT_SH += git-merge-resolve.sh
|
||||||
SCRIPT_SH += git-mergetool.sh
|
SCRIPT_SH += git-mergetool.sh
|
||||||
|
SCRIPT_SH += git-mergetool--lib.sh
|
||||||
SCRIPT_SH += git-parse-remote.sh
|
SCRIPT_SH += git-parse-remote.sh
|
||||||
SCRIPT_SH += git-pull.sh
|
SCRIPT_SH += git-pull.sh
|
||||||
SCRIPT_SH += git-quiltimport.sh
|
SCRIPT_SH += git-quiltimport.sh
|
||||||
|
@ -278,6 +312,7 @@ SCRIPT_SH += git-submodule.sh
|
||||||
SCRIPT_SH += git-web--browse.sh
|
SCRIPT_SH += git-web--browse.sh
|
||||||
|
|
||||||
SCRIPT_PERL += git-add--interactive.perl
|
SCRIPT_PERL += git-add--interactive.perl
|
||||||
|
SCRIPT_PERL += git-difftool.perl
|
||||||
SCRIPT_PERL += git-archimport.perl
|
SCRIPT_PERL += git-archimport.perl
|
||||||
SCRIPT_PERL += git-cvsexportcommit.perl
|
SCRIPT_PERL += git-cvsexportcommit.perl
|
||||||
SCRIPT_PERL += git-cvsimport.perl
|
SCRIPT_PERL += git-cvsimport.perl
|
||||||
|
@ -333,7 +368,7 @@ BUILT_INS += git-whatchanged$X
|
||||||
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
|
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
|
||||||
|
|
||||||
# what 'all' will build but not install in gitexecdir
|
# 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.
|
# Set paths to tools early so that they can be used for version tests.
|
||||||
ifndef SHELL_PATH
|
ifndef SHELL_PATH
|
||||||
|
@ -412,6 +447,7 @@ LIB_OBJS += archive-tar.o
|
||||||
LIB_OBJS += archive-zip.o
|
LIB_OBJS += archive-zip.o
|
||||||
LIB_OBJS += attr.o
|
LIB_OBJS += attr.o
|
||||||
LIB_OBJS += base85.o
|
LIB_OBJS += base85.o
|
||||||
|
LIB_OBJS += bisect.o
|
||||||
LIB_OBJS += blob.o
|
LIB_OBJS += blob.o
|
||||||
LIB_OBJS += branch.o
|
LIB_OBJS += branch.o
|
||||||
LIB_OBJS += bundle.o
|
LIB_OBJS += bundle.o
|
||||||
|
@ -512,6 +548,7 @@ BUILTIN_OBJS += builtin-add.o
|
||||||
BUILTIN_OBJS += builtin-annotate.o
|
BUILTIN_OBJS += builtin-annotate.o
|
||||||
BUILTIN_OBJS += builtin-apply.o
|
BUILTIN_OBJS += builtin-apply.o
|
||||||
BUILTIN_OBJS += builtin-archive.o
|
BUILTIN_OBJS += builtin-archive.o
|
||||||
|
BUILTIN_OBJS += builtin-bisect--helper.o
|
||||||
BUILTIN_OBJS += builtin-blame.o
|
BUILTIN_OBJS += builtin-blame.o
|
||||||
BUILTIN_OBJS += builtin-branch.o
|
BUILTIN_OBJS += builtin-branch.o
|
||||||
BUILTIN_OBJS += builtin-bundle.o
|
BUILTIN_OBJS += builtin-bundle.o
|
||||||
|
@ -655,6 +692,7 @@ ifeq ($(uname_S),Darwin)
|
||||||
endif
|
endif
|
||||||
NO_MEMMEM = YesPlease
|
NO_MEMMEM = YesPlease
|
||||||
THREADED_DELTA_SEARCH = YesPlease
|
THREADED_DELTA_SEARCH = YesPlease
|
||||||
|
USE_ST_TIMESPEC = YesPlease
|
||||||
endif
|
endif
|
||||||
ifeq ($(uname_S),SunOS)
|
ifeq ($(uname_S),SunOS)
|
||||||
NEEDS_SOCKET = YesPlease
|
NEEDS_SOCKET = YesPlease
|
||||||
|
@ -704,6 +742,7 @@ ifeq ($(uname_S),FreeBSD)
|
||||||
BASIC_CFLAGS += -I/usr/local/include
|
BASIC_CFLAGS += -I/usr/local/include
|
||||||
BASIC_LDFLAGS += -L/usr/local/lib
|
BASIC_LDFLAGS += -L/usr/local/lib
|
||||||
DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
|
DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
|
||||||
|
USE_ST_TIMESPEC = YesPlease
|
||||||
THREADED_DELTA_SEARCH = YesPlease
|
THREADED_DELTA_SEARCH = YesPlease
|
||||||
ifeq ($(shell expr "$(uname_R)" : '4\.'),2)
|
ifeq ($(shell expr "$(uname_R)" : '4\.'),2)
|
||||||
PTHREAD_LIBS = -pthread
|
PTHREAD_LIBS = -pthread
|
||||||
|
@ -714,6 +753,7 @@ endif
|
||||||
ifeq ($(uname_S),OpenBSD)
|
ifeq ($(uname_S),OpenBSD)
|
||||||
NO_STRCASESTR = YesPlease
|
NO_STRCASESTR = YesPlease
|
||||||
NO_MEMMEM = YesPlease
|
NO_MEMMEM = YesPlease
|
||||||
|
USE_ST_TIMESPEC = YesPlease
|
||||||
NEEDS_LIBICONV = YesPlease
|
NEEDS_LIBICONV = YesPlease
|
||||||
BASIC_CFLAGS += -I/usr/local/include
|
BASIC_CFLAGS += -I/usr/local/include
|
||||||
BASIC_LDFLAGS += -L/usr/local/lib
|
BASIC_LDFLAGS += -L/usr/local/lib
|
||||||
|
@ -726,12 +766,14 @@ ifeq ($(uname_S),NetBSD)
|
||||||
BASIC_CFLAGS += -I/usr/pkg/include
|
BASIC_CFLAGS += -I/usr/pkg/include
|
||||||
BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib
|
BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib
|
||||||
THREADED_DELTA_SEARCH = YesPlease
|
THREADED_DELTA_SEARCH = YesPlease
|
||||||
|
USE_ST_TIMESPEC = YesPlease
|
||||||
endif
|
endif
|
||||||
ifeq ($(uname_S),AIX)
|
ifeq ($(uname_S),AIX)
|
||||||
NO_STRCASESTR=YesPlease
|
NO_STRCASESTR=YesPlease
|
||||||
NO_MEMMEM = YesPlease
|
NO_MEMMEM = YesPlease
|
||||||
NO_MKDTEMP = YesPlease
|
NO_MKDTEMP = YesPlease
|
||||||
NO_STRLCPY = YesPlease
|
NO_STRLCPY = YesPlease
|
||||||
|
NO_NSEC = YesPlease
|
||||||
FREAD_READS_DIRECTORIES = UnfortunatelyYes
|
FREAD_READS_DIRECTORIES = UnfortunatelyYes
|
||||||
INTERNAL_QSORT = UnfortunatelyYes
|
INTERNAL_QSORT = UnfortunatelyYes
|
||||||
NEEDS_LIBICONV=YesPlease
|
NEEDS_LIBICONV=YesPlease
|
||||||
|
@ -772,9 +814,10 @@ ifeq ($(uname_S),HP-UX)
|
||||||
endif
|
endif
|
||||||
ifneq (,$(findstring CYGWIN,$(uname_S)))
|
ifneq (,$(findstring CYGWIN,$(uname_S)))
|
||||||
COMPAT_OBJS += compat/cygwin.o
|
COMPAT_OBJS += compat/cygwin.o
|
||||||
|
UNRELIABLE_FSTAT = UnfortunatelyYes
|
||||||
endif
|
endif
|
||||||
ifneq (,$(findstring MINGW,$(uname_S)))
|
ifneq (,$(findstring MINGW,$(uname_S)))
|
||||||
NO_MMAP = YesPlease
|
pathsep = ;
|
||||||
NO_PREAD = YesPlease
|
NO_PREAD = YesPlease
|
||||||
NO_OPENSSL = YesPlease
|
NO_OPENSSL = YesPlease
|
||||||
NO_CURL = YesPlease
|
NO_CURL = YesPlease
|
||||||
|
@ -797,6 +840,10 @@ ifneq (,$(findstring MINGW,$(uname_S)))
|
||||||
RUNTIME_PREFIX = YesPlease
|
RUNTIME_PREFIX = YesPlease
|
||||||
NO_POSIX_ONLY_PROGRAMS = YesPlease
|
NO_POSIX_ONLY_PROGRAMS = YesPlease
|
||||||
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
|
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
|
||||||
|
NO_NSEC = YesPlease
|
||||||
|
USE_WIN32_MMAP = YesPlease
|
||||||
|
UNRELIABLE_FSTAT = UnfortunatelyYes
|
||||||
|
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
|
||||||
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
|
COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch
|
||||||
COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
|
COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1
|
||||||
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
|
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
|
||||||
|
@ -918,6 +965,15 @@ endif
|
||||||
ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
|
ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
|
||||||
BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
|
BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
|
||||||
endif
|
endif
|
||||||
|
ifdef USE_NSEC
|
||||||
|
BASIC_CFLAGS += -DUSE_NSEC
|
||||||
|
endif
|
||||||
|
ifdef USE_ST_TIMESPEC
|
||||||
|
BASIC_CFLAGS += -DUSE_ST_TIMESPEC
|
||||||
|
endif
|
||||||
|
ifdef NO_NSEC
|
||||||
|
BASIC_CFLAGS += -DNO_NSEC
|
||||||
|
endif
|
||||||
ifdef NO_C99_FORMAT
|
ifdef NO_C99_FORMAT
|
||||||
BASIC_CFLAGS += -DNO_C99_FORMAT
|
BASIC_CFLAGS += -DNO_C99_FORMAT
|
||||||
endif
|
endif
|
||||||
|
@ -965,6 +1021,14 @@ endif
|
||||||
ifdef NO_MMAP
|
ifdef NO_MMAP
|
||||||
COMPAT_CFLAGS += -DNO_MMAP
|
COMPAT_CFLAGS += -DNO_MMAP
|
||||||
COMPAT_OBJS += compat/mmap.o
|
COMPAT_OBJS += compat/mmap.o
|
||||||
|
else
|
||||||
|
ifdef USE_WIN32_MMAP
|
||||||
|
COMPAT_CFLAGS += -DUSE_WIN32_MMAP
|
||||||
|
COMPAT_OBJS += compat/win32mmap.o
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
ifdef OBJECT_CREATION_USES_RENAMES
|
||||||
|
COMPAT_CFLAGS += -DOBJECT_CREATION_MODE=1
|
||||||
endif
|
endif
|
||||||
ifdef NO_PREAD
|
ifdef NO_PREAD
|
||||||
COMPAT_CFLAGS += -DNO_PREAD
|
COMPAT_CFLAGS += -DNO_PREAD
|
||||||
|
@ -1061,11 +1125,18 @@ endif
|
||||||
ifdef NO_EXTERNAL_GREP
|
ifdef NO_EXTERNAL_GREP
|
||||||
BASIC_CFLAGS += -DNO_EXTERNAL_GREP
|
BASIC_CFLAGS += -DNO_EXTERNAL_GREP
|
||||||
endif
|
endif
|
||||||
|
ifdef UNRELIABLE_FSTAT
|
||||||
|
BASIC_CFLAGS += -DUNRELIABLE_FSTAT
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(TCLTK_PATH),)
|
ifeq ($(TCLTK_PATH),)
|
||||||
NO_TCLTK=NoThanks
|
NO_TCLTK=NoThanks
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(PERL_PATH),)
|
||||||
|
NO_PERL=NoThanks
|
||||||
|
endif
|
||||||
|
|
||||||
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
|
QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
|
||||||
QUIET_SUBDIR1 =
|
QUIET_SUBDIR1 =
|
||||||
|
|
||||||
|
@ -1140,7 +1211,9 @@ ifndef NO_TCLTK
|
||||||
$(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) gitexecdir='$(gitexec_instdir_SQ)' all
|
$(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) gitexecdir='$(gitexec_instdir_SQ)' all
|
||||||
$(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all
|
$(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all
|
||||||
endif
|
endif
|
||||||
|
ifndef NO_PERL
|
||||||
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
|
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
|
||||||
|
endif
|
||||||
$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1)
|
$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1)
|
||||||
|
|
||||||
please_set_SHELL_PATH_to_a_more_modern_shell:
|
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
|
git.o: git.c common-cmds.h GIT-CFLAGS
|
||||||
$(QUIET_CC)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
|
$(QUIET_CC)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
|
||||||
|
'-DGIT_HTML_PATH="$(htmldir_SQ)"' \
|
||||||
$(ALL_CFLAGS) -c $(filter %.c,$^)
|
$(ALL_CFLAGS) -c $(filter %.c,$^)
|
||||||
|
|
||||||
git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
|
git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
|
||||||
|
@ -1180,13 +1254,13 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||||
$(QUIET_GEN)$(RM) $@ $@+ && \
|
$(QUIET_GEN)$(RM) $@ $@+ && \
|
||||||
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||||
-e 's|@SHELL_PATH@|$(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/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||||
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
|
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
|
||||||
$@.sh >$@+ && \
|
$@.sh >$@+ && \
|
||||||
chmod +x $@+ && \
|
chmod +x $@+ && \
|
||||||
mv $@+ $@
|
mv $@+ $@
|
||||||
|
|
||||||
|
ifndef NO_PERL
|
||||||
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
|
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
|
||||||
|
|
||||||
perl/perl.mak: GIT-CFLAGS perl/Makefile perl/Makefile.PL
|
perl/perl.mak: GIT-CFLAGS perl/Makefile perl/Makefile.PL
|
||||||
|
@ -1198,7 +1272,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
|
||||||
sed -e '1{' \
|
sed -e '1{' \
|
||||||
-e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \
|
-e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \
|
||||||
-e ' h' \
|
-e ' h' \
|
||||||
-e ' s=.*=use lib (split(/:/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \
|
-e ' s=.*=use lib (split(/$(pathsep)/, $$ENV{GITPERLLIB} || "@@INSTLIBDIR@@"));=' \
|
||||||
-e ' H' \
|
-e ' H' \
|
||||||
-e ' x' \
|
-e ' x' \
|
||||||
-e '}' \
|
-e '}' \
|
||||||
|
@ -1208,6 +1282,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
|
||||||
chmod +x $@+ && \
|
chmod +x $@+ && \
|
||||||
mv $@+ $@
|
mv $@+ $@
|
||||||
|
|
||||||
|
OTHER_PROGRAMS += gitweb/gitweb.cgi
|
||||||
gitweb/gitweb.cgi: gitweb/gitweb.perl
|
gitweb/gitweb.cgi: gitweb/gitweb.perl
|
||||||
$(QUIET_GEN)$(RM) $@ $@+ && \
|
$(QUIET_GEN)$(RM) $@ $@+ && \
|
||||||
sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
|
sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
|
||||||
|
@ -1246,6 +1321,15 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
|
||||||
$@.sh > $@+ && \
|
$@.sh > $@+ && \
|
||||||
chmod +x $@+ && \
|
chmod +x $@+ && \
|
||||||
mv $@+ $@
|
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
|
configure: configure.ac
|
||||||
$(QUIET_GEN)$(RM) $@ $<+ && \
|
$(QUIET_GEN)$(RM) $@ $<+ && \
|
||||||
|
@ -1361,6 +1445,8 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS
|
||||||
GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
|
GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS
|
||||||
@echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
|
@echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
|
||||||
@echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
|
@echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
|
||||||
|
@echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
|
||||||
|
@echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@
|
||||||
|
|
||||||
### Detect Tck/Tk interpreter path changes
|
### Detect Tck/Tk interpreter path changes
|
||||||
ifndef NO_TCLTK
|
ifndef NO_TCLTK
|
||||||
|
@ -1455,17 +1541,20 @@ install: all
|
||||||
$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
|
$(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)'
|
$(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
|
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
|
||||||
|
ifndef NO_PERL
|
||||||
$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
|
$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
|
||||||
|
endif
|
||||||
ifndef NO_TCLTK
|
ifndef NO_TCLTK
|
||||||
$(MAKE) -C gitk-git install
|
$(MAKE) -C gitk-git install
|
||||||
$(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install
|
$(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install
|
||||||
endif
|
endif
|
||||||
ifneq (,$X)
|
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
|
endif
|
||||||
bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
|
bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
|
||||||
execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
|
execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
|
||||||
{ $(RM) "$$execdir/git-add$X" && \
|
{ $(RM) "$$execdir/git-add$X" && \
|
||||||
|
test -z "$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
|
||||||
ln "$$bindir/git$X" "$$execdir/git-add$X" 2>/dev/null || \
|
ln "$$bindir/git$X" "$$execdir/git-add$X" 2>/dev/null || \
|
||||||
cp "$$bindir/git$X" "$$execdir/git-add$X"; } && \
|
cp "$$bindir/git$X" "$$execdir/git-add$X"; } && \
|
||||||
{ for p in $(filter-out git-add$X,$(BUILT_INS)); do \
|
{ 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 "$$execdir/git-add$X" "$$execdir/$$p" 2>/dev/null || \
|
||||||
ln -s "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; \
|
cp "$$execdir/git-add$X" "$$execdir/$$p" || exit; \
|
||||||
done } && \
|
done; } && \
|
||||||
./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
|
./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
|
||||||
|
|
||||||
install-doc:
|
install-doc:
|
||||||
|
@ -1563,9 +1652,11 @@ clean:
|
||||||
$(RM) -r $(GIT_TARNAME) .doc-tmp-dir
|
$(RM) -r $(GIT_TARNAME) .doc-tmp-dir
|
||||||
$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
|
$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
|
||||||
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
|
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
|
||||||
$(RM) gitweb/gitweb.cgi
|
|
||||||
$(MAKE) -C Documentation/ clean
|
$(MAKE) -C Documentation/ clean
|
||||||
|
ifndef NO_PERL
|
||||||
|
$(RM) gitweb/gitweb.cgi
|
||||||
$(MAKE) -C perl clean
|
$(MAKE) -C perl clean
|
||||||
|
endif
|
||||||
$(MAKE) -C templates/ clean
|
$(MAKE) -C templates/ clean
|
||||||
$(MAKE) -C t/ clean
|
$(MAKE) -C t/ clean
|
||||||
ifndef NO_TCLTK
|
ifndef NO_TCLTK
|
||||||
|
@ -1638,3 +1729,27 @@ check-docs::
|
||||||
check-builtins::
|
check-builtins::
|
||||||
./check-builtins.sh
|
./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
|
||||||
|
|
2
RelNotes
2
RelNotes
|
@ -1 +1 @@
|
||||||
Documentation/RelNotes-1.6.2.5.txt
|
Documentation/RelNotes-1.6.4.txt
|
10
alias.c
10
alias.c
|
@ -27,7 +27,7 @@ int split_cmdline(char *cmdline, const char ***argv)
|
||||||
int src, dst, count = 0, size = 16;
|
int src, dst, count = 0, size = 16;
|
||||||
char quoted = 0;
|
char quoted = 0;
|
||||||
|
|
||||||
*argv = xmalloc(sizeof(char*) * size);
|
*argv = xmalloc(sizeof(char *) * size);
|
||||||
|
|
||||||
/* split alias_string */
|
/* split alias_string */
|
||||||
(*argv)[count++] = cmdline;
|
(*argv)[count++] = cmdline;
|
||||||
|
@ -38,10 +38,7 @@ int split_cmdline(char *cmdline, const char ***argv)
|
||||||
while (cmdline[++src]
|
while (cmdline[++src]
|
||||||
&& isspace(cmdline[src]))
|
&& isspace(cmdline[src]))
|
||||||
; /* skip */
|
; /* skip */
|
||||||
if (count >= size) {
|
ALLOC_GROW(*argv, count+1, size);
|
||||||
size += 16;
|
|
||||||
*argv = xrealloc(*argv, sizeof(char*) * size);
|
|
||||||
}
|
|
||||||
(*argv)[count++] = cmdline + dst;
|
(*argv)[count++] = cmdline + dst;
|
||||||
} else if (!quoted && (c == '\'' || c == '"')) {
|
} else if (!quoted && (c == '\'' || c == '"')) {
|
||||||
quoted = c;
|
quoted = c;
|
||||||
|
@ -72,6 +69,9 @@ int split_cmdline(char *cmdline, const char ***argv)
|
||||||
return error("unclosed quote");
|
return error("unclosed quote");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALLOC_GROW(*argv, count+1, size);
|
||||||
|
(*argv)[count] = NULL;
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
alloc.c
2
alloc.c
|
@ -57,7 +57,7 @@ DEFINE_ALLOCATOR(object, union any_object)
|
||||||
#define SZ_FMT "%zu"
|
#define SZ_FMT "%zu"
|
||||||
#endif
|
#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);
|
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.mode, "%07o", mode & 07777);
|
||||||
sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0);
|
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.uid, "%07o", 0);
|
||||||
sprintf(header.gid, "%07o", 0);
|
sprintf(header.gid, "%07o", 0);
|
||||||
|
|
28
archive.c
28
archive.c
|
@ -4,6 +4,7 @@
|
||||||
#include "attr.h"
|
#include "attr.h"
|
||||||
#include "archive.h"
|
#include "archive.h"
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
|
#include "unpack-trees.h"
|
||||||
|
|
||||||
static char const * const archive_usage[] = {
|
static char const * const archive_usage[] = {
|
||||||
"git archive [options] <tree-ish> [path...]",
|
"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)
|
write_archive_entry_fn_t write_entry)
|
||||||
{
|
{
|
||||||
struct archiver_context context;
|
struct archiver_context context;
|
||||||
|
struct unpack_trees_options opts;
|
||||||
|
struct tree_desc t;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
|
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.args = args;
|
||||||
context.write_entry = write_entry;
|
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,
|
err = read_tree_recursive(args->tree, args->base, args->baselen, 0,
|
||||||
args->pathspec, write_archive_entry, &context);
|
args->pathspec, write_archive_entry, &context);
|
||||||
if (err == READ_TREE_RECURSIVE)
|
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 *base = NULL;
|
||||||
const char *remote = NULL;
|
const char *remote = NULL;
|
||||||
const char *exec = NULL;
|
const char *exec = NULL;
|
||||||
|
const char *output = NULL;
|
||||||
int compression_level = -1;
|
int compression_level = -1;
|
||||||
int verbose = 0;
|
int verbose = 0;
|
||||||
int i;
|
int i;
|
||||||
int list = 0;
|
int list = 0;
|
||||||
|
int worktree_attributes = 0;
|
||||||
struct option opts[] = {
|
struct option opts[] = {
|
||||||
OPT_GROUP(""),
|
OPT_GROUP(""),
|
||||||
OPT_STRING(0, "format", &format, "fmt", "archive format"),
|
OPT_STRING(0, "format", &format, "fmt", "archive format"),
|
||||||
OPT_STRING(0, "prefix", &base, "prefix",
|
OPT_STRING(0, "prefix", &base, "prefix",
|
||||||
"prepend prefix to each pathname in the archive"),
|
"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__VERBOSE(&verbose),
|
||||||
OPT__COMPR('0', &compression_level, "store only", 0),
|
OPT__COMPR('0', &compression_level, "store only", 0),
|
||||||
OPT__COMPR('1', &compression_level, "compress faster", 1),
|
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");
|
die("Unexpected option --remote");
|
||||||
if (exec)
|
if (exec)
|
||||||
die("Option --exec can only be used together with --remote");
|
die("Option --exec can only be used together with --remote");
|
||||||
|
if (output)
|
||||||
|
die("Unexpected option --output");
|
||||||
|
|
||||||
if (!base)
|
if (!base)
|
||||||
base = "";
|
base = "";
|
||||||
|
@ -319,6 +346,7 @@ static int parse_archive_args(int argc, const char **argv,
|
||||||
args->verbose = verbose;
|
args->verbose = verbose;
|
||||||
args->base = base;
|
args->base = base;
|
||||||
args->baselen = strlen(base);
|
args->baselen = strlen(base);
|
||||||
|
args->worktree_attributes = worktree_attributes;
|
||||||
|
|
||||||
return argc;
|
return argc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ struct archiver_args {
|
||||||
time_t time;
|
time_t time;
|
||||||
const char **pathspec;
|
const char **pathspec;
|
||||||
unsigned int verbose : 1;
|
unsigned int verbose : 1;
|
||||||
|
unsigned int worktree_attributes : 1;
|
||||||
int compression_level;
|
int compression_level;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
87
attr.c
87
attr.c
|
@ -1,3 +1,4 @@
|
||||||
|
#define NO_THE_INDEX_COMPATIBILITY_MACROS
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "attr.h"
|
#include "attr.h"
|
||||||
|
|
||||||
|
@ -223,7 +224,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
|
||||||
if (is_macro)
|
if (is_macro)
|
||||||
res->u.attr = git_attr(name, namelen);
|
res->u.attr = git_attr(name, namelen);
|
||||||
else {
|
else {
|
||||||
res->u.pattern = (char*)&(res->state[num_attr]);
|
res->u.pattern = (char *)&(res->state[num_attr]);
|
||||||
memcpy(res->u.pattern, name, namelen);
|
memcpy(res->u.pattern, name, namelen);
|
||||||
res->u.pattern[namelen] = 0;
|
res->u.pattern[namelen] = 0;
|
||||||
}
|
}
|
||||||
|
@ -274,7 +275,7 @@ static void free_attr_elem(struct attr_stack *e)
|
||||||
setto == ATTR__UNKNOWN)
|
setto == ATTR__UNKNOWN)
|
||||||
;
|
;
|
||||||
else
|
else
|
||||||
free((char*) setto);
|
free((char *) setto);
|
||||||
}
|
}
|
||||||
free(a);
|
free(a);
|
||||||
}
|
}
|
||||||
|
@ -318,6 +319,9 @@ static struct attr_stack *read_attr_from_array(const char **list)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum git_attr_direction direction;
|
||||||
|
static struct index_state *use_index;
|
||||||
|
|
||||||
static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
|
static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
|
||||||
{
|
{
|
||||||
FILE *fp = fopen(path, "r");
|
FILE *fp = fopen(path, "r");
|
||||||
|
@ -340,9 +344,10 @@ static void *read_index_data(const char *path)
|
||||||
unsigned long sz;
|
unsigned long sz;
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
void *data;
|
void *data;
|
||||||
|
struct index_state *istate = use_index ? use_index : &the_index;
|
||||||
|
|
||||||
len = strlen(path);
|
len = strlen(path);
|
||||||
pos = cache_name_pos(path, len);
|
pos = index_name_pos(istate, path, len);
|
||||||
if (pos < 0) {
|
if (pos < 0) {
|
||||||
/*
|
/*
|
||||||
* We might be in the middle of a merge, in which
|
* We might be in the middle of a merge, in which
|
||||||
|
@ -350,15 +355,15 @@ static void *read_index_data(const char *path)
|
||||||
*/
|
*/
|
||||||
int i;
|
int i;
|
||||||
for (i = -pos - 1;
|
for (i = -pos - 1;
|
||||||
(pos < 0 && i < active_nr &&
|
(pos < 0 && i < istate->cache_nr &&
|
||||||
!strcmp(active_cache[i]->name, path));
|
!strcmp(istate->cache[i]->name, path));
|
||||||
i++)
|
i++)
|
||||||
if (ce_stage(active_cache[i]) == 2)
|
if (ce_stage(istate->cache[i]) == 2)
|
||||||
pos = i;
|
pos = i;
|
||||||
}
|
}
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
data = read_sha1_file(active_cache[pos]->sha1, &type, &sz);
|
data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
|
||||||
if (!data || type != OBJ_BLOB) {
|
if (!data || type != OBJ_BLOB) {
|
||||||
free(data);
|
free(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -366,27 +371,17 @@ static void *read_index_data(const char *path)
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct attr_stack *read_attr(const char *path, int macro_ok)
|
static struct attr_stack *read_attr_from_index(const char *path, int macro_ok)
|
||||||
{
|
{
|
||||||
struct attr_stack *res;
|
struct attr_stack *res;
|
||||||
char *buf, *sp;
|
char *buf, *sp;
|
||||||
int lineno = 0;
|
int lineno = 0;
|
||||||
|
|
||||||
res = read_attr_from_file(path, macro_ok);
|
|
||||||
if (res)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
res = xcalloc(1, sizeof(*res));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There is no checked out .gitattributes file there, but
|
|
||||||
* we might have it in the index. We allow operation in a
|
|
||||||
* sparsely checked out work tree, so read from it.
|
|
||||||
*/
|
|
||||||
buf = read_index_data(path);
|
buf = read_index_data(path);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return res;
|
return NULL;
|
||||||
|
|
||||||
|
res = xcalloc(1, sizeof(*res));
|
||||||
for (sp = buf; *sp; ) {
|
for (sp = buf; *sp; ) {
|
||||||
char *ep;
|
char *ep;
|
||||||
int more;
|
int more;
|
||||||
|
@ -401,6 +396,32 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct attr_stack *read_attr(const char *path, int macro_ok)
|
||||||
|
{
|
||||||
|
struct attr_stack *res;
|
||||||
|
|
||||||
|
if (direction == GIT_ATTR_CHECKOUT) {
|
||||||
|
res = read_attr_from_index(path, macro_ok);
|
||||||
|
if (!res)
|
||||||
|
res = read_attr_from_file(path, macro_ok);
|
||||||
|
}
|
||||||
|
else 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
|
#if DEBUG_ATTR
|
||||||
static void debug_info(const char *what, struct attr_stack *elem)
|
static void debug_info(const char *what, struct attr_stack *elem)
|
||||||
{
|
{
|
||||||
|
@ -428,6 +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)
|
#define debug_set(a,b,c,d) do { ; } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void drop_attr_stack(void)
|
||||||
|
{
|
||||||
|
while (attr_stack) {
|
||||||
|
struct attr_stack *elem = attr_stack;
|
||||||
|
attr_stack = elem->prev;
|
||||||
|
free_attr_elem(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void bootstrap_attr_stack(void)
|
static void bootstrap_attr_stack(void)
|
||||||
{
|
{
|
||||||
if (!attr_stack) {
|
if (!attr_stack) {
|
||||||
|
@ -438,7 +468,7 @@ static void bootstrap_attr_stack(void)
|
||||||
elem->prev = attr_stack;
|
elem->prev = attr_stack;
|
||||||
attr_stack = elem;
|
attr_stack = elem;
|
||||||
|
|
||||||
if (!is_bare_repository()) {
|
if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
|
||||||
elem = read_attr(GITATTRIBUTES_FILE, 1);
|
elem = read_attr(GITATTRIBUTES_FILE, 1);
|
||||||
elem->origin = strdup("");
|
elem->origin = strdup("");
|
||||||
elem->prev = attr_stack;
|
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
|
* Read from parent directories and push them down
|
||||||
*/
|
*/
|
||||||
if (!is_bare_repository()) {
|
if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
|
||||||
while (1) {
|
while (1) {
|
||||||
char *cp;
|
char *cp;
|
||||||
|
|
||||||
|
@ -642,3 +672,16 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate)
|
||||||
|
{
|
||||||
|
enum git_attr_direction old = direction;
|
||||||
|
|
||||||
|
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
7
attr.h
|
@ -31,4 +31,11 @@ struct git_attr_check {
|
||||||
|
|
||||||
int git_checkattr(const char *path, int, struct git_attr_check *);
|
int git_checkattr(const char *path, int, struct git_attr_check *);
|
||||||
|
|
||||||
|
enum git_attr_direction {
|
||||||
|
GIT_ATTR_CHECKIN,
|
||||||
|
GIT_ATTR_CHECKOUT,
|
||||||
|
GIT_ATTR_INDEX,
|
||||||
|
};
|
||||||
|
void git_attr_set_direction(enum git_attr_direction, struct index_state *);
|
||||||
|
|
||||||
#endif /* ATTR_H */
|
#endif /* ATTR_H */
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
70
branch.c
70
branch.c
|
@ -32,21 +32,59 @@ static int find_tracked_branch(struct remote *remote, void *priv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int should_setup_rebase(const struct tracking *tracking)
|
static int should_setup_rebase(const char *origin)
|
||||||
{
|
{
|
||||||
switch (autorebase) {
|
switch (autorebase) {
|
||||||
case AUTOREBASE_NEVER:
|
case AUTOREBASE_NEVER:
|
||||||
return 0;
|
return 0;
|
||||||
case AUTOREBASE_LOCAL:
|
case AUTOREBASE_LOCAL:
|
||||||
return tracking->remote == NULL;
|
return origin == NULL;
|
||||||
case AUTOREBASE_REMOTE:
|
case AUTOREBASE_REMOTE:
|
||||||
return tracking->remote != NULL;
|
return origin != NULL;
|
||||||
case AUTOREBASE_ALWAYS:
|
case AUTOREBASE_ALWAYS:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
|
||||||
|
{
|
||||||
|
struct strbuf key = STRBUF_INIT;
|
||||||
|
int rebasing = should_setup_rebase(origin);
|
||||||
|
|
||||||
|
strbuf_addf(&key, "branch.%s.remote", local);
|
||||||
|
git_config_set(key.buf, origin ? origin : ".");
|
||||||
|
|
||||||
|
strbuf_reset(&key);
|
||||||
|
strbuf_addf(&key, "branch.%s.merge", local);
|
||||||
|
git_config_set(key.buf, remote);
|
||||||
|
|
||||||
|
if (rebasing) {
|
||||||
|
strbuf_reset(&key);
|
||||||
|
strbuf_addf(&key, "branch.%s.rebase", local);
|
||||||
|
git_config_set(key.buf, "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flag & BRANCH_CONFIG_VERBOSE) {
|
||||||
|
strbuf_reset(&key);
|
||||||
|
|
||||||
|
strbuf_addstr(&key, origin ? "remote" : "local");
|
||||||
|
|
||||||
|
/* Are we tracking a proper "branch"? */
|
||||||
|
if (!prefixcmp(remote, "refs/heads/")) {
|
||||||
|
strbuf_addf(&key, " branch %s", remote + 11);
|
||||||
|
if (origin)
|
||||||
|
strbuf_addf(&key, " from %s", origin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
strbuf_addf(&key, " ref %s", remote);
|
||||||
|
printf("Branch %s set up to track %s%s.\n",
|
||||||
|
local, key.buf,
|
||||||
|
rebasing ? " by rebasing" : "");
|
||||||
|
}
|
||||||
|
strbuf_release(&key);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is called when new_ref is branched off of orig_ref, and tries
|
* This is called when new_ref is branched off of orig_ref, and tries
|
||||||
* to infer the settings for branch.<new_ref>.{remote,merge} from the
|
* to infer the settings for branch.<new_ref>.{remote,merge} from the
|
||||||
|
@ -55,7 +93,6 @@ static int should_setup_rebase(const struct tracking *tracking)
|
||||||
static int setup_tracking(const char *new_ref, const char *orig_ref,
|
static int setup_tracking(const char *new_ref, const char *orig_ref,
|
||||||
enum branch_track track)
|
enum branch_track track)
|
||||||
{
|
{
|
||||||
char key[1024];
|
|
||||||
struct tracking tracking;
|
struct tracking tracking;
|
||||||
|
|
||||||
if (strlen(new_ref) > 1024 - 7 - 7 - 1)
|
if (strlen(new_ref) > 1024 - 7 - 7 - 1)
|
||||||
|
@ -80,19 +117,10 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
|
||||||
return error("Not tracking: ambiguous information for ref %s",
|
return error("Not tracking: ambiguous information for ref %s",
|
||||||
orig_ref);
|
orig_ref);
|
||||||
|
|
||||||
sprintf(key, "branch.%s.remote", new_ref);
|
install_branch_config(BRANCH_CONFIG_VERBOSE, new_ref, tracking.remote,
|
||||||
git_config_set(key, tracking.remote ? tracking.remote : ".");
|
tracking.src ? tracking.src : orig_ref);
|
||||||
sprintf(key, "branch.%s.merge", new_ref);
|
|
||||||
git_config_set(key, tracking.src ? tracking.src : orig_ref);
|
|
||||||
printf("Branch %s set up to track %s branch %s.\n", new_ref,
|
|
||||||
tracking.remote ? "remote" : "local", orig_ref);
|
|
||||||
if (should_setup_rebase(&tracking)) {
|
|
||||||
sprintf(key, "branch.%s.rebase", new_ref);
|
|
||||||
git_config_set(key, "true");
|
|
||||||
printf("This branch will rebase on pull.\n");
|
|
||||||
}
|
|
||||||
free(tracking.src);
|
|
||||||
|
|
||||||
|
free(tracking.src);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,16 +134,8 @@ void create_branch(const char *head,
|
||||||
char *real_ref, msg[PATH_MAX + 20];
|
char *real_ref, msg[PATH_MAX + 20];
|
||||||
struct strbuf ref = STRBUF_INIT;
|
struct strbuf ref = STRBUF_INIT;
|
||||||
int forcing = 0;
|
int forcing = 0;
|
||||||
int len;
|
|
||||||
|
|
||||||
len = strlen(name);
|
if (strbuf_check_branch_ref(&ref, 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))
|
|
||||||
die("'%s' is not a valid branch name.", name);
|
die("'%s' is not a valid branch name.", name);
|
||||||
|
|
||||||
if (resolve_ref(ref.buf, sha1, 1, NULL)) {
|
if (resolve_ref(ref.buf, sha1, 1, NULL)) {
|
||||||
|
|
7
branch.h
7
branch.h
|
@ -21,4 +21,11 @@ void create_branch(const char *head, const char *name, const char *start_name,
|
||||||
*/
|
*/
|
||||||
void remove_branch_state(void);
|
void remove_branch_state(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure local branch "local" to merge remote branch "remote"
|
||||||
|
* taken from origin "origin".
|
||||||
|
*/
|
||||||
|
#define BRANCH_CONFIG_VERBOSE 01
|
||||||
|
extern void install_branch_config(int flag, const char *local, const char *origin, const char *remote);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,12 +10,14 @@
|
||||||
#include "cache-tree.h"
|
#include "cache-tree.h"
|
||||||
#include "run-command.h"
|
#include "run-command.h"
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
|
#include "diff.h"
|
||||||
|
#include "revision.h"
|
||||||
|
|
||||||
static const char * const builtin_add_usage[] = {
|
static const char * const builtin_add_usage[] = {
|
||||||
"git add [options] [--] <filepattern>...",
|
"git add [options] [--] <filepattern>...",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static int patch_interactive, add_interactive;
|
static int patch_interactive, add_interactive, edit_interactive;
|
||||||
static int take_worktree_changes;
|
static int take_worktree_changes;
|
||||||
|
|
||||||
static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)
|
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);
|
fill_pathspec_matches(pathspec, seen, specs);
|
||||||
|
|
||||||
for (i = 0; i < specs; i++) {
|
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",
|
die("pathspec '%s' did not match any files",
|
||||||
pathspec[i]);
|
pathspec[i]);
|
||||||
}
|
}
|
||||||
|
@ -104,7 +106,7 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec,
|
||||||
/* Set up the default git porcelain excludes */
|
/* Set up the default git porcelain excludes */
|
||||||
memset(dir, 0, sizeof(*dir));
|
memset(dir, 0, sizeof(*dir));
|
||||||
if (!ignored_too) {
|
if (!ignored_too) {
|
||||||
dir->collect_ignored = 1;
|
dir->flags |= DIR_COLLECT_IGNORED;
|
||||||
setup_standard_excludes(dir);
|
setup_standard_excludes(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +150,7 @@ static const char **validate_pathspec(int argc, const char **argv, const char *p
|
||||||
if (pathspec) {
|
if (pathspec) {
|
||||||
const char **p;
|
const char **p;
|
||||||
for (p = pathspec; *p; p++) {
|
for (p = pathspec; *p; p++) {
|
||||||
if (has_symlink_leading_path(strlen(*p), *p)) {
|
if (has_symlink_leading_path(*p, strlen(*p))) {
|
||||||
int len = prefix ? strlen(prefix) : 0;
|
int len = prefix ? strlen(prefix) : 0;
|
||||||
die("'%s' is beyond a symbolic link", *p + len);
|
die("'%s' is beyond a symbolic link", *p + len);
|
||||||
}
|
}
|
||||||
|
@ -187,6 +189,51 @@ int interactive_add(int argc, const char **argv, const char *prefix)
|
||||||
return status;
|
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 struct lock_file lock_file;
|
||||||
|
|
||||||
static const char ignore_error[] =
|
static const char ignore_error[] =
|
||||||
|
@ -201,6 +248,7 @@ static struct option builtin_add_options[] = {
|
||||||
OPT_GROUP(""),
|
OPT_GROUP(""),
|
||||||
OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
|
OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
|
||||||
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
|
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('f', "force", &ignored_too, "allow adding otherwise ignored files"),
|
||||||
OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked 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"),
|
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;
|
int require_pathspec;
|
||||||
|
|
||||||
argc = parse_options(argc, argv, builtin_add_options,
|
argc = parse_options(argc, argv, builtin_add_options,
|
||||||
builtin_add_usage, 0);
|
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
|
||||||
if (patch_interactive)
|
if (patch_interactive)
|
||||||
add_interactive = 1;
|
add_interactive = 1;
|
||||||
if (add_interactive)
|
if (add_interactive)
|
||||||
exit(interactive_add(argc, argv, prefix));
|
exit(interactive_add(argc - 1, argv + 1, prefix));
|
||||||
|
|
||||||
git_config(add_config, NULL);
|
git_config(add_config, NULL);
|
||||||
|
|
||||||
|
if (edit_interactive)
|
||||||
|
return(edit_patch(argc, argv, prefix));
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
|
||||||
if (addremove && take_worktree_changes)
|
if (addremove && take_worktree_changes)
|
||||||
die("-A and -u are mutually incompatible");
|
die("-A and -u are mutually incompatible");
|
||||||
if ((addremove || take_worktree_changes) && !argc) {
|
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
|
* In such a case, path "new_name" does not exist as
|
||||||
* far as git is concerned.
|
* far as git is concerned.
|
||||||
*/
|
*/
|
||||||
if (has_symlink_leading_path(strlen(new_name), new_name))
|
if (has_symlink_leading_path(new_name, strlen(new_name)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return error("%s: already exists in working directory", new_name);
|
return error("%s: already exists in working directory", new_name);
|
||||||
|
@ -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)
|
if ((st_mode ^ patch->old_mode) & S_IFMT)
|
||||||
return error("%s: wrong type", old_name);
|
return error("%s: wrong type", old_name);
|
||||||
if (st_mode != patch->old_mode)
|
if (st_mode != patch->old_mode)
|
||||||
fprintf(stderr, "warning: %s has type %o, expected %o\n",
|
warning("%s has type %o, expected %o",
|
||||||
old_name, st_mode, patch->old_mode);
|
old_name, st_mode, patch->old_mode);
|
||||||
if (!patch->new_mode && !patch->is_delete)
|
if (!patch->new_mode && !patch->is_delete)
|
||||||
patch->new_mode = st_mode;
|
patch->new_mode = st_mode;
|
||||||
|
@ -2781,7 +2781,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
|
||||||
if (rmdir(patch->old_name))
|
if (rmdir(patch->old_name))
|
||||||
warning("unable to remove submodule %s",
|
warning("unable to remove submodule %s",
|
||||||
patch->old_name);
|
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);
|
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 (!try_create_file(newpath, mode, buf, size)) {
|
||||||
if (!rename(newpath, path))
|
if (!rename(newpath, path))
|
||||||
return;
|
return;
|
||||||
unlink(newpath);
|
unlink_or_warn(newpath);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (errno != EEXIST)
|
if (errno != EEXIST)
|
||||||
|
@ -2971,8 +2971,7 @@ static int write_out_one_reject(struct patch *patch)
|
||||||
cnt = strlen(patch->new_name);
|
cnt = strlen(patch->new_name);
|
||||||
if (ARRAY_SIZE(namebuf) <= cnt + 5) {
|
if (ARRAY_SIZE(namebuf) <= cnt + 5) {
|
||||||
cnt = ARRAY_SIZE(namebuf) - 5;
|
cnt = ARRAY_SIZE(namebuf) - 5;
|
||||||
fprintf(stderr,
|
warning("truncating .rej filename to %.*s.rej",
|
||||||
"warning: truncating .rej filename to %.*s.rej",
|
|
||||||
cnt - 1, patch->new_name);
|
cnt - 1, patch->new_name);
|
||||||
}
|
}
|
||||||
memcpy(namebuf, patch->new_name, cnt);
|
memcpy(namebuf, patch->new_name, cnt);
|
||||||
|
@ -3263,10 +3262,10 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
|
||||||
"ignore additions made by the patch"),
|
"ignore additions made by the patch"),
|
||||||
OPT_BOOLEAN(0, "stat", &diffstat,
|
OPT_BOOLEAN(0, "stat", &diffstat,
|
||||||
"instead of applying the patch, output diffstat for the input"),
|
"instead of applying the patch, output diffstat for the input"),
|
||||||
OPT_BOOLEAN(0, "allow-binary-replacement", &binary,
|
{ OPTION_BOOLEAN, 0, "allow-binary-replacement", &binary,
|
||||||
"now no-op"),
|
NULL, "old option, now no-op", PARSE_OPT_HIDDEN },
|
||||||
OPT_BOOLEAN(0, "binary", &binary,
|
{ OPTION_BOOLEAN, 0, "binary", &binary,
|
||||||
"now no-op"),
|
NULL, "old option, now no-op", PARSE_OPT_HIDDEN },
|
||||||
OPT_BOOLEAN(0, "numstat", &numstat,
|
OPT_BOOLEAN(0, "numstat", &numstat,
|
||||||
"shows number of added and deleted lines in decimal notation"),
|
"shows number of added and deleted lines in decimal notation"),
|
||||||
OPT_BOOLEAN(0, "summary", &summary,
|
OPT_BOOLEAN(0, "summary", &summary,
|
||||||
|
@ -3358,8 +3357,8 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
|
||||||
squelch_whitespace_errors < whitespace_error) {
|
squelch_whitespace_errors < whitespace_error) {
|
||||||
int squelched =
|
int squelched =
|
||||||
whitespace_error - squelch_whitespace_errors;
|
whitespace_error - squelch_whitespace_errors;
|
||||||
fprintf(stderr, "warning: squelched %d "
|
warning("squelched %d "
|
||||||
"whitespace error%s\n",
|
"whitespace error%s",
|
||||||
squelched,
|
squelched,
|
||||||
squelched == 1 ? "" : "s");
|
squelched == 1 ? "" : "s");
|
||||||
}
|
}
|
||||||
|
@ -3369,12 +3368,12 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
|
||||||
whitespace_error == 1 ? "" : "s",
|
whitespace_error == 1 ? "" : "s",
|
||||||
whitespace_error == 1 ? "s" : "");
|
whitespace_error == 1 ? "s" : "");
|
||||||
if (applied_after_fixing_ws && apply)
|
if (applied_after_fixing_ws && apply)
|
||||||
fprintf(stderr, "warning: %d line%s applied after"
|
warning("%d line%s applied after"
|
||||||
" fixing whitespace errors.\n",
|
" fixing whitespace errors.",
|
||||||
applied_after_fixing_ws,
|
applied_after_fixing_ws,
|
||||||
applied_after_fixing_ws == 1 ? "" : "s");
|
applied_after_fixing_ws == 1 ? "" : "s");
|
||||||
else if (whitespace_error)
|
else if (whitespace_error)
|
||||||
fprintf(stderr, "warning: %d line%s add%s whitespace errors.\n",
|
warning("%d line%s add%s whitespace errors.",
|
||||||
whitespace_error,
|
whitespace_error,
|
||||||
whitespace_error == 1 ? "" : "s",
|
whitespace_error == 1 ? "" : "s",
|
||||||
whitespace_error == 1 ? "s" : "");
|
whitespace_error == 1 ? "s" : "");
|
||||||
|
|
|
@ -5,44 +5,35 @@
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "archive.h"
|
#include "archive.h"
|
||||||
|
#include "parse-options.h"
|
||||||
#include "pkt-line.h"
|
#include "pkt-line.h"
|
||||||
#include "sideband.h"
|
#include "sideband.h"
|
||||||
|
|
||||||
static int run_remote_archiver(const char *remote, int argc,
|
static void create_output_file(const char *output_file)
|
||||||
const char **argv)
|
{
|
||||||
|
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];
|
char *url, buf[LARGE_PACKET_MAX];
|
||||||
int fd[2], i, len, rv;
|
int fd[2], i, len, rv;
|
||||||
struct child_process *conn;
|
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);
|
url = xstrdup(remote);
|
||||||
conn = git_connect(fd, url, exec, 0);
|
conn = git_connect(fd, url, exec, 0);
|
||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++)
|
||||||
if (i == exec_at || i == exec_value_at)
|
|
||||||
continue;
|
|
||||||
packet_write(fd[1], "argument %s\n", argv[i]);
|
packet_write(fd[1], "argument %s\n", argv[i]);
|
||||||
}
|
|
||||||
packet_flush(fd[1]);
|
packet_flush(fd[1]);
|
||||||
|
|
||||||
len = packet_read_line(fd[0], buf, sizeof(buf));
|
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");
|
die("git archive: expected a flush");
|
||||||
|
|
||||||
/* Now, start reading from fd[0] and spit it out to stdout */
|
/* 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[0]);
|
||||||
close(fd[1]);
|
close(fd[1]);
|
||||||
rv |= finish_connect(conn);
|
rv |= finish_connect(conn);
|
||||||
|
@ -69,51 +60,33 @@ static int run_remote_archiver(const char *remote, int argc,
|
||||||
return !!rv;
|
return !!rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *extract_remote_arg(int *ac, const char **av)
|
#define PARSE_OPT_KEEP_ALL ( PARSE_OPT_KEEP_DASHDASH | \
|
||||||
{
|
PARSE_OPT_KEEP_ARGV0 | \
|
||||||
int ix, iy, cnt = *ac;
|
PARSE_OPT_KEEP_UNKNOWN | \
|
||||||
int no_more_options = 0;
|
PARSE_OPT_NO_INTERNAL_HELP )
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cmd_archive(int argc, const char **argv, const char *prefix)
|
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;
|
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)
|
if (remote)
|
||||||
return run_remote_archiver(remote, argc, argv);
|
return run_remote_archiver(argc, argv, remote, exec);
|
||||||
|
|
||||||
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
|
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
182
builtin-blame.c
182
builtin-blame.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Pickaxe
|
* Blame
|
||||||
*
|
*
|
||||||
* Copyright (c) 2006, Junio C Hamano
|
* Copyright (c) 2006, Junio C Hamano
|
||||||
*/
|
*/
|
||||||
|
@ -40,6 +40,10 @@ static int reverse;
|
||||||
static int blank_boundary;
|
static int blank_boundary;
|
||||||
static int incremental;
|
static int incremental;
|
||||||
static int xdl_opts = XDF_NEED_MINIMAL;
|
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;
|
static struct string_list mailmap;
|
||||||
|
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
|
@ -74,6 +78,7 @@ static unsigned blame_copy_score;
|
||||||
*/
|
*/
|
||||||
struct origin {
|
struct origin {
|
||||||
int refcnt;
|
int refcnt;
|
||||||
|
struct origin *previous;
|
||||||
struct commit *commit;
|
struct commit *commit;
|
||||||
mmfile_t file;
|
mmfile_t file;
|
||||||
unsigned char blob_sha1[20];
|
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)
|
static void origin_decref(struct origin *o)
|
||||||
{
|
{
|
||||||
if (o && --o->refcnt <= 0) {
|
if (o && --o->refcnt <= 0) {
|
||||||
|
if (o->previous)
|
||||||
|
origin_decref(o->previous);
|
||||||
free(o->file.ptr);
|
free(o->file.ptr);
|
||||||
free(o);
|
free(o);
|
||||||
}
|
}
|
||||||
|
@ -866,7 +873,7 @@ static void find_copy_in_blob(struct scoreboard *sb,
|
||||||
* Prepare mmfile that contains only the lines in ent.
|
* Prepare mmfile that contains only the lines in ent.
|
||||||
*/
|
*/
|
||||||
cp = nth_line(sb, ent->lno);
|
cp = nth_line(sb, ent->lno);
|
||||||
file_o.ptr = (char*) cp;
|
file_o.ptr = (char *) cp;
|
||||||
cnt = ent->num_lines;
|
cnt = ent->num_lines;
|
||||||
|
|
||||||
while (cnt && cp < sb->final_buf + sb->final_buf_size) {
|
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];
|
struct origin *porigin = sg_origin[i];
|
||||||
if (!porigin)
|
if (!porigin)
|
||||||
continue;
|
continue;
|
||||||
|
if (!origin->previous) {
|
||||||
|
origin_incref(porigin);
|
||||||
|
origin->previous = porigin;
|
||||||
|
}
|
||||||
if (pass_blame_to_parent(sb, origin, porigin))
|
if (pass_blame_to_parent(sb, origin, porigin))
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
@ -1414,6 +1425,39 @@ static void write_filename_info(const char *path)
|
||||||
write_name_quoted(path, stdout, '\n');
|
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
|
* The blame_entry is found to be guilty for the range. Mark it
|
||||||
* as such, and show it in incremental output.
|
* 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",
|
printf("%s %d %d %d\n",
|
||||||
sha1_to_hex(suspect->commit->object.sha1),
|
sha1_to_hex(suspect->commit->object.sha1),
|
||||||
ent->s_lno + 1, ent->lno + 1, ent->num_lines);
|
ent->s_lno + 1, ent->lno + 1, ent->num_lines);
|
||||||
if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
|
emit_one_suspect_detail(suspect);
|
||||||
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");
|
|
||||||
}
|
|
||||||
write_filename_info(suspect->path);
|
write_filename_info(suspect->path);
|
||||||
maybe_flush_or_die(stdout, "stdout");
|
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)
|
int show_raw_time)
|
||||||
{
|
{
|
||||||
static char time_buf[128];
|
static char time_buf[128];
|
||||||
time_t t = time;
|
const char *time_str;
|
||||||
int minutes, tz;
|
int time_len;
|
||||||
struct tm *tm;
|
int tz;
|
||||||
|
|
||||||
if (show_raw_time) {
|
if (show_raw_time) {
|
||||||
sprintf(time_buf, "%lu %s", time, tz_str);
|
sprintf(time_buf, "%lu %s", time, tz_str);
|
||||||
return time_buf;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
tz = atoi(tz_str);
|
tz = atoi(tz_str);
|
||||||
minutes = tz < 0 ? -tz : tz;
|
time_str = show_date(time, tz, blame_date_mode);
|
||||||
minutes = (minutes / 100)*60 + (minutes % 100);
|
time_len = strlen(time_str);
|
||||||
minutes = tz < 0 ? -minutes : minutes;
|
memcpy(time_buf, time_str, time_len);
|
||||||
t = time + minutes * 60;
|
memset(time_buf + time_len, ' ', blame_date_width - time_len);
|
||||||
tm = gmtime(&t);
|
}
|
||||||
|
|
||||||
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", tm);
|
|
||||||
strcat(time_buf, tz_str);
|
|
||||||
return time_buf;
|
return time_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1551,24 +1576,8 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
|
||||||
ent->s_lno + 1,
|
ent->s_lno + 1,
|
||||||
ent->lno + 1,
|
ent->lno + 1,
|
||||||
ent->num_lines);
|
ent->num_lines);
|
||||||
if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
|
if (emit_one_suspect_detail(suspect) ||
|
||||||
struct commit_info ci;
|
(suspect->commit->object.flags & MORE_THAN_ONE_PATH))
|
||||||
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)
|
|
||||||
write_filename_info(suspect->path);
|
write_filename_info(suspect->path);
|
||||||
|
|
||||||
cp = nth_line(sb, ent->lno);
|
cp = nth_line(sb, ent->lno);
|
||||||
|
@ -1695,7 +1704,7 @@ static int prepare_lines(struct scoreboard *sb)
|
||||||
while (len--) {
|
while (len--) {
|
||||||
if (bol) {
|
if (bol) {
|
||||||
sb->lineno = xrealloc(sb->lineno,
|
sb->lineno = xrealloc(sb->lineno,
|
||||||
sizeof(int* ) * (num + 1));
|
sizeof(int *) * (num + 1));
|
||||||
sb->lineno[num] = buf - sb->final_buf;
|
sb->lineno[num] = buf - sb->final_buf;
|
||||||
bol = 0;
|
bol = 0;
|
||||||
}
|
}
|
||||||
|
@ -1705,7 +1714,7 @@ static int prepare_lines(struct scoreboard *sb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb->lineno = xrealloc(sb->lineno,
|
sb->lineno = xrealloc(sb->lineno,
|
||||||
sizeof(int* ) * (num + incomplete + 1));
|
sizeof(int *) * (num + incomplete + 1));
|
||||||
sb->lineno[num + incomplete] = buf - sb->final_buf;
|
sb->lineno[num + incomplete] = buf - sb->final_buf;
|
||||||
sb->num_lines = num + incomplete;
|
sb->num_lines = num + incomplete;
|
||||||
return sb->num_lines;
|
return sb->num_lines;
|
||||||
|
@ -1806,36 +1815,6 @@ static void sanity_check_refcnt(struct scoreboard *sb)
|
||||||
baa = 1;
|
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) {
|
if (baa) {
|
||||||
int opt = 0160;
|
int opt = 0160;
|
||||||
find_alignment(sb, &opt);
|
find_alignment(sb, &opt);
|
||||||
|
@ -1910,7 +1889,7 @@ static const char *parse_loc(const char *spec,
|
||||||
return spec;
|
return spec;
|
||||||
|
|
||||||
/* it could be a regexp of form /.../ */
|
/* 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 == '\\')
|
if (*term == '\\')
|
||||||
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);
|
blank_boundary = git_config_bool(var, value);
|
||||||
return 0;
|
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);
|
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);
|
git_config(git_blame_config, NULL);
|
||||||
init_revisions(&revs, NULL);
|
init_revisions(&revs, NULL);
|
||||||
|
revs.date_mode = blame_date_mode;
|
||||||
|
|
||||||
save_commit_buffer = 0;
|
save_commit_buffer = 0;
|
||||||
dashdash_pos = 0;
|
dashdash_pos = 0;
|
||||||
|
|
||||||
|
@ -2267,8 +2254,35 @@ parse_done:
|
||||||
die("reading graft file %s failed: %s",
|
die("reading graft file %s failed: %s",
|
||||||
revs_file, strerror(errno));
|
revs_file, strerror(errno));
|
||||||
|
|
||||||
if (cmd_is_annotate)
|
if (cmd_is_annotate) {
|
||||||
output_option |= OUTPUT_ANNOTATE_COMPAT;
|
output_option |= OUTPUT_ANNOTATE_COMPAT;
|
||||||
|
blame_date_mode = DATE_ISO8601;
|
||||||
|
} 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))
|
if (DIFF_OPT_TST(&revs.diffopt, FIND_COPIES_HARDER))
|
||||||
opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE |
|
opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE |
|
||||||
|
|
206
builtin-branch.c
206
builtin-branch.c
|
@ -32,18 +32,18 @@ static unsigned char head_sha1[20];
|
||||||
|
|
||||||
static int branch_use_color = -1;
|
static int branch_use_color = -1;
|
||||||
static char branch_colors[][COLOR_MAXLEN] = {
|
static char branch_colors[][COLOR_MAXLEN] = {
|
||||||
"\033[m", /* reset */
|
GIT_COLOR_RESET,
|
||||||
"", /* PLAIN (normal) */
|
GIT_COLOR_NORMAL, /* PLAIN */
|
||||||
"\033[31m", /* REMOTE (red) */
|
GIT_COLOR_RED, /* REMOTE */
|
||||||
"", /* LOCAL (normal) */
|
GIT_COLOR_NORMAL, /* LOCAL */
|
||||||
"\033[32m", /* CURRENT (green) */
|
GIT_COLOR_GREEN, /* CURRENT */
|
||||||
};
|
};
|
||||||
enum color_branch {
|
enum color_branch {
|
||||||
COLOR_BRANCH_RESET = 0,
|
BRANCH_COLOR_RESET = 0,
|
||||||
COLOR_BRANCH_PLAIN = 1,
|
BRANCH_COLOR_PLAIN = 1,
|
||||||
COLOR_BRANCH_REMOTE = 2,
|
BRANCH_COLOR_REMOTE = 2,
|
||||||
COLOR_BRANCH_LOCAL = 3,
|
BRANCH_COLOR_LOCAL = 3,
|
||||||
COLOR_BRANCH_CURRENT = 4,
|
BRANCH_COLOR_CURRENT = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum merge_filter {
|
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)
|
static int parse_branch_color_slot(const char *var, int ofs)
|
||||||
{
|
{
|
||||||
if (!strcasecmp(var+ofs, "plain"))
|
if (!strcasecmp(var+ofs, "plain"))
|
||||||
return COLOR_BRANCH_PLAIN;
|
return BRANCH_COLOR_PLAIN;
|
||||||
if (!strcasecmp(var+ofs, "reset"))
|
if (!strcasecmp(var+ofs, "reset"))
|
||||||
return COLOR_BRANCH_RESET;
|
return BRANCH_COLOR_RESET;
|
||||||
if (!strcasecmp(var+ofs, "remote"))
|
if (!strcasecmp(var+ofs, "remote"))
|
||||||
return COLOR_BRANCH_REMOTE;
|
return BRANCH_COLOR_REMOTE;
|
||||||
if (!strcasecmp(var+ofs, "local"))
|
if (!strcasecmp(var+ofs, "local"))
|
||||||
return COLOR_BRANCH_LOCAL;
|
return BRANCH_COLOR_LOCAL;
|
||||||
if (!strcasecmp(var+ofs, "current"))
|
if (!strcasecmp(var+ofs, "current"))
|
||||||
return COLOR_BRANCH_CURRENT;
|
return BRANCH_COLOR_CURRENT;
|
||||||
die("bad config variable '%s'", var);
|
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");
|
die("Couldn't look up commit object for HEAD");
|
||||||
}
|
}
|
||||||
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
|
for (i = 0; i < argc; i++, strbuf_release(&bname)) {
|
||||||
int len = strlen(argv[i]);
|
strbuf_branchname(&bname, argv[i]);
|
||||||
|
|
||||||
if (interpret_nth_last_branch(argv[i], &bname) != len)
|
|
||||||
strbuf_add(&bname, argv[i], len);
|
|
||||||
|
|
||||||
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
|
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
|
||||||
error("Cannot delete the branch '%s' "
|
error("Cannot delete the branch '%s' "
|
||||||
"which you are currently on.", bname.buf);
|
"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 {
|
struct ref_item {
|
||||||
char *name;
|
char *name;
|
||||||
unsigned int kind;
|
char *dest;
|
||||||
|
unsigned int kind, len;
|
||||||
struct commit *commit;
|
struct commit *commit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -200,22 +197,47 @@ struct ref_list {
|
||||||
int kinds;
|
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)
|
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_list *ref_list = (struct ref_list*)(cb_data);
|
||||||
struct ref_item *newitem;
|
struct ref_item *newitem;
|
||||||
struct commit *commit;
|
struct commit *commit;
|
||||||
int kind;
|
int kind, i;
|
||||||
int len;
|
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 */
|
/* Detect kind */
|
||||||
if (!prefixcmp(refname, "refs/heads/")) {
|
for (i = 0; i < ARRAY_SIZE(ref_kind); i++) {
|
||||||
kind = REF_LOCAL_BRANCH;
|
prefix = ref_kind[i].prefix;
|
||||||
refname += 11;
|
if (strncmp(refname, prefix, ref_kind[i].pfxlen))
|
||||||
} else if (!prefixcmp(refname, "refs/remotes/")) {
|
continue;
|
||||||
kind = REF_REMOTE_BRANCH;
|
kind = ref_kind[i].kind;
|
||||||
refname += 13;
|
refname += ref_kind[i].pfxlen;
|
||||||
} else
|
break;
|
||||||
|
}
|
||||||
|
if (ARRAY_SIZE(ref_kind) <= i)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
commit = lookup_commit_reference_gently(sha1, 1);
|
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->name = xstrdup(refname);
|
||||||
newitem->kind = kind;
|
newitem->kind = kind;
|
||||||
newitem->commit = commit;
|
newitem->commit = commit;
|
||||||
len = strlen(newitem->name);
|
newitem->len = strlen(refname);
|
||||||
if (len > ref_list->maxwidth)
|
newitem->dest = resolve_symref(orig_refname, prefix);
|
||||||
ref_list->maxwidth = len;
|
/* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -257,8 +284,10 @@ static void free_ref_list(struct ref_list *ref_list)
|
||||||
{
|
{
|
||||||
int i;
|
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].name);
|
||||||
|
free(ref_list->list[i].dest);
|
||||||
|
}
|
||||||
free(ref_list->list);
|
free(ref_list->list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,19 +301,30 @@ static int ref_cmp(const void *r1, const void *r2)
|
||||||
return strcmp(c1->name, c2->name);
|
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;
|
int ours, theirs;
|
||||||
struct branch *branch = branch_get(branch_name);
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strbuf_addch(stat, '[');
|
||||||
|
if (show_upstream_ref)
|
||||||
|
strbuf_addf(stat, "%s: ",
|
||||||
|
shorten_unambiguous_ref(branch->merge[0]->dst, 0));
|
||||||
if (!ours)
|
if (!ours)
|
||||||
strbuf_addf(stat, "[behind %d] ", theirs);
|
strbuf_addf(stat, "behind %d] ", theirs);
|
||||||
else if (!theirs)
|
else if (!theirs)
|
||||||
strbuf_addf(stat, "[ahead %d] ", ours);
|
strbuf_addf(stat, "ahead %d] ", ours);
|
||||||
else
|
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)
|
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,
|
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;
|
char c;
|
||||||
int color;
|
int color;
|
||||||
struct commit *commit = item->commit;
|
struct commit *commit = item->commit;
|
||||||
|
struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
|
||||||
|
|
||||||
if (!matches_merge_filter(commit))
|
if (!matches_merge_filter(commit))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (item->kind) {
|
switch (item->kind) {
|
||||||
case REF_LOCAL_BRANCH:
|
case REF_LOCAL_BRANCH:
|
||||||
color = COLOR_BRANCH_LOCAL;
|
color = BRANCH_COLOR_LOCAL;
|
||||||
break;
|
break;
|
||||||
case REF_REMOTE_BRANCH:
|
case REF_REMOTE_BRANCH:
|
||||||
color = COLOR_BRANCH_REMOTE;
|
color = BRANCH_COLOR_REMOTE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
color = COLOR_BRANCH_PLAIN;
|
color = BRANCH_COLOR_PLAIN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = ' ';
|
c = ' ';
|
||||||
if (current) {
|
if (current) {
|
||||||
c = '*';
|
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;
|
struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
|
||||||
const char *sub = " **** invalid ref ****";
|
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)
|
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),
|
strbuf_addf(&out, " %s %s%s",
|
||||||
maxwidth, item->name,
|
find_unique_abbrev(item->commit->object.sha1, abbrev),
|
||||||
branch_get_color(COLOR_BRANCH_RESET),
|
stat.buf, sub);
|
||||||
find_unique_abbrev(item->commit->object.sha1, abbrev),
|
|
||||||
stat.buf, sub);
|
|
||||||
strbuf_release(&stat);
|
strbuf_release(&stat);
|
||||||
strbuf_release(&subject);
|
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)
|
static int calc_maxwidth(struct ref_list *refs)
|
||||||
{
|
{
|
||||||
int i, l, w = 0;
|
int i, w = 0;
|
||||||
for (i = 0; i < refs->index; i++) {
|
for (i = 0; i < refs->index; i++) {
|
||||||
if (!matches_merge_filter(refs->list[i].commit))
|
if (!matches_merge_filter(refs->list[i].commit))
|
||||||
continue;
|
continue;
|
||||||
l = strlen(refs->list[i].name);
|
if (refs->list[i].len > w)
|
||||||
if (l > w)
|
w = refs->list[i].len;
|
||||||
w = l;
|
|
||||||
}
|
}
|
||||||
return w;
|
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)) {
|
is_descendant_of(head_commit, with_commit)) {
|
||||||
struct ref_item item;
|
struct ref_item item;
|
||||||
item.name = xstrdup("(no branch)");
|
item.name = xstrdup("(no branch)");
|
||||||
|
item.len = strlen(item.name);
|
||||||
item.kind = REF_LOCAL_BRANCH;
|
item.kind = REF_LOCAL_BRANCH;
|
||||||
|
item.dest = NULL;
|
||||||
item.commit = head_commit;
|
item.commit = head_commit;
|
||||||
if (strlen(item.name) > ref_list.maxwidth)
|
if (item.len > ref_list.maxwidth)
|
||||||
ref_list.maxwidth = strlen(item.name);
|
ref_list.maxwidth = item.len;
|
||||||
print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1);
|
print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1, "");
|
||||||
free(item.name);
|
free(item.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,8 +460,11 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str
|
||||||
int current = !detached &&
|
int current = !detached &&
|
||||||
(ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
|
(ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
|
||||||
!strcmp(ref_list.list[i].name, head);
|
!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,
|
print_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose,
|
||||||
abbrev, current);
|
abbrev, current, prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
free_ref_list(&ref_list);
|
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;
|
struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
|
struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
|
||||||
|
int recovery = 0;
|
||||||
|
|
||||||
if (!oldname)
|
if (!oldname)
|
||||||
die("cannot rename the current branch while not on any.");
|
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))
|
if (strbuf_check_branch_ref(&newref, newname))
|
||||||
die("Invalid branch name: %s", oldref.buf);
|
die("Invalid branch name: '%s'", newname);
|
||||||
|
|
||||||
strbuf_addf(&newref, "refs/heads/%s", newname);
|
|
||||||
|
|
||||||
if (check_ref_format(newref.buf))
|
|
||||||
die("Invalid branch name: %s", newref.buf);
|
|
||||||
|
|
||||||
if (resolve_ref(newref.buf, sha1, 1, NULL) && !force)
|
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",
|
strbuf_addf(&logmsg, "Branch: renamed %s to %s",
|
||||||
oldref.buf, newref.buf);
|
oldref.buf, newref.buf);
|
||||||
|
@ -445,6 +504,9 @@ static void rename_branch(const char *oldname, const char *newname, int force)
|
||||||
die("Branch rename failed");
|
die("Branch rename failed");
|
||||||
strbuf_release(&logmsg);
|
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 */
|
/* no need to pass logmsg here as HEAD didn't really move */
|
||||||
if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL))
|
if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL))
|
||||||
die("Branch renamed to %s, but HEAD is not updated!", newname);
|
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[] = {
|
struct option options[] = {
|
||||||
OPT_GROUP("Generic options"),
|
OPT_GROUP("Generic options"),
|
||||||
OPT__VERBOSE(&verbose),
|
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),
|
BRANCH_TRACK_EXPLICIT),
|
||||||
OPT_BOOLEAN( 0 , "color", &branch_use_color, "use colored output"),
|
OPT_BOOLEAN( 0 , "color", &branch_use_color, "use colored output"),
|
||||||
OPT_SET_INT('r', NULL, &kinds, "act on remote-tracking branches",
|
OPT_SET_INT('r', NULL, &kinds, "act on remote-tracking branches",
|
||||||
|
|
|
@ -5,9 +5,18 @@
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
#include "strbuf.h"
|
||||||
|
|
||||||
int cmd_check_ref_format(int argc, const char **argv, const char *prefix)
|
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)
|
if (argc != 2)
|
||||||
usage("git check-ref-format refname");
|
usage("git check-ref-format refname");
|
||||||
return !!check_ref_format(argv[1]);
|
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)
|
static void checkout_all(const char *prefix, int prefix_length)
|
||||||
{
|
{
|
||||||
int i, errs = 0;
|
int i, errs = 0;
|
||||||
struct cache_entry* last_ce = NULL;
|
struct cache_entry *last_ce = NULL;
|
||||||
|
|
||||||
for (i = 0; i < active_nr ; i++) {
|
for (i = 0; i < active_nr ; i++) {
|
||||||
struct cache_entry *ce = active_cache[i];
|
struct cache_entry *ce = active_cache[i];
|
||||||
|
@ -278,7 +278,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
|
||||||
p = prefix_path(prefix, prefix_length, arg);
|
p = prefix_path(prefix, prefix_length, arg);
|
||||||
checkout_file(p, prefix_length);
|
checkout_file(p, prefix_length);
|
||||||
if (p < arg || p > arg + strlen(arg))
|
if (p < arg || p > arg + strlen(arg))
|
||||||
free((char*)p);
|
free((char *)p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_from_stdin) {
|
if (read_from_stdin) {
|
||||||
|
|
|
@ -179,7 +179,7 @@ static int checkout_merged(int pos, struct checkout *state)
|
||||||
/*
|
/*
|
||||||
* NEEDSWORK:
|
* NEEDSWORK:
|
||||||
* There is absolutely no reason to write this as a blob object
|
* 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
|
* primarily to get to the write_entry() machinery that massages
|
||||||
* the contents to work-tree format and writes out which only
|
* the contents to work-tree format and writes out which only
|
||||||
* allows it for a cache entry. The code in write_entry() needs
|
* 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));
|
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
|
||||||
|
|
||||||
newfd = hold_locked_index(lock_file, 1);
|
newfd = hold_locked_index(lock_file, 1);
|
||||||
if (read_cache() < 0)
|
if (read_cache_preload(pathspec) < 0)
|
||||||
return error("corrupt index file");
|
return error("corrupt index file");
|
||||||
|
|
||||||
if (source_tree)
|
if (source_tree)
|
||||||
|
@ -293,6 +293,8 @@ static void show_local_changes(struct object *head)
|
||||||
init_revisions(&rev, NULL);
|
init_revisions(&rev, NULL);
|
||||||
rev.abbrev = 0;
|
rev.abbrev = 0;
|
||||||
rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
|
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);
|
add_pending_object(&rev, head, NULL);
|
||||||
run_diff_index(&rev, 0);
|
run_diff_index(&rev, 0);
|
||||||
}
|
}
|
||||||
|
@ -349,16 +351,11 @@ struct branch_info {
|
||||||
static void setup_branch_path(struct branch_info *branch)
|
static void setup_branch_path(struct branch_info *branch)
|
||||||
{
|
{
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
int ret;
|
|
||||||
|
|
||||||
if ((ret = interpret_nth_last_branch(branch->name, &buf))
|
strbuf_branchname(&buf, branch->name);
|
||||||
&& ret == strlen(branch->name)) {
|
if (strcmp(buf.buf, branch->name))
|
||||||
branch->name = xstrdup(buf.buf);
|
branch->name = xstrdup(buf.buf);
|
||||||
strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
|
strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
|
||||||
} else {
|
|
||||||
strbuf_addstr(&buf, "refs/heads/");
|
|
||||||
strbuf_addstr(&buf, branch->name);
|
|
||||||
}
|
|
||||||
branch->path = strbuf_detach(&buf, NULL);
|
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));
|
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
|
||||||
int newfd = hold_locked_index(lock_file, 1);
|
int newfd = hold_locked_index(lock_file, 1);
|
||||||
|
|
||||||
if (read_cache() < 0)
|
if (read_cache_preload(NULL) < 0)
|
||||||
return error("corrupt index file");
|
return error("corrupt index file");
|
||||||
|
|
||||||
if (opts->force) {
|
if (opts->force) {
|
||||||
|
@ -403,7 +400,7 @@ static int merge_working_tree(struct checkout_opts *opts,
|
||||||
topts.verbose_update = !opts->quiet;
|
topts.verbose_update = !opts->quiet;
|
||||||
topts.fn = twoway_merge;
|
topts.fn = twoway_merge;
|
||||||
topts.dir = xcalloc(1, sizeof(*topts.dir));
|
topts.dir = xcalloc(1, sizeof(*topts.dir));
|
||||||
topts.dir->show_ignored = 1;
|
topts.dir->flags |= DIR_SHOW_IGNORED;
|
||||||
topts.dir->exclude_per_dir = ".gitignore";
|
topts.dir->exclude_per_dir = ".gitignore";
|
||||||
tree = parse_tree_indirect(old->commit->object.sha1);
|
tree = parse_tree_indirect(old->commit->object.sha1);
|
||||||
init_tree_desc(&trees[0], tree->buffer, tree->size);
|
init_tree_desc(&trees[0], tree->buffer, tree->size);
|
||||||
|
@ -544,18 +541,10 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
|
||||||
parse_commit(new->commit);
|
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 (!old.commit && !opts->force) {
|
||||||
if (!opts->quiet) {
|
if (!opts->quiet) {
|
||||||
fprintf(stderr, "warning: You appear to be on a branch yet to be born.\n");
|
warning("You appear to be on a branch yet to be born.");
|
||||||
fprintf(stderr, "warning: Forcing checkout of %s.\n", new->name);
|
warning("Forcing checkout of %s.", new->name);
|
||||||
}
|
}
|
||||||
opts->force = 1;
|
opts->force = 1;
|
||||||
}
|
}
|
||||||
|
@ -564,6 +553,14 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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);
|
update_refs_for_switch(opts, &old, new);
|
||||||
|
|
||||||
ret = post_checkout_hook(old.commit, new->commit, 1);
|
ret = post_checkout_hook(old.commit, new->commit, 1);
|
||||||
|
@ -734,12 +731,11 @@ no_reference:
|
||||||
|
|
||||||
if (opts.new_branch) {
|
if (opts.new_branch) {
|
||||||
struct strbuf buf = STRBUF_INIT;
|
struct strbuf buf = STRBUF_INIT;
|
||||||
strbuf_addstr(&buf, "refs/heads/");
|
if (strbuf_check_branch_ref(&buf, opts.new_branch))
|
||||||
strbuf_addstr(&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))
|
if (!get_sha1(buf.buf, rev))
|
||||||
die("git checkout: branch %s already exists", opts.new_branch);
|
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);
|
strbuf_release(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
memset(&dir, 0, sizeof(dir));
|
memset(&dir, 0, sizeof(dir));
|
||||||
if (ignored_only)
|
if (ignored_only)
|
||||||
dir.show_ignored = 1;
|
dir.flags |= DIR_SHOW_IGNORED;
|
||||||
|
|
||||||
if (ignored && ignored_only)
|
if (ignored && ignored_only)
|
||||||
die("-x and -X cannot be used together");
|
die("-x and -X cannot be used together");
|
||||||
|
@ -69,7 +69,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
||||||
die("clean.requireForce%s set and -n or -f not given; "
|
die("clean.requireForce%s set and -n or -f not given; "
|
||||||
"refusing to clean", config_set ? "" : " not");
|
"refusing to clean", config_set ? "" : " not");
|
||||||
|
|
||||||
dir.show_other_directories = 1;
|
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
|
||||||
|
|
||||||
if (!ignored)
|
if (!ignored)
|
||||||
setup_standard_excludes(&dir);
|
setup_standard_excludes(&dir);
|
||||||
|
|
138
builtin-clone.c
138
builtin-clone.c
|
@ -20,6 +20,9 @@
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
#include "pack-refs.h"
|
#include "pack-refs.h"
|
||||||
#include "sigchain.h"
|
#include "sigchain.h"
|
||||||
|
#include "branch.h"
|
||||||
|
#include "remote.h"
|
||||||
|
#include "run-command.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Overall FIXMEs:
|
* 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)
|
static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
|
||||||
{
|
{
|
||||||
const char *end = repo + strlen(repo), *start;
|
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--;
|
end--;
|
||||||
if (end - repo > 5 && is_dir_sep(end[-5]) &&
|
if (end - repo > 5 && is_dir_sep(end[-5]) &&
|
||||||
!strncmp(end - 4, ".git", 4)) {
|
!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) {
|
if (is_bare) {
|
||||||
struct strbuf result = STRBUF_INIT;
|
struct strbuf result = STRBUF_INIT;
|
||||||
strbuf_addf(&result, "%.*s.git", (int)(end - start), start);
|
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 dir;
|
||||||
return xstrndup(start, end - start);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void strip_trailing_slashes(char *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)
|
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 (!option_no_hardlinks) {
|
||||||
if (!link(src->buf, dest->buf))
|
if (!link(src->buf, dest->buf))
|
||||||
continue;
|
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_work_tree;
|
||||||
static const char *junk_git_dir;
|
static const char *junk_git_dir;
|
||||||
pid_t junk_pid;
|
static pid_t junk_pid;
|
||||||
|
|
||||||
static void remove_junk(void)
|
static void remove_junk(void)
|
||||||
{
|
{
|
||||||
|
@ -293,43 +321,6 @@ static void remove_junk_on_signal(int signo)
|
||||||
raise(signo);
|
raise(signo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ref *locate_head(const struct ref *refs,
|
|
||||||
const struct ref *mapped_refs,
|
|
||||||
const struct ref **remote_head_p)
|
|
||||||
{
|
|
||||||
const struct ref *remote_head = NULL;
|
|
||||||
const struct ref *remote_master = NULL;
|
|
||||||
const struct ref *r;
|
|
||||||
for (r = refs; r; r = r->next)
|
|
||||||
if (!strcmp(r->name, "HEAD"))
|
|
||||||
remote_head = r;
|
|
||||||
|
|
||||||
for (r = mapped_refs; r; r = r->next)
|
|
||||||
if (!strcmp(r->name, "refs/heads/master"))
|
|
||||||
remote_master = r;
|
|
||||||
|
|
||||||
if (remote_head_p)
|
|
||||||
*remote_head_p = remote_head;
|
|
||||||
|
|
||||||
/* If there's no HEAD value at all, never mind. */
|
|
||||||
if (!remote_head)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* If refs/heads/master could be right, it is. */
|
|
||||||
if (remote_master && !hashcmp(remote_master->old_sha1,
|
|
||||||
remote_head->old_sha1))
|
|
||||||
return remote_master;
|
|
||||||
|
|
||||||
/* Look for another ref that points there */
|
|
||||||
for (r = mapped_refs; r; r = r->next)
|
|
||||||
if (r != remote_head &&
|
|
||||||
!hashcmp(r->old_sha1, remote_head->old_sha1))
|
|
||||||
return r;
|
|
||||||
|
|
||||||
/* Nothing is the same */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct ref *write_remote_refs(const struct ref *refs,
|
static struct ref *write_remote_refs(const struct ref *refs,
|
||||||
struct refspec *refspec, const char *reflog)
|
struct refspec *refspec, const char *reflog)
|
||||||
{
|
{
|
||||||
|
@ -350,23 +341,8 @@ static struct ref *write_remote_refs(const struct ref *refs,
|
||||||
return local_refs;
|
return local_refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void install_branch_config(const char *local,
|
|
||||||
const char *origin,
|
|
||||||
const char *remote)
|
|
||||||
{
|
|
||||||
struct strbuf key = STRBUF_INIT;
|
|
||||||
strbuf_addf(&key, "branch.%s.remote", local);
|
|
||||||
git_config_set(key.buf, origin);
|
|
||||||
strbuf_reset(&key);
|
|
||||||
strbuf_addf(&key, "branch.%s.merge", local);
|
|
||||||
git_config_set(key.buf, remote);
|
|
||||||
strbuf_release(&key);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cmd_clone(int argc, const char **argv, const char *prefix)
|
int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int use_local_hardlinks = 1;
|
|
||||||
int use_separate_remote = 1;
|
|
||||||
int is_bundle = 0;
|
int is_bundle = 0;
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
const char *repo_name, *repo, *work_tree, *git_dir;
|
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 strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
|
||||||
struct transport *transport = NULL;
|
struct transport *transport = NULL;
|
||||||
char *src_ref_prefix = "refs/heads/";
|
char *src_ref_prefix = "refs/heads/";
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
struct refspec refspec;
|
struct refspec *refspec;
|
||||||
|
const char *fetch_pattern;
|
||||||
|
|
||||||
junk_pid = getpid();
|
junk_pid = getpid();
|
||||||
|
|
||||||
|
@ -388,9 +366,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
if (argc == 0)
|
if (argc == 0)
|
||||||
die("You must specify a repository to clone.");
|
die("You must specify a repository to clone.");
|
||||||
|
|
||||||
if (option_no_hardlinks)
|
|
||||||
use_local_hardlinks = 0;
|
|
||||||
|
|
||||||
if (option_mirror)
|
if (option_mirror)
|
||||||
option_bare = 1;
|
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.",
|
die("--bare and --origin %s options are incompatible.",
|
||||||
option_origin);
|
option_origin);
|
||||||
option_no_checkout = 1;
|
option_no_checkout = 1;
|
||||||
use_separate_remote = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!option_origin)
|
if (!option_origin)
|
||||||
|
@ -457,7 +431,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
atexit(remove_junk);
|
atexit(remove_junk);
|
||||||
sigchain_push_common(remove_junk_on_signal);
|
sigchain_push_common(remove_junk_on_signal);
|
||||||
|
|
||||||
setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1);
|
setenv(CONFIG_ENVIRONMENT, mkpath("%s/config", git_dir), 1);
|
||||||
|
|
||||||
if (safe_create_leading_directories_const(git_dir) < 0)
|
if (safe_create_leading_directories_const(git_dir) < 0)
|
||||||
die("could not create leading directories of '%s'", git_dir);
|
die("could not create leading directories of '%s'", git_dir);
|
||||||
|
@ -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(&branch_top, "refs/remotes/%s/", option_origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
|
||||||
|
|
||||||
if (option_mirror || !option_bare) {
|
if (option_mirror || !option_bare) {
|
||||||
/* Configure the remote */
|
/* Configure the remote */
|
||||||
|
strbuf_addf(&key, "remote.%s.fetch", option_origin);
|
||||||
|
git_config_set_multivar(key.buf, value.buf, "^$", 0);
|
||||||
|
strbuf_reset(&key);
|
||||||
|
|
||||||
if (option_mirror) {
|
if (option_mirror) {
|
||||||
strbuf_addf(&key, "remote.%s.mirror", option_origin);
|
strbuf_addf(&key, "remote.%s.mirror", option_origin);
|
||||||
git_config_set(key.buf, "true");
|
git_config_set(key.buf, "true");
|
||||||
|
@ -497,19 +477,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
strbuf_addf(&key, "remote.%s.url", option_origin);
|
strbuf_addf(&key, "remote.%s.url", option_origin);
|
||||||
git_config_set(key.buf, repo);
|
git_config_set(key.buf, repo);
|
||||||
strbuf_reset(&key);
|
|
||||||
|
|
||||||
strbuf_addf(&key, "remote.%s.fetch", option_origin);
|
|
||||||
strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
|
|
||||||
git_config_set_multivar(key.buf, value.buf, "^$", 0);
|
|
||||||
strbuf_reset(&key);
|
strbuf_reset(&key);
|
||||||
strbuf_reset(&value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refspec.force = 0;
|
fetch_pattern = value.buf;
|
||||||
refspec.pattern = 1;
|
refspec = parse_fetch_refspec(1, &fetch_pattern);
|
||||||
refspec.src = src_ref_prefix;
|
|
||||||
refspec.dst = branch_top.buf;
|
strbuf_reset(&value);
|
||||||
|
|
||||||
if (path && !is_bundle)
|
if (path && !is_bundle)
|
||||||
refs = clone_local(path, git_dir);
|
refs = clone_local(path, git_dir);
|
||||||
|
@ -543,9 +517,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
if (refs) {
|
if (refs) {
|
||||||
clear_extra_refs();
|
clear_extra_refs();
|
||||||
|
|
||||||
mapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);
|
mapped_refs = write_remote_refs(refs, refspec, reflog_msg.buf);
|
||||||
|
|
||||||
head_points_at = locate_head(refs, mapped_refs, &remote_head);
|
remote_head = find_ref_by_name(refs, "HEAD");
|
||||||
|
head_points_at = guess_remote_head(remote_head, mapped_refs, 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
warning("You appear to have cloned an empty repository.");
|
warning("You appear to have cloned an empty repository.");
|
||||||
|
@ -553,7 +528,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
remote_head = NULL;
|
remote_head = NULL;
|
||||||
option_no_checkout = 1;
|
option_no_checkout = 1;
|
||||||
if (!option_bare)
|
if (!option_bare)
|
||||||
install_branch_config("master", option_origin,
|
install_branch_config(0, "master", option_origin,
|
||||||
"refs/heads/master");
|
"refs/heads/master");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,7 +558,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
head_points_at->peer_ref->name,
|
head_points_at->peer_ref->name,
|
||||||
reflog_msg.buf);
|
reflog_msg.buf);
|
||||||
|
|
||||||
install_branch_config(head, option_origin,
|
install_branch_config(0, head, option_origin,
|
||||||
head_points_at->name);
|
head_points_at->name);
|
||||||
}
|
}
|
||||||
} else if (remote_head) {
|
} else if (remote_head) {
|
||||||
|
@ -631,6 +606,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
if (write_cache(fd, active_cache, active_nr) ||
|
if (write_cache(fd, active_cache, active_nr) ||
|
||||||
commit_locked_index(lock_file))
|
commit_locked_index(lock_file))
|
||||||
die("unable to write new index 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);
|
strbuf_release(&reflog_msg);
|
||||||
|
@ -638,5 +616,5 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||||
strbuf_release(&key);
|
strbuf_release(&key);
|
||||||
strbuf_release(&value);
|
strbuf_release(&value);
|
||||||
junk_pid = 0;
|
junk_pid = 0;
|
||||||
return 0;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
427
builtin-config.c
427
builtin-config.c
|
@ -1,9 +1,12 @@
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
|
#include "parse-options.h"
|
||||||
|
|
||||||
static const char git_config_set_usage[] =
|
static const char *const builtin_config_usage[] = {
|
||||||
"git config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]";
|
"git config [options]",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
static char *key;
|
static char *key;
|
||||||
static regex_t *key_regexp;
|
static regex_t *key_regexp;
|
||||||
|
@ -16,7 +19,67 @@ static int seen;
|
||||||
static char delim = '=';
|
static char delim = '=';
|
||||||
static char key_delim = ' ';
|
static char key_delim = ' ';
|
||||||
static char term = '\n';
|
static char term = '\n';
|
||||||
static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW;
|
|
||||||
|
static int use_global_config, use_system_config;
|
||||||
|
static const char *given_config_file;
|
||||||
|
static int actions, types;
|
||||||
|
static const char *get_color_slot, *get_colorbool_slot;
|
||||||
|
static int end_null;
|
||||||
|
|
||||||
|
#define ACTION_GET (1<<0)
|
||||||
|
#define ACTION_GET_ALL (1<<1)
|
||||||
|
#define ACTION_GET_REGEXP (1<<2)
|
||||||
|
#define ACTION_REPLACE_ALL (1<<3)
|
||||||
|
#define ACTION_ADD (1<<4)
|
||||||
|
#define ACTION_UNSET (1<<5)
|
||||||
|
#define ACTION_UNSET_ALL (1<<6)
|
||||||
|
#define ACTION_RENAME_SECTION (1<<7)
|
||||||
|
#define ACTION_REMOVE_SECTION (1<<8)
|
||||||
|
#define ACTION_LIST (1<<9)
|
||||||
|
#define ACTION_EDIT (1<<10)
|
||||||
|
#define ACTION_SET (1<<11)
|
||||||
|
#define ACTION_SET_ALL (1<<12)
|
||||||
|
#define ACTION_GET_COLOR (1<<13)
|
||||||
|
#define ACTION_GET_COLORBOOL (1<<14)
|
||||||
|
|
||||||
|
#define TYPE_BOOL (1<<0)
|
||||||
|
#define TYPE_INT (1<<1)
|
||||||
|
#define TYPE_BOOL_OR_INT (1<<2)
|
||||||
|
|
||||||
|
static struct option builtin_config_options[] = {
|
||||||
|
OPT_GROUP("Config file location"),
|
||||||
|
OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"),
|
||||||
|
OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
|
||||||
|
OPT_STRING('f', "file", &given_config_file, "FILE", "use given config file"),
|
||||||
|
OPT_GROUP("Action"),
|
||||||
|
OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET),
|
||||||
|
OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL),
|
||||||
|
OPT_BIT(0, "get-regexp", &actions, "get values for regexp: name-regex [value-regex]", ACTION_GET_REGEXP),
|
||||||
|
OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name value [value_regex]", ACTION_REPLACE_ALL),
|
||||||
|
OPT_BIT(0, "add", &actions, "adds a new variable: name value", ACTION_ADD),
|
||||||
|
OPT_BIT(0, "unset", &actions, "removes a variable: name [value-regex]", ACTION_UNSET),
|
||||||
|
OPT_BIT(0, "unset-all", &actions, "removes all matches: name [value-regex]", ACTION_UNSET_ALL),
|
||||||
|
OPT_BIT(0, "rename-section", &actions, "rename section: old-name new-name", ACTION_RENAME_SECTION),
|
||||||
|
OPT_BIT(0, "remove-section", &actions, "remove a section: name", ACTION_REMOVE_SECTION),
|
||||||
|
OPT_BIT('l', "list", &actions, "list all", ACTION_LIST),
|
||||||
|
OPT_BIT('e', "edit", &actions, "opens an editor", ACTION_EDIT),
|
||||||
|
OPT_STRING(0, "get-color", &get_color_slot, "slot", "find the color configured: [default]"),
|
||||||
|
OPT_STRING(0, "get-colorbool", &get_colorbool_slot, "slot", "find the color setting: [stdout-is-tty]"),
|
||||||
|
OPT_GROUP("Type"),
|
||||||
|
OPT_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL),
|
||||||
|
OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT),
|
||||||
|
OPT_BIT(0, "bool-or-int", &types, "value is --bool or --int", TYPE_BOOL_OR_INT),
|
||||||
|
OPT_GROUP("Other"),
|
||||||
|
OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"),
|
||||||
|
OPT_END(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void check_argc(int argc, int min, int max) {
|
||||||
|
if (argc >= min && argc <= max)
|
||||||
|
return;
|
||||||
|
error("wrong number of arguments");
|
||||||
|
usage_with_options(builtin_config_usage, builtin_config_options);
|
||||||
|
}
|
||||||
|
|
||||||
static int show_all_config(const char *key_, const char *value_, void *cb)
|
static int show_all_config(const char *key_, const char *value_, void *cb)
|
||||||
{
|
{
|
||||||
|
@ -27,7 +90,7 @@ static int show_all_config(const char *key_, const char *value_, void *cb)
|
||||||
return 0;
|
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];
|
char value[256];
|
||||||
const char *vptr = value;
|
const char *vptr = value;
|
||||||
|
@ -49,11 +112,11 @@ static int show_config(const char* key_, const char* value_, void *cb)
|
||||||
}
|
}
|
||||||
if (seen && !do_all)
|
if (seen && !do_all)
|
||||||
dup_error = 1;
|
dup_error = 1;
|
||||||
if (type == T_INT)
|
if (types == TYPE_INT)
|
||||||
sprintf(value, "%d", git_config_int(key_, value_?value_:""));
|
sprintf(value, "%d", git_config_int(key_, value_?value_:""));
|
||||||
else if (type == T_BOOL)
|
else if (types == TYPE_BOOL)
|
||||||
vptr = git_config_bool(key_, value_) ? "true" : "false";
|
vptr = git_config_bool(key_, value_) ? "true" : "false";
|
||||||
else if (type == T_BOOL_OR_INT) {
|
else if (types == TYPE_BOOL_OR_INT) {
|
||||||
int is_bool, v;
|
int is_bool, v;
|
||||||
v = git_config_bool_or_int(key_, value_, &is_bool);
|
v = git_config_bool_or_int(key_, value_, &is_bool);
|
||||||
if (is_bool)
|
if (is_bool)
|
||||||
|
@ -74,7 +137,7 @@ static int show_config(const char* key_, const char* value_, void *cb)
|
||||||
return 0;
|
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;
|
int ret = -1;
|
||||||
char *tl;
|
char *tl;
|
||||||
|
@ -152,18 +215,18 @@ static char *normalize_value(const char *key, const char *value)
|
||||||
if (!value)
|
if (!value)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (type == T_RAW)
|
if (types == 0)
|
||||||
normalized = xstrdup(value);
|
normalized = xstrdup(value);
|
||||||
else {
|
else {
|
||||||
normalized = xmalloc(64);
|
normalized = xmalloc(64);
|
||||||
if (type == T_INT) {
|
if (types == TYPE_INT) {
|
||||||
int v = git_config_int(key, value);
|
int v = git_config_int(key, value);
|
||||||
sprintf(normalized, "%d", v);
|
sprintf(normalized, "%d", v);
|
||||||
}
|
}
|
||||||
else if (type == T_BOOL)
|
else if (types == TYPE_BOOL)
|
||||||
sprintf(normalized, "%s",
|
sprintf(normalized, "%s",
|
||||||
git_config_bool(key, value) ? "true" : "false");
|
git_config_bool(key, value) ? "true" : "false");
|
||||||
else if (type == T_BOOL_OR_INT) {
|
else if (types == TYPE_BOOL_OR_INT) {
|
||||||
int is_bool, v;
|
int is_bool, v;
|
||||||
v = git_config_bool_or_int(key, value, &is_bool);
|
v = git_config_bool_or_int(key, value, &is_bool);
|
||||||
if (!is_bool)
|
if (!is_bool)
|
||||||
|
@ -178,6 +241,7 @@ static char *normalize_value(const char *key, const char *value)
|
||||||
|
|
||||||
static int get_color_found;
|
static int get_color_found;
|
||||||
static const char *get_color_slot;
|
static const char *get_color_slot;
|
||||||
|
static const char *get_colorbool_slot;
|
||||||
static char parsed_color[COLOR_MAXLEN];
|
static char parsed_color[COLOR_MAXLEN];
|
||||||
|
|
||||||
static int git_get_color_config(const char *var, const char *value, void *cb)
|
static int git_get_color_config(const char *var, const char *value, void *cb)
|
||||||
|
@ -191,29 +255,8 @@ static int git_get_color_config(const char *var, const char *value, void *cb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_color(int argc, const char **argv)
|
static void get_color(const char *def_color)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* grab the color setting for the given slot from the configuration,
|
|
||||||
* or parse the default value if missing, and return ANSI color
|
|
||||||
* escape sequence.
|
|
||||||
*
|
|
||||||
* e.g.
|
|
||||||
* git config --get-color color.diff.whitespace "blue reverse"
|
|
||||||
*/
|
|
||||||
const char *def_color = NULL;
|
|
||||||
|
|
||||||
switch (argc) {
|
|
||||||
default:
|
|
||||||
usage(git_config_set_usage);
|
|
||||||
case 2:
|
|
||||||
def_color = argv[1];
|
|
||||||
/* fallthru */
|
|
||||||
case 1:
|
|
||||||
get_color_slot = argv[0];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_color_found = 0;
|
get_color_found = 0;
|
||||||
parsed_color[0] = '\0';
|
parsed_color[0] = '\0';
|
||||||
git_config(git_get_color_config, NULL);
|
git_config(git_get_color_config, NULL);
|
||||||
|
@ -222,7 +265,6 @@ static int get_color(int argc, const char **argv)
|
||||||
color_parse(def_color, "command line", parsed_color);
|
color_parse(def_color, "command line", parsed_color);
|
||||||
|
|
||||||
fputs(parsed_color, stdout);
|
fputs(parsed_color, stdout);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stdout_is_tty;
|
static int stdout_is_tty;
|
||||||
|
@ -231,7 +273,7 @@ static int get_diff_color_found;
|
||||||
static int git_get_colorbool_config(const char *var, const char *value,
|
static int git_get_colorbool_config(const char *var, const char *value,
|
||||||
void *cb)
|
void *cb)
|
||||||
{
|
{
|
||||||
if (!strcmp(var, get_color_slot)) {
|
if (!strcmp(var, get_colorbool_slot)) {
|
||||||
get_colorbool_found =
|
get_colorbool_found =
|
||||||
git_config_colorbool(var, value, stdout_is_tty);
|
git_config_colorbool(var, value, stdout_is_tty);
|
||||||
}
|
}
|
||||||
|
@ -246,183 +288,190 @@ static int git_get_colorbool_config(const char *var, const char *value,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_colorbool(int argc, const char **argv)
|
static int get_colorbool(int print)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* git config --get-colorbool <slot> [<stdout-is-tty>]
|
|
||||||
*
|
|
||||||
* returns "true" or "false" depending on how <slot>
|
|
||||||
* is configured.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (argc == 2)
|
|
||||||
stdout_is_tty = git_config_bool("command line", argv[1]);
|
|
||||||
else if (argc == 1)
|
|
||||||
stdout_is_tty = isatty(1);
|
|
||||||
else
|
|
||||||
usage(git_config_set_usage);
|
|
||||||
get_colorbool_found = -1;
|
get_colorbool_found = -1;
|
||||||
get_diff_color_found = -1;
|
get_diff_color_found = -1;
|
||||||
get_color_slot = argv[0];
|
|
||||||
git_config(git_get_colorbool_config, NULL);
|
git_config(git_get_colorbool_config, NULL);
|
||||||
|
|
||||||
if (get_colorbool_found < 0) {
|
if (get_colorbool_found < 0) {
|
||||||
if (!strcmp(get_color_slot, "color.diff"))
|
if (!strcmp(get_colorbool_slot, "color.diff"))
|
||||||
get_colorbool_found = get_diff_color_found;
|
get_colorbool_found = get_diff_color_found;
|
||||||
if (get_colorbool_found < 0)
|
if (get_colorbool_found < 0)
|
||||||
get_colorbool_found = git_use_color_default;
|
get_colorbool_found = git_use_color_default;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == 1) {
|
if (print) {
|
||||||
return get_colorbool_found ? 0 : 1;
|
|
||||||
} else {
|
|
||||||
printf("%s\n", get_colorbool_found ? "true" : "false");
|
printf("%s\n", get_colorbool_found ? "true" : "false");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
} else
|
||||||
|
return get_colorbool_found ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmd_config(int argc, const char **argv, const char *prefix)
|
int cmd_config(int argc, const char **argv, const char *unused_prefix)
|
||||||
{
|
{
|
||||||
int nongit;
|
int nongit;
|
||||||
char* value;
|
char *value;
|
||||||
const char *file = setup_git_directory_gently(&nongit);
|
const char *prefix = setup_git_directory_gently(&nongit);
|
||||||
|
|
||||||
config_exclusive_filename = getenv(CONFIG_ENVIRONMENT);
|
config_exclusive_filename = getenv(CONFIG_ENVIRONMENT);
|
||||||
|
|
||||||
while (1 < argc) {
|
argc = parse_options(argc, argv, builtin_config_options, builtin_config_usage,
|
||||||
if (!strcmp(argv[1], "--int"))
|
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||||
type = T_INT;
|
|
||||||
else if (!strcmp(argv[1], "--bool"))
|
if (use_global_config + use_system_config + !!given_config_file > 1) {
|
||||||
type = T_BOOL;
|
error("only one config file at a time.");
|
||||||
else if (!strcmp(argv[1], "--bool-or-int"))
|
usage_with_options(builtin_config_usage, builtin_config_options);
|
||||||
type = T_BOOL_OR_INT;
|
|
||||||
else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
|
|
||||||
if (argc != 2)
|
|
||||||
usage(git_config_set_usage);
|
|
||||||
if (git_config(show_all_config, NULL) < 0 &&
|
|
||||||
file && errno)
|
|
||||||
die("unable to read config file %s: %s", file,
|
|
||||||
strerror(errno));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (!strcmp(argv[1], "--global")) {
|
|
||||||
char *home = getenv("HOME");
|
|
||||||
if (home) {
|
|
||||||
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
|
|
||||||
config_exclusive_filename = user_config;
|
|
||||||
} else {
|
|
||||||
die("$HOME not set");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!strcmp(argv[1], "--system"))
|
|
||||||
config_exclusive_filename = git_etc_gitconfig();
|
|
||||||
else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) {
|
|
||||||
if (argc < 3)
|
|
||||||
usage(git_config_set_usage);
|
|
||||||
if (!is_absolute_path(argv[2]) && file)
|
|
||||||
file = prefix_filename(file, strlen(file),
|
|
||||||
argv[2]);
|
|
||||||
else
|
|
||||||
file = argv[2];
|
|
||||||
config_exclusive_filename = file;
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
}
|
|
||||||
else if (!strcmp(argv[1], "--null") || !strcmp(argv[1], "-z")) {
|
|
||||||
term = '\0';
|
|
||||||
delim = '\n';
|
|
||||||
key_delim = '\n';
|
|
||||||
}
|
|
||||||
else if (!strcmp(argv[1], "--rename-section")) {
|
|
||||||
int ret;
|
|
||||||
if (argc != 4)
|
|
||||||
usage(git_config_set_usage);
|
|
||||||
ret = git_config_rename_section(argv[2], argv[3]);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
if (ret == 0) {
|
|
||||||
fprintf(stderr, "No such section!\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (!strcmp(argv[1], "--remove-section")) {
|
|
||||||
int ret;
|
|
||||||
if (argc != 3)
|
|
||||||
usage(git_config_set_usage);
|
|
||||||
ret = git_config_rename_section(argv[2], NULL);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
if (ret == 0) {
|
|
||||||
fprintf(stderr, "No such section!\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} else if (!strcmp(argv[1], "--get-color")) {
|
|
||||||
return get_color(argc-2, argv+2);
|
|
||||||
} else if (!strcmp(argv[1], "--get-colorbool")) {
|
|
||||||
return get_colorbool(argc-2, argv+2);
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (argc) {
|
if (use_global_config) {
|
||||||
case 2:
|
char *home = getenv("HOME");
|
||||||
return get_value(argv[1], NULL);
|
if (home) {
|
||||||
case 3:
|
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
|
||||||
if (!strcmp(argv[1], "--unset"))
|
config_exclusive_filename = user_config;
|
||||||
return git_config_set(argv[2], NULL);
|
|
||||||
else if (!strcmp(argv[1], "--unset-all"))
|
|
||||||
return git_config_set_multivar(argv[2], NULL, NULL, 1);
|
|
||||||
else if (!strcmp(argv[1], "--get"))
|
|
||||||
return get_value(argv[2], NULL);
|
|
||||||
else if (!strcmp(argv[1], "--get-all")) {
|
|
||||||
do_all = 1;
|
|
||||||
return get_value(argv[2], NULL);
|
|
||||||
} else if (!strcmp(argv[1], "--get-regexp")) {
|
|
||||||
show_keys = 1;
|
|
||||||
use_key_regexp = 1;
|
|
||||||
do_all = 1;
|
|
||||||
return get_value(argv[2], NULL);
|
|
||||||
} else {
|
} else {
|
||||||
value = normalize_value(argv[1], argv[2]);
|
die("$HOME not set");
|
||||||
return git_config_set(argv[1], value);
|
|
||||||
}
|
}
|
||||||
case 4:
|
|
||||||
if (!strcmp(argv[1], "--unset"))
|
|
||||||
return git_config_set_multivar(argv[2], NULL, argv[3], 0);
|
|
||||||
else if (!strcmp(argv[1], "--unset-all"))
|
|
||||||
return git_config_set_multivar(argv[2], NULL, argv[3], 1);
|
|
||||||
else if (!strcmp(argv[1], "--get"))
|
|
||||||
return get_value(argv[2], argv[3]);
|
|
||||||
else if (!strcmp(argv[1], "--get-all")) {
|
|
||||||
do_all = 1;
|
|
||||||
return get_value(argv[2], argv[3]);
|
|
||||||
} else if (!strcmp(argv[1], "--get-regexp")) {
|
|
||||||
show_keys = 1;
|
|
||||||
use_key_regexp = 1;
|
|
||||||
do_all = 1;
|
|
||||||
return get_value(argv[2], argv[3]);
|
|
||||||
} else if (!strcmp(argv[1], "--add")) {
|
|
||||||
value = normalize_value(argv[2], argv[3]);
|
|
||||||
return git_config_set_multivar(argv[2], value, "^$", 0);
|
|
||||||
} else if (!strcmp(argv[1], "--replace-all")) {
|
|
||||||
value = normalize_value(argv[2], argv[3]);
|
|
||||||
return git_config_set_multivar(argv[2], value, NULL, 1);
|
|
||||||
} else {
|
|
||||||
value = normalize_value(argv[1], argv[2]);
|
|
||||||
return git_config_set_multivar(argv[1], value, argv[3], 0);
|
|
||||||
}
|
|
||||||
case 5:
|
|
||||||
if (!strcmp(argv[1], "--replace-all")) {
|
|
||||||
value = normalize_value(argv[2], argv[3]);
|
|
||||||
return git_config_set_multivar(argv[2], value, argv[4], 1);
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
default:
|
|
||||||
usage(git_config_set_usage);
|
|
||||||
}
|
}
|
||||||
|
else if (use_system_config)
|
||||||
|
config_exclusive_filename = git_etc_gitconfig();
|
||||||
|
else if (given_config_file) {
|
||||||
|
if (!is_absolute_path(given_config_file) && prefix)
|
||||||
|
config_exclusive_filename = prefix_filename(prefix,
|
||||||
|
strlen(prefix),
|
||||||
|
argv[2]);
|
||||||
|
else
|
||||||
|
config_exclusive_filename = given_config_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end_null) {
|
||||||
|
term = '\0';
|
||||||
|
delim = '\n';
|
||||||
|
key_delim = '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAS_MULTI_BITS(types)) {
|
||||||
|
error("only one type at a time.");
|
||||||
|
usage_with_options(builtin_config_usage, builtin_config_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_color_slot)
|
||||||
|
actions |= ACTION_GET_COLOR;
|
||||||
|
if (get_colorbool_slot)
|
||||||
|
actions |= ACTION_GET_COLORBOOL;
|
||||||
|
|
||||||
|
if ((get_color_slot || get_colorbool_slot) && types) {
|
||||||
|
error("--get-color and variable type are incoherent");
|
||||||
|
usage_with_options(builtin_config_usage, builtin_config_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAS_MULTI_BITS(actions)) {
|
||||||
|
error("only one action at a time.");
|
||||||
|
usage_with_options(builtin_config_usage, builtin_config_options);
|
||||||
|
}
|
||||||
|
if (actions == 0)
|
||||||
|
switch (argc) {
|
||||||
|
case 1: actions = ACTION_GET; break;
|
||||||
|
case 2: actions = ACTION_SET; break;
|
||||||
|
case 3: actions = ACTION_SET_ALL; break;
|
||||||
|
default:
|
||||||
|
usage_with_options(builtin_config_usage, builtin_config_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actions == ACTION_LIST) {
|
||||||
|
check_argc(argc, 0, 0);
|
||||||
|
if (git_config(show_all_config, NULL) < 0) {
|
||||||
|
if (config_exclusive_filename)
|
||||||
|
die("unable to read config file %s: %s",
|
||||||
|
config_exclusive_filename, strerror(errno));
|
||||||
|
else
|
||||||
|
die("error processing config file(s)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (actions == ACTION_EDIT) {
|
||||||
|
check_argc(argc, 0, 0);
|
||||||
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,7 +334,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
|
||||||
die("--long is incompatible with --abbrev=0");
|
die("--long is incompatible with --abbrev=0");
|
||||||
|
|
||||||
if (contains) {
|
if (contains) {
|
||||||
const char **args = xmalloc((7 + argc) * sizeof(char*));
|
const char **args = xmalloc((7 + argc) * sizeof(char *));
|
||||||
int i = 0;
|
int i = 0;
|
||||||
args[i++] = "name-rev";
|
args[i++] = "name-rev";
|
||||||
args[i++] = "--name-only";
|
args[i++] = "--name-only";
|
||||||
|
@ -349,7 +349,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
|
||||||
args[i++] = s;
|
args[i++] = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memcpy(args + i, argv, argc * sizeof(char*));
|
memcpy(args + i, argv, argc * sizeof(char *));
|
||||||
args[i + argc] = NULL;
|
args[i + argc] = NULL;
|
||||||
return cmd_name_rev(i + argc, args, prefix);
|
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);
|
init_revisions(opt, prefix);
|
||||||
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
|
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
|
||||||
nr_sha1 = 0;
|
|
||||||
opt->abbrev = 0;
|
opt->abbrev = 0;
|
||||||
opt->diff = 1;
|
opt->diff = 1;
|
||||||
argc = setup_revisions(argc, argv, opt, NULL);
|
argc = setup_revisions(argc, argv, opt, NULL);
|
||||||
|
|
|
@ -221,7 +221,8 @@ static void handle_commit(struct commit *commit, struct rev_info *rev)
|
||||||
if (message)
|
if (message)
|
||||||
message += 2;
|
message += 2;
|
||||||
|
|
||||||
if (commit->parents) {
|
if (commit->parents &&
|
||||||
|
get_object_mark(&commit->parents->item->object) != 0) {
|
||||||
parse_commit(commit->parents->item);
|
parse_commit(commit->parents->item);
|
||||||
diff_tree_sha1(commit->parents->item->tree->object.sha1,
|
diff_tree_sha1(commit->parents->item->tree->object.sha1,
|
||||||
commit->tree->object.sha1, "", &rev->diffopt);
|
commit->tree->object.sha1, "", &rev->diffopt);
|
||||||
|
|
|
@ -112,7 +112,7 @@ static void mark_common(struct commit *commit,
|
||||||
Get the next rev to send, ignoring the common.
|
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;
|
struct commit *commit = NULL;
|
||||||
|
|
||||||
|
@ -217,9 +217,8 @@ static int find_common(int fd[2], unsigned char *result_sha1,
|
||||||
if (args.depth > 0) {
|
if (args.depth > 0) {
|
||||||
char line[1024];
|
char line[1024];
|
||||||
unsigned char sha1[20];
|
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 (!prefixcmp(line, "shallow ")) {
|
||||||
if (get_sha1_hex(line + 8, sha1))
|
if (get_sha1_hex(line + 8, sha1))
|
||||||
die("invalid shallow line: %s", line);
|
die("invalid shallow line: %s", line);
|
||||||
|
@ -484,7 +483,7 @@ static int sideband_demux(int fd, void *data)
|
||||||
{
|
{
|
||||||
int *xd = 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)
|
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
|
/* When cloning, it is not unusual to have
|
||||||
* no common commit.
|
* no common commit.
|
||||||
*/
|
*/
|
||||||
fprintf(stderr, "warning: no common commits\n");
|
warning("no common commits");
|
||||||
|
|
||||||
if (get_pack(fd, pack_lockfile))
|
if (get_pack(fd, pack_lockfile))
|
||||||
die("git fetch-pack: fetch failed.");
|
die("git fetch-pack: fetch failed.");
|
||||||
|
@ -812,15 +811,13 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
mtime.sec = st.st_mtime;
|
mtime.sec = st.st_mtime;
|
||||||
#ifdef USE_NSEC
|
mtime.nsec = ST_MTIME_NSEC(st);
|
||||||
mtime.usec = st.st_mtim.usec;
|
|
||||||
#endif
|
|
||||||
if (stat(shallow, &st)) {
|
if (stat(shallow, &st)) {
|
||||||
if (mtime.sec)
|
if (mtime.sec)
|
||||||
die("shallow file was removed during fetch");
|
die("shallow file was removed during fetch");
|
||||||
} else if (st.st_mtime != mtime.sec
|
} else if (st.st_mtime != mtime.sec
|
||||||
#ifdef USE_NSEC
|
#ifdef USE_NSEC
|
||||||
|| st.st_mtim.usec != mtime.usec
|
|| ST_MTIME_NSEC(st) != mtime.nsec
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
die("shallow file was changed during fetch");
|
die("shallow file was changed during fetch");
|
||||||
|
@ -828,7 +825,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args,
|
||||||
fd = hold_lock_file_for_update(&lock, shallow,
|
fd = hold_lock_file_for_update(&lock, shallow,
|
||||||
LOCK_DIE_ON_ERROR);
|
LOCK_DIE_ON_ERROR);
|
||||||
if (!write_shallow_commits(fd, 0)) {
|
if (!write_shallow_commits(fd, 0)) {
|
||||||
unlink(shallow);
|
unlink_or_warn(shallow);
|
||||||
rollback_lock_file(&lock);
|
rollback_lock_file(&lock);
|
||||||
} else {
|
} else {
|
||||||
commit_lock_file(&lock);
|
commit_lock_file(&lock);
|
||||||
|
|
|
@ -197,11 +197,7 @@ static int update_local_ref(struct ref *ref,
|
||||||
struct commit *current = NULL, *updated;
|
struct commit *current = NULL, *updated;
|
||||||
enum object_type type;
|
enum object_type type;
|
||||||
struct branch *current_branch = branch_get(NULL);
|
struct branch *current_branch = branch_get(NULL);
|
||||||
const char *pretty_ref = ref->name + (
|
const char *pretty_ref = prettify_refname(ref->name);
|
||||||
!prefixcmp(ref->name, "refs/heads/") ? 11 :
|
|
||||||
!prefixcmp(ref->name, "refs/tags/") ? 10 :
|
|
||||||
!prefixcmp(ref->name, "refs/remotes/") ? 13 :
|
|
||||||
0);
|
|
||||||
|
|
||||||
*display = 0;
|
*display = 0;
|
||||||
type = sha1_object_info(ref->new_sha1, NULL);
|
type = sha1_object_info(ref->new_sha1, NULL);
|
||||||
|
@ -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)
|
struct ref *ref_map)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
@ -302,11 +298,13 @@ static int store_updated_refs(const char *url, const char *remote_name,
|
||||||
char note[1024];
|
char note[1024];
|
||||||
const char *what, *kind;
|
const char *what, *kind;
|
||||||
struct ref *rm;
|
struct ref *rm;
|
||||||
char *filename = git_path("FETCH_HEAD");
|
char *url, *filename = git_path("FETCH_HEAD");
|
||||||
|
|
||||||
fp = fopen(filename, "a");
|
fp = fopen(filename, "a");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return error("cannot open %s: %s\n", filename, strerror(errno));
|
return error("cannot open %s: %s\n", filename, strerror(errno));
|
||||||
|
|
||||||
|
url = transport_anonymize_url(raw_url);
|
||||||
for (rm = ref_map; rm; rm = rm->next) {
|
for (rm = ref_map; rm; rm = rm->next) {
|
||||||
struct ref *ref = NULL;
|
struct ref *ref = NULL;
|
||||||
|
|
||||||
|
@ -357,12 +355,18 @@ static int store_updated_refs(const char *url, const char *remote_name,
|
||||||
kind);
|
kind);
|
||||||
note_len += sprintf(note + note_len, "'%s' of ", what);
|
note_len += sprintf(note + note_len, "'%s' of ", what);
|
||||||
}
|
}
|
||||||
note_len += sprintf(note + note_len, "%.*s", url_len, url);
|
note[note_len] = '\0';
|
||||||
fprintf(fp, "%s\t%s\t%s\n",
|
fprintf(fp, "%s\t%s\t%s",
|
||||||
sha1_to_hex(commit ? commit->object.sha1 :
|
sha1_to_hex(commit ? commit->object.sha1 :
|
||||||
rm->old_sha1),
|
rm->old_sha1),
|
||||||
rm->merge ? "" : "not-for-merge",
|
rm->merge ? "" : "not-for-merge",
|
||||||
note);
|
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)
|
if (ref)
|
||||||
rc |= update_local_ref(ref, what, note);
|
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);
|
fprintf(stderr, " %s\n", note);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(url);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
if (rc & 2)
|
if (rc & 2)
|
||||||
error("some local refs could not be updated; try running\n"
|
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)
|
for (; ref_map; ref_map = ref_map->next)
|
||||||
if (ref_map->peer_ref && !strcmp(current_branch->refname,
|
if (ref_map->peer_ref && !strcmp(current_branch->refname,
|
||||||
ref_map->peer_ref->name))
|
ref_map->peer_ref->name))
|
||||||
die("Refusing to fetch into current branch");
|
die("Refusing to fetch into current branch %s "
|
||||||
|
"of non-bare repository", current_branch->refname);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_fetch(struct transport *transport,
|
static int do_fetch(struct transport *transport,
|
||||||
|
|
|
@ -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 fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
|
||||||
int limit = 20, i = 0, pos = 0;
|
int limit = 20, i = 0, pos = 0;
|
||||||
char line[1024];
|
char *sep = "";
|
||||||
char *p = line, *sep = "";
|
|
||||||
unsigned char head_sha1[20];
|
unsigned char head_sha1[20];
|
||||||
const char *current_branch;
|
const char *current_branch;
|
||||||
|
|
||||||
|
@ -271,9 +270,8 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
|
||||||
/* get a line */
|
/* get a line */
|
||||||
while (pos < in->len) {
|
while (pos < in->len) {
|
||||||
int len;
|
int len;
|
||||||
char *newline;
|
char *newline, *p = in->buf + pos;
|
||||||
|
|
||||||
p = in->buf + pos;
|
|
||||||
newline = strchr(p, '\n');
|
newline = strchr(p, '\n');
|
||||||
len = newline ? newline - p : strlen(p);
|
len = newline ? newline - p : strlen(p);
|
||||||
pos += len + !!newline;
|
pos += len + !!newline;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "blob.h"
|
#include "blob.h"
|
||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
|
#include "remote.h"
|
||||||
|
|
||||||
/* Quoting styles */
|
/* Quoting styles */
|
||||||
#define QUOTE_NONE 0
|
#define QUOTE_NONE 0
|
||||||
|
@ -66,6 +67,7 @@ static struct {
|
||||||
{ "subject" },
|
{ "subject" },
|
||||||
{ "body" },
|
{ "body" },
|
||||||
{ "contents" },
|
{ "contents" },
|
||||||
|
{ "upstream" },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -337,8 +339,11 @@ static const char *copy_name(const char *buf)
|
||||||
static const char *copy_email(const char *buf)
|
static const char *copy_email(const char *buf)
|
||||||
{
|
{
|
||||||
const char *email = strchr(buf, '<');
|
const char *email = strchr(buf, '<');
|
||||||
const char *eoemail = strchr(email, '>');
|
const char *eoemail;
|
||||||
if (!email || !eoemail)
|
if (!email)
|
||||||
|
return "";
|
||||||
|
eoemail = strchr(email, '>');
|
||||||
|
if (!eoemail)
|
||||||
return "";
|
return "";
|
||||||
return xmemdupz(email, eoemail + 1 - email);
|
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.
|
* 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];
|
const char *name = used_atom[i];
|
||||||
struct atom_value *v = &ref->value[i];
|
struct atom_value *v = &ref->value[i];
|
||||||
int deref = 0;
|
int deref = 0;
|
||||||
|
const char *refname;
|
||||||
|
const char *formatp;
|
||||||
|
|
||||||
if (*name == '*') {
|
if (*name == '*') {
|
||||||
deref = 1;
|
deref = 1;
|
||||||
name++;
|
name++;
|
||||||
}
|
}
|
||||||
if (!prefixcmp(name, "refname")) {
|
|
||||||
const char *formatp = strchr(name, ':');
|
|
||||||
const char *refname = ref->refname;
|
|
||||||
|
|
||||||
/* look for "short" refname format */
|
if (!prefixcmp(name, "refname"))
|
||||||
if (formatp) {
|
refname = ref->refname;
|
||||||
formatp++;
|
else if(!prefixcmp(name, "upstream")) {
|
||||||
if (!strcmp(formatp, "short"))
|
struct branch *branch;
|
||||||
refname = get_short_ref(ref);
|
/* only local branches may have an upstream */
|
||||||
else
|
if (prefixcmp(ref->refname, "refs/heads/"))
|
||||||
die("unknown refname format %s",
|
continue;
|
||||||
formatp);
|
branch = branch_get(ref->refname + 11);
|
||||||
}
|
|
||||||
|
|
||||||
if (!deref)
|
if (!branch || !branch->merge || !branch->merge[0] ||
|
||||||
v->s = refname;
|
!branch->merge[0]->dst)
|
||||||
else {
|
continue;
|
||||||
int len = strlen(refname);
|
refname = branch->merge[0]->dst;
|
||||||
char *s = xmalloc(len + 4);
|
}
|
||||||
sprintf(s, "%s^{}", refname);
|
else
|
||||||
v->s = s;
|
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;
|
return -1;
|
||||||
|
|
||||||
*sort_tail = s = xcalloc(1, sizeof(*s));
|
*sort_tail = s = xcalloc(1, sizeof(*s));
|
||||||
sort_tail = &s->next;
|
|
||||||
|
|
||||||
if (*arg == '-') {
|
if (*arg == '-') {
|
||||||
s->reverse = 1;
|
s->reverse = 1;
|
||||||
|
@ -1002,6 +921,9 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
|
||||||
sort = default_sort();
|
sort = default_sort();
|
||||||
sort_atom_limit = used_atom_cnt;
|
sort_atom_limit = used_atom_cnt;
|
||||||
|
|
||||||
|
/* for warn_ambiguous_refs */
|
||||||
|
git_config(git_default_config, NULL);
|
||||||
|
|
||||||
memset(&cbdata, 0, sizeof(cbdata));
|
memset(&cbdata, 0, sizeof(cbdata));
|
||||||
cbdata.grab_pattern = argv;
|
cbdata.grab_pattern = argv;
|
||||||
for_each_ref(grab_single_ref, &cbdata);
|
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 pack_refs = 1;
|
||||||
static int aggressive_window = -1;
|
static int aggressive_window = 250;
|
||||||
static int gc_auto_threshold = 6700;
|
static int gc_auto_threshold = 6700;
|
||||||
static int gc_auto_pack_limit = 50;
|
static int gc_auto_pack_limit = 50;
|
||||||
static const char *prune_expire = "2.weeks.ago";
|
static const char *prune_expire = "2.weeks.ago";
|
||||||
|
@ -200,6 +200,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
if (aggressive) {
|
if (aggressive) {
|
||||||
append_option(argv_repack, "-f", MAX_ADD);
|
append_option(argv_repack, "-f", MAX_ADD);
|
||||||
|
append_option(argv_repack, "--depth=250", MAX_ADD);
|
||||||
if (aggressive_window > 0) {
|
if (aggressive_window > 0) {
|
||||||
sprintf(buf, "--window=%d", aggressive_window);
|
sprintf(buf, "--window=%d", aggressive_window);
|
||||||
append_option(argv_repack, buf, MAX_ADD);
|
append_option(argv_repack, buf, MAX_ADD);
|
||||||
|
|
465
builtin-grep.c
465
builtin-grep.c
|
@ -10,6 +10,7 @@
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include "tree-walk.h"
|
#include "tree-walk.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
#include "parse-options.h"
|
||||||
#include "grep.h"
|
#include "grep.h"
|
||||||
|
|
||||||
#ifndef NO_EXTERNAL_GREP
|
#ifndef NO_EXTERNAL_GREP
|
||||||
|
@ -20,7 +21,29 @@
|
||||||
#endif
|
#endif
|
||||||
#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;
|
* git grep pathspecs are somewhat different from diff-tree pathspecs;
|
||||||
|
@ -269,6 +292,21 @@ static int flush_grep(struct grep_opt *opt,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void grep_add_color(struct strbuf *sb, const char *escape_seq)
|
||||||
|
{
|
||||||
|
size_t orig_len = sb->len;
|
||||||
|
|
||||||
|
while (*escape_seq) {
|
||||||
|
if (*escape_seq == 'm')
|
||||||
|
strbuf_addch(sb, ';');
|
||||||
|
else if (*escape_seq != '\033' && *escape_seq != '[')
|
||||||
|
strbuf_addch(sb, *escape_seq);
|
||||||
|
escape_seq++;
|
||||||
|
}
|
||||||
|
if (sb->len > orig_len && sb->buf[sb->len - 1] == ';')
|
||||||
|
strbuf_setlen(sb, sb->len - 1);
|
||||||
|
}
|
||||||
|
|
||||||
static int external_grep(struct grep_opt *opt, const char **paths, int cached)
|
static int external_grep(struct grep_opt *opt, const char **paths, int cached)
|
||||||
{
|
{
|
||||||
int i, nr, argc, hit, len, status;
|
int i, nr, argc, hit, len, status;
|
||||||
|
@ -339,6 +377,23 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
|
||||||
push_arg("-e");
|
push_arg("-e");
|
||||||
push_arg(p->pattern);
|
push_arg(p->pattern);
|
||||||
}
|
}
|
||||||
|
if (opt->color) {
|
||||||
|
struct strbuf sb = STRBUF_INIT;
|
||||||
|
|
||||||
|
grep_add_color(&sb, opt->color_match);
|
||||||
|
setenv("GREP_COLOR", sb.buf, 1);
|
||||||
|
|
||||||
|
strbuf_reset(&sb);
|
||||||
|
strbuf_addstr(&sb, "mt=");
|
||||||
|
grep_add_color(&sb, opt->color_match);
|
||||||
|
strbuf_addstr(&sb, ":sl=:cx=:fn=:ln=:bn=:se=");
|
||||||
|
setenv("GREP_COLORS", sb.buf, 1);
|
||||||
|
|
||||||
|
strbuf_release(&sb);
|
||||||
|
|
||||||
|
if (opt->color_external && strlen(opt->color_external) > 0)
|
||||||
|
push_arg(opt->color_external);
|
||||||
|
}
|
||||||
|
|
||||||
hit = 0;
|
hit = 0;
|
||||||
argc = nr;
|
argc = nr;
|
||||||
|
@ -381,7 +436,8 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
|
||||||
}
|
}
|
||||||
#endif
|
#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 hit = 0;
|
||||||
int nr;
|
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
|
* we grep through the checked-out files. It tends to
|
||||||
* be a lot more optimized
|
* be a lot more optimized
|
||||||
*/
|
*/
|
||||||
if (!cached && !builtin_grep) {
|
if (!cached && external_grep_allowed) {
|
||||||
hit = external_grep(opt, paths, cached);
|
hit = external_grep(opt, paths, cached);
|
||||||
if (hit >= 0)
|
if (hit >= 0)
|
||||||
return hit;
|
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));
|
die("unable to grep from object of type %s", typename(obj->type));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char builtin_grep_usage[] =
|
static int context_callback(const struct option *opt, const char *arg,
|
||||||
"git grep <option>* [-e] <pattern> <rev>* [[--] <path>...]";
|
int unset)
|
||||||
|
{
|
||||||
|
struct grep_opt *grep_opt = opt->value;
|
||||||
|
int value;
|
||||||
|
const char *endp;
|
||||||
|
|
||||||
static const char emsg_invalid_context_len[] =
|
if (unset) {
|
||||||
"%s: invalid context length argument";
|
grep_opt->pre_context = grep_opt->post_context = 0;
|
||||||
static const char emsg_missing_context_len[] =
|
return 0;
|
||||||
"missing context length argument";
|
}
|
||||||
static const char emsg_missing_argument[] =
|
value = strtol(arg, (char **)&endp, 10);
|
||||||
"option requires an argument -%s";
|
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 cmd_grep(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int hit = 0;
|
int hit = 0;
|
||||||
int cached = 0;
|
int cached = 0;
|
||||||
|
int external_grep_allowed = 1;
|
||||||
int seen_dashdash = 0;
|
int seen_dashdash = 0;
|
||||||
struct grep_opt opt;
|
struct grep_opt opt;
|
||||||
struct object_array list = { 0, 0, NULL };
|
struct object_array list = { 0, 0, NULL };
|
||||||
const char **paths = NULL;
|
const char **paths = NULL;
|
||||||
int i;
|
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));
|
memset(&opt, 0, sizeof(opt));
|
||||||
opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
|
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.pattern_tail = &opt.pattern_list;
|
||||||
opt.regflags = REG_NEWLINE;
|
opt.regflags = REG_NEWLINE;
|
||||||
|
|
||||||
|
strcpy(opt.color_match, GIT_COLOR_RED GIT_COLOR_BOLD);
|
||||||
|
opt.color = -1;
|
||||||
|
git_config(grep_config, &opt);
|
||||||
|
if (opt.color == -1)
|
||||||
|
opt.color = git_use_color_default;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there is no -- then the paths must exist in the working
|
* If there is no -- then the paths must exist in the working
|
||||||
* tree. If there is no explicit pattern specified with -e or
|
* tree. If there is no explicit pattern specified with -e or
|
||||||
|
@ -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
|
* unrecognized non option is the beginning of the refs list
|
||||||
* that continues up to the -- (if exists), and then paths.
|
* 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) {
|
/* First unrecognized non-option token */
|
||||||
const char *arg = argv[1];
|
if (argc > 0 && !opt.pattern_list) {
|
||||||
argc--; argv++;
|
append_grep_pattern(&opt, argv[0], "command line", 0,
|
||||||
if (!strcmp("--cached", arg)) {
|
GREP_PATTERN);
|
||||||
cached = 1;
|
argv++;
|
||||||
continue;
|
argc--;
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt.color && !opt.color_external)
|
||||||
|
external_grep_allowed = 0;
|
||||||
if (!opt.pattern_list)
|
if (!opt.pattern_list)
|
||||||
die("no pattern given.");
|
die("no pattern given.");
|
||||||
if ((opt.regflags != REG_NEWLINE) && opt.fixed)
|
if ((opt.regflags != REG_NEWLINE) && opt.fixed)
|
||||||
|
@ -764,7 +787,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
||||||
compile_grep_patterns(&opt);
|
compile_grep_patterns(&opt);
|
||||||
|
|
||||||
/* Check revs and then paths */
|
/* Check revs and then paths */
|
||||||
for (i = 1; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
const char *arg = argv[i];
|
const char *arg = argv[i];
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
/* Is it a rev? */
|
/* Is it a rev? */
|
||||||
|
@ -807,7 +830,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
||||||
if (!list.nr) {
|
if (!list.nr) {
|
||||||
if (!cached)
|
if (!cached)
|
||||||
setup_work_tree();
|
setup_work_tree();
|
||||||
return !grep_cache(&opt, paths, cached);
|
return !grep_cache(&opt, paths, cached, external_grep_allowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cached)
|
if (cached)
|
||||||
|
|
|
@ -114,7 +114,7 @@ static int check_emacsclient_version(void)
|
||||||
return 0;
|
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()) {
|
if (!check_emacsclient_version()) {
|
||||||
/* This works only with emacsclient version >= 22. */
|
/* 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");
|
const char *display = getenv("DISPLAY");
|
||||||
if (display && *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)
|
if (!path)
|
||||||
path = "man";
|
path = "man";
|
||||||
|
@ -236,7 +236,7 @@ static int add_man_viewer_info(const char *var, const char *value)
|
||||||
const char *subkey = strrchr(name, '.');
|
const char *subkey = strrchr(name, '.');
|
||||||
|
|
||||||
if (!subkey)
|
if (!subkey)
|
||||||
return error("Config with no key for man viewer: %s", name);
|
return 0;
|
||||||
|
|
||||||
if (!strcmp(subkey, ".path")) {
|
if (!strcmp(subkey, ".path")) {
|
||||||
if (!value)
|
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);
|
return add_man_viewer_cmd(name, subkey - name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
warning("'%s': unsupported man viewer sub key.", subkey);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,8 +132,7 @@ static void copy_templates(const char *template_dir)
|
||||||
}
|
}
|
||||||
dir = opendir(template_path);
|
dir = opendir(template_path);
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
fprintf(stderr, "warning: templates not found %s\n",
|
warning("templates not found %s", template_dir);
|
||||||
template_dir);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,8 +145,8 @@ static void copy_templates(const char *template_dir)
|
||||||
|
|
||||||
if (repository_format_version &&
|
if (repository_format_version &&
|
||||||
repository_format_version != GIT_REPO_VERSION) {
|
repository_format_version != GIT_REPO_VERSION) {
|
||||||
fprintf(stderr, "warning: not copying templates of "
|
warning("not copying templates of "
|
||||||
"a wrong format version %d from '%s'\n",
|
"a wrong format version %d from '%s'",
|
||||||
repository_format_version,
|
repository_format_version,
|
||||||
template_dir);
|
template_dir);
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
|
255
builtin-log.c
255
builtin-log.c
|
@ -17,6 +17,7 @@
|
||||||
#include "run-command.h"
|
#include "run-command.h"
|
||||||
#include "shortlog.h"
|
#include "shortlog.h"
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
|
#include "string-list.h"
|
||||||
|
|
||||||
/* Set a default date-time format for git log ("log.date" config variable) */
|
/* Set a default date-time format for git log ("log.date" config variable) */
|
||||||
static const char *default_date_mode = NULL;
|
static const char *default_date_mode = NULL;
|
||||||
|
@ -416,18 +417,13 @@ int cmd_log(int argc, const char **argv, const char *prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* format-patch */
|
/* 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 const char *fmt_patch_suffix = ".patch";
|
||||||
static int numbered = 0;
|
static int numbered = 0;
|
||||||
static int auto_number = 1;
|
static int auto_number = 1;
|
||||||
|
|
||||||
|
static char *default_attach = NULL;
|
||||||
|
|
||||||
static char **extra_hdr;
|
static char **extra_hdr;
|
||||||
static int extra_hdr_nr;
|
static int extra_hdr_nr;
|
||||||
static int extra_hdr_alloc;
|
static int extra_hdr_alloc;
|
||||||
|
@ -459,6 +455,11 @@ static void add_header(const char *value)
|
||||||
extra_hdr[extra_hdr_nr++] = xstrndup(value, len);
|
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)
|
static int git_format_config(const char *var, const char *value, void *cb)
|
||||||
{
|
{
|
||||||
if (!strcmp(var, "format.headers")) {
|
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;
|
auto_number = auto_number && numbered;
|
||||||
return 0;
|
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);
|
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 FILE *realstdout = NULL;
|
||||||
static const char *output_directory = NULL;
|
static const char *output_directory = NULL;
|
||||||
static int outdir_offset;
|
static int outdir_offset;
|
||||||
|
|
||||||
static int reopen_stdout(const char *oneline, int nr, int total)
|
static int reopen_stdout(struct commit *commit, struct rev_info *rev)
|
||||||
{
|
{
|
||||||
char filename[PATH_MAX];
|
struct strbuf filename = STRBUF_INIT;
|
||||||
int len = 0;
|
|
||||||
int suffix_len = strlen(fmt_patch_suffix) + 1;
|
int suffix_len = strlen(fmt_patch_suffix) + 1;
|
||||||
|
|
||||||
if (output_directory) {
|
if (output_directory) {
|
||||||
len = snprintf(filename, sizeof(filename), "%s",
|
strbuf_addstr(&filename, output_directory);
|
||||||
output_directory);
|
if (filename.len >=
|
||||||
if (len >=
|
PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len)
|
||||||
sizeof(filename) - FORMAT_PATCH_NAME_MAX - suffix_len)
|
|
||||||
return error("name of output directory is too long");
|
return error("name of output directory is too long");
|
||||||
if (filename[len - 1] != '/')
|
if (filename.buf[filename.len - 1] != '/')
|
||||||
filename[len++] = '/';
|
strbuf_addch(&filename, '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!oneline)
|
get_patch_filename(commit, rev->nr, fmt_patch_suffix, &filename);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(realstdout, "%s\n", filename + outdir_offset);
|
if (!DIFF_OPT_TST(&rev->diffopt, QUIET))
|
||||||
if (freopen(filename, "w", stdout) == NULL)
|
fprintf(realstdout, "%s\n", filename.buf + outdir_offset);
|
||||||
return error("Cannot open patch file %s",filename);
|
|
||||||
|
|
||||||
|
if (freopen(filename.buf, "w", stdout) == NULL)
|
||||||
|
return error("Cannot open patch file %s", filename.buf);
|
||||||
|
|
||||||
|
strbuf_release(&filename);
|
||||||
return 0;
|
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)
|
int nr, struct commit **list, struct commit *head)
|
||||||
{
|
{
|
||||||
const char *committer;
|
const char *committer;
|
||||||
char *head_sha1;
|
|
||||||
const char *subject_start = NULL;
|
const char *subject_start = NULL;
|
||||||
const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n";
|
const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n";
|
||||||
const char *msg;
|
const char *msg;
|
||||||
|
@ -656,21 +622,41 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
|
||||||
const char *encoding = "utf-8";
|
const char *encoding = "utf-8";
|
||||||
struct diff_options opts;
|
struct diff_options opts;
|
||||||
int need_8bit_cte = 0;
|
int need_8bit_cte = 0;
|
||||||
|
struct commit *commit = NULL;
|
||||||
|
|
||||||
if (rev->commit_format != CMIT_FMT_EMAIL)
|
if (rev->commit_format != CMIT_FMT_EMAIL)
|
||||||
die("Cover letter needs email format");
|
die("Cover letter needs email format");
|
||||||
|
|
||||||
if (!use_stdout && reopen_stdout(numbered_files ?
|
committer = git_committer_info(0);
|
||||||
NULL : "cover-letter", 0, rev->total))
|
|
||||||
|
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;
|
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);
|
&need_8bit_cte);
|
||||||
|
|
||||||
committer = git_committer_info(0);
|
|
||||||
|
|
||||||
msg = body;
|
msg = body;
|
||||||
pp_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822,
|
pp_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822,
|
||||||
encoding);
|
encoding);
|
||||||
|
@ -766,10 +752,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
||||||
int numbered_files = 0; /* _just_ numbers */
|
int numbered_files = 0; /* _just_ numbers */
|
||||||
int subject_prefix = 0;
|
int subject_prefix = 0;
|
||||||
int ignore_if_in_upstream = 0;
|
int ignore_if_in_upstream = 0;
|
||||||
int thread = 0;
|
|
||||||
int cover_letter = 0;
|
int cover_letter = 0;
|
||||||
int boundary_count = 0;
|
int boundary_count = 0;
|
||||||
int no_binary_diff = 0;
|
int no_binary_diff = 0;
|
||||||
|
int numbered_cmdline_opt = 0;
|
||||||
struct commit *origin = NULL, *head = NULL;
|
struct commit *origin = NULL, *head = NULL;
|
||||||
const char *in_reply_to = NULL;
|
const char *in_reply_to = NULL;
|
||||||
struct patch_ids ids;
|
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;
|
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
|
* Parse the arguments before setup_revisions(), or something
|
||||||
* like "git format-patch -o a123 HEAD^.." may fail; a123 is
|
* 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"))
|
if (!strcmp(argv[i], "--stdout"))
|
||||||
use_stdout = 1;
|
use_stdout = 1;
|
||||||
else if (!strcmp(argv[i], "-n") ||
|
else if (!strcmp(argv[i], "-n") ||
|
||||||
!strcmp(argv[i], "--numbered"))
|
!strcmp(argv[i], "--numbered")) {
|
||||||
numbered = 1;
|
numbered = 1;
|
||||||
|
numbered_cmdline_opt = 1;
|
||||||
|
}
|
||||||
else if (!strcmp(argv[i], "-N") ||
|
else if (!strcmp(argv[i], "-N") ||
|
||||||
!strcmp(argv[i], "--no-numbered")) {
|
!strcmp(argv[i], "--no-numbered")) {
|
||||||
numbered = 0;
|
numbered = 0;
|
||||||
|
@ -833,13 +826,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
||||||
}
|
}
|
||||||
else if (!strcmp(argv[i], "--signoff") ||
|
else if (!strcmp(argv[i], "--signoff") ||
|
||||||
!strcmp(argv[i], "-s")) {
|
!strcmp(argv[i], "-s")) {
|
||||||
const char *committer;
|
do_signoff = 1;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
else if (!strcmp(argv[i], "--attach")) {
|
else if (!strcmp(argv[i], "--attach")) {
|
||||||
rev.mime_boundary = git_version_string;
|
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.mime_boundary = argv[i] + 9;
|
||||||
rev.no_inline = 1;
|
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")) {
|
else if (!strcmp(argv[i], "--inline")) {
|
||||||
rev.mime_boundary = git_version_string;
|
rev.mime_boundary = git_version_string;
|
||||||
rev.no_inline = 0;
|
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"))
|
else if (!strcmp(argv[i], "--ignore-if-in-upstream"))
|
||||||
ignore_if_in_upstream = 1;
|
ignore_if_in_upstream = 1;
|
||||||
else if (!strcmp(argv[i], "--thread"))
|
else if (!strcmp(argv[i], "--thread")
|
||||||
thread = 1;
|
|| !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="))
|
else if (!prefixcmp(argv[i], "--in-reply-to="))
|
||||||
in_reply_to = argv[i] + 14;
|
in_reply_to = argv[i] + 14;
|
||||||
else if (!strcmp(argv[i], "--in-reply-to")) {
|
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;
|
cover_letter = 1;
|
||||||
else if (!strcmp(argv[i], "--no-binary"))
|
else if (!strcmp(argv[i], "--no-binary"))
|
||||||
no_binary_diff = 1;
|
no_binary_diff = 1;
|
||||||
|
else if (!prefixcmp(argv[i], "--add-header="))
|
||||||
|
add_header(argv[i] + 13);
|
||||||
else
|
else
|
||||||
argv[j++] = argv[i];
|
argv[j++] = argv[i];
|
||||||
}
|
}
|
||||||
argc = j;
|
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++) {
|
for (i = 0; i < extra_hdr_nr; i++) {
|
||||||
strbuf_addstr(&buf, extra_hdr[i]);
|
strbuf_addstr(&buf, extra_hdr[i]);
|
||||||
strbuf_addch(&buf, '\n');
|
strbuf_addch(&buf, '\n');
|
||||||
|
@ -913,6 +921,15 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
||||||
|
|
||||||
if (start_number < 0)
|
if (start_number < 0)
|
||||||
start_number = 1;
|
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)
|
if (numbered && keep_subject)
|
||||||
die ("-n and -k are mutually exclusive.");
|
die ("-n and -k are mutually exclusive.");
|
||||||
if (keep_subject && subject_prefix)
|
if (keep_subject && subject_prefix)
|
||||||
|
@ -1009,8 +1026,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
||||||
numbered = 1;
|
numbered = 1;
|
||||||
if (numbered)
|
if (numbered)
|
||||||
rev.total = total + start_number - 1;
|
rev.total = total + start_number - 1;
|
||||||
if (in_reply_to)
|
if (in_reply_to || thread || cover_letter)
|
||||||
rev.ref_message_id = clean_message_id(in_reply_to);
|
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 (cover_letter) {
|
||||||
if (thread)
|
if (thread)
|
||||||
gen_message_id(&rev, "cover");
|
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? */
|
/* Have we already had a message ID? */
|
||||||
if (rev.message_id) {
|
if (rev.message_id) {
|
||||||
/*
|
/*
|
||||||
* If we've got the ID to be a reply
|
* For deep threading: make every mail
|
||||||
* to, discard the current ID;
|
* a reply to the previous one, no
|
||||||
* otherwise, make everything a reply
|
* matter what other options are set.
|
||||||
* to that.
|
*
|
||||||
|
* 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);
|
free(rev.message_id);
|
||||||
else
|
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));
|
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),
|
if (!use_stdout && reopen_stdout(numbered_files ? NULL : commit,
|
||||||
rev.nr, rev.total))
|
&rev))
|
||||||
die("Failed to create output files");
|
die("Failed to create output files");
|
||||||
shown = log_tree_commit(&rev, commit);
|
shown = log_tree_commit(&rev, commit);
|
||||||
free(commit->buffer);
|
free(commit->buffer);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
|
#include "parse-options.h"
|
||||||
|
|
||||||
static int abbrev;
|
static int abbrev;
|
||||||
static int show_deleted;
|
static int show_deleted;
|
||||||
|
@ -28,6 +29,7 @@ static const char **pathspec;
|
||||||
static int error_unmatch;
|
static int error_unmatch;
|
||||||
static char *ps_matched;
|
static char *ps_matched;
|
||||||
static const char *with_tree;
|
static const char *with_tree;
|
||||||
|
static int exc_given;
|
||||||
|
|
||||||
static const char *tag_cached = "";
|
static const char *tag_cached = "";
|
||||||
static const char *tag_unmerged = "";
|
static const char *tag_unmerged = "";
|
||||||
|
@ -174,7 +176,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
|
||||||
for (i = 0; i < active_nr; i++) {
|
for (i = 0; i < active_nr; i++) {
|
||||||
struct cache_entry *ce = active_cache[i];
|
struct cache_entry *ce = active_cache[i];
|
||||||
int dtype = ce_to_dtype(ce);
|
int dtype = ce_to_dtype(ce);
|
||||||
if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
|
if (excluded(dir, ce->name, &dtype) !=
|
||||||
|
!!(dir->flags & DIR_SHOW_IGNORED))
|
||||||
continue;
|
continue;
|
||||||
if (show_unmerged && !ce_stage(ce))
|
if (show_unmerged && !ce_stage(ce))
|
||||||
continue;
|
continue;
|
||||||
|
@ -189,7 +192,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int err;
|
int err;
|
||||||
int dtype = ce_to_dtype(ce);
|
int dtype = ce_to_dtype(ce);
|
||||||
if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
|
if (excluded(dir, ce->name, &dtype) !=
|
||||||
|
!!(dir->flags & DIR_SHOW_IGNORED))
|
||||||
continue;
|
continue;
|
||||||
if (ce->ce_flags & CE_UPDATE)
|
if (ce->ce_flags & CE_UPDATE)
|
||||||
continue;
|
continue;
|
||||||
|
@ -374,159 +378,141 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char ls_files_usage[] =
|
static const char * const ls_files_usage[] = {
|
||||||
"git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
|
"git ls-files [options] [<file>]*",
|
||||||
"[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] "
|
NULL
|
||||||
"[ --exclude-per-directory=<filename> ] [--exclude-standard] "
|
};
|
||||||
"[--full-name] [--abbrev] [--] [<file>]*";
|
|
||||||
|
static int option_parse_z(const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
|
{
|
||||||
|
line_terminator = unset ? '\n' : '\0';
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int option_parse_exclude(const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
|
{
|
||||||
|
struct exclude_list *list = opt->value;
|
||||||
|
|
||||||
|
exc_given = 1;
|
||||||
|
add_exclude(arg, "", 0, list);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int option_parse_exclude_from(const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
|
{
|
||||||
|
struct dir_struct *dir = opt->value;
|
||||||
|
|
||||||
|
exc_given = 1;
|
||||||
|
add_excludes_from_file(dir, arg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int option_parse_exclude_standard(const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
|
{
|
||||||
|
struct dir_struct *dir = opt->value;
|
||||||
|
|
||||||
|
exc_given = 1;
|
||||||
|
setup_standard_excludes(dir);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int i;
|
int require_work_tree = 0, show_tag = 0;
|
||||||
int exc_given = 0, require_work_tree = 0;
|
|
||||||
struct dir_struct dir;
|
struct dir_struct dir;
|
||||||
|
struct option builtin_ls_files_options[] = {
|
||||||
|
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
|
||||||
|
"paths are separated with NUL character",
|
||||||
|
PARSE_OPT_NOARG, option_parse_z },
|
||||||
|
OPT_BOOLEAN('t', NULL, &show_tag,
|
||||||
|
"identify the file status with tags"),
|
||||||
|
OPT_BOOLEAN('v', NULL, &show_valid_bit,
|
||||||
|
"use lowercase letters for 'assume unchanged' files"),
|
||||||
|
OPT_BOOLEAN('c', "cached", &show_cached,
|
||||||
|
"show cached files in the output (default)"),
|
||||||
|
OPT_BOOLEAN('d', "deleted", &show_deleted,
|
||||||
|
"show deleted files in the output"),
|
||||||
|
OPT_BOOLEAN('m', "modified", &show_modified,
|
||||||
|
"show modified files in the output"),
|
||||||
|
OPT_BOOLEAN('o', "others", &show_others,
|
||||||
|
"show other files in the output"),
|
||||||
|
OPT_BIT('i', "ignored", &dir.flags,
|
||||||
|
"show ignored files in the output",
|
||||||
|
DIR_SHOW_IGNORED),
|
||||||
|
OPT_BOOLEAN('s', "stage", &show_stage,
|
||||||
|
"show staged contents' object name in the output"),
|
||||||
|
OPT_BOOLEAN('k', "killed", &show_killed,
|
||||||
|
"show files on the filesystem that need to be removed"),
|
||||||
|
OPT_BIT(0, "directory", &dir.flags,
|
||||||
|
"show 'other' directories' name only",
|
||||||
|
DIR_SHOW_OTHER_DIRECTORIES),
|
||||||
|
OPT_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));
|
memset(&dir, 0, sizeof(dir));
|
||||||
if (prefix)
|
if (prefix)
|
||||||
prefix_offset = strlen(prefix);
|
prefix_offset = strlen(prefix);
|
||||||
git_config(git_default_config, NULL);
|
git_config(git_default_config, NULL);
|
||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
argc = parse_options(argc, argv, builtin_ls_files_options,
|
||||||
const char *arg = argv[i];
|
ls_files_usage, 0);
|
||||||
|
if (show_tag || show_valid_bit) {
|
||||||
if (!strcmp(arg, "--")) {
|
tag_cached = "H ";
|
||||||
i++;
|
tag_unmerged = "M ";
|
||||||
break;
|
tag_removed = "R ";
|
||||||
}
|
tag_modified = "C ";
|
||||||
if (!strcmp(arg, "-z")) {
|
tag_other = "? ";
|
||||||
line_terminator = 0;
|
tag_killed = "K ";
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!strcmp(arg, "-t") || !strcmp(arg, "-v")) {
|
|
||||||
tag_cached = "H ";
|
|
||||||
tag_unmerged = "M ";
|
|
||||||
tag_removed = "R ";
|
|
||||||
tag_modified = "C ";
|
|
||||||
tag_other = "? ";
|
|
||||||
tag_killed = "K ";
|
|
||||||
if (arg[1] == 'v')
|
|
||||||
show_valid_bit = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) {
|
|
||||||
show_cached = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
|
|
||||||
show_deleted = 1;
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
|
||||||
|
require_work_tree = 1;
|
||||||
|
if (show_unmerged)
|
||||||
|
/*
|
||||||
|
* There's no point in showing unmerged unless
|
||||||
|
* you also show the stage information.
|
||||||
|
*/
|
||||||
|
show_stage = 1;
|
||||||
|
if (dir.exclude_per_dir)
|
||||||
|
exc_given = 1;
|
||||||
|
|
||||||
if (require_work_tree && !is_inside_work_tree())
|
if (require_work_tree && !is_inside_work_tree())
|
||||||
setup_work_tree();
|
setup_work_tree();
|
||||||
|
|
||||||
pathspec = get_pathspec(prefix, argv + i);
|
pathspec = get_pathspec(prefix, argv);
|
||||||
|
|
||||||
/* be nice with submodule patsh ending in a slash */
|
/* be nice with submodule paths ending in a slash */
|
||||||
read_cache();
|
read_cache();
|
||||||
if (pathspec)
|
if (pathspec)
|
||||||
strip_trailing_slash_from_submodules();
|
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);
|
ps_matched = xcalloc(1, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir.show_ignored && !exc_given) {
|
if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) {
|
||||||
fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
|
fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
|
||||||
argv[0]);
|
argv[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
|
@ -60,7 +60,6 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
const char *type = blob_type;
|
const char *type = blob_type;
|
||||||
unsigned long size;
|
|
||||||
|
|
||||||
if (S_ISGITLINK(mode)) {
|
if (S_ISGITLINK(mode)) {
|
||||||
/*
|
/*
|
||||||
|
@ -90,17 +89,20 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
|
||||||
|
|
||||||
if (!(ls_options & LS_NAME_ONLY)) {
|
if (!(ls_options & LS_NAME_ONLY)) {
|
||||||
if (ls_options & LS_SHOW_SIZE) {
|
if (ls_options & LS_SHOW_SIZE) {
|
||||||
|
char size_text[24];
|
||||||
if (!strcmp(type, blob_type)) {
|
if (!strcmp(type, blob_type)) {
|
||||||
sha1_object_info(sha1, &size);
|
unsigned long size;
|
||||||
printf("%06o %s %s %7lu\t", mode, type,
|
if (sha1_object_info(sha1, &size) == OBJ_BAD)
|
||||||
abbrev ? find_unique_abbrev(sha1, abbrev)
|
strcpy(size_text, "BAD");
|
||||||
: sha1_to_hex(sha1),
|
else
|
||||||
size);
|
snprintf(size_text, sizeof(size_text),
|
||||||
|
"%lu", size);
|
||||||
} else
|
} else
|
||||||
printf("%06o %s %s %7c\t", mode, type,
|
strcpy(size_text, "-");
|
||||||
abbrev ? find_unique_abbrev(sha1, abbrev)
|
printf("%06o %s %s %7s\t", mode, type,
|
||||||
: sha1_to_hex(sha1),
|
abbrev ? find_unique_abbrev(sha1, abbrev)
|
||||||
'-');
|
: sha1_to_hex(sha1),
|
||||||
|
size_text);
|
||||||
} else
|
} else
|
||||||
printf("%06o %s %s\t", mode, type,
|
printf("%06o %s %s\t", mode, type,
|
||||||
abbrev ? find_unique_abbrev(sha1, abbrev)
|
abbrev ? find_unique_abbrev(sha1, abbrev)
|
||||||
|
|
|
@ -537,7 +537,6 @@ static int decode_header_bq(struct strbuf *it)
|
||||||
*/
|
*/
|
||||||
strbuf_add(&outbuf, in, ep - in);
|
strbuf_add(&outbuf, in, ep - in);
|
||||||
}
|
}
|
||||||
in = ep;
|
|
||||||
}
|
}
|
||||||
/* E.g.
|
/* E.g.
|
||||||
* ep : "=?iso-2022-jp?B?GyR...?= foo"
|
* 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;
|
bases[bases_count++] = sha;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
warning("Cannot handle more than %zu bases. "
|
warning("Cannot handle more than %d bases. "
|
||||||
"Ignoring %s.", ARRAY_SIZE(bases)-1, argv[i]);
|
"Ignoring %s.",
|
||||||
|
(int)ARRAY_SIZE(bases)-1, argv[i]);
|
||||||
}
|
}
|
||||||
if (argc - i != 3) /* "--" "<head>" "<remote>" */
|
if (argc - i != 3) /* "--" "<head>" "<remote>" */
|
||||||
die("Not handling anything other than two heads merge.");
|
die("Not handling anything other than two heads merge.");
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче