From e0c2b742e0fece8aeee415331f0b988dd7765abd Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Wed, 3 Mar 2021 15:16:03 +0900 Subject: [PATCH] Imported Upstream version 2.12.0 --- .gitignore | 1 - .mailmap | 3 + Documentation/Makefile | 22 +- Documentation/RelNotes/2.10.3.txt | 7 - Documentation/RelNotes/2.10.4.txt | 4 - Documentation/RelNotes/2.10.5.txt | 17 - Documentation/RelNotes/2.11.2.txt | 12 - Documentation/RelNotes/2.11.3.txt | 4 - Documentation/RelNotes/2.11.4.txt | 17 - Documentation/RelNotes/2.12.0.txt | 500 + Documentation/RelNotes/2.4.12.txt | 12 - Documentation/RelNotes/2.5.6.txt | 12 - Documentation/RelNotes/2.6.7.txt | 12 - Documentation/RelNotes/2.7.5.txt | 14 - Documentation/RelNotes/2.7.6.txt | 25 - Documentation/RelNotes/2.8.5.txt | 12 - Documentation/RelNotes/2.8.6.txt | 4 - Documentation/RelNotes/2.9.4.txt | 7 - Documentation/RelNotes/2.9.5.txt | 4 - Documentation/SubmittingPatches | 13 +- Documentation/asciidoctor-extensions.rb | 28 + Documentation/blame-options.txt | 4 +- Documentation/cat-texi.perl | 21 +- Documentation/config.txt | 107 +- Documentation/diff-config.txt | 19 +- Documentation/diff-heuristic-options.txt | 2 - Documentation/diff-options.txt | 36 +- Documentation/git-branch.txt | 7 + Documentation/git-check-ref-format.txt | 6 +- Documentation/git-difftool.txt | 5 +- Documentation/git-for-each-ref.txt | 5 + Documentation/git-gc.txt | 2 +- Documentation/git-grep.txt | 14 + Documentation/git-gui.txt | 2 +- Documentation/git-init.txt | 4 +- Documentation/git-merge.txt | 8 + Documentation/git-p4.txt | 15 + Documentation/git-push.txt | 13 +- Documentation/git-rebase.txt | 7 +- Documentation/git-relink.txt | 30 - Documentation/git-reset.txt | 48 + Documentation/git-rev-parse.txt | 3 +- Documentation/git-shell.txt | 16 - Documentation/git-shortlog.txt | 4 + Documentation/git-stash.txt | 5 +- Documentation/git-submodule.txt | 81 +- Documentation/git-tag.txt | 16 +- Documentation/git-verify-tag.txt | 2 +- Documentation/git-worktree.txt | 2 +- Documentation/git.txt | 68 +- Documentation/gitcore-tutorial.txt | 2 +- Documentation/gitcvs-migration.txt | 2 +- Documentation/gitdiffcore.txt | 2 +- Documentation/giteveryday.txt | 17 +- Documentation/gitglossary.txt | 2 +- Documentation/gitk.txt | 14 +- Documentation/gitremote-helpers.txt | 10 +- Documentation/gitrepository-layout.txt | 2 +- Documentation/gittutorial-2.txt | 2 +- Documentation/gittutorial.txt | 2 +- Documentation/gitworkflows.txt | 2 +- Documentation/pretty-formats.txt | 2 + Documentation/rev-list-options.txt | 4 +- Documentation/technical/api-hashmap.txt | 4 +- Documentation/technical/api-setup.txt | 2 - Documentation/technical/api-submodule-config.txt | 14 +- Documentation/texi.xsl | 26 + Documentation/user-manual.txt | 8 + GIT-VERSION-GEN | 4 +- Makefile | 33 +- RelNotes | 2 +- abspath.c | 238 +- apply.c | 25 +- bisect.c | 2 +- branch.c | 2 +- builtin.h | 1 + builtin/add.c | 2 +- builtin/am.c | 6 +- builtin/blame.c | 9 +- builtin/branch.c | 23 +- builtin/checkout-index.c | 2 +- builtin/checkout.c | 19 +- builtin/clean.c | 10 +- builtin/clone.c | 8 +- builtin/commit.c | 41 +- builtin/diff-tree.c | 4 +- builtin/diff.c | 9 +- builtin/difftool.c | 692 ++ builtin/fetch.c | 4 +- builtin/for-each-ref.c | 5 +- builtin/fsck.c | 164 +- builtin/grep.c | 386 +- builtin/init-db.c | 8 +- builtin/ls-files.c | 21 +- builtin/ls-tree.c | 16 +- builtin/merge-index.c | 2 +- builtin/merge.c | 31 +- builtin/mv.c | 52 +- builtin/push.c | 2 + builtin/read-tree.c | 38 +- builtin/receive-pack.c | 7 +- builtin/remote.c | 14 +- builtin/reset.c | 2 +- builtin/rev-list.c | 2 +- builtin/rm.c | 82 +- builtin/shortlog.c | 15 +- builtin/show-ref.c | 49 +- builtin/submodule--helper.c | 101 +- builtin/tag.c | 41 +- builtin/update-index.c | 1 + builtin/verify-tag.c | 22 +- builtin/worktree.c | 4 +- cache.h | 47 +- color.c | 12 +- command-list.txt | 1 - commit.c | 22 +- commit.h | 2 +- compat/qsort_s.c | 69 + compat/winansi.c | 4 + config.c | 15 +- config.mak.uname | 3 - connect.c | 11 - contrib/coccinelle/free.cocci | 6 + contrib/coccinelle/swap.cocci | 28 + contrib/coccinelle/xstrdup_or_null.cocci | 6 + contrib/completion/git-completion.bash | 153 +- contrib/convert-objects/convert-objects.c | 329 - contrib/convert-objects/git-convert-objects.txt | 29 - .../examples/git-difftool.perl | 22 +- contrib/gitview/gitview | 1305 --- contrib/gitview/gitview.txt | 57 - diff-no-index.c | 6 +- diff.c | 46 +- dir.c | 227 +- dir.h | 4 + environment.c | 4 +- fsck.c | 4 + git-add--interactive.perl | 334 +- git-archimport.perl | 4 +- git-compat-util.h | 21 + git-cvsimport.perl | 1 - git-cvsserver.perl | 77 +- git-mergetool.sh | 21 +- git-p4.py | 121 +- git-rebase--interactive.sh | 3 +- git-rebase.sh | 6 +- git-relink.perl | 173 - git-send-email.perl | 191 +- git-sh-setup.sh | 4 +- git-submodule.sh | 39 +- git.c | 7 +- gitk-git/Makefile | 1 + gitk-git/gitk | 166 +- gitk-git/po/bg.po | 4 +- gitk-git/po/ca.po | 6 +- gitk-git/po/de.po | 4 +- gitk-git/po/es.po | 4 +- gitk-git/po/fr.po | 4 +- gitk-git/po/hu.po | 4 +- gitk-git/po/it.po | 4 +- gitk-git/po/ja.po | 13 +- gitk-git/po/pt_br.po | 4 +- gitk-git/po/pt_pt.po | 1376 +++ gitk-git/po/ru.po | 670 +- gitk-git/po/sv.po | 19 +- gitk-git/po/vi.po | 4 +- gpg-interface.h | 5 +- graph.c | 51 +- grep.c | 16 +- grep.h | 1 + help.c | 21 +- http-walker.c | 52 +- http.c | 35 +- line-range.c | 3 +- lockfile.c | 12 +- lockfile.h | 8 +- merge-recursive.c | 7 +- merge.c | 2 +- object.c | 4 +- pack-revindex.c | 5 +- path.c | 5 - pathspec.c | 515 +- pathspec.h | 5 +- perl/Git.pm | 38 + perl/Git/I18N.pm | 19 +- perl/Git/SVN.pm | 2 +- po/TEAMS | 5 +- po/bg.po | 10422 +++++++++++-------- po/ca.po | 4894 +++++---- po/de.po | 4331 +++++--- po/fr.po | 4293 +++++--- po/git.pot | 3997 ++++--- po/ko.po | 4221 +++++--- po/pt_PT.po | 4562 +++++--- po/sv.po | 4275 +++++--- po/vi.po | 4275 +++++--- po/zh_CN.po | 4258 +++++--- pretty.c | 17 + prio-queue.c | 4 +- read-cache.c | 19 +- ref-filter.c | 83 +- ref-filter.h | 9 + refs.c | 15 +- refs.h | 2 + refs/files-backend.c | 8 +- refs/refs-internal.h | 2 - remote.c | 12 +- remote.h | 4 +- rerere.c | 2 +- run-command.c | 8 +- sequencer.c | 1184 ++- sequencer.h | 4 +- setup.c | 65 +- sha1_file.c | 237 +- shell.c | 16 +- shortlog.h | 1 + strbuf.h | 4 +- string-list.c | 13 +- submodule-config.c | 60 +- submodule-config.h | 7 +- submodule.c | 267 +- submodule.h | 65 +- t/Makefile | 6 + t/helper/test-scrap-cache-tree.c | 2 +- t/helper/test-string-list.c | 25 + t/lib-proto-disable.sh | 142 +- t/lib-submodule-update.sh | 5 +- t/perf/p0071-sort.sh | 26 + t/perf/p5302-pack-index.sh | 7 + t/t0001-init.sh | 3 + t/t0202/test.pl | 14 +- t/t1000-read-tree-m-3way.sh | 648 +- t/t1001-read-tree-m-2way.sh | 649 +- t/t1400-update-ref.sh | 80 +- t/t1403-show-ref.sh | 42 + t/t1450-fsck.sh | 160 +- t/t3203-branch-output.sh | 29 + t/t3404-rebase-interactive.sh | 16 + t/t3407-rebase-abort.sh | 24 + t/t3510-cherry-pick-sequence.sh | 6 +- t/t3511-cherry-pick-x.sh | 16 +- t/t3600-rm.sh | 39 +- t/t3701-add-interactive.sh | 14 + t/t4014-format-patch.sh | 37 +- t/t4026-color.sh | 7 +- t/t4032-diff-inter-hunk-context.sh | 27 +- t/t4201-shortlog.sh | 19 + t/t4202-log.sh | 70 + t/t4205-log-pretty-formats.sh | 26 + t/t5504-fetch-receive-strict.sh | 2 +- t/t5505-remote.sh | 7 + t/t5509-fetch-push-namespaces.sh | 1 + t/t5516-fetch-push.sh | 2 +- t/t5531-deep-submodule-push.sh | 21 + t/t5532-fetch-proxy.sh | 5 - t/t5545-push-options.sh | 15 + t/t5550-http-fetch-dumb.sh | 10 + t/t5580-clone-push-unc.sh | 48 + t/t5601-clone.sh | 2 +- t/t5802-connect-helper.sh | 1 + t/t5810-proto-disable-local.sh | 23 - t/t5812-proto-disable-http.sh | 7 + t/t5813-proto-disable-ssh.sh | 23 - t/t6030-bisect-porcelain.sh | 2 +- t/t6134-pathspec-in-submodule.sh | 36 + t/t6300-for-each-ref.sh | 25 + t/t7004-tag.sh | 183 +- t/t7030-verify-tag.sh | 16 + t/t7400-submodule-basic.sh | 14 + t/t7406-submodule-update.sh | 29 + t/t7408-submodule-reference.sh | 66 + t/t7411-submodule-config.sh | 39 +- t/t7412-submodule-absorbgitdirs.sh | 128 + t/t7501-commit.sh | 36 + t/t7512-status-help.sh | 19 + t/t7600-merge.sh | 11 + t/t7610-mergetool.sh | 281 +- t/t7800-difftool.sh | 135 +- t/t7814-grep-recurse-submodules.sh | 241 + t/t9001-send-email.sh | 2 +- t/t9117-git-svn-init-clone.sh | 12 +- t/t9400-git-cvsserver-server.sh | 48 - t/t9800-git-p4-basic.sh | 20 + t/t9806-git-p4-options.sh | 32 + t/t9807-git-p4-submit.sh | 69 + t/t9813-git-p4-preserve-users.sh | 16 +- t/t9814-git-p4-rename.sh | 6 +- t/t9822-git-p4-path-encoding.sh | 16 + t/t9824-git-p4-git-lfs.sh | 24 +- t/test-lib-functions.sh | 20 +- t/test-lib.sh | 4 +- tag.c | 5 +- tempfile.c | 8 +- trailer.c | 301 +- trailer.h | 25 + transport-helper.c | 7 + transport.c | 101 +- transport.h | 50 +- tree-walk.c | 28 + unpack-trees.c | 96 +- usage.c | 17 +- versioncmp.c | 99 +- worktree.c | 54 +- worktree.h | 5 + wt-status.c | 25 +- xdiff/xdiff.h | 3 +- xdiff/xdiffi.c | 33 - xdiff/xutils.c | 106 - 308 files changed, 42887 insertions(+), 23656 deletions(-) delete mode 100644 Documentation/RelNotes/2.10.4.txt delete mode 100644 Documentation/RelNotes/2.10.5.txt delete mode 100644 Documentation/RelNotes/2.11.2.txt delete mode 100644 Documentation/RelNotes/2.11.3.txt delete mode 100644 Documentation/RelNotes/2.11.4.txt create mode 100644 Documentation/RelNotes/2.12.0.txt delete mode 100644 Documentation/RelNotes/2.4.12.txt delete mode 100644 Documentation/RelNotes/2.5.6.txt delete mode 100644 Documentation/RelNotes/2.6.7.txt delete mode 100644 Documentation/RelNotes/2.7.5.txt delete mode 100644 Documentation/RelNotes/2.7.6.txt delete mode 100644 Documentation/RelNotes/2.8.5.txt delete mode 100644 Documentation/RelNotes/2.8.6.txt delete mode 100644 Documentation/RelNotes/2.9.5.txt create mode 100644 Documentation/asciidoctor-extensions.rb delete mode 100644 Documentation/git-relink.txt create mode 100644 Documentation/texi.xsl create mode 100644 builtin/difftool.c create mode 100644 compat/qsort_s.c create mode 100644 contrib/coccinelle/swap.cocci delete mode 100644 contrib/convert-objects/convert-objects.c delete mode 100644 contrib/convert-objects/git-convert-objects.txt rename git-difftool.perl => contrib/examples/git-difftool.perl (96%) delete mode 100755 contrib/gitview/gitview delete mode 100644 contrib/gitview/gitview.txt delete mode 100755 git-relink.perl create mode 100644 gitk-git/po/pt_pt.po create mode 100755 t/perf/p0071-sort.sh create mode 100755 t/t5580-clone-push-unc.sh create mode 100755 t/t6134-pathspec-in-submodule.sh create mode 100755 t/t7412-submodule-absorbgitdirs.sh create mode 100755 t/t7814-grep-recurse-submodules.sh diff --git a/.gitignore b/.gitignore index 6722f78..b1020b8 100644 --- a/.gitignore +++ b/.gitignore @@ -118,7 +118,6 @@ /git-rebase--merge /git-receive-pack /git-reflog -/git-relink /git-remote /git-remote-http /git-remote-https diff --git a/.mailmap b/.mailmap index 9cc33e9..ab59b2f 100644 --- a/.mailmap +++ b/.mailmap @@ -192,6 +192,8 @@ Philippe Bruhat Ralf Thielow Ramsay Jones René Scharfe +Richard Hansen +Richard Hansen Robert Fitzsimons Robert Shearman Robert Zeh @@ -223,6 +225,7 @@ Steven Walter Steven Walter Sven Verdoolaege Sven Verdoolaege +SZEDER Gábor Tay Ray Chuan Ted Percival Theodore Ts'o diff --git a/Documentation/Makefile b/Documentation/Makefile index b43d66e..b5be2e2 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -120,6 +120,7 @@ INSTALL_INFO = install-info DOCBOOK2X_TEXI = docbook2x-texi DBLATEX = dblatex ASCIIDOC_DBLATEX_DIR = /etc/asciidoc/dblatex +DBLATEX_COMMON = -p $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.xsl -s $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.sty ifndef PERL_PATH PERL_PATH = /usr/bin/perl endif @@ -173,6 +174,16 @@ ifdef GNU_ROFF XMLTO_EXTRA += -m manpage-quote-apos.xsl endif +ifdef USE_ASCIIDOCTOR +ASCIIDOC = asciidoctor +ASCIIDOC_CONF = +ASCIIDOC_HTML = xhtml5 +ASCIIDOC_DOCBOOK = docbook45 +ASCIIDOC_EXTRA += -I. -rasciidoctor-extensions +ASCIIDOC_EXTRA += -alitdd='&\#x2d;&\#x2d;' +DBLATEX_COMMON = +endif + SHELL_PATH ?= $(SHELL) # Shell quote; SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) @@ -337,7 +348,7 @@ manpage-base-url.xsl: manpage-base-url.xsl.in user-manual.xml: user-manual.txt user-manual.conf $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ - $(TXT_TO_XML) -d article -o $@+ $< && \ + $(TXT_TO_XML) -d book -o $@+ $< && \ mv $@+ $@ technical/api-index.txt: technical/api-index-skel.txt \ @@ -368,13 +379,14 @@ user-manual.texi: user-manual.xml user-manual.pdf: user-manual.xml $(QUIET_DBLATEX)$(RM) $@+ $@ && \ - $(DBLATEX) -o $@+ -p $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.xsl -s $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.sty $< && \ + $(DBLATEX) -o $@+ $(DBLATEX_COMMON) $< && \ mv $@+ $@ -gitman.texi: $(MAN_XML) cat-texi.perl +gitman.texi: $(MAN_XML) cat-texi.perl texi.xsl $(QUIET_DB2TEXI)$(RM) $@+ $@ && \ - ($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \ - --to-stdout $(xml) &&) true) > $@++ && \ + ($(foreach xml,$(sort $(MAN_XML)),xsltproc -o $(xml)+ texi.xsl $(xml) && \ + $(DOCBOOK2X_TEXI) --encoding=UTF-8 --to-stdout $(xml)+ && \ + rm $(xml)+ &&) true) > $@++ && \ $(PERL_PATH) cat-texi.perl $@ <$@++ >$@+ && \ rm $@++ && \ mv $@+ $@ diff --git a/Documentation/RelNotes/2.10.3.txt b/Documentation/RelNotes/2.10.3.txt index ad6a01b..277a2a1 100644 --- a/Documentation/RelNotes/2.10.3.txt +++ b/Documentation/RelNotes/2.10.3.txt @@ -45,11 +45,4 @@ Fixes since v2.10.2 * Improve the rule to convert "unsigned char [20]" into "struct object_id *" in contrib/coccinelle/ - * "git-shell" rejects a request to serve a repository whose name - begins with a dash, which makes it no longer possible to get it - confused into spawning service programs like "git-upload-pack" with - an option like "--help", which in turn would spawn an interactive - pager, instead of working with the repository user asked to access - (i.e. the one whose name is "--help"). - Also contains minor documentation updates and code clean-ups. diff --git a/Documentation/RelNotes/2.10.4.txt b/Documentation/RelNotes/2.10.4.txt deleted file mode 100644 index ee8142a..0000000 --- a/Documentation/RelNotes/2.10.4.txt +++ /dev/null @@ -1,4 +0,0 @@ -Git v2.10.4 Release Notes -========================= - -This release forward-ports the fix for "ssh://..." URL from Git v2.7.6 diff --git a/Documentation/RelNotes/2.10.5.txt b/Documentation/RelNotes/2.10.5.txt deleted file mode 100644 index a498fd6..0000000 --- a/Documentation/RelNotes/2.10.5.txt +++ /dev/null @@ -1,17 +0,0 @@ -Git v2.10.5 Release Notes -========================= - -Fixes since v2.10.4 -------------------- - - * "git cvsserver" no longer is invoked by "git daemon" by default, - as it is old and largely unmaintained. - - * Various Perl scripts did not use safe_pipe_capture() instead of - backticks, leaving them susceptible to end-user input. They have - been corrected. - -Credits go to joernchen for finding the -unsafe constructs in "git cvsserver", and to Jeff King at GitHub for -finding and fixing instances of the same issue in other scripts. - diff --git a/Documentation/RelNotes/2.11.2.txt b/Documentation/RelNotes/2.11.2.txt deleted file mode 100644 index 7428851..0000000 --- a/Documentation/RelNotes/2.11.2.txt +++ /dev/null @@ -1,12 +0,0 @@ -Git v2.11.2 Release Notes -========================= - -Fixes since v2.11.1 -------------------- - - * "git-shell" rejects a request to serve a repository whose name - begins with a dash, which makes it no longer possible to get it - confused into spawning service programs like "git-upload-pack" with - an option like "--help", which in turn would spawn an interactive - pager, instead of working with the repository user asked to access - (i.e. the one whose name is "--help"). diff --git a/Documentation/RelNotes/2.11.3.txt b/Documentation/RelNotes/2.11.3.txt deleted file mode 100644 index 4e3b78d..0000000 --- a/Documentation/RelNotes/2.11.3.txt +++ /dev/null @@ -1,4 +0,0 @@ -Git v2.11.3 Release Notes -========================= - -This release forward-ports the fix for "ssh://..." URL from Git v2.7.6 diff --git a/Documentation/RelNotes/2.11.4.txt b/Documentation/RelNotes/2.11.4.txt deleted file mode 100644 index ad4da8e..0000000 --- a/Documentation/RelNotes/2.11.4.txt +++ /dev/null @@ -1,17 +0,0 @@ -Git v2.11.4 Release Notes -========================= - -Fixes since v2.11.3 -------------------- - - * "git cvsserver" no longer is invoked by "git daemon" by default, - as it is old and largely unmaintained. - - * Various Perl scripts did not use safe_pipe_capture() instead of - backticks, leaving them susceptible to end-user input. They have - been corrected. - -Credits go to joernchen for finding the -unsafe constructs in "git cvsserver", and to Jeff King at GitHub for -finding and fixing instances of the same issue in other scripts. - diff --git a/Documentation/RelNotes/2.12.0.txt b/Documentation/RelNotes/2.12.0.txt new file mode 100644 index 0000000..2915480 --- /dev/null +++ b/Documentation/RelNotes/2.12.0.txt @@ -0,0 +1,500 @@ +Git 2.12 Release Notes +====================== + +Backward compatibility notes. + + * Use of an empty string that is used for 'everything matches' is + still warned and Git asks users to use a more explicit '.' for that + instead. The hope is that existing users will not mind this + change, and eventually the warning can be turned into a hard error, + upgrading the deprecation into removal of this (mis)feature. That + is not scheduled to happen in the upcoming release (yet). + + * The historical argument order "git merge HEAD ..." + has been deprecated for quite some time, and will be removed in a + future release. + + * An ancient script "git relink" has been removed. + + +Updates since v2.11 +------------------- + +UI, Workflows & Features + + * Various updates to "git p4". + + * "git p4" didn't interact with the internal of .git directory + correctly in the modern "git-worktree"-enabled world. + + * "git branch --list" and friends learned "--ignore-case" option to + optionally sort branches and tags case insensitively. + + * In addition to %(subject), %(body), "log --pretty=format:..." + learned a new placeholder %(trailers). + + * "git rebase" learned "--quit" option, which allows a user to + remove the metadata left by an earlier "git rebase" that was + manually aborted without using "git rebase --abort". + + * "git clone --reference $there --recurse-submodules $super" has been + taught to guess repositories usable as references for submodules of + $super that are embedded in $there while making a clone of the + superproject borrow objects from $there; extend the mechanism to + also allow submodules of these submodules to borrow repositories + embedded in these clones of the submodules embedded in the clone of + the superproject. + + * Porcelain scripts written in Perl are getting internationalized. + + * "git merge --continue" has been added as a synonym to "git commit" + to conclude a merge that has stopped due to conflicts. + + * Finer-grained control of what protocols are allowed for transports + during clone/fetch/push have been enabled via a new configuration + mechanism. + + * "git shortlog" learned "--committer" option to group commits by + committer, instead of author. + + * GitLFS integration with "git p4" has been updated. + + * The isatty() emulation for Windows has been updated to eradicate + the previous hack that depended on internals of (older) MSVC + runtime. + + * Some platforms no longer understand "latin-1" that is still seen in + the wild in e-mail headers; replace them with "iso-8859-1" that is + more widely known when conversion fails from/to it. + + * "git grep" has been taught to optionally recurse into submodules. + + * "git rm" used to refuse to remove a submodule when it has its own + git repository embedded in its working tree. It learned to move + the repository away to $GIT_DIR/modules/ of the superproject + instead, and allow the submodule to be deleted (as long as there + will be no loss of local modifications, that is). + + * A recent updates to "git p4" was not usable for older p4 but it + could be made to work with minimum changes. Do so. + + * "git diff" learned diff.interHunkContext configuration variable + that gives the default value for its --inter-hunk-context option. + + * The prereleaseSuffix feature of version comparison that is used in + "git tag -l" did not correctly when two or more prereleases for the + same release were present (e.g. when 2.0, 2.0-beta1, and 2.0-beta2 + are there and the code needs to compare 2.0-beta1 and 2.0-beta2). + + * "git submodule push" learned "--recurse-submodules=only option to + push submodules out without pushing the top-level superproject. + + * "git tag" and "git verify-tag" learned to put GPG verification + status in their "--format=" output format. + + * An ancient repository conversion tool left in contrib/ has been + removed. + + * "git show-ref HEAD" used with "--verify" because the user is not + interested in seeing refs/remotes/origin/HEAD, and used with + "--head" because the user does not want HEAD to be filtered out, + i.e. "git show-ref --head --verify HEAD", did not work as expected. + + * "git submodule add" used to be confused and refused to add a + locally created repository; users can now use "--force" option + to add them. + (merge 619acfc78c sb/submodule-add-force later to maint). + + * Some people feel the default set of colors used by "git log --graph" + rather limiting. A mechanism to customize the set of colors has + been introduced. + + * "git read-tree" and its underlying unpack_trees() machinery learned + to report problematic paths prefixed with the --super-prefix option. + + * When a submodule "A", which has another submodule "B" nested within + it, is "absorbed" into the top-level superproject, the inner + submodule "B" used to be left in a strange state. The logic to + adjust the .git pointers in these submodules has been corrected. + + * The user can specify a custom update method that is run when + "submodule update" updates an already checked out submodule. This + was ignored when checking the submodule out for the first time and + we instead always just checked out the commit that is bound to the + path in the superproject's index. + + * The command line completion (in contrib/) learned that + "git diff --submodule=" can take "diff" as a recently added option. + + * The "core.logAllRefUpdates" that used to be boolean has been + enhanced to take 'always' as well, to record ref updates to refs + other than the ones that are expected to be updated (i.e. branches, + remote-tracking branches and notes). + + * Comes with more command line completion (in contrib/) for recently + introduced options. + + +Performance, Internal Implementation, Development Support etc. + + * Commands that operate on a log message and add lines to the trailer + blocks, such as "format-patch -s", "cherry-pick (-x|-s)", and + "commit -s", have been taught to use the logic of and share the + code with "git interpret-trailer". + + * The default Travis-CI configuration specifies newer P4 and GitLFS. + + * The "fast hash" that had disastrous performance issues in some + corner cases has been retired from the internal diff. + + * The character width table has been updated to match Unicode 9.0 + + * Update the procedure to generate "tags" for developer support. + + * The codeflow of setting NOATIME and CLOEXEC on file descriptors Git + opens has been simplified. + + * "git diff" and its family had two experimental heuristics to shift + the contents of a hunk to make the patch easier to read. One of + them turns out to be better than the other, so leave only the + "--indent-heuristic" option and remove the other one. + + * A new submodule helper "git submodule embedgitdirs" to make it + easier to move embedded .git/ directory for submodules in a + superproject to .git/modules/ (and point the latter with the former + that is turned into a "gitdir:" file) has been added. + + * "git push \\server\share\dir" has recently regressed and then + fixed. A test has retroactively been added for this breakage. + + * Build updates for Cygwin. + + * The implementation of "real_path()" was to go there with chdir(2) + and call getcwd(3), but this obviously wouldn't be usable in a + threaded environment. Rewrite it to manually resolve relative + paths including symbolic links in path components. + + * Adjust documentation to help AsciiDoctor render better while not + breaking the rendering done by AsciiDoc. + + * The sequencer machinery has been further enhanced so that a later + set of patches can start using it to reimplement "rebase -i". + + * Update the definition of the MacOSX test environment used by + TravisCI. + + * Rewrite a scripted porcelain "git difftool" in C. + + * "make -C t failed" will now run only the tests that failed in the + previous run. This is usable only when prove is not use, and gives + a useless error message when run after "make clean", but otherwise + is serviceable. + + * "uchar [40]" to "struct object_id" conversion continues. + + +Also contains various documentation updates and code clean-ups. + +Fixes since v2.10 +----------------- + +Unless otherwise noted, all the fixes since v2.9 in the maintenance +track are contained in this release (see the maintenance releases' +notes for details). + + * We often decide if a session is interactive by checking if the + standard I/O streams are connected to a TTY, but isatty() that + comes with Windows incorrectly returned true if it is used on NUL + (i.e. an equivalent to /dev/null). This has been fixed. + + * "git svn" did not work well with path components that are "0", and + some configuration variable it uses were not documented. + + * "git rev-parse --symbolic" failed with a more recent notation like + "HEAD^-1" and "HEAD^!". + + * An empty directory in a working tree that can simply be nuked used + to interfere while merging or cherry-picking a change to create a + submodule directory there, which has been fixed.. + + * The code in "git push" to compute if any commit being pushed in the + superproject binds a commit in a submodule that hasn't been pushed + out was overly inefficient, making it unusable even for a small + project that does not have any submodule but have a reasonable + number of refs. + + * "git push --dry-run --recurse-submodule=on-demand" wasn't + "--dry-run" in the submodules. + + * The output from "git worktree list" was made in readdir() order, + and was unstable. + + * mergetool..trustExitCode configuration variable did not apply + to built-in tools, but now it does. + + * "git p4" LFS support was broken when LFS stores an empty blob. + + * A corner case in merge-recursive regression that crept in + during 2.10 development cycle has been fixed. + + * Transport with dumb http can be fooled into following foreign URLs + that the end user does not intend to, especially with the server + side redirects and http-alternates mechanism, which can lead to + security issues. Tighten the redirection and make it more obvious + to the end user when it happens. + + * Update the error messages from the dumb-http client when it fails + to obtain loose objects; we used to give sensible error message + only upon 404 but we now forbid unexpected redirects that needs to + be reported with something sensible. + + * When diff.renames configuration is on (and with Git 2.9 and later, + it is enabled by default, which made it worse), "git stash" + misbehaved if a file is removed and another file with a very + similar content is added. + + * "git diff --no-index" did not take "--no-abbrev" option. + + * "git difftool --dir-diff" had a minor regression when started from + a subdirectory, which has been fixed. + + * "git commit --allow-empty --only" (no pathspec) with dirty index + ought to be an acceptable way to create a new commit that does not + change any paths, but it was forbidden, perhaps because nobody + needed it so far. + + * Git 2.11 had a minor regression in "merge --ff-only" that competed + with another process that simultanously attempted to update the + index. We used to explain what went wrong with an error message, + but the new code silently failed. The error message has been + resurrected. + + * A pathname that begins with "//" or "\\" on Windows is special but + path normalization logic was unaware of it. + + * "git pull --rebase", when there is no new commits on our side since + we forked from the upstream, should be able to fast-forward without + invoking "git rebase", but it didn't. + + * The way to specify hotkeys to "xxdiff" that is used by "git + mergetool" has been modernized to match recent versions of xxdiff. + + * Unlike "git am --abort", "git cherry-pick --abort" moved HEAD back + to where cherry-pick started while picking multiple changes, when + the cherry-pick stopped to ask for help from the user, and the user + did "git reset --hard" to a different commit in order to re-attempt + the operation. + + * Code cleanup in shallow boundary computation. + + * A recent update to receive-pack to make it easier to drop garbage + objects made it clear that GIT_ALTERNATE_OBJECT_DIRECTORIES cannot + have a pathname with a colon in it (no surprise!), and this in turn + made it impossible to push into a repository at such a path. This + has been fixed by introducing a quoting mechanism used when + appending such a path to the colon-separated list. + + * The function usage_msg_opt() has been updated to say "fatal:" + before the custom message programs give, when they want to die + with a message about wrong command line options followed by the + standard usage string. + + * "git index-pack --stdin" needs an access to an existing repository, + but "git index-pack file.pack" to generate an .idx file that + corresponds to a packfile does not. + + * Fix for NDEBUG builds. + + * A lazy "git push" without refspec did not internally use a fully + specified refspec to perform 'current', 'simple', or 'upstream' + push, causing unnecessary "ambiguous ref" errors. + + * "git p4" misbehaved when swapping a directory and a symbolic link. + + * Even though an fix was attempted in Git 2.9.3 days, but running + "git difftool --dir-diff" from a subdirectory never worked. This + has been fixed. + + * "git p4" that tracks multile p4 paths imported a single changelist + that touches files in these multiple paths as one commit, followed + by many empty commits. This has been fixed. + + * A potential but unlikely buffer overflow in Windows port has been + fixed. + + * When the http server gives an incomplete response to a smart-http + rpc call, it could lead to client waiting for a full response that + will never come. Teach the client side to notice this condition + and abort the transfer. + + * Compression setting for producing packfiles were spread across + three codepaths, one of which did not honor any configuration. + Unify these so that all of them honor core.compression and + pack.compression variables the same way. + + * "git fast-import" sometimes mishandled while rebalancing notes + tree, which has been fixed. + + * Recent update to the default abbreviation length that auto-scales + lacked documentation update, which has been corrected. + + * Leakage of lockfiles in the config subsystem has been fixed. + + * It is natural that "git gc --auto" may not attempt to pack + everything into a single pack, and there is no point in warning + when the user has configured the system to use the pack bitmap, + leading to disabling further "gc". + + * "git archive" did not read the standard configuration files, and + failed to notice a file that is marked as binary via the userdiff + driver configuration. + + * "git blame --porcelain" misidentified the "previous" + pair (aka "source") when contents came from two or more files. + + * "git rebase -i" with a recent update started showing an incorrect + count when squashing more than 10 commits. + + * "git @{push}" on a detached HEAD used to segfault; it has + been corrected to error out with a message. + + * Running "git add a/b" when "a" is a submodule correctly errored + out, but without a meaningful error message. + (merge 2d81c48fa7 sb/pathspec-errors later to maint). + + * Typing ^C to pager, which usually does not kill it, killed Git and + took the pager down as a collateral damage in certain process-tree + structure. This has been fixed. + + * "git mergetool" without any pathspec on the command line that is + run from a subdirectory became no-op in Git v2.11 by mistake, which + has been fixed. + + * Retire long unused/unmaintained gitview from the contrib/ area. + (merge 3120925c25 sb/remove-gitview later to maint). + + * Tighten a test to avoid mistaking an extended ERE regexp engine as + a PRE regexp engine. + + * An error message with an ASCII control character like '\r' in it + can alter the message to hide its early part, which is problematic + when a remote side gives such an error message that the local side + will relay with a "remote: " prefix. + (merge f290089879 jk/vreport-sanitize later to maint). + + * "git fsck" inspects loose objects more carefully now. + (merge cce044df7f jk/loose-object-fsck later to maint). + + * A crashing bug introduced in v2.11 timeframe has been found (it is + triggerable only in fast-import) and fixed. + (merge abd5a00268 jk/clear-delta-base-cache-fix later to maint). + + * With an anticipatory tweak for remotes defined in ~/.gitconfig + (e.g. "remote.origin.prune" set to true, even though there may or + may not actually be "origin" remote defined in a particular Git + repository), "git remote rename" and other commands misinterpreted + and behaved as if such a non-existing remote actually existed. + (merge e459b073fb js/remote-rename-with-half-configured-remote later to maint). + + * A few codepaths had to rely on a global variable when sorting + elements of an array because sort(3) API does not allow extra data + to be passed to the comparison function. Use qsort_s() when + natively available, and a fallback implementation of it when not, + to eliminate the need, which is a prerequisite for making the + codepath reentrant. + + * "git fsck --connectivity-check" was not working at all. + (merge a2b22854bd jk/fsck-connectivity-check-fix later to maint). + + * After starting "git rebase -i", which first opens the user's editor + to edit the series of patches to apply, but before saving the + contents of that file, "git status" failed to show the current + state (i.e. you are in an interactive rebase session, but you have + applied no steps yet) correctly. + (merge df9ded4984 js/status-pre-rebase-i later to maint). + + * Test tweak for FreeBSD where /usr/bin/unzip is unsuitable to run + our tests but /usr/local/bin/unzip is usable. + (merge d98b2c5fce js/unzip-in-usr-bin-workaround later to maint). + + * "git p4" did not work well with multiple git-p4.mapUser entries on + Windows. + (merge c3c2b05776 gv/mingw-p4-mapuser later to maint). + + * "git help" enumerates executable files in $PATH; the implementation + of "is this file executable?" on Windows has been optimized. + (merge c755015f79 hv/mingw-help-is-executable later to maint). + + * Test tweaks for those who have default ACL in their git source tree + that interfere with the umask test. + (merge d549d21307 mm/reset-facl-before-umask-test later to maint). + + * Names of the various hook scripts must be spelled exactly, but on + Windows, an .exe binary must be named with .exe suffix; notice + $GIT_DIR/hooks/.exe as a valid hook. + (merge 235be51fbe js/mingw-hooks-with-exe-suffix later to maint). + + * Asciidoctor, an alternative reimplementation of AsciiDoc, still + needs some changes to work with documents meant to be formatted + with AsciiDoc. "make USE_ASCIIDOCTOR=YesPlease" to use it out of + the box to document our pages is getting closer to reality. + + * Correct command line completion (in contrib/) on "git svn" + (merge 2cbad17642 ew/complete-svn-authorship-options later to maint). + + * Incorrect usage help message for "git worktree prune" has been fixed. + (merge 2488dcab22 ps/worktree-prune-help-fix later to maint). + + * Adjust a perf test to new world order where commands that do + require a repository are really strict about having a repository. + (merge c86000c1a7 rs/p5302-create-repositories-before-tests later to maint). + + * "git log --graph" did not work well with "--name-only", even though + other forms of "diff" output were handled correctly. + (merge f5022b5fed jk/log-graph-name-only later to maint). + + * The push-options given via the "--push-options" option were not + passed through to external remote helpers such as "smart HTTP" that + are invoked via the transport helper. + + * The documentation explained what "git stash" does to the working + tree (after stashing away the local changes) in terms of "reset + --hard", which was exposing an unnecessary implementation detail. + (merge 20a7e06172 tg/stash-doc-cleanup later to maint). + + * When "git p4" imports changelist that removes paths, it failed to + convert pathnames when the p4 used encoding different from the one + used on the Git side. This has been corrected. + (merge a8b05162e8 ls/p4-path-encoding later to maint). + + * A new coccinelle rule that catches a check of !pointer before the + pointer is free(3)d, which most likely is a bug. + (merge ec6cd14c7a rs/cocci-check-free-only-null later to maint). + + * "ls-files" run with pathspec has been micro-optimized to avoid + having to memmove(3) unnecessary bytes. + (merge 96f6d3f61a rs/ls-files-partial-optim later to maint). + + * A hotfix for a topic already in 'master'. + (merge a4d92d579f js/mingw-isatty later to maint). + + * Other minor doc, test and build updates and code cleanups. + (merge f2627d9b19 sb/submodule-config-cleanup later to maint). + (merge 384f1a167b sb/unpack-trees-cleanup later to maint). + (merge 874444b704 rh/diff-orderfile-doc later to maint). + (merge eafd5d9483 cw/doc-sign-off later to maint). + (merge 0aaad415bc rs/absolute-pathdup later to maint). + (merge 4432dd6b5b rs/receive-pack-cleanup later to maint). + (merge 540a398e9c sg/mailmap-self later to maint). + (merge 209df269a6 nd/rev-list-all-includes-HEAD-doc later to maint). + (merge 941b9c5270 sb/doc-unify-bottom later to maint). + (merge 2aaf37b62c jk/doc-remote-helpers-markup-fix later to maint). + (merge e91461b332 jk/doc-submodule-markup-fix later to maint). + (merge 8ab9740d9f dp/submodule-doc-markup-fix later to maint). + (merge 0838cbc22f jk/tempfile-ferror-fclose-confusion later to maint). + (merge 115a40add6 dr/doc-check-ref-format-normalize later to maint). + (merge 133f0a299d gp/document-dotfiles-in-templates-are-not-copied later to maint). + (merge 2b35a9f4c7 bc/blame-doc-fix later to maint). + (merge 7e82388024 ps/doc-gc-aggressive-depth-update later to maint). + (merge 9993a7c5f1 bc/worktree-doc-fix-detached later to maint). + (merge e519eccdf4 rt/align-add-i-help-text later to maint). diff --git a/Documentation/RelNotes/2.4.12.txt b/Documentation/RelNotes/2.4.12.txt deleted file mode 100644 index 7d15f94..0000000 --- a/Documentation/RelNotes/2.4.12.txt +++ /dev/null @@ -1,12 +0,0 @@ -Git v2.4.12 Release Notes -========================= - -Fixes since v2.4.11 -------------------- - - * "git-shell" rejects a request to serve a repository whose name - begins with a dash, which makes it no longer possible to get it - confused into spawning service programs like "git-upload-pack" with - an option like "--help", which in turn would spawn an interactive - pager, instead of working with the repository user asked to access - (i.e. the one whose name is "--help"). diff --git a/Documentation/RelNotes/2.5.6.txt b/Documentation/RelNotes/2.5.6.txt deleted file mode 100644 index 9cd025b..0000000 --- a/Documentation/RelNotes/2.5.6.txt +++ /dev/null @@ -1,12 +0,0 @@ -Git v2.5.6 Release Notes -======================== - -Fixes since v2.5.5 ------------------- - - * "git-shell" rejects a request to serve a repository whose name - begins with a dash, which makes it no longer possible to get it - confused into spawning service programs like "git-upload-pack" with - an option like "--help", which in turn would spawn an interactive - pager, instead of working with the repository user asked to access - (i.e. the one whose name is "--help"). diff --git a/Documentation/RelNotes/2.6.7.txt b/Documentation/RelNotes/2.6.7.txt deleted file mode 100644 index 1335de4..0000000 --- a/Documentation/RelNotes/2.6.7.txt +++ /dev/null @@ -1,12 +0,0 @@ -Git v2.6.7 Release Notes -======================== - -Fixes since v2.6.6 ------------------- - - * "git-shell" rejects a request to serve a repository whose name - begins with a dash, which makes it no longer possible to get it - confused into spawning service programs like "git-upload-pack" with - an option like "--help", which in turn would spawn an interactive - pager, instead of working with the repository user asked to access - (i.e. the one whose name is "--help"). diff --git a/Documentation/RelNotes/2.7.5.txt b/Documentation/RelNotes/2.7.5.txt deleted file mode 100644 index 83559ce..0000000 --- a/Documentation/RelNotes/2.7.5.txt +++ /dev/null @@ -1,14 +0,0 @@ -Git v2.7.5 Release Notes -======================== - -Fixes since v2.7.4 ------------------- - - * "git-shell" rejects a request to serve a repository whose name - begins with a dash, which makes it no longer possible to get it - confused into spawning service programs like "git-upload-pack" with - an option like "--help", which in turn would spawn an interactive - pager, instead of working with the repository user asked to access - (i.e. the one whose name is "--help"). - -Also contains a few fixes backported from later development tracks. diff --git a/Documentation/RelNotes/2.7.6.txt b/Documentation/RelNotes/2.7.6.txt deleted file mode 100644 index 4c6d1dc..0000000 --- a/Documentation/RelNotes/2.7.6.txt +++ /dev/null @@ -1,25 +0,0 @@ -Git v2.7.6 Release Notes -======================== - -Fixes since v2.7.5 ------------------- - - * A "ssh://..." URL can result in a "ssh" command line with a - hostname that begins with a dash "-", which would cause the "ssh" - command to instead (mis)treat it as an option. This is now - prevented by forbidding such a hostname (which will not be - necessary in the real world). - - * Similarly, when GIT_PROXY_COMMAND is configured, the command is - run with host and port that are parsed out from "ssh://..." URL; - a poorly written GIT_PROXY_COMMAND could be tricked into treating - a string that begins with a dash "-". This is now prevented by - forbidding such a hostname and port number (again, which will not - be necessary in the real world). - - * In the same spirit, a repository name that begins with a dash "-" - is also forbidden now. - -Credits go to Brian Neel at GitLab, Joern Schneeweisz of Recurity -Labs and Jeff King at GitHub. - diff --git a/Documentation/RelNotes/2.8.5.txt b/Documentation/RelNotes/2.8.5.txt deleted file mode 100644 index 7bd179f..0000000 --- a/Documentation/RelNotes/2.8.5.txt +++ /dev/null @@ -1,12 +0,0 @@ -Git v2.8.5 Release Notes -======================== - -Fixes since v2.8.4 ------------------- - - * "git-shell" rejects a request to serve a repository whose name - begins with a dash, which makes it no longer possible to get it - confused into spawning service programs like "git-upload-pack" with - an option like "--help", which in turn would spawn an interactive - pager, instead of working with the repository user asked to access - (i.e. the one whose name is "--help"). diff --git a/Documentation/RelNotes/2.8.6.txt b/Documentation/RelNotes/2.8.6.txt deleted file mode 100644 index d8db55d..0000000 --- a/Documentation/RelNotes/2.8.6.txt +++ /dev/null @@ -1,4 +0,0 @@ -Git v2.8.6 Release Notes -======================== - -This release forward-ports the fix for "ssh://..." URL from Git v2.7.6 diff --git a/Documentation/RelNotes/2.9.4.txt b/Documentation/RelNotes/2.9.4.txt index 9768293..01e8642 100644 --- a/Documentation/RelNotes/2.9.4.txt +++ b/Documentation/RelNotes/2.9.4.txt @@ -80,11 +80,4 @@ Fixes since v2.9.3 the file descriptor still open. Open tempfile with O_CLOEXEC flag to avoid this (on Windows, this is mapped to O_NOINHERIT). - * "git-shell" rejects a request to serve a repository whose name - begins with a dash, which makes it no longer possible to get it - confused into spawning service programs like "git-upload-pack" with - an option like "--help", which in turn would spawn an interactive - pager, instead of working with the repository user asked to access - (i.e. the one whose name is "--help"). - Also contains minor documentation updates and code clean-ups. diff --git a/Documentation/RelNotes/2.9.5.txt b/Documentation/RelNotes/2.9.5.txt deleted file mode 100644 index 668313a..0000000 --- a/Documentation/RelNotes/2.9.5.txt +++ /dev/null @@ -1,4 +0,0 @@ -Git v2.9.5 Release Notes -======================== - -This release forward-ports the fix for "ssh://..." URL from Git v2.7.6 diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 08352de..3faf7eb 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -216,12 +216,11 @@ that it will be postponed. Exception: If your mailer is mangling patches then someone may ask you to re-send them using MIME, that is OK. -Do not PGP sign your patch, at least for now. Most likely, your -maintainer or other people on the list would not have your PGP -key and would not bother obtaining it anyway. Your patch is not -judged by who you are; a good patch from an unknown origin has a -far better chance of being accepted than a patch from a known, -respected origin that is done poorly or does incorrect things. +Do not PGP sign your patch. Most likely, your maintainer or other people on the +list would not have your PGP key and would not bother obtaining it anyway. +Your patch is not judged by who you are; a good patch from an unknown origin +has a far better chance of being accepted than a patch from a known, respected +origin that is done poorly or does incorrect things. If you really really really really want to do a PGP signed patch, format it as "multipart/signed", not a text/plain message @@ -246,7 +245,7 @@ patch. *2* The mailing list: git@vger.kernel.org -(5) Sign your work +(5) Certify your work by adding your "Signed-off-by: " line To improve tracking of who did what, we've borrowed the "sign-off" procedure from the Linux kernel project on patches diff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb new file mode 100644 index 0000000..ec83b49 --- /dev/null +++ b/Documentation/asciidoctor-extensions.rb @@ -0,0 +1,28 @@ +require 'asciidoctor' +require 'asciidoctor/extensions' + +module Git + module Documentation + class LinkGitProcessor < Asciidoctor::Extensions::InlineMacroProcessor + use_dsl + + named :chrome + + def process(parent, target, attrs) + if parent.document.basebackend? 'html' + prefix = parent.document.attr('git-relative-html-prefix') + %(#{target}(#{attrs[1]})\n) + elsif parent.document.basebackend? 'docbook' + "\n" \ + "#{target}" \ + "#{attrs[1]}\n" \ + "\n" + end + end + end + end +end + +Asciidoctor::Extensions.register do + inline_macro Git::Documentation::LinkGitProcessor, :linkgit +end diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt index 2669b87..dc41957 100644 --- a/Documentation/blame-options.txt +++ b/Documentation/blame-options.txt @@ -77,7 +77,7 @@ include::line-range-format.txt[] terminal. Can't use `--progress` together with `--porcelain` or `--incremental`. --M||:: +-M[]:: Detect moved or copied lines within a file. When a commit moves or copies a block of lines (e.g. the original file has A and then B, and the commit changes it to B and then @@ -93,7 +93,7 @@ alphanumeric characters that Git must detect as moving/copying within a file for it to associate those lines with the parent commit. The default value is 20. --C||:: +-C[]:: In addition to `-M`, detect lines moved or copied from other files that were modified in the same commit. This is useful when you reorganize your program and move code diff --git a/Documentation/cat-texi.perl b/Documentation/cat-texi.perl index 87437f8..14d2f83 100755 --- a/Documentation/cat-texi.perl +++ b/Documentation/cat-texi.perl @@ -1,9 +1,12 @@ #!/usr/bin/perl -w +use strict; +use warnings; + my @menu = (); my $output = $ARGV[0]; -open TMP, '>', "$output.tmp"; +open my $tmp, '>', "$output.tmp"; while () { next if (/^\\input texinfo/../\@node Top/); @@ -11,13 +14,13 @@ while () { if (s/^\@top (.*)/\@node $1,,,Top/) { push @menu, $1; } - s/\(\@pxref{\[(URLS|REMOTES)\]}\)//; + s/\(\@pxref\{\[(URLS|REMOTES)\]}\)//; s/\@anchor\{[^{}]*\}//g; - print TMP; + print $tmp $_; } -close TMP; +close $tmp; -printf '\input texinfo +print '\input texinfo @setfilename gitman.info @documentencoding UTF-8 @dircategory Development @@ -28,16 +31,16 @@ printf '\input texinfo @top Git Manual Pages @documentlanguage en @menu -', $menu[0]; +'; for (@menu) { print "* ${_}::\n"; } print "\@end menu\n"; -open TMP, '<', "$output.tmp"; -while () { +open $tmp, '<', "$output.tmp"; +while (<$tmp>) { print; } -close TMP; +close $tmp; print "\@bye\n"; unlink "$output.tmp"; diff --git a/Documentation/config.txt b/Documentation/config.txt index 1fee83c..015346c 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -170,6 +170,9 @@ The position of any attributes with respect to the colors be turned off by prefixing them with `no` or `no-` (e.g., `noreverse`, `no-ul`, etc). + +An empty color string produces no color effect at all. This can be used +to avoid coloring specific elements without disabling color entirely. ++ For git's pre-defined color slots, the attributes are meant to be reset at the beginning of each item in the colored output. So setting `color.decorate.branch` to `black` will paint that branch name in a @@ -517,10 +520,12 @@ core.logAllRefUpdates:: "`$GIT_DIR/logs/`", by appending the new and old SHA-1, the date/time and the reason of the update, but only when the file exists. If this configuration - variable is set to true, missing "`$GIT_DIR/logs/`" + variable is set to `true`, missing "`$GIT_DIR/logs/`" file is automatically created for branch heads (i.e. under - refs/heads/), remote refs (i.e. under refs/remotes/), - note refs (i.e. under refs/notes/), and the symbolic ref HEAD. + `refs/heads/`), remote refs (i.e. under `refs/remotes/`), + note refs (i.e. under `refs/notes/`), and the symbolic ref `HEAD`. + If it is set to `always`, then a missing reflog is automatically + created for any ref under `refs/`. + This information can be used to determine what commit was the tip of a branch "2 days ago". @@ -2036,6 +2041,10 @@ log.follow:: i.e. it cannot be used to follow multiple files and does not work well on non-linear history. +log.graphColors:: + A list of colors, separated by commas, that can be used to draw + history lines in `git log --graph`. + log.showRoot:: If true, the initial commit will be shown as a big creation event. This is equivalent to a diff against an empty tree. @@ -2321,6 +2330,52 @@ pretty.:: Note that an alias with the same name as a built-in format will be silently ignored. +protocol.allow:: + If set, provide a user defined default policy for all protocols which + don't explicitly have a policy (`protocol..allow`). By default, + if unset, known-safe protocols (http, https, git, ssh, file) have a + default policy of `always`, known-dangerous protocols (ext) have a + default policy of `never`, and all other protocols have a default + policy of `user`. Supported policies: ++ +-- + +* `always` - protocol is always able to be used. + +* `never` - protocol is never able to be used. + +* `user` - protocol is only able to be used when `GIT_PROTOCOL_FROM_USER` is + either unset or has a value of 1. This policy should be used when you want a + protocol to be directly usable by the user but don't want it used by commands which + execute clone/fetch/push commands without user input, e.g. recursive + submodule initialization. + +-- + +protocol..allow:: + Set a policy to be used by protocol `` with clone/fetch/push + commands. See `protocol.allow` above for the available policies. ++ +The protocol names currently used by git are: ++ +-- + - `file`: any local file-based path (including `file://` URLs, + or local paths) + + - `git`: the anonymous git protocol over a direct TCP + connection (or proxy, if configured) + + - `ssh`: git over ssh (including `host:path` syntax, + `ssh://`, etc). + + - `http`: git over http, both "smart http" and "dumb http". + Note that this does _not_ include `https`; if you want to configure + both, you must do so individually. + + - any external helpers are named by their protocol (e.g., use + `hg` to allow the `git-remote-hg` helper) +-- + pull.ff:: By default, Git does not create an extra merge commit when merging a commit that is a descendant of the current commit. Instead, the @@ -2894,7 +2949,7 @@ submodule.alternateLocation:: value is set to `superproject` the submodule to be cloned computes its alternates location relative to the superprojects alternate. -submodule.alternateErrorStrategy +submodule.alternateErrorStrategy:: Specifies how to treat errors with the alternates for a submodule as computed via `submodule.alternateLocation`. Possible values are `ignore`, `info`, `die`. Default is `die`. @@ -3067,17 +3122,39 @@ user.signingKey:: This option is passed unchanged to gpg's --local-user parameter, so you may specify a key using any method that gpg supports. -versionsort.prereleaseSuffix:: - When version sort is used in linkgit:git-tag[1], prerelease - tags (e.g. "1.0-rc1") may appear after the main release - "1.0". By specifying the suffix "-rc" in this variable, - "1.0-rc1" will appear before "1.0". -+ -This variable can be specified multiple times, once per suffix. The -order of suffixes in the config file determines the sorting order -(e.g. if "-pre" appears before "-rc" in the config file then 1.0-preXX -is sorted before 1.0-rcXX). The sorting order between different -suffixes is undefined if they are in multiple config files. +versionsort.prereleaseSuffix (deprecated):: + Deprecated alias for `versionsort.suffix`. Ignored if + `versionsort.suffix` is set. + +versionsort.suffix:: + Even when version sort is used in linkgit:git-tag[1], tagnames + with the same base version but different suffixes are still sorted + lexicographically, resulting e.g. in prerelease tags appearing + after the main release (e.g. "1.0-rc1" after "1.0"). This + variable can be specified to determine the sorting order of tags + with different suffixes. ++ +By specifying a single suffix in this variable, any tagname containing +that suffix will appear before the corresponding main release. E.g. if +the variable is set to "-rc", then all "1.0-rcX" tags will appear before +"1.0". If specified multiple times, once per suffix, then the order of +suffixes in the configuration will determine the sorting order of tagnames +with those suffixes. E.g. if "-pre" appears before "-rc" in the +configuration, then all "1.0-preX" tags will be listed before any +"1.0-rcX" tags. The placement of the main release tag relative to tags +with various suffixes can be determined by specifying the empty suffix +among those other suffixes. E.g. if the suffixes "-rc", "", "-ck" and +"-bfs" appear in the configuration in this order, then all "v4.8-rcX" tags +are listed first, followed by "v4.8", then "v4.8-ckX" and finally +"v4.8-bfsX". ++ +If more than one suffixes match the same tagname, then that tagname will +be sorted according to the suffix which starts at the earliest position in +the tagname. If more than one different matching suffixes start at +that earliest position, then that tagname will be sorted according to the +longest of those suffixes. +The sorting order between different suffixes is undefined if they are +in multiple config files. web.browser:: Specify a web browser that may be used by some commands. diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt index 58f4bd6..cbce8ec 100644 --- a/Documentation/diff-config.txt +++ b/Documentation/diff-config.txt @@ -60,6 +60,12 @@ diff.context:: Generate diffs with lines of context instead of the default of 3. This value is overridden by the -U option. +diff.interHunkContext:: + Show the context between diff hunks, up to the specified number + of lines, thereby fusing the hunks that are close to each other. + This value serves as the default for the `--inter-hunk-context` + command line option. + diff.external:: If this config variable is set, diff generation is not performed using the internal diff machinery, but using the @@ -99,9 +105,10 @@ diff.noprefix:: If set, 'git diff' does not show any source or destination prefix. diff.orderFile:: - File indicating how to order files within a diff, using - one shell glob pattern per line. - Can be overridden by the '-O' option to linkgit:git-diff[1]. + File indicating how to order files within a diff. + See the '-O' option to linkgit:git-diff[1] for details. + If `diff.orderFile` is a relative pathname, it is treated as + relative to the top of the working tree. diff.renameLimit:: The number of files to consider when performing the copy/rename @@ -172,10 +179,8 @@ diff.tool:: include::mergetools-diff.txt[] diff.indentHeuristic:: -diff.compactionHeuristic:: - Set one of these options to `true` to enable one of two - experimental heuristics that shift diff hunk boundaries to - make patches easier to read. + Set this option to `true` to enable experimental heuristics + that shift diff hunk boundaries to make patches easier to read. diff.algorithm:: Choose a diff algorithm. The variants are as follows: diff --git a/Documentation/diff-heuristic-options.txt b/Documentation/diff-heuristic-options.txt index 36cb549..d4f3d95 100644 --- a/Documentation/diff-heuristic-options.txt +++ b/Documentation/diff-heuristic-options.txt @@ -1,7 +1,5 @@ --indent-heuristic:: --no-indent-heuristic:: ---compaction-heuristic:: ---no-compaction-heuristic:: These are to help debugging and tuning experimental heuristics (which are off by default) that shift diff hunk boundaries to make patches easier to read. diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index e6215c3..d91ddbd 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -466,11 +466,41 @@ information. endif::git-format-patch[] -O:: - Output the patch in the order specified in the - , which has one shell glob pattern per line. + Control the order in which files appear in the output. This overrides the `diff.orderFile` configuration variable (see linkgit:git-config[1]). To cancel `diff.orderFile`, use `-O/dev/null`. ++ +The output order is determined by the order of glob patterns in +. +All files with pathnames that match the first pattern are output +first, all files with pathnames that match the second pattern (but not +the first) are output next, and so on. +All files with pathnames that do not match any pattern are output +last, as if there was an implicit match-all pattern at the end of the +file. +If multiple pathnames have the same rank (they match the same pattern +but no earlier patterns), their output order relative to each other is +the normal order. ++ + is parsed as follows: ++ +-- + - Blank lines are ignored, so they can be used as separators for + readability. + + - Lines starting with a hash ("`#`") are ignored, so they can be used + for comments. Add a backslash ("`\`") to the beginning of the + pattern if it starts with a hash. + + - Each other line contains a single pattern. +-- ++ +Patterns have the same syntax and semantics as patterns used for +fnmantch(3) without the FNM_PATHNAME flag, except a pathname also +matches a pattern if removing any number of the final pathname +components matches the pattern. For example, the pattern "`foo*bar`" +matches "`fooasdfbar`" and "`foo/bar/baz/asdf`" but not "`foobarx`". ifndef::git-format-patch[] -R:: @@ -511,6 +541,8 @@ endif::git-format-patch[] --inter-hunk-context=:: Show the context between diff hunks, up to the specified number of lines, thereby fusing hunks that are close to each other. + Defaults to `diff.interHunkContext` or 0 if the config option + is unset. -W:: --function-context:: diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 1fe7344..28d46cc 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -91,6 +91,9 @@ OPTIONS based sha1 expressions such as "@\{yesterday}". Note that in non-bare repositories, reflogs are usually enabled by default by the `core.logallrefupdates` config option. + The negated form `--no-create-reflog` only overrides an earlier + `--create-reflog`, but currently does not negate the setting of + `core.logallrefupdates`. -f:: --force:: @@ -118,6 +121,10 @@ OPTIONS default to color output. Same as `--color=never`. +-i:: +--ignore-case:: + Sorting and filtering branches are case insensitive. + --column[=]:: --no-column:: Display branch listing in columns. See configuration variable diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt index 8611a99..92777ce 100644 --- a/Documentation/git-check-ref-format.txt +++ b/Documentation/git-check-ref-format.txt @@ -100,10 +100,10 @@ OPTIONS --normalize:: Normalize 'refname' by removing any leading slash (`/`) characters and collapsing runs of adjacent slashes between - name components into a single slash. Iff the normalized + name components into a single slash. If the normalized refname is valid then print it to standard output and exit - with a status of 0. (`--print` is a deprecated way to spell - `--normalize`.) + with a status of 0, otherwise exit with a non-zero status. + (`--print` is a deprecated way to spell `--normalize`.) EXAMPLES diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt index 224fb30..96c26e6 100644 --- a/Documentation/git-difftool.txt +++ b/Documentation/git-difftool.txt @@ -86,10 +86,11 @@ instead. `--no-symlinks` is the default on Windows. Additionally, `$BASE` is set in the environment. -g:: ---gui:: +--[no-]gui:: When 'git-difftool' is invoked with the `-g` or `--gui` option the default diff tool will be read from the configured - `diff.guitool` variable instead of `diff.tool`. + `diff.guitool` variable instead of `diff.tool`. The `--no-gui` + option can be used to override this setting. --[no-]trust-exit-code:: 'git-difftool' invokes a diff tool individually on each file. diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index f57e69b..abe13f3 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -79,6 +79,9 @@ OPTIONS Only list refs which contain the specified commit (HEAD if not specified). +--ignore-case:: + Sorting and filtering refs are case insensitive. + FIELD NAMES ----------- @@ -165,6 +168,8 @@ of all lines of the commit message up to the first blank line. The next line is 'contents:body', where body is all of the lines after the first blank line. The optional GPG signature is `contents:signature`. The first `N` lines of the message is obtained using `contents:lines=N`. +Additionally, the trailers as interpreted by linkgit:git-interpret-trailers[1] +are obtained as 'contents:trailers'. For sorting purposes, fields with numeric values sort in numeric order (`objectsize`, `authordate`, `committerdate`, `creatordate`, `taggerdate`). diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt index 852b72c..571b5a7 100644 --- a/Documentation/git-gc.txt +++ b/Documentation/git-gc.txt @@ -127,7 +127,7 @@ the documentation for the --window' option in linkgit:git-repack[1] for more details. This defaults to 250. Similarly, the optional configuration variable `gc.aggressiveDepth` -controls --depth option in linkgit:git-repack[1]. This defaults to 250. +controls --depth option in linkgit:git-repack[1]. This defaults to 50. The optional configuration variable `gc.pruneExpire` controls how old the unreferenced loose objects have to be before they are pruned. The diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 0ecea6e..71f32f3 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -26,6 +26,7 @@ SYNOPSIS [--threads ] [-f ] [-e] [--and|--or|--not|(|)|-e ...] + [--recurse-submodules] [--parent-basename ] [ [--[no-]exclude-standard] [--cached | --no-index | --untracked] | ...] [--] [...] @@ -88,6 +89,19 @@ OPTIONS mechanism. Only useful when searching files in the current directory with `--no-index`. +--recurse-submodules:: + Recursively search in each submodule that has been initialized and + checked out in the repository. When used in combination with the + option the prefix of all submodule output will be the name of + the parent project's object. + +--parent-basename :: + For internal use only. In order to produce uniform output with the + --recurse-submodules option, this option can be used to provide the + basename of a parent's object to a submodule so the submodule + can prefix its output with the parent's name rather than the SHA1 of + the submodule. + -a:: --text:: Process binary files as if they were text. diff --git a/Documentation/git-gui.txt b/Documentation/git-gui.txt index c1a3e8b..5f93f80 100644 --- a/Documentation/git-gui.txt +++ b/Documentation/git-gui.txt @@ -35,7 +35,7 @@ blame:: browser:: Start a tree browser showing all files in the specified - commit (or `HEAD` by default). Files selected through the + commit. Files selected through the browser are opened in the blame viewer. citool:: diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt index 9d27197..3c5a67f 100644 --- a/Documentation/git-init.txt +++ b/Documentation/git-init.txt @@ -116,8 +116,8 @@ does not exist, it will be created. TEMPLATE DIRECTORY ------------------ -The template directory contains files and directories that will be copied to -the `$GIT_DIR` after it is created. +Files and directories in the template directory whose name do not start with a +dot will be copied to the `$GIT_DIR` after it is created. The template directory will be one of the following (in order): diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index b758d55..ca3c27b 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -15,6 +15,7 @@ SYNOPSIS [--[no-]rerere-autoupdate] [-m ] [...] 'git merge' HEAD ... 'git merge' --abort +'git merge' --continue DESCRIPTION ----------- @@ -61,6 +62,8 @@ reconstruct the original (pre-merge) changes. Therefore: discouraged: while possible, it may leave you in a state that is hard to back out of in the case of a conflict. +The fourth syntax ("`git merge --continue`") can only be run after the +merge has resulted in conflicts. OPTIONS ------- @@ -99,6 +102,11 @@ commit or stash your changes before running 'git merge'. 'git merge --abort' is equivalent to 'git reset --merge' when `MERGE_HEAD` is present. +--continue:: + After a 'git merge' stops due to conflicts you can conclude the + merge by running 'git merge --continue' (see "HOW TO RESOLVE + CONFLICTS" section below). + ...:: Commits, usually other branch heads, to merge into our branch. Specifying more than one commit will create a merge with diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt index c83aaf3..7436c64 100644 --- a/Documentation/git-p4.txt +++ b/Documentation/git-p4.txt @@ -303,6 +303,15 @@ These options can be used to modify 'git p4 submit' behavior. submit manually or revert. This option always stops after the first (oldest) commit. Git tags are not exported to p4. +--shelve:: + Instead of submitting create a series of shelved changelists. + After creating each shelve, the relevant files are reverted/deleted. + If you have multiple commits pending multiple shelves will be created. + +--update-shelve CHANGELIST:: + Update an existing shelved changelist with this commit. Implies + --shelve. + --conflict=(ask|skip|quit):: Conflicts can occur when applying a commit to p4. When this happens, the default behavior ("ask") is to prompt whether to @@ -467,6 +476,12 @@ git-p4.client:: Client specified as an option to all p4 commands, with '-c ', including the client spec. +git-p4.retries:: + Specifies the number of times to retry a p4 command (notably, + 'p4 sync') if the network times out. The default value is 3. + Set the value to 0 to disable retries or if your p4 version + does not support retries (pre 2012.2). + Clone and sync variables ~~~~~~~~~~~~~~~~~~~~~~~~ git-p4.syncFromOrigin:: diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index 8eefabd..1624a35 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -272,7 +272,7 @@ origin +master` to force a push to the `master` branch). See the standard error stream is not directed to a terminal. --no-recurse-submodules:: ---recurse-submodules=check|on-demand|no:: +--recurse-submodules=check|on-demand|only|no:: May be used to make sure all submodule commits used by the revisions to be pushed are available on a remote-tracking branch. If 'check' is used Git will verify that all submodule commits that @@ -280,11 +280,12 @@ origin +master` to force a push to the `master` branch). See the remote of the submodule. If any commits are missing the push will be aborted and exit with non-zero status. If 'on-demand' is used all submodules that changed in the revisions to be pushed will be - pushed. If on-demand was not able to push all necessary revisions - it will also be aborted and exit with non-zero status. A value of - 'no' or using `--no-recurse-submodules` can be used to override the - push.recurseSubmodules configuration variable when no submodule - recursion is required. + pushed. If on-demand was not able to push all necessary revisions it will + also be aborted and exit with non-zero status. If 'only' is used all + submodules will be recursively pushed while the superproject is left + unpushed. A value of 'no' or using `--no-recurse-submodules` can be used + to override the push.recurseSubmodules configuration variable when no + submodule recursion is required. --[no-]verify:: Toggle the pre-push hook (see linkgit:githooks[5]). The diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index de222c8..67d48e6 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -12,7 +12,7 @@ SYNOPSIS [ []] 'git rebase' [-i | --interactive] [options] [--exec ] [--onto ] --root [] -'git rebase' --continue | --skip | --abort | --edit-todo +'git rebase' --continue | --skip | --abort | --quit | --edit-todo DESCRIPTION ----------- @@ -252,6 +252,11 @@ leave out at most one of A and B, in which case it defaults to HEAD. will be reset to where it was when the rebase operation was started. +--quit:: + Abort the rebase operation but HEAD is not reset back to the + original branch. The index and working tree are also left + unchanged as a result. + --keep-empty:: Keep the commits that do not change anything from its parents in the result. diff --git a/Documentation/git-relink.txt b/Documentation/git-relink.txt deleted file mode 100644 index 3b33c99..0000000 --- a/Documentation/git-relink.txt +++ /dev/null @@ -1,30 +0,0 @@ -git-relink(1) -============= - -NAME ----- -git-relink - Hardlink common objects in local repositories - -SYNOPSIS --------- -[verse] -'git relink' [--safe] ... - -DESCRIPTION ------------ -This will scan 1 or more object repositories and look for objects in common -with a master repository. Objects not already hardlinked to the master -repository will be replaced with a hardlink to the master repository. - -OPTIONS -------- ---safe:: - Stops if two objects with the same hash exist but have different sizes. - Default is to warn and continue. - -:: - Directories containing a .git/objects/ subdirectory. - -GIT ---- -Part of the linkgit:git[1] suite diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt index 25432d9..8a21198 100644 --- a/Documentation/git-reset.txt +++ b/Documentation/git-reset.txt @@ -292,6 +292,54 @@ $ git reset --keep start <3> <3> But you can use "reset --keep" to remove the unwanted commit after you switched to "branch2". +Split a commit apart into a sequence of commits:: ++ +Suppose that you have created lots of logically separate changes and commited +them together. Then, later you decide that it might be better to have each +logical chunk associated with its own commit. You can use git reset to rewind +history without changing the contents of your local files, and then successively +use `git add -p` to interactively select which hunks to include into each commit, +using `git commit -c` to pre-populate the commit message. ++ +------------ +$ git reset -N HEAD^ <1> +$ git add -p <2> +$ git diff --cached <3> +$ git commit -c HEAD@{1} <4> +... <5> +$ git add ... <6> +$ git diff --cached <7> +$ git commit ... <8> +------------ ++ +<1> First, reset the history back one commit so that we remove the original + commit, but leave the working tree with all the changes. The -N ensures + that any new files added with HEAD are still marked so that git add -p + will find them. +<2> Next, we interactively select diff hunks to add using the git add -p + facility. This will ask you about each diff hunk in sequence and you can + use simple commands such as "yes, include this", "No don't include this" + or even the very powerful "edit" facility. +<3> Once satisfied with the hunks you want to include, you should verify what + has been prepared for the first commit by using git diff --cached. This + shows all the changes that have been moved into the index and are about + to be committed. +<4> Next, commit the changes stored in the index. The -c option specifies to + pre-populate the commit message from the original message that you started + with in the first commit. This is helpful to avoid retyping it. The HEAD@{1} + is a special notation for the commit that HEAD used to be at prior to the + original reset commit (1 change ago). See linkgit:git-reflog[1] for more + details. You may also use any other valid commit reference. +<5> You can repeat steps 2-4 multiple times to break the original code into + any number of commits. +<6> Now you've split out many of the changes into their own commits, and might + no longer use the patch mode of git add, in order to select all remaining + uncommitted changes. +<7> Once again, check to verify that you've included what you want to. You may + also wish to verify that git diff doesn't show any remaining changes to be + committed later. +<8> And finally create the final commit. + DISCUSSION ---------- diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index b6c6326..7241e96 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -91,7 +91,8 @@ repository. For example: ---- prefix=$(git rev-parse --show-prefix) cd "$(git rev-parse --show-toplevel)" -eval "set -- $(git rev-parse --sq --prefix "$prefix" "$@")" +# rev-parse provides the -- needed for 'set' +eval "set $(git rev-parse --sq --prefix "$prefix" -- "$@")" ---- --verify:: diff --git a/Documentation/git-shell.txt b/Documentation/git-shell.txt index 54cf256..2e30a3e 100644 --- a/Documentation/git-shell.txt +++ b/Documentation/git-shell.txt @@ -79,22 +79,6 @@ EOF $ chmod +x $HOME/git-shell-commands/no-interactive-login ---------------- -To enable git-cvsserver access (which should generally have the -`no-interactive-login` example above as a prerequisite, as creating -the git-shell-commands directory allows interactive logins): - ----------------- -$ cat >$HOME/git-shell-commands/cvs <<\EOF -if ! test $# = 1 && test "$1" = "server" -then - echo >&2 "git-cvsserver only handles \"server\"" - exit 1 -fi -exec git cvsserver server -EOF -$ chmod +x $HOME/git-shell-commands/cvs ----------------- - SEE ALSO -------- ssh(1), diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt index 31af7f2..ee6c547 100644 --- a/Documentation/git-shortlog.txt +++ b/Documentation/git-shortlog.txt @@ -47,6 +47,10 @@ OPTIONS Each pretty-printed commit will be rewrapped before it is shown. +-c:: +--committer:: + Collect and show committer identities instead of authors. + -w[[,[,]]]:: Linewrap the output by wrapping each line at `width`. The first line of each entry is indented by `indent1` spaces, and the second diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt index 2e9cef0..2e9e344 100644 --- a/Documentation/git-stash.txt +++ b/Documentation/git-stash.txt @@ -47,8 +47,9 @@ OPTIONS save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] []:: - Save your local modifications to a new 'stash', and run `git reset - --hard` to revert them. The part is optional and gives + Save your local modifications to a new 'stash' and roll them + back to HEAD (in the working tree and in the index). + The part is optional and gives the description along with the stashed state. For quickly making a snapshot, you can omit _both_ "save" and , but giving only does not trigger this action to prevent a misspelled diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index d841573..8acc72e 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -9,19 +9,15 @@ git-submodule - Initialize, update or inspect submodules SYNOPSIS -------- [verse] -'git submodule' [--quiet] add [-b ] [-f|--force] [--name ] - [--reference ] [--depth ] [--] [] +'git submodule' [--quiet] add [] [--] [] 'git submodule' [--quiet] status [--cached] [--recursive] [--] [...] 'git submodule' [--quiet] init [--] [...] 'git submodule' [--quiet] deinit [-f|--force] (--all|[--] ...) -'git submodule' [--quiet] update [--init] [--remote] [-N|--no-fetch] - [--[no-]recommend-shallow] [-f|--force] [--rebase|--merge] - [--reference ] [--depth ] [--recursive] - [--jobs ] [--] [...] -'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) ] - [commit] [--] [...] +'git submodule' [--quiet] update [] [--] [...] +'git submodule' [--quiet] summary [] [--] [...] 'git submodule' [--quiet] foreach [--recursive] 'git submodule' [--quiet] sync [--recursive] [--] [...] +'git submodule' [--quiet] absorbgitdirs [--] [...] DESCRIPTION @@ -62,7 +58,7 @@ if you choose to go that route. COMMANDS -------- -add:: +add [-b ] [-f|--force] [--name ] [--reference ] [--depth ] [--] []:: Add the given repository as a submodule at the given path to the changeset to be committed next to the current project: the current project is termed the "superproject". @@ -103,7 +99,7 @@ together in the same relative location, and only the superproject's URL needs to be provided: git-submodule will correctly locate the submodule using the relative URL in .gitmodules. -status:: +status [--cached] [--recursive] [--] [...]:: Show the status of the submodules. This will print the SHA-1 of the currently checked out commit for each submodule, along with the submodule path and the output of 'git describe' for the @@ -120,7 +116,7 @@ submodules with respect to the commit recorded in the index or the HEAD, linkgit:git-status[1] and linkgit:git-diff[1] will provide that information too (and can also report changes to a submodule's work tree). -init:: +init [--] [...]:: Initialize the submodules recorded in the index (which were added and committed elsewhere) by copying submodule names and urls from .gitmodules to .git/config. @@ -135,7 +131,7 @@ init:: the explicit 'init' step if you do not intend to customize any submodule locations. -deinit:: +deinit [-f|--force] (--all|[--] ...):: Unregister the given submodules, i.e. remove the whole `submodule.$name` section from .git/config together with their work tree. Further calls to `git submodule update`, `git submodule foreach` @@ -151,20 +147,20 @@ instead of deinit-ing everything, to prevent mistakes. If `--force` is specified, the submodule's working tree will be removed even if it contains local modifications. -update:: +update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference ] [--depth ] [--recursive] [--jobs ] [--] [...]:: + -- Update the registered submodules to match what the superproject expects by cloning missing submodules and updating the working tree of the submodules. The "updating" can be done in several ways depending on command line options and the value of `submodule..update` -configuration variable. Supported update procedures are: +configuration variable. The command line option takes precedence over +the configuration variable. if neither is given, a checkout is performed. +update procedures supported both from the command line as well as setting +`submodule..update`: checkout;; the commit recorded in the superproject will be - checked out in the submodule on a detached HEAD. This is - done when `--checkout` option is given, or no option is - given, and `submodule..update` is unset, or if it is - set to 'checkout'. + checked out in the submodule on a detached HEAD. + If `--force` is specified, the submodule will be checked out (using `git checkout --force` if appropriate), even if the commit specified @@ -172,23 +168,21 @@ in the index of the containing repository already matches the commit checked out in the submodule. rebase;; the current branch of the submodule will be rebased - onto the commit recorded in the superproject. This is done - when `--rebase` option is given, or no option is given, and - `submodule..update` is set to 'rebase'. + onto the commit recorded in the superproject. merge;; the commit recorded in the superproject will be merged - into the current branch in the submodule. This is done - when `--merge` option is given, or no option is given, and - `submodule..update` is set to 'merge'. + into the current branch in the submodule. + +The following procedures are only available via the `submodule..update` +configuration variable: custom command;; arbitrary shell command that takes a single argument (the sha1 of the commit recorded in the - superproject) is executed. This is done when no option is - given, and `submodule..update` has the form of - '!command'. + superproject) is executed. When `submodule..update` + is set to '!command', the remainder after the exclamation mark + is the custom command. -When no option is given and `submodule..update` is set to 'none', -the submodule is not updated. + none;; the submodule is not updated. If the submodule is not yet initialized, and you just want to use the setting as stored in .gitmodules, you can automatically initialize the @@ -197,7 +191,7 @@ submodule with the `--init` option. If `--recursive` is specified, this command will recurse into the registered submodules, and update any nested submodules within. -- -summary:: +summary [--cached|--files] [(-n|--summary-limit) ] [commit] [--] [...]:: Show commit summary between the given commit (defaults to HEAD) and working tree/index. For a submodule in question, a series of commits in the submodule between the given super project commit and the @@ -210,7 +204,7 @@ summary:: Using the `--submodule=log` option with linkgit:git-diff[1] will provide that information too. -foreach:: +foreach [--recursive] :: Evaluates an arbitrary shell command in each checked out submodule. The command has access to the variables $name, $path, $sha1 and $toplevel: @@ -227,11 +221,14 @@ foreach:: the processing to terminate. This can be overridden by adding '|| :' to the end of the command. + -As an example, +git submodule foreach \'echo $path {backtick}git -rev-parse HEAD{backtick}'+ will show the path and currently checked out -commit for each submodule. +As an example, the command below will show the path and currently +checked out commit for each submodule: ++ +-------------- +git submodule foreach 'echo $path `git rev-parse HEAD`' +-------------- -sync:: +sync [--recursive] [--] [...]:: Synchronizes submodules' remote URL configuration setting to the value specified in .gitmodules. It will only affect those submodules which already have a URL entry in .git/config (that is the @@ -245,6 +242,20 @@ sync:: If `--recursive` is specified, this command will recurse into the registered submodules, and sync any nested submodules within. +absorbgitdirs:: + If a git directory of a submodule is inside the submodule, + move the git directory of the submodule into its superprojects + `$GIT_DIR/modules` path and then connect the git directory and + its working directory by setting the `core.worktree` and adding + a .git file pointing to the git directory embedded in the + superprojects git directory. ++ +A repository that was cloned independently and later added as a submodule or +old setups have the submodules git directory inside the submodule instead of +embedded into the superprojects git directory. ++ +This command is recursive by default. + OPTIONS ------- -q:: diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 80019c5..525737a 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -15,7 +15,7 @@ SYNOPSIS 'git tag' [-n[]] -l [--contains ] [--points-at ] [--column[=] | --no-column] [--create-reflog] [--sort=] [--format=] [--[no-]merged []] [...] -'git tag' -v ... +'git tag' -v [--format=] ... DESCRIPTION ----------- @@ -101,13 +101,17 @@ OPTIONS multiple times, in which case the last key becomes the primary key. Also supports "version:refname" or "v:refname" (tag names are treated as versions). The "version:refname" sort - order can also be affected by the - "versionsort.prereleaseSuffix" configuration variable. + order can also be affected by the "versionsort.suffix" + configuration variable. The keys supported are the same as those in `git for-each-ref`. Sort order defaults to the value configured for the `tag.sort` variable if it exists, or lexicographic order otherwise. See linkgit:git-config[1]. +-i:: +--ignore-case:: + Sorting and filtering tags are case insensitive. + --column[=]:: --no-column:: Display tag listing in columns. See configuration variable @@ -146,7 +150,11 @@ This option is only applicable when listing tags without annotation lines. 'strip' removes both whitespace and commentary. --create-reflog:: - Create a reflog for the tag. + Create a reflog for the tag. To globally enable reflogs for tags, see + `core.logAllRefUpdates` in linkgit:git-config[1]. + The negated form `--no-create-reflog` only overrides an earlier + `--create-reflog`, but currently does not negate the setting of + `core.logallrefupdates`. :: The name of the tag to create, delete, or describe. diff --git a/Documentation/git-verify-tag.txt b/Documentation/git-verify-tag.txt index d590edc..0b8075d 100644 --- a/Documentation/git-verify-tag.txt +++ b/Documentation/git-verify-tag.txt @@ -8,7 +8,7 @@ git-verify-tag - Check the GPG signature of tags SYNOPSIS -------- [verse] -'git verify-tag' ... +'git verify-tag' [--format=] ... DESCRIPTION ----------- diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index e257c19..553cf84 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -52,7 +52,7 @@ is linked to the current repository, sharing everything except working directory specific files such as HEAD, index, etc. `-` may also be specified as ``; it is synonymous with `@{-1}`. + -If `` is omitted and neither `-b` nor `-B` nor `--detached` used, +If `` is omitted and neither `-b` nor `-B` nor `--detach` used, then, as a convenience, a new branch based at HEAD is created automatically, as if `-b $(basename )` was specified. diff --git a/Documentation/git.txt b/Documentation/git.txt index cc21536..aa895da 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -44,54 +44,52 @@ unreleased) version of Git, that is available from the 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v2.11.2/git.html[documentation for release 2.11.2] +* link:v2.12.0/git.html[documentation for release 2.12.0] + +* release notes for + link:RelNotes/2.12.0.txt[2.12]. + +* link:v2.11.1/git.html[documentation for release 2.11.1] * release notes for - link:RelNotes/2.11.2.txt[2.11.2], link:RelNotes/2.11.1.txt[2.11.1], link:RelNotes/2.11.0.txt[2.11]. -* link:v2.10.3/git.html[documentation for release 2.10.3] +* link:v2.10.2/git.html[documentation for release 2.10.2] * release notes for - link:RelNotes/2.10.3.txt[2.10.3], link:RelNotes/2.10.2.txt[2.10.2], link:RelNotes/2.10.1.txt[2.10.1], link:RelNotes/2.10.0.txt[2.10]. -* link:v2.9.4/git.html[documentation for release 2.9.4] +* link:v2.9.3/git.html[documentation for release 2.9.3] * release notes for - link:RelNotes/2.9.4.txt[2.9.4], link:RelNotes/2.9.3.txt[2.9.3], link:RelNotes/2.9.2.txt[2.9.2], link:RelNotes/2.9.1.txt[2.9.1], link:RelNotes/2.9.0.txt[2.9]. -* link:v2.8.5/git.html[documentation for release 2.8.5] +* link:v2.8.4/git.html[documentation for release 2.8.4] * release notes for - link:RelNotes/2.8.5.txt[2.8.5], link:RelNotes/2.8.4.txt[2.8.4], link:RelNotes/2.8.3.txt[2.8.3], link:RelNotes/2.8.2.txt[2.8.2], link:RelNotes/2.8.1.txt[2.8.1], link:RelNotes/2.8.0.txt[2.8]. -* link:v2.7.5/git.html[documentation for release 2.7.5] +* link:v2.7.3/git.html[documentation for release 2.7.3] * release notes for - link:RelNotes/2.7.5.txt[2.7.5], - link:RelNotes/2.7.4.txt[2.7.4], link:RelNotes/2.7.3.txt[2.7.3], link:RelNotes/2.7.2.txt[2.7.2], link:RelNotes/2.7.1.txt[2.7.1], link:RelNotes/2.7.0.txt[2.7]. -* link:v2.6.7/git.html[documentation for release 2.6.7] +* link:v2.6.6/git.html[documentation for release 2.6.6] * release notes for - link:RelNotes/2.6.7.txt[2.6.7], link:RelNotes/2.6.6.txt[2.6.6], link:RelNotes/2.6.5.txt[2.6.5], link:RelNotes/2.6.4.txt[2.6.4], @@ -100,10 +98,9 @@ Documentation for older releases are available here: link:RelNotes/2.6.1.txt[2.6.1], link:RelNotes/2.6.0.txt[2.6]. -* link:v2.5.6/git.html[documentation for release 2.5.6] +* link:v2.5.5/git.html[documentation for release 2.5.5] * release notes for - link:RelNotes/2.5.6.txt[2.5.6], link:RelNotes/2.5.5.txt[2.5.5], link:RelNotes/2.5.4.txt[2.5.4], link:RelNotes/2.5.3.txt[2.5.3], @@ -111,10 +108,9 @@ Documentation for older releases are available here: link:RelNotes/2.5.1.txt[2.5.1], link:RelNotes/2.5.0.txt[2.5]. -* link:v2.4.12/git.html[documentation for release 2.4.12] +* link:v2.4.11/git.html[documentation for release 2.4.11] * release notes for - link:RelNotes/2.4.12.txt[2.4.12], link:RelNotes/2.4.11.txt[2.4.11], link:RelNotes/2.4.10.txt[2.4.10], link:RelNotes/2.4.9.txt[2.4.9], @@ -1171,30 +1167,20 @@ of clones and fetches. cloning a repository to make a backup). `GIT_ALLOW_PROTOCOL`:: - If set, provide a colon-separated list of protocols which are - allowed to be used with fetch/push/clone. This is useful to - restrict recursive submodule initialization from an untrusted - repository. Any protocol not mentioned will be disallowed (i.e., - this is a whitelist, not a blacklist). If the variable is not - set at all, all protocols are enabled. The protocol names - currently used by git are: - - - `file`: any local file-based path (including `file://` URLs, - or local paths) - - - `git`: the anonymous git protocol over a direct TCP - connection (or proxy, if configured) - - - `ssh`: git over ssh (including `host:path` syntax, - `ssh://`, etc). - - - `http`: git over http, both "smart http" and "dumb http". - Note that this does _not_ include `https`; if you want both, - you should specify both as `http:https`. - - - any external helpers are named by their protocol (e.g., use - `hg` to allow the `git-remote-hg` helper) - + If set to a colon-separated list of protocols, behave as if + `protocol.allow` is set to `never`, and each of the listed + protocols has `protocol..allow` set to `always` + (overriding any existing configuration). In other words, any + protocol not mentioned will be disallowed (i.e., this is a + whitelist, not a blacklist). See the description of + `protocol.allow` in linkgit:git-config[1] for more details. + +`GIT_PROTOCOL_FROM_USER`:: + Set to 0 to prevent protocols used by fetch/push/clone which are + configured to the `user` state. This is useful to restrict recursive + submodule initialization from an untrusted repository or for programs + which feed potentially-untrusted URLS to git commands. See + linkgit:git-config[1] for more details. Discussion[[Discussion]] ------------------------ diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt index 22309cf..3a0ec8c 100644 --- a/Documentation/gitcore-tutorial.txt +++ b/Documentation/gitcore-tutorial.txt @@ -1658,4 +1658,4 @@ link:user-manual.html[The Git User's Manual] GIT --- -Part of the linkgit:git[1] suite. +Part of the linkgit:git[1] suite diff --git a/Documentation/gitcvs-migration.txt b/Documentation/gitcvs-migration.txt index 4c6143c..1cd1283 100644 --- a/Documentation/gitcvs-migration.txt +++ b/Documentation/gitcvs-migration.txt @@ -203,4 +203,4 @@ link:user-manual.html[The Git User's Manual] GIT --- -Part of the linkgit:git[1] suite. +Part of the linkgit:git[1] suite diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt index 08cf622..46bc6d0 100644 --- a/Documentation/gitdiffcore.txt +++ b/Documentation/gitdiffcore.txt @@ -288,4 +288,4 @@ link:user-manual.html[The Git User's Manual] GIT --- -Part of the linkgit:git[1] suite. +Part of the linkgit:git[1] suite diff --git a/Documentation/giteveryday.txt b/Documentation/giteveryday.txt index 35473ad..10c8ff9 100644 --- a/Documentation/giteveryday.txt +++ b/Documentation/giteveryday.txt @@ -307,9 +307,16 @@ master or exposed as a part of a stable branch. <9> backport a critical fix. <10> create a signed tag. <11> make sure master was not accidentally rewound beyond that -already pushed out. `ko` shorthand points at the Git maintainer's +already pushed out. +<12> In the output from `git show-branch`, `master` should have +everything `ko/master` has, and `next` should have +everything `ko/next` has, etc. +<13> push out the bleeding edge, together with new tags that point +into the pushed history. + +In this example, the `ko` shorthand points at the Git maintainer's repository at kernel.org, and looks like this: -+ + ------------ (in .git/config) [remote "ko"] @@ -320,12 +327,6 @@ repository at kernel.org, and looks like this: push = +refs/heads/pu push = refs/heads/maint ------------ -+ -<12> In the output from `git show-branch`, `master` should have -everything `ko/master` has, and `next` should have -everything `ko/next` has, etc. -<13> push out the bleeding edge, together with new tags that point -into the pushed history. Repository Administration[[ADMINISTRATION]] diff --git a/Documentation/gitglossary.txt b/Documentation/gitglossary.txt index 212e254..571f640 100644 --- a/Documentation/gitglossary.txt +++ b/Documentation/gitglossary.txt @@ -24,4 +24,4 @@ link:user-manual.html[The Git User's Manual] GIT --- -Part of the linkgit:git[1] suite. +Part of the linkgit:git[1] suite diff --git a/Documentation/gitk.txt b/Documentation/gitk.txt index e382dd9..ca96c28 100644 --- a/Documentation/gitk.txt +++ b/Documentation/gitk.txt @@ -178,19 +178,21 @@ used by default. If '$XDG_CONFIG_HOME' is not set it defaults to History ------- Gitk was the first graphical repository browser. It's written in -tcl/tk and started off in a separate repository but was later merged -into the main Git repository. +tcl/tk. +'gitk' is actually maintained as an independent project, but stable +versions are distributed as part of the Git suite for the convenience +of end users. + +gitk-git/ comes from Paul Mackerras's gitk project: + + git://ozlabs.org/~paulus/gitk SEE ALSO -------- 'qgit(1)':: A repository browser written in C++ using Qt. -'gitview(1)':: - A repository browser written in Python using Gtk. It's based on - 'bzrk(1)' and distributed in the contrib area of the Git repository. - 'tig(1)':: A minimal repository browser and Git tool output highlighter written in C using Ncurses. diff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt index 9e8681f..e4b785e 100644 --- a/Documentation/gitremote-helpers.txt +++ b/Documentation/gitremote-helpers.txt @@ -452,16 +452,20 @@ set by Git if the remote helper has the 'option' capability. Request the helper to perform a force update. Defaults to 'false'. -'option cloning {'true'|'false'}:: +'option cloning' {'true'|'false'}:: Notify the helper this is a clone request (i.e. the current repository is guaranteed empty). -'option update-shallow {'true'|'false'}:: +'option update-shallow' {'true'|'false'}:: Allow to extend .git/shallow if the new refs require it. -'option pushcert {'true'|'false'}:: +'option pushcert' {'true'|'false'}:: GPG sign pushes. +'option push-option :: + Transmit as a push option. As the a push option + must not contain LF or NUL characters, the string is not encoded. + SEE ALSO -------- linkgit:git-remote[1] diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt index a5f99cb..f51ed4e 100644 --- a/Documentation/gitrepository-layout.txt +++ b/Documentation/gitrepository-layout.txt @@ -289,4 +289,4 @@ link:user-manual.html[The Git User's Manual] GIT --- -Part of the linkgit:git[1] suite. +Part of the linkgit:git[1] suite diff --git a/Documentation/gittutorial-2.txt b/Documentation/gittutorial-2.txt index 30d2119..e0976f6 100644 --- a/Documentation/gittutorial-2.txt +++ b/Documentation/gittutorial-2.txt @@ -433,4 +433,4 @@ link:user-manual.html[The Git User's Manual] GIT --- -Part of the linkgit:git[1] suite. +Part of the linkgit:git[1] suite diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt index b3b58d3..794b833 100644 --- a/Documentation/gittutorial.txt +++ b/Documentation/gittutorial.txt @@ -674,4 +674,4 @@ link:user-manual.html[The Git User's Manual] GIT --- -Part of the linkgit:git[1] suite. +Part of the linkgit:git[1] suite diff --git a/Documentation/gitworkflows.txt b/Documentation/gitworkflows.txt index f16c414..177610e 100644 --- a/Documentation/gitworkflows.txt +++ b/Documentation/gitworkflows.txt @@ -477,4 +477,4 @@ linkgit:git-am[1] GIT --- -Part of the linkgit:git[1] suite. +Part of the linkgit:git[1] suite diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index 3bcee2d..47b286b 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -199,6 +199,8 @@ endif::git-rev-list[] than given and there are spaces on its left, use those spaces - '%><()', '%><|()': similar to '% <()', '%<|()' respectively, but padding both sides (i.e. the text is centered) +-%(trailers): display the trailers of the body as interpreted by + linkgit:git-interpret-trailers[1] NOTE: Some placeholders may depend on other options given to the revision traversal engine. For example, the `%g*` reflog options will diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 5da7cf5..a02f732 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -133,8 +133,8 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit). for all following revision specifiers, up to the next `--not`. --all:: - Pretend as if all the refs in `refs/` are listed on the - command line as ''. + Pretend as if all the refs in `refs/`, along with `HEAD`, are + listed on the command line as ''. --branches[=]:: Pretend as if all the refs in `refs/heads` are listed diff --git a/Documentation/technical/api-hashmap.txt b/Documentation/technical/api-hashmap.txt index 28f5a8b..a3f020c 100644 --- a/Documentation/technical/api-hashmap.txt +++ b/Documentation/technical/api-hashmap.txt @@ -188,7 +188,9 @@ Returns the removed entry, or NULL if not found. `void *hashmap_iter_next(struct hashmap_iter *iter)`:: `void *hashmap_iter_first(struct hashmap *map, struct hashmap_iter *iter)`:: - Used to iterate over all entries of a hashmap. + Used to iterate over all entries of a hashmap. Note that it is + not safe to add or remove entries to the hashmap while + iterating. + `hashmap_iter_init` initializes a `hashmap_iter` structure. + diff --git a/Documentation/technical/api-setup.txt b/Documentation/technical/api-setup.txt index 540e455..eb1fa98 100644 --- a/Documentation/technical/api-setup.txt +++ b/Documentation/technical/api-setup.txt @@ -27,8 +27,6 @@ parse_pathspec(). This function takes several arguments: - prefix and args come from cmd_* functions -get_pathspec() is obsolete and should never be used in new code. - parse_pathspec() helps catch unsupported features and reject them politely. At a lower level, different pathspec-related functions may not support the same set of features. Such pathspec-sensitive diff --git a/Documentation/technical/api-submodule-config.txt b/Documentation/technical/api-submodule-config.txt index 941fa17..3dce003 100644 --- a/Documentation/technical/api-submodule-config.txt +++ b/Documentation/technical/api-submodule-config.txt @@ -47,16 +47,20 @@ Functions Can be passed to the config parsing infrastructure to parse local (worktree) submodule configurations. -`const struct submodule *submodule_from_path(const unsigned char *commit_sha1, const char *path)`:: +`const struct submodule *submodule_from_path(const unsigned char *treeish_name, const char *path)`:: - Lookup values for one submodule by its commit_sha1 and path. + Given a tree-ish in the superproject and a path, return the + submodule that is bound at the path in the named tree. -`const struct submodule *submodule_from_name(const unsigned char *commit_sha1, const char *name)`:: +`const struct submodule *submodule_from_name(const unsigned char *treeish_name, const char *name)`:: The same as above but lookup by name. -If given the null_sha1 as commit_sha1 the local configuration of a -submodule will be returned (e.g. consolidated values from local git +Whenever a submodule configuration is parsed in `parse_submodule_config_option` +via e.g. `gitmodules_config()`, it will overwrite the null_sha1 entry. +So in the normal case, when HEAD:.gitmodules is parsed first and then overlayed +with the repository configuration, the null_sha1 entry contains the local +configuration of a submodule (e.g. consolidated values from local git configuration and the .gitmodules file in the worktree). For an example usage see test-submodule-config.c. diff --git a/Documentation/texi.xsl b/Documentation/texi.xsl new file mode 100644 index 0000000..0f8ff07 --- /dev/null +++ b/Documentation/texi.xsl @@ -0,0 +1,26 @@ + + + + + + + refsect + + + + + + + + + + + + + diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index 5e07454..bc29298 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -4395,6 +4395,10 @@ itself! Git Glossary ============ +[[git-explained]] +Git explained +------------- + include::glossary-content.txt[] [[git-quick-start]] @@ -4636,6 +4640,10 @@ $ git gc Appendix B: Notes and todo list for this manual =============================================== +[[todo-list]] +Todo list +--------- + This is a work in progress. The basic requirements: diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 845d214..6a208e9 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.11.4 +DEF_VER=v2.12.0 LF=' ' @@ -12,7 +12,7 @@ if test -f version then VN=$(cat version) || VN="$DEF_VER" elif test -d ${GIT_DIR:-.git} -o -f .git && - VN=$(git describe --match "v[0-9]*" --abbrev=7 HEAD 2>/dev/null) && + VN=$(git describe --match "v[0-9]*" HEAD 2>/dev/null) && case "$VN" in *$LF*) (exit 1) ;; v[0-9]*) diff --git a/Makefile b/Makefile index 7626726..8e4081e 100644 --- a/Makefile +++ b/Makefile @@ -250,6 +250,12 @@ all:: # apostrophes to be ASCII so that cut&pasting examples to the shell # will work. # +# Define USE_ASCIIDOCTOR to use Asciidoctor instead of AsciiDoc to build the +# documentation. +# +# Define ASCIIDOCTOR_EXTENSIONS_LAB to point to the location of the Asciidoctor +# Extensions Lab if you have it available. +# # Define PERL_PATH to the path of your Perl binary (usually /usr/bin/perl). # # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's @@ -279,6 +285,9 @@ all:: # is a simplified version of the merge sort used in glibc. This is # recommended if Git triggers O(n^2) behavior in your platform's qsort(). # +# Define HAVE_ISO_QSORT_S if your platform provides a qsort_s() that's +# compatible with the one described in C11 Annex K. +# # 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. @@ -338,11 +347,6 @@ all:: # # Define NATIVE_CRLF if your platform uses CRLF for line endings. # -# Define XDL_FAST_HASH to use an alternative line-hashing method in -# the diff algorithm. It gives a nice speedup if your processor has -# fast unaligned word loads. Does NOT work on big-endian systems! -# Enabled by default on x86_64. -# # Define GIT_USER_AGENT if you want to change how git identifies itself during # network interactions. The default is "git/$(GIT_VERSION)". # @@ -527,12 +531,10 @@ SCRIPT_LIB += git-sh-setup SCRIPT_LIB += git-sh-i18n SCRIPT_PERL += git-add--interactive.perl -SCRIPT_PERL += git-difftool.perl SCRIPT_PERL += git-archimport.perl SCRIPT_PERL += git-cvsexportcommit.perl SCRIPT_PERL += git-cvsimport.perl SCRIPT_PERL += git-cvsserver.perl -SCRIPT_PERL += git-relink.perl SCRIPT_PERL += git-send-email.perl SCRIPT_PERL += git-svn.perl @@ -888,6 +890,7 @@ BUILTIN_OBJS += builtin/diff-files.o BUILTIN_OBJS += builtin/diff-index.o BUILTIN_OBJS += builtin/diff-tree.o BUILTIN_OBJS += builtin/diff.o +BUILTIN_OBJS += builtin/difftool.o BUILTIN_OBJS += builtin/fast-export.o BUILTIN_OBJS += builtin/fetch-pack.o BUILTIN_OBJS += builtin/fetch.o @@ -1423,6 +1426,11 @@ ifdef INTERNAL_QSORT COMPAT_CFLAGS += -DINTERNAL_QSORT COMPAT_OBJS += compat/qsort.o endif +ifdef HAVE_ISO_QSORT_S + COMPAT_CFLAGS += -DHAVE_ISO_QSORT_S +else + COMPAT_OBJS += compat/qsort_s.o +endif ifdef RUNTIME_PREFIX COMPAT_CFLAGS += -DRUNTIME_PREFIX endif @@ -1485,10 +1493,6 @@ ifndef NO_MSGFMT_EXTENDED_OPTIONS MSGFMT += --check --statistics endif -ifneq (,$(XDL_FAST_HASH)) - BASIC_CFLAGS += -DXDL_FAST_HASH -endif - ifdef GMTIME_UNRELIABLE_ERRORS COMPAT_OBJS += compat/gmtime.o BASIC_CFLAGS += -DGMTIME_UNRELIABLE_ERRORS @@ -1825,7 +1829,7 @@ $(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES git.res: git.rc GIT-VERSION-FILE $(QUIET_RC)$(RC) \ $(join -DMAJOR= -DMINOR=, $(wordlist 1,2,$(subst -, ,$(subst ., ,$(GIT_VERSION))))) \ - -DGIT_VERSION="\\\"$(GIT_VERSION)\\\"" $< -o $@ + -DGIT_VERSION="\\\"$(GIT_VERSION)\\\"" -i $< -o $@ # This makes sure we depend on the NO_PERL setting itself. $(SCRIPT_PERL_GEN): GIT-BUILD-OPTIONS @@ -2055,7 +2059,7 @@ git-%$X: %.o GIT-LDFLAGS $(GITLIBS) git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ - $(LIBS) $(IMAP_SEND_LDFLAGS) + $(IMAP_SEND_LDFLAGS) $(LIBS) git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ @@ -2114,7 +2118,8 @@ XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \ --keyword=_ --keyword=N_ --keyword="Q_:1,2" XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \ --keyword=gettextln --keyword=eval_gettextln -XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl +XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \ + --keyword=__ --keyword=N__ --keyword="__n:1,2" LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H) LOCALIZED_SH = $(SCRIPT_SH) LOCALIZED_SH += git-parse-remote.sh diff --git a/RelNotes b/RelNotes index 1f96450..d09c3d5 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes/2.11.4.txt \ No newline at end of file +Documentation/RelNotes/2.12.0.txt \ No newline at end of file diff --git a/abspath.c b/abspath.c index 2825de8..2f0c26e 100644 --- a/abspath.c +++ b/abspath.c @@ -11,46 +11,83 @@ int is_directory(const char *path) return (!stat(path, &st) && S_ISDIR(st.st_mode)); } +/* removes the last path component from 'path' except if 'path' is root */ +static void strip_last_component(struct strbuf *path) +{ + size_t offset = offset_1st_component(path->buf); + size_t len = path->len; + + /* Find start of the last component */ + while (offset < len && !is_dir_sep(path->buf[len - 1])) + len--; + /* Skip sequences of multiple path-separators */ + while (offset < len && is_dir_sep(path->buf[len - 1])) + len--; + + strbuf_setlen(path, len); +} + +/* get (and remove) the next component in 'remaining' and place it in 'next' */ +static void get_next_component(struct strbuf *next, struct strbuf *remaining) +{ + char *start = NULL; + char *end = NULL; + + strbuf_reset(next); + + /* look for the next component */ + /* Skip sequences of multiple path-separators */ + for (start = remaining->buf; is_dir_sep(*start); start++) + ; /* nothing */ + /* Find end of the path component */ + for (end = start; *end && !is_dir_sep(*end); end++) + ; /* nothing */ + + strbuf_add(next, start, end - start); + /* remove the component from 'remaining' */ + strbuf_remove(remaining, 0, end - remaining->buf); +} + +/* copies root part from remaining to resolved, canonicalizing it on the way */ +static void get_root_part(struct strbuf *resolved, struct strbuf *remaining) +{ + int offset = offset_1st_component(remaining->buf); + + strbuf_reset(resolved); + strbuf_add(resolved, remaining->buf, offset); +#ifdef GIT_WINDOWS_NATIVE + convert_slashes(resolved->buf); +#endif + strbuf_remove(remaining, 0, offset); +} + /* We allow "recursive" symbolic links. Only within reason, though. */ -#define MAXDEPTH 5 +#ifndef MAXSYMLINKS +#define MAXSYMLINKS 32 +#endif /* * Return the real path (i.e., absolute path, with symlinks resolved * and extra slashes removed) equivalent to the specified path. (If * you want an absolute path but don't mind links, use - * absolute_path().) The return value is a pointer to a static - * buffer. + * absolute_path().) Places the resolved realpath in the provided strbuf. * - * The input and all intermediate paths must be shorter than MAX_PATH. * The directory part of path (i.e., everything up to the last * dir_sep) must denote a valid, existing directory, but the last * component need not exist. If die_on_error is set, then die with an * informative error message if there is a problem. Otherwise, return * NULL on errors (without generating any output). - * - * If path is our buffer, then return path, as it's already what the - * user wants. */ -static const char *real_path_internal(const char *path, int die_on_error) +char *strbuf_realpath(struct strbuf *resolved, const char *path, + int die_on_error) { - static struct strbuf sb = STRBUF_INIT; + struct strbuf remaining = STRBUF_INIT; + struct strbuf next = STRBUF_INIT; + struct strbuf symlink = STRBUF_INIT; char *retval = NULL; - - /* - * If we have to temporarily chdir(), store the original CWD - * here so that we can chdir() back to it at the end of the - * function: - */ - struct strbuf cwd = STRBUF_INIT; - - int depth = MAXDEPTH; - char *last_elem = NULL; + int num_symlinks = 0; struct stat st; - /* We've already done it */ - if (path == sb.buf) - return path; - if (!*path) { if (die_on_error) die("The empty string is not a valid path"); @@ -58,86 +95,136 @@ static const char *real_path_internal(const char *path, int die_on_error) goto error_out; } - strbuf_reset(&sb); - strbuf_addstr(&sb, path); - - while (depth--) { - if (!is_directory(sb.buf)) { - char *last_slash = find_last_dir_sep(sb.buf); - if (last_slash) { - last_elem = xstrdup(last_slash + 1); - strbuf_setlen(&sb, last_slash - sb.buf + 1); - } else { - last_elem = xmemdupz(sb.buf, sb.len); - strbuf_reset(&sb); - } + strbuf_addstr(&remaining, path); + get_root_part(resolved, &remaining); + + if (!resolved->len) { + /* relative path; can use CWD as the initial resolved path */ + if (strbuf_getcwd(resolved)) { + if (die_on_error) + die_errno("unable to get current working directory"); + else + goto error_out; } + } - if (sb.len) { - if (!cwd.len && strbuf_getcwd(&cwd)) { + /* Iterate over the remaining path components */ + while (remaining.len > 0) { + get_next_component(&next, &remaining); + + if (next.len == 0) { + continue; /* empty component */ + } else if (next.len == 1 && !strcmp(next.buf, ".")) { + continue; /* '.' component */ + } else if (next.len == 2 && !strcmp(next.buf, "..")) { + /* '..' component; strip the last path component */ + strip_last_component(resolved); + continue; + } + + /* append the next component and resolve resultant path */ + if (!is_dir_sep(resolved->buf[resolved->len - 1])) + strbuf_addch(resolved, '/'); + strbuf_addbuf(resolved, &next); + + if (lstat(resolved->buf, &st)) { + /* error out unless this was the last component */ + if (errno != ENOENT || remaining.len) { if (die_on_error) - die_errno("Could not get current working directory"); + die_errno("Invalid path '%s'", + resolved->buf); else goto error_out; } + } else if (S_ISLNK(st.st_mode)) { + ssize_t len; + strbuf_reset(&symlink); + + if (num_symlinks++ > MAXSYMLINKS) { + errno = ELOOP; - if (chdir(sb.buf)) { if (die_on_error) - die_errno("Could not switch to '%s'", - sb.buf); + die("More than %d nested symlinks " + "on path '%s'", MAXSYMLINKS, path); else goto error_out; } - } - if (strbuf_getcwd(&sb)) { - if (die_on_error) - die_errno("Could not get current working directory"); - else - goto error_out; - } - if (last_elem) { - if (sb.len && !is_dir_sep(sb.buf[sb.len - 1])) - strbuf_addch(&sb, '/'); - strbuf_addstr(&sb, last_elem); - free(last_elem); - last_elem = NULL; - } - - if (!lstat(sb.buf, &st) && S_ISLNK(st.st_mode)) { - struct strbuf next_sb = STRBUF_INIT; - ssize_t len = strbuf_readlink(&next_sb, sb.buf, 0); + len = strbuf_readlink(&symlink, resolved->buf, + st.st_size); if (len < 0) { if (die_on_error) die_errno("Invalid symlink '%s'", - sb.buf); + resolved->buf); else goto error_out; } - strbuf_swap(&sb, &next_sb); - strbuf_release(&next_sb); - } else - break; + + if (is_absolute_path(symlink.buf)) { + /* absolute symlink; set resolved to root */ + get_root_part(resolved, &symlink); + } else { + /* + * relative symlink + * strip off the last component since it will + * be replaced with the contents of the symlink + */ + strip_last_component(resolved); + } + + /* + * if there are still remaining components to resolve + * then append them to symlink + */ + if (remaining.len) { + strbuf_addch(&symlink, '/'); + strbuf_addbuf(&symlink, &remaining); + } + + /* + * use the symlink as the remaining components that + * need to be resloved + */ + strbuf_swap(&symlink, &remaining); + } } - retval = sb.buf; + retval = resolved->buf; + error_out: - free(last_elem); - if (cwd.len && chdir(cwd.buf)) - die_errno("Could not change back to '%s'", cwd.buf); - strbuf_release(&cwd); + strbuf_release(&remaining); + strbuf_release(&next); + strbuf_release(&symlink); + + if (!retval) + strbuf_reset(resolved); return retval; } const char *real_path(const char *path) { - return real_path_internal(path, 1); + static struct strbuf realpath = STRBUF_INIT; + return strbuf_realpath(&realpath, path, 1); } const char *real_path_if_valid(const char *path) { - return real_path_internal(path, 0); + static struct strbuf realpath = STRBUF_INIT; + return strbuf_realpath(&realpath, path, 0); +} + +char *real_pathdup(const char *path) +{ + struct strbuf realpath = STRBUF_INIT; + char *retval = NULL; + + if (strbuf_realpath(&realpath, path, 0)) + retval = strbuf_detach(&realpath, NULL); + + strbuf_release(&realpath); + + return retval; } /* @@ -152,6 +239,13 @@ const char *absolute_path(const char *path) return sb.buf; } +char *absolute_pathdup(const char *path) +{ + struct strbuf sb = STRBUF_INIT; + strbuf_add_absolute_path(&sb, path); + return strbuf_detach(&sb, NULL); +} + /* * Unlike prefix_path, this should be used if the named file does * not have to interact with index entry; i.e. name of a random file diff --git a/apply.c b/apply.c index 705cf56..0e2caea 100644 --- a/apply.c +++ b/apply.c @@ -2187,29 +2187,20 @@ static int parse_chunk(struct apply_state *state, char *buffer, unsigned long si return offset + hdrsize + patchsize; } -#define swap(a,b) myswap((a),(b),sizeof(a)) - -#define myswap(a, b, size) do { \ - unsigned char mytmp[size]; \ - memcpy(mytmp, &a, size); \ - memcpy(&a, &b, size); \ - memcpy(&b, mytmp, size); \ -} while (0) - static void reverse_patches(struct patch *p) { for (; p; p = p->next) { struct fragment *frag = p->fragments; - swap(p->new_name, p->old_name); - swap(p->new_mode, p->old_mode); - swap(p->is_new, p->is_delete); - swap(p->lines_added, p->lines_deleted); - swap(p->old_sha1_prefix, p->new_sha1_prefix); + SWAP(p->new_name, p->old_name); + SWAP(p->new_mode, p->old_mode); + SWAP(p->is_new, p->is_delete); + SWAP(p->lines_added, p->lines_deleted); + SWAP(p->old_sha1_prefix, p->new_sha1_prefix); for (; frag; frag = frag->next) { - swap(frag->newpos, frag->oldpos); - swap(frag->newlines, frag->oldlines); + SWAP(frag->newpos, frag->oldpos); + SWAP(frag->newlines, frag->oldlines); } } } @@ -4688,7 +4679,7 @@ static int apply_patch(struct apply_state *state, state->index_file, LOCK_DIE_ON_ERROR); else - state->newfd = hold_locked_index(state->lock_file, 1); + state->newfd = hold_locked_index(state->lock_file, LOCK_DIE_ON_ERROR); } if (state->check_index && read_apply_cache(state) < 0) { diff --git a/bisect.c b/bisect.c index 21bc6da..8e63c40 100644 --- a/bisect.c +++ b/bisect.c @@ -747,7 +747,7 @@ static void handle_bad_merge_base(void) exit(3); } - fprintf(stderr, _("Some %s revs are not ancestor of the %s rev.\n" + fprintf(stderr, _("Some %s revs are not ancestors of the %s rev.\n" "git bisect cannot work properly in this case.\n" "Maybe you mistook %s and %s revs?\n"), term_good, term_bad, term_good, term_bad); diff --git a/branch.c b/branch.c index c431cbf..b955d4f 100644 --- a/branch.c +++ b/branch.c @@ -298,7 +298,7 @@ void create_branch(const char *name, const char *start_name, start_name); if (reflog) - log_all_ref_updates = 1; + log_all_ref_updates = LOG_REFS_NORMAL; if (!dont_change_ref) { struct ref_transaction *transaction; diff --git a/builtin.h b/builtin.h index b9122bc..67f8051 100644 --- a/builtin.h +++ b/builtin.h @@ -60,6 +60,7 @@ extern int cmd_diff_files(int argc, const char **argv, const char *prefix); extern int cmd_diff_index(int argc, const char **argv, const char *prefix); extern int cmd_diff(int argc, const char **argv, const char *prefix); extern int cmd_diff_tree(int argc, const char **argv, const char *prefix); +extern int cmd_difftool(int argc, const char **argv, const char *prefix); extern int cmd_fast_export(int argc, const char **argv, const char *prefix); extern int cmd_fetch(int argc, const char **argv, const char *prefix); extern int cmd_fetch_pack(int argc, const char **argv, const char *prefix); diff --git a/builtin/add.c b/builtin/add.c index e8fb80b..9f53f02 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -361,7 +361,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) add_new_files = !take_worktree_changes && !refresh_only; require_pathspec = !(take_worktree_changes || (0 < addremove_explicit)); - hold_locked_index(&lock_file, 1); + hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); flags = ((verbose ? ADD_CACHE_VERBOSE : 0) | (show_only ? ADD_CACHE_PRETEND : 0) | diff --git a/builtin/am.c b/builtin/am.c index 826f18b..31fb605 100644 --- a/builtin/am.c +++ b/builtin/am.c @@ -1119,7 +1119,7 @@ static void refresh_and_write_cache(void) { struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); - hold_locked_index(lock_file, 1); + hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); refresh_cache(REFRESH_QUIET); if (write_locked_index(&the_index, lock_file, COMMIT_LOCK)) die(_("unable to write index file")); @@ -1976,7 +1976,7 @@ static int fast_forward_to(struct tree *head, struct tree *remote, int reset) return -1; lock_file = xcalloc(1, sizeof(struct lock_file)); - hold_locked_index(lock_file, 1); + hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); refresh_cache(REFRESH_QUIET); @@ -2016,7 +2016,7 @@ static int merge_tree(struct tree *tree) return -1; lock_file = xcalloc(1, sizeof(struct lock_file)); - hold_locked_index(lock_file, 1); + hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); memset(&opts, 0, sizeof(opts)); opts.head_idx = 1; diff --git a/builtin/blame.c b/builtin/blame.c index 3aae19a..cffc626 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1901,7 +1901,7 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent, struct origin *suspect = ent->suspect; char hex[GIT_SHA1_HEXSZ + 1]; - sha1_to_hex_r(hex, suspect->commit->object.oid.hash); + oid_to_hex_r(hex, &suspect->commit->object.oid); printf("%s %d %d %d\n", hex, ent->s_lno + 1, @@ -1941,7 +1941,7 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP); get_commit_info(suspect->commit, &ci, 1); - sha1_to_hex_r(hex, suspect->commit->object.oid.hash); + oid_to_hex_r(hex, &suspect->commit->object.oid); cp = nth_line(sb, ent->lno); for (cnt = 0; cnt < ent->num_lines; cnt++) { @@ -2601,8 +2601,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) * and are only included here to get included in the "-h" * output: */ - { OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental indent-based heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb }, - { OPTION_LOWLEVEL_CALLBACK, 0, "compaction-heuristic", NULL, NULL, N_("Use an experimental blank-line-based heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb }, + { OPTION_LOWLEVEL_CALLBACK, 0, "indent-heuristic", NULL, NULL, N_("Use an experimental heuristic to improve diffs"), PARSE_OPT_NOARG, parse_opt_unknown_cb }, OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL), OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from instead of calling git-rev-list")), @@ -2650,7 +2649,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) } parse_done: no_whole_file_rename = !DIFF_OPT_TST(&revs.diffopt, FOLLOW_RENAMES); - xdl_opts |= revs.diffopt.xdl_opts & (XDF_COMPACTION_HEURISTIC | XDF_INDENT_HEURISTIC); + xdl_opts |= revs.diffopt.xdl_opts & XDF_INDENT_HEURISTIC; DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES); argc = parse_options_end(&ctx); diff --git a/builtin/branch.c b/builtin/branch.c index 4757075..9d30f55 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -512,15 +512,6 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin if (filter->verbose) maxwidth = calc_maxwidth(&array, strlen(remote_prefix)); - /* - * If no sorting parameter is given then we default to sorting - * by 'refname'. This would give us an alphabetically sorted - * array with the 'HEAD' ref at the beginning followed by - * local branches 'refs/heads/...' and finally remote-tacking - * branches 'refs/remotes/...'. - */ - if (!sorting) - sorting = ref_default_sorting(); ref_array_sort(sorting, &array); for (i = 0; i < array.nr; i++) @@ -645,6 +636,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) const char *new_upstream = NULL; enum branch_track track; struct ref_filter filter; + int icase = 0; static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting; struct option options[] = { @@ -686,6 +678,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"), N_("print only branches of the object"), 0, parse_opt_object_name }, + OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")), OPT_END(), }; @@ -723,6 +716,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if (filter.abbrev == -1) filter.abbrev = DEFAULT_ABBREV; + filter.ignore_case = icase; + finalize_colopts(&colopts, -1); if (filter.verbose) { if (explicitly_enable_column(colopts)) @@ -744,6 +739,16 @@ int cmd_branch(int argc, const char **argv, const char *prefix) if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached) filter.kind |= FILTER_REFS_DETACHED_HEAD; filter.name_patterns = argv; + /* + * If no sorting parameter is given then we default to sorting + * by 'refname'. This would give us an alphabetically sorted + * array with the 'HEAD' ref at the beginning followed by + * local branches 'refs/heads/...' and finally remote-tacking + * branches 'refs/remotes/...'. + */ + if (!sorting) + sorting = ref_default_sorting(); + sorting->ignore_case = icase; print_ref_list(&filter, sorting); print_columns(&output, colopts, NULL); string_list_clear(&output, 0); diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 30a49d9..07631d0 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -205,7 +205,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) if (index_opt && !state.base_dir_len && !to_tempfile) { state.refresh_cache = 1; state.istate = &the_index; - newfd = hold_locked_index(&lock_file, 1); + newfd = hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); } /* Check out named files first */ diff --git a/builtin/checkout.c b/builtin/checkout.c index 512492a..f174f50 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -56,8 +56,8 @@ static int post_checkout_hook(struct commit *old, struct commit *new, int changed) { return run_hook_le(NULL, "post-checkout", - sha1_to_hex(old ? old->object.oid.hash : null_sha1), - sha1_to_hex(new ? new->object.oid.hash : null_sha1), + oid_to_hex(old ? &old->object.oid : &null_oid), + oid_to_hex(new ? &new->object.oid : &null_oid), changed ? "1" : "0", NULL); /* "new" can be NULL when checking out from the index before a commit exists. */ @@ -274,7 +274,7 @@ static int checkout_paths(const struct checkout_opts *opts, lock_file = xcalloc(1, sizeof(struct lock_file)); - hold_locked_index(lock_file, 1); + hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); if (read_cache_preload(&opts->pathspec) < 0) return error(_("index file corrupt")); @@ -467,7 +467,7 @@ static int merge_working_tree(const struct checkout_opts *opts, int ret; struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); - hold_locked_index(lock_file, 1); + hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); if (read_cache_preload(NULL) < 0) return error(_("index file corrupt")); @@ -612,22 +612,25 @@ static void update_refs_for_switch(const struct checkout_opts *opts, const char *old_desc, *reflog_msg; if (opts->new_branch) { if (opts->new_orphan_branch) { - if (opts->new_branch_log && !log_all_ref_updates) { + char *refname; + + refname = mkpathdup("refs/heads/%s", opts->new_orphan_branch); + if (opts->new_branch_log && + !should_autocreate_reflog(refname)) { int ret; - char *refname; struct strbuf err = STRBUF_INIT; - refname = mkpathdup("refs/heads/%s", opts->new_orphan_branch); ret = safe_create_reflog(refname, 1, &err); - free(refname); if (ret) { fprintf(stderr, _("Can not do reflog for '%s': %s\n"), opts->new_orphan_branch, err.buf); strbuf_release(&err); + free(refname); return; } strbuf_release(&err); } + free(refname); } else create_branch(opts->new_branch, new->name, diff --git a/builtin/clean.c b/builtin/clean.c index 0371010..d6bc3aa 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -287,11 +287,11 @@ static void pretty_print_menus(struct string_list *menu_list) static void prompt_help_cmd(int singleton) { clean_print_color(CLEAN_COLOR_HELP); - printf_ln(singleton ? + printf(singleton ? _("Prompt help:\n" "1 - select a numbered item\n" "foo - select item based on unique prefix\n" - " - (empty) select nothing") : + " - (empty) select nothing\n") : _("Prompt help:\n" "1 - select a single item\n" "3-5 - select a range of items\n" @@ -299,7 +299,7 @@ static void prompt_help_cmd(int singleton) "foo - select item based on unique prefix\n" "-... - unselect specified items\n" "* - choose all items\n" - " - (empty) finish selecting")); + " - (empty) finish selecting\n")); clean_print_color(CLEAN_COLOR_RESET); } @@ -508,7 +508,7 @@ static int parse_choice(struct menu_stuff *menu_stuff, if (top <= 0 || bottom <= 0 || top > menu_stuff->nr || bottom > top || (is_single && bottom != top)) { clean_print_color(CLEAN_COLOR_ERROR); - printf_ln(_("Huh (%s)?"), (*ptr)->buf); + printf(_("Huh (%s)?\n"), (*ptr)->buf); clean_print_color(CLEAN_COLOR_RESET); continue; } @@ -774,7 +774,7 @@ static int ask_each_cmd(void) static int quit_cmd(void) { string_list_clear(&del_list, 0); - printf_ln(_("Bye.")); + printf(_("Bye.\n")); return MENU_RETURN_NO_LOOP; } diff --git a/builtin/clone.c b/builtin/clone.c index 6c76a6e..3f63edb 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -99,7 +99,7 @@ static struct option builtin_clone_options[] = { OPT_STRING(0, "shallow-since", &option_since, N_("time"), N_("create a shallow clone since a specific time")), OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("revision"), - N_("deepen history of shallow clone by excluding rev")), + N_("deepen history of shallow clone, excluding rev")), OPT_BOOL(0, "single-branch", &option_single_branch, N_("clone only one branch, HEAD or --branch")), OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules, @@ -170,7 +170,7 @@ static char *get_repo_path(const char *repo, int *is_bundle) strbuf_addstr(&path, repo); raw = get_repo_path_1(&path, is_bundle); - canon = raw ? xstrdup(absolute_path(raw)) : NULL; + canon = raw ? absolute_pathdup(raw) : NULL; strbuf_release(&path); return canon; } @@ -711,7 +711,7 @@ static int checkout(int submodule_progress) setup_work_tree(); lock_file = xcalloc(1, sizeof(struct lock_file)); - hold_locked_index(lock_file, 1); + hold_locked_index(lock_file, LOCK_DIE_ON_ERROR); memset(&opts, 0, sizeof opts); opts.update = 1; @@ -894,7 +894,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) path = get_repo_path(repo_name, &is_bundle); if (path) - repo = xstrdup(absolute_path(repo_name)); + repo = absolute_pathdup(repo_name); else if (!strchr(repo_name, ':')) die(_("repository '%s' does not exist"), repo_name); else diff --git a/builtin/commit.c b/builtin/commit.c index 276c740..2de5f6c 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -351,7 +351,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix if (interactive) { char *old_index_env = NULL; - hold_locked_index(&index_lock, 1); + hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); refresh_cache_or_die(refresh_flags); @@ -396,7 +396,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix * (B) on failure, rollback the real index. */ if (all || (also && pathspec.nr)) { - hold_locked_index(&index_lock, 1); + hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); add_files_to_cache(also ? prefix : NULL, &pathspec, 0); refresh_cache_or_die(refresh_flags); update_main_cache_tree(WRITE_TREE_SILENT); @@ -416,7 +416,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix * We still need to refresh the index here. */ if (!only && !pathspec.nr) { - hold_locked_index(&index_lock, 1); + hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); refresh_cache_or_die(refresh_flags); if (active_cache_changed || !cache_tree_fully_valid(active_cache_tree)) @@ -468,7 +468,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix if (read_cache() < 0) die(_("cannot read the index")); - hold_locked_index(&index_lock, 1); + hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); update_main_cache_tree(WRITE_TREE_SILENT); @@ -790,7 +790,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, strbuf_stripspace(&sb, 0); if (signoff) - append_signoff(&sb, ignore_non_trailer(&sb), 0); + append_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0); if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len) die_errno(_("could not write commit template")); @@ -960,15 +960,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix, return 0; if (use_editor) { - char index[PATH_MAX]; - const char *env[2] = { NULL }; - env[0] = index; - snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); - if (launch_editor(git_path_commit_editmsg(), NULL, env)) { + struct argv_array env = ARGV_ARRAY_INIT; + + argv_array_pushf(&env, "GIT_INDEX_FILE=%s", index_file); + if (launch_editor(git_path_commit_editmsg(), NULL, env.argv)) { fprintf(stderr, _("Please supply the message using either -m or -F option.\n")); exit(1); } + argv_array_clear(&env); } if (!no_verify && @@ -1525,12 +1525,10 @@ static int git_commit_config(const char *k, const char *v, void *cb) static int run_rewrite_hook(const unsigned char *oldsha1, const unsigned char *newsha1) { - /* oldsha1 SP newsha1 LF NUL */ - static char buf[2*40 + 3]; struct child_process proc = CHILD_PROCESS_INIT; const char *argv[3]; int code; - size_t n; + struct strbuf sb = STRBUF_INIT; argv[0] = find_hook("post-rewrite"); if (!argv[0]) @@ -1546,34 +1544,33 @@ static int run_rewrite_hook(const unsigned char *oldsha1, code = start_command(&proc); if (code) return code; - n = snprintf(buf, sizeof(buf), "%s %s\n", - sha1_to_hex(oldsha1), sha1_to_hex(newsha1)); + strbuf_addf(&sb, "%s %s\n", sha1_to_hex(oldsha1), sha1_to_hex(newsha1)); sigchain_push(SIGPIPE, SIG_IGN); - write_in_full(proc.in, buf, n); + write_in_full(proc.in, sb.buf, sb.len); close(proc.in); + strbuf_release(&sb); sigchain_pop(SIGPIPE); return finish_command(&proc); } int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...) { - const char *hook_env[3] = { NULL }; - char index[PATH_MAX]; + struct argv_array hook_env = ARGV_ARRAY_INIT; va_list args; int ret; - snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); - hook_env[0] = index; + argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", index_file); /* * Let the hook know that no editor will be launched. */ if (!editor_is_used) - hook_env[1] = "GIT_EDITOR=:"; + argv_array_push(&hook_env, "GIT_EDITOR=:"); va_start(args, name); - ret = run_hook_ve(hook_env, name, args); + ret = run_hook_ve(hook_env.argv,name, args); va_end(args); + argv_array_clear(&hook_env); return ret; } diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c index 806dd7a..8ce0048 100644 --- a/builtin/diff-tree.c +++ b/builtin/diff-tree.c @@ -147,9 +147,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) tree1 = opt->pending.objects[0].item; tree2 = opt->pending.objects[1].item; if (tree2->flags & UNINTERESTING) { - struct object *tmp = tree2; - tree2 = tree1; - tree1 = tmp; + SWAP(tree2, tree1); } diff_tree_sha1(tree1->oid.hash, tree2->oid.hash, diff --git a/builtin/diff.c b/builtin/diff.c index 7f91f6d..3d64b85 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -45,12 +45,9 @@ static void stuff_change(struct diff_options *opt, return; if (DIFF_OPT_TST(opt, REVERSE_DIFF)) { - unsigned tmp; - const unsigned char *tmp_u; - const char *tmp_c; - tmp = old_mode; old_mode = new_mode; new_mode = tmp; - tmp_u = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_u; - tmp_c = old_name; old_name = new_name; new_name = tmp_c; + SWAP(old_mode, new_mode); + SWAP(old_sha1, new_sha1); + SWAP(old_name, new_name); } if (opt->prefix && diff --git a/builtin/difftool.c b/builtin/difftool.c new file mode 100644 index 0000000..d13350c --- /dev/null +++ b/builtin/difftool.c @@ -0,0 +1,692 @@ +/* + * "git difftool" builtin command + * + * This is a wrapper around the GIT_EXTERNAL_DIFF-compatible + * git-difftool--helper script. + * + * This script exports GIT_EXTERNAL_DIFF and GIT_PAGER for use by git. + * The GIT_DIFF* variables are exported for use by git-difftool--helper. + * + * Any arguments that are unknown to this script are forwarded to 'git diff'. + * + * Copyright (C) 2016 Johannes Schindelin + */ +#include "cache.h" +#include "builtin.h" +#include "run-command.h" +#include "exec_cmd.h" +#include "parse-options.h" +#include "argv-array.h" +#include "strbuf.h" +#include "lockfile.h" +#include "dir.h" + +static char *diff_gui_tool; +static int trust_exit_code; + +static const char *const builtin_difftool_usage[] = { + N_("git difftool [] [ []] [--] [...]"), + NULL +}; + +static int difftool_config(const char *var, const char *value, void *cb) +{ + if (!strcmp(var, "diff.guitool")) { + diff_gui_tool = xstrdup(value); + return 0; + } + + if (!strcmp(var, "difftool.trustexitcode")) { + trust_exit_code = git_config_bool(var, value); + return 0; + } + + return git_default_config(var, value, cb); +} + +static int print_tool_help(void) +{ + const char *argv[] = { "mergetool", "--tool-help=diff", NULL }; + return run_command_v_opt(argv, RUN_GIT_CMD); +} + +static int parse_index_info(char *p, int *mode1, int *mode2, + struct object_id *oid1, struct object_id *oid2, + char *status) +{ + if (*p != ':') + return error("expected ':', got '%c'", *p); + *mode1 = (int)strtol(p + 1, &p, 8); + if (*p != ' ') + return error("expected ' ', got '%c'", *p); + *mode2 = (int)strtol(p + 1, &p, 8); + if (*p != ' ') + return error("expected ' ', got '%c'", *p); + if (get_oid_hex(++p, oid1)) + return error("expected object ID, got '%s'", p + 1); + p += GIT_SHA1_HEXSZ; + if (*p != ' ') + return error("expected ' ', got '%c'", *p); + if (get_oid_hex(++p, oid2)) + return error("expected object ID, got '%s'", p + 1); + p += GIT_SHA1_HEXSZ; + if (*p != ' ') + return error("expected ' ', got '%c'", *p); + *status = *++p; + if (!*status) + return error("missing status"); + if (p[1] && !isdigit(p[1])) + return error("unexpected trailer: '%s'", p + 1); + return 0; +} + +/* + * Remove any trailing slash from $workdir + * before starting to avoid double slashes in symlink targets. + */ +static void add_path(struct strbuf *buf, size_t base_len, const char *path) +{ + strbuf_setlen(buf, base_len); + if (buf->len && buf->buf[buf->len - 1] != '/') + strbuf_addch(buf, '/'); + strbuf_addstr(buf, path); +} + +/* + * Determine whether we can simply reuse the file in the worktree. + */ +static int use_wt_file(const char *workdir, const char *name, + struct object_id *oid) +{ + struct strbuf buf = STRBUF_INIT; + struct stat st; + int use = 0; + + strbuf_addstr(&buf, workdir); + add_path(&buf, buf.len, name); + + if (!lstat(buf.buf, &st) && !S_ISLNK(st.st_mode)) { + struct object_id wt_oid; + int fd = open(buf.buf, O_RDONLY); + + if (fd >= 0 && + !index_fd(wt_oid.hash, fd, &st, OBJ_BLOB, name, 0)) { + if (is_null_oid(oid)) { + oidcpy(oid, &wt_oid); + use = 1; + } else if (!oidcmp(oid, &wt_oid)) + use = 1; + } + } + + strbuf_release(&buf); + + return use; +} + +struct working_tree_entry { + struct hashmap_entry entry; + char path[FLEX_ARRAY]; +}; + +static int working_tree_entry_cmp(struct working_tree_entry *a, + struct working_tree_entry *b, void *keydata) +{ + return strcmp(a->path, b->path); +} + +/* + * The `left` and `right` entries hold paths for the symlinks hashmap, + * and a SHA-1 surrounded by brief text for submodules. + */ +struct pair_entry { + struct hashmap_entry entry; + char left[PATH_MAX], right[PATH_MAX]; + const char path[FLEX_ARRAY]; +}; + +static int pair_cmp(struct pair_entry *a, struct pair_entry *b, void *keydata) +{ + return strcmp(a->path, b->path); +} + +static void add_left_or_right(struct hashmap *map, const char *path, + const char *content, int is_right) +{ + struct pair_entry *e, *existing; + + FLEX_ALLOC_STR(e, path, path); + hashmap_entry_init(e, strhash(path)); + existing = hashmap_get(map, e, NULL); + if (existing) { + free(e); + e = existing; + } else { + e->left[0] = e->right[0] = '\0'; + hashmap_add(map, e); + } + strlcpy(is_right ? e->right : e->left, content, PATH_MAX); +} + +struct path_entry { + struct hashmap_entry entry; + char path[FLEX_ARRAY]; +}; + +static int path_entry_cmp(struct path_entry *a, struct path_entry *b, void *key) +{ + return strcmp(a->path, key ? key : b->path); +} + +static void changed_files(struct hashmap *result, const char *index_path, + const char *workdir) +{ + struct child_process update_index = CHILD_PROCESS_INIT; + struct child_process diff_files = CHILD_PROCESS_INIT; + struct strbuf index_env = STRBUF_INIT, buf = STRBUF_INIT; + const char *git_dir = absolute_path(get_git_dir()), *env[] = { + NULL, NULL + }; + FILE *fp; + + strbuf_addf(&index_env, "GIT_INDEX_FILE=%s", index_path); + env[0] = index_env.buf; + + argv_array_pushl(&update_index.args, + "--git-dir", git_dir, "--work-tree", workdir, + "update-index", "--really-refresh", "-q", + "--unmerged", NULL); + update_index.no_stdin = 1; + update_index.no_stdout = 1; + update_index.no_stderr = 1; + update_index.git_cmd = 1; + update_index.use_shell = 0; + update_index.clean_on_exit = 1; + update_index.dir = workdir; + update_index.env = env; + /* Ignore any errors of update-index */ + run_command(&update_index); + + argv_array_pushl(&diff_files.args, + "--git-dir", git_dir, "--work-tree", workdir, + "diff-files", "--name-only", "-z", NULL); + diff_files.no_stdin = 1; + diff_files.git_cmd = 1; + diff_files.use_shell = 0; + diff_files.clean_on_exit = 1; + diff_files.out = -1; + diff_files.dir = workdir; + diff_files.env = env; + if (start_command(&diff_files)) + die("could not obtain raw diff"); + fp = xfdopen(diff_files.out, "r"); + while (!strbuf_getline_nul(&buf, fp)) { + struct path_entry *entry; + FLEX_ALLOC_STR(entry, path, buf.buf); + hashmap_entry_init(entry, strhash(buf.buf)); + hashmap_add(result, entry); + } + if (finish_command(&diff_files)) + die("diff-files did not exit properly"); + strbuf_release(&index_env); + strbuf_release(&buf); +} + +static NORETURN void exit_cleanup(const char *tmpdir, int exit_code) +{ + struct strbuf buf = STRBUF_INIT; + strbuf_addstr(&buf, tmpdir); + remove_dir_recursively(&buf, 0); + if (exit_code) + warning(_("failed: %d"), exit_code); + exit(exit_code); +} + +static int ensure_leading_directories(char *path) +{ + switch (safe_create_leading_directories(path)) { + case SCLD_OK: + case SCLD_EXISTS: + return 0; + default: + return error(_("could not create leading directories " + "of '%s'"), path); + } +} + +static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, + int argc, const char **argv) +{ + char tmpdir[PATH_MAX]; + struct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT; + struct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT; + struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT; + struct strbuf wtdir = STRBUF_INIT; + size_t ldir_len, rdir_len, wtdir_len; + struct cache_entry *ce = xcalloc(1, sizeof(ce) + PATH_MAX + 1); + const char *workdir, *tmp; + int ret = 0, i; + FILE *fp; + struct hashmap working_tree_dups, submodules, symlinks2; + struct hashmap_iter iter; + struct pair_entry *entry; + enum object_type type; + unsigned long size; + struct index_state wtindex; + struct checkout lstate, rstate; + int rc, flags = RUN_GIT_CMD, err = 0; + struct child_process child = CHILD_PROCESS_INIT; + const char *helper_argv[] = { "difftool--helper", NULL, NULL, NULL }; + struct hashmap wt_modified, tmp_modified; + int indices_loaded = 0; + + workdir = get_git_work_tree(); + + /* Setup temp directories */ + tmp = getenv("TMPDIR"); + xsnprintf(tmpdir, sizeof(tmpdir), "%s/git-difftool.XXXXXX", tmp ? tmp : "/tmp"); + if (!mkdtemp(tmpdir)) + return error("could not create '%s'", tmpdir); + strbuf_addf(&ldir, "%s/left/", tmpdir); + strbuf_addf(&rdir, "%s/right/", tmpdir); + strbuf_addstr(&wtdir, workdir); + if (!wtdir.len || !is_dir_sep(wtdir.buf[wtdir.len - 1])) + strbuf_addch(&wtdir, '/'); + mkdir(ldir.buf, 0700); + mkdir(rdir.buf, 0700); + + memset(&wtindex, 0, sizeof(wtindex)); + + memset(&lstate, 0, sizeof(lstate)); + lstate.base_dir = ldir.buf; + lstate.base_dir_len = ldir.len; + lstate.force = 1; + memset(&rstate, 0, sizeof(rstate)); + rstate.base_dir = rdir.buf; + rstate.base_dir_len = rdir.len; + rstate.force = 1; + + ldir_len = ldir.len; + rdir_len = rdir.len; + wtdir_len = wtdir.len; + + hashmap_init(&working_tree_dups, + (hashmap_cmp_fn)working_tree_entry_cmp, 0); + hashmap_init(&submodules, (hashmap_cmp_fn)pair_cmp, 0); + hashmap_init(&symlinks2, (hashmap_cmp_fn)pair_cmp, 0); + + child.no_stdin = 1; + child.git_cmd = 1; + child.use_shell = 0; + child.clean_on_exit = 1; + child.dir = prefix; + child.out = -1; + argv_array_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z", + NULL); + for (i = 0; i < argc; i++) + argv_array_push(&child.args, argv[i]); + if (start_command(&child)) + die("could not obtain raw diff"); + fp = xfdopen(child.out, "r"); + + /* Build index info for left and right sides of the diff */ + i = 0; + while (!strbuf_getline_nul(&info, fp)) { + int lmode, rmode; + struct object_id loid, roid; + char status; + const char *src_path, *dst_path; + size_t src_path_len, dst_path_len; + + if (starts_with(info.buf, "::")) + die(N_("combined diff formats('-c' and '--cc') are " + "not supported in\n" + "directory diff mode('-d' and '--dir-diff').")); + + if (parse_index_info(info.buf, &lmode, &rmode, &loid, &roid, + &status)) + break; + if (strbuf_getline_nul(&lpath, fp)) + break; + src_path = lpath.buf; + src_path_len = lpath.len; + + i++; + if (status != 'C' && status != 'R') { + dst_path = src_path; + dst_path_len = src_path_len; + } else { + if (strbuf_getline_nul(&rpath, fp)) + break; + dst_path = rpath.buf; + dst_path_len = rpath.len; + } + + if (S_ISGITLINK(lmode) || S_ISGITLINK(rmode)) { + strbuf_reset(&buf); + strbuf_addf(&buf, "Subproject commit %s", + oid_to_hex(&loid)); + add_left_or_right(&submodules, src_path, buf.buf, 0); + strbuf_reset(&buf); + strbuf_addf(&buf, "Subproject commit %s", + oid_to_hex(&roid)); + if (!oidcmp(&loid, &roid)) + strbuf_addstr(&buf, "-dirty"); + add_left_or_right(&submodules, dst_path, buf.buf, 1); + continue; + } + + if (S_ISLNK(lmode)) { + char *content = read_sha1_file(loid.hash, &type, &size); + add_left_or_right(&symlinks2, src_path, content, 0); + free(content); + } + + if (S_ISLNK(rmode)) { + char *content = read_sha1_file(roid.hash, &type, &size); + add_left_or_right(&symlinks2, dst_path, content, 1); + free(content); + } + + if (lmode && status != 'C') { + ce->ce_mode = lmode; + oidcpy(&ce->oid, &loid); + strcpy(ce->name, src_path); + ce->ce_namelen = src_path_len; + if (checkout_entry(ce, &lstate, NULL)) + return error("could not write '%s'", src_path); + } + + if (rmode) { + struct working_tree_entry *entry; + + /* Avoid duplicate working_tree entries */ + FLEX_ALLOC_STR(entry, path, dst_path); + hashmap_entry_init(entry, strhash(dst_path)); + if (hashmap_get(&working_tree_dups, entry, NULL)) { + free(entry); + continue; + } + hashmap_add(&working_tree_dups, entry); + + if (!use_wt_file(workdir, dst_path, &roid)) { + ce->ce_mode = rmode; + oidcpy(&ce->oid, &roid); + strcpy(ce->name, dst_path); + ce->ce_namelen = dst_path_len; + if (checkout_entry(ce, &rstate, NULL)) + return error("could not write '%s'", + dst_path); + } else if (!is_null_oid(&roid)) { + /* + * Changes in the working tree need special + * treatment since they are not part of the + * index. + */ + struct cache_entry *ce2 = + make_cache_entry(rmode, roid.hash, + dst_path, 0, 0); + + add_index_entry(&wtindex, ce2, + ADD_CACHE_JUST_APPEND); + + add_path(&rdir, rdir_len, dst_path); + if (ensure_leading_directories(rdir.buf)) + return error("could not create " + "directory for '%s'", + dst_path); + add_path(&wtdir, wtdir_len, dst_path); + if (symlinks) { + if (symlink(wtdir.buf, rdir.buf)) { + ret = error_errno("could not symlink '%s' to '%s'", wtdir.buf, rdir.buf); + goto finish; + } + } else { + struct stat st; + if (stat(wtdir.buf, &st)) + st.st_mode = 0644; + if (copy_file(rdir.buf, wtdir.buf, + st.st_mode)) { + ret = error("could not copy '%s' to '%s'", wtdir.buf, rdir.buf); + goto finish; + } + } + } + } + } + + if (finish_command(&child)) { + ret = error("error occurred running diff --raw"); + goto finish; + } + + if (!i) + return 0; + + /* + * Changes to submodules require special treatment.This loop writes a + * temporary file to both the left and right directories to show the + * change in the recorded SHA1 for the submodule. + */ + hashmap_iter_init(&submodules, &iter); + while ((entry = hashmap_iter_next(&iter))) { + if (*entry->left) { + add_path(&ldir, ldir_len, entry->path); + ensure_leading_directories(ldir.buf); + write_file(ldir.buf, "%s", entry->left); + } + if (*entry->right) { + add_path(&rdir, rdir_len, entry->path); + ensure_leading_directories(rdir.buf); + write_file(rdir.buf, "%s", entry->right); + } + } + + /* + * Symbolic links require special treatment.The standard "git diff" + * shows only the link itself, not the contents of the link target. + * This loop replicates that behavior. + */ + hashmap_iter_init(&symlinks2, &iter); + while ((entry = hashmap_iter_next(&iter))) { + if (*entry->left) { + add_path(&ldir, ldir_len, entry->path); + ensure_leading_directories(ldir.buf); + write_file(ldir.buf, "%s", entry->left); + } + if (*entry->right) { + add_path(&rdir, rdir_len, entry->path); + ensure_leading_directories(rdir.buf); + write_file(rdir.buf, "%s", entry->right); + } + } + + strbuf_release(&buf); + + strbuf_setlen(&ldir, ldir_len); + helper_argv[1] = ldir.buf; + strbuf_setlen(&rdir, rdir_len); + helper_argv[2] = rdir.buf; + + if (extcmd) { + helper_argv[0] = extcmd; + flags = 0; + } else + setenv("GIT_DIFFTOOL_DIRDIFF", "true", 1); + rc = run_command_v_opt(helper_argv, flags); + + /* + * If the diff includes working copy files and those + * files were modified during the diff, then the changes + * should be copied back to the working tree. + * Do not copy back files when symlinks are used and the + * external tool did not replace the original link with a file. + * + * These hashes are loaded lazily since they aren't needed + * in the common case of --symlinks and the difftool updating + * files through the symlink. + */ + hashmap_init(&wt_modified, (hashmap_cmp_fn)path_entry_cmp, + wtindex.cache_nr); + hashmap_init(&tmp_modified, (hashmap_cmp_fn)path_entry_cmp, + wtindex.cache_nr); + + for (i = 0; i < wtindex.cache_nr; i++) { + struct hashmap_entry dummy; + const char *name = wtindex.cache[i]->name; + struct stat st; + + add_path(&rdir, rdir_len, name); + if (lstat(rdir.buf, &st)) + continue; + + if ((symlinks && S_ISLNK(st.st_mode)) || !S_ISREG(st.st_mode)) + continue; + + if (!indices_loaded) { + static struct lock_file lock; + strbuf_reset(&buf); + strbuf_addf(&buf, "%s/wtindex", tmpdir); + if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 || + write_locked_index(&wtindex, &lock, COMMIT_LOCK)) { + ret = error("could not write %s", buf.buf); + rollback_lock_file(&lock); + goto finish; + } + changed_files(&wt_modified, buf.buf, workdir); + strbuf_setlen(&rdir, rdir_len); + changed_files(&tmp_modified, buf.buf, rdir.buf); + add_path(&rdir, rdir_len, name); + indices_loaded = 1; + } + + hashmap_entry_init(&dummy, strhash(name)); + if (hashmap_get(&tmp_modified, &dummy, name)) { + add_path(&wtdir, wtdir_len, name); + if (hashmap_get(&wt_modified, &dummy, name)) { + warning(_("both files modified: '%s' and '%s'."), + wtdir.buf, rdir.buf); + warning(_("working tree file has been left.")); + warning("%s", ""); + err = 1; + } else if (unlink(wtdir.buf) || + copy_file(wtdir.buf, rdir.buf, st.st_mode)) + warning_errno(_("could not copy '%s' to '%s'"), + rdir.buf, wtdir.buf); + } + } + + if (err) { + warning(_("temporary files exist in '%s'."), tmpdir); + warning(_("you may want to cleanup or recover these.")); + exit(1); + } else + exit_cleanup(tmpdir, rc); + +finish: + free(ce); + strbuf_release(&ldir); + strbuf_release(&rdir); + strbuf_release(&wtdir); + strbuf_release(&buf); + + return ret; +} + +static int run_file_diff(int prompt, const char *prefix, + int argc, const char **argv) +{ + struct argv_array args = ARGV_ARRAY_INIT; + const char *env[] = { + "GIT_PAGER=", "GIT_EXTERNAL_DIFF=git-difftool--helper", NULL, + NULL + }; + int ret = 0, i; + + if (prompt > 0) + env[2] = "GIT_DIFFTOOL_PROMPT=true"; + else if (!prompt) + env[2] = "GIT_DIFFTOOL_NO_PROMPT=true"; + + + argv_array_push(&args, "diff"); + for (i = 0; i < argc; i++) + argv_array_push(&args, argv[i]); + ret = run_command_v_opt_cd_env(args.argv, RUN_GIT_CMD, prefix, env); + exit(ret); +} + +int cmd_difftool(int argc, const char **argv, const char *prefix) +{ + int use_gui_tool = 0, dir_diff = 0, prompt = -1, symlinks = 0, + tool_help = 0; + static char *difftool_cmd = NULL, *extcmd = NULL; + struct option builtin_difftool_options[] = { + OPT_BOOL('g', "gui", &use_gui_tool, + N_("use `diff.guitool` instead of `diff.tool`")), + OPT_BOOL('d', "dir-diff", &dir_diff, + N_("perform a full-directory diff")), + { OPTION_SET_INT, 'y', "no-prompt", &prompt, NULL, + N_("do not prompt before launching a diff tool"), + PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 0}, + { OPTION_SET_INT, 0, "prompt", &prompt, NULL, NULL, + PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_HIDDEN, + NULL, 1 }, + OPT_BOOL(0, "symlinks", &symlinks, + N_("use symlinks in dir-diff mode")), + OPT_STRING('t', "tool", &difftool_cmd, N_(""), + N_("use the specified diff tool")), + OPT_BOOL(0, "tool-help", &tool_help, + N_("print a list of diff tools that may be used with " + "`--tool`")), + OPT_BOOL(0, "trust-exit-code", &trust_exit_code, + N_("make 'git-difftool' exit when an invoked diff " + "tool returns a non - zero exit code")), + OPT_STRING('x', "extcmd", &extcmd, N_(""), + N_("specify a custom command for viewing diffs")), + OPT_END() + }; + + git_config(difftool_config, NULL); + symlinks = has_symlinks; + + argc = parse_options(argc, argv, prefix, builtin_difftool_options, + builtin_difftool_usage, PARSE_OPT_KEEP_UNKNOWN | + PARSE_OPT_KEEP_DASHDASH); + + if (tool_help) + return print_tool_help(); + + /* NEEDSWORK: once we no longer spawn anything, remove this */ + setenv(GIT_DIR_ENVIRONMENT, absolute_path(get_git_dir()), 1); + setenv(GIT_WORK_TREE_ENVIRONMENT, absolute_path(get_git_work_tree()), 1); + + if (use_gui_tool && diff_gui_tool && *diff_gui_tool) + setenv("GIT_DIFF_TOOL", diff_gui_tool, 1); + else if (difftool_cmd) { + if (*difftool_cmd) + setenv("GIT_DIFF_TOOL", difftool_cmd, 1); + else + die(_("no given for --tool=")); + } + + if (extcmd) { + if (*extcmd) + setenv("GIT_DIFFTOOL_EXTCMD", extcmd, 1); + else + die(_("no given for --extcmd=")); + } + + setenv("GIT_DIFFTOOL_TRUST_EXIT_CODE", + trust_exit_code ? "true" : "false", 1); + + /* + * In directory diff mode, 'git-difftool--helper' is called once + * to compare the a / b directories. In file diff mode, 'git diff' + * will invoke a separate instance of 'git-difftool--helper' for + * each file that changed. + */ + if (dir_diff) + return run_dir_diff(extcmd, symlinks, prefix, argc, argv); + return run_file_diff(prompt, prefix, argc, argv); +} diff --git a/builtin/fetch.c b/builtin/fetch.c index 1d77e58..b5ad09d 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -122,7 +122,7 @@ static struct option builtin_fetch_options[] = { OPT_STRING(0, "shallow-since", &deepen_since, N_("time"), N_("deepen history of shallow repository based on time")), OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("revision"), - N_("deepen history of shallow clone by excluding rev")), + N_("deepen history of shallow clone, excluding rev")), OPT_INTEGER(0, "deepen", &deepen_relative, N_("deepen history of shallow clone")), { OPTION_SET_INT, 0, "unshallow", &unshallow, NULL, @@ -1177,7 +1177,7 @@ static int add_remote_or_group(const char *name, struct string_list *list) git_config(get_remote_group, &g); if (list->nr == prev_nr) { struct remote *remote = remote_get(name); - if (!remote_is_configured(remote)) + if (!remote_is_configured(remote, 0)) return 0; string_list_append(list, remote->name); } diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 4e9f6c2..df41fa0 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -18,7 +18,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) int i; const char *format = "%(objectname) %(objecttype)\t%(refname)"; struct ref_sorting *sorting = NULL, **sorting_tail = &sorting; - int maxcount = 0, quote_style = 0; + int maxcount = 0, quote_style = 0, icase = 0; struct ref_array array; struct ref_filter filter; @@ -43,6 +43,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) OPT_MERGED(&filter, N_("print only refs that are merged")), OPT_NO_MERGED(&filter, N_("print only refs that are not merged")), OPT_CONTAINS(&filter.with_commit, N_("print only refs which contain the commit")), + OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")), OPT_END(), }; @@ -63,6 +64,8 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) if (!sorting) sorting = ref_default_sorting(); + sorting->ignore_case = icase; + filter.ignore_case = icase; /* for warn_ambiguous_refs */ git_config(git_default_config, NULL); diff --git a/builtin/fsck.c b/builtin/fsck.c index f01b81e..1a5cacc 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -56,6 +56,23 @@ static const char *describe_object(struct object *obj) return buf.buf; } +static const char *printable_type(struct object *obj) +{ + const char *ret; + + if (obj->type == OBJ_NONE) { + enum object_type type = sha1_object_info(obj->oid.hash, NULL); + if (type > 0) + object_as_type(obj, type, 0); + } + + ret = typename(obj->type); + if (!ret) + ret = "unknown"; + + return ret; +} + static int fsck_config(const char *var, const char *value, void *cb) { if (strcmp(var, "fsck.skiplist") == 0) { @@ -83,7 +100,7 @@ static void objreport(struct object *obj, const char *msg_type, const char *err) { fprintf(stderr, "%s in %s %s: %s\n", - msg_type, typename(obj->type), describe_object(obj), err); + msg_type, printable_type(obj), describe_object(obj), err); } static int objerror(struct object *obj, const char *err) @@ -114,7 +131,7 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt if (!obj) { /* ... these references to parent->fld are safe here */ printf("broken link from %7s %s\n", - typename(parent->type), describe_object(parent)); + printable_type(parent), describe_object(parent)); printf("broken link from %7s %s\n", (type == OBJ_ANY ? "unknown" : typename(type)), "unknown"); errors_found |= ERROR_REACHABLE; @@ -131,9 +148,9 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt if (!(obj->flags & HAS_OBJ)) { if (parent && !has_object_file(&obj->oid)) { printf("broken link from %7s %s\n", - typename(parent->type), describe_object(parent)); + printable_type(parent), describe_object(parent)); printf(" to %7s %s\n", - typename(obj->type), describe_object(obj)); + printable_type(obj), describe_object(obj)); errors_found |= ERROR_REACHABLE; } return 1; @@ -205,9 +222,7 @@ static void check_reachable_object(struct object *obj) if (!(obj->flags & HAS_OBJ)) { if (has_sha1_pack(obj->oid.hash)) return; /* it is in pack - forget about it */ - if (connectivity_only && has_object_file(&obj->oid)) - return; - printf("missing %s %s\n", typename(obj->type), + printf("missing %s %s\n", printable_type(obj), describe_object(obj)); errors_found |= ERROR_REACHABLE; return; @@ -225,7 +240,7 @@ static void check_unreachable_object(struct object *obj) * to complain about it being unreachable (since it does * not exist). */ - if (!obj->parsed) + if (!(obj->flags & HAS_OBJ)) return; /* @@ -233,7 +248,7 @@ static void check_unreachable_object(struct object *obj) * since this is something that is prunable. */ if (show_unreachable) { - printf("unreachable %s %s\n", typename(obj->type), + printf("unreachable %s %s\n", printable_type(obj), describe_object(obj)); return; } @@ -252,7 +267,7 @@ static void check_unreachable_object(struct object *obj) */ if (!obj->used) { if (show_dangling) - printf("dangling %s %s\n", typename(obj->type), + printf("dangling %s %s\n", printable_type(obj), describe_object(obj)); if (write_lost_and_found) { char *filename = git_pathdup("lost-found/%s/%s", @@ -326,7 +341,7 @@ static int fsck_obj(struct object *obj) if (verbose) fprintf(stderr, "Checking %s %s\n", - typename(obj->type), describe_object(obj)); + printable_type(obj), describe_object(obj)); if (fsck_walk(obj, NULL, &fsck_obj_options)) objerror(obj, "broken links"); @@ -352,7 +367,7 @@ static int fsck_obj(struct object *obj) struct tag *tag = (struct tag *) obj; if (show_tags && tag->tagged) { - printf("tagged %s %s", typename(tag->tagged->type), + printf("tagged %s %s", printable_type(tag->tagged), describe_object(tag->tagged)); printf(" (%s) in %s\n", tag->tag, describe_object(&tag->object)); @@ -362,18 +377,6 @@ static int fsck_obj(struct object *obj) return 0; } -static int fsck_sha1(const unsigned char *sha1) -{ - struct object *obj = parse_object(sha1); - if (!obj) { - errors_found |= ERROR_OBJECT; - return error("%s: object corrupt or missing", - sha1_to_hex(sha1)); - } - obj->flags |= HAS_OBJ; - return fsck_obj(obj); -} - static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type, unsigned long size, void *buffer, int *eaten) { @@ -400,7 +403,7 @@ static void fsck_handle_reflog_sha1(const char *refname, unsigned char *sha1, if (!is_null_sha1(sha1)) { obj = lookup_object(sha1); - if (obj) { + if (obj && (obj->flags & HAS_OBJ)) { if (timestamp && name_objects) add_decoration(fsck_walk_options.object_names, obj, @@ -488,9 +491,41 @@ static void get_default_heads(void) } } +static struct object *parse_loose_object(const unsigned char *sha1, + const char *path) +{ + struct object *obj; + void *contents; + enum object_type type; + unsigned long size; + int eaten; + + if (read_loose_object(path, sha1, &type, &size, &contents) < 0) + return NULL; + + if (!contents && type != OBJ_BLOB) + die("BUG: read_loose_object streamed a non-blob"); + + obj = parse_object_buffer(sha1, type, size, contents, &eaten); + + if (!eaten) + free(contents); + return obj; +} + static int fsck_loose(const unsigned char *sha1, const char *path, void *data) { - if (fsck_sha1(sha1)) + struct object *obj = parse_loose_object(sha1, path); + + if (!obj) { + errors_found |= ERROR_OBJECT; + error("%s: object corrupt or missing: %s", + sha1_to_hex(sha1), path); + return 0; /* keep checking other objects */ + } + + obj->flags = HAS_OBJ; + if (fsck_obj(obj)) errors_found |= ERROR_OBJECT; return 0; } @@ -584,6 +619,29 @@ static int fsck_cache_tree(struct cache_tree *it) return err; } +static void mark_object_for_connectivity(const unsigned char *sha1) +{ + struct object *obj = lookup_unknown_object(sha1); + obj->flags |= HAS_OBJ; +} + +static int mark_loose_for_connectivity(const unsigned char *sha1, + const char *path, + void *data) +{ + mark_object_for_connectivity(sha1); + return 0; +} + +static int mark_packed_for_connectivity(const unsigned char *sha1, + struct packed_git *pack, + uint32_t pos, + void *data) +{ + mark_object_for_connectivity(sha1); + return 0; +} + static char const * const fsck_usage[] = { N_("git fsck [] [...]"), NULL @@ -640,38 +698,41 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) git_config(fsck_config, NULL); fsck_head_link(); - if (!connectivity_only) { + if (connectivity_only) { + for_each_loose_object(mark_loose_for_connectivity, NULL, 0); + for_each_packed_object(mark_packed_for_connectivity, NULL, 0); + } else { fsck_object_dir(get_object_directory()); prepare_alt_odb(); for (alt = alt_odb_list; alt; alt = alt->next) fsck_object_dir(alt->path); - } - if (check_full) { - struct packed_git *p; - uint32_t total = 0, count = 0; - struct progress *progress = NULL; + if (check_full) { + struct packed_git *p; + uint32_t total = 0, count = 0; + struct progress *progress = NULL; - prepare_packed_git(); + prepare_packed_git(); - if (show_progress) { + if (show_progress) { + for (p = packed_git; p; p = p->next) { + if (open_pack_index(p)) + continue; + total += p->num_objects; + } + + progress = start_progress(_("Checking objects"), total); + } for (p = packed_git; p; p = p->next) { - if (open_pack_index(p)) - continue; - total += p->num_objects; + /* verify gives error messages itself */ + if (verify_pack(p, fsck_obj_buffer, + progress, count)) + errors_found |= ERROR_PACK; + count += p->num_objects; } - - progress = start_progress(_("Checking objects"), total); + stop_progress(&progress); } - for (p = packed_git; p; p = p->next) { - /* verify gives error messages itself */ - if (verify_pack(p, fsck_obj_buffer, - progress, count)) - errors_found |= ERROR_PACK; - count += p->num_objects; - } - stop_progress(&progress); } heads = 0; @@ -681,9 +742,11 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) if (!get_sha1(arg, sha1)) { struct object *obj = lookup_object(sha1); - /* Error is printed by lookup_object(). */ - if (!obj) + if (!obj || !(obj->flags & HAS_OBJ)) { + error("%s: object missing", sha1_to_hex(sha1)); + errors_found |= ERROR_OBJECT; continue; + } obj->used = 1; if (name_objects) @@ -694,6 +757,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) continue; } error("invalid parameter: expected sha1, got '%s'", arg); + errors_found |= ERROR_OBJECT; } /* @@ -701,7 +765,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) * default ones from .git/refs. We also consider the index file * in this case (ie this implies --cache). */ - if (!heads) { + if (!argc) { get_default_heads(); keep_cache_objects = 1; } diff --git a/builtin/grep.c b/builtin/grep.c index 8887b6a..2c727ef 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -18,12 +18,22 @@ #include "quote.h" #include "dir.h" #include "pathspec.h" +#include "submodule.h" +#include "submodule-config.h" static char const * const grep_usage[] = { N_("git grep [] [-e] [...] [[--] ...]"), NULL }; +static const char *super_prefix; +static int recurse_submodules; +static struct argv_array submodule_options = ARGV_ARRAY_INIT; +static const char *parent_basename; + +static int grep_submodule_launch(struct grep_opt *opt, + const struct grep_source *gs); + #define GREP_NUM_THREADS_DEFAULT 8 static int num_threads; @@ -174,7 +184,10 @@ static void *run(void *arg) break; opt->output_priv = w; - hit |= grep_source(opt, &w->source); + if (w->source.type == GREP_SOURCE_SUBMODULE) + hit |= grep_submodule_launch(opt, &w->source); + else + hit |= grep_source(opt, &w->source); grep_source_clear_data(&w->source); work_done(w); } @@ -300,6 +313,10 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, if (opt->relative && opt->prefix_length) { quote_path_relative(filename + tree_name_len, opt->prefix, &pathbuf); strbuf_insert(&pathbuf, 0, filename, tree_name_len); + } else if (super_prefix) { + strbuf_add(&pathbuf, filename, tree_name_len); + strbuf_addstr(&pathbuf, super_prefix); + strbuf_addstr(&pathbuf, filename + tree_name_len); } else { strbuf_addstr(&pathbuf, filename); } @@ -328,10 +345,13 @@ static int grep_file(struct grep_opt *opt, const char *filename) { struct strbuf buf = STRBUF_INIT; - if (opt->relative && opt->prefix_length) + if (opt->relative && opt->prefix_length) { quote_path_relative(filename, opt->prefix, &buf); - else + } else { + if (super_prefix) + strbuf_addstr(&buf, super_prefix); strbuf_addstr(&buf, filename); + } #ifndef NO_PTHREADS if (num_threads) { @@ -378,31 +398,310 @@ static void run_pager(struct grep_opt *opt, const char *prefix) exit(status); } -static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached) +static void compile_submodule_options(const struct grep_opt *opt, + const struct pathspec *pathspec, + int cached, int untracked, + int opt_exclude, int use_index, + int pattern_type_arg) +{ + struct grep_pat *pattern; + int i; + + if (recurse_submodules) + argv_array_push(&submodule_options, "--recurse-submodules"); + + if (cached) + argv_array_push(&submodule_options, "--cached"); + if (!use_index) + argv_array_push(&submodule_options, "--no-index"); + if (untracked) + argv_array_push(&submodule_options, "--untracked"); + if (opt_exclude > 0) + argv_array_push(&submodule_options, "--exclude-standard"); + + if (opt->invert) + argv_array_push(&submodule_options, "-v"); + if (opt->ignore_case) + argv_array_push(&submodule_options, "-i"); + if (opt->word_regexp) + argv_array_push(&submodule_options, "-w"); + switch (opt->binary) { + case GREP_BINARY_NOMATCH: + argv_array_push(&submodule_options, "-I"); + break; + case GREP_BINARY_TEXT: + argv_array_push(&submodule_options, "-a"); + break; + default: + break; + } + if (opt->allow_textconv) + argv_array_push(&submodule_options, "--textconv"); + if (opt->max_depth != -1) + argv_array_pushf(&submodule_options, "--max-depth=%d", + opt->max_depth); + if (opt->linenum) + argv_array_push(&submodule_options, "-n"); + if (!opt->pathname) + argv_array_push(&submodule_options, "-h"); + if (!opt->relative) + argv_array_push(&submodule_options, "--full-name"); + if (opt->name_only) + argv_array_push(&submodule_options, "-l"); + if (opt->unmatch_name_only) + argv_array_push(&submodule_options, "-L"); + if (opt->null_following_name) + argv_array_push(&submodule_options, "-z"); + if (opt->count) + argv_array_push(&submodule_options, "-c"); + if (opt->file_break) + argv_array_push(&submodule_options, "--break"); + if (opt->heading) + argv_array_push(&submodule_options, "--heading"); + if (opt->pre_context) + argv_array_pushf(&submodule_options, "--before-context=%d", + opt->pre_context); + if (opt->post_context) + argv_array_pushf(&submodule_options, "--after-context=%d", + opt->post_context); + if (opt->funcname) + argv_array_push(&submodule_options, "-p"); + if (opt->funcbody) + argv_array_push(&submodule_options, "-W"); + if (opt->all_match) + argv_array_push(&submodule_options, "--all-match"); + if (opt->debug) + argv_array_push(&submodule_options, "--debug"); + if (opt->status_only) + argv_array_push(&submodule_options, "-q"); + + switch (pattern_type_arg) { + case GREP_PATTERN_TYPE_BRE: + argv_array_push(&submodule_options, "-G"); + break; + case GREP_PATTERN_TYPE_ERE: + argv_array_push(&submodule_options, "-E"); + break; + case GREP_PATTERN_TYPE_FIXED: + argv_array_push(&submodule_options, "-F"); + break; + case GREP_PATTERN_TYPE_PCRE: + argv_array_push(&submodule_options, "-P"); + break; + case GREP_PATTERN_TYPE_UNSPECIFIED: + break; + } + + for (pattern = opt->pattern_list; pattern != NULL; + pattern = pattern->next) { + switch (pattern->token) { + case GREP_PATTERN: + argv_array_pushf(&submodule_options, "-e%s", + pattern->pattern); + break; + case GREP_AND: + case GREP_OPEN_PAREN: + case GREP_CLOSE_PAREN: + case GREP_NOT: + case GREP_OR: + argv_array_push(&submodule_options, pattern->pattern); + break; + /* BODY and HEAD are not used by git-grep */ + case GREP_PATTERN_BODY: + case GREP_PATTERN_HEAD: + break; + } + } + + /* + * Limit number of threads for child process to use. + * This is to prevent potential fork-bomb behavior of git-grep as each + * submodule process has its own thread pool. + */ + argv_array_pushf(&submodule_options, "--threads=%d", + (num_threads + 1) / 2); + + /* Add Pathspecs */ + argv_array_push(&submodule_options, "--"); + for (i = 0; i < pathspec->nr; i++) + argv_array_push(&submodule_options, + pathspec->items[i].original); +} + +/* + * Launch child process to grep contents of a submodule + */ +static int grep_submodule_launch(struct grep_opt *opt, + const struct grep_source *gs) +{ + struct child_process cp = CHILD_PROCESS_INIT; + int status, i; + const char *end_of_base; + const char *name; + struct work_item *w = opt->output_priv; + + end_of_base = strchr(gs->name, ':'); + if (gs->identifier && end_of_base) + name = end_of_base + 1; + else + name = gs->name; + + prepare_submodule_repo_env(&cp.env_array); + argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT); + + /* Add super prefix */ + argv_array_pushf(&cp.args, "--super-prefix=%s%s/", + super_prefix ? super_prefix : "", + name); + argv_array_push(&cp.args, "grep"); + + /* + * Add basename of parent project + * When performing grep on a tree object the filename is prefixed + * with the object's name: 'tree-name:filename'. In order to + * provide uniformity of output we want to pass the name of the + * parent project's object name to the submodule so the submodule can + * prefix its output with the parent's name and not its own SHA1. + */ + if (gs->identifier && end_of_base) + argv_array_pushf(&cp.args, "--parent-basename=%.*s", + (int) (end_of_base - gs->name), + gs->name); + + /* Add options */ + for (i = 0; i < submodule_options.argc; i++) { + /* + * If there is a tree identifier for the submodule, add the + * rev after adding the submodule options but before the + * pathspecs. To do this we listen for the '--' and insert the + * sha1 before pushing the '--' onto the child process argv + * array. + */ + if (gs->identifier && + !strcmp("--", submodule_options.argv[i])) { + argv_array_push(&cp.args, sha1_to_hex(gs->identifier)); + } + + argv_array_push(&cp.args, submodule_options.argv[i]); + } + + cp.git_cmd = 1; + cp.dir = gs->path; + + /* + * Capture output to output buffer and check the return code from the + * child process. A '0' indicates a hit, a '1' indicates no hit and + * anything else is an error. + */ + status = capture_command(&cp, &w->out, 0); + if (status && (status != 1)) { + /* flush the buffer */ + write_or_die(1, w->out.buf, w->out.len); + die("process for submodule '%s' failed with exit code: %d", + gs->name, status); + } + + /* invert the return code to make a hit equal to 1 */ + return !status; +} + +/* + * Prep grep structures for a submodule grep + * sha1: the sha1 of the submodule or NULL if using the working tree + * filename: name of the submodule including tree name of parent + * path: location of the submodule + */ +static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1, + const char *filename, const char *path) +{ + if (!is_submodule_initialized(path)) + return 0; + if (!is_submodule_populated(path)) { + /* + * If searching history, check for the presense of the + * submodule's gitdir before skipping the submodule. + */ + if (sha1) { + const struct submodule *sub = + submodule_from_path(null_sha1, path); + if (sub) + path = git_path("modules/%s", sub->name); + + if (!(is_directory(path) && is_git_directory(path))) + return 0; + } else { + return 0; + } + } + +#ifndef NO_PTHREADS + if (num_threads) { + add_work(opt, GREP_SOURCE_SUBMODULE, filename, path, sha1); + return 0; + } else +#endif + { + struct work_item w; + int hit; + + grep_source_init(&w.source, GREP_SOURCE_SUBMODULE, + filename, path, sha1); + strbuf_init(&w.out, 0); + opt->output_priv = &w; + hit = grep_submodule_launch(opt, &w.source); + + write_or_die(1, w.out.buf, w.out.len); + + grep_source_clear(&w.source); + strbuf_release(&w.out); + return hit; + } +} + +static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, + int cached) { int hit = 0; int nr; + struct strbuf name = STRBUF_INIT; + int name_base_len = 0; + if (super_prefix) { + name_base_len = strlen(super_prefix); + strbuf_addstr(&name, super_prefix); + } + read_cache(); for (nr = 0; nr < active_nr; nr++) { const struct cache_entry *ce = active_cache[nr]; - if (!S_ISREG(ce->ce_mode)) - continue; - if (!ce_path_match(ce, pathspec, NULL)) + strbuf_setlen(&name, name_base_len); + strbuf_addstr(&name, ce->name); + + if (S_ISREG(ce->ce_mode) && + match_pathspec(pathspec, name.buf, name.len, 0, NULL, + S_ISDIR(ce->ce_mode) || + S_ISGITLINK(ce->ce_mode))) { + /* + * If CE_VALID is on, we assume worktree file and its + * cache entry are identical, even if worktree file has + * been modified, so use cache version instead + */ + if (cached || (ce->ce_flags & CE_VALID) || + ce_skip_worktree(ce)) { + if (ce_stage(ce) || ce_intent_to_add(ce)) + continue; + hit |= grep_sha1(opt, ce->oid.hash, ce->name, + 0, ce->name); + } else { + hit |= grep_file(opt, ce->name); + } + } else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && + submodule_path_match(pathspec, name.buf, NULL)) { + hit |= grep_submodule(opt, NULL, ce->name, ce->name); + } else { continue; - /* - * If CE_VALID is on, we assume worktree file and its cache entry - * are identical, even if worktree file has been modified, so use - * cache version instead - */ - if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) { - if (ce_stage(ce) || ce_intent_to_add(ce)) - continue; - hit |= grep_sha1(opt, ce->oid.hash, ce->name, 0, - ce->name); } - else - hit |= grep_file(opt, ce->name); + if (ce_stage(ce)) { do { nr++; @@ -413,6 +712,8 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int if (hit && opt->status_only) break; } + + strbuf_release(&name); return hit; } @@ -424,12 +725,22 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, enum interesting match = entry_not_interesting; struct name_entry entry; int old_baselen = base->len; + struct strbuf name = STRBUF_INIT; + int name_base_len = 0; + if (super_prefix) { + strbuf_addstr(&name, super_prefix); + name_base_len = name.len; + } while (tree_entry(tree, &entry)) { int te_len = tree_entry_len(&entry); if (match != all_entries_interesting) { - match = tree_entry_interesting(&entry, base, tn_len, pathspec); + strbuf_addstr(&name, base->buf + tn_len); + match = tree_entry_interesting(&entry, &name, + 0, pathspec); + strbuf_setlen(&name, name_base_len); + if (match == all_entries_not_interesting) break; if (match == entry_not_interesting) @@ -441,8 +752,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, if (S_ISREG(entry.mode)) { hit |= grep_sha1(opt, entry.oid->hash, base->buf, tn_len, check_attr ? base->buf + tn_len : NULL); - } - else if (S_ISDIR(entry.mode)) { + } else if (S_ISDIR(entry.mode)) { enum object_type type; struct tree_desc sub; void *data; @@ -458,12 +768,18 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, hit |= grep_tree(opt, pathspec, &sub, base, tn_len, check_attr); free(data); + } else if (recurse_submodules && S_ISGITLINK(entry.mode)) { + hit |= grep_submodule(opt, entry.oid->hash, base->buf, + base->buf + tn_len); } + strbuf_setlen(base, old_baselen); if (hit && opt->status_only) break; } + + strbuf_release(&name); return hit; } @@ -487,6 +803,10 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, if (!data) die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid)); + /* Use parent's name as base when recursing submodules */ + if (recurse_submodules && parent_basename) + name = parent_basename; + len = name ? strlen(name) : 0; strbuf_init(&base, PATH_MAX + len + 1); if (len) { @@ -513,6 +833,12 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec, for (i = 0; i < nr; i++) { struct object *real_obj; real_obj = deref_tag(list->objects[i].item, NULL, 0); + + /* load the gitmodules file for this rev */ + if (recurse_submodules) { + submodule_free(); + gitmodules_config_sha1(real_obj->oid.hash); + } if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path)) { hit = 1; if (opt->status_only) @@ -651,6 +977,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) N_("search in both tracked and untracked files")), OPT_SET_INT(0, "exclude-standard", &opt_exclude, N_("ignore files specified via '.gitignore'"), 1), + OPT_BOOL(0, "recurse-submodules", &recurse_submodules, + N_("recursivley search in each submodule")), + OPT_STRING(0, "parent-basename", &parent_basename, + N_("basename"), + N_("prepend parent project's basename to output")), OPT_GROUP(""), OPT_BOOL('v', "invert-match", &opt.invert, N_("show non-matching lines")), @@ -755,6 +1086,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) init_grep_defaults(); git_config(grep_cmd_config, NULL); grep_init(&opt, prefix); + super_prefix = get_super_prefix(); /* * If there is no -- then the paths must exist in the working @@ -872,6 +1204,13 @@ int cmd_grep(int argc, const char **argv, const char *prefix) pathspec.max_depth = opt.max_depth; pathspec.recursive = 1; + if (recurse_submodules) { + gitmodules_config(); + compile_submodule_options(&opt, &pathspec, cached, untracked, + opt_exclude, use_index, + pattern_type_arg); + } + if (show_in_pager && (cached || list.nr)) die(_("--open-files-in-pager only works on the worktree")); @@ -895,6 +1234,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) } } + if (recurse_submodules && (!use_index || untracked)) + die(_("option not supported with --recurse-submodules.")); + if (!show_in_pager && !opt.status_only) setup_pager(); diff --git a/builtin/init-db.c b/builtin/init-db.c index 2399b97..1d4d6a0 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -262,7 +262,7 @@ static int create_default_files(const char *template_path, const char *work_tree = get_git_work_tree(); git_config_set("core.bare", "false"); /* allow template config file to override the default */ - if (log_all_ref_updates == -1) + if (log_all_ref_updates == LOG_REFS_UNSET) git_config_set("core.logallrefupdates", "true"); if (needs_work_tree_config(original_git_dir, work_tree)) git_config_set("core.worktree", work_tree); @@ -338,7 +338,7 @@ int init_db(const char *git_dir, const char *real_git_dir, { int reinit; int exist_ok = flags & INIT_DB_EXIST_OK; - char *original_git_dir = xstrdup(real_path(git_dir)); + char *original_git_dir = real_pathdup(git_dir); if (real_git_dir) { struct stat st; @@ -489,7 +489,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0); if (real_git_dir && !is_absolute_path(real_git_dir)) - real_git_dir = xstrdup(real_path(real_git_dir)); + real_git_dir = real_pathdup(real_git_dir); if (argc == 1) { int mkdir_tried = 0; @@ -560,7 +560,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) const char *git_dir_parent = strrchr(git_dir, '/'); if (git_dir_parent) { char *rel = xstrndup(git_dir, git_dir_parent - git_dir); - git_work_tree_cfg = xstrdup(real_path(rel)); + git_work_tree_cfg = real_pathdup(rel); free(rel); } if (!git_work_tree_cfg) diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 1592290..1c0f057 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -369,28 +369,30 @@ static void show_files(struct dir_struct *dir) /* * Prune the index to only contain stuff starting with "prefix" */ -static void prune_cache(const char *prefix) +static void prune_cache(const char *prefix, size_t prefixlen) { - int pos = cache_name_pos(prefix, max_prefix_len); + int pos; unsigned int first, last; + if (!prefix) + return; + pos = cache_name_pos(prefix, prefixlen); if (pos < 0) pos = -pos-1; - memmove(active_cache, active_cache + pos, - (active_nr - pos) * sizeof(struct cache_entry *)); - active_nr -= pos; - first = 0; + first = pos; last = active_nr; while (last > first) { int next = (last + first) >> 1; const struct cache_entry *ce = active_cache[next]; - if (!strncmp(ce->name, prefix, max_prefix_len)) { + if (!strncmp(ce->name, prefix, prefixlen)) { first = next+1; continue; } last = next; } - active_nr = last; + memmove(active_cache, active_cache + pos, + (last - pos) * sizeof(struct cache_entry *)); + active_nr = last - pos; } /* @@ -641,8 +643,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) show_killed || show_modified || show_resolve_undo)) show_cached = 1; - if (max_prefix) - prune_cache(max_prefix); + prune_cache(max_prefix, max_prefix_len); if (with_tree) { /* * Basic sanity check; show-stages and show-unmerged diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index 0e30d86..d7ebeb4 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -31,21 +31,18 @@ static const char * const ls_tree_usage[] = { static int show_recursive(const char *base, int baselen, const char *pathname) { - const char **s; + int i; if (ls_options & LS_RECURSIVE) return 1; - s = pathspec._raw; - if (!s) + if (!pathspec.nr) return 0; - for (;;) { - const char *spec = *s++; + for (i = 0; i < pathspec.nr; i++) { + const char *spec = pathspec.items[i].match; int len, speclen; - if (!spec) - return 0; if (strncmp(base, spec, baselen)) continue; len = strlen(pathname); @@ -59,6 +56,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname) continue; return 1; } + return 0; } static int show_tree(const unsigned char *sha1, struct strbuf *base, @@ -175,8 +173,8 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix) * cannot be lifted until it is converted to use * match_pathspec() or tree_entry_interesting() */ - parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE | - PATHSPEC_EXCLUDE, + parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC & + ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL), PATHSPEC_PREFER_CWD, prefix, argv + 1); for (i = 0; i < pathspec.nr; i++) diff --git a/builtin/merge-index.c b/builtin/merge-index.c index ce356b1..2d1b6db 100644 --- a/builtin/merge-index.c +++ b/builtin/merge-index.c @@ -22,7 +22,7 @@ static int merge_entry(int pos, const char *path) if (strcmp(ce->name, path)) break; found++; - sha1_to_hex_r(hexbuf[stage], ce->oid.hash); + oid_to_hex_r(hexbuf[stage], &ce->oid); xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode); arguments[stage] = hexbuf[stage]; arguments[stage + 4] = ownbuf[stage]; diff --git a/builtin/merge.c b/builtin/merge.c index b65eeaa..a96d4fb 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -46,6 +46,7 @@ static const char * const builtin_merge_usage[] = { N_("git merge [] [...]"), N_("git merge [] HEAD "), N_("git merge --abort"), + N_("git merge --continue"), NULL }; @@ -65,6 +66,7 @@ static int option_renormalize; static int verbosity; static int allow_rerere_auto; static int abort_current_merge; +static int continue_current_merge; static int allow_unrelated_histories; static int show_progress = -1; static int default_to_upstream = 1; @@ -223,6 +225,8 @@ static struct option builtin_merge_options[] = { OPT__VERBOSITY(&verbosity), OPT_BOOL(0, "abort", &abort_current_merge, N_("abort the current in-progress merge")), + OPT_BOOL(0, "continue", &continue_current_merge, + N_("continue the current in-progress merge")), OPT_BOOL(0, "allow-unrelated-histories", &allow_unrelated_histories, N_("allow merging unrelated histories")), OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1), @@ -634,7 +638,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, { static struct lock_file lock; - hold_locked_index(&lock, 1); + hold_locked_index(&lock, LOCK_DIE_ON_ERROR); refresh_cache(REFRESH_QUIET); if (active_cache_changed && write_locked_index(&the_index, &lock, COMMIT_LOCK)) @@ -671,7 +675,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, for (j = common; j; j = j->next) commit_list_insert(j->item, &reversed); - hold_locked_index(&lock, 1); + hold_locked_index(&lock, LOCK_DIE_ON_ERROR); clean = merge_recursive(&o, head, remoteheads->item, reversed, &result); if (clean < 0) @@ -781,7 +785,7 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads) struct commit_list *parents, **pptr = &parents; static struct lock_file lock; - hold_locked_index(&lock, 1); + hold_locked_index(&lock, LOCK_DIE_ON_ERROR); refresh_cache(REFRESH_QUIET); if (active_cache_changed && write_locked_index(&the_index, &lock, COMMIT_LOCK)) @@ -1125,6 +1129,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) const char *best_strategy = NULL, *wt_strategy = NULL; struct commit_list *remoteheads, *p; void *branch_to_free; + int orig_argc = argc; if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(builtin_merge_usage, builtin_merge_options); @@ -1158,6 +1163,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix) int nargc = 2; const char *nargv[] = {"reset", "--merge", NULL}; + if (orig_argc != 2) + usage_msg_opt(_("--abort expects no arguments"), + builtin_merge_usage, builtin_merge_options); + if (!file_exists(git_path_merge_head())) die(_("There is no merge to abort (MERGE_HEAD missing).")); @@ -1166,6 +1175,22 @@ int cmd_merge(int argc, const char **argv, const char *prefix) goto done; } + if (continue_current_merge) { + int nargc = 1; + const char *nargv[] = {"commit", NULL}; + + if (orig_argc != 2) + usage_msg_opt(_("--continue expects no arguments"), + builtin_merge_usage, builtin_merge_options); + + if (!file_exists(git_path_merge_head())) + die(_("There is no merge in progress (MERGE_HEAD missing).")); + + /* Invoke 'git commit' */ + ret = cmd_commit(nargc, nargv, prefix); + goto done; + } + if (read_cache_unmerged()) die_resolve_conflict("merge"); diff --git a/builtin/mv.c b/builtin/mv.c index 2f43877..61d2003 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -4,6 +4,7 @@ * Copyright (C) 2006 Johannes Schindelin */ #include "builtin.h" +#include "pathspec.h" #include "lockfile.h" #include "dir.h" #include "cache-tree.h" @@ -19,31 +20,42 @@ static const char * const builtin_mv_usage[] = { #define DUP_BASENAME 1 #define KEEP_TRAILING_SLASH 2 -static const char **internal_copy_pathspec(const char *prefix, - const char **pathspec, - int count, unsigned flags) +static const char **internal_prefix_pathspec(const char *prefix, + const char **pathspec, + int count, unsigned flags) { int i; const char **result; + int prefixlen = prefix ? strlen(prefix) : 0; ALLOC_ARRAY(result, count + 1); - COPY_ARRAY(result, pathspec, count); - result[count] = NULL; + + /* Create an intermediate copy of the pathspec based on the flags */ for (i = 0; i < count; i++) { - int length = strlen(result[i]); + int length = strlen(pathspec[i]); int to_copy = length; + char *it; while (!(flags & KEEP_TRAILING_SLASH) && - to_copy > 0 && is_dir_sep(result[i][to_copy - 1])) + to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1])) to_copy--; - if (to_copy != length || flags & DUP_BASENAME) { - char *it = xmemdupz(result[i], to_copy); - if (flags & DUP_BASENAME) { - result[i] = xstrdup(basename(it)); - free(it); - } else - result[i] = it; + + it = xmemdupz(pathspec[i], to_copy); + if (flags & DUP_BASENAME) { + result[i] = xstrdup(basename(it)); + free(it); + } else { + result[i] = it; } } - return get_pathspec(prefix, result); + result[count] = NULL; + + /* Prefix the pathspec and free the old intermediate strings */ + for (i = 0; i < count; i++) { + const char *match = prefix_path(prefix, prefixlen, result[i]); + free((char *) result[i]); + result[i] = match; + } + + return result; } static const char *add_slash(const char *path) @@ -126,11 +138,11 @@ int cmd_mv(int argc, const char **argv, const char *prefix) if (--argc < 1) usage_with_options(builtin_mv_usage, builtin_mv_options); - hold_locked_index(&lock_file, 1); + hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); if (read_cache() < 0) die(_("index file corrupt")); - source = internal_copy_pathspec(prefix, argv, argc, 0); + source = internal_prefix_pathspec(prefix, argv, argc, 0); modes = xcalloc(argc, sizeof(enum update_mode)); /* * Keep trailing slash, needed to let @@ -140,16 +152,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix) flags = KEEP_TRAILING_SLASH; if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1])) flags = 0; - dest_path = internal_copy_pathspec(prefix, argv + argc, 1, flags); + dest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags); submodule_gitfile = xcalloc(argc, sizeof(char *)); if (dest_path[0][0] == '\0') /* special case: "." was normalized to "" */ - destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME); + destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME); else if (!lstat(dest_path[0], &st) && S_ISDIR(st.st_mode)) { dest_path[0] = add_slash(dest_path[0]); - destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME); + destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME); } else { if (argc != 1) die(_("destination '%s' is not a directory"), dest_path[0]); diff --git a/builtin/push.c b/builtin/push.c index 9307ad5..5c22e9f 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -568,6 +568,8 @@ int cmd_push(int argc, const char **argv, const char *prefix) flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK; else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) flags |= TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND; + else if (recurse_submodules == RECURSE_SUBMODULES_ONLY) + flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY; if (tags) add_refspec("refs/tags/*"); diff --git a/builtin/read-tree.c b/builtin/read-tree.c index 9bd1fd7..8ba64bc 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -109,34 +109,34 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) { OPTION_CALLBACK, 0, "index-output", NULL, N_("file"), N_("write resulting index to "), PARSE_OPT_NONEG, index_output_cb }, - OPT_SET_INT(0, "empty", &read_empty, - N_("only empty the index"), 1), + OPT_BOOL(0, "empty", &read_empty, + N_("only empty the index")), OPT__VERBOSE(&opts.verbose_update, N_("be verbose")), OPT_GROUP(N_("Merging")), - OPT_SET_INT('m', NULL, &opts.merge, - N_("perform a merge in addition to a read"), 1), - OPT_SET_INT(0, "trivial", &opts.trivial_merges_only, - N_("3-way merge if no file level merging required"), 1), - OPT_SET_INT(0, "aggressive", &opts.aggressive, - N_("3-way merge in presence of adds and removes"), 1), - OPT_SET_INT(0, "reset", &opts.reset, - N_("same as -m, but discard unmerged entries"), 1), + OPT_BOOL('m', NULL, &opts.merge, + N_("perform a merge in addition to a read")), + OPT_BOOL(0, "trivial", &opts.trivial_merges_only, + N_("3-way merge if no file level merging required")), + OPT_BOOL(0, "aggressive", &opts.aggressive, + N_("3-way merge in presence of adds and removes")), + OPT_BOOL(0, "reset", &opts.reset, + N_("same as -m, but discard unmerged entries")), { OPTION_STRING, 0, "prefix", &opts.prefix, N_("/"), N_("read the tree into the index under /"), PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP }, - OPT_SET_INT('u', NULL, &opts.update, - N_("update working tree with merge result"), 1), + OPT_BOOL('u', NULL, &opts.update, + N_("update working tree with merge result")), { OPTION_CALLBACK, 0, "exclude-per-directory", &opts, N_("gitignore"), N_("allow explicitly ignored files to be overwritten"), PARSE_OPT_NONEG, exclude_per_directory_cb }, - OPT_SET_INT('i', NULL, &opts.index_only, - N_("don't check the working tree after merging"), 1), + OPT_BOOL('i', NULL, &opts.index_only, + N_("don't check the working tree after merging")), OPT__DRY_RUN(&opts.dry_run, N_("don't update the index or the work tree")), - OPT_SET_INT(0, "no-sparse-checkout", &opts.skip_sparse_checkout, - N_("skip applying sparse checkout filter"), 1), - OPT_SET_INT(0, "debug-unpack", &opts.debug_unpack, - N_("debug unpack-trees"), 1), + OPT_BOOL(0, "no-sparse-checkout", &opts.skip_sparse_checkout, + N_("skip applying sparse checkout filter")), + OPT_BOOL(0, "debug-unpack", &opts.debug_unpack, + N_("debug unpack-trees")), OPT_END() }; @@ -150,7 +150,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) argc = parse_options(argc, argv, unused_prefix, read_tree_options, read_tree_usage, 0); - hold_locked_index(&lock_file, 1); + hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); prefix_set = opts.prefix ? 1 : 0; if (1 < opts.merge + opts.reset + prefix_set) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index e6b3879..1dbb8a0 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -795,8 +795,8 @@ static char *refuse_unconfigured_deny_msg = "with what you pushed, and will require 'git reset --hard' to match\n" "the work tree to HEAD.\n" "\n" - "You can set 'receive.denyCurrentBranch' configuration variable to\n" - "'ignore' or 'warn' in the remote repository to allow pushing into\n" + "You can set the 'receive.denyCurrentBranch' configuration variable\n" + "to 'ignore' or 'warn' in the remote repository to allow pushing into\n" "its current branch; however, this is not recommended unless you\n" "arranged to update its work tree to match what you pushed in some\n" "other way.\n" @@ -1942,8 +1942,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) run_receive_hook(commands, "post-receive", 1, &push_options); run_update_post_hook(commands); - if (push_options.nr) - string_list_clear(&push_options, 0); + string_list_clear(&push_options, 0); if (auto_gc) { const char *argv_gc_auto[] = { "gc", "--auto", "--quiet", NULL, diff --git a/builtin/remote.c b/builtin/remote.c index e52cf39..5339ed6 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -186,7 +186,7 @@ static int add(int argc, const char **argv) url = argv[1]; remote = remote_get(name); - if (remote_is_configured(remote)) + if (remote_is_configured(remote, 1)) die(_("remote %s already exists."), name); strbuf_addf(&buf2, "refs/heads/test:refs/remotes/%s/test", name); @@ -618,14 +618,14 @@ static int mv(int argc, const char **argv) rename.remote_branches = &remote_branches; oldremote = remote_get(rename.old); - if (!remote_is_configured(oldremote)) + if (!remote_is_configured(oldremote, 1)) die(_("No such remote: %s"), rename.old); if (!strcmp(rename.old, rename.new) && oldremote->origin != REMOTE_CONFIG) return migrate_file(oldremote); newremote = remote_get(rename.new); - if (remote_is_configured(newremote)) + if (remote_is_configured(newremote, 1)) die(_("remote %s already exists."), rename.new); strbuf_addf(&buf, "refs/heads/test:refs/remotes/%s/test", rename.new); @@ -753,7 +753,7 @@ static int rm(int argc, const char **argv) usage_with_options(builtin_remote_rm_usage, options); remote = remote_get(argv[1]); - if (!remote_is_configured(remote)) + if (!remote_is_configured(remote, 1)) die(_("No such remote: %s"), argv[1]); known_remotes.to_delete = remote; @@ -1415,7 +1415,7 @@ static int set_remote_branches(const char *remotename, const char **branches, strbuf_addf(&key, "remote.%s.fetch", remotename); remote = remote_get(remotename); - if (!remote_is_configured(remote)) + if (!remote_is_configured(remote, 1)) die(_("No such remote '%s'"), remotename); if (!add_mode && remove_all_fetch_refspecs(remotename, key.buf)) { @@ -1469,7 +1469,7 @@ static int get_url(int argc, const char **argv) remotename = argv[0]; remote = remote_get(remotename); - if (!remote_is_configured(remote)) + if (!remote_is_configured(remote, 1)) die(_("No such remote '%s'"), remotename); url_nr = 0; @@ -1537,7 +1537,7 @@ static int set_url(int argc, const char **argv) oldurl = newurl; remote = remote_get(remotename); - if (!remote_is_configured(remote)) + if (!remote_is_configured(remote, 1)) die(_("No such remote '%s'"), remotename); if (push_mode) { diff --git a/builtin/reset.c b/builtin/reset.c index c04ac07..8ab915b 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -354,7 +354,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) if (reset_type != SOFT) { struct lock_file *lock = xcalloc(1, sizeof(*lock)); - hold_locked_index(lock, 1); + hold_locked_index(lock, LOCK_DIE_ON_ERROR); if (reset_type == MIXED) { int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN; if (read_from_tree(&pathspec, &oid, intent_to_add)) diff --git a/builtin/rev-list.c b/builtin/rev-list.c index c43decd..0aa93d5 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -237,7 +237,7 @@ static int show_bisect_vars(struct rev_list_info *info, int reaches, int all) cnt = reaches; if (revs->commits) - sha1_to_hex_r(hex, revs->commits->item->object.oid.hash); + oid_to_hex_r(hex, &revs->commits->item->object.oid); if (flags & BISECT_SHOW_ALL) { traverse_commit_list(revs, show_commit, show_object, info); diff --git a/builtin/rm.c b/builtin/rm.c index 3f3e24e..fb79dca 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -59,27 +59,9 @@ static void print_error_files(struct string_list *files_list, } } -static void error_removing_concrete_submodules(struct string_list *files, int *errs) -{ - print_error_files(files, - Q_("the following submodule (or one of its nested " - "submodules)\n" - "uses a .git directory:", - "the following submodules (or one of their nested " - "submodules)\n" - "use a .git directory:", files->nr), - _("\n(use 'rm -rf' if you really want to remove " - "it including all of its history)"), - errs); - string_list_clear(files, 0); -} - -static int check_submodules_use_gitfiles(void) +static void submodules_absorb_gitdir_if_needed(const char *prefix) { int i; - int errs = 0; - struct string_list files = STRING_LIST_INIT_NODUP; - for (i = 0; i < list.nr; i++) { const char *name = list.entry[i].name; int pos; @@ -99,12 +81,9 @@ static int check_submodules_use_gitfiles(void) continue; if (!submodule_uses_gitfile(name)) - string_list_append(&files, name); + absorb_git_dir_into_superproject(prefix, name, + ABSORB_GITDIR_RECURSE_SUBMODULES); } - - error_removing_concrete_submodules(&files, &errs); - - return errs; } static int check_local_mod(struct object_id *head, int index_only) @@ -120,7 +99,6 @@ static int check_local_mod(struct object_id *head, int index_only) int errs = 0; struct string_list files_staged = STRING_LIST_INIT_NODUP; struct string_list files_cached = STRING_LIST_INIT_NODUP; - struct string_list files_submodule = STRING_LIST_INIT_NODUP; struct string_list files_local = STRING_LIST_INIT_NODUP; no_head = is_null_oid(head); @@ -187,7 +165,9 @@ static int check_local_mod(struct object_id *head, int index_only) */ if (ce_match_stat(ce, &st, 0) || (S_ISGITLINK(ce->ce_mode) && - !ok_to_remove_submodule(ce->name))) + bad_to_remove_submodule(ce->name, + SUBMODULE_REMOVAL_DIE_ON_ERROR | + SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED))) local_changes = 1; /* @@ -217,13 +197,8 @@ static int check_local_mod(struct object_id *head, int index_only) else if (!index_only) { if (staged_changes) string_list_append(&files_cached, name); - if (local_changes) { - if (S_ISGITLINK(ce->ce_mode) && - !submodule_uses_gitfile(name)) - string_list_append(&files_submodule, name); - else - string_list_append(&files_local, name); - } + if (local_changes) + string_list_append(&files_local, name); } } print_error_files(&files_staged, @@ -245,8 +220,6 @@ static int check_local_mod(struct object_id *head, int index_only) &errs); string_list_clear(&files_cached, 0); - error_removing_concrete_submodules(&files_submodule, &errs); - print_error_files(&files_local, Q_("the following file has local modifications:", "the following files have local modifications:", @@ -292,7 +265,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) if (!index_only) setup_work_tree(); - hold_locked_index(&lock_file, 1); + hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); if (read_cache() < 0) die(_("index file corrupt")); @@ -340,6 +313,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix) exit(0); } + if (!index_only) + submodules_absorb_gitdir_if_needed(prefix); + /* * If not forced, the file, the index and the HEAD (if exists) * must match; but the file can already been removed, since @@ -356,9 +332,6 @@ int cmd_rm(int argc, const char **argv, const char *prefix) oidclr(&oid); if (check_local_mod(&oid, index_only)) exit(1); - } else if (!index_only) { - if (check_submodules_use_gitfiles()) - exit(1); } /* @@ -391,28 +364,15 @@ int cmd_rm(int argc, const char **argv, const char *prefix) for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (list.entry[i].is_submodule) { - if (is_empty_dir(path)) { - if (!rmdir(path)) { - removed = 1; - if (!remove_path_from_gitmodules(path)) - gitmodules_modified = 1; - continue; - } - } else { - strbuf_reset(&buf); - strbuf_addstr(&buf, path); - if (!remove_dir_recursively(&buf, 0)) { - removed = 1; - if (!remove_path_from_gitmodules(path)) - gitmodules_modified = 1; - strbuf_release(&buf); - continue; - } else if (!file_exists(path)) - /* Submodule was removed by user */ - if (!remove_path_from_gitmodules(path)) - gitmodules_modified = 1; - /* Fallthrough and let remove_path() fail. */ - } + strbuf_reset(&buf); + strbuf_addstr(&buf, path); + if (remove_dir_recursively(&buf, 0)) + die(_("could not remove '%s'"), path); + + removed = 1; + if (!remove_path_from_gitmodules(path)) + gitmodules_modified = 1; + continue; } if (!remove_path(path)) { removed = 1; diff --git a/builtin/shortlog.c b/builtin/shortlog.c index ba0e115..c9585d4 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -117,11 +117,15 @@ static void read_from_stdin(struct shortlog *log) { struct strbuf author = STRBUF_INIT; struct strbuf oneline = STRBUF_INIT; + static const char *author_match[2] = { "Author: ", "author " }; + static const char *committer_match[2] = { "Commit: ", "committer " }; + const char **match; + match = log->committer ? committer_match : author_match; while (strbuf_getline_lf(&author, stdin) != EOF) { const char *v; - if (!skip_prefix(author.buf, "Author: ", &v) && - !skip_prefix(author.buf, "author ", &v)) + if (!skip_prefix(author.buf, match[0], &v) && + !skip_prefix(author.buf, match[1], &v)) continue; while (strbuf_getline_lf(&oneline, stdin) != EOF && oneline.len) @@ -140,6 +144,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit) struct strbuf author = STRBUF_INIT; struct strbuf oneline = STRBUF_INIT; struct pretty_print_context ctx = {0}; + const char *fmt; ctx.fmt = CMIT_FMT_USERFORMAT; ctx.abbrev = log->abbrev; @@ -148,7 +153,9 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit) ctx.date_mode.type = DATE_NORMAL; ctx.output_encoding = get_log_output_encoding(); - format_commit_message(commit, "%an <%ae>", &author, &ctx); + fmt = log->committer ? "%cn <%ce>" : "%an <%ae>"; + + format_commit_message(commit, fmt, &author, &ctx); if (!log->summary) { if (log->user_format) pretty_print_commit(&ctx, commit, &oneline); @@ -238,6 +245,8 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) int nongit = !startup_info->have_repository; const struct option options[] = { + OPT_BOOL('c', "committer", &log.committer, + N_("Group by committer rather than author")), OPT_BOOL('n', "numbered", &log.sort_by_number, N_("sort output according to the number of commits per author")), OPT_BOOL('s', "summary", &log.summary, diff --git a/builtin/show-ref.c b/builtin/show-ref.c index 6d4e669..013d241 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -19,19 +19,34 @@ static const char *exclude_existing_arg; static void show_one(const char *refname, const struct object_id *oid) { - const char *hex = find_unique_abbrev(oid->hash, abbrev); + const char *hex; + struct object_id peeled; + + if (!has_sha1_file(oid->hash)) + die("git show-ref: bad ref %s (%s)", refname, + oid_to_hex(oid)); + + if (quiet) + return; + + hex = find_unique_abbrev(oid->hash, abbrev); if (hash_only) printf("%s\n", hex); else printf("%s %s\n", hex, refname); + + if (!deref_tags) + return; + + if (!peel_ref(refname, peeled.hash)) { + hex = find_unique_abbrev(peeled.hash, abbrev); + printf("%s %s^{}\n", hex, refname); + } } static int show_ref(const char *refname, const struct object_id *oid, int flag, void *cbdata) { - const char *hex; - struct object_id peeled; - if (show_head && !strcmp(refname, "HEAD")) goto match; @@ -54,9 +69,6 @@ static int show_ref(const char *refname, const struct object_id *oid, continue; if (len == reflen) goto match; - /* "--verify" requires an exact match */ - if (verify) - continue; if (refname[reflen - len - 1] == '/') goto match; } @@ -66,26 +78,8 @@ static int show_ref(const char *refname, const struct object_id *oid, match: found_match++; - /* This changes the semantics slightly that even under quiet we - * detect and return error if the repository is corrupt and - * ref points at a nonexistent object. - */ - if (!has_sha1_file(oid->hash)) - die("git show-ref: bad ref %s (%s)", refname, - oid_to_hex(oid)); - - if (quiet) - return 0; - show_one(refname, oid); - if (!deref_tags) - return 0; - - if (!peel_ref(refname, peeled.hash)) { - hex = find_unique_abbrev(peeled.hash, abbrev); - printf("%s %s^{}\n", hex, refname); - } return 0; } @@ -202,10 +196,9 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix) while (*pattern) { struct object_id oid; - if (starts_with(*pattern, "refs/") && + if ((starts_with(*pattern, "refs/") || !strcmp(*pattern, "HEAD")) && !read_ref(*pattern, oid.hash)) { - if (!quiet) - show_one(*pattern, &oid); + show_one(*pattern, &oid); } else if (!quiet) die("'%s' - not a valid ref", *pattern); diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 4beeda5..899dc33 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -317,8 +317,12 @@ static void init_submodule(const char *path, const char *prefix, int quiet) /* Only loads from .gitmodules, no overlay with .git/config */ gitmodules_config(); - if (prefix) { - strbuf_addf(&sb, "%s%s", prefix, path); + if (prefix && get_super_prefix()) + die("BUG: cannot have prefix and superprefix"); + else if (prefix) + displaypath = xstrdup(relative_path(path, prefix, &sb)); + else if (get_super_prefix()) { + strbuf_addf(&sb, "%s%s", get_super_prefix(), path); displaypath = strbuf_detach(&sb, NULL); } else displaypath = xstrdup(path); @@ -403,9 +407,6 @@ static int module_init(int argc, const char **argv, const char *prefix) int i; struct option module_init_options[] = { - OPT_STRING(0, "prefix", &prefix, - N_("path"), - N_("alternative anchor for relative paths")), OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")), OPT_END() }; @@ -498,9 +499,9 @@ static int add_possible_reference_from_superproject( /* * If the alternate object store is another repository, try the - * standard layout with .git/modules//objects + * standard layout with .git/(modules/)+/objects */ - if (ends_with(alt->path, ".git/objects")) { + if (ends_with(alt->path, "/objects")) { char *sm_alternate; struct strbuf sb = STRBUF_INIT; struct strbuf err = STRBUF_INIT; @@ -583,6 +584,7 @@ static int module_clone(int argc, const char **argv, const char *prefix) struct strbuf rel_path = STRBUF_INIT; struct strbuf sb = STRBUF_INIT; struct string_list reference = STRING_LIST_INIT_NODUP; + char *sm_alternate = NULL, *error_strategy = NULL; struct option module_clone_options[] = { OPT_STRING(0, "prefix", &prefix, @@ -624,7 +626,7 @@ static int module_clone(int argc, const char **argv, const char *prefix) module_clone_options); strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), name); - sm_gitdir = xstrdup(absolute_path(sb.buf)); + sm_gitdir = absolute_pathdup(sb.buf); strbuf_reset(&sb); if (!is_absolute_path(path)) { @@ -672,6 +674,20 @@ static int module_clone(int argc, const char **argv, const char *prefix) die(_("could not get submodule directory for '%s'"), path); git_config_set_in_file(p, "core.worktree", relative_path(path, sm_gitdir, &rel_path)); + + /* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */ + git_config_get_string("submodule.alternateLocation", &sm_alternate); + if (sm_alternate) + git_config_set_in_file(p, "submodule.alternateLocation", + sm_alternate); + git_config_get_string("submodule.alternateErrorStrategy", &error_strategy); + if (error_strategy) + git_config_set_in_file(p, "submodule.alternateErrorStrategy", + error_strategy); + + free(sm_alternate); + free(error_strategy); + strbuf_release(&sb); strbuf_release(&rel_path); free(sm_gitdir); @@ -1076,21 +1092,62 @@ static int resolve_remote_submodule_branch(int argc, const char **argv, return 0; } +static int absorb_git_dirs(int argc, const char **argv, const char *prefix) +{ + int i; + struct pathspec pathspec; + struct module_list list = MODULE_LIST_INIT; + unsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES; + + struct option embed_gitdir_options[] = { + OPT_STRING(0, "prefix", &prefix, + N_("path"), + N_("path into the working tree")), + OPT_BIT(0, "--recursive", &flags, N_("recurse into submodules"), + ABSORB_GITDIR_RECURSE_SUBMODULES), + OPT_END() + }; + + const char *const git_submodule_helper_usage[] = { + N_("git submodule--helper embed-git-dir [...]"), + NULL + }; + + argc = parse_options(argc, argv, prefix, embed_gitdir_options, + git_submodule_helper_usage, 0); + + gitmodules_config(); + git_config(submodule_config, NULL); + + if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0) + return 1; + + for (i = 0; i < list.nr; i++) + absorb_git_dir_into_superproject(prefix, + list.entries[i]->name, flags); + + return 0; +} + +#define SUPPORT_SUPER_PREFIX (1<<0) + struct cmd_struct { const char *cmd; int (*fn)(int, const char **, const char *); + unsigned option; }; static struct cmd_struct commands[] = { - {"list", module_list}, - {"name", module_name}, - {"clone", module_clone}, - {"update-clone", update_clone}, - {"relative-path", resolve_relative_path}, - {"resolve-relative-url", resolve_relative_url}, - {"resolve-relative-url-test", resolve_relative_url_test}, - {"init", module_init}, - {"remote-branch", resolve_remote_submodule_branch} + {"list", module_list, 0}, + {"name", module_name, 0}, + {"clone", module_clone, 0}, + {"update-clone", update_clone, 0}, + {"relative-path", resolve_relative_path, 0}, + {"resolve-relative-url", resolve_relative_url, 0}, + {"resolve-relative-url-test", resolve_relative_url_test, 0}, + {"init", module_init, SUPPORT_SUPER_PREFIX}, + {"remote-branch", resolve_remote_submodule_branch, 0}, + {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX}, }; int cmd_submodule__helper(int argc, const char **argv, const char *prefix) @@ -1100,9 +1157,15 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix) die(_("submodule--helper subcommand must be " "called with a subcommand")); - for (i = 0; i < ARRAY_SIZE(commands); i++) - if (!strcmp(argv[1], commands[i].cmd)) + for (i = 0; i < ARRAY_SIZE(commands); i++) { + if (!strcmp(argv[1], commands[i].cmd)) { + if (get_super_prefix() && + !(commands[i].option & SUPPORT_SUPER_PREFIX)) + die(_("%s doesn't support --super-prefix"), + commands[i].cmd); return commands[i].fn(argc - 1, argv + 1, prefix); + } + } die(_("'%s' is not a valid submodule--helper " "subcommand"), argv[1]); diff --git a/builtin/tag.c b/builtin/tag.c index 50e4ae5..e40c4a9 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -24,7 +24,7 @@ static const char * const git_tag_usage[] = { N_("git tag -d ..."), N_("git tag -l [-n[]] [--contains ] [--points-at ]" "\n\t\t[--format=] [--[no-]merged []] [...]"), - N_("git tag -v ..."), + N_("git tag -v [--format=] ..."), NULL }; @@ -66,9 +66,10 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con } typedef int (*each_tag_name_fn)(const char *name, const char *ref, - const unsigned char *sha1); + const unsigned char *sha1, const void *cb_data); -static int for_each_tag_name(const char **argv, each_tag_name_fn fn) +static int for_each_tag_name(const char **argv, each_tag_name_fn fn, + const void *cb_data) { const char **p; char ref[PATH_MAX]; @@ -87,14 +88,14 @@ static int for_each_tag_name(const char **argv, each_tag_name_fn fn) had_error = 1; continue; } - if (fn(*p, ref, sha1)) + if (fn(*p, ref, sha1, cb_data)) had_error = 1; } return had_error; } static int delete_tag(const char *name, const char *ref, - const unsigned char *sha1) + const unsigned char *sha1, const void *cb_data) { if (delete_ref(ref, sha1, 0)) return 1; @@ -103,9 +104,22 @@ static int delete_tag(const char *name, const char *ref, } static int verify_tag(const char *name, const char *ref, - const unsigned char *sha1) + const unsigned char *sha1, const void *cb_data) { - return gpg_verify_tag(sha1, name, GPG_VERIFY_VERBOSE); + int flags; + const char *fmt_pretty = cb_data; + flags = GPG_VERIFY_VERBOSE; + + if (fmt_pretty) + flags = GPG_VERIFY_OMIT_STATUS; + + if (gpg_verify_tag(sha1, name, flags)) + return -1; + + if (fmt_pretty) + pretty_print_ref(name, sha1, fmt_pretty); + + return 0; } static int do_sign(struct strbuf *buffer) @@ -335,6 +349,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) struct ref_filter filter; static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting; const char *format = NULL; + int icase = 0; struct option options[] = { OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'), { OPTION_INTEGER, 'n', NULL, &filter.lines, N_("n"), @@ -370,6 +385,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) N_("print only tags of the object"), 0, parse_opt_object_name }, OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")), + OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")), OPT_END() }; @@ -401,6 +417,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) } if (!sorting) sorting = ref_default_sorting(); + sorting->ignore_case = icase; + filter.ignore_case = icase; if (cmdmode == 'l') { int ret; if (column_active(colopts)) { @@ -424,9 +442,12 @@ int cmd_tag(int argc, const char **argv, const char *prefix) if (filter.merge_commit) die(_("--merged and --no-merged option are only allowed with -l")); if (cmdmode == 'd') - return for_each_tag_name(argv, delete_tag); - if (cmdmode == 'v') - return for_each_tag_name(argv, verify_tag); + return for_each_tag_name(argv, delete_tag, NULL); + if (cmdmode == 'v') { + if (format) + verify_ref_format(format); + return for_each_tag_name(argv, verify_tag, format); + } if (msg.given || msgfile) { if (msg.given && msgfile) diff --git a/builtin/update-index.c b/builtin/update-index.c index f3f07e7..d530e89 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -1012,6 +1012,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) /* We can't free this memory, it becomes part of a linked list parsed atexit() */ lock_file = xcalloc(1, sizeof(struct lock_file)); + /* we will diagnose later if it turns out that we need to update it */ newfd = hold_locked_index(lock_file, 0); if (newfd < 0) lock_error = errno; diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c index 99f8148..5199553 100644 --- a/builtin/verify-tag.c +++ b/builtin/verify-tag.c @@ -12,9 +12,10 @@ #include #include "parse-options.h" #include "gpg-interface.h" +#include "ref-filter.h" static const char * const verify_tag_usage[] = { - N_("git verify-tag [-v | --verbose] ..."), + N_("git verify-tag [-v | --verbose] [--format=] ..."), NULL }; @@ -30,9 +31,11 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix) { int i = 1, verbose = 0, had_error = 0; unsigned flags = 0; + char *fmt_pretty = NULL; const struct option verify_tag_options[] = { OPT__VERBOSE(&verbose, N_("print tag contents")), OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW), + OPT_STRING( 0 , "format", &fmt_pretty, N_("format"), N_("format to use for the output")), OPT_END() }; @@ -46,13 +49,26 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix) if (verbose) flags |= GPG_VERIFY_VERBOSE; + if (fmt_pretty) { + verify_ref_format(fmt_pretty); + flags |= GPG_VERIFY_OMIT_STATUS; + } + while (i < argc) { unsigned char sha1[20]; const char *name = argv[i++]; - if (get_sha1(name, sha1)) + if (get_sha1(name, sha1)) { had_error = !!error("tag '%s' not found.", name); - else if (gpg_verify_tag(sha1, name, flags)) + continue; + } + + if (gpg_verify_tag(sha1, name, flags)) { had_error = 1; + continue; + } + + if (fmt_pretty) + pretty_print_ref(name, sha1, fmt_pretty); } return had_error; } diff --git a/builtin/worktree.c b/builtin/worktree.c index 9a97e37..831fe05 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -125,9 +125,9 @@ static int prune(int ac, const char **av, const char *prefix) { struct option options[] = { OPT__DRY_RUN(&show_only, N_("do not remove, show only")), - OPT__VERBOSE(&verbose, N_("report pruned objects")), + OPT__VERBOSE(&verbose, N_("report pruned working trees")), OPT_EXPIRY_DATE(0, "expire", &expire, - N_("expire objects older than