diff options
584 files changed, 57345 insertions, 17502 deletions
diff --git a/.gitignore b/.gitignore index f1acd3e77..726db7345 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,10 @@ /GIT-CFLAGS /GIT-LDFLAGS /GIT-GUI-VARS +/GIT-PREFIX +/GIT-PYTHON-VARS +/GIT-SCRIPT-DEFINES +/GIT-USER-AGENT /GIT-VERSION-FILE /bin-wrappers/ /git @@ -31,6 +35,7 @@ /git-commit-tree /git-config /git-count-objects +/git-credential /git-credential-cache /git-credential-cache--daemon /git-credential-store @@ -121,6 +126,7 @@ /git-remote-fd /git-remote-ext /git-remote-testgit +/git-remote-testsvn /git-repack /git-replace /git-repo-config @@ -172,7 +178,6 @@ /gitweb/static/gitweb.js /gitweb/static/gitweb.min.* /test-chmtime -/test-credential /test-ctype /test-date /test-delta @@ -191,6 +196,7 @@ /test-run-command /test-sha1 /test-sigchain +/test-string-list /test-subprocess /test-svn-fe /common-cmds.h @@ -9,7 +9,9 @@ Alex Bennée <kernel-hacker@bennee.com> Alexander Gavrilov <angavrilov@gmail.com> Aneesh Kumar K.V <aneesh.kumar@gmail.com> Brian M. Carlson <sandals@crustytoothpaste.ath.cx> +Cheng Renquan <crquan@gmail.com> Chris Shoemaker <c.shoemaker@cox.net> +Dan Johnson <computerdruid@gmail.com> Dana L. How <danahow@gmail.com> Dana L. How <how@deathvalley.cswitch.com> Daniel Barkalow <barkalow@iabervon.org> @@ -18,14 +20,22 @@ David KÃ¥gedal <davidk@lysator.liu.se> David S. Miller <davem@davemloft.net> Deskin Miller <deskinm@umich.edu> Dirk Süsserott <newsletter@dirk.my1.cc> +Eric S. Raymond <esr@thyrsus.com> +Erik Faye-Lund <kusmabite@gmail.com> <kusmabite@googlemail.com> Fredrik Kuivinen <freku045@student.liu.se> +Frédéric Heitzmann <frederic.heitzmann@gmail.com> H. Peter Anvin <hpa@bonde.sc.orionmulti.com> H. Peter Anvin <hpa@tazenda.sc.orionmulti.com> H. Peter Anvin <hpa@trantor.hos.anvin.org> Horst H. von Brand <vonbrand@inf.utfsm.cl> İsmail Dönmez <ismail@pardus.org.tr> +Jakub NarÄ™bski <jnareb@gmail.com> Jay Soffian <jaysoffian+git@gmail.com> +Jeff King <peff@peff.net> <peff@github.com> Joachim Berdal Haga <cjhaga@fys.uio.no> +Johannes Sixt <j6t@kdbg.org> <johannes.sixt@telecom.at> +Johannes Sixt <j6t@kdbg.org> <j.sixt@viscovery.net> +Johannes Sixt <j6t@kdbg.org> <J.Sixt@eudaptics.com> Jon Loeliger <jdl@freescale.com> Jon Seymour <jon@blackcubes.dyndns.org> Jonathan Nieder <jrnieder@uchicago.edu> @@ -37,12 +47,22 @@ Junio C Hamano <gitster@pobox.com> <junio@hera.kernel.org> Junio C Hamano <gitster@pobox.com> <junio@kernel.org> Junio C Hamano <gitster@pobox.com> <junkio@cox.net> Karl Hasselström <kha@treskal.com> +Kevin Leung <kevinlsk@gmail.com> Kent Engstrom <kent@lysator.liu.se> Lars Doelle <lars.doelle@on-line ! de> Lars Doelle <lars.doelle@on-line.de> Li Hong <leehong@pku.edu.cn> +Linus Torvalds <torvalds@linux-foundation.org> <torvalds@woody.linux-foundation.org> +Linus Torvalds <torvalds@linux-foundation.org> <torvalds@osdl.org> +Linus Torvalds <torvalds@linux-foundation.org> <torvalds@g5.osdl.org> +Linus Torvalds <torvalds@linux-foundation.org> <torvalds@evo.osdl.org> +Linus Torvalds <torvalds@linux-foundation.org> <torvalds@ppc970.osdl.org> +Linus Torvalds <torvalds@linux-foundation.org> <torvalds@ppc970.osdl.org.(none)> Lukas Sandström <lukass@etek.chalmers.se> -Martin Langhoff <martin@laptop.org> +Marc-André Lureau <marcandre.lureau@gmail.com> +Mark Rada <marada@uwaterloo.ca> +Martin Langhoff <martin@laptop.org> <martin@catalyst.net.nz> +Martin von Zweigbergk <martinvonz@gmail.com> <martin.von.zweigbergk@gmail.com> Michael Coleman <tutufan@gmail.com> Michael J Gruber <git@drmicha.warpmail.net> <michaeljgruber+gmane@fastmail.fm> Michael W. Olson <mwolson@gnu.org> @@ -51,16 +71,22 @@ Nanako Shiraishi <nanako3@bluebottle.com> Nanako Shiraishi <nanako3@lavabit.com> Nguyá»…n Thái Ngá»c Duy <pclouds@gmail.com> <nico@fluxnic.net> <nico@cam.org> +Peter Krefting <peter@softwolves.pp.se> <peter@svarten.intern.softwolves.pp.se> +Peter Krefting <peter@softwolves.pp.se> <peter@softwolves.pp.se> Philippe Bruhat <book@cpan.org> +Ralf Thielow <ralf.thielow@gmail.com> <ralf.thielow@googlemail.com> Ramsay Allan Jones <ramsay@ramsay1.demon.co.uk> René Scharfe <rene.scharfe@lsrfire.ath.cx> Robert Fitzsimons <robfitz@273k.net> +Robert Zeh <robert.a.zeh@gmail.com> Sam Vilain <sam@vilain.net> Santi Béjar <sbejar@gmail.com> Sean Estabrooks <seanlkml@sympatico.ca> Shawn O. Pearce <spearce@spearce.org> Steven Grimm <koreth@midwinter.com> +Tay Ray Chuan <rctay89@gmail.com> Theodore Ts'o <tytso@mit.edu> +Thomas Rast <trast@inf.ethz.ch> <trast@student.ethz.ch> Tony Luck <tony.luck@intel.com> Uwe Kleine-König <Uwe_Zeisberger@digi.com> Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com> diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index 57da6aade..69f7e9b76 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -112,6 +112,14 @@ For C programs: - We try to keep to at most 80 characters per line. + - We try to support a wide range of C compilers to compile git with, + including old ones. That means that you should not use C99 + initializers, even if a lot of compilers grok it. + + - Variables have to be declared at the beginning of the block. + + - NULL pointers shall be written as NULL, not as 0. + - When declaring pointers, the star sides with the variable name, i.e. "char *string", not "char* string" or "char * string". This makes it easier to understand code diff --git a/Documentation/Makefile b/Documentation/Makefile index 5d76a8407..e53d333e5 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -21,11 +21,33 @@ ARTICLES += git-tools ARTICLES += git-bisect-lk2009 # with their own formatting rules. SP_ARTICLES = user-manual +SP_ARTICLES += howto/new-command SP_ARTICLES += howto/revert-branch-rebase SP_ARTICLES += howto/using-merge-subtree SP_ARTICLES += howto/using-signed-tag-in-pull-request +SP_ARTICLES += howto/use-git-daemon +SP_ARTICLES += howto/update-hook-example +SP_ARTICLES += howto/setup-git-server-over-http +SP_ARTICLES += howto/separating-topic-branches +SP_ARTICLES += howto/revert-a-faulty-merge +SP_ARTICLES += howto/recover-corrupted-blob-object +SP_ARTICLES += howto/rebuild-from-update-hook +SP_ARTICLES += howto/rebase-from-internal-branch +SP_ARTICLES += howto/maintain-git API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt))) SP_ARTICLES += $(API_DOCS) + +TECH_DOCS = technical/index-format +TECH_DOCS += technical/pack-format +TECH_DOCS += technical/pack-heuristics +TECH_DOCS += technical/pack-protocol +TECH_DOCS += technical/protocol-capabilities +TECH_DOCS += technical/protocol-common +TECH_DOCS += technical/racy-git +TECH_DOCS += technical/send-pack-pipeline +TECH_DOCS += technical/shallow +TECH_DOCS += technical/trivial-merge +SP_ARTICLES += $(TECH_DOCS) SP_ARTICLES += technical/api-index DOC_HTML += $(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES)) @@ -44,9 +66,10 @@ man5dir=$(mandir)/man5 man7dir=$(mandir)/man7 # DESTDIR= -ASCIIDOC=asciidoc +ASCIIDOC = asciidoc ASCIIDOC_EXTRA = MANPAGE_XSL = manpage-normal.xsl +XMLTO = xmlto XMLTO_EXTRA = INSTALL?=install RM ?= rm -f @@ -66,12 +89,6 @@ endif -include ../config.mak # -# For asciidoc ... -# -7.1.2, set ASCIIDOC7 -# 8.0-, no extra settings are needed -# - -# # For docbook-xsl ... # -1.68.1, no extra settings are needed? # 1.69.0, set ASCIIDOC_ROFF? @@ -81,9 +98,6 @@ endif # 1.73.0-, no extra settings are needed # -ifndef ASCIIDOC7 -ASCIIDOC_EXTRA += -a asciidoc7compatible -endif ifdef DOCBOOK_XSL_172 ASCIIDOC_EXTRA += -a git-asciidoc-no-roff MANPAGE_XSL = manpage-1.72.xsl @@ -134,15 +148,6 @@ DEFAULT_EDITOR_SQ = $(subst ','\'',$(DEFAULT_EDITOR)) ASCIIDOC_EXTRA += -a 'git-default-editor=$(DEFAULT_EDITOR_SQ)' endif -# -# Please note that there is a minor bug in asciidoc. -# The version after 6.0.3 _will_ include the patch found here: -# http://marc.theaimsgroup.com/?l=git&m=111558757202243&w=2 -# -# Until that version is released you may have to apply the patch -# yourself - yes, all 6 characters of it! -# - QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir QUIET_SUBDIR1 = @@ -248,7 +253,7 @@ clean: $(RM) *.texi *.texi+ *.texi++ git.info gitman.info $(RM) *.pdf $(RM) howto-index.txt howto/*.html doc.dep - $(RM) technical/api-*.html technical/api-index.txt + $(RM) technical/*.html technical/api-index.txt $(RM) $(cmds_txt) *.made $(RM) manpage-base-url.xsl @@ -263,7 +268,7 @@ manpage-base-url.xsl: manpage-base-url.xsl.in %.1 %.5 %.7 : %.xml manpage-base-url.xsl $(QUIET_XMLTO)$(RM) $@ && \ - xmlto -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< + $(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< %.xml : %.txt $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ @@ -281,7 +286,7 @@ technical/api-index.txt: technical/api-index-skel.txt \ $(QUIET_GEN)cd technical && '$(SHELL_PATH_SQ)' ./api-index.sh technical/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../ -$(patsubst %,%.html,$(API_DOCS) technical/api-index): %.html : %.txt +$(patsubst %,%.html,$(API_DOCS) technical/api-index $(TECH_DOCS)): %.html : %.txt $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 -f asciidoc.conf \ $(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) $*.txt @@ -326,7 +331,7 @@ $(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml howto-index.txt: howto-index.sh $(wildcard howto/*.txt) $(QUIET_GEN)$(RM) $@+ $@ && \ - '$(SHELL_PATH_SQ)' ./howto-index.sh $(wildcard howto/*.txt) >$@+ && \ + '$(SHELL_PATH_SQ)' ./howto-index.sh $(sort $(wildcard howto/*.txt)) >$@+ && \ mv $@+ $@ $(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt @@ -362,4 +367,7 @@ require-htmlrepo:: quick-install-html: require-htmlrepo '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REPO) $(DESTDIR)$(htmldir) +print-man1: + @for i in $(MAN1_TXT); do echo $$i; done + .PHONY: FORCE diff --git a/Documentation/RelNotes/1.5.2.1.txt b/Documentation/RelNotes/1.5.2.1.txt index ebf20e22a..d41984df0 100644 --- a/Documentation/RelNotes/1.5.2.1.txt +++ b/Documentation/RelNotes/1.5.2.1.txt @@ -45,9 +45,3 @@ Fixes since v1.5.2 - git-fastimport --import-marks was broken; fixed. - A lot of documentation updates, clarifications and fixes. - --- -exec >/var/tmp/1 -O=v1.5.2-65-g996e2d6 -echo O=`git describe refs/heads/maint` -git shortlog --no-merges $O..refs/heads/maint diff --git a/Documentation/RelNotes/1.6.0.2.txt b/Documentation/RelNotes/1.6.0.2.txt index e1e24b329..7d8fb85e1 100644 --- a/Documentation/RelNotes/1.6.0.2.txt +++ b/Documentation/RelNotes/1.6.0.2.txt @@ -79,9 +79,3 @@ Fixes since v1.6.0.1 packfile. Also contains many documentation updates. - --- -exec >/var/tmp/1 -O=v1.6.0.1-78-g3632cfc -echo O=$(git describe maint) -git shortlog --no-merges $O..maint diff --git a/Documentation/RelNotes/1.6.1.3.txt b/Documentation/RelNotes/1.6.1.3.txt index 6f0bde156..cd08d8174 100644 --- a/Documentation/RelNotes/1.6.1.3.txt +++ b/Documentation/RelNotes/1.6.1.3.txt @@ -26,7 +26,3 @@ Fixes since v1.6.1.2 * RPM binary package installed the html manpages in a wrong place. Also includes minor documentation fixes and updates. - - --- -git shortlog --no-merges v1.6.1.2-33-gc789350.. diff --git a/Documentation/RelNotes/1.6.1.4.txt b/Documentation/RelNotes/1.6.1.4.txt index 0ce6316d7..ccbad794c 100644 --- a/Documentation/RelNotes/1.6.1.4.txt +++ b/Documentation/RelNotes/1.6.1.4.txt @@ -39,6 +39,3 @@ Fixes since v1.6.1.3 This fix was first merged to 1.6.2.3. Also includes minor documentation fixes and updates. - --- -git shortlog --no-merges v1.6.1.3.. diff --git a/Documentation/RelNotes/1.6.1.txt b/Documentation/RelNotes/1.6.1.txt index adb7ccab0..7b152a6fd 100644 --- a/Documentation/RelNotes/1.6.1.txt +++ b/Documentation/RelNotes/1.6.1.txt @@ -278,9 +278,3 @@ release, unless otherwise noted. * "gitweb" did not mark non-ASCII characters imported from external HTML fragments correctly. - --- -exec >/var/tmp/1 -O=v1.6.1-rc3-74-gf66bc5f -echo O=$(git describe master) -git shortlog --no-merges $O..master ^maint diff --git a/Documentation/RelNotes/1.7.12.1.txt b/Documentation/RelNotes/1.7.12.1.txt new file mode 100644 index 000000000..b8f04af19 --- /dev/null +++ b/Documentation/RelNotes/1.7.12.1.txt @@ -0,0 +1,134 @@ +Git 1.7.12.1 Release Notes +========================== + +Fixes since v1.7.12 +------------------- + + * "git apply -p0" did not parse pathnames on "diff --git" line + correctly. This caused patches that had pathnames in no other + places to be mistakenly rejected (most notably, binary patch that + does not rename nor change mode). Textual patches, renames or mode + changes have preimage and postimage pathnames in different places + in a form that can be parsed unambiguously and did not suffer from + this problem. + + * "git cherry-pick A C B" used to replay changes in A and then B and + then C if these three commits had committer timestamps in that + order, which is not what the user who said "A C B" naturally + expects. + + * "git commit --amend" let the user edit the log message and then + died when the human-readable committer name was given + insufficiently by getpwent(3). + + * Some capabilities were asked by fetch-pack even when upload-pack + did not advertise that they are available. fetch-pack has been + fixed not to do so. + + * "git diff" had a confusion between taking data from a path in the + working tree and taking data from an object that happens to have + name 0{40} recorded in a tree. + + * "git for-each-ref" did not correctly support more than one --sort + option. + + * "git log .." errored out saying it is both rev range and a path + when there is no disambiguating "--" is on the command line. + Update the command line parser to interpret ".." as a path in such + a case. + + * The "--topo-order", "--date-order" (and the lack of either means + the default order) options to "rev-list" and "log" family of + commands were poorly described in the documentation. + + * "git prune" without "-v" used to warn about leftover temporary + files (which is an indication of an earlier aborted operation). + + * Pushing to smart HTTP server with recent Git fails without having + the username in the URL to force authentication, if the server is + configured to allow GET anonymously, while requiring authentication + for POST. + + * The reflog entries left by "git rebase" and "git rebase -i" were + inconsistent (the interactive one gave an abbreviated object name). + + * When "git push" triggered the automatic gc on the receiving end, a + message from "git prune" that said it was removing cruft leaked to + the standard output, breaking the communication protocol. + + * "git show --quiet" ought to be a synonym for "git show -s", but + wasn't. + + * "git show --format='%ci'" did not give timestamp correctly for + commits created without human readable name on "committer" line. + + * "git send-email" did not unquote encoded words that appear on the + header correctly, and lost "_" from strings. + + * The interactive prompt "git send-email" gives was error prone. It + asked "What e-mail address do you want to use?" with the address it + guessed (correctly) the user would want to use in its prompt, + tempting the user to say "y". But the response was taken as "No, + please use 'y' as the e-mail address instead", which is most + certainly not what the user meant. + + * "gitweb" when used with PATH_INFO failed to notice directories with + SP (and other characters that need URL-style quoting) in them. + + * When the user gives an argument that can be taken as both a + revision name and a pathname without disambiguating with "--", we + used to give a help message "Use '--' to separate". The message + has been clarified to show where that '--' goes on the command + line. + + * When the user exports a non-default IFS without HT, scripts that + rely on being able to parse "ls-files -s | while read a b c..." + started to fail. Protect them from such a misconfiguration. + + * The attribute system may be asked for a path that itself or its + leading directories no longer exists in the working tree, and it is + fine if we cannot open .gitattribute file in such a case. Failure + to open per-directory .gitattributes with error status other than + ENOENT and ENOTDIR should be diagnosed, but it wasn't. + + * After "gitk" showed the contents of a tag, neither "Reread + references" nor "Reload" did not update what is shown as the + contents of it, when the user overwrote the tag with "git tag -f". + + * "ciabot" script (in contrib/) has been updated with extensive + documentation. + + * "git-jump" script (in contrib/) did not work well when + diff.noprefix or diff.mnemonicprefix is in effect. + + * Older parts of the documentation described as if having a regular + file in .git/refs/ hierarchy were the only way to have branches and + tags, which is not true for quite some time. + + * A utility shell function test_seq has been added as a replacement + for the 'seq' utility found on some platforms. + + * Compatibility wrapper to learn the maximum number of file + descriptors we can open around sysconf(_SC_OPEN_MAX) and + getrlimit(RLIMIT_NO_FILE) has been introduced for portability. + + * We used curl_easy_strerror() without checking version of cURL, + breaking the build for versions before curl 7.12.0. + + * Code to work around MacOS X UTF-8 gotcha has been cleaned up. + + * Fallback 'getpass' implementation made unportable use of stdio API. + + * The "--rebase" option to "git pull" can be abbreviated to "-r", + but we didn't document it. + + * It was generally understood that "--long-option"s to many of our + subcommands can be abbreviated to the unique prefix, but it was not + easy to find it described for new readers of the documentation set. + + * The synopsis said "checkout [-B branch]" to make it clear the + branch name is a parameter to the option, but the heading for the + option description was "-B::", not "-B branch::", making the + documentation misleading. + +Also contains numerous documentation updates. diff --git a/Documentation/RelNotes/1.7.12.2.txt b/Documentation/RelNotes/1.7.12.2.txt new file mode 100644 index 000000000..69255745e --- /dev/null +++ b/Documentation/RelNotes/1.7.12.2.txt @@ -0,0 +1,40 @@ +Git 1.7.12.2 Release Notes +========================== + +Fixes since v1.7.12.1 +--------------------- + + * When "git am" is fed an input that has multiple "Content-type: ..." + header, it did not grok charset= attribute correctly. + + * Even during a conflicted merge, "git blame $path" always meant to + blame uncommitted changes to the "working tree" version; make it + more useful by showing cleanly merged parts as coming from the other + branch that is being merged. + + * "git blame MAKEFILE" run in a history that has "Makefile" but not + "MAKEFILE" should say "No such file MAKEFILE in HEAD", but got + confused on a case insensitive filesystem and failed to do so. + + * "git fetch --all", when passed "--no-tags", did not honor the + "--no-tags" option while fetching from individual remotes (the same + issue existed with "--tags", but combination "--all --tags" makes + much less sense than "--all --no-tags"). + + * "git log/diff/format-patch --stat" showed the "N line(s) added" + comment in user's locale and caused careless submitters to send + patches with such a line in them to projects whose project language + is not their language, mildly irritating others. Localization to + the line has been disabled for now. + + * "git log --all-match --grep=A --grep=B" ought to show commits that + mention both A and B, but when these three options are used with + --author or --committer, it showed commits that mention either A or + B (or both) instead. + + * The subcommand to remove the definition of a remote in "git remote" + was named "rm" even though all other subcommands were spelled out. + Introduce "git remote remove" to remove confusion, and keep "rm" as + a backward compatible synonym. + +Also contains a handful of documentation updates. diff --git a/Documentation/RelNotes/1.7.12.3.txt b/Documentation/RelNotes/1.7.12.3.txt new file mode 100644 index 000000000..ecda427a3 --- /dev/null +++ b/Documentation/RelNotes/1.7.12.3.txt @@ -0,0 +1,34 @@ +Git 1.7.12.3 Release Notes +========================== + +Fixes since v1.7.12.2 +--------------------- + + * "git am" mishandled a patch attached as application/octet-stream + (e.g. not text/*); Content-Transfer-Encoding (e.g. base64) was not + honored correctly. + + * It was unclear in the documentation for "git blame" that it is + unnecessary for users to use the "--follow" option. + + * A repository created with "git clone --single" had its fetch + refspecs set up just like a clone without "--single", leading the + subsequent "git fetch" to slurp all the other branches, defeating + the whole point of specifying "only this branch". + + * "git fetch" over http had an old workaround for an unlikely server + misconfiguration; it turns out that this hurts debuggability of the + configuration in general, and has been reverted. + + * "git fetch" over http advertised that it supports "deflate", which + is much less common, and did not advertise the more common "gzip" on + its Accept-Encoding header. + + * "git receive-pack" (the counterpart to "git push") did not give + progress output while processing objects it received to the puser + when run over the smart-http protocol. + + * "git status" honored the ignore=dirty settings in .gitmodules but + "git commit" didn't. + +Also contains a handful of documentation updates. diff --git a/Documentation/RelNotes/1.7.12.4.txt b/Documentation/RelNotes/1.7.12.4.txt new file mode 100644 index 000000000..c6da3cc93 --- /dev/null +++ b/Documentation/RelNotes/1.7.12.4.txt @@ -0,0 +1,23 @@ +Git 1.7.12.4 Release Notes +========================== + +Fixes since v1.7.12.3 +--------------------- + + * "git fetch" over the dumb-http revision walker could segfault when + curl's multi interface was used. + + * It was possible to give specific paths for "asciidoc" and other + tools in the documentation toolchain, but not for "xmlto". + + * "gitweb" did not give the correct committer timezone in its feed + output due to a typo. + + * The "-Xours" (and similarly -Xtheirs) backend option to "git + merge -s recursive" was ignored for binary files. Now it is + honored. + + * The "binary" synthetic attribute made "diff" to treat the path as + binary, but not "merge". + +Also contains many documentation updates. diff --git a/Documentation/RelNotes/1.7.12.txt b/Documentation/RelNotes/1.7.12.txt new file mode 100644 index 000000000..010d8c7de --- /dev/null +++ b/Documentation/RelNotes/1.7.12.txt @@ -0,0 +1,136 @@ +Git v1.7.12 Release Notes +========================= + +Updates since v1.7.11 +--------------------- + +UI, Workflows & Features + + * Git can be told to normalize pathnames it read from readdir(3) and + all arguments it got from the command line into precomposed UTF-8 + (assuming that they come as decomposed UTF-8), in order to work + around issues on Mac OS. + + I think there still are other places that need conversion + (e.g. paths that are read from stdin for some commands), but this + should be a good first step in the right direction. + + * Per-user $HOME/.gitconfig file can optionally be stored in + $HOME/.config/git/config instead, which is in line with XDG. + + * The value of core.attributesfile and core.excludesfile default to + $HOME/.config/git/attributes and $HOME/.config/git/ignore respectively + when these files exist. + + * Logic to disambiguate abbreviated object names have been taught to + take advantage of object types that are expected in the context, + e.g. XXXXXX in the "git describe" output v1.2.3-gXXXXXX must be a + commit object, not a blob nor a tree. This will help us prolong + the lifetime of abbreviated object names. + + * "git apply" learned to wiggle the base version and perform three-way + merge when a patch does not exactly apply to the version you have. + + * Scripted Porcelain writers now have access to the credential API via + the "git credential" plumbing command. + + * "git help" used to always default to "man" format even on platforms + where "man" viewer is not widely available. + + * "git clone --local $path" started its life as an experiment to + optionally use link/copy when cloning a repository on the disk, but + we didn't deprecate it after we made the option a no-op to always + use the optimization. The command learned "--no-local" option to + turn this off, as a more explicit alternative over use of file:// + URL. + + * "git fetch" and friends used to say "remote side hung up + unexpectedly" when they failed to get response they expect from the + other side, but one common reason why they don't get expected + response is that the remote repository does not exist or cannot be + read. The error message in this case was updated to give better + hints to the user. + + * "git help -w $cmd" can show HTML version of documentation for + "git-$cmd" by setting help.htmlpath to somewhere other than the + default location where the build procedure installs them locally; + the variable can even point at a http:// URL. + + * "git rebase [-i] --root $tip" can now be used to rewrite all the + history leading to "$tip" down to the root commit. + + * "git rebase -i" learned "-x <cmd>" to insert "exec <cmd>" after + each commit in the resulting history. + + * "git status" gives finer classification to various states of paths + in conflicted state and offer advice messages in its output. + + * "git submodule" learned to deal with nested submodule structure + where a module is contained within a module whose origin is + specified as a relative URL to its superproject's origin. + + * A rather heavy-ish "git completion" script has been split to create + a separate "git prompting" script, to help lazy-autoloading of the + completion part while making prompting part always available. + + * "gitweb" pays attention to various forms of credits that are + similar to "Signed-off-by:" lines in the commit objects and + highlights them accordingly. + + +Foreign Interface + + * "mediawiki" remote helper (in contrib/) learned to handle file + attachments. + + * "git p4" now uses "Jobs:" and "p4 move" when appropriate. + + * vcs-svn has been updated to clean-up compilation, lift 32-bit + limitations, etc. + + +Performance, Internal Implementation, etc. (please report possible regressions) + + * Some tests showed false failures caused by a bug in ecryptofs. + + * We no longer use AsciiDoc7 syntax in our documentation and favor a + more modern style. + + * "git am --rebasing" codepath was taught to grab authorship, log + message and the patch text directly out of existing commits. This + will help rebasing commits that have confusing "diff" output in + their log messages. + + * "git index-pack" and "git pack-objects" use streaming API to read + from the object store to avoid having to hold a large blob object + in-core while they are doing their thing. + + * Code to match paths with exclude patterns learned to avoid calling + fnmatch() by comparing fixed leading substring literally when + possible. + + * "git log -n 1 -- rarely-touched-path" was spending unnecessary + cycles after showing the first change to find the next one, only to + discard it. + + * "git svn" got a large-looking code reorganization at the last + minute before the code freeze. + + +Also contains minor documentation updates and code clean-ups. + + +Fixes since v1.7.11 +------------------- + +Unless otherwise noted, all the fixes since v1.7.11 in the maintenance +releases are contained in this release (see release notes to them for +details). + + * "git submodule add" was confused when the superproject did not have + its repository in its usual place in the working tree and GIT_DIR + and GIT_WORK_TREE was used to access it. + + * "git commit --amend" let the user edit the log message and then died + when the human-readable committer name was given insufficiently by + getpwent(3). diff --git a/Documentation/RelNotes/1.8.0.1.txt b/Documentation/RelNotes/1.8.0.1.txt new file mode 100644 index 000000000..1f372fa0b --- /dev/null +++ b/Documentation/RelNotes/1.8.0.1.txt @@ -0,0 +1,64 @@ +Git v1.8.0.1 Release Notes +========================== + +Fixes since v1.8.0 +------------------ + + * The configuration parser had an unnecessary hardcoded limit on + variable names that was not checked consistently. + + * The "say" function in the test scaffolding incorrectly allowed + "echo" to interpret "\a" as if it were a C-string asking for a + BEL output. + + * "git mergetool" feeds /dev/null as a common ancestor when dealing + with an add/add conflict, but p4merge backend cannot handle + it. Work it around by passing a temporary empty file. + + * "git log -F -E --grep='<ere>'" failed to use the given <ere> + pattern as extended regular expression, and instead looked for the + string literally. + + * "git grep -e pattern <tree>" asked the attribute system to read + "<tree>:.gitattributes" file in the working tree, which was + nonsense. + + * A symbolic ref refs/heads/SYM was not correctly removed with "git + branch -d SYM"; the command removed the ref pointed by SYM + instead. + + * Earlier we fixed documentation to hyphenate "remote-tracking branch" + to clarify that these are not a remote entity, but unhyphenated + spelling snuck in to a few places since then. + + * "git pull --rebase" run while the HEAD is detached tried to find + the upstream branch of the detached HEAD (which by definition + does not exist) and emitted unnecessary error messages. + + * The refs/replace hierarchy was not mentioned in the + repository-layout docs. + + * Sometimes curl_multi_timeout() function suggested a wrong timeout + value when there is no file descriptors to wait on and the http + transport ended up sleeping for minutes in select(2) system call. + A workaround has been added for this. + + * Various rfc2047 quoting issues around a non-ASCII name on the + From: line in the output from format-patch have been corrected. + + * "git diff -G<pattern>" did not honor textconv filter when looking + for changes. + + * Bash completion script (in contrib/) did not correctly complete a + lazy "git checkout $name_of_remote_tracking_branch_that_is_unique" + command line. + + * RSS feed from "gitweb" had a xss hole in its title output. + + * "git config --path $key" segfaulted on "[section] key" (a boolean + "true" spelled without "=", not "[section] key = true"). + + * "git checkout -b foo" while on an unborn branch did not say + "Switched to a new branch 'foo'" like other cases. + +Also contains other minor fixes and documentation updates. diff --git a/Documentation/RelNotes/1.8.0.2.txt b/Documentation/RelNotes/1.8.0.2.txt new file mode 100644 index 000000000..8497e051d --- /dev/null +++ b/Documentation/RelNotes/1.8.0.2.txt @@ -0,0 +1,34 @@ +Git v1.8.0.2 Release Notes +========================== + +Fixes since v1.8.0.1 +-------------------- + + * Various codepaths have workaround for a common misconfiguration to + spell "UTF-8" as "utf8", but it was not used uniformly. Most + notably, mailinfo (which is used by "git am") lacked this support. + + * We failed to mention a file without any content change but whose + permission bit was modified, or (worse yet) a new file without any + content in the "git diff --stat" output. + + * When "--stat-count" hides a diffstat for binary contents, the total + number of added and removed lines at the bottom was computed + incorrectly. + + * When "--stat-count" hides a diffstat for unmerged paths, the total + number of affected files at the bottom of the "diff --stat" output + was computed incorrectly. + + * "diff --shortstat" miscounted the total number of affected files + when there were unmerged paths. + + * "git p4" used to try expanding malformed "$keyword$" that spans + across multiple lines. + + * "git update-ref -d --deref SYM" to delete a ref through a symbolic + ref that points to it did not remove it correctly. + + * Syntax highlighting in "gitweb" was not quite working. + +Also contains other minor fixes and documentation updates. diff --git a/Documentation/RelNotes/1.8.0.3.txt b/Documentation/RelNotes/1.8.0.3.txt new file mode 100644 index 000000000..92b1e4b36 --- /dev/null +++ b/Documentation/RelNotes/1.8.0.3.txt @@ -0,0 +1,14 @@ +Git v1.8.0.3 Release Notes +========================== + +Fixes since v1.8.0.2 +-------------------- + + * "git log -p -S<string>" did not apply the textconv filter while + looking for the <string>. + + * In the documentation, some invalid example e-mail addresses were + formatted into mailto: links. + +Also contains many documentation updates backported from the 'master' +branch that is preparing for the upcoming 1.8.1 release. diff --git a/Documentation/RelNotes/1.8.0.txt b/Documentation/RelNotes/1.8.0.txt new file mode 100644 index 000000000..43883c14f --- /dev/null +++ b/Documentation/RelNotes/1.8.0.txt @@ -0,0 +1,267 @@ +Git v1.8.0 Release Notes +======================== + +Backward compatibility notes +---------------------------- + +In the next major release (not *this* one), we will change the +behavior of the "git push" command. + +When "git push [$there]" does not say what to push, we have used the +traditional "matching" semantics so far (all your branches were sent +to the remote as long as there already are branches of the same name +over there). We will use the "simple" semantics that pushes the +current branch to the branch with the same name, only when the current +branch is set to integrate with that remote branch. There is a user +preference configuration variable "push.default" to change this, and +"git push" will warn about the upcoming change until you set this +variable in this release. + +"git branch --set-upstream" is deprecated and may be removed in a +relatively distant future. "git branch [-u|--set-upstream-to]" has +been introduced with a saner order of arguments. + + +Updates since v1.7.12 +--------------------- + +UI, Workflows & Features + + * A credential helper for Win32 to allow access to the keychain of + the logged-in user has been added. + + * An initial port to HP NonStop. + + * A credential helper to allow access to the Gnome keyring has been + added. + + * When "git am" sanitizes the "Subject:" line, we strip the prefix from + "Re: subject" and also from a less common "re: subject", but left + the even less common "RE: subject" intact. Now we strip that too. + + * It was tempting to say "git branch --set-upstream origin/master", + but that tells Git to arrange the local branch "origin/master" to + integrate with the currently checked out branch, which is highly + unlikely what the user meant. The option is deprecated; use the + new "--set-upstream-to" (with a short-and-sweet "-u") option + instead. + + * "git cherry-pick" learned the "--allow-empty-message" option to + allow it to replay a commit without any log message. + + * After "git cherry-pick -s" gave control back to the user asking + help to resolve conflicts, concluding "git commit" used to need to + be run with "-s" if the user wants to sign it off; now the command + leaves the sign-off line in the log template. + + * "git daemon" learned the "--access-hook" option to allow an + external command to decline service based on the client address, + repository path, etc. + + * "git difftool --dir-diff" learned to use symbolic links to prepare + a temporary copy of the working tree when available. + + * "git grep" learned to use a non-standard pattern type by default if + a configuration variable tells it to. + + * Accumulated updates to "git gui" has been merged. + + * "git log -g" learned the "--grep-reflog=<pattern>" option to limit + its output to commits with a reflog message that matches the given + pattern. + + * "git merge-base" learned the "--is-ancestor A B" option to tell if A is + an ancestor of B. The result is indicated by its exit status code. + + * "git mergetool" now allows users to override the actual command used + with the mergetool.$name.cmd configuration variable even for built-in + mergetool backends. + + * "git rebase -i" learned the "--edit-todo" option to open an editor + to edit the instruction sheet. + + +Foreign Interface + + * "git svn" has been updated to work with SVN 1.7. + + * "git p4" learned the "--conflicts" option to specify what to do when + encountering a conflict during "p4 submit". + + +Performance, Internal Implementation, etc. + + * Git ships with a fall-back regexp implementation for platforms with + buggy regexp library, but it was easy for people to keep using their + platform regexp by mistake. A new test has been added to check this. + + * The "check-docs" build target has been updated and greatly + simplified. + + * The test suite is run under MALLOC_CHECK_ when running with a glibc + that supports the feature. + + * The documentation in the TeXinfo format was using indented output + for materials meant to be examples that are better typeset in + monospace. + + * Compatibility wrapper around some mkdir(2) implementations that + reject parameters with trailing slash has been introduced. + + * Compatibility wrapper for systems that lack usable setitimer() has + been added. + + * The option parsing of "git checkout" had error checking, dwim and + defaulting missing options, all mixed in the code, and issuing an + appropriate error message with useful context was getting harder. + The code has been reorganized to allow giving a proper diagnosis + when the user says "git checkout -b -t foo bar" (e.g. "-t" is not a + good name for a branch). + + * Many internal uses of a "git merge-base" equivalent were only to see + if one commit fast-forwards to the other, which did not need the + full set of merge bases to be computed. They have been updated to + use less expensive checks. + + * The heuristics to detect and silently convert latin1 to utf8 when + we were told to use utf-8 in the log message has been transplanted + from "mailinfo" to "commit" and "commit-tree". + + * Messages given by "git <subcommand> -h" from many subcommands have + been marked for translation. + + +Also contains minor documentation updates and code clean-ups. + + +Fixes since v1.7.12 +------------------- + +Unless otherwise noted, all the fixes since v1.7.12 in the +maintenance track are contained in this release (see release notes +to them for details). + + * The attribute system may be asked for a path that itself or its + leading directories no longer exists in the working tree, and it is + fine if we cannot open .gitattribute file in such a case. Failure + to open per-directory .gitattributes with error status other than + ENOENT and ENOTDIR should be diagnosed, but it wasn't. + + * When looking for $HOME/.gitconfig etc., it is OK if we cannot read + them because they do not exist, but we did not diagnose existing + files that we cannot read. + + * When "git am" is fed an input that has multiple "Content-type: ..." + header, it did not grok charset= attribute correctly. + + * "git am" mishandled a patch attached as application/octet-stream + (e.g. not text/*); Content-Transfer-Encoding (e.g. base64) was not + honored correctly. + + * "git blame MAKEFILE" run in a history that has "Makefile" but not + "MAKEFILE" should say "No such file MAKEFILE in HEAD", but got + confused on a case insensitive filesystem and failed to do so. + + * Even during a conflicted merge, "git blame $path" always meant to + blame uncommitted changes to the "working tree" version; make it + more useful by showing cleanly merged parts as coming from the other + branch that is being merged. + + * It was unclear in the documentation for "git blame" that it is + unnecessary for users to use the "--follow" option. + + * Output from "git branch -v" contains "(no branch)" that could be + localized, but the code to align it along with the names of + branches was counting in bytes, not in display columns. + + * "git cherry-pick A C B" used to replay changes in A and then B and + then C if these three commits had committer timestamps in that + order, which is not what the user who said "A C B" naturally + expects. + + * A repository created with "git clone --single" had its fetch + refspecs set up just like a clone without "--single", leading the + subsequent "git fetch" to slurp all the other branches, defeating + the whole point of specifying "only this branch". + + * Documentation talked about "first line of commit log" when it meant + the title of the commit. The description was clarified by defining + how the title is decided and rewording the casual mention of "first + line" to "title". + + * "git cvsimport" did not thoroughly cleanse tag names that it + inferred from the names of the tags it obtained from CVS, which + caused "git tag" to barf and stop the import in the middle. + + * Earlier we made the diffstat summary line that shows the number of + lines added/deleted localizable, but it was found irritating having + to see them in various languages on a list whose discussion language + is English, and this change has been reverted. + + * "git fetch --all", when passed "--no-tags", did not honor the + "--no-tags" option while fetching from individual remotes (the same + issue existed with "--tags", but the combination "--all --tags" makes + much less sense than "--all --no-tags"). + + * "git fetch" over http had an old workaround for an unlikely server + misconfiguration; it turns out that this hurts debuggability of the + configuration in general, and has been reverted. + + * "git fetch" over http advertised that it supports "deflate", which + is much less common, and did not advertise the more common "gzip" on + its Accept-Encoding header. + + * "git fetch" over the dumb-http revision walker could segfault when + curl's multi interface was used. + + * "git gc --auto" notified the user that auto-packing has triggered + even under the "--quiet" option. + + * After "gitk" showed the contents of a tag, neither "Reread + references" nor "Reload" updated what is shown as the + contents of it when the user overwrote the tag with "git tag -f". + + * "git log --all-match --grep=A --grep=B" ought to show commits that + mention both A and B, but when these three options are used with + --author or --committer, it showed commits that mention either A or + B (or both) instead. + + * The "-Xours" backend option to "git merge -s recursive" was ignored + for binary files. + + * "git p4", when "--use-client-spec" and "--detect-branches" are used + together, misdetected branches. + + * "git receive-pack" (the counterpart to "git push") did not give + progress output while processing objects it received to the puser + when run over the smart-http protocol. + + * When you misspell the command name you give to the "exec" action in + the "git rebase -i" instruction sheet you were told that 'rebase' is not a + git subcommand from "git rebase --continue". + + * The subcommand in "git remote" to remove a defined remote was + "rm" and the command did not take a fully-spelled "remove". + + * The interactive prompt that "git send-email" gives was error prone. It + asked "What e-mail address do you want to use?" with the address it + guessed (correctly) the user would want to use in its prompt, + tempting the user to say "y". But the response was taken as "No, + please use 'y' as the e-mail address instead", which is most + certainly not what the user meant. + + * "git show --format='%ci'" did not give the timestamp correctly for + commits created without human readable name on the "committer" line. + + * "git show --quiet" ought to be a synonym for "git show -s", but + wasn't. + + * "git submodule frotz" was not diagnosed as "frotz" being an unknown + subcommand to "git submodule"; the user instead got a complaint + that "git submodule status" was run with an unknown path "frotz". + + * "git status" honored the ignore=dirty settings in .gitmodules but + "git commit" didn't. + + * "gitweb" did not give the correct committer timezone in its feed + output due to a typo. diff --git a/Documentation/RelNotes/1.8.1.1.txt b/Documentation/RelNotes/1.8.1.1.txt new file mode 100644 index 000000000..0dc37dcdd --- /dev/null +++ b/Documentation/RelNotes/1.8.1.1.txt @@ -0,0 +1,36 @@ +Git 1.8.1.1 Release Notes +========================= + +Fixes since v1.8.1 +------------------ + + * After failing to create a temporary file using mkstemp(), failing + pathname was not reported correctly on some platforms. + + * http transport was wrong to ask for the username when the + authentication is done by certificate identity. + + * After "git add -N" and then writing a tree object out of the + index, the cache-tree data structure got corrupted. + + * "git pack-refs" that ran in parallel to another process that + created new refs had a race that can lose new ones. + + * When a line to be wrapped has a solid run of non space characters + whose length exactly is the wrap width, "git shortlog -w" failed + to add a newline after such a line. + + * "gitweb", when sorting by age to show repositories with new + activities first, used to sort repositories with absolutely + nothing in it early, which was not very useful. + + * Some scripted programs written in Python did not get updated when + PYTHON_PATH changed. + + * We have been carrying a translated and long-unmaintained copy of an + old version of the tutorial; removed. + + * Portability issues in many self-test scripts have been addressed. + + +Also contains other minor fixes and documentation updates. diff --git a/Documentation/RelNotes/1.8.1.txt b/Documentation/RelNotes/1.8.1.txt new file mode 100644 index 000000000..d6f955592 --- /dev/null +++ b/Documentation/RelNotes/1.8.1.txt @@ -0,0 +1,241 @@ +Git v1.8.1 Release Notes +======================== + +Backward compatibility notes +---------------------------- + +In the next major release (not *this* one), we will change the +behavior of the "git push" command. + +When "git push [$there]" does not say what to push, we have used the +traditional "matching" semantics so far (all your branches were sent +to the remote as long as there already are branches of the same name +over there). We will use the "simple" semantics that pushes the +current branch to the branch with the same name, only when the current +branch is set to integrate with that remote branch. There is a user +preference configuration variable "push.default" to change this, and +"git push" will warn about the upcoming change until you set this +variable in this release. + +"git branch --set-upstream" is deprecated and may be removed in a +relatively distant future. "git branch [-u|--set-upstream-to]" has +been introduced with a saner order of arguments to replace it. + + +Updates since v1.8.0 +-------------------- + +UI, Workflows & Features + + * Command-line completion scripts for tcsh and zsh have been added. + + * "git-prompt" scriptlet (in contrib/completion) can be told to paint + pieces of the hints in the prompt string in colors. + + * Some documentation pages that used to ship only in the plain text + format are now formatted in HTML as well. + + * We used to have a workaround for a bug in ancient "less" that + causes it to exit without any output when the terminal is resized. + The bug has been fixed in "less" version 406 (June 2007), and the + workaround has been removed in this release. + + * When "git checkout" checks out a branch, it tells the user how far + behind (or ahead) the new branch is relative to the remote tracking + branch it builds upon. The message now also advises how to sync + them up by pushing or pulling. This can be disabled with the + advice.statusHints configuration variable. + + * "git config --get" used to diagnose presence of multiple + definitions of the same variable in the same configuration file as + an error, but it now applies the "last one wins" rule used by the + internal configuration logic. Strictly speaking, this may be an + API regression but it is expected that nobody will notice it in + practice. + + * A new configuration variable "diff.context" can be used to + give the default number of context lines in the patch output, to + override the hardcoded default of 3 lines. + + * "git format-patch" learned the "--notes=<ref>" option to give + notes for the commit after the three-dash lines in its output. + + * "git log -p -S<string>" now looks for the <string> after applying + the textconv filter (if defined); earlier it inspected the contents + of the blobs without filtering. + + * "git log --grep=<pcre>" learned to honor the "grep.patterntype" + configuration set to "perl". + + * "git replace -d <object>" now interprets <object> as an extended + SHA-1 (e.g. HEAD~4 is allowed), instead of only accepting full hex + object name. + + * "git rm $submodule" used to punt on removing a submodule working + tree to avoid losing the repository embedded in it. Because + recent git uses a mechanism to separate the submodule repository + from the submodule working tree, "git rm" learned to detect this + case and removes the submodule working tree when it is safe to do so. + + * "git send-email" used to prompt for the sender address, even when + the committer identity is well specified (e.g. via user.name and + user.email configuration variables). The command no longer gives + this prompt when not necessary. + + * "git send-email" did not allow non-address garbage strings to + appear after addresses on Cc: lines in the patch files (and when + told to pick them up to find more recipients), e.g. + + Cc: Stable Kernel <stable@k.org> # for v3.2 and up + + The command now strips " # for v3.2 and up" part before adding the + remainder of this line to the list of recipients. + + * "git submodule add" learned to add a new submodule at the same + path as the path where an unrelated submodule was bound to in an + existing revision via the "--name" option. + + * "git submodule sync" learned the "--recursive" option. + + * "diff.submodule" configuration variable can be used to give custom + default value to the "git diff --submodule" option. + + * "git symbolic-ref" learned the "-d $symref" option to delete the + named symbolic ref, which is more intuitive way to spell it than + "update-ref -d --no-deref $symref". + + +Foreign Interface + + * "git cvsimport" can be told to record timezones (other than GMT) + per-author via its author info file. + + * The remote helper interface to interact with subversion + repositories (one of the GSoC 2012 projects) has been merged. + + * A new remote-helper interface for Mercurial has been added to + contrib/remote-helpers. + + * The documentation for git(1) was pointing at a page at an external + site for the list of authors that no longer existed. The link has + been updated to point at an alternative site. + + +Performance, Internal Implementation, etc. + + * Compilation on Cygwin with newer header files are supported now. + + * A couple of low-level implementation updates on MinGW. + + * The logic to generate the initial advertisement from "upload-pack" + (i.e. what is invoked by "git fetch" on the other side of the + connection) to list what refs are available in the repository has + been optimized. + + * The logic to find set of attributes that match a given path has + been optimized. + + * Use preloadindex in "git diff-index" and "git update-index", which + has a nice speedup on systems with slow stat calls (and even on + Linux). + + +Also contains minor documentation updates and code clean-ups. + + +Fixes since v1.8.0 +------------------ + +Unless otherwise noted, all the fixes since v1.8.0 in the maintenance +track are contained in this release (see release notes to them for +details). + + * The configuration parser had an unnecessary hardcoded limit on + variable names that was not checked consistently. + + * The "say" function in the test scaffolding incorrectly allowed + "echo" to interpret "\a" as if it were a C-string asking for a + BEL output. + + * "git mergetool" feeds /dev/null as a common ancestor when dealing + with an add/add conflict, but p4merge backend cannot handle + it. Work it around by passing a temporary empty file. + + * "git log -F -E --grep='<ere>'" failed to use the given <ere> + pattern as extended regular expression, and instead looked for the + string literally. + + * "git grep -e pattern <tree>" asked the attribute system to read + "<tree>:.gitattributes" file in the working tree, which was + nonsense. + + * A symbolic ref refs/heads/SYM was not correctly removed with "git + branch -d SYM"; the command removed the ref pointed by SYM + instead. + + * Update "remote tracking branch" in the documentation to + "remote-tracking branch". + + * "git pull --rebase" run while the HEAD is detached tried to find + the upstream branch of the detached HEAD (which by definition + does not exist) and emitted unnecessary error messages. + + * The refs/replace hierarchy was not mentioned in the + repository-layout docs. + + * Various rfc2047 quoting issues around a non-ASCII name on the + From: line in the output from format-patch have been corrected. + + * Sometimes curl_multi_timeout() function suggested a wrong timeout + value when there is no file descriptor to wait on and the http + transport ended up sleeping for minutes in select(2) system call. + A workaround has been added for this. + + * For a fetch refspec (or the result of applying wildcard on one), + we always want the RHS to map to something inside "refs/" + hierarchy, but the logic to check it was not exactly right. + (merge 5c08c1f jc/maint-fetch-tighten-refname-check later to maint). + + * "git diff -G<pattern>" did not honor textconv filter when looking + for changes. + + * Some HTTP servers ask for auth only during the actual packing phase + (not in ls-remote phase); this is not really a recommended + configuration, but the clients used to fail to authenticate with + such servers. + (merge 2e736fd jk/maint-http-half-auth-fetch later to maint). + + * "git p4" used to try expanding malformed "$keyword$" that spans + across multiple lines. + + * Syntax highlighting in "gitweb" was not quite working. + + * RSS feed from "gitweb" had a xss hole in its title output. + + * "git config --path $key" segfaulted on "[section] key" (a boolean + "true" spelled without "=", not "[section] key = true"). + + * "git checkout -b foo" while on an unborn branch did not say + "Switched to a new branch 'foo'" like other cases. + + * Various codepaths have workaround for a common misconfiguration to + spell "UTF-8" as "utf8", but it was not used uniformly. Most + notably, mailinfo (which is used by "git am") lacked this support. + + * We failed to mention a file without any content change but whose + permission bit was modified, or (worse yet) a new file without any + content in the "git diff --stat" output. + + * When "--stat-count" hides a diffstat for binary contents, the total + number of added and removed lines at the bottom was computed + incorrectly. + + * When "--stat-count" hides a diffstat for unmerged paths, the total + number of affected files at the bottom of the "diff --stat" output + was computed incorrectly. + + * "diff --shortstat" miscounted the total number of affected files + when there were unmerged paths. + + * "update-ref -d --deref SYM" to delete a ref through a symbolic ref + that points to it did not remove it correctly. diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 0dbf2c984..90133d8c3 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -1,65 +1,5 @@ -Checklist (and a short version for the impatient): - - Commits: - - - make commits of logical units - - check for unnecessary whitespace with "git diff --check" - before committing - - do not check in commented out code or unneeded files - - the first line of the commit message should be a short - description (50 characters is the soft limit, see DISCUSSION - in git-commit(1)), and should skip the full stop - - the body should provide a meaningful commit message, which: - . explains the problem the change tries to solve, iow, what - is wrong with the current code without the change. - . justifies the way the change solves the problem, iow, why - the result with the change is better. - . alternate solutions considered but discarded, if any. - - describe changes in imperative mood, e.g. "make xyzzy do frotz" - instead of "[This patch] makes xyzzy do frotz" or "[I] changed - xyzzy to do frotz", as if you are giving orders to the codebase - to change its behaviour. - - try to make sure your explanation can be understood without - external resources. Instead of giving a URL to a mailing list - archive, summarize the relevant points of the discussion. - - add a "Signed-off-by: Your Name <you@example.com>" line to the - commit message (or just use the option "-s" when committing) - to confirm that you agree to the Developer's Certificate of Origin - - make sure that you have tests for the bug you are fixing - - make sure that the test suite passes after your commit - - Patch: - - - use "git format-patch -M" to create the patch - - do not PGP sign your patch - - do not attach your patch, but read in the mail - body, unless you cannot teach your mailer to - leave the formatting of the patch alone. - - be careful doing cut & paste into your mailer, not to - corrupt whitespaces. - - provide additional information (which is unsuitable for - the commit message) between the "---" and the diffstat - - if you change, add, or remove a command line option or - make some other user interface change, the associated - documentation should be updated as well. - - if your name is not writable in ASCII, make sure that - you send off a message in the correct encoding. - - send the patch to the list (git@vger.kernel.org) and the - maintainer (gitster@pobox.com) if (and only if) the patch - is ready for inclusion. If you use git-send-email(1), - please test it first by sending email to yourself. - - see below for instructions specific to your mailer - -Long version: - -I started reading over the SubmittingPatches document for Linux -kernel, primarily because I wanted to have a document similar to -it for the core GIT to make sure people understand what they are -doing when they write "Signed-off-by" line. - -But the patch submission requirements are a lot more relaxed -here on the technical/contents front, because the core GIT is -thousand times smaller ;-). So here is only the relevant bits. +Here are some guidelines for people who want to contribute their code +to this software. (0) Decide what to base your work on. @@ -86,6 +26,10 @@ change is relevant to. wait until some of the dependent topics graduate to 'master', and rebase your work. + - Some parts of the system have dedicated maintainers with their own + repositories (see the section "Subsystems" below). Changes to + these parts should be based on their trees. + To find the tip of a topic branch, run "git log --first-parent master..pu" and look for the merge commit. The second parent of this commit is the tip of the topic branch. @@ -113,26 +57,53 @@ change, the approach taken by the change, and if relevant how this differs substantially from the prior version, are all good things to have. +Make sure that you have tests for the bug you are fixing. + +When adding a new feature, make sure that you have new tests to show +the feature triggers the new behaviour when it should, and to show the +feature does not trigger when it shouldn't. Also make sure that the +test suite passes after your commit. Do not forget to update the +documentation to describe the updated behaviour. + Oh, another thing. I am picky about whitespaces. Make sure your changes do not trigger errors with the sample pre-commit hook shipped in templates/hooks--pre-commit. To help ensure this does not happen, run git diff --check on your changes before you commit. -(1a) Try to be nice to older C compilers +(2) Describe your changes well. + +The first line of the commit message should be a short description (50 +characters is the soft limit, see DISCUSSION in git-commit(1)), and +should skip the full stop. It is also conventional in most cases to +prefix the first line with "area: " where the area is a filename or +identifier for the general area of the code being modified, e.g. + + . archive: ustar header checksum is computed unsigned + . git-cherry-pick.txt: clarify the use of revision range notation + +If in doubt which identifier to use, run "git log --no-merges" on the +files you are modifying to see the current conventions. -We try to support a wide range of C compilers to compile -git with. That means that you should not use C99 initializers, even -if a lot of compilers grok it. +The body should provide a meaningful commit message, which: -Also, variables have to be declared at the beginning of the block -(you can check this with gcc, using the -Wdeclaration-after-statement -option). + . explains the problem the change tries to solve, iow, what is wrong + with the current code without the change. -Another thing: NULL pointers shall be written as NULL, not as 0. + . justifies the way the change solves the problem, iow, why the + result with the change is better. + . alternate solutions considered but discarded, if any. -(2) Generate your patch using git tools out of your commits. +Describe your changes in imperative mood, e.g. "make xyzzy do frotz" +instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy +to do frotz", as if you are giving orders to the codebase to change +its behaviour. Try to make sure your explanation can be understood +without external resources. Instead of giving a URL to a mailing list +archive, summarize the relevant points of the discussion. + + +(3) Generate your patch using git tools out of your commits. git based diff tools generate unidiff which is the preferred format. @@ -140,22 +111,27 @@ You do not have to be afraid to use -M option to "git diff" or "git format-patch", if your patch involves file renames. The receiving end can handle them just fine. -Please make sure your patch does not include any extra files -which do not belong in a patch submission. Make sure to review +Please make sure your patch does not add commented out debugging code, +or include any extra files which do not relate to what your patch +is trying to achieve. Make sure to review your patch after generating it, to ensure accuracy. Before sending out, please make sure it cleanly applies to the "master" branch head. If you are preparing a work based on "next" branch, that is fine, but please mark it as such. -(3) Sending your patches. +(4) Sending your patches. People on the git mailing list need to be able to read and comment on the changes you are submitting. It is important for a developer to be able to "quote" your changes, using standard e-mail tools, so that they may comment on specific portions of your code. For this reason, all patches should be submitted -"inline". WARNING: Be wary of your MUAs word-wrap +"inline". If your log message (including your name on the +Signed-off-by line) is not writable in ASCII, make sure that +you send off a message in the correct encoding. + +WARNING: Be wary of your MUAs word-wrap corrupting your patch. Do not cut-n-paste your patch; you can lose tabs that way if you are not careful. @@ -179,7 +155,8 @@ message starts, you can put a "From: " line to name that person. You often want to add additional explanation about the patch, other than the commit message itself. Place such "cover letter" -material between the three dash lines and the diffstat. +material between the three dash lines and the diffstat. Git-notes +can also be inserted using the `--notes` option. Do not attach the patch as a MIME attachment, compressed or not. Do not let your e-mail client send quoted-printable. Do not let @@ -207,19 +184,25 @@ patch, format it as "multipart/signed", not a text/plain message that starts with '-----BEGIN PGP SIGNED MESSAGE-----'. That is not a text/plain, it's something else. -Unless your patch is a very trivial and an obviously correct one, -first send it with "To:" set to the mailing list, with "cc:" listing +Send your patch with "To:" set to the mailing list, with "cc:" listing people who are involved in the area you are touching (the output from "git blame $path" and "git shortlog --no-merges $path" would help to -identify them), to solicit comments and reviews. After the list -reached a consensus that it is a good idea to apply the patch, re-send -it with "To:" set to the maintainer and optionally "cc:" the list for -inclusion. Do not forget to add trailers such as "Acked-by:", -"Reviewed-by:" and "Tested-by:" after your "Signed-off-by:" line as -necessary. +identify them), to solicit comments and reviews. + +After the list reached a consensus that it is a good idea to apply the +patch, re-send it with "To:" set to the maintainer [*1*] and "cc:" the +list [*2*] for inclusion. + +Do not forget to add trailers such as "Acked-by:", "Reviewed-by:" and +"Tested-by:" lines as necessary to credit people who helped your +patch. + [Addresses] + *1* The current maintainer: gitster@pobox.com + *2* The mailing list: git@vger.kernel.org -(4) Sign your work + +(5) Sign your work To improve tracking of who did what, we've borrowed the "sign-off" procedure from the Linux kernel project on patches @@ -290,6 +273,26 @@ You can also create your own tag or use one that's in common usage such as "Thanks-to:", "Based-on-patch-by:", or "Mentored-by:". ------------------------------------------------ +Subsystems with dedicated maintainers + +Some parts of the system have dedicated maintainers with their own +repositories. + + - git-gui/ comes from git-gui project, maintained by Pat Thoyts: + + git://repo.or.cz/git-gui.git + + - gitk-git/ comes from Paul Mackerras's gitk project: + + git://ozlabs.org/~paulus/gitk + + - po/ comes from the localization coordinator, Jiang Xin: + + https://github.com/git-l10n/git-po/ + +Patches to these parts should be based on their trees. + +------------------------------------------------ An ideal patch flow Here is an ideal patch flow for this project the current maintainer diff --git a/Documentation/config.txt b/Documentation/config.txt index b49feb582..bf8f911e1 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -159,9 +159,11 @@ advice.*:: specified a refspec that isn't your current branch) and it resulted in a non-fast-forward error. statusHints:: - Directions on how to stage/unstage/add shown in the - output of linkgit:git-status[1] and the template shown - when writing commit messages. + Show directions on how to proceed from the current + state in the output of linkgit:git-status[1], in + the template shown when writing commit messages in + linkgit:git-commit[1], and in the help message shown + by linkgit:git-checkout[1] when switching branch. commitBeforeMerge:: Advice shown when linkgit:git-merge[1] refuses to merge to avoid overwriting local changes. @@ -213,6 +215,15 @@ The default is false, except linkgit:git-clone[1] or linkgit:git-init[1] will probe and set core.ignorecase true if appropriate when the repository is created. +core.precomposeunicode:: + This option is only used by Mac OS implementation of git. + When core.precomposeunicode=true, git reverts the unicode decomposition + of filenames done by Mac OS. This is useful when sharing a repository + between Mac OS and Linux or Windows. + (Git for Windows 1.7.10 or higher is needed, or git under cygwin 1.7). + When false, file names are handled fully transparent by git, + which is backward compatible with older versions of git. + core.trustctime:: If false, the ctime differences between the index and the working tree are ignored; useful when the inode change time @@ -486,7 +497,9 @@ core.excludesfile:: '.git/info/exclude', git looks into this file for patterns of files which are not meant to be tracked. "`~/`" is expanded to the value of `$HOME` and "`~user/`" to the specified user's - home directory. See linkgit:gitignore[5]. + home directory. Its default value is $XDG_CONFIG_HOME/git/ignore. + If $XDG_CONFIG_HOME is either not set or empty, $HOME/.config/git/ignore + is used instead. See linkgit:gitignore[5]. core.askpass:: Some commands (e.g. svn and http interfaces) that interactively @@ -501,7 +514,9 @@ core.attributesfile:: In addition to '.gitattributes' (per-directory) and '.git/info/attributes', git looks into this file for attributes (see linkgit:gitattributes[5]). Path expansions are made the same - way as for `core.excludesfile`. + way as for `core.excludesfile`. Its default value is + $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not + set or empty, $HOME/.config/git/attributes is used instead. core.editor:: Commands such as `commit` and `tag` that lets you edit @@ -524,14 +539,14 @@ core.pager:: `LESS` variable to some other value. Alternately, these settings can be overridden on a project or global basis by setting the `core.pager` option. - Setting `core.pager` has no affect on the `LESS` + Setting `core.pager` has no effect on the `LESS` environment variable behaviour above, so if you want to override git's default settings this way, you need to be explicit. For example, to disable the S option in a backward compatible manner, set `core.pager` - to `less -+$LESS -FRX`. This will be passed to the - shell by git, which will translate the final command to - `LESS=FRSX less -+FRSX -FRX`. + to `less -+S`. This will be passed to the shell by + git, which will translate the final command to + `LESS=FRSX less -+S`. core.whitespace:: A comma separated list of common whitespace problems to @@ -545,8 +560,9 @@ core.whitespace:: * `space-before-tab` treats a space character that appears immediately before a tab character in the initial indent part of the line as an error (enabled by default). -* `indent-with-non-tab` treats a line that is indented with 8 or more - space characters as an error (not enabled by default). +* `indent-with-non-tab` treats a line that is indented with space + characters instead of the equivalent tabs as an error (not enabled by + default). * `tab-in-indent` treats a tab character in the initial indent part of the line as an error (not enabled by default). * `blank-at-eof` treats blank lines added at the end of file as an error @@ -883,7 +899,7 @@ column.ui:: make equal size columns -- + - This option defaults to 'never'. +This option defaults to 'never'. column.branch:: Specify whether to output branch listing in `git branch` in columns. @@ -947,12 +963,6 @@ difftool.<tool>.cmd:: difftool.prompt:: Prompt before each invocation of the diff tool. -diff.wordRegex:: - A POSIX Extended Regular Expression used to determine what is a "word" - when performing word-by-word difference calculations. Character - sequences that match the regular expression are "words", all other - characters are *ignorable* whitespace. - fetch.recurseSubmodules:: This option can be either set to a boolean value or to 'on-demand'. Setting it to a boolean changes the behavior of fetch and pull to @@ -1196,8 +1206,16 @@ gitweb.snapshot:: grep.lineNumber:: If set to true, enable '-n' option by default. +grep.patternType:: + Set the default matching behavior. Using a value of 'basic', 'extended', + 'fixed', or 'perl' will enable the '--basic-regexp', '--extended-regexp', + '--fixed-strings', or '--perl-regexp' option accordingly, while the + value 'default' will return to the default matching behavior. + grep.extendedRegexp:: - If set to true, enable '--extended-regexp' option by default. + If set to true, enable '--extended-regexp' option by default. This + option is ignored when the 'grep.patternType' option is set to a value + other than 'default'. gpg.program:: Use this custom program instead of "gpg" found on $PATH when @@ -1723,6 +1741,7 @@ push.default:: no refspec is implied by any of the options given on the command line. Possible values are: + +-- * `nothing` - do not push anything. * `matching` - push all branches having the same name in both ends. This is for those who prepare all the branches into a publishable @@ -1742,12 +1761,13 @@ push.default:: option and is well-suited for beginners. It will become the default in Git 2.0. * `current` - push the current branch to a branch of the same name. - + - The `simple`, `current` and `upstream` modes are for those who want to - push out a single branch after finishing work, even when the other - branches are not yet ready to be pushed out. If you are working with - other people to push into the same shared repository, you would want - to use one of these. +-- ++ +The `simple`, `current` and `upstream` modes are for those who want to +push out a single branch after finishing work, even when the other +branches are not yet ready to be pushed out. If you are working with +other people to push into the same shared repository, you would want +to use one of these. rebase.stat:: Whether to show a diffstat of what changed upstream since the last diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt index 67a90a828..4314ad0fb 100644 --- a/Documentation/diff-config.txt +++ b/Documentation/diff-config.txt @@ -56,6 +56,10 @@ diff.statGraphWidth:: Limit the width of the graph part in --stat output. If set, applies to all commands generating --stat output except format-patch. +diff.context:: + Generate diffs with <n> lines of context instead of the default + of 3. This value is overridden by the -U option. + diff.external:: If this config variable is set, diff generation is not performed using the internal diff machinery, but using the @@ -103,6 +107,19 @@ diff.suppressBlankEmpty:: A boolean to inhibit the standard behavior of printing a space before each empty output line. Defaults to false. +diff.submodule:: + Specify the format in which differences in submodules are + shown. The "log" format lists the commits in the range like + linkgit:git-submodule[1] `summary` does. The "short" format + format just shows the names of the commits at the beginning + and end of the range. Defaults to short. + +diff.wordRegex:: + A POSIX Extended Regular Expression used to determine what is a "word" + when performing word-by-word difference calculations. Character + sequences that match the regular expression are "words", all other + characters are *ignorable* whitespace. + diff.<driver>.command:: The custom diff driver command. See linkgit:gitattributes[5] for details. diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index cf4b21659..39f2c5074 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -170,7 +170,8 @@ any of those replacements occurred. the commits in the range like linkgit:git-submodule[1] `summary` does. Omitting the `--submodule` option or specifying `--submodule=short`, uses the 'short' format. This format just shows the names of the commits - at the beginning and end of the range. + at the beginning and end of the range. Can be tweaked via the + `diff.submodule` configuration variable. --color[=<when>]:: Show colored diff. @@ -308,7 +309,11 @@ endif::git-log[] index (i.e. amount of addition/deletions compared to the file's size). For example, `-M90%` means git should consider a delete/add pair to be a rename if more than 90% of the file - hasn't changed. + hasn't changed. Without a `%` sign, the number is to be read as + a fraction, with a decimal point before it. I.e., `-M5` becomes + 0.5, and is thus the same as `-M50%`. Similarly, `-M05` is + the same as `-M5%`. To limit detection to exact renames, use + `-M100%`. -C[<n>]:: --find-copies[=<n>]:: diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 39d326abc..6e98bdf14 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -10,7 +10,8 @@ --depth=<depth>:: Deepen the history of a 'shallow' repository created by `git clone` with `--depth=<depth>` option (see linkgit:git-clone[1]) - by the specified number of commits. + to the specified number of commits from the tip of each remote + branch history. Tags for the deepened commits are not fetched. ifndef::git-pull[] --dry-run:: @@ -56,14 +57,11 @@ endif::git-pull[] ifndef::git-pull[] -t:: --tags:: - Most of the tags are fetched automatically as branch - heads are downloaded, but tags that do not point at - objects reachable from the branch heads that are being - tracked will not be fetched by this mechanism. This - flag lets all tags and their associated objects be - downloaded. The default behavior for a remote may be - specified with the remote.<name>.tagopt setting. See - linkgit:git-config[1]. + This is a short-hand for giving "refs/tags/*:refs/tags/*" + refspec from the command line, to ask all tags to be fetched + and stored locally. Because this acts as an explicit + refspec, the default refspecs (configured with the + remote.$name.fetch variable) are overridden and not used. --recurse-submodules[=yes|on-demand|no]:: This option controls if and under what conditions new commits of diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt index 9c1d39572..fd9e36b99 100644 --- a/Documentation/git-add.txt +++ b/Documentation/git-add.txt @@ -155,7 +155,7 @@ Configuration The optional configuration variable `core.excludesfile` indicates a path to a file containing patterns of file names to exclude from git-add, similar to $GIT_DIR/info/exclude. Patterns in the exclude file are used in addition to -those in info/exclude. See linkgit:gitrepository-layout[5]. +those in info/exclude. See linkgit:gitignore[5]. EXAMPLES diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt index afd2c9ae5..634b84e4b 100644 --- a/Documentation/git-apply.txt +++ b/Documentation/git-apply.txt @@ -9,7 +9,7 @@ git-apply - Apply a patch to files and/or to the index SYNOPSIS -------- [verse] -'git apply' [--stat] [--numstat] [--summary] [--check] [--index] +'git apply' [--stat] [--numstat] [--summary] [--check] [--index] [--3way] [--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse] [--allow-binary-replacement | --binary] [--reject] [-z] [-p<n>] [-C<n>] [--inaccurate-eof] [--recount] [--cached] @@ -72,6 +72,15 @@ OPTIONS cached data, apply the patch, and store the result in the index without using the working tree. This implies `--index`. +-3:: +--3way:: + When the patch does not apply cleanly, fall back on 3-way merge if + the patch records the identity of blobs it is supposed to apply to, + and we have those blobs available locally, possibly leaving the + conflict markers in the files in the working tree for the user to + resolve. This option implies the `--index` option, and is incompatible + with the `--reject` and the `--cached` options. + --build-fake-ancestor=<file>:: Newer 'git diff' output has embedded 'index information' for each blob to help identify the original version that diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.txt index 8a2ba3790..ec4497e09 100644 --- a/Documentation/git-bisect-lk2009.txt +++ b/Documentation/git-bisect-lk2009.txt @@ -257,7 +257,7 @@ Date: Sat May 3 11:59:44 2008 -0700 Linux 2.6.26-rc1 -:100644 100644 5cf8258195331a4dbdddff08b8d68642638eea57 4492984efc09ab72ff6219a7bc21fb6a957c4cd5 M Makefile +:100644 100644 5cf82581... 4492984e... M Makefile ------------- At this point we can see what the commit does, check it out (if it's @@ -331,7 +331,7 @@ Date: Sat May 3 11:59:44 2008 -0700 Linux 2.6.26-rc1 -:100644 100644 5cf8258195331a4dbdddff08b8d68642638eea57 4492984efc09ab72ff6219a7bc21fb6a957c4cd5 M Makefile +:100644 100644 5cf82581... 4492984e... M Makefile bisect run success ------------- diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt index 7ee923629..e44173f66 100644 --- a/Documentation/git-blame.txt +++ b/Documentation/git-blame.txt @@ -20,6 +20,12 @@ last modified the line. Optionally, start annotating from the given revision. The command can also limit the range of lines annotated. +The origin of lines is automatically followed across whole-file +renames (currently there is no option to turn the rename-following +off). To follow lines moved from one file to another, or to follow +lines that were copied and pasted from another file, etc., see the +`-C` and `-M` options. + The report does not tell you anything about lines which have been deleted or replaced; you need to use a tool such as 'git diff' or the "pickaxe" interface briefly mentioned in the following paragraph. diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 47235bea0..45a225e0a 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -13,6 +13,8 @@ SYNOPSIS [--column[=<options>] | --no-column] [(--merged | --no-merged | --contains) [<commit>]] [<pattern>...] 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>] +'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>] +'git branch' --unset-upstream [<branchname>] 'git branch' (-m | -M) [<oldbranch>] <newbranch> 'git branch' (-d | -D) [-r] <branchname>... 'git branch' --edit-description [<branchname>] @@ -48,7 +50,7 @@ branch so that 'git pull' will appropriately merge from the remote-tracking branch. This behavior may be changed via the global `branch.autosetupmerge` configuration flag. That setting can be overridden by using the `--track` and `--no-track` options, and -changed later using `git branch --set-upstream`. +changed later using `git branch --set-upstream-to`. With a `-m` or `-M` option, <oldbranch> will be renamed to <newbranch>. If <oldbranch> had a corresponding reflog, it is renamed to match @@ -129,11 +131,13 @@ This option is only applicable in non-verbose mode. use `git branch --list <pattern>` to list matching branches. -v:: +-vv:: --verbose:: When in list mode, show sha1 and commit subject line for each head, along with relationship to upstream branch (if any). If given twice, print - the name of the upstream branch, as well. + the name of the upstream branch, as well (see also `git remote + show <remote>`). -q:: --quiet:: @@ -173,6 +177,16 @@ start-point is either a local or remote-tracking branch. like `--track` would when creating the branch, except that where branch points to is not changed. +-u <upstream>:: +--set-upstream-to=<upstream>:: + Set up <branchname>'s tracking information so <upstream> is + considered <branchname>'s upstream branch. If no <branchname> + is specified, then it defaults to the current branch. + +--unset-upstream:: + Remove the upstream information for <branchname>. If no branch + is specified it defaults to the current branch. + --edit-description:: Open an editor and edit the text to explain what the branch is for, to be used by various other commands (e.g. `request-pull`). diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt index 16a6b0ace..bc023cc5f 100644 --- a/Documentation/git-bundle.txt +++ b/Documentation/git-bundle.txt @@ -112,13 +112,12 @@ machineA$ git bundle create file.bundle master machineA$ git tag -f lastR2bundle master ---------------- -Then you transfer file.bundle to the target machine B. If you are creating -the repository on machine B, then you can clone from the bundle as if it -were a remote repository instead of creating an empty repository and then -pulling or fetching objects from the bundle: +Then you transfer file.bundle to the target machine B. Because this +bundle does not require any existing object to be extracted, you can +create a new repository on machine B by cloning from it: ---------------- -machineB$ git clone /home/me/tmp/file.bundle R2 +machineB$ git clone -b master /home/me/tmp/file.bundle R2 ---------------- This will define a remote called "origin" in the resulting repository that diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 7958a4700..6f04d22f5 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -21,18 +21,34 @@ or the specified tree. If no paths are given, 'git checkout' will also update `HEAD` to set the specified branch as the current branch. -'git checkout' [<branch>]:: +'git checkout' <branch>:: + To prepare for working on <branch>, switch to it by updating + the index and the files in the working tree, and by pointing + HEAD at the branch. Local modifications to the files in the + working tree are kept, so that they can be committed to the + <branch>. ++ +If <branch> is not found but there does exist a tracking branch in +exactly one remote (call it <remote>) with a matching name, treat as +equivalent to ++ +------------ +$ git checkout -b <branch> --track <remote>/<branch> +------------ ++ +You could omit <branch>, in which case the command degenerates to +"check out the current branch", which is a glorified no-op with a +rather expensive side-effects to show only the tracking information, +if exists, for the current branch. + 'git checkout' -b|-B <new_branch> [<start point>]:: -'git checkout' [--detach] [<commit>]:: - This form switches branches by updating the index, working - tree, and HEAD to reflect the specified branch or commit. -+ -If `-b` is given, a new branch is created as if linkgit:git-branch[1] -were called and then checked out; in this case you can -use the `--track` or `--no-track` options, which will be passed to -'git branch'. As a convenience, `--track` without `-b` implies branch -creation; see the description of `--track` below. + Specifying `-b` causes a new branch to be created as if + linkgit:git-branch[1] were called and then checked out. In + this case you can use the `--track` or `--no-track` options, + which will be passed to 'git branch'. As a convenience, + `--track` without `-b` implies branch creation; see the + description of `--track` below. + If `-B` is given, <new_branch> is created if it doesn't exist; otherwise, it is reset. This is the transactional equivalent of @@ -45,6 +61,21 @@ $ git checkout <branch> that is to say, the branch is not reset/created unless "git checkout" is successful. +'git checkout' --detach [<branch>]:: +'git checkout' <commit>:: + + Prepare to work on top of <commit>, by detaching HEAD at it + (see "DETACHED HEAD" section), and updating the index and the + files in the working tree. Local modifications to the files + in the working tree are kept, so that the resulting working + tree will be the state recorded in the commit plus the local + modifications. ++ +Passing `--detach` forces this behavior in the case of a <branch> (without +the option, giving a branch name to the command would check out the branch, +instead of detaching HEAD at it), or the current commit, +if no <branch> is specified. + 'git checkout' [-p|--patch] [<tree-ish>] [--] <pathspec>...:: When <paths> or `--patch` are given, 'git checkout' does *not* diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index 0e170a51c..c205d2363 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -118,6 +118,11 @@ effect to your index in a row. previous commit are dropped. To force the inclusion of those commits use `--keep-redundant-commits`. +--allow-empty-message:: + By default, cherry-picking a commit with an empty message will fail. + This option overrides that behaviour, allowing commits with empty + messages to be cherry picked. + --keep-redundant-commits:: If a commit being cherry picked duplicates a commit already in the current history, it will become empty. By default these diff --git a/Documentation/git-clean.txt b/Documentation/git-clean.txt index 79fb98414..9f42c0d0e 100644 --- a/Documentation/git-clean.txt +++ b/Documentation/git-clean.txt @@ -63,6 +63,10 @@ OPTIONS Remove only files ignored by git. This may be useful to rebuild everything from scratch, but keep manually created files. +SEE ALSO +-------- +linkgit:gitignore[5] + GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 6e22522c4..7fefdb038 100644 --- a/Documentation/git-clone.txt +++ b/Documentation/git-clone.txt @@ -29,7 +29,8 @@ currently active branch. After the clone, a plain `git fetch` without arguments will update all the remote-tracking branches, and a `git pull` without arguments will in addition merge the remote master branch into the -current master branch, if any. +current master branch, if any (this is untrue when "--single-branch" +is given; see below). This default configuration is achieved by creating references to the remote branch heads under `refs/remotes/origin` and @@ -46,13 +47,18 @@ OPTIONS mechanism and clones the repository by making a copy of HEAD and everything under objects and refs directories. The files under `.git/objects/` directory are hardlinked - to save space when possible. This is now the default when - the source repository is specified with `/path/to/repo` - syntax, so it essentially is a no-op option. To force - copying instead of hardlinking (which may be desirable - if you are trying to make a back-up of your repository), - but still avoid the usual "git aware" transport - mechanism, `--no-hardlinks` can be used. + to save space when possible. ++ +If the repository is specified as a local path (e.g., `/path/to/repo`), +this is the default, and --local is essentially a no-op. If the +repository is specified as a URL, then this flag is ignored (and we +never use the local optimizations). Specifying `--no-local` will +override the default when `/path/to/repo` is given, using the regular +git transport instead. ++ +To force copying instead of hardlinking (which may be desirable if you +are trying to make a back-up of your repository), but still avoid the +usual "git aware" transport mechanism, `--no-hardlinks` can be used. --no-hardlinks:: Optimize the cloning process from a repository on a @@ -147,9 +153,10 @@ objects from the source repository into a pack in the cloned repository. -b <name>:: Instead of pointing the newly created HEAD to the branch pointed to by the cloned repository's HEAD, point to `<name>` branch - instead. `--branch` can also take tags and treat them like - detached HEAD. In a non-bare repository, this is the branch - that will be checked out. + instead. In a non-bare repository, this is the branch that will + be checked out. + `--branch` can also take tags and detaches the HEAD at that commit + in the resulting repository. --upload-pack <upload-pack>:: -u <upload-pack>:: @@ -188,6 +195,11 @@ objects from the source repository into a pack in the cloned repository. clone with the `--depth` option, this is the default, unless `--no-single-branch` is given to fetch the histories near the tips of all branches. + Further fetches into the resulting repository will only update the + remote-tracking branch for the branch this option was used for the + initial cloning. If the HEAD at the remote did not point at any + branch when `--single-branch` clone was made, no remote-tracking + branch is created. --recursive:: --recurse-submodules:: diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 4622297ec..7bdb039d5 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -13,7 +13,7 @@ SYNOPSIS [-F <file> | -m <msg>] [--reset-author] [--allow-empty] [--allow-empty-message] [--no-verify] [-e] [--author=<author>] [--date=<date>] [--cleanup=<mode>] [--status | --no-status] - [-i | -o] [--] [<file>...] + [-i | -o] [-S[<keyid>]] [--] [<file>...] DESCRIPTION ----------- @@ -109,6 +109,10 @@ OPTIONS format. See linkgit:git-status[1] for details. Implies `--dry-run`. +--long:: + When doing a dry-run, give the output in a the long-format. + Implies `--dry-run`. + -z:: --null:: When showing `short` or `porcelain` status output, terminate @@ -184,6 +188,11 @@ OPTIONS commit log message unmodified. This option lets you further edit the message taken from these sources. +--no-edit:: + Use the selected commit message without launching an editor. + For example, `git commit --amend --no-edit` amends a commit + without changing its commit message. + --amend:: Used to amend the tip of the current branch. Prepare the tree object you would want to replace the latest commit as usual @@ -193,10 +202,6 @@ OPTIONS current tip -- if it was a merge, it will have the parents of the current tip as parents -- so the current top commit is discarded. - ---no-post-rewrite:: - Bypass the post-rewrite hook. - + -- It is a rough equivalent for: @@ -213,6 +218,9 @@ You should understand the implications of rewriting history if you amend a commit that has already been published. (See the "RECOVERING FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].) +--no-post-rewrite:: + Bypass the post-rewrite hook. + -i:: --include:: Before making a commit out of staged contents so far, @@ -276,6 +284,10 @@ configuration variable documented in linkgit:git-config[1]. commit message template when using an editor to prepare the default commit message. +-S[<keyid>]:: +--gpg-sign[=<keyid>]:: + GPG-sign commit. + \--:: Do not interpret any more arguments as options. @@ -389,8 +401,10 @@ DISCUSSION Though not required, it's a good idea to begin the commit message with a single short (less than 50 character) line summarizing the change, followed by a blank line and then a more thorough description. -Tools that turn commits into email, for example, use the first line -on the Subject: line and the rest of the commit in the body. +The text up to the first blank line in a commit message is treated +as the commit title, and that title is used throughout git. +For example, linkgit:git-format-patch[1] turns a commit into email, and it uses +the title on the Subject line and the rest of the commit in the body. include::i18n.txt[] diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 21b8f6110..9ae2508f3 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -97,10 +97,11 @@ OPTIONS --global:: For writing options: write to global ~/.gitconfig file rather than - the repository .git/config. + the repository .git/config, write to $XDG_CONFIG_HOME/git/config file + if this file exists and the ~/.gitconfig file doesn't. + -For reading options: read only from global ~/.gitconfig rather than -from all available files. +For reading options: read only from global ~/.gitconfig and from +$XDG_CONFIG_HOME/git/config rather than from all available files. + See also <<FILES>>. @@ -194,7 +195,7 @@ See also <<FILES>>. FILES ----- -If not set explicitly with '--file', there are three files where +If not set explicitly with '--file', there are four files where 'git config' will search for configuration options: $GIT_DIR/config:: @@ -204,6 +205,14 @@ $GIT_DIR/config:: User-specific configuration file. Also called "global" configuration file. +$XDG_CONFIG_HOME/git/config:: + Second user-specific configuration file. If $XDG_CONFIG_HOME is not set + or empty, $HOME/.config/git/config will be used. Any single-valued + variable set in this file will be overwritten by whatever is in + ~/.gitconfig. It is a good idea not to create this file if + you sometimes use older versions of Git, as support for this + file was added fairly recently. + $(prefix)/etc/gitconfig:: System-wide configuration file. @@ -231,6 +240,10 @@ GIT_CONFIG:: Using the "--global" option forces this to ~/.gitconfig. Using the "--system" option forces this to $(prefix)/etc/gitconfig. +GIT_CONFIG_NOSYSTEM:: + Whether to skip reading settings from the system-wide + $(prefix)/etc/gitconfig file. See linkgit:git[1] for details. + See also <<FILES>>. diff --git a/Documentation/git-credential-cache--daemon.txt b/Documentation/git-credential-cache--daemon.txt index 11edc5a17..d15db42d4 100644 --- a/Documentation/git-credential-cache--daemon.txt +++ b/Documentation/git-credential-cache--daemon.txt @@ -3,7 +3,7 @@ git-credential-cache--daemon(1) NAME ---- -git-credential-cache--daemon - temporarily store user credentials in memory +git-credential-cache--daemon - Temporarily store user credentials in memory SYNOPSIS -------- diff --git a/Documentation/git-credential-cache.txt b/Documentation/git-credential-cache.txt index f3d09c5d5..eeff5fa98 100644 --- a/Documentation/git-credential-cache.txt +++ b/Documentation/git-credential-cache.txt @@ -3,7 +3,7 @@ git-credential-cache(1) NAME ---- -git-credential-cache - helper to temporarily store passwords in memory +git-credential-cache - Helper to temporarily store passwords in memory SYNOPSIS -------- diff --git a/Documentation/git-credential-store.txt b/Documentation/git-credential-store.txt index 31093467d..b27c03c36 100644 --- a/Documentation/git-credential-store.txt +++ b/Documentation/git-credential-store.txt @@ -3,7 +3,7 @@ git-credential-store(1) NAME ---- -git-credential-store - helper to store credentials on disk +git-credential-store - Helper to store credentials on disk SYNOPSIS -------- diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt new file mode 100644 index 000000000..810e95712 --- /dev/null +++ b/Documentation/git-credential.txt @@ -0,0 +1,154 @@ +git-credential(1) +================= + +NAME +---- +git-credential - Retrieve and store user credentials + +SYNOPSIS +-------- +------------------ +git credential <fill|approve|reject> +------------------ + +DESCRIPTION +----------- + +Git has an internal interface for storing and retrieving credentials +from system-specific helpers, as well as prompting the user for +usernames and passwords. The git-credential command exposes this +interface to scripts which may want to retrieve, store, or prompt for +credentials in the same manner as git. The design of this scriptable +interface models the internal C API; see +link:technical/api-credentials.txt[the git credential API] for more +background on the concepts. + +git-credential takes an "action" option on the command-line (one of +`fill`, `approve`, or `reject`) and reads a credential description +on stdin (see <<IOFMT,INPUT/OUTPUT FORMAT>>). + +If the action is `fill`, git-credential will attempt to add "username" +and "password" attributes to the description by reading config files, +by contacting any configured credential helpers, or by prompting the +user. The username and password attributes of the credential +description are then printed to stdout together with the attributes +already provided. + +If the action is `approve`, git-credential will send the description +to any configured credential helpers, which may store the credential +for later use. + +If the action is `reject`, git-credential will send the description to +any configured credential helpers, which may erase any stored +credential matching the description. + +If the action is `approve` or `reject`, no output should be emitted. + +TYPICAL USE OF GIT CREDENTIAL +----------------------------- + +An application using git-credential will typically use `git +credential` following these steps: + + 1. Generate a credential description based on the context. ++ +For example, if we want a password for +`https://example.com/foo.git`, we might generate the following +credential description (don't forget the blank line at the end; it +tells `git credential` that the application finished feeding all the +infomation it has): + + protocol=https + host=example.com + path=foo.git + + 2. Ask git-credential to give us a username and password for this + description. This is done by running `git credential fill`, + feeding the description from step (1) to its standard input. The complete + credential description (including the credential per se, i.e. the + login and password) will be produced on standard output, like: + + protocol=https + host=example.com + username=bob + password=secr3t ++ +In most cases, this means the attributes given in the input will be +repeated in the output, but git may also modify the credential +description, for example by removing the `path` attribute when the +protocol is HTTP(s) and `credential.useHttpPath` is false. ++ +If the `git credential` knew about the password, this step may +not have involved the user actually typing this password (the +user may have typed a password to unlock the keychain instead, +or no user interaction was done if the keychain was already +unlocked) before it returned `password=secr3t`. + + 3. Use the credential (e.g., access the URL with the username and + password from step (2)), and see if it's accepted. + + 4. Report on the success or failure of the password. If the + credential allowed the operation to complete successfully, then + it can be marked with an "approve" action to tell `git + credential` to reuse it in its next invocation. If the credential + was rejected during the operation, use the "reject" action so + that `git credential` will ask for a new password in its next + invocation. In either case, `git credential` should be fed with + the credential description obtained from step (2) (which also + contain the ones provided in step (1)). + +[[IOFMT]] +INPUT/OUTPUT FORMAT +------------------- + +`git credential` reads and/or writes (depending on the action used) +credential information in its standard input/output. This information +can correspond either to keys for which `git credential` will obtain +the login/password information (e.g. host, protocol, path), or to the +actual credential data to be obtained (login/password). + +The credential is split into a set of named attributes, with one +attribute per line. Each attribute is +specified by a key-value pair, separated by an `=` (equals) sign, +followed by a newline. The key may contain any bytes except `=`, +newline, or NUL. The value may contain any bytes except newline or NUL. +In both cases, all bytes are treated as-is (i.e., there is no quoting, +and one cannot transmit a value with newline or NUL in it). The list of +attributes is terminated by a blank line or end-of-file. +Git understands the following attributes: + +`protocol`:: + + The protocol over which the credential will be used (e.g., + `https`). + +`host`:: + + The remote hostname for a network credential. + +`path`:: + + The path with which the credential will be used. E.g., for + accessing a remote https repository, this will be the + repository's path on the server. + +`username`:: + + The credential's username, if we already have one (e.g., from a + URL, from the user, or from a previously run helper). + +`password`:: + + The credential's password, if we are asking it to be stored. + +`url`:: + + When this special attribute is read by `git credential`, the + value is parsed as a URL and treated as if its constituent parts + were read (e.g., `url=https://example.com` would behave as if + `protocol=https` and `host=example.com` had been provided). This + can help callers avoid parsing URLs themselves. Note that any + components which are missing from the URL (e.g., there is no + username in the example above) will be set to empty; if you want + to provide a URL and override some attributes, provide the URL + attribute first, followed by any overrides. diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt index 6695ab3b4..98d9881d7 100644 --- a/Documentation/git-cvsimport.txt +++ b/Documentation/git-cvsimport.txt @@ -137,17 +137,19 @@ This option can be used several times to provide several detection regexes. -A <author-conv-file>:: CVS by default uses the Unix username when writing its commit logs. Using this option and an author-conv-file - in this format + maps the name recorded in CVS to author name, e-mail and + optional timezone: + --------- exon=Andreas Ericsson <ae@op5.se> - spawn=Simon Pawn <spawn@frog-pond.org> + spawn=Simon Pawn <spawn@frog-pond.org> America/Chicago --------- + 'git cvsimport' will make it appear as those authors had their GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL set properly -all along. +all along. If a timezone is specified, GIT_AUTHOR_DATE will +have the corresponding offset applied. + For convenience, this data is saved to `$GIT_DIR/cvs-authors` each time the '-A' option is provided and read from that same diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt index e8f757704..7e5098a95 100644 --- a/Documentation/git-daemon.txt +++ b/Documentation/git-daemon.txt @@ -16,6 +16,7 @@ SYNOPSIS [--reuseaddr] [--detach] [--pid-file=<file>] [--enable=<service>] [--disable=<service>] [--allow-override=<service>] [--forbid-override=<service>] + [--access-hook=<path>] [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>] [--user=<user> [--group=<group>]] [<directory>...] @@ -171,6 +172,21 @@ the facility of inet daemon to achieve the same before spawning errors are not enabled, all errors report "access denied" to the client. The default is --no-informative-errors. +--access-hook=<path>:: + Every time a client connects, first run an external command + specified by the <path> with service name (e.g. "upload-pack"), + path to the repository, hostname (%H), canonical hostname + (%CH), ip address (%IP), and tcp port (%P) as its command line + arguments. The external command can decide to decline the + service by exiting with a non-zero status (or to allow it by + exiting with a zero status). It can also look at the $REMOTE_ADDR + and $REMOTE_PORT environment variables to learn about the + requestor when making this decision. ++ +The external command can optionally write a single line to its +standard output to be sent to the requestor as an error message when +it declines the service. + <directory>:: A directory to add to the whitelist of allowed directories. Unless --strict-paths is specified this will also include subdirectories diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt index f8d081911..f8c06013f 100644 --- a/Documentation/git-diff.txt +++ b/Documentation/git-diff.txt @@ -12,6 +12,7 @@ SYNOPSIS 'git diff' [options] [<commit>] [--] [<path>...] 'git diff' [options] --cached [<commit>] [--] [<path>...] 'git diff' [options] <commit> <commit> [--] [<path>...] +'git diff' [options] <blob> <blob> 'git diff' [options] [--no-index] [--] <path> <path> DESCRIPTION @@ -55,6 +56,11 @@ directories. This behavior can be forced by --no-index. This is to view the changes between two arbitrary <commit>. +'git diff' [options] <blob> <blob>:: + + This form is to view the differences between the raw + contents of two blob objects. + 'git diff' [--options] <commit>..<commit> [--] [<path>...]:: This is synonymous to the previous form. If <commit> on @@ -72,8 +78,7 @@ directories. This behavior can be forced by --no-index. Just in case if you are doing something exotic, it should be noted that all of the <commit> in the above description, except in the last two forms that use ".." notations, can be any -<tree>. The third form ('git diff <commit> <commit>') can also -be used to compare two <blob> objects. +<tree>. For a more complete list of ways to spell <commit>, see "SPECIFYING REVISIONS" section in linkgit:gitrevisions[7]. diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt index 31fc2e3ae..73ca7025a 100644 --- a/Documentation/git-difftool.txt +++ b/Documentation/git-difftool.txt @@ -69,6 +69,14 @@ with custom merge tool commands and has the same value as `$MERGED`. --tool-help:: Print a list of diff tools that may be used with `--tool`. +--symlinks:: +--no-symlinks:: + 'git difftool''s default behavior is create symlinks to the + working tree when run in `--dir-diff` mode. ++ + Specifying `--no-symlinks` instructs 'git difftool' to create + copies instead. `--no-symlinks` is the default on Windows. + -x <command>:: --extcmd=<command>:: Specify a custom command for viewing diffs. diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt index 2620d28b4..68bca1a29 100644 --- a/Documentation/git-fast-import.txt +++ b/Documentation/git-fast-import.txt @@ -39,6 +39,10 @@ OPTIONS See ``Date Formats'' below for details about which formats are supported, and their syntax. +-- done:: + Terminate with error if there is no 'done' command at the + end of the stream. + --force:: Force updating modified existing branches, even if doing so would cause commits to be lost (as the new commit does @@ -423,7 +427,7 @@ they made it. Here `<name>` is the person's display name (for example ``Com M Itter'') and `<email>` is the person's email address -(``cm@example.com''). `LT` and `GT` are the literal less-than (\x3c) +(``\cm@example.com''). `LT` and `GT` are the literal less-than (\x3c) and greater-than (\x3e) symbols. These are required to delimit the email address from the other fields in the line. Note that `<name>` and `<email>` are free-form and may contain any sequence @@ -438,7 +442,9 @@ their syntax. ^^^^^^ The `from` command is used to specify the commit to initialize this branch from. This revision will be the first ancestor of the -new commit. +new commit. The state of the tree built at this commit will begin +with the state at the `from` commit, and be altered by the content +modifications in this commit. Omitting the `from` command in the first commit of a new branch will cause fast-import to create that commit with no ancestor. This @@ -488,7 +494,9 @@ existing value of the branch. `merge` ^^^^^^^ -Includes one additional ancestor commit. If the `from` command is +Includes one additional ancestor commit. The additional ancestry +link does not change the way the tree state is built at this commit. +If the `from` command is omitted when creating a new branch, the first `merge` commit will be the first ancestor of the current commit, and the branch will start out with no files. An unlimited number of `merge` commands per @@ -554,8 +562,12 @@ A `<path>` string must use UNIX-style directory separators (forward slash `/`), may contain any byte other than `LF`, and must not start with double quote (`"`). -If an `LF` or double quote must be encoded into `<path>` shell-style -quoting should be used, e.g. `"path/with\n and \" in it"`. +A path can use C-style string quoting; this is accepted in all cases +and mandatory if the filename starts with double quote or contains +`LF`. In C-style quoting, the complete name should be surrounded with +double quotes, and any `LF`, backslash, or double quote characters +must be escaped by preceding them with a backslash (e.g., +`"path/with\n, \\ and \" in it"`). The value of `<path>` must be in canonical form. That is it must not: @@ -1047,7 +1059,9 @@ done:: Error out if the stream ends without a 'done' command. Without this feature, errors causing the frontend to end abruptly at a convenient point in the stream can go - undetected. + undetected. This may occur, for example, if an import + front end dies in mid-operation without emitting SIGTERM + or SIGKILL at its subordinate git fast-import instance. `option` ~~~~~~~~ diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt index 474fa307a..8c751202d 100644 --- a/Documentation/git-fetch-pack.txt +++ b/Documentation/git-fetch-pack.txt @@ -9,7 +9,10 @@ git-fetch-pack - Receive missing objects from another repository SYNOPSIS -------- [verse] -'git fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...] +'git fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] + [--upload-pack=<git-upload-pack>] + [--depth=<n>] [--no-progress] + [-v] [<host>:]<directory> [<refs>...] DESCRIPTION ----------- diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt index 15e7ac80c..e2301f5c0 100644 --- a/Documentation/git-filter-branch.txt +++ b/Documentation/git-filter-branch.txt @@ -304,6 +304,11 @@ committed a merge between P1 and P2, it will be propagated properly and all children of the merge will become merge commits with P1,P2 as their parents instead of the merge commit. +*NOTE* the changes introduced by the commits, and which are not reverted +by subsequent commits, will still be in the rewritten branch. If you want +to throw out _changes_ together with the commits, you should use the +interactive mode of 'git rebase'. + You can rewrite the commit log messages using `--msg-filter`. For example, 'git svn-id' strings in a repository created by 'git svn' can be removed this way: @@ -314,11 +319,6 @@ git filter-branch --msg-filter ' ' ------------------------------------------------------- -To restrict rewriting to only part of the history, specify a revision -range in addition to the new branch name. The new branch name will -point to the top-most revision that a 'git rev-list' of this range -will print. - If you need to add 'Acked-by' lines to, say, the last 10 commits (none of which is a merge), use this command: @@ -329,11 +329,10 @@ git filter-branch --msg-filter ' ' HEAD~10..HEAD -------------------------------------------------------- -*NOTE* the changes introduced by the commits, and which are not reverted -by subsequent commits, will still be in the rewritten branch. If you want -to throw out _changes_ together with the commits, you should use the -interactive mode of 'git rebase'. - +To restrict rewriting to only part of the history, specify a revision +range in addition to the new branch name. The new branch name will +point to the top-most revision that a 'git rev-list' of this range +will print. Consider this history: diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index c872b883b..db55a4e0b 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -102,9 +102,10 @@ Fields that have name-email-date tuple as its value (`author`, and `date` to extract the named component. The complete message in a commit and tag object is `contents`. -Its first line is `contents:subject`, the remaining lines -are `contents:body` and the optional GPG signature -is `contents:signature`. +Its first line is `contents:subject`, where subject is the concatenation +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. Finally, the optional GPG signature is `contents:signature`. For sorting purposes, fields with numeric values sort in numeric order (`objectsize`, `authordate`, `committerdate`, `taggerdate`). diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 04c7346e3..259dce499 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -20,7 +20,7 @@ SYNOPSIS [--ignore-if-in-upstream] [--subject-prefix=Subject-Prefix] [--to=<email>] [--cc=<email>] - [--cover-letter] [--quiet] + [--cover-letter] [--quiet] [--notes[=<ref>]] [<common diff options>] [ <since> | <revision range> ] @@ -58,10 +58,13 @@ output, unless the `--stdout` option is specified. If `-o` is specified, output files are created in <dir>. Otherwise they are created in the current working directory. -By default, the subject of a single patch is "[PATCH] First Line" and -the subject when multiple patches are output is "[PATCH n/m] First -Line". To force 1/1 to be added for a single patch, use `-n`. To omit -patch numbers from the subject, use `-N`. +By default, the subject of a single patch is "[PATCH] " followed by +the concatenation of lines from the commit message up to the first blank +line (see the DISCUSSION section of linkgit:git-commit[1]). + +When multiple patches are output, the subject prefix will instead be +"[PATCH n/m] ". To force 1/1 to be added for a single patch, use `-n`. +To omit patch numbers from the subject, use `-N`. If given `--thread`, `git-format-patch` will generate `In-Reply-To` and `References` headers to make the second and subsequent patch mails appear @@ -188,6 +191,18 @@ will want to ensure that threading is disabled for `git send-email`. containing the shortlog and the overall diffstat. You can fill in a description in the file before sending it out. +--notes[=<ref>]:: + Append the notes (see linkgit:git-notes[1]) for the commit + after the three-dash line. ++ +The expected use case of this is to write supporting explanation for +the commit that does not belong to the commit log message proper, +and include it with the patch submission. While one can simply write +these explanations after `format-patch` has run but before sending, +keeping them as git notes allows them to be maintained between versions +of the patch series (but see the discussion of the `notes.rewrite` +configuration options in linkgit:git-notes[1] to use this workflow). + --[no]-signature=<signature>:: Add a signature to each message produced. Per RFC 3676 the signature is separated from the body by a line with '-- ' on it. If the diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 3bec03688..cfecf848f 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -42,8 +42,16 @@ CONFIGURATION grep.lineNumber:: If set to true, enable '-n' option by default. +grep.patternType:: + Set the default matching behavior. Using a value of 'basic', 'extended', + 'fixed', or 'perl' will enable the '--basic-regexp', '--extended-regexp', + '--fixed-strings', or '--perl-regexp' option accordingly, while the + value 'default' will return to the default matching behavior. + grep.extendedRegexp:: - If set to true, enable '--extended-regexp' option by default. + If set to true, enable '--extended-regexp' option by default. This + option is ignored when the 'grep.patternType' option is set to a value + other than 'default'. OPTIONS diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt index 1f906208f..585dac40b 100644 --- a/Documentation/git-log.txt +++ b/Documentation/git-log.txt @@ -24,10 +24,6 @@ each commit introduces are shown. OPTIONS ------- --<n>:: - Limits the number of commits to show. - Note that this is a commit limiting option, see below. - <since>..<until>:: Show only commits between the named two commits. When either <since> or <until> is omitted, it defaults to @@ -137,6 +133,8 @@ Examples This makes sense only when following a strict policy of merging all topic branches when staying on a single integration branch. +`git log -3`:: + Limits the number of commits to show to 3. Discussion ---------- diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt index 7a9b86a58..774de5e9d 100644 --- a/Documentation/git-ls-remote.txt +++ b/Documentation/git-ls-remote.txt @@ -42,6 +42,11 @@ OPTIONS it successfully talked with the remote repository, whether it found any matching refs. +--get-url:: + Expand the URL of the given remote repository taking into account any + "url.<base>.insteadOf" config setting (See linkgit:git-config[1]) and + exit without talking to the remote. + <repository>:: Location of the repository. The shorthand defined in $GIT_DIR/branches/ can be used. Use "." (dot) to list references in diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.txt index b295bf833..87842e33f 100644 --- a/Documentation/git-merge-base.txt +++ b/Documentation/git-merge-base.txt @@ -11,6 +11,7 @@ SYNOPSIS [verse] 'git merge-base' [-a|--all] <commit> <commit>... 'git merge-base' [-a|--all] --octopus <commit>... +'git merge-base' --is-ancestor <commit> <commit> 'git merge-base' --independent <commit>... DESCRIPTION @@ -50,6 +51,12 @@ from linkgit:git-show-branch[1] when used with the `--merge-base` option. from any other. This mimics the behavior of 'git show-branch --independent'. +--is-ancestor:: + Check if the first <commit> is an ancestor of the second <commit>, + and exit with status 0 if true, or with status 1 if not. + Errors are signaled by a non-zero status that is not 1. + + OPTIONS ------- -a:: @@ -110,6 +117,27 @@ both '1' and '2' are merge-bases of A and B. Neither one is better than the other (both are 'best' merge bases). When the `--all` option is not given, it is unspecified which best one is output. +A common idiom to check "fast-forward-ness" between two commits A +and B is (or at least used to be) to compute the merge base between +A and B, and check if it is the same as A, in which case, A is an +ancestor of B. You will see this idiom used often in older scripts. + + A=$(git rev-parse --verify A) + if test "$A" = "$(git merge-base A B)" + then + ... A is an ancestor of B ... + fi + +In modern git, you can say this in a more direct way: + + if git merge-base --is-ancestor A B + then + ... A is an ancestor of B ... + fi + +instead. + + See also -------- linkgit:git-rev-list[1], diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index 20f922851..d34ea3c50 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -99,7 +99,7 @@ commit or stash your changes before running 'git merge'. more than two parents (affectionately called an Octopus merge). + If no commit is given from the command line, and if `merge.defaultToUpstream` -configuration variable is set, merge the remote tracking branches +configuration variable is set, merge the remote-tracking branches that the current branch is configured to use as its upstream. See also the configuration section of this manual page. diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index d7207bd9b..6b563c500 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -64,6 +64,9 @@ variable `mergetool.<tool>.trustExitCode` can be set to `true`. Otherwise, 'git mergetool' will prompt the user to indicate the success of the resolution after the custom tool has exited. +--tool-help:: + Print a list of merge tools that may be used with `--tool`. + -y:: --no-prompt:: Don't prompt before each invocation of the merge resolution diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt index b95aafae2..46ef0466b 100644 --- a/Documentation/git-notes.txt +++ b/Documentation/git-notes.txt @@ -39,6 +39,10 @@ message stored in the commit object, the notes are indented like the message, after an unindented line saying "Notes (<refname>):" (or "Notes:" for `refs/notes/commits`). +Notes can also be added to patches prepared with `git format-patch` by +using the `--notes` option. Such notes are added as a patch commentary +after a three dash separator line. + To change which notes are shown by 'git log', see the "notes.displayRef" configuration in linkgit:git-log[1]. diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt index fe1f49bc6..beff6229c 100644 --- a/Documentation/git-p4.txt +++ b/Documentation/git-p4.txt @@ -163,7 +163,7 @@ All commands except clone accept these options. --git-dir <dir>:: Set the 'GIT_DIR' environment variable. See linkgit:git[1]. ---verbose:: +--verbose, -v:: Provide more progress information. Sync options @@ -255,7 +255,7 @@ These options can be used to modify 'git p4 submit' behavior. p4. By default, this is the most recent p4 commit reachable from 'HEAD'. --M[<n>]:: +-M:: Detect renames. See linkgit:git-diff[1]. Renames will be represented in p4 using explicit 'move' operations. There is no corresponding option to detect copies, but there are @@ -269,6 +269,24 @@ These options can be used to modify 'git p4 submit' behavior. Export tags from git as p4 labels. Tags found in git are applied to the perforce working directory. +--dry-run, -n:: + Show just what commits would be submitted to p4; do not change + state in git or p4. + +--prepare-p4-only:: + Apply a commit to the p4 workspace, opening, adding and deleting + files in p4 as for a normal submit operation. Do not issue the + final "p4 submit", but instead print a message about how to + submit manually or revert. This option always stops after the + first (oldest) commit. Git tags are not exported to p4. + +--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 + skip this commit and continue, or quit. This option can be used + to bypass the prompt, causing conflicting commits to be automatically + skipped, or to quit trying to apply commits, without prompting. + Rebase options ~~~~~~~~~~~~~~ These options can be used to modify 'git p4 rebase' behavior. @@ -465,13 +483,15 @@ git-p4.useClientSpec:: Submit variables ~~~~~~~~~~~~~~~~ git-p4.detectRenames:: - Detect renames. See linkgit:git-diff[1]. + Detect renames. See linkgit:git-diff[1]. This can be true, + false, or a score as expected by 'git diff -M'. git-p4.detectCopies:: - Detect copies. See linkgit:git-diff[1]. + Detect copies. See linkgit:git-diff[1]. This can be true, + false, or a score as expected by 'git diff -C'. git-p4.detectCopiesHarder:: - Detect copies harder. See linkgit:git-diff[1]. + Detect copies harder. See linkgit:git-diff[1]. A boolean. git-p4.preserveUser:: On submit, re-author changes to reflect the git author, @@ -517,6 +537,10 @@ git-p4.labelExportRegexp:: Only p4 labels matching this regular expression will be exported. The default value is '[a-zA-Z0-9_\-.]+$'. +git-p4.conflict:: + Specify submit behavior when a conflict with p4 is found, as per + --conflict. The default behavior is 'ask'. + IMPLEMENTATION DETAILS ---------------------- * Changesets from p4 are imported using git fast-import. diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index cb97cc1c3..8b637d339 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -37,7 +37,9 @@ OPTIONS[[OPTIONS]] `+`, followed by the source ref <src>, followed by a colon `:`, followed by the destination ref <dst>. It is used to specify with what <src> object the <dst> ref - in the remote repository is to be updated. + in the remote repository is to be updated. If not specified, + the behavior of the command is controlled by the `push.default` + configuration variable. + The <src> is often the name of the branch you would want to push, but it can be any arbitrary "SHA-1 expression", such as `master~4` or @@ -65,7 +67,8 @@ directs git to push "matching" branches: for every branch that exists on the local side, the remote side is updated if a branch of the same name already exists on the remote side. This is the default operation mode if no explicit refspec is found (that is neither on the command line -nor in any Push line of the corresponding remotes file---see below). +nor in any Push line of the corresponding remotes file---see below) and +no `push.default` configuration variable is set. --all:: Instead of naming each ref to push, specifies that all @@ -172,7 +175,7 @@ useful if you write an alias or script around 'git push'. --recurse-submodules=check|on-demand:: Make sure all submodule commits used by the revisions to be - pushed are available on a remote tracking branch. If 'check' is + pushed are available on a remote-tracking branch. If 'check' is used git will verify that all submodule commits that changed in the revisions to be pushed are available on at least one remote of the submodule. If any commits are missing the push will be @@ -283,7 +286,8 @@ leading to commit A. The history looks like this: ---------------- Further suppose that the other person already pushed changes leading to A -back to the original repository you two obtained the original commit X. +back to the original repository from which you two obtained the original +commit X. The push done by the other person updated the branch that used to point at commit X to point at commit A. It is a fast-forward. @@ -357,7 +361,8 @@ Examples `git push origin :`. + The default behavior of this command when no <refspec> is given can be -configured by setting the `push` option of the remote. +configured by setting the `push` option of the remote, or the `push.default` +configuration variable. + For example, to default to pushing only the current branch to `origin` use `git config remote.origin.push HEAD`. Any valid <refspec> (like @@ -380,11 +385,23 @@ the ones in the examples below) can be configured as the default for A handy way to push the current branch to the same name on the remote. -`git push origin master:satellite/master dev:satellite/dev`:: +`git push mothership master:satellite/master dev:satellite/dev`:: Use the source ref that matches `master` (e.g. `refs/heads/master`) to update the ref that matches `satellite/master` (most probably - `refs/remotes/satellite/master`) in the `origin` repository, then + `refs/remotes/satellite/master`) in the `mothership` repository; do the same for `dev` and `satellite/dev`. ++ +This is to emulate `git fetch` run on the `mothership` using `git +push` that is run in the opposite direction in order to integrate +the work done on `satellite`, and is often necessary when you can +only make connection in one way (i.e. satellite can ssh into +mothership but mothership cannot initiate connection to satellite +because the latter is behind a firewall or does not run sshd). ++ +After running this `git push` on the `satellite` machine, you would +ssh into the `mothership` and run `git merge` there to complete the +emulation of `git pull` that were run on `mothership` to pull changes +made on `satellite`. `git push origin HEAD:master`:: Push the current branch to the remote ref matching `master` in the diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index feb51a6ea..da067ecaf 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -8,11 +8,11 @@ git-rebase - Forward-port local commits to the updated upstream head SYNOPSIS -------- [verse] -'git rebase' [-i | --interactive] [options] [--onto <newbase>] +'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>] -'git rebase' [-i | --interactive] [options] --onto <newbase> +'git rebase' [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>] -'git rebase' --continue | --skip | --abort +'git rebase' --continue | --skip | --abort | --edit-todo DESCRIPTION ----------- @@ -210,7 +210,7 @@ rebase.autosquash:: OPTIONS ------- -<newbase>:: +--onto <newbase>:: Starting point at which to create the new commits. If the --onto option is not specified, the starting point is <upstream>. May be any valid commit, and not just an @@ -245,6 +245,9 @@ leave out at most one of A and B, in which case it defaults to HEAD. --skip:: Restart the rebasing process by skipping the current patch. +--edit-todo:: + Edit the todo list during an interactive rebase. + -m:: --merge:: Use merging strategies to rebase. When the recursive (default) merge @@ -344,14 +347,36 @@ This uses the `--interactive` machinery internally, but combining it with the `--interactive` option explicitly is generally not a good idea unless you know what you are doing (see BUGS below). +-x <cmd>:: +--exec <cmd>:: + Append "exec <cmd>" after each line creating a commit in the + final history. <cmd> will be interpreted as one or more shell + commands. ++ +This option can only be used with the `--interactive` option +(see INTERACTIVE MODE below). ++ +You may execute several commands by either using one instance of `--exec` +with several commands: ++ + git rebase -i --exec "cmd1 && cmd2 && ..." ++ +or by giving more than one `--exec`: ++ + git rebase -i --exec "cmd1" --exec "cmd2" --exec ... ++ +If `--autosquash` is used, "exec" lines will not be appended for +the intermediate commits, and will only appear at the end of each +squash/fixup series. --root:: Rebase all commits reachable from <branch>, instead of limiting them with an <upstream>. This allows you to rebase - the root commit(s) on a branch. Must be used with --onto, and + the root commit(s) on a branch. When used with --onto, it will skip changes already contained in <newbase> (instead of - <upstream>). When used together with --preserve-merges, 'all' - root commits will be rewritten to have <newbase> as parent + <upstream>) whereas without --onto it will operate on every change. + When used together with both --onto and --preserve-merges, + 'all' root commits will be rewritten to have <newbase> as parent instead. --autosquash:: @@ -521,6 +546,24 @@ in `$SHELL`, or the default shell if `$SHELL` is not set), so you can use shell features (like "cd", ">", ";" ...). The command is run from the root of the working tree. +---------------------------------- +$ git rebase -i --exec "make test" +---------------------------------- + +This command lets you check that intermediate commits are compilable. +The todo list becomes like that: + +-------------------- +pick 5928aea one +exec make test +pick 04d0fda two +exec make test +pick ba46169 three +exec make test +pick f4593f9 four +exec make test +-------------------- + SPLITTING COMMITS ----------------- diff --git a/Documentation/git-remote-helpers.txt b/Documentation/git-remote-helpers.txt index f5836e46d..6d696e0f9 100644 --- a/Documentation/git-remote-helpers.txt +++ b/Documentation/git-remote-helpers.txt @@ -35,6 +35,37 @@ transport protocols, such as 'git-remote-http', 'git-remote-https', 'git-remote-ftp' and 'git-remote-ftps'. They implement the capabilities 'fetch', 'option', and 'push'. +INVOCATION +---------- + +Remote helper programs are invoked with one or (optionally) two +arguments. The first argument specifies a remote repository as in git; +it is either the name of a configured remote or a URL. The second +argument specifies a URL; it is usually of the form +'<transport>://<address>', but any arbitrary string is possible. +The 'GIT_DIR' environment variable is set up for the remote helper +and can be used to determine where to store additional data or from +which directory to invoke auxiliary git commands. + +When git encounters a URL of the form '<transport>://<address>', where +'<transport>' is a protocol that it cannot handle natively, it +automatically invokes 'git remote-<transport>' with the full URL as +the second argument. If such a URL is encountered directly on the +command line, the first argument is the same as the second, and if it +is encountered in a configured remote, the first argument is the name +of that remote. + +A URL of the form '<transport>::<address>' explicitly instructs git to +invoke 'git remote-<transport>' with '<address>' as the second +argument. If such a URL is encountered directly on the command line, +the first argument is '<address>', and if it is encountered in a +configured remote, the first argument is the name of that remote. + +Additionally, when a configured remote has 'remote.<name>.vcs' set to +'<transport>', git explicitly invokes 'git remote-<transport>' with +'<name>' as the first argument. If set, the second argument is +'remote.<name>.url'; otherwise, the second argument is omitted. + INPUT FORMAT ------------ @@ -57,53 +88,17 @@ Each remote helper is expected to support only a subset of commands. The operations a helper supports are declared to git in the response to the `capabilities` command (see COMMANDS, below). -'option':: - For specifying settings like `verbosity` (how much output to - write to stderr) and `depth` (how much history is wanted in the - case of a shallow clone) that affect how other commands are - carried out. - -'connect':: - For fetching and pushing using git's native packfile protocol - that requires a bidirectional, full-duplex connection. - -'push':: - For listing remote refs and pushing specified objects from the - local object store to remote refs. - -'fetch':: - For listing remote refs and fetching the associated history to - the local object store. - -'import':: - For listing remote refs and fetching the associated history as - a fast-import stream. - -'refspec' <refspec>:: - This modifies the 'import' capability, allowing the produced - fast-import stream to modify refs in a private namespace - instead of writing to refs/heads or refs/remotes directly. - It is recommended that all importers providing the 'import' - capability use this. -+ -A helper advertising the capability -`refspec refs/heads/*:refs/svn/origin/branches/*` -is saying that, when it is asked to `import refs/heads/topic`, the -stream it outputs will update the `refs/svn/origin/branches/topic` -ref. -+ -This capability can be advertised multiple times. The first -applicable refspec takes precedence. The left-hand of refspecs -advertised with this capability must cover all refs reported by -the list command. If no 'refspec' capability is advertised, -there is an implied `refspec *:*`. +In the following, we list all defined capabilities and for +each we list which commands a helper with that capability +must provide. Capabilities for Pushing -~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^ 'connect':: Can attempt to connect to 'git receive-pack' (for pushing), - 'git upload-pack', etc for communication using the - packfile protocol. + 'git upload-pack', etc for communication using + git's native packfile protocol. This + requires a bidirectional, full-duplex connection. + Supported commands: 'connect'. @@ -113,16 +108,26 @@ Supported commands: 'connect'. + Supported commands: 'list for-push', 'push'. -If a helper advertises both 'connect' and 'push', git will use -'connect' if possible and fall back to 'push' if the helper requests -so when connecting (see the 'connect' command under COMMANDS). +'export':: + Can discover remote refs and push specified objects from a + fast-import stream to remote refs. ++ +Supported commands: 'list for-push', 'export'. + +If a helper advertises 'connect', git will use it if possible and +fall back to another capability if the helper requests so when +connecting (see the 'connect' command under COMMANDS). +When choosing between 'push' and 'export', git prefers 'push'. +Other frontends may have some other order of preference. + Capabilities for Fetching -~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^ 'connect':: Can try to connect to 'git upload-pack' (for fetching), 'git receive-pack', etc for communication using the - packfile protocol. + git's native packfile protocol. This + requires a bidirectional, full-duplex connection. + Supported commands: 'connect'. @@ -144,14 +149,27 @@ connecting (see the 'connect' command under COMMANDS). When choosing between 'fetch' and 'import', git prefers 'fetch'. Other frontends may have some other order of preference. +Miscellaneous capabilities +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +'option':: + For specifying settings like `verbosity` (how much output to + write to stderr) and `depth` (how much history is wanted in the + case of a shallow clone) that affect how other commands are + carried out. + 'refspec' <refspec>:: - This modifies the 'import' capability. + This modifies the 'import' capability, allowing the produced + fast-import stream to modify refs in a private namespace + instead of writing to refs/heads or refs/remotes directly. + It is recommended that all importers providing the 'import' + capability use this. + -A helper advertising +A helper advertising the capability `refspec refs/heads/*:refs/svn/origin/branches/*` -in its capabilities is saying that, when it handles -`import refs/heads/topic`, the stream it outputs will update the -`refs/svn/origin/branches/topic` ref. +is saying that, when it is asked to `import refs/heads/topic`, the +stream it outputs will update the `refs/svn/origin/branches/topic` +ref. + This capability can be advertised multiple times. The first applicable refspec takes precedence. The left-hand of refspecs @@ -159,36 +177,33 @@ advertised with this capability must cover all refs reported by the list command. If no 'refspec' capability is advertised, there is an implied `refspec *:*`. -INVOCATION ----------- +'bidi-import':: + This modifies the 'import' capability. + The fast-import commands 'cat-blob' and 'ls' can be used by remote-helpers + to retrieve information about blobs and trees that already exist in + fast-import's memory. This requires a channel from fast-import to the + remote-helper. + If it is advertised in addition to "import", git establishes a pipe from + fast-import to the remote-helper's stdin. + It follows that git and fast-import are both connected to the + remote-helper's stdin. Because git can send multiple commands to + the remote-helper it is required that helpers that use 'bidi-import' + buffer all 'import' commands of a batch before sending data to fast-import. + This is to prevent mixing commands and fast-import responses on the + helper's stdin. -Remote helper programs are invoked with one or (optionally) two -arguments. The first argument specifies a remote repository as in git; -it is either the name of a configured remote or a URL. The second -argument specifies a URL; it is usually of the form -'<transport>://<address>', but any arbitrary string is possible. -The 'GIT_DIR' environment variable is set up for the remote helper -and can be used to determine where to store additional data or from -which directory to invoke auxiliary git commands. +'export-marks' <file>:: + This modifies the 'export' capability, instructing git to dump the + internal marks table to <file> when complete. For details, + read up on '--export-marks=<file>' in linkgit:git-fast-export[1]. + +'import-marks' <file>:: + This modifies the 'export' capability, instructing git to load the + marks specified in <file> before processing any input. For details, + read up on '--import-marks=<file>' in linkgit:git-fast-export[1]. -When git encounters a URL of the form '<transport>://<address>', where -'<transport>' is a protocol that it cannot handle natively, it -automatically invokes 'git remote-<transport>' with the full URL as -the second argument. If such a URL is encountered directly on the -command line, the first argument is the same as the second, and if it -is encountered in a configured remote, the first argument is the name -of that remote. -A URL of the form '<transport>::<address>' explicitly instructs git to -invoke 'git remote-<transport>' with '<address>' as the second -argument. If such a URL is encountered directly on the command line, -the first argument is '<address>', and if it is encountered in a -configured remote, the first argument is the name of that remote. -Additionally, when a configured remote has 'remote.<name>.vcs' set to -'<transport>', git explicitly invokes 'git remote-<transport>' with -'<name>' as the first argument. If set, the second argument is -'remote.<name>.url'; otherwise, the second argument is omitted. COMMANDS -------- @@ -198,9 +213,11 @@ Commands are given by the caller on the helper's standard input, one per line. 'capabilities':: Lists the capabilities of the helper, one per line, ending with a blank line. Each capability may be preceded with '*', - which marks them mandatory for git version using the remote - helper to understand (unknown mandatory capability is fatal - error). + which marks them mandatory for git versions using the remote + helper to understand. Any unknown mandatory capability is a + fatal error. ++ +Support for this command is mandatory. 'list':: Lists the refs, one per line, in the format "<value> <name> @@ -210,9 +227,20 @@ Commands are given by the caller on the helper's standard input, one per line. the name; unrecognized attributes are ignored. The list ends with a blank line. + -If 'push' is supported this may be called as 'list for-push' -to obtain the current refs prior to sending one or more 'push' -commands to the helper. +See REF LIST ATTRIBUTES for a list of currently defined attributes. ++ +Supported if the helper has the "fetch" or "import" capability. + +'list for-push':: + Similar to 'list', except that it is used if and only if + the caller wants to the resulting ref list to prepare + push commands. + A helper supporting both push and fetch can use this + to distinguish for which operation the output of 'list' + is going to be used, possibly reducing the amount + of work that needs to be performed. ++ +Supported if the helper has the "push" or "export" capability. 'option' <name> <value>:: Sets the transport helper option <name> to <value>. Outputs a @@ -222,6 +250,8 @@ commands to the helper. for it). Options should be set before other commands, and may influence the behavior of those commands. + +See OPTIONS for a list of currently defined options. ++ Supported if the helper has the "option" capability. 'fetch' <sha1> <name>:: @@ -230,7 +260,7 @@ Supported if the helper has the "option" capability. per line, terminated with a blank line. Outputs a single blank line when all fetch commands in the same batch are complete. Only objects which were reported - in the ref list with a sha1 may be fetched this way. + in the output of 'list' with a sha1 may be fetched this way. + Optionally may output a 'lock <file>' line indicating a file under GIT_DIR/objects/pack which is keeping a pack until refs can be @@ -286,8 +316,29 @@ terminated with a blank line. For each batch of 'import', the remote helper should produce a fast-import stream terminated by a 'done' command. + +Note that if the 'bidi-import' capability is used the complete batch +sequence has to be buffered before starting to send data to fast-import +to prevent mixing of commands and fast-import responses on the helper's +stdin. ++ Supported if the helper has the "import" capability. +'export':: + Instructs the remote helper that any subsequent input is + part of a fast-import stream (generated by 'git fast-export') + containing objects which should be pushed to the remote. ++ +Especially useful for interoperability with a foreign versioning +system. ++ +The 'export-marks' and 'import-marks' capabilities, if specified, +affect this command in so far as they are passed on to 'git +fast-export', which then will load/store a table of marks for +local objects. This can be used to implement for incremental +operations. ++ +Supported if the helper has the "export" capability. + 'connect' <service>:: Connects to given service. Standard input and standard output of helper are connected to specified service (git prefix is @@ -313,10 +364,9 @@ capabilities reported by the helper. REF LIST ATTRIBUTES ------------------- -'for-push':: - The caller wants to use the ref list to prepare push - commands. A helper might chose to acquire the ref list by - opening a different type of connection to the destination. +The 'list' command produces a list of refs in which each ref +may be followed by a list of attributes. The following ref list +attributes are defined. 'unchanged':: This ref is unchanged since the last import or fetch, although @@ -324,6 +374,10 @@ REF LIST ATTRIBUTES OPTIONS ------- + +The following options are defined and (under suitable circumstances) +set by git if the remote helper has the 'option' capability. + 'option verbosity' <n>:: Changes the verbosity of messages displayed by the helper. A value of 0 for <n> means that processes operate diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt index a308f4c79..e8c396b5f 100644 --- a/Documentation/git-remote.txt +++ b/Documentation/git-remote.txt @@ -12,7 +12,7 @@ SYNOPSIS 'git remote' [-v | --verbose] 'git remote add' [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url> 'git remote rename' <old> <new> -'git remote rm' <name> +'git remote remove' <name> 'git remote set-head' <name> (-a | -d | <branch>) 'git remote set-branches' [--add] <name> <branch>... 'git remote set-url' [--push] <name> <newurl> [<oldurl>] @@ -85,6 +85,7 @@ In case <old> and <new> are the same, and <old> is a file under `$GIT_DIR/remotes` or `$GIT_DIR/branches`, the remote is converted to the configuration file format. +'remove':: 'rm':: Remove the remote named <name>. All remote-tracking branches and diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt index 117e3743a..978d8da50 100644 --- a/Documentation/git-reset.txt +++ b/Documentation/git-reset.txt @@ -10,7 +10,7 @@ SYNOPSIS [verse] 'git reset' [-q] [<commit>] [--] <paths>... 'git reset' (--patch | -p) [<commit>] [--] [<paths>...] -'git reset' (--soft | --mixed | --hard | --merge | --keep) [-q] [<commit>] +'git reset' [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>] DESCRIPTION ----------- @@ -43,11 +43,11 @@ This means that `git reset -p` is the opposite of `git add -p`, i.e. you can use it to selectively reset hunks. See the ``Interactive Mode'' section of linkgit:git-add[1] to learn how to operate the `--patch` mode. -'git reset' --<mode> [<commit>]:: +'git reset' [<mode>] [<commit>]:: This form resets the current branch head to <commit> and possibly updates the index (resetting it to the tree of <commit>) and - the working tree depending on <mode>, which - must be one of the following: + the working tree depending on <mode>. If <mode> is omitted, + defaults to "--mixed". The <mode> must be one of the following: + -- --soft:: diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 4cc3e9586..3c63561f0 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -101,6 +101,12 @@ OPTIONS The option core.warnAmbiguousRefs is used to select the strict abbreviation mode. +--disambiguate=<prefix>:: + Show every object whose name begins with the given prefix. + The <prefix> must be at least 4 hexadecimal digits long to + avoid listing each and every object in the repository by + mistake. + --all:: Show all refs found in `refs/`. diff --git a/Documentation/git-rm.txt b/Documentation/git-rm.txt index 5d31860eb..262436b7b 100644 --- a/Documentation/git-rm.txt +++ b/Documentation/git-rm.txt @@ -134,6 +134,21 @@ use the following command: git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached ---------------- +Submodules +~~~~~~~~~~ +Only submodules using a gitfile (which means they were cloned +with a git version 1.7.8 or newer) will be removed from the work +tree, as their repository lives inside the .git directory of the +superproject. If a submodule (or one of those nested inside it) +still uses a .git directory, `git rm` will fail - no matter if forced +or not - to protect the submodule's history. + +A submodule is considered up-to-date when the HEAD is the same as +recorded in the index, no tracked files are modified and no untracked +files that aren't ignored are present in the submodules work tree. +Ignored files are deemed expendable and won't stop a submodule's work +tree from being removed. + EXAMPLES -------- `git rm Documentation/\*.txt`:: diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 324117072..eeb561cf1 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -126,6 +126,10 @@ The --to option must be repeated for each user you want on the to list. + Note that no attempts whatsoever are made to validate the encoding. +--compose-encoding=<encoding>:: + Specify encoding of compose message. Default is the value of the + 'sendemail.composeencoding'; if that is unspecified, UTF-8 is assumed. + Sending ~~~~~~~ diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt index 01d841731..afeb4cdf1 100644 --- a/Documentation/git-shortlog.txt +++ b/Documentation/git-shortlog.txt @@ -14,8 +14,7 @@ git log --pretty=short | 'git shortlog' [-h] [-n] [-s] [-e] [-w] DESCRIPTION ----------- Summarizes 'git log' output in a format suitable for inclusion -in release announcements. Each commit will be grouped by author and -the first line of the commit message will be shown. +in release announcements. Each commit will be grouped by author and title. Additionally, "[PATCH]" will be stripped from the commit description. diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt index 0aa4e20ea..711ffe17a 100644 --- a/Documentation/git-stash.txt +++ b/Documentation/git-stash.txt @@ -144,7 +144,7 @@ drop [-q|--quiet] [<stash>]:: Remove a single stashed state from the stash list. When no `<stash>` is given, it removes the latest one. i.e. `stash@{0}`, otherwise - `<stash>` must a valid stash log reference of the form + `<stash>` must be a valid stash log reference of the form `stash@{<revision>}`. create:: diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index 67e5f53a9..9f1ef9a46 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -38,6 +38,9 @@ OPTIONS across git versions and regardless of user configuration. See below for details. +--long:: + Give the output in the long-format. This is the default. + -u[<mode>]:: --untracked-files[=<mode>]:: Show untracked files. diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index 2de7bf090..b1de3bade 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -9,7 +9,7 @@ git-submodule - Initialize, update or inspect submodules SYNOPSIS -------- [verse] -'git submodule' [--quiet] add [-b branch] [-f|--force] +'git submodule' [--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>] 'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...] 'git submodule' [--quiet] init [--] [<path>...] @@ -112,7 +112,6 @@ status:: initialized, `+` if the currently checked out submodule commit does not match the SHA-1 found in the index of the containing repository and `U` if the submodule has merge conflicts. - This command is the default command for 'git submodule'. + If `--recursive` is specified, this command will recurse into nested submodules, and show their status as well. @@ -266,6 +265,11 @@ OPTIONS Initialize all submodules for which "git submodule init" has not been called so far before updating. +--name:: + This option is only valid for the add command. It sets the submodule's + name to the given string instead of defaulting to its path. The name + must be valid as a directory name and may not end with a '/'. + --reference <repository>:: This option is only valid for add and update commands. These commands sometimes need to clone a remote repository. In this case, diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt index cfe8d2b5d..69decb13b 100644 --- a/Documentation/git-svn.txt +++ b/Documentation/git-svn.txt @@ -146,6 +146,13 @@ Skip "branches" and "tags" of first level directories;; ------------------------------------------------------------------------ -- +--log-window-size=<n>;; + Fetch <n> log entries per request when scanning Subversion history. + The default is 100. For very large Subversion repositories, larger + values may be needed for 'clone'/'fetch' to complete in reasonable + time. But overly large values may lead to higher memory usage and + request timeouts. + 'clone':: Runs 'init' and 'fetch'. It will automatically create a directory based on the basename of the URL passed to it; @@ -621,10 +628,19 @@ ADVANCED OPTIONS Default: "svn" --follow-parent:: + This option is only relevant if we are tracking branches (using + one of the repository layout options --trunk, --tags, + --branches, --stdlayout). For each tracked branch, try to find + out where its revision was copied from, and set + a suitable parent in the first git commit for the branch. This is especially helpful when we're tracking a directory - that has been moved around within the repository, or if we - started tracking a branch and never tracked the trunk it was - descended from. This feature is enabled by default, use + that has been moved around within the repository. If this + feature is disabled, the branches created by 'git svn' will all + be linear and not share any history, meaning that there will be + no information on where branches were branched off or merged. + However, following long/convoluted histories can take a long + time, so disabling this feature may speed up the cloning + process. This feature is enabled by default, use --no-follow-parent to disable it. + [verse] @@ -732,7 +748,8 @@ for rewriteRoot and rewriteUUID which can be used together. BASIC EXAMPLES -------------- -Tracking and contributing to the trunk of a Subversion-managed project: +Tracking and contributing to the trunk of a Subversion-managed project +(ignoring tags and branches): ------------------------------------------------------------------------ # Clone a repo (like git clone): @@ -757,8 +774,10 @@ Tracking and contributing to an entire Subversion-managed project (complete with a trunk, tags and branches): ------------------------------------------------------------------------ -# Clone a repo (like git clone): - git svn clone http://svn.example.com/project -T trunk -b branches -t tags +# Clone a repo with standard SVN directory layout (like git clone): + git svn clone http://svn.example.com/project --stdlayout +# Or, if the repo uses a non-standard directory layout: + git svn clone http://svn.example.com/project -T tr -b branch -t tag # View all branches and tags you have cloned: git branch -r # Create a new branch in SVN @@ -823,6 +842,52 @@ inside git back upstream to SVN users. Therefore it is advised that users keep history as linear as possible inside git to ease compatibility with SVN (see the CAVEATS section below). +HANDLING OF SVN BRANCHES +------------------------ +If 'git svn' is configured to fetch branches (and --follow-branches +is in effect), it sometimes creates multiple git branches for one +SVN branch, where the addtional branches have names of the form +'branchname@nnn' (with nnn an SVN revision number). These additional +branches are created if 'git svn' cannot find a parent commit for the +first commit in an SVN branch, to connect the branch to the history of +the other branches. + +Normally, the first commit in an SVN branch consists +of a copy operation. 'git svn' will read this commit to get the SVN +revision the branch was created from. It will then try to find the +git commit that corresponds to this SVN revision, and use that as the +parent of the branch. However, it is possible that there is no suitable +git commit to serve as parent. This will happen, among other reasons, +if the SVN branch is a copy of a revision that was not fetched by 'git +svn' (e.g. because it is an old revision that was skipped with +'--revision'), or if in SVN a directory was copied that is not tracked +by 'git svn' (such as a branch that is not tracked at all, or a +subdirectory of a tracked branch). In these cases, 'git svn' will still +create a git branch, but instead of using an existing git commit as the +parent of the branch, it will read the SVN history of the directory the +branch was copied from and create appropriate git commits. This is +indicated by the message "Initializing parent: <branchname>". + +Additionally, it will create a special branch named +'<branchname>@<SVN-Revision>', where <SVN-Revision> is the SVN revision +number the branch was copied from. This branch will point to the newly +created parent commit of the branch. If in SVN the branch was deleted +and later recreated from a different version, there will be multiple +such branches with an '@'. + +Note that this may mean that multiple git commits are created for a +single SVN revision. + +An example: in an SVN repository with a standard +trunk/tags/branches layout, a directory trunk/sub is created in r.100. +In r.200, trunk/sub is branched by copying it to branches/. 'git svn +clone -s' will then create a branch 'sub'. It will also create new git +commits for r.100 through r.199 and use these as the history of branch +'sub'. Thus there will be two git commits for each revision from r.100 +to r.199 (one containing trunk/, one containing trunk/sub/). Finally, +it will create a branch 'sub@200' pointing to the new parent commit of +branch 'sub' (i.e. the commit for r.200 and trunk/sub/). + CAVEATS ------- @@ -864,6 +929,21 @@ already dcommitted. It is considered bad practice to --amend commits you've already pushed to a remote repository for other users, and dcommit with SVN is analogous to that. +When cloning an SVN repository, if none of the options for describing +the repository layout is used (--trunk, --tags, --branches, +--stdlayout), 'git svn clone' will create a git repository with +completely linear history, where branches and tags appear as separate +directories in the working copy. While this is the easiest way to get a +copy of a complete repository, for projects with many branches it will +lead to a working copy many times larger than just the trunk. Thus for +projects using the standard directory structure (trunk/branches/tags), +it is recommended to clone with option '--stdlayout'. If the project +uses a non-standard structure, and/or if branches and tags are not +required, it is easiest to only clone one directory (typically trunk), +without giving any repository layout options. If the full history with +branches and tags is required, the options '--trunk' / '--branches' / +'--tags' must be used. + When using multiple --branches or --tags, 'git svn' does not automatically handle name collisions (for example, if two branches from different paths have the same name, or if a branch and a tag have the same name). In these cases, @@ -887,6 +967,12 @@ the possible corner cases (git doesn't do it, either). Committing renamed and copied files is fully supported if they're similar enough for git to detect them. +In SVN, it is possible (though discouraged) to commit changes to a tag +(because a tag is just a directory copy, thus technically the same as a +branch). When cloning an SVN repository, 'git svn' cannot know if such a +commit to a tag will happen in the future. Thus it acts conservatively +and imports all SVN tags as branches, prefixing the tag name with 'tags/'. + CONFIGURATION ------------- diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt index 981d3a8fc..ef68ad2b7 100644 --- a/Documentation/git-symbolic-ref.txt +++ b/Documentation/git-symbolic-ref.txt @@ -3,13 +3,14 @@ git-symbolic-ref(1) NAME ---- -git-symbolic-ref - Read and modify symbolic refs +git-symbolic-ref - Read, modify and delete symbolic refs SYNOPSIS -------- [verse] 'git symbolic-ref' [-m <reason>] <name> <ref> 'git symbolic-ref' [-q] [--short] <name> +'git symbolic-ref' --delete [-q] <name> DESCRIPTION ----------- @@ -21,6 +22,9 @@ argument to see which branch your working tree is on. Given two arguments, creates or updates a symbolic ref <name> to point at the given branch <ref>. +Given `--delete` and an additional argument, deletes the given +symbolic ref. + A symbolic ref is a regular file that stores a string that begins with `ref: refs/`. For example, your `.git/HEAD` is a regular file whose contents is `ref: refs/heads/master`. @@ -28,6 +32,10 @@ a regular file whose contents is `ref: refs/heads/master`. OPTIONS ------- +-d:: +--delete:: + Delete the symbolic ref <name>. + -q:: --quiet:: Do not issue an error message if the <name> is not a diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 247534e90..6470cffd3 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -129,7 +129,7 @@ This option is only applicable when listing tags without annotation lines. CONFIGURATION ------------- By default, 'git tag' in sign-with-default mode (-s) will use your -committer identity (of the form "Your Name <your@email.address>") to +committer identity (of the form "Your Name <\your@email.address>") to find a key. If you want to use a different default key, you can specify it in the repository configuration as follows: diff --git a/Documentation/git.txt b/Documentation/git.txt index 65c37c454..5bb5cc830 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -22,18 +22,17 @@ unusually rich command set that provides both high-level operations and full access to internals. See linkgit:gittutorial[7] to get started, then see -link:everyday.html[Everyday Git] for a useful minimum set of commands, and -"man git-commandname" for documentation of each command. CVS users may -also want to read linkgit:gitcvs-migration[7]. See -the link:user-manual.html[Git User's Manual] for a more in-depth -introduction. +link:everyday.html[Everyday Git] for a useful minimum set of +commands. The link:user-manual.html[Git User's Manual] has a more +in-depth introduction. -The '<command>' is either a name of a Git command (see below) or an alias -as defined in the configuration file (see linkgit:git-config[1]). +After you mastered the basic concepts, you can come back to this +page to learn what commands git offers. You can learn more about +individual git commands with "git help command". linkgit:gitcli[7] +manual page gives you an overview of the command line command syntax. -Formatted and hyperlinked version of the latest git -documentation can be viewed at -`http://www.kernel.org/pub/software/scm/git/docs/`. +Formatted and hyperlinked version of the latest git documentation +can be viewed at `http://git-htmldocs.googlecode.com/git/git.html`. ifdef::stalenotes[] [NOTE] @@ -44,6 +43,28 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: +* link:v1.8.1/git.html[documentation for release 1.8.1] + +* release notes for + link:RelNotes/1.8.1.txt[1.8.1]. + +* link:v1.8.0.3/git.html[documentation for release 1.8.0.3] + +* release notes for + link:RelNotes/1.8.0.3.txt[1.8.0.3], + link:RelNotes/1.8.0.2.txt[1.8.0.2], + link:RelNotes/1.8.0.1.txt[1.8.0.1], + link:RelNotes/1.8.0.txt[1.8.0]. + +* link:v1.7.12.4/git.html[documentation for release 1.7.12.4] + +* release notes for + link:RelNotes/1.7.12.4.txt[1.7.12.4], + link:RelNotes/1.7.12.3.txt[1.7.12.3], + link:RelNotes/1.7.12.2.txt[1.7.12.2], + link:RelNotes/1.7.12.1.txt[1.7.12.1], + link:RelNotes/1.7.12.txt[1.7.12]. + * link:v1.7.11.7/git.html[documentation for release 1.7.11.7] * release notes for @@ -408,24 +429,6 @@ help ...`. linkgit:git-replace[1] for more information. -FURTHER DOCUMENTATION ---------------------- - -See the references above to get started using git. The following is -probably more detail than necessary for a first-time user. - -The link:user-manual.html#git-concepts[git concepts chapter of the -user-manual] and linkgit:gitcore-tutorial[7] both provide -introductions to the underlying git architecture. - -See linkgit:gitworkflows[7] for an overview of recommended workflows. - -See also the link:howto-index.html[howto] documents for some useful -examples. - -The internals are documented in the -link:technical/api-index.html[GIT API documentation]. - GIT COMMANDS ------------ @@ -653,6 +656,7 @@ git so take care if using Cogito etc. If the 'GIT_DIR' environment variable is set then it specifies a path to use instead of the default `.git` for the base of the repository. + The '--git-dir' command-line option also sets this value. 'GIT_WORK_TREE':: Set the path to the working tree. The value will not be @@ -768,6 +772,14 @@ for further details. and read the password from its STDOUT. See also the 'core.askpass' option in linkgit:git-config[1]. +'GIT_CONFIG_NOSYSTEM':: + Whether to skip reading settings from the system-wide + `$(prefix)/etc/gitconfig` file. This environment variable can + be used along with `$HOME` and `$XDG_CONFIG_HOME` to create a + predictable environment for a picky script, or you can set it + temporarily to avoid using a buggy `/etc/gitconfig` file while + waiting for someone with sufficient permissions to fix it. + 'GIT_FLUSH':: If this environment variable is set to "1", then commands such as 'git blame' (in incremental mode), 'git rev-list', 'git log', @@ -845,12 +857,37 @@ The index is also capable of storing multiple entries (called "stages") for a given pathname. These stages are used to hold the various unmerged version of a file when a merge is in progress. +FURTHER DOCUMENTATION +--------------------- + +See the references in the "description" section to get started +using git. The following is probably more detail than necessary +for a first-time user. + +The link:user-manual.html#git-concepts[git concepts chapter of the +user-manual] and linkgit:gitcore-tutorial[7] both provide +introductions to the underlying git architecture. + +See linkgit:gitworkflows[7] for an overview of recommended workflows. + +See also the link:howto-index.html[howto] documents for some useful +examples. + +The internals are documented in the +link:technical/api-index.html[GIT API documentation]. + +Users migrating from CVS may also want to +read linkgit:gitcvs-migration[7]. + + Authors ------- Git was started by Linus Torvalds, and is currently maintained by Junio C Hamano. Numerous contributions have come from the git mailing list -<git@vger.kernel.org>. For a more complete list of contributors, see -http://git-scm.com/about. If you have a clone of git.git itself, the +<git@vger.kernel.org>. http://www.ohloh.net/p/git/contributors/summary +gives you a more complete list of contributors. + +If you have a clone of git.git itself, the output of linkgit:git-shortlog[1] and linkgit:git-blame[1] can show you the authors for specific parts of the project. diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 80120ea14..2698f63cf 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -56,6 +56,7 @@ When more than one pattern matches the path, a later line overrides an earlier line. This overriding is done per attribute. The rules how the pattern matches paths are the same as in `.gitignore` files; see linkgit:gitignore[5]. +Unlike `.gitignore`, negative patterns are forbidden. When deciding what attributes are assigned to a path, git consults `$GIT_DIR/info/attributes` file (which has the highest @@ -66,6 +67,11 @@ is from the path in question, the lower its precedence). Finally global and system-wide files are considered (they have the lowest precedence). +When the `.gitattributes` file is missing from the work tree, the +path in the index is used as a fall-back. During checkout process, +`.gitattributes` in the index is used and then the file in the +working tree is used as a fall-back. + If you wish to affect only a single repository (i.e., to assign attributes to files that are particular to one user's workflow for that repository), then @@ -75,6 +81,8 @@ repositories (i.e., attributes of interest to all users) should go into `.gitattributes` files. Attributes that should affect all repositories for a single user should be placed in a file specified by the `core.attributesfile` configuration option (see linkgit:git-config[1]). +Its default value is $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME +is either not set or empty, $HOME/.config/git/attributes is used instead. Attributes for all users on a system should be placed in the `$(prefix)/etc/gitattributes` file. @@ -509,6 +517,8 @@ configuration file (you still need to enable this with the attribute mechanism, via `.gitattributes`). The following built in patterns are available: +- `ada` suitable for source code in the Ada language. + - `bibtex` suitable for files with BibTeX coded references. - `cpp` suitable for source code in the C and C++ languages. @@ -925,7 +935,7 @@ file at the toplevel (i.e. not in any subdirectory). The built-in macro attribute "binary" is equivalent to: ------------ -[attr]binary -diff -text +[attr]binary -diff -merge -text ------------ diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt index f6ba90c2d..3bc1500ed 100644 --- a/Documentation/gitcli.txt +++ b/Documentation/gitcli.txt @@ -93,7 +93,7 @@ ENHANCED OPTION PARSER From the git 1.5.4 series and further, many git commands (not all of them at the time of the writing though) come with an enhanced option parser. -Here is an exhaustive list of the facilities provided by this option parser. +Here is a list of the facilities provided by this option parser. Magic Options @@ -137,6 +137,16 @@ options. This means that you can for example use `git rm -rf` or `git clean -fdx`. +Abbreviating long options +~~~~~~~~~~~~~~~~~~~~~~~~~ +Commands that support the enhanced option parser accepts unique +prefix of a long option as if it is fully spelled out, but use this +with a caution. For example, `git commit --amen` behaves as if you +typed `git commit --amend`, but that is true only until a later version +of Git introduces another option that shares the same prefix, +e.g `git commit --amenity" option. + + Separating argument from the option ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can write the mandatory option parameter to an option as a separate diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt index 9d893369a..5325c5a7d 100644 --- a/Documentation/gitcore-tutorial.txt +++ b/Documentation/gitcore-tutorial.txt @@ -956,12 +956,11 @@ $ git show-branch --topo-order --more=1 master mybranch ------------------------------------------------ The first two lines indicate that it is showing the two branches -and the first line of the commit log message from their -top-of-the-tree commits, you are currently on `master` branch -(notice the asterisk `*` character), and the first column for -the later output lines is used to show commits contained in the +with the titles of their top-of-the-tree commits, you are currently on +`master` branch (notice the asterisk `*` character), and the first +column for the later output lines is used to show commits contained in the `master` branch, and the second column for the `mybranch` -branch. Three commits are shown along with their log messages. +branch. Three commits are shown along with their titles. All of them have non blank characters in the first column (`*` shows an ordinary commit on the current branch, `-` is a merge commit), which means they are now part of the `master` branch. Only the "Some diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt index 2e7328b83..1b82fe196 100644 --- a/Documentation/gitignore.txt +++ b/Documentation/gitignore.txt @@ -41,16 +41,24 @@ precedence, the last matching pattern decides the outcome): variable 'core.excludesfile'. Which file to place a pattern in depends on how the pattern is meant to -be used. Patterns which should be version-controlled and distributed to -other repositories via clone (i.e., files that all developers will want -to ignore) should go into a `.gitignore` file. Patterns which are -specific to a particular repository but which do not need to be shared -with other related repositories (e.g., auxiliary files that live inside -the repository but are specific to one user's workflow) should go into -the `$GIT_DIR/info/exclude` file. Patterns which a user wants git to -ignore in all situations (e.g., backup or temporary files generated by -the user's editor of choice) generally go into a file specified by -`core.excludesfile` in the user's `~/.gitconfig`. +be used. + + * Patterns which should be version-controlled and distributed to + other repositories via clone (i.e., files that all developers will want + to ignore) should go into a `.gitignore` file. + + * Patterns which are + specific to a particular repository but which do not need to be shared + with other related repositories (e.g., auxiliary files that live inside + the repository but are specific to one user's workflow) should go into + the `$GIT_DIR/info/exclude` file. + + * Patterns which a user wants git to + ignore in all situations (e.g., backup or temporary files generated by + the user's editor of choice) generally go into a file specified by + `core.excludesfile` in the user's `~/.gitconfig`. Its default value is + $XDG_CONFIG_HOME/git/ignore. If $XDG_CONFIG_HOME is either not set or + empty, $HOME/.config/git/ignore is used instead. The underlying git plumbing tools, such as 'git ls-files' and 'git read-tree', read @@ -66,11 +74,15 @@ PATTERN FORMAT for readability. - A line starting with # serves as a comment. + Put a backslash ("`\`") in front of the first hash for patterns + that begin with a hash. - - An optional prefix '!' which negates the pattern; any + - An optional prefix "`!`" which negates the pattern; any matching file excluded by a previous pattern will become included again. If a negated pattern matches, this will override lower precedence patterns sources. + Put a backslash ("`\`") in front of the first "`!`" for patterns + that begin with a literal "`!`", for example, "`\!important!.txt`". - If the pattern ends with a slash, it is removed for the purpose of the following description, but it would only find diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt index 4effd7890..ab3e91c05 100644 --- a/Documentation/gitmodules.txt +++ b/Documentation/gitmodules.txt @@ -18,7 +18,9 @@ working tree, is a text file with a syntax matching the requirements of linkgit:git-config[1]. The file contains one subsection per submodule, and the subsection value -is the name of the submodule. Each submodule section also contains the +is the name of the submodule. The name is set to the path where the +submodule has been added unless it was customized with the '--name' +option of 'git submodule add'. Each submodule section also contains the following required keys: submodule.<name>.path:: diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt index 5c891f116..9f628862b 100644 --- a/Documentation/gitrepository-layout.txt +++ b/Documentation/gitrepository-layout.txt @@ -93,6 +93,12 @@ refs/remotes/`name`:: records tip-of-the-tree commit objects of branches copied from a remote repository. +refs/replace/`<obj-sha1>`:: + records the SHA1 of the object that replaces `<obj-sha1>`. + This is similar to info/grafts and is internally used and + maintained by linkgit:git-replace[1]. Such refs can be exchanged + between repositories while grafts are not. + packed-refs:: records the same information as refs/heads/, refs/tags/, and friends record in a more efficient way. See diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt index dee050567..f1cb6f3be 100644 --- a/Documentation/gittutorial.txt +++ b/Documentation/gittutorial.txt @@ -139,9 +139,11 @@ them to the index, and commit, all in one step. A note on commit messages: Though not required, it's a good idea to begin the commit message with a single short (less than 50 character) line summarizing the change, followed by a blank line and then a more -thorough description. Tools that turn commits into email, for -example, use the first line on the Subject: line and the rest of the -commit in the body. +thorough description. The text up to the first blank line in a commit +message is treated as the commit title, and that title is used +throughout git. For example, linkgit:git-format-patch[1] turns a +commit into email, and it uses the title on the Subject line and the +rest of the commit in the body. Git tracks content not files ---------------------------- diff --git a/Documentation/howto/maintain-git.txt b/Documentation/howto/maintain-git.txt index 8823a3706..ea6e4a52c 100644 --- a/Documentation/howto/maintain-git.txt +++ b/Documentation/howto/maintain-git.txt @@ -5,6 +5,10 @@ Abstract: Imagine that git development is racing along as usual, when our friend neighborhood maintainer is struck down by a wayward bus. Out of the hordes of suckers (loyal developers), you have been tricked (chosen) to step up as the new maintainer. This howto will show you "how to" do it. +Content-type: text/asciidoc + +How to maintain Git +=================== The maintainer's git time is spent on three activities. diff --git a/Documentation/howto/new-command.txt b/Documentation/howto/new-command.txt new file mode 100644 index 000000000..36502f671 --- /dev/null +++ b/Documentation/howto/new-command.txt @@ -0,0 +1,104 @@ +From: Eric S. Raymond <esr@thyrsus.com> +Abstract: This is how-to documentation for people who want to add extension + commands to git. It should be read alongside api-builtin.txt. +Content-type: text/asciidoc + +How to integrate new subcommands +================================ + +This is how-to documentation for people who want to add extension +commands to git. It should be read alongside api-builtin.txt. + +Runtime environment +------------------- + +git subcommands are standalone executables that live in the git exec +path, normally /usr/lib/git-core. The git executable itself is a +thin wrapper that knows where the subcommands live, and runs them by +passing command-line arguments to them. + +(If "git foo" is not found in the git exec path, the wrapper +will look in the rest of your $PATH for it. Thus, it's possible +to write local git extensions that don't live in system space.) + +Implementation languages +------------------------ + +Most subcommands are written in C or shell. A few are written in +Perl. + +While we strongly encourage coding in portable C for portability, +these specific scripting languages are also acceptable. We won't +accept more without a very strong technical case, as we don't want +to broaden the git suite's required dependencies. Import utilities, +surgical tools, remote helpers and other code at the edges of the +git suite are more lenient and we allow Python (and even Tcl/tk), +but they should not be used for core functions. + +This may change in the future. Especially Python is not allowed in +core because we need better Python integration in the git Windows +installer before we can be confident people in that environment +won't experience an unacceptably large loss of capability. + +C commands are normally written as single modules, named after the +command, that link a collection of functions called libgit. Thus, +your command 'git-foo' would normally be implemented as a single +"git-foo.c" (or "builtin/foo.c" if it is to be linked to the main +binary); this organization makes it easy for people reading the code +to find things. + +See the CodingGuidelines document for other guidance on what we consider +good practice in C and shell, and api-builtin.txt for the support +functions available to built-in commands written in C. + +What every extension command needs +---------------------------------- + +You must have a man page, written in asciidoc (this is what git help +followed by your subcommand name will display). Be aware that there is +a local asciidoc configuration and macros which you should use. It's +often helpful to start by cloning an existing page and replacing the +text content. + +You must have a test, written to report in TAP (Test Anything Protocol). +Tests are executables (usually shell scripts) that live in the 't' +subdirectory of the tree. Each test name begins with 't' and a sequence +number that controls where in the test sequence it will be executed; +conventionally the rest of the name stem is that of the command +being tested. + +Read the file t/README to learn more about the conventions to be used +in writing tests, and the test support library. + +Integrating a command +--------------------- + +Here are the things you need to do when you want to merge a new +subcommand into the git tree. + +1. Don't forget to sign off your patch! + +2. Append your command name to one of the variables BUILTIN_OBJS, +EXTRA_PROGRAMS, SCRIPT_SH, SCRIPT_PERL or SCRIPT_PYTHON. + +3. Drop its test in the t directory. + +4. If your command is implemented in an interpreted language with a +p-code intermediate form, make sure .gitignore in the main directory +includes a pattern entry that ignores such files. Python .pyc and +.pyo files will already be covered. + +5. If your command has any dependency on a particular version of +your language, document it in the INSTALL file. + +6. There is a file command-list.txt in the distribution main directory +that categorizes commands by type, so they can be listed in appropriate +subsections in the documentation's summary command list. Add an entry +for yours. To understand the categories, look at git-cmmands.txt +in the main directory. + +7. Give the maintainer one paragraph to include in the RelNotes file +to describe the new feature; a good place to do so is in the cover +letter [PATCH 0/n]. + +That's all there is to it. diff --git a/Documentation/howto/rebase-from-internal-branch.txt b/Documentation/howto/rebase-from-internal-branch.txt index 74a1c0c4b..4627ee47f 100644 --- a/Documentation/howto/rebase-from-internal-branch.txt +++ b/Documentation/howto/rebase-from-internal-branch.txt @@ -8,7 +8,12 @@ Abstract: In this article, JC talks about how he rebases the the "master" branch, and how "rebase" works. Also discussed is how this applies to individual developers who sends patches upstream. +Content-type: text/asciidoc +How to rebase from an internal branch +===================================== + +-------------------------------------- Petr Baudis <pasky@suse.cz> writes: > Dear diary, on Sun, Aug 14, 2005 at 09:57:13AM CEST, I got a letter @@ -19,6 +24,7 @@ Petr Baudis <pasky@suse.cz> writes: >> > branch to the real branches. >> > Actually, wouldn't this be also precisely for what StGIT is intended to? +-------------------------------------- Exactly my feeling. I was sort of waiting for Catalin to speak up. With its basing philosophical ancestry on quilt, this is @@ -156,8 +162,3 @@ you continue on starting from the new "master" head, which is the #1' commit. -jc - -- -To unsubscribe from this list: send the line "unsubscribe git" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/Documentation/howto/rebuild-from-update-hook.txt b/Documentation/howto/rebuild-from-update-hook.txt index 48c67568d..00c1b45b7 100644 --- a/Documentation/howto/rebuild-from-update-hook.txt +++ b/Documentation/howto/rebuild-from-update-hook.txt @@ -5,6 +5,10 @@ Date: Fri, 26 Aug 2005 18:19:10 -0700 Abstract: In this how-to article, JC talks about how he uses the post-update hook to automate git documentation page shown at http://www.kernel.org/pub/software/scm/git/docs/. +Content-type: text/asciidoc + +How to rebuild from update hook +=============================== The pages under http://www.kernel.org/pub/software/scm/git/docs/ are built from Documentation/ directory of the git.git project diff --git a/Documentation/howto/recover-corrupted-blob-object.txt b/Documentation/howto/recover-corrupted-blob-object.txt index 323b513ed..748473532 100644 --- a/Documentation/howto/recover-corrupted-blob-object.txt +++ b/Documentation/howto/recover-corrupted-blob-object.txt @@ -3,11 +3,17 @@ From: Linus Torvalds <torvalds@linux-foundation.org> Subject: corrupt object on git-gc Abstract: Some tricks to reconstruct blob objects in order to fix a corrupted repository. +Content-type: text/asciidoc +How to recover a corrupted blob object +====================================== + +----------------------------------------------------------- On Fri, 9 Nov 2007, Yossi Leybovich wrote: > > Did not help still the repository look for this object? > Any one know how can I track this object and understand which file is it +----------------------------------------------------------- So exactly *because* the SHA1 hash is cryptographically secure, the hash itself doesn't actually tell you anything, in order to fix a corrupt @@ -31,19 +37,23 @@ original object, so right now the corrupt object is useless, but it's very interesting for the future, in the hope that you can re-create a non-corrupt version. +----------------------------------------------------------- So: > ib]$ mv .git/objects/4b/9458b3786228369c63936db65827de3cc06200 ../ +----------------------------------------------------------- This is the right thing to do, although it's usually best to save it under it's full SHA1 name (you just dropped the "4b" from the result ;). Let's see what that tells us: +----------------------------------------------------------- > ib]$ git-fsck --full > broken link from tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8 > to blob 4b9458b3786228369c63936db65827de3cc06200 > missing blob 4b9458b3786228369c63936db65827de3cc06200 +----------------------------------------------------------- Ok, I removed the "dangling commit" messages, because they are just messages about the fact that you probably have rebased etc, so they're not diff --git a/Documentation/howto/revert-a-faulty-merge.txt b/Documentation/howto/revert-a-faulty-merge.txt index 6fd711996..8a685483f 100644 --- a/Documentation/howto/revert-a-faulty-merge.txt +++ b/Documentation/howto/revert-a-faulty-merge.txt @@ -7,6 +7,10 @@ Abstract: Sometimes a branch that was already merged to the mainline after the offending branch is fixed. Message-ID: <7vocz8a6zk.fsf@gitster.siamese.dyndns.org> References: <alpine.LFD.2.00.0812181949450.14014@localhost.localdomain> +Content-type: text/asciidoc + +How to revert a faulty merge +============================ Alan <alan@clueserver.org> said: diff --git a/Documentation/howto/revert-branch-rebase.txt b/Documentation/howto/revert-branch-rebase.txt index 093c65604..a59ced8d0 100644 --- a/Documentation/howto/revert-branch-rebase.txt +++ b/Documentation/howto/revert-branch-rebase.txt @@ -8,8 +8,8 @@ Date: Mon, 29 Aug 2005 21:39:02 -0700 Content-type: text/asciidoc Message-ID: <7voe7g3uop.fsf@assigned-by-dhcp.cox.net> -Reverting an existing commit -============================ +How to revert an existing commit +================================ One of the changes I pulled into the 'master' branch turns out to break building GIT with GCC 2.95. While they were well intentioned diff --git a/Documentation/howto/separating-topic-branches.txt b/Documentation/howto/separating-topic-branches.txt index 6d3eb8ed0..bd1027433 100644 --- a/Documentation/howto/separating-topic-branches.txt +++ b/Documentation/howto/separating-topic-branches.txt @@ -1,6 +1,10 @@ From: Junio C Hamano <gitster@pobox.com> Subject: Separating topic branches Abstract: In this article, JC describes how to separate topic branches. +Content-type: text/asciidoc + +How to separate topic branches +============================== This text was originally a footnote to a discussion about the behaviour of the git diff commands. diff --git a/Documentation/howto/setup-git-server-over-http.txt b/Documentation/howto/setup-git-server-over-http.txt index 622ee5c8d..a695f01f0 100644 --- a/Documentation/howto/setup-git-server-over-http.txt +++ b/Documentation/howto/setup-git-server-over-http.txt @@ -1,6 +1,10 @@ From: Rutger Nijlunsing <rutger@nospam.com> Subject: Setting up a git repository which can be pushed into and pulled from over HTTP(S). Date: Thu, 10 Aug 2006 22:00:26 +0200 +Content-type: text/asciidoc + +How to setup git server over http +================================= Since Apache is one of those packages people like to compile themselves while others prefer the bureaucrat's dream Debian, it is diff --git a/Documentation/howto/update-hook-example.txt b/Documentation/howto/update-hook-example.txt index b7f8d416d..a5193b1e5 100644 --- a/Documentation/howto/update-hook-example.txt +++ b/Documentation/howto/update-hook-example.txt @@ -5,6 +5,10 @@ Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net> Abstract: An example hooks/update script is presented to implement repository maintenance policies, such as who can push into which branch and who can make a tag. +Content-type: text/asciidoc + +How to use the update hook +========================== When your developer runs git-push into the repository, git-receive-pack is run (either locally or over ssh) as that @@ -32,8 +36,7 @@ like this as your hooks/update script. [jc: editorial note. This is a much improved version by Carl since I posted the original outline] --- >8 -- beginning of script -- >8 -- - +---------------------------------------------------- #!/bin/bash umask 002 @@ -111,12 +114,12 @@ then info "Found matching head pattern: '$head_pattern'" for user_pattern in $user_patterns; do - info "Checking user: '$username' against pattern: '$user_pattern'" - matchlen=$(expr "$username" : "$user_pattern") - if test "$matchlen" = "${#username}" - then - grant "Allowing user: '$username' with pattern: '$user_pattern'" - fi + info "Checking user: '$username' against pattern: '$user_pattern'" + matchlen=$(expr "$username" : "$user_pattern") + if test "$matchlen" = "${#username}" + then + grant "Allowing user: '$username' with pattern: '$user_pattern'" + fi done deny "The user is not in the access list for this branch" done @@ -149,13 +152,13 @@ then info "Found matching head pattern: '$head_pattern'" for group_pattern in $group_patterns; do - for groupname in $groups; do - info "Checking group: '$groupname' against pattern: '$group_pattern'" - matchlen=$(expr "$groupname" : "$group_pattern") - if test "$matchlen" = "${#groupname}" - then - grant "Allowing group: '$groupname' with pattern: '$group_pattern'" - fi + for groupname in $groups; do + info "Checking group: '$groupname' against pattern: '$group_pattern'" + matchlen=$(expr "$groupname" : "$group_pattern") + if test "$matchlen" = "${#groupname}" + then + grant "Allowing group: '$groupname' with pattern: '$group_pattern'" + fi done done deny "None of the user's groups are in the access list for this branch" @@ -169,24 +172,21 @@ then fi deny >/dev/null "There are no more rules to check. Denying access" - --- >8 -- end of script -- >8 -- +---------------------------------------------------- This uses two files, $GIT_DIR/info/allowed-users and allowed-groups, to describe which heads can be pushed into by whom. The format of each file would look like this: - refs/heads/master junio - +refs/heads/pu junio - refs/heads/cogito$ pasky - refs/heads/bw/.* linus - refs/heads/tmp/.* .* - refs/tags/v[0-9].* junio + refs/heads/master junio + +refs/heads/pu junio + refs/heads/cogito$ pasky + refs/heads/bw/.* linus + refs/heads/tmp/.* .* + refs/tags/v[0-9].* junio With this, Linus can push or create "bw/penguin" or "bw/zebra" or "bw/panda" branches, Pasky can do only "cogito", and JC can do master and pu branches and make versioned tags. And anybody can do tmp/blah branches. The '+' sign at the pu record means that JC can make non-fast-forward pushes on it. - ------------- diff --git a/Documentation/howto/use-git-daemon.txt b/Documentation/howto/use-git-daemon.txt index 4e2f75cb6..23cdf3543 100644 --- a/Documentation/howto/use-git-daemon.txt +++ b/Documentation/howto/use-git-daemon.txt @@ -1,4 +1,7 @@ +Content-type: text/asciidoc + How to use git-daemon +===================== Git can be run in inetd mode and in stand alone mode. But all you want is let a coworker pull from you, and therefore need to set up a git server diff --git a/Documentation/howto/using-signed-tag-in-pull-request.txt b/Documentation/howto/using-signed-tag-in-pull-request.txt index 98c0033a5..00f693bde 100644 --- a/Documentation/howto/using-signed-tag-in-pull-request.txt +++ b/Documentation/howto/using-signed-tag-in-pull-request.txt @@ -7,8 +7,8 @@ Abstract: Beginning v1.7.9, a contributor can push a signed tag to her later validate it. Content-type: text/asciidoc -Using signed tag in pull requests -================================= +How to use a signed tag in pull requests +======================================== A typical distributed workflow using Git is for a contributor to fork a project, build on it, publish the result to her public repository, and ask diff --git a/Documentation/mailmap.txt b/Documentation/mailmap.txt index 288f04e70..dd89fca3f 100644 --- a/Documentation/mailmap.txt +++ b/Documentation/mailmap.txt @@ -46,7 +46,7 @@ Jane Doe <jane@desktop.(none)> Joe R. Developer <joe@example.com> ------------ -Note how there is no need for an entry for <jane@laptop.(none)>, because the +Note how there is no need for an entry for `<jane@laptop.(none)>`, because the real name of that author is already correct. Example 2: Your repository contains commits from the following diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 861bd6f55..9bb4956cc 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -9,11 +9,11 @@ merge.conflictstyle:: merge.defaultToUpstream:: If merge is called without any commit argument, merge the upstream branches configured for the current branch by using their last - observed values stored in their remote tracking branches. + observed values stored in their remote-tracking branches. The values of the `branch.<current branch>.merge` that name the branches at the remote named by `branch.<current branch>.remote` are consulted, and then they are mapped via `remote.<remote>.fetch` - to their corresponding remote tracking branches, and the tips of + to their corresponding remote-tracking branches, and the tips of these tracking branches are merged. merge.ff:: diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt index 595a3cf1a..66db80296 100644 --- a/Documentation/merge-strategies.txt +++ b/Documentation/merge-strategies.txt @@ -32,13 +32,14 @@ ours;; This option forces conflicting hunks to be auto-resolved cleanly by favoring 'our' version. Changes from the other tree that do not conflict with our side are reflected to the merge result. + For a binary file, the entire contents are taken from our side. + This should not be confused with the 'ours' merge strategy, which does not even look at what the other tree contains at all. It discards everything the other tree did, declaring 'our' history contains all that happened in it. theirs;; - This is opposite of 'ours'. + This is the opposite of 'ours'. patience;; With this option, 'merge-recursive' spends a little extra time diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index e3d8a83b2..d9eddedc7 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -130,6 +130,9 @@ The placeholders are: - '%b': body - '%B': raw body (unwrapped subject and body) - '%N': commit notes +- '%GG': raw verification message from GPG for a signed commit +- '%G?': show either "G" for Good or "B" for Bad for a signed commit +- '%GS': show the name of the signer for a signed commit - '%gD': reflog selector, e.g., `refs/stash@{1}` - '%gd': shortened reflog selector, e.g., `stash@{1}` - '%gn': reflog identity name diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt index 2a3dc8664..5e499421a 100644 --- a/Documentation/pretty-options.txt +++ b/Documentation/pretty-options.txt @@ -66,3 +66,7 @@ being displayed. Examples: "--notes=foo" will show only notes from --[no-]standard-notes:: These options are deprecated. Use the above --notes/--no-notes options instead. + +--show-signature:: + Check the validity of a signed commit object by passing the signature + to `gpg --verify` and show the output. diff --git a/Documentation/pt_BR/gittutorial.txt b/Documentation/pt_BR/gittutorial.txt deleted file mode 100644 index beba06525..000000000 --- a/Documentation/pt_BR/gittutorial.txt +++ /dev/null @@ -1,675 +0,0 @@ -gittutorial(7) -============== - -NOME ----- -gittutorial - Um tutorial de introdução ao git (para versão 1.5.1 ou mais nova) - -SINOPSE --------- -git * - -DESCRIÇÃO ------------ - -Este tutorial explica como importar um novo projeto para o git, -adicionar mudanças a ele, e compartilhar mudanças com outros -desenvolvedores. - -Se, ao invés disso, você está interessado primariamente em usar git para -obter um projeto, por exemplo, para testar a última versão, você pode -preferir começar com os primeiros dois capÃtulos de -link:user-manual.html[O Manual do Usuário Git]. - -Primeiro, note que você pode obter documentação para um comando como -`git log --graph` com: - ------------------------------------------------- -$ man git-log ------------------------------------------------- - -ou: - ------------------------------------------------- -$ git help log ------------------------------------------------- - -Com a última forma, você pode usar o visualizador de manual de sua -escolha; veja linkgit:git-help[1] para maior informação. - -É uma boa idéia informar ao git seu nome e endereço público de email -antes de fazer qualquer operação. A maneira mais fácil de fazê-lo é: - ------------------------------------------------- -$ git config --global user.name "Seu Nome Vem Aqui" -$ git config --global user.email voce@seudominio.exemplo.com ------------------------------------------------- - - -Importando um novo projeto ------------------------ - -Assuma que você tem um tarball project.tar.gz com seu trabalho inicial. -Você pode colocá-lo sob controle de revisão git da seguinte forma: - ------------------------------------------------- -$ tar xzf project.tar.gz -$ cd project -$ git init ------------------------------------------------- - -Git irá responder - ------------------------------------------------- -Initialized empty Git repository in .git/ ------------------------------------------------- - -Agora que você iniciou seu diretório de trabalho, você deve ter notado que um -novo diretório foi criado com o nome de ".git". - -A seguir, diga ao git para gravar um instantâneo do conteúdo de todos os -arquivos sob o diretório atual (note o '.'), com 'git-add': - ------------------------------------------------- -$ git add . ------------------------------------------------- - -Este instantâneo está agora armazenado em uma área temporária que o git -chama de "index" ou Ãndice. Você pode armazenar permanentemente o -conteúdo do Ãndice no repositório com 'git-commit': - ------------------------------------------------- -$ git commit ------------------------------------------------- - -Isto vai te pedir por uma mensagem de commit. Você agora gravou sua -primeira versão de seu projeto no git. - -Fazendo mudanças --------------- - -Modifique alguns arquivos, e, então, adicione seu conteúdo atualizado ao -Ãndice: - ------------------------------------------------- -$ git add file1 file2 file3 ------------------------------------------------- - -Você está agora pronto para fazer o commit. Você pode ver o que está -para ser gravado usando 'git-diff' com a opção --cached: - ------------------------------------------------- -$ git diff --cached ------------------------------------------------- - -(Sem --cached, o comando 'git-diff' irá te mostrar quaisquer mudanças -que você tenha feito mas ainda não adicionou ao Ãndice.) Você também -pode obter um breve sumário da situação com 'git-status': - ------------------------------------------------- -$ git status -# On branch master -# Changes to be committed: -# (use "git reset HEAD <file>..." to unstage) -# -# modified: file1 -# modified: file2 -# modified: file3 -# ------------------------------------------------- - -Se você precisar fazer qualquer outro ajuste, faça-o agora, e, então, -adicione qualquer conteúdo modificado ao Ãndice. Finalmente, grave suas -mudanças com: - ------------------------------------------------- -$ git commit ------------------------------------------------- - -Ao executar esse comando, ele irá te pedir uma mensagem descrevendo a mudança, -e, então, irá gravar a nova versão do projeto. - -Alternativamente, ao invés de executar 'git-add' antes, você pode usar - ------------------------------------------------- -$ git commit -a ------------------------------------------------- - -o que irá automaticamente notar quaisquer arquivos modificados (mas não -novos), adicioná-los ao Ãndices, e gravar, tudo em um único passo. - -Uma nota em mensagens de commit: Apesar de não ser exigido, é uma boa -idéia começar a mensagem com uma simples e curta (menos de 50 -caracteres) linha sumarizando a mudança, seguida de uma linha em branco -e, então, uma descrição mais detalhada. Ferramentas que transformam -commits em email, por exemplo, usam a primeira linha no campo de -cabeçalho "Subject:" e o resto no corpo. - -Git rastreia conteúdo, não arquivos ----------------------------- - -Muitos sistemas de controle de revisão provêem um comando `add` que diz -ao sistema para começar a rastrear mudanças em um novo arquivo. O -comando `add` do git faz algo mais simples e mais poderoso: 'git-add' é -usado tanto para arquivos novos e arquivos recentemente modificados, e -em ambos os casos, ele tira o instantâneo dos arquivos dados e armazena -o conteúdo no Ãndice, pronto para inclusão do próximo commit. - -Visualizando a história do projeto ------------------------ - -Em qualquer ponto você pode visualizar a história das suas mudanças -usando - ------------------------------------------------- -$ git log ------------------------------------------------- - -Se você também quiser ver a diferença completa a cada passo, use - ------------------------------------------------- -$ git log -p ------------------------------------------------- - -Geralmente, uma visão geral da mudança é útil para ter a sensação de -cada passo - ------------------------------------------------- -$ git log --stat --summary ------------------------------------------------- - -Gerenciando "branches"/ramos ------------------ - -Um simples repositório git pode manter múltiplos ramos de -desenvolvimento. Para criar um novo ramo chamado "experimental", use - ------------------------------------------------- -$ git branch experimental ------------------------------------------------- - -Se você executar agora - ------------------------------------------------- -$ git branch ------------------------------------------------- - -você vai obter uma lista de todos os ramos existentes: - ------------------------------------------------- - experimental -* master ------------------------------------------------- - -O ramo "experimental" é o que você acaba de criar, e o ramo "master" é o -ramo padrão que foi criado pra você automaticamente. O asterisco marca -o ramo em que você está atualmente; digite - ------------------------------------------------- -$ git checkout experimental ------------------------------------------------- - -para mudar para o ramo experimental. Agora edite um arquivo, grave a -mudança, e mude de volta para o ramo master: - ------------------------------------------------- -(edita arquivo) -$ git commit -a -$ git checkout master ------------------------------------------------- - -Verifique que a mudança que você fez não está mais visÃvel, já que ela -foi feita no ramo experimental e você está de volta ao ramo master. - -Você pode fazer uma mudança diferente no ramo master: - ------------------------------------------------- -(edit file) -$ git commit -a ------------------------------------------------- - -neste ponto, os dois ramos divergiram, com diferentes mudanças feitas em -cada um. Para unificar as mudanças feitas no experimental para o -master, execute - ------------------------------------------------- -$ git merge experimental ------------------------------------------------- - -Se as mudanças não conflitarem, estará pronto. Se existirem conflitos, -marcadores serão deixados nos arquivos problemáticos exibindo o -conflito; - ------------------------------------------------- -$ git diff ------------------------------------------------- - -vai exibir isto. Após você editar os arquivos para resolver os -conflitos, - ------------------------------------------------- -$ git commit -a ------------------------------------------------- - -irá gravar o resultado da unificação. Finalmente, - ------------------------------------------------- -$ gitk ------------------------------------------------- - -vai mostrar uma bela representação gráfica da história resultante. - -Neste ponto você pode remover seu ramo experimental com - ------------------------------------------------- -$ git branch -d experimental ------------------------------------------------- - -Este comando garante que as mudanças no ramo experimental já estão no -ramo atual. - -Se você desenvolve em um ramo ideia-louca, e se arrepende, você pode -sempre remover o ramo com - -------------------------------------- -$ git branch -D ideia-louca -------------------------------------- - -Ramos são baratos e fáceis, então isto é uma boa maneira de experimentar -alguma coisa. - -Usando git para colaboração ---------------------------- - -Suponha que Alice começou um novo projeto com um repositório git em -/home/alice/project, e que Bob, que tem um diretório home na mesma -máquina, quer contribuir. - -Bob começa com: - ------------------------------------------------- -bob$ git clone /home/alice/project myrepo ------------------------------------------------- - -Isso cria um novo diretório "myrepo" contendo um clone do repositório de -Alice. O clone está no mesmo pé que o projeto original, possuindo sua -própria cópia da história do projeto original. - -Bob então faz algumas mudanças e as grava: - ------------------------------------------------- -(editar arquivos) -bob$ git commit -a -(repetir conforme necessário) ------------------------------------------------- - -Quanto está pronto, ele diz a Alice para puxar as mudanças do -repositório em /home/bob/myrepo. Ela o faz com: - ------------------------------------------------- -alice$ cd /home/alice/project -alice$ git pull /home/bob/myrepo master ------------------------------------------------- - -Isto unifica as mudanças do ramo "master" do Bob ao ramo atual de Alice. -Se Alice fez suas próprias mudanças no intervalo, ela, então, pode -precisar corrigir manualmente quaisquer conflitos. (Note que o argumento -"master" no comando acima é, de fato, desnecessário, já que é o padrão.) - -O comando "pull" executa, então, duas operações: ele obtém mudanças de -um ramo remoto, e, então, as unifica no ramo atual. - -Note que, em geral, Alice gostaria que suas mudanças locais fossem -gravadas antes de iniciar este "pull". Se o trabalho de Bob conflita -com o que Alice fez desde que suas histórias se ramificaram, Alice irá -usar seu diretório de trabalho e o Ãndice para resolver conflitos, e -mudanças locais existentes irão interferir com o processo de resolução -de conflitos (git ainda irá realizar a obtenção mas irá se recusar a -unificar --- Alice terá que se livrar de suas mudanças locais de alguma -forma e puxar de novo quando isso acontecer). - -Alice pode espiar o que Bob fez sem unificar primeiro, usando o comando -"fetch"; isto permite Alice inspecionar o que Bob fez, usando um sÃmbolo -especial "FETCH_HEAD", com o fim de determinar se ele tem alguma coisa -que vale puxar, assim: - ------------------------------------------------- -alice$ git fetch /home/bob/myrepo master -alice$ git log -p HEAD..FETCH_HEAD ------------------------------------------------- - -Esta operação é segura mesmo se Alice tem mudanças locais não gravadas. -A notação de intervalo "HEAD..FETCH_HEAD" significa mostrar tudo que é -alcançável de FETCH_HEAD mas exclua tudo o que é alcançável de HEAD. -Alice já sabe tudo que leva a seu estado atual (HEAD), e revisa o que Bob -tem em seu estado (FETCH_HEAD) que ela ainda não viu com esse comando. - -Se Alice quer visualizar o que Bob fez desde que suas histórias se -ramificaram, ela pode disparar o seguinte comando: - ------------------------------------------------- -$ gitk HEAD..FETCH_HEAD ------------------------------------------------- - -Isto usa a mesma notação de intervalo que vimos antes com 'git log'. - -Alice pode querer ver o que ambos fizeram desde que ramificaram. Ela -pode usar a forma com três pontos ao invés da forma com dois pontos: - ------------------------------------------------- -$ gitk HEAD...FETCH_HEAD ------------------------------------------------- - -Isto significa "mostre tudo que é alcançável de qualquer um deles, mas -exclua tudo que é alcançável a partir de ambos". - -Por favor, note que essas notações de intervalo podem ser usadas tanto -com gitk quanto com "git log". - -Após inspecionar o que Bob fez, se não há nada urgente, Alice pode -decidir continuar trabalhando sem puxar de Bob. Se a história de Bob -tem alguma coisa que Alice precisa imediatamente, Alice pode optar por -separar seu trabalho em progresso primeiro, fazer um "pull", e, então, -finalmente, retomar seu trabalho em progresso em cima da história -resultante. - -Quando você está trabalhando em um pequeno grupo unido, não é incomum -interagir com o mesmo repositório várias e várias vezes. Definindo um -repositório remoto antes de tudo, você pode fazê-lo mais facilmente: - ------------------------------------------------- -alice$ git remote add bob /home/bob/myrepo ------------------------------------------------- - -Com isso, Alice pode executar a primeira parte da operação "pull" usando -o comando 'git-fetch' sem unificar suas mudanças com seu próprio ramo, -usando: - -------------------------------------- -alice$ git fetch bob -------------------------------------- - -Diferente da forma longa, quando Alice obteve de Bob usando um -repositório remoto antes definido com 'git-remote', o que foi obtido é -armazenado em um ramo remoto, neste caso `bob/master`. Então, após isso: - -------------------------------------- -alice$ git log -p master..bob/master -------------------------------------- - -mostra uma lista de todas as mudanças que Bob fez desde que ramificou do -ramo master de Alice. - -Após examinar essas mudanças, Alice pode unificá-las em seu ramo master: - -------------------------------------- -alice$ git merge bob/master -------------------------------------- - -Esse `merge` pode também ser feito puxando de seu próprio ramo remoto, -assim: - -------------------------------------- -alice$ git pull . remotes/bob/master -------------------------------------- - -Note que 'git pull' sempre unifica ao ramo atual, independente do que -mais foi passado na linha de comando. - -Depois, Bob pode atualizar seu repositório com as últimas mudanças de -Alice, usando - -------------------------------------- -bob$ git pull -------------------------------------- - -Note que ele não precisa dar o caminho do repositório de Alice; quando -Bob clonou seu repositório, o git armazenou a localização de seu -repositório na configuração do mesmo, e essa localização é usada -para puxar: - -------------------------------------- -bob$ git config --get remote.origin.url -/home/alice/project -------------------------------------- - -(A configuração completa criada por 'git-clone' é visÃvel usando `git -config -l`, e a página de manual linkgit:git-config[1] explica o -significado de cada opção.) - -Git também mantém uma cópia limpa do ramo master de Alice sob o nome -"origin/master": - -------------------------------------- -bob$ git branch -r - origin/master -------------------------------------- - -Se Bob decidir depois em trabalhar em um host diferente, ele ainda pode -executar clones e puxar usando o protocolo ssh: - -------------------------------------- -bob$ git clone alice.org:/home/alice/project myrepo -------------------------------------- - -Alternativamente, o git tem um protocolo nativo, ou pode usar rsync ou -http; veja linkgit:git-pull[1] para detalhes. - -Git pode também ser usado em um modo parecido com CVS, com um -repositório central para o qual vários usuários empurram modificações; -veja linkgit:git-push[1] e linkgit:gitcvs-migration[7]. - -Explorando história ------------------ - -A história no git é representada como uma série de commits -interrelacionados. Nós já vimos que o comando 'git-log' pode listar -esses commits. Note que a primeira linha de cada entrada no log também -dá o nome para o commit: - -------------------------------------- -$ git log -commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7 -Author: Junio C Hamano <junkio@cox.net> -Date: Tue May 16 17:18:22 2006 -0700 - - merge-base: Clarify the comments on post processing. -------------------------------------- - -Nós podemos dar este nome ao 'git-show' para ver os detalhes sobre este -commit. - -------------------------------------- -$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7 -------------------------------------- - -Mas há outras formas de se referir aos commits. Você pode usar qualquer -parte inicial do nome que seja longo o bastante para identificar -unicamente o commit: - -------------------------------------- -$ git show c82a22c39c # os primeiros caracteres do nome são o bastante - # usualmente -$ git show HEAD # a ponta do ramo atual -$ git show experimental # a ponta do ramo "experimental" -------------------------------------- - -Todo commit normalmente tem um commit "pai" que aponta para o estado -anterior do projeto: - -------------------------------------- -$ git show HEAD^ # para ver o pai de HEAD -$ git show HEAD^^ # para ver o avô de HEAD -$ git show HEAD~4 # para ver o trisavô de HEAD -------------------------------------- - -Note que commits de unificação podem ter mais de um pai: - -------------------------------------- -$ git show HEAD^1 # mostra o primeiro pai de HEAD (o mesmo que HEAD^) -$ git show HEAD^2 # mostra o segundo pai de HEAD -------------------------------------- - -Você também pode dar aos commits nomes à sua escolha; após executar - -------------------------------------- -$ git tag v2.5 1b2e1d63ff -------------------------------------- - -você pode se referir a 1b2e1d63ff pelo nome "v2.5". Se você pretende -compartilhar esse nome com outras pessoas (por exemplo, para identificar -uma versão de lançamento), você deveria criar um objeto "tag", e talvez -assiná-lo; veja linkgit:git-tag[1] para detalhes. - -Qualquer comando git que precise conhecer um commit pode receber -quaisquer desses nomes. Por exemplo: - -------------------------------------- -$ git diff v2.5 HEAD # compara o HEAD atual com v2.5 -$ git branch stable v2.5 # inicia um novo ramo chamado "stable" baseado - # em v2.5 -$ git reset --hard HEAD^ # reseta seu ramo atual e seu diretório de - # trabalho a seu estado em HEAD^ -------------------------------------- - -Seja cuidadoso com o último comando: além de perder quaisquer mudanças -em seu diretório de trabalho, ele também remove todos os commits -posteriores desse ramo. Se esse ramo é o único ramo contendo esses -commits, eles serão perdidos. Também, não use 'git-reset' num ramo -publicamente visÃvel de onde outros desenvolvedores puxam, já que vai -forçar unificações desnecessárias para que outros desenvolvedores limpem -a história. Se você precisa desfazer mudanças que você empurrou, use -'git-revert' no lugar. - -O comando 'git-grep' pode buscar strings em qualquer versão de seu -projeto, então - -------------------------------------- -$ git grep "hello" v2.5 -------------------------------------- - -procura por todas as ocorrências de "hello" em v2.5. - -Se você deixar de fora o nome do commit, 'git-grep' irá procurar -quaisquer dos arquivos que ele gerencia no diretório corrente. Então - -------------------------------------- -$ git grep "hello" -------------------------------------- - -é uma forma rápida de buscar somente os arquivos que são rastreados pelo -git. - -Muitos comandos git também recebem um conjunto de commits, o que pode -ser especificado de várias formas. Aqui estão alguns exemplos com 'git-log': - -------------------------------------- -$ git log v2.5..v2.6 # commits entre v2.5 e v2.6 -$ git log v2.5.. # commits desde v2.5 -$ git log --since="2 weeks ago" # commits das últimas 2 semanas -$ git log v2.5.. Makefile # commits desde v2.5 que modificam - # Makefile -------------------------------------- - -Você também pode dar ao 'git-log' um "intervalo" de commits onde o -primeiro não é necessariamente um ancestral do segundo; por exemplo, se -as pontas dos ramos "stable" e "master" divergiram de um commit -comum algum tempo atrás, então - -------------------------------------- -$ git log stable..master -------------------------------------- - -irá listar os commits feitos no ramo "master" mas não no ramo -"stable", enquanto - -------------------------------------- -$ git log master..stable -------------------------------------- - -irá listar a lista de commits feitos no ramo "stable" mas não no ramo -"master". - -O comando 'git-log' tem uma fraqueza: ele precisa mostrar os commits em -uma lista. Quando a história tem linhas de desenvolvimento que -divergiram e então foram unificadas novamente, a ordem em que 'git-log' -apresenta essas mudanças é irrelevante. - -A maioria dos projetos com múltiplos contribuidores (como o kernel -Linux, ou o próprio git) tem unificações frequentes, e 'gitk' faz um -trabalho melhor de visualizar sua história. Por exemplo, - -------------------------------------- -$ gitk --since="2 weeks ago" drivers/ -------------------------------------- - -permite a você navegar em quaisquer commits desde as últimas duas semanas -de commits que modificaram arquivos sob o diretório "drivers". (Nota: -você pode ajustar as fontes do gitk segurando a tecla control enquanto -pressiona "-" ou "+".) - -Finalmente, a maioria dos comandos que recebem nomes de arquivo permitirão -também, opcionalmente, preceder qualquer nome de arquivo por um -commit, para especificar uma versão particular do arquivo: - -------------------------------------- -$ git diff v2.5:Makefile HEAD:Makefile.in -------------------------------------- - -Você pode usar 'git-show' para ver tal arquivo: - -------------------------------------- -$ git show v2.5:Makefile -------------------------------------- - -Próximos passos ----------- - -Este tutorial deve ser o bastante para operar controle de revisão -distribuÃdo básico para seus projetos. No entanto, para entender -plenamente a profundidade e o poder do git você precisa entender duas -idéias simples nas quais ele se baseia: - - * A base de objetos é um sistema bem elegante usado para armazenar a - história de seu projeto--arquivos, diretórios, e commits. - - * O arquivo de Ãndice é um cache do estado de uma árvore de diretório, - usado para criar commits, restaurar diretórios de trabalho, e - armazenar as várias árvores envolvidas em uma unificação. - -A parte dois deste tutorial explica a base de objetos, o arquivo de -Ãndice, e algumas outras coisinhas que você vai precisar pra usar o -máximo do git. Você pode encontrá-la em linkgit:gittutorial-2[7]. - -Se você não quiser continuar com o tutorial agora nesse momento, algumas -outras digressões que podem ser interessantes neste ponto são: - - * linkgit:git-format-patch[1], linkgit:git-am[1]: Estes convertem - séries de commits em patches para email, e vice-versa, úteis para - projetos como o kernel Linux que dependem fortemente de patches - enviados por email. - - * linkgit:git-bisect[1]: Quando há uma regressão em seu projeto, uma - forma de rastrear um bug é procurando pela história para encontrar o - commit culpado. Git bisect pode ajudar a executar uma busca binária - por esse commit. Ele é inteligente o bastante para executar uma - busca próxima da ótima mesmo no caso de uma história complexa - não-linear com muitos ramos unificados. - - * link:everyday.html[GIT diariamente com 20 e tantos comandos] - - * linkgit:gitcvs-migration[7]: Git para usuários de CVS. - -VEJA TAMBÉM --------- -linkgit:gittutorial-2[7], -linkgit:gitcvs-migration[7], -linkgit:gitcore-tutorial[7], -linkgit:gitglossary[7], -linkgit:git-help[1], -link:everyday.html[git diariamente], -link:user-manual.html[O Manual do Usuário git] - -GIT ---- -Parte da suite linkgit:git[1]. diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index def1340ac..1ec14a068 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -3,12 +3,20 @@ Commit Limiting Besides specifying a range of commits that should be listed using the special notations explained in the description, additional commit -limiting may be applied. Note that they are applied before commit -ordering and formatting options, such as '--reverse'. +limiting may be applied. + +Using more options generally further limits the output (e.g. +`--since=<date1>` limits to commits newer than `<date1>`, and using it +with `--grep=<pattern>` further limits to commits whose log message +has a line that matches `<pattern>`), unless otherwise noted. + +Note that these are applied before commit +ordering and formatting options, such as `--reverse`. -- --n 'number':: +-<number>:: +-n <number>:: --max-count=<number>:: Limit the number of commits to output. @@ -38,22 +46,44 @@ endif::git-rev-list[] --committer=<pattern>:: Limit the commits output to ones with author/committer - header lines that match the specified pattern (regular expression). + header lines that match the specified pattern (regular + expression). With more than one `--author=<pattern>`, + commits whose author matches any of the given patterns are + chosen (similarly for multiple `--committer=<pattern>`). + +--grep-reflog=<pattern>:: + + Limit the commits output to ones with reflog entries that + match the specified pattern (regular expression). With + more than one `--grep-reflog`, commits whose reflog message + matches any of the given patterns are chosen. It is an + error to use this option unless `--walk-reflogs` is in use. --grep=<pattern>:: Limit the commits output to ones with log message that - matches the specified pattern (regular expression). + matches the specified pattern (regular expression). With + more than one `--grep=<pattern>`, commits whose message + matches any of the given patterns are chosen (but see + `--all-match`). ++ +When `--show-notes` is in effect, the message from the notes as +if it is part of the log message. --all-match:: Limit the commits output to ones that match all given --grep, - --author and --committer instead of ones that match at least one. + instead of ones that match at least one. -i:: --regexp-ignore-case:: Match the regexp limiting patterns without regard to letters case. +--basic-regexp:: + + Consider the limiting patterns to be basic regular expressions; + this is the default. + -E:: --extended-regexp:: @@ -66,6 +96,11 @@ endif::git-rev-list[] Consider the limiting patterns to be fixed strings (don't interpret pattern as a regular expression). +--perl-regexp:: + + Consider the limiting patterns to be Perl-compatible regexp. + Requires libpcre to be compiled in. + --remove-empty:: Stop when a given path disappears from the tree. @@ -636,10 +671,14 @@ These options are mostly targeted for packing of git repositories. Only useful with '--objects'; print the object IDs that are not in packs. ---no-walk:: +--no-walk[=(sorted|unsorted)]:: - Only show the given revs, but do not traverse their ancestors. - This has no effect if a range is specified. + Only show the given commits, but do not traverse their ancestors. + This has no effect if a range is specified. If the argument + "unsorted" is given, the commits are show in the order they were + given on the command line. Otherwise (if "sorted" or no argument + was given), the commits are show in reverse chronological order + by commit time. --do-walk:: diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt index 69d996bc3..991fcd8f3 100644 --- a/Documentation/revisions.txt +++ b/Documentation/revisions.txt @@ -55,6 +55,8 @@ when you run `git cherry-pick`. + Note that any of the 'refs/*' cases above may come either from the '$GIT_DIR/refs' directory or from the '$GIT_DIR/packed-refs' file. +While the ref name encoding is unspecified, UTF-8 is prefered as +some output processing may assume ref names in UTF-8. '<refname>@\{<date>\}', e.g. 'master@\{yesterday\}', 'HEAD@\{5 minutes ago\}':: A ref followed by the suffix '@' with a date specification diff --git a/Documentation/technical/api-allocation-growing.txt b/Documentation/technical/api-allocation-growing.txt index 43dbe09f7..542946b1b 100644 --- a/Documentation/technical/api-allocation-growing.txt +++ b/Documentation/technical/api-allocation-growing.txt @@ -5,7 +5,9 @@ Dynamically growing an array using realloc() is error prone and boring. Define your array with: -* a pointer (`ary`) that points at the array, initialized to `NULL`; +* a pointer (`item`) that points at the array, initialized to `NULL` + (although please name the variable based on its contents, not on its + type); * an integer variable (`alloc`) that keeps track of how big the current allocation is, initialized to `0`; @@ -13,22 +15,22 @@ Define your array with: * another integer variable (`nr`) to keep track of how many elements the array currently has, initialized to `0`. -Then before adding `n`th element to the array, call `ALLOC_GROW(ary, n, +Then before adding `n`th element to the item, call `ALLOC_GROW(item, n, alloc)`. This ensures that the array can hold at least `n` elements by calling `realloc(3)` and adjusting `alloc` variable. ------------ -sometype *ary; +sometype *item; size_t nr; size_t alloc for (i = 0; i < nr; i++) - if (we like ary[i] already) + if (we like item[i] already) return; /* we did not like any existing one, so add one */ -ALLOC_GROW(ary, nr + 1, alloc); -ary[nr++] = value you like; +ALLOC_GROW(item, nr + 1, alloc); +item[nr++] = value you like; ------------ You are responsible for updating the `nr` variable. diff --git a/Documentation/technical/api-argv-array.txt b/Documentation/technical/api-argv-array.txt index 1b7d8f140..a959517b2 100644 --- a/Documentation/technical/api-argv-array.txt +++ b/Documentation/technical/api-argv-array.txt @@ -46,6 +46,18 @@ Functions Format a string and push it onto the end of the array. This is a convenience wrapper combining `strbuf_addf` and `argv_array_push`. +`argv_array_pop`:: + Remove the final element from the array. If there are no + elements in the array, do nothing. + `argv_array_clear`:: Free all memory associated with the array and return it to the initial, empty state. + +`argv_array_detach`:: + Detach the argv array from the `struct argv_array`, transfering + ownership of the allocated array and strings. + +`argv_array_free_detached`:: + Free the memory allocated by a `struct argv_array` that was later + detached and is now no longer needed. diff --git a/Documentation/technical/api-credentials.txt b/Documentation/technical/api-credentials.txt index adb6f0c89..5977b58e5 100644 --- a/Documentation/technical/api-credentials.txt +++ b/Documentation/technical/api-credentials.txt @@ -241,42 +241,9 @@ appended to its command line, which is one of: Remove a matching credential, if any, from the helper's storage. The details of the credential will be provided on the helper's stdin -stream. The credential is split into a set of named attributes. -Attributes are provided to the helper, one per line. Each attribute is -specified by a key-value pair, separated by an `=` (equals) sign, -followed by a newline. The key may contain any bytes except `=`, -newline, or NUL. The value may contain any bytes except newline or NUL. -In both cases, all bytes are treated as-is (i.e., there is no quoting, -and one cannot transmit a value with newline or NUL in it). The list of -attributes is terminated by a blank line or end-of-file. - -Git will send the following attributes (but may not send all of -them for a given credential; for example, a `host` attribute makes no -sense when dealing with a non-network protocol): - -`protocol`:: - - The protocol over which the credential will be used (e.g., - `https`). - -`host`:: - - The remote hostname for a network credential. - -`path`:: - - The path with which the credential will be used. E.g., for - accessing a remote https repository, this will be the - repository's path on the server. - -`username`:: - - The credential's username, if we already have one (e.g., from a - URL, from the user, or from a previously run helper). - -`password`:: - - The credential's password, if we are asking it to be stored. +stream. The exact format is the same as the input/output format of the +`git credential` plumbing command (see the section `INPUT/OUTPUT +FORMAT` in linkgit:git-credential[7] for a detailed specification). For a `get` operation, the helper should produce a list of attributes on stdout in the same format. A helper is free to produce a subset, or diff --git a/Documentation/technical/api-history-graph.txt b/Documentation/technical/api-history-graph.txt index d6fc90ac7..18142b6d2 100644 --- a/Documentation/technical/api-history-graph.txt +++ b/Documentation/technical/api-history-graph.txt @@ -33,11 +33,11 @@ The following utility functions are wrappers around `graph_next_line()` and They can all be called with a NULL graph argument, in which case no graph output will be printed. -* `graph_show_commit()` calls `graph_next_line()` until it returns non-zero. - This prints all graph lines up to, and including, the line containing this - commit. Output is printed to stdout. The last line printed does not contain - a terminating newline. This should not be called if the commit line has - already been printed, or it will loop forever. +* `graph_show_commit()` calls `graph_next_line()` and + `graph_is_commit_finished()` until one of them return non-zero. This prints + all graph lines up to, and including, the line containing this commit. + Output is printed to stdout. The last line printed does not contain a + terminating newline. * `graph_show_oneline()` calls `graph_next_line()` and prints the result to stdout. The line printed does not contain a terminating newline. diff --git a/Documentation/technical/api-index-skel.txt b/Documentation/technical/api-index-skel.txt index af7cc2e39..730cfacf7 100644 --- a/Documentation/technical/api-index-skel.txt +++ b/Documentation/technical/api-index-skel.txt @@ -11,5 +11,3 @@ documents them. //////////////////////////////////////////////////////////////// // table of contents end //////////////////////////////////////////////////////////////// - -2007-11-24 diff --git a/Documentation/technical/api-sha1-array.txt b/Documentation/technical/api-sha1-array.txt index 4a4bae810..45d1c517c 100644 --- a/Documentation/technical/api-sha1-array.txt +++ b/Documentation/technical/api-sha1-array.txt @@ -25,9 +25,6 @@ Functions the array (but note that some operations below may lose this ordering). -`sha1_array_sort`:: - Sort the elements in the array. - `sha1_array_lookup`:: Perform a binary search of the array for a specific sha1. If found, returns the offset (in number of elements) of the diff --git a/Documentation/technical/api-strbuf.txt b/Documentation/technical/api-strbuf.txt index 95a8bf384..84686b5c6 100644 --- a/Documentation/technical/api-strbuf.txt +++ b/Documentation/technical/api-strbuf.txt @@ -279,6 +279,22 @@ same behaviour as well. Strip whitespace from a buffer. The second parameter controls if comments are considered contents to be removed or not. +`strbuf_split_buf`:: +`strbuf_split_str`:: +`strbuf_split_max`:: +`strbuf_split`:: + + Split a string or strbuf into a list of strbufs at a specified + terminator character. The returned substrings include the + terminator characters. Some of these functions take a `max` + parameter, which, if positive, limits the output to that + number of substrings. + +`strbuf_list_free`:: + + Free a list of strbufs (for example, the return values of the + `strbuf_split()` functions). + `launch_editor`:: Launch the user preferred editor to edit a file and fill the buffer diff --git a/Documentation/technical/api-string-list.txt b/Documentation/technical/api-string-list.txt index 5a0c14fce..7386bcab3 100644 --- a/Documentation/technical/api-string-list.txt +++ b/Documentation/technical/api-string-list.txt @@ -1,8 +1,9 @@ string-list API =============== -The string_list API offers a data structure and functions to handle sorted -and unsorted string lists. +The string_list API offers a data structure and functions to handle +sorted and unsorted string lists. A "sorted" list is one whose +entries are sorted by string value in `strcmp()` order. The 'string_list' struct used to be called 'path_list', but was renamed because it is not specific to paths. @@ -20,8 +21,9 @@ If you need something advanced, you can manually malloc() the `items` member (you need this if you add things later) and you should set the `nr` and `alloc` members in that case, too. -. Adds new items to the list, using `string_list_append` or - `string_list_insert`. +. Adds new items to the list, using `string_list_append`, + `string_list_append_nodup`, `string_list_insert`, + `string_list_split`, and/or `string_list_split_in_place`. . Can check if a string is in the list using `string_list_has_string` or `unsorted_string_list_has_string` and get it from the list using @@ -29,18 +31,24 @@ member (you need this if you add things later) and you should set the . Can sort an unsorted list using `sort_string_list`. +. Can remove duplicate items from a sorted list using + `string_list_remove_duplicates`. + . Can remove individual items of an unsorted list using `unsorted_string_list_delete_item`. +. Can remove items not matching a criterion from a sorted or unsorted + list using `filter_string_list`, or remove empty strings using + `string_list_remove_empty_items`. + . Finally it should free the list using `string_list_clear`. Example: ---- -struct string_list list; +struct string_list list = STRING_LIST_INIT_NODUP; int i; -memset(&list, 0, sizeof(struct string_list)); string_list_append(&list, "foo"); string_list_append(&list, "bar"); for (i = 0; i < list.nr; i++) @@ -60,6 +68,28 @@ Functions * General ones (works with sorted and unsorted lists as well) +`filter_string_list`:: + + Apply a function to each item in a list, retaining only the + items for which the function returns true. If free_util is + true, call free() on the util members of any items that have + to be deleted. Preserve the order of the items that are + retained. + +`string_list_remove_empty_items`:: + + Remove any empty strings from the list. If free_util is true, + call free() on the util members of any items that have to be + deleted. Preserve the order of the items that are retained. + +`string_list_longest_prefix`:: + + Return the longest string within a string_list that is a + prefix (in the sense of prefixcmp()) of the specified string, + or NULL if no such prefix exists. This function does not + require the string_list to be sorted (it does a linear + search). + `print_string_list`:: Dump a string_list to stdout, useful mainly for debugging purposes. It @@ -96,15 +126,32 @@ write `string_list_insert(...)->util = ...;`. Look up a given string in the string_list, returning the containing string_list_item. If the string is not found, NULL is returned. +`string_list_remove_duplicates`:: + + Remove all but the first of consecutive entries that have the + same string value. If free_util is true, call free() on the + util members of any items that have to be deleted. + * Functions for unsorted lists only `string_list_append`:: - Append a new string to the end of the string_list. + Append a new string to the end of the string_list. If + `strdup_string` is set, then the string argument is copied; + otherwise the new `string_list_entry` refers to the input + string. + +`string_list_append_nodup`:: + + Append a new string to the end of the string_list. The new + `string_list_entry` always refers to the input string, even if + `strdup_string` is set. This function can be used to hand + ownership of a malloc()ed string to a `string_list` that has + `strdup_string` set. `sort_string_list`:: - Make an unsorted list sorted. + Sort the list's entries by string value in `strcmp()` order. `unsorted_string_list_has_string`:: @@ -124,6 +171,25 @@ counterpart for sorted lists, which performs a binary search. is set. The third parameter controls if the `util` pointer of the items should be freed or not. +`string_list_split`:: +`string_list_split_in_place`:: + + Split a string into substrings on a delimiter character and + append the substrings to a `string_list`. If `maxsplit` is + non-negative, then split at most `maxsplit` times. Return the + number of substrings appended to the list. ++ +`string_list_split` requires a `string_list` that has `strdup_strings` +set to true; it leaves the input string untouched and makes copies of +the substrings in newly-allocated memory. +`string_list_split_in_place` requires a `string_list` that has +`strdup_strings` set to false; it splits the input string in place, +overwriting the delimiter characters with NULs and creating new +string_list_items that point into the original string (the original +string must therefore not be modified or freed while the `string_list` +is in use). + + Data structures --------------- diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt index 9d25b3017..732415483 100644 --- a/Documentation/technical/index-format.txt +++ b/Documentation/technical/index-format.txt @@ -1,7 +1,7 @@ GIT index format ================ -= The git index file has the following format +== The git index file has the following format All binary numbers are in network byte order. Version 2 is described here unless stated otherwise. @@ -161,8 +161,9 @@ GIT index format this span of index as a tree. An entry can be in an invalidated state and is represented by having - -1 in the entry_count field. In this case, there is no object name - and the next entry starts immediately after the newline. + a negative number in the entry_count field. In this case, there is no + object name and the next entry starts immediately after the newline. + When writing an invalid entry, -1 should always be used as entry_count. The entries are written out in the top-down, depth-first order. The first entry represents the root level of the repository, followed by the diff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt index 1803e64e4..a7871fb86 100644 --- a/Documentation/technical/pack-format.txt +++ b/Documentation/technical/pack-format.txt @@ -1,7 +1,7 @@ GIT pack format =============== -= pack-*.pack files have the following format: +== pack-*.pack files have the following format: - A header appears at the beginning and consists of the following: @@ -34,7 +34,7 @@ GIT pack format - The trailer records 20-byte SHA1 checksum of all of the above. -= Original (version 1) pack-*.idx files have the following format: +== Original (version 1) pack-*.idx files have the following format: - The header consists of 256 4-byte network byte order integers. N-th entry of this table records the number of @@ -123,8 +123,8 @@ Pack file entry: <+ -= Version 2 pack-*.idx files support packs larger than 4 GiB, and - have some other reorganizations. They have the format: +== Version 2 pack-*.idx files support packs larger than 4 GiB, and + have some other reorganizations. They have the format: - A 4-byte magic number '\377tOc' which is an unreasonable fanout[0] value. diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt index 49cdc571c..f1a51edf4 100644 --- a/Documentation/technical/pack-protocol.txt +++ b/Documentation/technical/pack-protocol.txt @@ -117,7 +117,7 @@ A few things to remember here: - The repository path is always quoted with single quotes. Fetching Data From a Server -=========================== +--------------------------- When one Git repository wants to get data that a second repository has, the first can 'fetch' from the second. This operation determines @@ -134,7 +134,8 @@ with the object name that each reference currently points to. $ echo -e -n "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" | nc -v example.com 9418 - 00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress include-tag + 00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack + side-band side-band-64k ofs-delta shallow no-progress include-tag 00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration 003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master 003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9 @@ -259,8 +260,10 @@ a positive depth, this step is skipped. ---- If the client has requested a positive depth, the server will compute -the set of commits which are no deeper than the desired depth, starting -at the client's wants. The server writes 'shallow' lines for each +the set of commits which are no deeper than the desired depth. The set +of commits start at the client's wants. + +The server writes 'shallow' lines for each commit whose parents will not be sent as a result. The server writes an 'unshallow' line for each commit which the client has indicated is shallow, but is no longer shallow at the currently requested depth @@ -419,7 +422,7 @@ entire packfile without multiplexing. Pushing Data To a Server -======================== +------------------------ Pushing data to a server will invoke the 'receive-pack' process on the server, which will allow the client to tell it which references it should diff --git a/Documentation/technical/send-pack-pipeline.txt b/Documentation/technical/send-pack-pipeline.txt index 681efe421..9b5a0bc18 100644 --- a/Documentation/technical/send-pack-pipeline.txt +++ b/Documentation/technical/send-pack-pipeline.txt @@ -1,5 +1,5 @@ -git-send-pack -============= +Git-send-pack internals +======================= Overall operation ----------------- diff --git a/Documentation/technical/shallow.txt b/Documentation/technical/shallow.txt index 559263af4..0502a5471 100644 --- a/Documentation/technical/shallow.txt +++ b/Documentation/technical/shallow.txt @@ -1,6 +1,12 @@ -Def.: Shallow commits do have parents, but not in the shallow +Shallow commits +=============== + +.Definition +********************************************************* +Shallow commits do have parents, but not in the shallow repo, and therefore grafts are introduced pretending that these commits have no parents. +********************************************************* The basic idea is to write the SHA1s of shallow commits into $GIT_DIR/shallow, and handle its contents like the contents diff --git a/Documentation/technical/trivial-merge.txt b/Documentation/technical/trivial-merge.txt index 24c84100b..c79d4a7c4 100644 --- a/Documentation/technical/trivial-merge.txt +++ b/Documentation/technical/trivial-merge.txt @@ -74,24 +74,24 @@ For multiple ancestors, a '+' means that this case applies even if only one ancestor or remote fits; a '^' means all of the ancestors must be the same. -case ancest head remote result ----------------------------------------- -1 (empty)+ (empty) (empty) (empty) -2ALT (empty)+ *empty* remote remote -2 (empty)^ (empty) remote no merge -3ALT (empty)+ head *empty* head -3 (empty)^ head (empty) no merge -4 (empty)^ head remote no merge -5ALT * head head head -6 ancest+ (empty) (empty) no merge -8 ancest^ (empty) ancest no merge -7 ancest+ (empty) remote no merge -10 ancest^ ancest (empty) no merge -9 ancest+ head (empty) no merge -16 anc1/anc2 anc1 anc2 no merge -13 ancest+ head ancest head -14 ancest+ ancest remote remote -11 ancest+ head remote no merge + case ancest head remote result + ---------------------------------------- + 1 (empty)+ (empty) (empty) (empty) + 2ALT (empty)+ *empty* remote remote + 2 (empty)^ (empty) remote no merge + 3ALT (empty)+ head *empty* head + 3 (empty)^ head (empty) no merge + 4 (empty)^ head remote no merge + 5ALT * head head head + 6 ancest+ (empty) (empty) no merge + 8 ancest^ (empty) ancest no merge + 7 ancest+ (empty) remote no merge + 10 ancest^ ancest (empty) no merge + 9 ancest+ head (empty) no merge + 16 anc1/anc2 anc1 anc2 no merge + 13 ancest+ head ancest head + 14 ancest+ ancest remote remote + 11 ancest+ head remote no merge Only #2ALT and #3ALT use *empty*, because these are the only cases where there can be conflicts that didn't exist before. Note that we diff --git a/Documentation/urls.txt b/Documentation/urls.txt index 289019478..1d15ee7e5 100644 --- a/Documentation/urls.txt +++ b/Documentation/urls.txt @@ -6,8 +6,12 @@ address of the remote server, and the path to the repository. Depending on the transport protocol, some of this information may be absent. -Git natively supports ssh, git, http, https, ftp, ftps, and rsync -protocols. The following syntaxes may be used with them: +Git supports ssh, git, http, and https protocols (in addition, ftp, +and ftps can be used for fetching and rsync can be used for fetching +and pushing, but these are inefficient and deprecated; do not use +them). + +The following syntaxes may be used with them: - ssh://{startsb}user@{endsb}host.xz{startsb}:port{endsb}/path/to/repo.git/ - git://host.xz{startsb}:port{endsb}/path/to/repo.git/ diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index 03d95dc29..1b377dc20 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -1136,9 +1136,12 @@ Creating good commit messages Though not required, it's a good idea to begin the commit message with a single short (less than 50 character) line summarizing the change, followed by a blank line and then a more thorough -description. Tools that turn commits into email, for example, use -the first line on the Subject line and the rest of the commit in the -body. +description. The text up to the first blank line in a commit +message is treated as the commit title, and that title is used +throughout git. For example, linkgit:git-format-patch[1] turns a +commit into email, and it uses the title on the Subject line and the +rest of the commit in the body. + [[ignoring-files]] Ignoring files @@ -1784,6 +1787,13 @@ $ git format-patch origin will produce a numbered series of files in the current directory, one for each patch in the current branch but not in origin/HEAD. +`git format-patch` can include an initial "cover letter". You can insert +commentary on individual patches after the three dash line which +`format-patch` places after the commit message but before the patch +itself. If you use `git notes` to track your cover letter material, +`git format-patch --notes` will include the commit's notes in a similar +manner. + You can then import these into your mail client and send them by hand. However, if you have a lot to send at once, you may prefer to use the linkgit:git-send-email[1] script to automate the process. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 28f12902a..72e37c9bf 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.7.11.7 +DEF_VER=v1.8.1 LF=' ' @@ -90,6 +90,8 @@ all:: # # Define NO_MKDTEMP if you don't have mkdtemp in the C library. # +# Define MKDIR_WO_TRAILING_SLASH if your mkdir() can't deal with trailing slash. +# # Define NO_MKSTEMPS if you don't have mkstemps in the C library. # # Define NO_STRTOK_R if you don't have strtok_r in the C library. @@ -143,6 +145,12 @@ all:: # # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin). # +# Define NEEDS_LIBINTL_BEFORE_LIBICONV if you need libintl before libiconv. +# +# Define NO_INTPTR_T if you don't have intptr_t nor uintptr_t. +# +# Define NO_UINTMAX_T if you don't have uintmax_t. +# # Define NEEDS_SOCKET if linking with libc is not enough (SunOS, # Patrick Mauritz). # @@ -152,11 +160,21 @@ all:: # # Define NO_MMAP if you want to avoid mmap. # +# Define NO_SYS_POLL_H if you don't have sys/poll.h. +# +# Define NO_POLL if you do not have or don't want to use poll(). +# This also implies NO_SYS_POLL_H. +# # Define NO_PTHREADS if you do not have or do not want to use Pthreads. # # Define NO_PREAD if you have a problem with pread() system call (e.g. # cygwin1.dll before v1.5.22). # +# Define NO_SETITIMER if you don't have setitimer() +# +# Define NO_STRUCT_ITIMERVAL if you don't have struct itimerval +# This also implies NO_SETITIMER +# # Define NO_THREAD_SAFE_PREAD if your pread() implementation is not # thread-safe. (e.g. compat/pread.c or cygwin) # @@ -205,8 +223,6 @@ all:: # Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks # field that counts the on-disk footprint in 512-byte blocks. # -# Define ASCIIDOC7 if you want to format documentation with AsciiDoc 7 -# # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72 # (not v1.73 or v1.71). # @@ -298,6 +314,13 @@ all:: # 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)". +# +# Define DEFAULT_HELP_FORMAT to "man", "info" or "html" +# (defaults to "man") if you want to have a different default when +# "git help" is called without a parameter specifying the format. GIT-VERSION-FILE: FORCE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -351,7 +374,7 @@ htmldir = share/doc/git-doc ETC_GITCONFIG = $(sysconfdir)/gitconfig ETC_GITATTRIBUTES = $(sysconfdir)/gitattributes lib = lib -# DESTDIR= +# DESTDIR = pathsep = : export prefix bindir sharedir sysconfdir gitwebdir localedir @@ -391,12 +414,9 @@ BUILTIN_OBJS = BUILT_INS = COMPAT_CFLAGS = COMPAT_OBJS = -XDIFF_H = XDIFF_OBJS = -VCSSVN_H = VCSSVN_OBJS = -VCSSVN_TEST_OBJS = -MISC_H = +GENERATED_H = EXTRA_CPPFLAGS = LIB_H = LIB_OBJS = @@ -475,6 +495,7 @@ PROGRAM_OBJS += sh-i18n--envsubst.o PROGRAM_OBJS += shell.o PROGRAM_OBJS += show-index.o PROGRAM_OBJS += upload-pack.o +PROGRAM_OBJS += remote-testsvn.o # Binary suffix, set to .exe for Windows builds X = @@ -482,7 +503,6 @@ X = PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS)) TEST_PROGRAMS_NEED_X += test-chmtime -TEST_PROGRAMS_NEED_X += test-credential TEST_PROGRAMS_NEED_X += test-ctype TEST_PROGRAMS_NEED_X += test-date TEST_PROGRAMS_NEED_X += test-delta @@ -501,6 +521,7 @@ TEST_PROGRAMS_NEED_X += test-run-command TEST_PROGRAMS_NEED_X += test-scrap-cache-tree TEST_PROGRAMS_NEED_X += test-sha1 TEST_PROGRAMS_NEED_X += test-sigchain +TEST_PROGRAMS_NEED_X += test-string-list TEST_PROGRAMS_NEED_X += test-subprocess TEST_PROGRAMS_NEED_X += test-svn-fe @@ -554,58 +575,51 @@ endif export PERL_PATH export PYTHON_PATH -LIB_FILE=libgit.a -XDIFF_LIB=xdiff/lib.a -VCSSVN_LIB=vcs-svn/lib.a - -XDIFF_H += xdiff/xinclude.h -XDIFF_H += xdiff/xmacros.h -XDIFF_H += xdiff/xdiff.h -XDIFF_H += xdiff/xtypes.h -XDIFF_H += xdiff/xutils.h -XDIFF_H += xdiff/xprepare.h -XDIFF_H += xdiff/xdiffi.h -XDIFF_H += xdiff/xemit.h - -VCSSVN_H += vcs-svn/line_buffer.h -VCSSVN_H += vcs-svn/sliding_window.h -VCSSVN_H += vcs-svn/repo_tree.h -VCSSVN_H += vcs-svn/fast_export.h -VCSSVN_H += vcs-svn/svndiff.h -VCSSVN_H += vcs-svn/svndump.h - -MISC_H += bisect.h -MISC_H += branch.h -MISC_H += bundle.h -MISC_H += common-cmds.h -MISC_H += fetch-pack.h -MISC_H += reachable.h -MISC_H += send-pack.h -MISC_H += shortlog.h -MISC_H += tar.h -MISC_H += thread-utils.h -MISC_H += url.h -MISC_H += walker.h -MISC_H += wt-status.h +LIB_FILE = libgit.a +XDIFF_LIB = xdiff/lib.a +VCSSVN_LIB = vcs-svn/lib.a + +LIB_H += xdiff/xinclude.h +LIB_H += xdiff/xmacros.h +LIB_H += xdiff/xdiff.h +LIB_H += xdiff/xtypes.h +LIB_H += xdiff/xutils.h +LIB_H += xdiff/xprepare.h +LIB_H += xdiff/xdiffi.h +LIB_H += xdiff/xemit.h + +LIB_H += vcs-svn/line_buffer.h +LIB_H += vcs-svn/sliding_window.h +LIB_H += vcs-svn/repo_tree.h +LIB_H += vcs-svn/fast_export.h +LIB_H += vcs-svn/svndiff.h +LIB_H += vcs-svn/svndump.h + +GENERATED_H += common-cmds.h LIB_H += advice.h LIB_H += archive.h LIB_H += argv-array.h LIB_H += attr.h +LIB_H += bisect.h LIB_H += blob.h +LIB_H += branch.h LIB_H += builtin.h LIB_H += bulk-checkin.h -LIB_H += cache.h +LIB_H += bundle.h LIB_H += cache-tree.h +LIB_H += cache.h LIB_H += color.h +LIB_H += column.h LIB_H += commit.h LIB_H += compat/bswap.h LIB_H += compat/cygwin.h LIB_H += compat/mingw.h LIB_H += compat/obstack.h +LIB_H += compat/poll/poll.h +LIB_H += compat/precompose_utf8.h LIB_H += compat/terminal.h LIB_H += compat/win32/dirent.h -LIB_H += compat/win32/poll.h LIB_H += compat/win32/pthread.h LIB_H += compat/win32/syslog.h LIB_H += connected.h @@ -618,6 +632,7 @@ LIB_H += diff.h LIB_H += diffcore.h LIB_H += dir.h LIB_H += exec_cmd.h +LIB_H += fetch-pack.h LIB_H += fmt-merge-msg.h LIB_H += fsck.h LIB_H += gettext.h @@ -627,6 +642,7 @@ LIB_H += graph.h LIB_H += grep.h LIB_H += hash.h LIB_H += help.h +LIB_H += http.h LIB_H += kwset.h LIB_H += levenshtein.h LIB_H += list-objects.h @@ -636,19 +652,20 @@ LIB_H += mailmap.h LIB_H += merge-file.h LIB_H += merge-recursive.h LIB_H += mergesort.h -LIB_H += notes.h LIB_H += notes-cache.h LIB_H += notes-merge.h +LIB_H += notes.h LIB_H += object.h -LIB_H += pack.h LIB_H += pack-refs.h LIB_H += pack-revindex.h +LIB_H += pack.h LIB_H += parse-options.h LIB_H += patch-ids.h LIB_H += pkt-line.h LIB_H += progress.h LIB_H += prompt.h LIB_H += quote.h +LIB_H += reachable.h LIB_H += reflog-walk.h LIB_H += refs.h LIB_H += remote.h @@ -656,9 +673,11 @@ LIB_H += rerere.h LIB_H += resolve-undo.h LIB_H += revision.h LIB_H += run-command.h +LIB_H += send-pack.h LIB_H += sequencer.h LIB_H += sha1-array.h LIB_H += sha1-lookup.h +LIB_H += shortlog.h LIB_H += sideband.h LIB_H += sigchain.h LIB_H += strbuf.h @@ -666,14 +685,18 @@ LIB_H += streaming.h LIB_H += string-list.h LIB_H += submodule.h LIB_H += tag.h +LIB_H += tar.h LIB_H += thread-utils.h LIB_H += transport.h -LIB_H += tree.h LIB_H += tree-walk.h +LIB_H += tree.h LIB_H += unpack-trees.h +LIB_H += url.h LIB_H += userdiff.h LIB_H += utf8.h LIB_H += varint.h +LIB_H += walker.h +LIB_H += wt-status.h LIB_H += xdiff-interface.h LIB_H += xdiff/xdiff.h @@ -723,6 +746,7 @@ LIB_OBJS += editor.o LIB_OBJS += entry.o LIB_OBJS += environment.o LIB_OBJS += exec_cmd.o +LIB_OBJS += fetch-pack.o LIB_OBJS += fsck.o LIB_OBJS += gettext.o LIB_OBJS += gpg-interface.o @@ -740,6 +764,7 @@ LIB_OBJS += lockfile.o LIB_OBJS += log-tree.o LIB_OBJS += mailmap.o LIB_OBJS += match-trees.o +LIB_OBJS += merge.o LIB_OBJS += merge-file.o LIB_OBJS += merge-recursive.o LIB_OBJS += mergesort.o @@ -774,6 +799,7 @@ LIB_OBJS += rerere.o LIB_OBJS += resolve-undo.o LIB_OBJS += revision.o LIB_OBJS += run-command.o +LIB_OBJS += send-pack.o LIB_OBJS += sequencer.o LIB_OBJS += server-info.o LIB_OBJS += setup.o @@ -802,6 +828,7 @@ LIB_OBJS += usage.o LIB_OBJS += userdiff.o LIB_OBJS += utf8.o LIB_OBJS += varint.o +LIB_OBJS += version.o LIB_OBJS += walker.o LIB_OBJS += wrapper.o LIB_OBJS += write_or_die.o @@ -830,6 +857,7 @@ BUILTIN_OBJS += builtin/commit-tree.o BUILTIN_OBJS += builtin/commit.o BUILTIN_OBJS += builtin/config.o BUILTIN_OBJS += builtin/count-objects.o +BUILTIN_OBJS += builtin/credential.o BUILTIN_OBJS += builtin/describe.o BUILTIN_OBJS += builtin/diff-files.o BUILTIN_OBJS += builtin/diff-index.o @@ -907,6 +935,8 @@ BUILTIN_OBJS += builtin/write-tree.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) EXTLIBS = +GIT_USER_AGENT = git/$(GIT_VERSION) + # # Platform specific tweaks # @@ -993,6 +1023,8 @@ ifeq ($(uname_S),Darwin) NO_MEMMEM = YesPlease USE_ST_TIMESPEC = YesPlease HAVE_DEV_TTY = YesPlease + COMPAT_OBJS += compat/precompose_utf8.o + BASIC_CFLAGS += -DPRECOMPOSE_UNICODE endif ifeq ($(uname_S),SunOS) NEEDS_SOCKET = YesPlease @@ -1054,6 +1086,7 @@ ifeq ($(uname_O),Cygwin) NO_SYMLINK_HEAD = YesPlease NO_IPV6 = YesPlease OLD_ICONV = UnfortunatelyYes + CYGWIN_V15_WIN32API = YesPlease endif NO_THREAD_SAFE_PREAD = YesPlease NEEDS_LIBICONV = YesPlease @@ -1106,7 +1139,7 @@ ifeq ($(uname_S),NetBSD) endif ifeq ($(uname_S),AIX) DEFAULT_PAGER = more - NO_STRCASESTR=YesPlease + NO_STRCASESTR = YesPlease NO_MEMMEM = YesPlease NO_MKDTEMP = YesPlease NO_MKSTEMPS = YesPlease @@ -1114,7 +1147,7 @@ ifeq ($(uname_S),AIX) NO_NSEC = YesPlease FREAD_READS_DIRECTORIES = UnfortunatelyYes INTERNAL_QSORT = UnfortunatelyYes - NEEDS_LIBICONV=YesPlease + NEEDS_LIBICONV = YesPlease BASIC_CFLAGS += -D_LARGE_FILES ifeq ($(shell expr "$(uname_V)" : '[1234]'),1) NO_PTHREADS = YesPlease @@ -1122,13 +1155,13 @@ ifeq ($(uname_S),AIX) PTHREAD_LIBS = -lpthread endif ifeq ($(shell expr "$(uname_V).$(uname_R)" : '5\.1'),3) - INLINE='' + INLINE = '' endif GIT_TEST_CMP = cmp endif ifeq ($(uname_S),GNU) # GNU/Hurd - NO_STRLCPY=YesPlease + NO_STRLCPY = YesPlease NO_MKSTEMPS = YesPlease HAVE_PATHS_H = YesPlease LIBC_CONTAINS_LIBINTL = YesPlease @@ -1154,9 +1187,9 @@ ifeq ($(uname_S),IRIX) NEEDS_LIBGEN = YesPlease endif ifeq ($(uname_S),IRIX64) - NO_SETENV=YesPlease + NO_SETENV = YesPlease NO_UNSETENV = YesPlease - NO_STRCASESTR=YesPlease + NO_STRCASESTR = YesPlease NO_MEMMEM = YesPlease NO_MKSTEMPS = YesPlease NO_MKDTEMP = YesPlease @@ -1170,14 +1203,14 @@ ifeq ($(uname_S),IRIX64) NO_REGEX = YesPlease NO_FNMATCH_CASEFOLD = YesPlease SNPRINTF_RETURNS_BOGUS = YesPlease - SHELL_PATH=/usr/gnu/bin/bash + SHELL_PATH = /usr/gnu/bin/bash NEEDS_LIBGEN = YesPlease endif ifeq ($(uname_S),HP-UX) INLINE = __inline - NO_IPV6=YesPlease - NO_SETENV=YesPlease - NO_STRCASESTR=YesPlease + NO_IPV6 = YesPlease + NO_SETENV = YesPlease + NO_STRCASESTR = YesPlease NO_MEMMEM = YesPlease NO_MKSTEMPS = YesPlease NO_STRLCPY = YesPlease @@ -1208,7 +1241,7 @@ ifeq ($(uname_S),Windows) NO_PREAD = YesPlease NEEDS_CRYPTO_WITH_SSL = YesPlease NO_LIBGEN_H = YesPlease - NO_SYS_POLL_H = YesPlease + NO_POLL = YesPlease NO_SYMLINK_HEAD = YesPlease NO_IPV6 = YesPlease NO_UNIX_SOCKETS = YesPlease @@ -1241,6 +1274,7 @@ ifeq ($(uname_S),Windows) BLK_SHA1 = YesPlease NO_POSIX_GOODIES = UnfortunatelyYes NATIVE_CRLF = YesPlease + DEFAULT_HELP_FORMAT = html CC = compat/vcbuild/scripts/clink.pl AR = compat/vcbuild/scripts/lib.pl @@ -1248,7 +1282,7 @@ ifeq ($(uname_S),Windows) BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE COMPAT_OBJS = compat/msvc.o compat/winansi.o \ compat/win32/pthread.o compat/win32/syslog.o \ - compat/win32/poll.o compat/win32/dirent.o + compat/win32/dirent.o COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\" BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib @@ -1298,12 +1332,71 @@ ifeq ($(uname_S),Minix) NO_CURL = NO_EXPAT = endif +ifeq ($(uname_S),NONSTOP_KERNEL) + # Needs some C99 features, "inline" is just one of them. + # INLINE='' would just replace one set of warnings with another and + # still not compile in c89 mode, due to non-const array initializations. + CC = cc -c99 + # Disable all optimization, seems to result in bad code, with -O or -O2 + # or even -O1 (default), /usr/local/libexec/git-core/git-pack-objects + # abends on "git push". Needs more investigation. + CFLAGS = -g -O0 + # We'd want it to be here. + prefix = /usr/local + # Our's are in ${prefix}/bin (perl might also be in /usr/bin/perl). + PERL_PATH = ${prefix}/bin/perl + PYTHON_PATH = ${prefix}/bin/python + + # As detected by './configure'. + # Missdetected, hence commented out, see below. + #NO_CURL = YesPlease + # Added manually, see above. + NEEDS_SSL_WITH_CURL = YesPlease + HAVE_LIBCHARSET_H = YesPlease + NEEDS_LIBICONV = YesPlease + NEEDS_LIBINTL_BEFORE_LIBICONV = YesPlease + NO_SYS_SELECT_H = UnfortunatelyYes + NO_D_TYPE_IN_DIRENT = YesPlease + NO_HSTRERROR = YesPlease + NO_STRCASESTR = YesPlease + NO_FNMATCH_CASEFOLD = YesPlease + NO_MEMMEM = YesPlease + NO_STRLCPY = YesPlease + NO_SETENV = YesPlease + NO_UNSETENV = YesPlease + NO_MKDTEMP = YesPlease + NO_MKSTEMPS = YesPlease + # Currently libiconv-1.9.1. + OLD_ICONV = UnfortunatelyYes + NO_REGEX = YesPlease + NO_PTHREADS = UnfortunatelyYes + + # Not detected (nor checked for) by './configure'. + # We don't have SA_RESTART on NonStop, unfortunalety. + COMPAT_CFLAGS += -DSA_RESTART=0 + # Apparently needed in compat/fnmatch/fnmatch.c. + COMPAT_CFLAGS += -DHAVE_STRING_H=1 + NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease + NO_NSEC = YesPlease + NO_PREAD = YesPlease + NO_MMAP = YesPlease + NO_POLL = YesPlease + NO_INTPTR_T = UnfortunatelyYes + # Bug report 10-120822-4477 submitted to HP NonStop development. + MKDIR_WO_TRAILING_SLASH = YesPlease + # RFE 10-120912-4693 submitted to HP NonStop development. + NO_SETITIMER = UnfortunatelyYes + SANE_TOOL_PATH = /usr/coreutils/bin:/usr/local/bin + SHELL_PATH = /usr/local/bin/bash + # as of H06.25/J06.14, we might better use this + #SHELL_PATH = /usr/coreutils/bin/bash +endif ifneq (,$(findstring MINGW,$(uname_S))) pathsep = ; NO_PREAD = YesPlease NEEDS_CRYPTO_WITH_SSL = YesPlease NO_LIBGEN_H = YesPlease - NO_SYS_POLL_H = YesPlease + NO_POLL = YesPlease NO_SYMLINK_HEAD = YesPlease NO_UNIX_SOCKETS = YesPlease NO_SETENV = YesPlease @@ -1338,13 +1431,13 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/winansi.o \ compat/win32/pthread.o compat/win32/syslog.o \ - compat/win32/poll.o compat/win32/dirent.o + compat/win32/dirent.o EXTLIBS += -lws2_32 PTHREAD_LIBS = X = .exe SPARSE_FLAGS = -Wno-one-bit-signed-bitfield ifneq (,$(wildcard ../THIS_IS_MSYSGIT)) - htmldir=doc/git/html/ + htmldir = doc/git/html/ prefix = INSTALL = /bin/install EXTLIBS += /mingw/lib/libz.a @@ -1466,7 +1559,7 @@ else CURL_LIBCURL = -lcurl endif ifdef NEEDS_SSL_WITH_CURL - CURL_LIBCURL += -lssl + CURL_LIBCURL += -lssl ifdef NEEDS_CRYPTO_WITH_SSL CURL_LIBCURL += -lcrypto endif @@ -1480,7 +1573,7 @@ else REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES) PROGRAM_OBJS += http-fetch.o PROGRAMS += $(REMOTE_CURL_NAMES) - curl_check := $(shell (echo 070908; curl-config --vernum) | sort -r | sed -ne 2p) + curl_check := $(shell (echo 070908; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p) ifeq "$(curl_check)" "070908" ifndef NO_EXPAT PROGRAM_OBJS += http-push.o @@ -1534,6 +1627,9 @@ ifdef NEEDS_LIBICONV else ICONV_LINK = endif + ifdef NEEDS_LIBINTL_BEFORE_LIBICONV + ICONV_LINK += -lintl + endif EXTLIBS += $(ICONV_LINK) -liconv endif ifdef NEEDS_LIBGEN @@ -1592,6 +1688,11 @@ ifdef NO_GETTEXT BASIC_CFLAGS += -DNO_GETTEXT USE_GETTEXT_SCHEME ?= fallthrough endif +ifdef NO_POLL + NO_SYS_POLL_H = YesPlease + COMPAT_CFLAGS += -DNO_POLL -Icompat/poll + COMPAT_OBJS += compat/poll/poll.o +endif ifdef NO_STRCASESTR COMPAT_CFLAGS += -DNO_STRCASESTR COMPAT_OBJS += compat/strcasestr.o @@ -1630,6 +1731,10 @@ ifdef NO_MKDTEMP COMPAT_CFLAGS += -DNO_MKDTEMP COMPAT_OBJS += compat/mkdtemp.o endif +ifdef MKDIR_WO_TRAILING_SLASH + COMPAT_CFLAGS += -DMKDIR_WO_TRAILING_SLASH + COMPAT_OBJS += compat/mkdir.o +endif ifdef NO_MKSTEMPS COMPAT_CFLAGS += -DNO_MKSTEMPS endif @@ -1661,6 +1766,13 @@ endif ifdef OBJECT_CREATION_USES_RENAMES COMPAT_CFLAGS += -DOBJECT_CREATION_MODE=1 endif +ifdef NO_STRUCT_ITIMERVAL + COMPAT_CFLAGS += -DNO_STRUCT_ITIMERVAL + NO_SETITIMER = YesPlease +endif +ifdef NO_SETITIMER + COMPAT_CFLAGS += -DNO_SETITIMER +endif ifdef NO_PREAD COMPAT_CFLAGS += -DNO_PREAD COMPAT_OBJS += compat/pread.o @@ -1678,6 +1790,9 @@ endif ifdef NO_IPV6 BASIC_CFLAGS += -DNO_IPV6 endif +ifdef NO_INTPTR_T + COMPAT_CFLAGS += -DNO_INTPTR_T +endif ifdef NO_UINTMAX_T BASIC_CFLAGS += -Duintmax_t=uint32_t endif @@ -1783,6 +1898,9 @@ ifdef NO_REGEX COMPAT_CFLAGS += -Icompat/regex COMPAT_OBJS += compat/regex/regex.o endif +ifdef CYGWIN_V15_WIN32API + COMPAT_CFLAGS += -DCYGWIN_V15_WIN32API +endif ifdef USE_NED_ALLOCATOR COMPAT_CFLAGS += -Icompat/nedmalloc @@ -1802,15 +1920,15 @@ ifneq (,$(XDL_FAST_HASH)) endif ifeq ($(TCLTK_PATH),) -NO_TCLTK=NoThanks +NO_TCLTK = NoThanks endif ifeq ($(PERL_PATH),) -NO_PERL=NoThanks +NO_PERL = NoThanks endif ifeq ($(PYTHON_PATH),) -NO_PYTHON=NoThanks +NO_PYTHON = NoThanks endif QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir @@ -1843,10 +1961,6 @@ ifndef V endif endif -ifdef ASCIIDOC7 - export ASCIIDOC7 -endif - ifdef NO_INSTALL_HARDLINKS export NO_INSTALL_HARDLINKS endif @@ -1861,13 +1975,13 @@ PROFILE_DIR := $(CURDIR) ifeq ("$(PROFILE)","GEN") CFLAGS += -fprofile-generate=$(PROFILE_DIR) -DNO_NORETURN=1 EXTLIBS += -lgcov - export CCACHE_DISABLE=t - V=1 + export CCACHE_DISABLE = t + V = 1 else ifneq ("$(PROFILE)","") CFLAGS += -fprofile-use=$(PROFILE_DIR) -fprofile-correction -DNO_NORETURN=1 - export CCACHE_DISABLE=t - V=1 + export CCACHE_DISABLE = t + V = 1 endif endif @@ -1924,6 +2038,18 @@ SHELL_PATH_CQ_SQ = $(subst ','\'',$(SHELL_PATH_CQ)) BASIC_CFLAGS += -DSHELL_PATH='$(SHELL_PATH_CQ_SQ)' endif +GIT_USER_AGENT_SQ = $(subst ','\'',$(GIT_USER_AGENT)) +GIT_USER_AGENT_CQ = "$(subst ",\",$(subst \,\\,$(GIT_USER_AGENT)))" +GIT_USER_AGENT_CQ_SQ = $(subst ','\'',$(GIT_USER_AGENT_CQ)) +GIT-USER-AGENT: FORCE + @if test x'$(GIT_USER_AGENT_SQ)' != x"`cat GIT-USER-AGENT 2>/dev/null`"; then \ + echo '$(GIT_USER_AGENT_SQ)' >GIT-USER-AGENT; \ + fi + +ifdef DEFAULT_HELP_FORMAT +BASIC_CFLAGS += -DDEFAULT_HELP_FORMAT='"$(DEFAULT_HELP_FORMAT)"' +endif + ALL_CFLAGS += $(BASIC_CFLAGS) ALL_LDFLAGS += $(BASIC_LDFLAGS) @@ -1970,8 +2096,41 @@ shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell strip: $(PROGRAMS) git$X $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X -git.o: common-cmds.h -git.sp git.s git.o: EXTRA_CPPFLAGS = -DGIT_VERSION='"$(GIT_VERSION)"' \ +### Target-specific flags and dependencies + +# The generic compilation pattern rule and automatically +# computed header dependencies (falling back to a dependency on +# LIB_H) are enough to describe how most targets should be built, +# but some targets are special enough to need something a little +# different. +# +# - When a source file "foo.c" #includes a generated header file, +# we need to list that dependency for the "foo.o" target. +# +# We also list it from other targets that are built from foo.c +# like "foo.sp" and "foo.s", even though that is easy to forget +# to do because the generated header is already present around +# after a regular build attempt. +# +# - Some code depends on configuration kept in makefile +# variables. The target-specific variable EXTRA_CPPFLAGS can +# be used to convey that information to the C preprocessor +# using -D options. +# +# The "foo.o" target should have a corresponding dependency on +# a file that changes when the value of the makefile variable +# changes. For example, targets making use of the +# $(GIT_VERSION) variable depend on GIT-VERSION-FILE. +# +# Technically the ".sp" and ".s" targets do not need this +# dependency because they are force-built, but they get the +# same dependency for consistency. This way, you do not have to +# know how each target is implemented. And it means the +# dependencies here will not need to change if the force-build +# details change some day. + +git.sp git.s git.o: GIT-PREFIX +git.sp git.s git.o: EXTRA_CPPFLAGS = \ '-DGIT_HTML_PATH="$(htmldir_SQ)"' \ '-DGIT_MAN_PATH="$(mandir_SQ)"' \ '-DGIT_INFO_PATH="$(infodir_SQ)"' @@ -1980,14 +2139,19 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \ $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) -help.sp help.o: common-cmds.h +help.sp help.s help.o: common-cmds.h -builtin/help.sp builtin/help.o: common-cmds.h +builtin/help.sp builtin/help.s builtin/help.o: common-cmds.h GIT-PREFIX builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \ '-DGIT_HTML_PATH="$(htmldir_SQ)"' \ '-DGIT_MAN_PATH="$(mandir_SQ)"' \ '-DGIT_INFO_PATH="$(infodir_SQ)"' +version.sp version.s version.o: GIT-VERSION-FILE GIT-USER-AGENT +version.sp version.s version.o: EXTRA_CPPFLAGS = \ + '-DGIT_VERSION="$(GIT_VERSION)"' \ + '-DGIT_USER_AGENT=$(GIT_USER_AGENT_CQ_SQ)' + $(BUILT_INS): git$X $(QUIET_BUILT_IN)$(RM) $@ && \ ln git$X $@ 2>/dev/null || \ @@ -1999,35 +2163,54 @@ common-cmds.h: ./generate-cmdlist.sh command-list.txt common-cmds.h: $(wildcard Documentation/git-*.txt) $(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@ +SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\ + $(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\ + $(gitwebdir_SQ):$(PERL_PATH_SQ) define cmd_munge_script $(RM) $@ $@+ && \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ -e 's|@@DIFF@@|$(DIFF_SQ)|' \ - -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ -e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ -e 's/@@USE_GETTEXT_SCHEME@@/$(USE_GETTEXT_SCHEME)/g' \ -e $(BROKEN_PATH_FIX) \ + -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \ + -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ $@.sh >$@+ endef -$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh +GIT-SCRIPT-DEFINES: FORCE + @FLAGS='$(SCRIPT_DEFINES)'; \ + if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \ + echo 1>&2 " * new script parameters"; \ + echo "$$FLAGS" >$@; \ + fi + + +$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh GIT-SCRIPT-DEFINES $(QUIET_GEN)$(cmd_munge_script) && \ chmod +x $@+ && \ mv $@+ $@ -$(SCRIPT_LIB) : % : %.sh +$(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES $(QUIET_GEN)$(cmd_munge_script) && \ mv $@+ $@ ifndef NO_PERL $(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak -perl/perl.mak: GIT-CFLAGS perl/Makefile perl/Makefile.PL +perl/perl.mak: perl/PM.stamp + +perl/PM.stamp: FORCE + $(QUIET_GEN)$(FIND) perl -type f -name '*.pm' | sort >$@+ && \ + { cmp $@+ $@ >/dev/null 2>/dev/null || mv $@+ $@; } && \ + $(RM) $@+ + +perl/perl.mak: GIT-CFLAGS GIT-PREFIX perl/Makefile perl/Makefile.PL $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F) -$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl +$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE $(QUIET_GEN)$(RM) $@ $@+ && \ INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C perl -s --no-print-directory instlibdir` && \ sed -e '1{' \ @@ -2047,14 +2230,8 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl gitweb: $(QUIET_SUBDIR0)gitweb $(QUIET_SUBDIR1) all -git-instaweb: git-instaweb.sh gitweb - $(QUIET_GEN)$(RM) $@ $@+ && \ - sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ - -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ - -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ - -e 's|@@GITWEBDIR@@|$(gitwebdir_SQ)|g' \ - -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ - $@.sh > $@+ && \ +git-instaweb: git-instaweb.sh gitweb GIT-SCRIPT-DEFINES + $(QUIET_GEN)$(cmd_munge_script) && \ chmod +x $@+ && \ mv $@+ $@ else # NO_PERL @@ -2068,7 +2245,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)) git-instaweb: % : unimplemented.sh endif # NO_PERL ifndef NO_PYTHON -$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS +$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py $(QUIET_GEN)$(RM) $@ $@+ && \ INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \ @@ -2090,24 +2267,29 @@ $(patsubst %.py,%,$(SCRIPT_PYTHON)): % : unimplemented.sh mv $@+ $@ endif # NO_PYTHON -configure: configure.ac +configure: configure.ac GIT-VERSION-FILE $(QUIET_GEN)$(RM) $@ $<+ && \ sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ $< > $<+ && \ autoconf -o $@ $<+ && \ $(RM) $<+ -# These can record GIT_VERSION -git.o git.spec http.o \ - $(patsubst %.sh,%,$(SCRIPT_SH)) \ - $(patsubst %.perl,%,$(SCRIPT_PERL)) \ - : GIT-VERSION-FILE - -TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS)) -GIT_OBJS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \ - git.o -ifndef NO_CURL - GIT_OBJS += http.o http-walker.o remote-curl.o +ifdef AUTOCONFIGURED +# We avoid depending on 'configure' here, because it gets rebuilt +# every time GIT-VERSION-FILE is modified, only to update the embedded +# version number string, which config.status does not care about. We +# do want to recheck when the platform/environment detection logic +# changes, hence this depends on configure.ac. +config.status: configure.ac + $(QUIET_GEN)$(MAKE) configure && \ + if test -f config.status; then \ + ./config.status --recheck; \ + else \ + ./configure; \ + fi +reconfigure config.mak.autogen: config.status + $(QUIET_GEN)./config.status +.PHONY: reconfigure # This is a convenience target. endif XDIFF_OBJS += xdiff/xdiffi.o @@ -2125,9 +2307,14 @@ VCSSVN_OBJS += vcs-svn/fast_export.o VCSSVN_OBJS += vcs-svn/svndiff.o VCSSVN_OBJS += vcs-svn/svndump.o -VCSSVN_TEST_OBJS += test-line-buffer.o - -OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS) +TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS)) +OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \ + $(XDIFF_OBJS) \ + $(VCSSVN_OBJS) \ + git.o +ifndef NO_CURL + OBJECTS += http.o http-walker.o remote-curl.o +endif dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d) dep_dirs := $(addsuffix .depend,$(sort $(dir $(OBJECTS)))) @@ -2226,51 +2413,32 @@ else # Dependencies on automatically generated headers such as common-cmds.h # should _not_ be included here, since they are necessary even when # building an object for the first time. -# -# XXX. Please check occasionally that these include all dependencies -# gcc detects! -$(GIT_OBJS): $(LIB_H) -builtin/branch.o builtin/checkout.o builtin/clone.o builtin/reset.o branch.o transport.o: branch.h -builtin/bundle.o bundle.o transport.o: bundle.h -builtin/bisect--helper.o builtin/rev-list.o bisect.o: bisect.h -builtin/clone.o builtin/fetch-pack.o transport.o: fetch-pack.h -builtin/index-pack.o builtin/grep.o builtin/pack-objects.o transport-helper.o thread-utils.o: thread-utils.h -builtin/send-pack.o transport.o: send-pack.h -builtin/log.o builtin/shortlog.o: shortlog.h -builtin/prune.o builtin/reflog.o reachable.o: reachable.h -builtin/commit.o builtin/revert.o wt-status.o: wt-status.h -builtin/tar-tree.o archive-tar.o: tar.h -connect.o transport.o url.o http-backend.o: url.h -builtin/branch.o builtin/commit.o builtin/tag.o column.o help.o pager.o: column.h -http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h -http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h - -xdiff-interface.o $(XDIFF_OBJS): $(XDIFF_H) - -$(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) $(VCSSVN_H) +$(OBJECTS): $(LIB_H) endif +exec_cmd.sp exec_cmd.s exec_cmd.o: GIT-PREFIX exec_cmd.sp exec_cmd.s exec_cmd.o: EXTRA_CPPFLAGS = \ '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \ '-DBINDIR="$(bindir_relative_SQ)"' \ '-DPREFIX="$(prefix_SQ)"' +builtin/init-db.sp builtin/init-db.s builtin/init-db.o: GIT-PREFIX builtin/init-db.sp builtin/init-db.s builtin/init-db.o: EXTRA_CPPFLAGS = \ -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' +config.sp config.s config.o: GIT-PREFIX config.sp config.s config.o: EXTRA_CPPFLAGS = \ -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' +attr.sp attr.s attr.o: GIT-PREFIX attr.sp attr.s attr.o: EXTRA_CPPFLAGS = \ -DETC_GITATTRIBUTES='"$(ETC_GITATTRIBUTES_SQ)"' +gettext.sp gettext.s gettext.o: GIT-PREFIX gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \ -DGIT_LOCALE_PATH='"$(localedir_SQ)"' -http.sp http.s http.o: EXTRA_CPPFLAGS = \ - -DGIT_HTTP_USER_AGENT='"git/$(GIT_VERSION)"' - ifdef NO_EXPAT http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT endif @@ -2299,6 +2467,10 @@ git-http-push$X: revision.o http.o http-push.o GIT-LDFLAGS $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) +git-remote-testsvn$X: remote-testsvn.o GIT-LDFLAGS $(GITLIBS) $(VCSSVN_LIB) + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) \ + $(VCSSVN_LIB) + $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY) $(QUIET_LNCP)$(RM) $@ && \ ln $< $@ 2>/dev/null || \ @@ -2342,9 +2514,10 @@ XGETTEXT_FLAGS = \ --from-code=UTF-8 XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \ --keyword=_ --keyword=N_ --keyword="Q_:1,2" -XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell +XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \ + --keyword=gettextln --keyword=eval_gettextln XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl -LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(XDIFF_H) $(VCSSVN_H) $(MISC_H) +LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H) LOCALIZED_SH := $(SCRIPT_SH) LOCALIZED_PERL := $(SCRIPT_PERL) @@ -2391,14 +2564,22 @@ cscope: $(FIND_SOURCE_FILES) | xargs cscope -b ### Detect prefix changes -TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):\ - $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\ - $(localedir_SQ):$(USE_GETTEXT_SCHEME) +TRACK_PREFIX = $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\ + $(localedir_SQ) + +GIT-PREFIX: FORCE + @FLAGS='$(TRACK_PREFIX)'; \ + if test x"$$FLAGS" != x"`cat GIT-PREFIX 2>/dev/null`" ; then \ + echo 1>&2 " * new prefix flags"; \ + echo "$$FLAGS" >GIT-PREFIX; \ + fi + +TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):$(USE_GETTEXT_SCHEME) GIT-CFLAGS: FORCE @FLAGS='$(TRACK_CFLAGS)'; \ if test x"$$FLAGS" != x"`cat GIT-CFLAGS 2>/dev/null`" ; then \ - echo 1>&2 " * new build flags or prefix"; \ + echo 1>&2 " * new build flags"; \ echo "$$FLAGS" >GIT-CFLAGS; \ fi @@ -2461,6 +2642,18 @@ GIT-GUI-VARS: FORCE fi endif +### Detect Python interpreter path changes +ifndef NO_PYTHON +TRACK_PYTHON = $(subst ','\'',-DPYTHON_PATH='$(PYTHON_PATH_SQ)') + +GIT-PYTHON-VARS: FORCE + @VARS='$(TRACK_PYTHON)'; \ + if test x"$$VARS" != x"`cat $@ 2>/dev/null`" ; then \ + echo 1>&2 " * new Python interpreter location"; \ + echo "$$VARS" >$@; \ + fi +endif + test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X)) all:: $(TEST_PROGRAMS) $(test_bindir_programs) @@ -2477,6 +2670,7 @@ bin-wrappers/%: wrap-for-bin.sh # with that. export NO_SVN_TESTS +export TEST_NO_MALLOC_CHECK ### Testing rules @@ -2650,11 +2844,11 @@ quick-install-html: ### Maintainer's dist rules -git.spec: git.spec.in +git.spec: git.spec.in GIT-VERSION-FILE sed -e 's/@@VERSION@@/$(GIT_VERSION)/g' < $< > $@+ mv $@+ $@ -GIT_TARNAME=git-$(GIT_VERSION) +GIT_TARNAME = git-$(GIT_VERSION) dist: git.spec git-archive$(X) configure ./git-archive --format=tar \ --prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar @@ -2700,6 +2894,9 @@ dist-doc: distclean: clean $(RM) configure + $(RM) config.log config.status config.cache + $(RM) config.mak.autogen config.mak.append + $(RM) -r autom4te.cache profile-clean: $(RM) $(addsuffix *.gcda,$(addprefix $(PROFILE_DIR)/, $(object_dirs))) @@ -2714,8 +2911,6 @@ clean: profile-clean $(RM) -r $(dep_dirs) $(RM) -r po/build/ $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope* - $(RM) -r autom4te.cache - $(RM) config.log config.mak.autogen config.mak.append config.status config.cache $(RM) -r $(GIT_TARNAME) .doc-tmp-dir $(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz $(RM) $(htmldocs).tar.gz $(manpages).tar.gz @@ -2734,6 +2929,7 @@ ifndef NO_TCLTK $(MAKE) -C git-gui clean endif $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS + $(RM) GIT-USER-AGENT GIT-PREFIX GIT-SCRIPT-DEFINES GIT-PYTHON-VARS .PHONY: all install profile-clean clean strip .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell @@ -2741,8 +2937,13 @@ endif ### Check documentation # +ALL_COMMANDS = $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) +ALL_COMMANDS += git +ALL_COMMANDS += gitk +ALL_COMMANDS += gitweb +ALL_COMMANDS += git-gui git-citool check-docs:: - @(for v in $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk; \ + @(for v in $(ALL_COMMANDS); \ do \ case "$$v" in \ git-merge-octopus | git-merge-ours | git-merge-recursive | \ @@ -2764,35 +2965,13 @@ check-docs:: sed -e '/^#/d' \ -e 's/[ ].*//' \ -e 's/^/listed /' command-list.txt; \ - ls -1 Documentation/git*txt | \ + $(MAKE) -C Documentation print-man1 | \ + grep '\.txt$$' | \ sed -e 's|Documentation/|documented |' \ -e 's/\.txt//'; \ ) | while read how cmd; \ do \ - case "$$how,$$cmd" in \ - *,git-citool | \ - *,git-gui | \ - *,git-help | \ - documented,gitattributes | \ - documented,gitignore | \ - documented,gitmodules | \ - documented,gitcli | \ - documented,git-tools | \ - documented,gitcore-tutorial | \ - documented,gitcvs-migration | \ - documented,gitdiffcore | \ - documented,gitglossary | \ - documented,githooks | \ - documented,gitrepository-layout | \ - documented,gitrevisions | \ - documented,gittutorial | \ - documented,gittutorial-2 | \ - documented,git-bisect-lk2009 | \ - documented,git-remote-helpers | \ - documented,gitworkflows | \ - sentinel,not,matching,is,ok ) continue ;; \ - esac; \ - case " $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk " in \ + case " $(ALL_COMMANDS) " in \ *" $$cmd "*) ;; \ *) echo "removed but $$how: $$cmd" ;; \ esac; \ @@ -19,9 +19,10 @@ Git is a fast, scalable, distributed revision control system with an unusually rich command set that provides both high-level operations and full access to internals. -Git is an Open Source project covered by the GNU General Public License. -It was originally written by Linus Torvalds with help of a group of -hackers around the net. It is currently maintained by Junio C Hamano. +Git is an Open Source project covered by the GNU General Public +License version 2 (some parts of it are under different licenses, +compatible with the GPLv2). It was originally written by Linus +Torvalds with help of a group of hackers around the net. Please read the file INSTALL for installation instructions. @@ -1 +1 @@ -Documentation/RelNotes/1.7.11.7.txt
\ No newline at end of file +Documentation/RelNotes/1.8.1.1.txt
\ No newline at end of file @@ -35,6 +35,9 @@ const char *real_path(const char *path) if (path == buf || path == next_buf) return path; + if (!*path) + die("The empty string is not a valid path"); + if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die ("Too long path: %.*s", 60, path); @@ -42,8 +45,8 @@ const char *real_path(const char *path) if (!is_directory(buf)) { char *last_slash = find_last_dir_sep(buf); if (last_slash) { - *last_slash = '\0'; last_elem = xstrdup(last_slash + 1); + last_slash[1] = '\0'; } else { last_elem = xstrdup(buf); *buf = '\0'; @@ -123,7 +126,9 @@ const char *absolute_path(const char *path) { static char buf[PATH_MAX + 1]; - if (is_absolute_path(path)) { + if (!*path) { + die("The empty string is not a valid path"); + } else if (is_absolute_path(path)) { if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) die("Too long path: %.*s", 60, path); } else { diff --git a/archive-zip.c b/archive-zip.c index f5af81f90..55f66b406 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -4,6 +4,7 @@ #include "cache.h" #include "archive.h" #include "streaming.h" +#include "utf8.h" static int zip_date; static int zip_time; @@ -16,7 +17,8 @@ static unsigned int zip_dir_offset; static unsigned int zip_dir_entries; #define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024) -#define ZIP_STREAM (8) +#define ZIP_STREAM (1 << 3) +#define ZIP_UTF8 (1 << 11) struct zip_local_header { unsigned char magic[4]; @@ -74,6 +76,14 @@ struct zip_dir_trailer { unsigned char _end[1]; }; +struct zip_extra_mtime { + unsigned char magic[2]; + unsigned char extra_size[2]; + unsigned char flags[1]; + unsigned char mtime[4]; + unsigned char _end[1]; +}; + /* * On ARM, padding is added at the end of the struct, so a simple * sizeof(struct ...) reports two bytes more than the payload size @@ -83,6 +93,9 @@ struct zip_dir_trailer { #define ZIP_DATA_DESC_SIZE offsetof(struct zip_data_desc, _end) #define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end) #define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end) +#define ZIP_EXTRA_MTIME_SIZE offsetof(struct zip_extra_mtime, _end) +#define ZIP_EXTRA_MTIME_PAYLOAD_SIZE \ + (ZIP_EXTRA_MTIME_SIZE - offsetof(struct zip_extra_mtime, flags)) static void copy_le16(unsigned char *dest, unsigned int n) { @@ -164,6 +177,17 @@ static void set_zip_header_data_desc(struct zip_local_header *header, copy_le32(header->size, size); } +static int has_only_ascii(const char *s) +{ + for (;;) { + int c = *s++; + if (c == '\0') + return 1; + if (!isascii(c)) + return 0; + } +} + #define STREAM_BUFFER_SIZE (1024 * 16) static int write_zip_entry(struct archiver_args *args, @@ -173,6 +197,7 @@ static int write_zip_entry(struct archiver_args *args, { struct zip_local_header header; struct zip_dir_header dirent; + struct zip_extra_mtime extra; unsigned long attr2; unsigned long compressed_size; unsigned long crc; @@ -187,6 +212,13 @@ static int write_zip_entry(struct archiver_args *args, crc = crc32(0, NULL, 0); + if (!has_only_ascii(path)) { + if (is_utf8(path)) + flags |= ZIP_UTF8; + else + warning("Path is not valid UTF-8: %s", path); + } + if (pathlen > 0xffff) { return error("path too long (%d chars, SHA1: %s): %s", (int)pathlen, sha1_to_hex(sha1), path); @@ -246,8 +278,13 @@ static int write_zip_entry(struct archiver_args *args, } } + copy_le16(extra.magic, 0x5455); + copy_le16(extra.extra_size, ZIP_EXTRA_MTIME_PAYLOAD_SIZE); + extra.flags[0] = 1; /* just mtime */ + copy_le32(extra.mtime, args->time); + /* make sure we have enough free space in the dictionary */ - direntsize = ZIP_DIR_HEADER_SIZE + pathlen; + direntsize = ZIP_DIR_HEADER_SIZE + pathlen + ZIP_EXTRA_MTIME_SIZE; while (zip_dir_size < zip_dir_offset + direntsize) { zip_dir_size += ZIP_DIRECTORY_MIN_SIZE; zip_dir = xrealloc(zip_dir, zip_dir_size); @@ -263,7 +300,7 @@ static int write_zip_entry(struct archiver_args *args, copy_le16(dirent.mdate, zip_date); set_zip_dir_data_desc(&dirent, size, compressed_size, crc); copy_le16(dirent.filename_length, pathlen); - copy_le16(dirent.extra_length, 0); + copy_le16(dirent.extra_length, ZIP_EXTRA_MTIME_SIZE); copy_le16(dirent.comment_length, 0); copy_le16(dirent.disk, 0); copy_le16(dirent.attr1, 0); @@ -281,11 +318,13 @@ static int write_zip_entry(struct archiver_args *args, else set_zip_header_data_desc(&header, size, compressed_size, crc); copy_le16(header.filename_length, pathlen); - copy_le16(header.extra_length, 0); + copy_le16(header.extra_length, ZIP_EXTRA_MTIME_SIZE); write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE); zip_offset += ZIP_LOCAL_HEADER_SIZE; write_or_die(1, path, pathlen); zip_offset += pathlen; + write_or_die(1, &extra, ZIP_EXTRA_MTIME_SIZE); + zip_offset += ZIP_EXTRA_MTIME_SIZE; if (stream && method == 0) { unsigned char buf[STREAM_BUFFER_SIZE]; ssize_t readlen; @@ -382,6 +421,8 @@ static int write_zip_entry(struct archiver_args *args, zip_dir_offset += ZIP_DIR_HEADER_SIZE; memcpy(zip_dir + zip_dir_offset, path, pathlen); zip_dir_offset += pathlen; + memcpy(zip_dir + zip_dir_offset, &extra, ZIP_EXTRA_MTIME_SIZE); + zip_dir_offset += ZIP_EXTRA_MTIME_SIZE; zip_dir_entries++; return 0; @@ -7,10 +7,10 @@ #include "unpack-trees.h" static char const * const archive_usage[] = { - "git archive [options] <tree-ish> [<path>...]", - "git archive --list", - "git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]", - "git archive --remote <repo> [--exec <cmd>] --list", + N_("git archive [options] <tree-ish> [<path>...]"), + N_("git archive --list"), + N_("git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"), + N_("git archive --remote <repo> [--exec <cmd>] --list"), NULL }; @@ -120,6 +120,8 @@ static int write_archive_entry(const unsigned char *sha1, const char *base, strbuf_add(&path, args->base, args->baselen); strbuf_add(&path, base, baselen); strbuf_addstr(&path, filename); + if (S_ISDIR(mode) || S_ISGITLINK(mode)) + strbuf_addch(&path, '/'); path_without_prefix = path.buf + args->baselen; setup_archive_check(check); @@ -130,7 +132,6 @@ static int write_archive_entry(const unsigned char *sha1, const char *base, } if (S_ISDIR(mode) || S_ISGITLINK(mode)) { - strbuf_addch(&path, '/'); if (args->verbose) fprintf(stderr, "%.*s\n", (int)path.len, path.buf); err = write_entry(args, sha1, path.buf, path.len, mode); @@ -319,16 +320,16 @@ static int parse_archive_args(int argc, const char **argv, int worktree_attributes = 0; struct option opts[] = { OPT_GROUP(""), - OPT_STRING(0, "format", &format, "fmt", "archive format"), - OPT_STRING(0, "prefix", &base, "prefix", - "prepend prefix to each pathname in the archive"), - OPT_STRING('o', "output", &output, "file", - "write the archive to this file"), + OPT_STRING(0, "format", &format, N_("fmt"), N_("archive format")), + OPT_STRING(0, "prefix", &base, N_("prefix"), + N_("prepend prefix to each pathname in the archive")), + OPT_STRING('o', "output", &output, N_("file"), + N_("write the archive to this file")), OPT_BOOL(0, "worktree-attributes", &worktree_attributes, - "read .gitattributes in working directory"), - OPT__VERBOSE(&verbose, "report archived files on stderr"), - OPT__COMPR('0', &compression_level, "store only", 0), - OPT__COMPR('1', &compression_level, "compress faster", 1), + N_("read .gitattributes in working directory")), + OPT__VERBOSE(&verbose, N_("report archived files on stderr")), + OPT__COMPR('0', &compression_level, N_("store only"), 0), + OPT__COMPR('1', &compression_level, N_("compress faster"), 1), OPT__COMPR_HIDDEN('2', &compression_level, 2), OPT__COMPR_HIDDEN('3', &compression_level, 3), OPT__COMPR_HIDDEN('4', &compression_level, 4), @@ -336,15 +337,15 @@ static int parse_archive_args(int argc, const char **argv, OPT__COMPR_HIDDEN('6', &compression_level, 6), OPT__COMPR_HIDDEN('7', &compression_level, 7), OPT__COMPR_HIDDEN('8', &compression_level, 8), - OPT__COMPR('9', &compression_level, "compress better", 9), + OPT__COMPR('9', &compression_level, N_("compress better"), 9), OPT_GROUP(""), OPT_BOOL('l', "list", &list, - "list supported archive formats"), + N_("list supported archive formats")), OPT_GROUP(""), - OPT_STRING(0, "remote", &remote, "repo", - "retrieve the archive from remote repository <repo>"), - OPT_STRING(0, "exec", &exec, "cmd", - "path to the remote git-upload-archive command"), + OPT_STRING(0, "remote", &remote, N_("repo"), + N_("retrieve the archive from remote repository <repo>")), + OPT_STRING(0, "exec", &exec, N_("command"), + N_("path to the remote git-upload-archive command")), OPT_END() }; diff --git a/argv-array.c b/argv-array.c index 0b5f8898a..9e960d549 100644 --- a/argv-array.c +++ b/argv-array.c @@ -49,13 +49,42 @@ void argv_array_pushl(struct argv_array *array, ...) va_end(ap); } +void argv_array_pop(struct argv_array *array) +{ + if (!array->argc) + return; + free((char *)array->argv[array->argc - 1]); + array->argv[array->argc - 1] = NULL; + array->argc--; +} + void argv_array_clear(struct argv_array *array) { if (array->argv != empty_argv) { int i; for (i = 0; i < array->argc; i++) - free((char **)array->argv[i]); + free((char *)array->argv[i]); free(array->argv); } argv_array_init(array); } + +const char **argv_array_detach(struct argv_array *array, int *argc) +{ + const char **argv = + array->argv == empty_argv || array->argc == 0 ? NULL : array->argv; + if (argc) + *argc = array->argc; + argv_array_init(array); + return argv; +} + +void argv_array_free_detached(const char **argv) +{ + if (argv) { + int i; + for (i = 0; argv[i]; i++) + free((char **)argv[i]); + free(argv); + } +} diff --git a/argv-array.h b/argv-array.h index b93a69c36..40248d424 100644 --- a/argv-array.h +++ b/argv-array.h @@ -16,6 +16,9 @@ void argv_array_push(struct argv_array *, const char *); __attribute__((format (printf,2,3))) void argv_array_pushf(struct argv_array *, const char *fmt, ...); void argv_array_pushl(struct argv_array *, ...); +void argv_array_pop(struct argv_array *); void argv_array_clear(struct argv_array *); +const char **argv_array_detach(struct argv_array *array, int *argc); +void argv_array_free_detached(const char **argv); #endif /* ARGV_ARRAY_H */ @@ -115,6 +115,13 @@ struct attr_state { const char *setto; }; +struct pattern { + const char *pattern; + int patternlen; + int nowildcardlen; + int flags; /* EXC_FLAG_* */ +}; + /* * One rule, as from a .gitattributes file. * @@ -131,7 +138,7 @@ struct attr_state { */ struct match_attr { union { - char *pattern; + struct pattern pat; struct git_attr *attr; } u; char is_macro; @@ -241,9 +248,16 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, if (is_macro) res->u.attr = git_attr_internal(name, namelen); else { - res->u.pattern = (char *)&(res->state[num_attr]); - memcpy(res->u.pattern, name, namelen); - res->u.pattern[namelen] = 0; + char *p = (char *)&(res->state[num_attr]); + memcpy(p, name, namelen); + res->u.pat.pattern = p; + parse_exclude_pattern(&res->u.pat.pattern, + &res->u.pat.patternlen, + &res->u.pat.flags, + &res->u.pat.nowildcardlen); + if (res->u.pat.flags & EXC_FLAG_NEGATIVE) + die(_("Negative patterns are forbidden in git attributes\n" + "Use '\\!' for literal leading exclamation.")); } res->is_macro = is_macro; res->num_attr = num_attr; @@ -277,6 +291,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, static struct attr_stack { struct attr_stack *prev; char *origin; + size_t originlen; unsigned num_matches; unsigned alloc; struct match_attr **attrs; @@ -306,7 +321,7 @@ static void free_attr_elem(struct attr_stack *e) } static const char *builtin_attr[] = { - "[attr]binary -diff -text", + "[attr]binary -diff -merge -text", NULL, }; @@ -352,8 +367,11 @@ static struct attr_stack *read_attr_from_file(const char *path, int macro_ok) char buf[2048]; int lineno = 0; - if (!fp) + if (!fp) { + if (errno != ENOENT && errno != ENOTDIR) + warn_on_inaccessible(path); return NULL; + } res = xcalloc(1, sizeof(*res)); while (fgets(buf, sizeof(buf), fp)) handle_attr_line(res, buf, path, ++lineno, macro_ok); @@ -497,6 +515,7 @@ static int git_attr_system(void) static void bootstrap_attr_stack(void) { struct attr_stack *elem; + char *xdg_attributes_file; if (attr_stack) return; @@ -515,6 +534,10 @@ static void bootstrap_attr_stack(void) } } + if (!git_attributes_file) { + home_config_paths(NULL, &xdg_attributes_file, "attributes"); + git_attributes_file = xdg_attributes_file; + } if (git_attributes_file) { elem = read_attr_from_file(git_attributes_file, 1); if (elem) { @@ -527,6 +550,7 @@ static void bootstrap_attr_stack(void) if (!is_bare_repository() || direction == GIT_ATTR_INDEX) { elem = read_attr(GITATTRIBUTES_FILE, 1); elem->origin = xstrdup(""); + elem->originlen = 0; elem->prev = attr_stack; attr_stack = elem; debug_push(elem); @@ -540,17 +564,24 @@ static void bootstrap_attr_stack(void) attr_stack = elem; } +static const char *find_basename(const char *path) +{ + const char *cp, *last_slash = NULL; + + for (cp = path; *cp; cp++) { + if (*cp == '/' && cp[1]) + last_slash = cp; + } + return last_slash ? last_slash + 1 : path; +} + static void prepare_attr_stack(const char *path) { struct attr_stack *elem, *info; int dirlen, len; const char *cp; - cp = strrchr(path, '/'); - if (!cp) - dirlen = 0; - else - dirlen = cp - path; + dirlen = find_basename(path) - path; /* * At the bottom of the attribute stack is the built-in @@ -620,7 +651,7 @@ static void prepare_attr_stack(const char *path) strbuf_addstr(&pathbuf, GITATTRIBUTES_FILE); elem = read_attr(pathbuf.buf, 0); strbuf_setlen(&pathbuf, cp - path); - elem->origin = strbuf_detach(&pathbuf, NULL); + elem->origin = strbuf_detach(&pathbuf, &elem->originlen); elem->prev = attr_stack; attr_stack = elem; debug_push(elem); @@ -637,28 +668,26 @@ static void prepare_attr_stack(const char *path) } static int path_matches(const char *pathname, int pathlen, - const char *pattern, + const char *basename, + const struct pattern *pat, const char *base, int baselen) { - if (!strchr(pattern, '/')) { - /* match basename */ - const char *basename = strrchr(pathname, '/'); - basename = basename ? basename + 1 : pathname; - return (fnmatch_icase(pattern, basename, 0) == 0); - } - /* - * match with FNM_PATHNAME; the pattern has base implicitly - * in front of it. - */ - if (*pattern == '/') - pattern++; - if (pathlen < baselen || - (baselen && pathname[baselen] != '/') || - strncmp(pathname, base, baselen)) + const char *pattern = pat->pattern; + int prefix = pat->nowildcardlen; + + if ((pat->flags & EXC_FLAG_MUSTBEDIR) && + ((!pathlen) || (pathname[pathlen-1] != '/'))) return 0; - if (baselen != 0) - baselen++; - return fnmatch_icase(pattern, pathname + baselen, FNM_PATHNAME) == 0; + + if (pat->flags & EXC_FLAG_NODIR) { + return match_basename(basename, + pathlen - (basename - pathname), + pattern, prefix, + pat->patternlen, pat->flags); + } + return match_pathname(pathname, pathlen, + base, baselen, + pattern, prefix, pat->patternlen, pat->flags); } static int macroexpand_one(int attr_nr, int rem); @@ -685,7 +714,8 @@ static int fill_one(const char *what, struct match_attr *a, int rem) return rem; } -static int fill(const char *path, int pathlen, struct attr_stack *stk, int rem) +static int fill(const char *path, int pathlen, const char *basename, + struct attr_stack *stk, int rem) { int i; const char *base = stk->origin ? stk->origin : ""; @@ -694,8 +724,8 @@ static int fill(const char *path, int pathlen, struct attr_stack *stk, int rem) struct match_attr *a = stk->attrs[i]; if (a->is_macro) continue; - if (path_matches(path, pathlen, - a->u.pattern, base, strlen(base))) + if (path_matches(path, pathlen, basename, + &a->u.pat, base, stk->originlen)) rem = fill_one("fill", a, rem); } return rem; @@ -733,15 +763,17 @@ static void collect_all_attrs(const char *path) { struct attr_stack *stk; int i, pathlen, rem; + const char *basename; prepare_attr_stack(path); for (i = 0; i < attr_nr; i++) check_all_attr[i].value = ATTR__UNKNOWN; + basename = find_basename(path); pathlen = strlen(path); rem = attr_nr; for (stk = attr_stack; 0 < rem && stk; stk = stk->prev) - rem = fill(path, pathlen, stk, rem); + rem = fill(path, pathlen, basename, stk, rem); } int git_check_attr(const char *path, int num, struct git_attr_check *check) @@ -833,7 +833,7 @@ static int check_ancestors(const char *prefix) */ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout) { - char *filename = xstrdup(git_path("BISECT_ANCESTORS_OK")); + char *filename = git_pathdup("BISECT_ANCESTORS_OK"); struct stat st; int fd; @@ -956,3 +956,41 @@ int bisect_next_all(const char *prefix, int no_checkout) return bisect_checkout(bisect_rev_hex, no_checkout); } +static inline int log2i(int n) +{ + int log2 = 0; + + for (; n > 1; n >>= 1) + log2++; + + return log2; +} + +static inline int exp2i(int n) +{ + return 1 << n; +} + +/* + * Estimate the number of bisect steps left (after the current step) + * + * For any x between 0 included and 2^n excluded, the probability for + * n - 1 steps left looks like: + * + * P(2^n + x) == (2^n - x) / (2^n + x) + * + * and P(2^n + x) < 0.5 means 2^n < 3x + */ +int estimate_bisect_steps(int all) +{ + int n, x, e; + + if (all < 3) + return 0; + + n = log2i(all); + e = exp2i(n); + x = all - e; + + return (e < 3 * x) ? n : n - 1; +} @@ -11,10 +11,6 @@ extern struct commit_list *filter_skipped(struct commit_list *list, int *count, int *skipped_first); -extern void print_commit_list(struct commit_list *list, - const char *format_cur, - const char *format_last); - #define BISECT_SHOW_ALL (1<<0) #define REV_LIST_QUIET (1<<1) @@ -74,25 +74,33 @@ void install_branch_config(int flag, const char *local, const char *origin, cons strbuf_addf(&key, "branch.%s.rebase", local); git_config_set(key.buf, "true"); } + strbuf_release(&key); if (flag & BRANCH_CONFIG_VERBOSE) { - strbuf_reset(&key); - - strbuf_addstr(&key, origin ? "remote" : "local"); - - /* Are we tracking a proper "branch"? */ - if (remote_is_branch) { - strbuf_addf(&key, " branch %s", shortname); - if (origin) - strbuf_addf(&key, " from %s", origin); - } + if (remote_is_branch && origin) + printf(rebasing ? + "Branch %s set up to track remote branch %s from %s by rebasing.\n" : + "Branch %s set up to track remote branch %s from %s.\n", + local, shortname, origin); + else if (remote_is_branch && !origin) + printf(rebasing ? + "Branch %s set up to track local branch %s by rebasing.\n" : + "Branch %s set up to track local branch %s.\n", + local, shortname); + else if (!remote_is_branch && origin) + printf(rebasing ? + "Branch %s set up to track remote ref %s by rebasing.\n" : + "Branch %s set up to track remote ref %s.\n", + local, remote); + else if (!remote_is_branch && !origin) + printf(rebasing ? + "Branch %s set up to track local ref %s by rebasing.\n" : + "Branch %s set up to track local ref %s.\n", + local, remote); else - strbuf_addf(&key, " ref %s", remote); - printf("Branch %s set up to track %s%s.\n", - local, key.buf, - rebasing ? " by rebasing" : ""); + die("BUG: impossible combination of %d and %p", + remote_is_branch, origin); } - strbuf_release(&key); } /* @@ -9,7 +9,6 @@ #define DEFAULT_MERGE_LOG_LEN 20 -extern const char git_version_string[]; extern const char git_usage_string[]; extern const char git_more_info_string[]; @@ -22,7 +21,6 @@ struct fmt_merge_msg_opts { extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out, struct fmt_merge_msg_opts *); -extern void commit_notes(struct notes_tree *t, const char *msg); struct notes_rewrite_cfg { struct notes_tree **trees; @@ -34,16 +32,11 @@ struct notes_rewrite_cfg { int mode_from_env; }; -combine_notes_fn parse_combine_notes_fn(const char *v); struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd); int copy_note_for_rewrite(struct notes_rewrite_cfg *c, const unsigned char *from_obj, const unsigned char *to_obj); void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c); -extern int check_pager_config(const char *cmd); -struct diff_options; -extern void setup_diff_pager(struct diff_options *); - extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size); extern int cmd_add(int argc, const char **argv, const char *prefix); @@ -68,6 +61,7 @@ extern int cmd_commit(int argc, const char **argv, const char *prefix); extern int cmd_commit_tree(int argc, const char **argv, const char *prefix); extern int cmd_config(int argc, const char **argv, const char *prefix); extern int cmd_count_objects(int argc, const char **argv, const char *prefix); +extern int cmd_credential(int argc, const char **argv, const char *prefix); extern int cmd_describe(int argc, const char **argv, const char *prefix); 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); diff --git a/builtin/add.c b/builtin/add.c index 89dce56a2..e664100c7 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -16,7 +16,7 @@ #include "bulk-checkin.h" static const char * const builtin_add_usage[] = { - "git add [options] [--] <filepattern>...", + N_("git add [options] [--] <filepattern>..."), NULL }; static int patch_interactive, add_interactive, edit_interactive; @@ -260,7 +260,7 @@ int interactive_add(int argc, const char **argv, const char *prefix, int patch) static int edit_patch(int argc, const char **argv, const char *prefix) { - char *file = xstrdup(git_path("ADD_EDIT.patch")); + char *file = git_pathdup("ADD_EDIT.patch"); const char *apply_argv[] = { "apply", "--recount", "--cached", NULL, NULL }; struct child_process child; @@ -303,6 +303,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) die (_("Could not apply '%s'"), file); unlink(file); + free(file); return 0; } @@ -315,19 +316,19 @@ static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0; static int ignore_add_errors, addremove, intent_to_add, ignore_missing = 0; static struct option builtin_add_options[] = { - OPT__DRY_RUN(&show_only, "dry run"), - OPT__VERBOSE(&verbose, "be verbose"), + OPT__DRY_RUN(&show_only, N_("dry run")), + OPT__VERBOSE(&verbose, N_("be verbose")), OPT_GROUP(""), - OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"), - OPT_BOOLEAN('p', "patch", &patch_interactive, "select hunks interactively"), - OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"), - OPT__FORCE(&ignored_too, "allow adding otherwise ignored files"), - OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"), - OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"), - OPT_BOOLEAN('A', "all", &addremove, "add changes from all tracked and untracked files"), - OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"), - OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"), - OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, "check if - even missing - files are ignored in dry run"), + OPT_BOOLEAN('i', "interactive", &add_interactive, N_("interactive picking")), + OPT_BOOLEAN('p', "patch", &patch_interactive, N_("select hunks interactively")), + OPT_BOOLEAN('e', "edit", &edit_interactive, N_("edit current diff and apply")), + OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")), + OPT_BOOLEAN('u', "update", &take_worktree_changes, N_("update tracked files")), + OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")), + OPT_BOOLEAN('A', "all", &addremove, N_("add changes from all tracked and untracked files")), + OPT_BOOLEAN( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")), + OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")), + OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")), OPT_END(), }; diff --git a/builtin/apply.c b/builtin/apply.c index f8202e3b6..6c11e8bc7 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -16,6 +16,9 @@ #include "dir.h" #include "diff.h" #include "parse-options.h" +#include "xdiff-interface.h" +#include "ll-merge.h" +#include "rerere.h" /* * --check turns on checking that the working tree matches the @@ -46,6 +49,7 @@ static int apply_with_reject; static int apply_verbosely; static int allow_overlap; static int no_add; +static int threeway; static const char *fake_ancestor; static int line_termination = '\n'; static unsigned int p_context = UINT_MAX; @@ -192,12 +196,17 @@ struct patch { unsigned int is_copy:1; unsigned int is_rename:1; unsigned int recount:1; + unsigned int conflicted_threeway:1; + unsigned int direct_to_threeway:1; struct fragment *fragments; char *result; size_t resultsize; char old_sha1_prefix[41]; char new_sha1_prefix[41]; struct patch *next; + + /* three-way fallback result */ + unsigned char threeway_stage[3][20]; }; static void free_fragment_list(struct fragment *list) @@ -370,8 +379,8 @@ static void prepare_image(struct image *image, char *buf, size_t len, static void clear_image(struct image *image) { free(image->buf); - image->buf = NULL; - image->len = 0; + free(image->line_allocated); + memset(image, 0, sizeof(*image)); } /* fmt must contain _one_ %s and no other substitution */ @@ -2965,20 +2974,17 @@ static int apply_fragments(struct image *img, struct patch *patch) return 0; } -static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf) +static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsigned mode) { - if (!ce) - return 0; - - if (S_ISGITLINK(ce->ce_mode)) { + if (S_ISGITLINK(mode)) { strbuf_grow(buf, 100); - strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1)); + strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(sha1)); } else { enum object_type type; unsigned long sz; char *result; - result = read_sha1_file(ce->sha1, &type, &sz); + result = read_sha1_file(sha1, &type, &sz); if (!result) return -1; /* XXX read_sha1_file NUL-terminates */ @@ -2987,6 +2993,13 @@ static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf) return 0; } +static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf) +{ + if (!ce) + return 0; + return read_blob_object(buf, ce->sha1, ce->ce_mode); +} + static struct patch *in_fn_table(const char *name) { struct string_list_item *item; @@ -3005,9 +3018,15 @@ static struct patch *in_fn_table(const char *name) * item->util in the filename table records the status of the path. * Usually it points at a patch (whose result records the contents * of it after applying it), but it could be PATH_WAS_DELETED for a - * path that a previously applied patch has already removed. + * path that a previously applied patch has already removed, or + * PATH_TO_BE_DELETED for a path that a later patch would remove. + * + * The latter is needed to deal with a case where two paths A and B + * are swapped by first renaming A to B and then renaming B to A; + * moving A to B should not be prevented due to presense of B as we + * will remove it in a later patch. */ - #define PATH_TO_BE_DELETED ((struct patch *) -2) +#define PATH_TO_BE_DELETED ((struct patch *) -2) #define PATH_WAS_DELETED ((struct patch *) -1) static int to_be_deleted(struct patch *patch) @@ -3059,127 +3078,324 @@ static void prepare_fn_table(struct patch *patch) } } -static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce) +static int checkout_target(struct cache_entry *ce, struct stat *st) +{ + struct checkout costate; + + memset(&costate, 0, sizeof(costate)); + costate.base_dir = ""; + costate.refresh_cache = 1; + if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st)) + return error(_("cannot checkout %s"), ce->name); + return 0; +} + +static struct patch *previous_patch(struct patch *patch, int *gone) +{ + struct patch *previous; + + *gone = 0; + if (patch->is_copy || patch->is_rename) + return NULL; /* "git" patches do not depend on the order */ + + previous = in_fn_table(patch->old_name); + if (!previous) + return NULL; + + if (to_be_deleted(previous)) + return NULL; /* the deletion hasn't happened yet */ + + if (was_deleted(previous)) + *gone = 1; + + return previous; +} + +static int verify_index_match(struct cache_entry *ce, struct stat *st) +{ + if (S_ISGITLINK(ce->ce_mode)) { + if (!S_ISDIR(st->st_mode)) + return -1; + return 0; + } + return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE); +} + +#define SUBMODULE_PATCH_WITHOUT_INDEX 1 + +static int load_patch_target(struct strbuf *buf, + struct cache_entry *ce, + struct stat *st, + const char *name, + unsigned expected_mode) +{ + if (cached) { + if (read_file_or_gitlink(ce, buf)) + return error(_("read of %s failed"), name); + } else if (name) { + if (S_ISGITLINK(expected_mode)) { + if (ce) + return read_file_or_gitlink(ce, buf); + else + return SUBMODULE_PATCH_WITHOUT_INDEX; + } else { + if (read_old_data(st, name, buf)) + return error(_("read of %s failed"), name); + } + } + return 0; +} + +/* + * We are about to apply "patch"; populate the "image" with the + * current version we have, from the working tree or from the index, + * depending on the situation e.g. --cached/--index. If we are + * applying a non-git patch that incrementally updates the tree, + * we read from the result of a previous diff. + */ +static int load_preimage(struct image *image, + struct patch *patch, struct stat *st, struct cache_entry *ce) { struct strbuf buf = STRBUF_INIT; - struct image image; size_t len; char *img; - struct patch *tpatch; + struct patch *previous; + int status; - if (!(patch->is_copy || patch->is_rename) && - (tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) { - if (was_deleted(tpatch)) { - return error(_("patch %s has been renamed/deleted"), - patch->old_name); - } + previous = previous_patch(patch, &status); + if (status) + return error(_("path %s has been renamed/deleted"), + patch->old_name); + if (previous) { /* We have a patched copy in memory; use that. */ - strbuf_add(&buf, tpatch->result, tpatch->resultsize); - } else if (cached) { - if (read_file_or_gitlink(ce, &buf)) + strbuf_add(&buf, previous->result, previous->resultsize); + } else { + status = load_patch_target(&buf, ce, st, + patch->old_name, patch->old_mode); + if (status < 0) + return status; + else if (status == SUBMODULE_PATCH_WITHOUT_INDEX) { + /* + * There is no way to apply subproject + * patch without looking at the index. + * NEEDSWORK: shouldn't this be flagged + * as an error??? + */ + free_fragment_list(patch->fragments); + patch->fragments = NULL; + } else if (status) { return error(_("read of %s failed"), patch->old_name); - } else if (patch->old_name) { - if (S_ISGITLINK(patch->old_mode)) { - if (ce) { - read_file_or_gitlink(ce, &buf); - } else { - /* - * There is no way to apply subproject - * patch without looking at the index. - * NEEDSWORK: shouldn't this be flagged - * as an error??? - */ - free_fragment_list(patch->fragments); - patch->fragments = NULL; - } - } else { - if (read_old_data(st, patch->old_name, &buf)) - return error(_("read of %s failed"), patch->old_name); } } img = strbuf_detach(&buf, &len); - prepare_image(&image, img, len, !patch->is_binary); + prepare_image(image, img, len, !patch->is_binary); + return 0; +} - if (apply_fragments(&image, patch) < 0) - return -1; /* note with --reject this succeeds. */ - patch->result = image.buf; - patch->resultsize = image.len; - add_to_fn_table(patch); - free(image.line_allocated); +static int three_way_merge(struct image *image, + char *path, + const unsigned char *base, + const unsigned char *ours, + const unsigned char *theirs) +{ + mmfile_t base_file, our_file, their_file; + mmbuffer_t result = { NULL }; + int status; - if (0 < patch->is_delete && patch->resultsize) - return error(_("removal patch leaves file contents")); + read_mmblob(&base_file, base); + read_mmblob(&our_file, ours); + read_mmblob(&their_file, theirs); + status = ll_merge(&result, path, + &base_file, "base", + &our_file, "ours", + &their_file, "theirs", NULL); + free(base_file.ptr); + free(our_file.ptr); + free(their_file.ptr); + if (status < 0 || !result.ptr) { + free(result.ptr); + return -1; + } + clear_image(image); + image->buf = result.ptr; + image->len = result.size; + return status; +} + +/* + * When directly falling back to add/add three-way merge, we read from + * the current contents of the new_name. In no cases other than that + * this function will be called. + */ +static int load_current(struct image *image, struct patch *patch) +{ + struct strbuf buf = STRBUF_INIT; + int status, pos; + size_t len; + char *img; + struct stat st; + struct cache_entry *ce; + char *name = patch->new_name; + unsigned mode = patch->new_mode; + + if (!patch->is_new) + die("BUG: patch to %s is not a creation", patch->old_name); + + pos = cache_name_pos(name, strlen(name)); + if (pos < 0) + return error(_("%s: does not exist in index"), name); + ce = active_cache[pos]; + if (lstat(name, &st)) { + if (errno != ENOENT) + return error(_("%s: %s"), name, strerror(errno)); + if (checkout_target(ce, &st)) + return -1; + } + if (verify_index_match(ce, &st)) + return error(_("%s: does not match index"), name); + + status = load_patch_target(&buf, ce, &st, name, mode); + if (status < 0) + return status; + else if (status) + return -1; + img = strbuf_detach(&buf, &len); + prepare_image(image, img, len, !patch->is_binary); return 0; } -static int check_to_create_blob(const char *new_name, int ok_if_exists) +static int try_threeway(struct image *image, struct patch *patch, + struct stat *st, struct cache_entry *ce) { - struct stat nst; - if (!lstat(new_name, &nst)) { - if (S_ISDIR(nst.st_mode) || ok_if_exists) - return 0; - /* - * A leading component of new_name might be a symlink - * that is going to be removed with this patch, but - * still pointing at somewhere that has the path. - * In such a case, path "new_name" does not exist as - * far as git is concerned. - */ - if (has_symlink_leading_path(new_name, strlen(new_name))) - return 0; + unsigned char pre_sha1[20], post_sha1[20], our_sha1[20]; + struct strbuf buf = STRBUF_INIT; + size_t len; + int status; + char *img; + struct image tmp_image; + + /* No point falling back to 3-way merge in these cases */ + if (patch->is_delete || + S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode)) + return -1; - return error(_("%s: already exists in working directory"), new_name); + /* Preimage the patch was prepared for */ + if (patch->is_new) + write_sha1_file("", 0, blob_type, pre_sha1); + else if (get_sha1(patch->old_sha1_prefix, pre_sha1) || + read_blob_object(&buf, pre_sha1, patch->old_mode)) + return error("repository lacks the necessary blob to fall back on 3-way merge."); + + fprintf(stderr, "Falling back to three-way merge...\n"); + + img = strbuf_detach(&buf, &len); + prepare_image(&tmp_image, img, len, 1); + /* Apply the patch to get the post image */ + if (apply_fragments(&tmp_image, patch) < 0) { + clear_image(&tmp_image); + return -1; + } + /* post_sha1[] is theirs */ + write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_sha1); + clear_image(&tmp_image); + + /* our_sha1[] is ours */ + if (patch->is_new) { + if (load_current(&tmp_image, patch)) + return error("cannot read the current contents of '%s'", + patch->new_name); + } else { + if (load_preimage(&tmp_image, patch, st, ce)) + return error("cannot read the current contents of '%s'", + patch->old_name); + } + write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_sha1); + clear_image(&tmp_image); + + /* in-core three-way merge between post and our using pre as base */ + status = three_way_merge(image, patch->new_name, + pre_sha1, our_sha1, post_sha1); + if (status < 0) { + fprintf(stderr, "Failed to fall back on three-way merge...\n"); + return status; + } + + if (status) { + patch->conflicted_threeway = 1; + if (patch->is_new) + hashclr(patch->threeway_stage[0]); + else + hashcpy(patch->threeway_stage[0], pre_sha1); + hashcpy(patch->threeway_stage[1], our_sha1); + hashcpy(patch->threeway_stage[2], post_sha1); + fprintf(stderr, "Applied patch to '%s' with conflicts.\n", patch->new_name); + } else { + fprintf(stderr, "Applied patch to '%s' cleanly.\n", patch->new_name); } - else if ((errno != ENOENT) && (errno != ENOTDIR)) - return error("%s: %s", new_name, strerror(errno)); return 0; } -static int verify_index_match(struct cache_entry *ce, struct stat *st) +static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce) { - if (S_ISGITLINK(ce->ce_mode)) { - if (!S_ISDIR(st->st_mode)) + struct image image; + + if (load_preimage(&image, patch, st, ce) < 0) + return -1; + + if (patch->direct_to_threeway || + apply_fragments(&image, patch) < 0) { + /* Note: with --reject, apply_fragments() returns 0 */ + if (!threeway || try_threeway(&image, patch, st, ce) < 0) return -1; - return 0; } - return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE); + patch->result = image.buf; + patch->resultsize = image.len; + add_to_fn_table(patch); + free(image.line_allocated); + + if (0 < patch->is_delete && patch->resultsize) + return error(_("removal patch leaves file contents")); + + return 0; } +/* + * If "patch" that we are looking at modifies or deletes what we have, + * we would want it not to lose any local modification we have, either + * in the working tree or in the index. + * + * This also decides if a non-git patch is a creation patch or a + * modification to an existing empty file. We do not check the state + * of the current tree for a creation patch in this function; the caller + * check_patch() separately makes sure (and errors out otherwise) that + * the path the patch creates does not exist in the current tree. + */ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st) { const char *old_name = patch->old_name; - struct patch *tpatch = NULL; - int stat_ret = 0; + struct patch *previous = NULL; + int stat_ret = 0, status; unsigned st_mode = 0; - /* - * Make sure that we do not have local modifications from the - * index when we are looking at the index. Also make sure - * we have the preimage file to be patched in the work tree, - * unless --cached, which tells git to apply only in the index. - */ if (!old_name) return 0; assert(patch->is_new <= 0); + previous = previous_patch(patch, &status); - if (!(patch->is_copy || patch->is_rename) && - (tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) { - if (was_deleted(tpatch)) - return error(_("%s: has been deleted/renamed"), old_name); - st_mode = tpatch->new_mode; + if (status) + return error(_("path %s has been renamed/deleted"), old_name); + if (previous) { + st_mode = previous->new_mode; } else if (!cached) { stat_ret = lstat(old_name, st); if (stat_ret && errno != ENOENT) return error(_("%s: %s"), old_name, strerror(errno)); } - if (to_be_deleted(tpatch)) - tpatch = NULL; - - if (check_index && !tpatch) { + if (check_index && !previous) { int pos = cache_name_pos(old_name, strlen(old_name)); if (pos < 0) { if (patch->is_new < 0) @@ -3188,13 +3404,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s } *ce = active_cache[pos]; if (stat_ret < 0) { - struct checkout costate; - /* checkout */ - memset(&costate, 0, sizeof(costate)); - costate.base_dir = ""; - costate.refresh_cache = 1; - if (checkout_entry(*ce, &costate, NULL) || - lstat(old_name, st)) + if (checkout_target(*ce, st)) return -1; } if (!cached && verify_index_match(*ce, st)) @@ -3207,7 +3417,7 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s return error(_("%s: %s"), old_name, strerror(errno)); } - if (!cached && !tpatch) + if (!cached && !previous) st_mode = ce_mode_from_stat(*ce, st->st_mode); if (patch->is_new < 0) @@ -3231,6 +3441,41 @@ static int check_preimage(struct patch *patch, struct cache_entry **ce, struct s return 0; } + +#define EXISTS_IN_INDEX 1 +#define EXISTS_IN_WORKTREE 2 + +static int check_to_create(const char *new_name, int ok_if_exists) +{ + struct stat nst; + + if (check_index && + cache_name_pos(new_name, strlen(new_name)) >= 0 && + !ok_if_exists) + return EXISTS_IN_INDEX; + if (cached) + return 0; + + if (!lstat(new_name, &nst)) { + if (S_ISDIR(nst.st_mode) || ok_if_exists) + return 0; + /* + * A leading component of new_name might be a symlink + * that is going to be removed with this patch, but + * still pointing at somewhere that has the path. + * In such a case, path "new_name" does not exist as + * far as git is concerned. + */ + if (has_symlink_leading_path(new_name, strlen(new_name))) + return 0; + + return EXISTS_IN_WORKTREE; + } else if ((errno != ENOENT) && (errno != ENOTDIR)) { + return error("%s: %s", new_name, strerror(errno)); + } + return 0; +} + /* * Check and apply the patch in-core; leave the result in patch->result * for the caller to write it out to the final destination. @@ -3253,31 +3498,45 @@ static int check_patch(struct patch *patch) return status; old_name = patch->old_name; + /* + * A type-change diff is always split into a patch to delete + * old, immediately followed by a patch to create new (see + * diff.c::run_diff()); in such a case it is Ok that the entry + * to be deleted by the previous patch is still in the working + * tree and in the index. + * + * A patch to swap-rename between A and B would first rename A + * to B and then rename B to A. While applying the first one, + * the presense of B should not stop A from getting renamed to + * B; ask to_be_deleted() about the later rename. Removal of + * B and rename from A to B is handled the same way by asking + * was_deleted(). + */ if ((tpatch = in_fn_table(new_name)) && - (was_deleted(tpatch) || to_be_deleted(tpatch))) - /* - * A type-change diff is always split into a patch to - * delete old, immediately followed by a patch to - * create new (see diff.c::run_diff()); in such a case - * it is Ok that the entry to be deleted by the - * previous patch is still in the working tree and in - * the index. - */ + (was_deleted(tpatch) || to_be_deleted(tpatch))) ok_if_exists = 1; else ok_if_exists = 0; if (new_name && ((0 < patch->is_new) | (0 < patch->is_rename) | patch->is_copy)) { - if (check_index && - cache_name_pos(new_name, strlen(new_name)) >= 0 && - !ok_if_exists) + int err = check_to_create(new_name, ok_if_exists); + + if (err && threeway) { + patch->direct_to_threeway = 1; + } else switch (err) { + case 0: + break; /* happy */ + case EXISTS_IN_INDEX: return error(_("%s: already exists in index"), new_name); - if (!cached) { - int err = check_to_create_blob(new_name, ok_if_exists); - if (err) - return err; + break; + case EXISTS_IN_WORKTREE: + return error(_("%s: already exists in working directory"), + new_name); + default: + return err; } + if (!patch->new_mode) { if (0 < patch->is_new) patch->new_mode = S_IFREG | 0644; @@ -3358,7 +3617,7 @@ static void build_fake_ancestor(struct patch *list, const char *filename) name = patch->old_name ? patch->old_name : patch->new_name; if (0 < patch->is_new) continue; - else if (get_sha1(patch->old_sha1_prefix, sha1)) + else if (get_sha1_blob(patch->old_sha1_prefix, sha1)) /* git diff has no index line for mode/type changes */ if (!patch->lines_added && !patch->lines_deleted) { if (get_current_sha1(patch->old_name, sha1)) @@ -3538,7 +3797,8 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned ce = xcalloc(1, ce_size); memcpy(ce->name, path, namelen); ce->ce_mode = create_ce_mode(mode); - ce->ce_flags = namelen; + ce->ce_flags = create_ce_flags(0); + ce->ce_namelen = namelen; if (S_ISGITLINK(mode)) { const char *s = buf; @@ -3640,6 +3900,33 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned die_errno(_("unable to write file '%s' mode %o"), path, mode); } +static void add_conflicted_stages_file(struct patch *patch) +{ + int stage, namelen; + unsigned ce_size, mode; + struct cache_entry *ce; + + if (!update_index) + return; + namelen = strlen(patch->new_name); + ce_size = cache_entry_size(namelen); + mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644); + + remove_file_from_cache(patch->new_name); + for (stage = 1; stage < 4; stage++) { + if (is_null_sha1(patch->threeway_stage[stage - 1])) + continue; + ce = xcalloc(1, ce_size); + memcpy(ce->name, patch->new_name, namelen); + ce->ce_mode = create_ce_mode(mode); + ce->ce_flags = create_ce_flags(stage); + ce->ce_namelen = namelen; + hashcpy(ce->sha1, patch->threeway_stage[stage - 1]); + if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) + die(_("unable to add cache entry for %s"), patch->new_name); + } +} + static void create_file(struct patch *patch) { char *path = patch->new_name; @@ -3650,7 +3937,11 @@ static void create_file(struct patch *patch) if (!mode) mode = S_IFREG | 0644; create_one_file(path, mode, buf, size); - add_index_file(path, mode, buf, size); + + if (patch->conflicted_threeway) + add_conflicted_stages_file(patch); + else + add_index_file(path, mode, buf, size); } /* phase zero is to remove, phase one is to create */ @@ -3752,6 +4043,7 @@ static int write_out_results(struct patch *list) int phase; int errs = 0; struct patch *l; + struct string_list cpath = STRING_LIST_INIT_DUP; for (phase = 0; phase < 2; phase++) { l = list; @@ -3760,12 +4052,30 @@ static int write_out_results(struct patch *list) errs = 1; else { write_out_one_result(l, phase); - if (phase == 1 && write_out_one_reject(l)) - errs = 1; + if (phase == 1) { + if (write_out_one_reject(l)) + errs = 1; + if (l->conflicted_threeway) { + string_list_append(&cpath, l->new_name); + errs = 1; + } + } } l = l->next; } } + + if (cpath.nr) { + struct string_list_item *item; + + sort_string_list(&cpath); + for_each_string_list_item(item, &cpath) + fprintf(stderr, "U %s\n", item->string); + string_list_clear(&cpath, 0); + + rerere(0); + } + return errs; } @@ -3888,8 +4198,12 @@ static int apply_patch(int fd, const char *filename, int options) !apply_with_reject) exit(1); - if (apply && write_out_results(list)) - exit(1); + if (apply && write_out_results(list)) { + if (apply_with_reject) + exit(1); + /* with --3way, we still need to write the index out */ + return 1; + } if (fake_ancestor) build_fake_ancestor(list, fake_ancestor); @@ -4011,7 +4325,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix_) OPT_NOOP_NOARG(0, "allow-binary-replacement"), OPT_NOOP_NOARG(0, "binary"), OPT_BOOLEAN(0, "numstat", &numstat, - N_("shows number of added and deleted lines in decimal notation")), + N_("show number of added and deleted lines in decimal notation")), OPT_BOOLEAN(0, "summary", &summary, N_("instead of applying the patch, output a summary for the input")), OPT_BOOLEAN(0, "check", &check, @@ -4022,6 +4336,8 @@ int cmd_apply(int argc, const char **argv, const char *prefix_) N_("apply a patch without touching the working tree")), OPT_BOOLEAN(0, "apply", &force_apply, N_("also apply the patch (use with --stat/--summary/--check)")), + OPT_BOOL('3', "3way", &threeway, + N_( "attempt three-way merge if a patch does not apply")), OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor, N_("build a temporary index based on embedded index information")), { OPTION_CALLBACK, 'z', NULL, NULL, NULL, @@ -4070,6 +4386,15 @@ int cmd_apply(int argc, const char **argv, const char *prefix_) argc = parse_options(argc, argv, prefix, builtin_apply_options, apply_usage, 0); + if (apply_with_reject && threeway) + die("--reject and --3way cannot be used together."); + if (cached && threeway) + die("--cached and --3way cannot be used together."); + if (threeway) { + if (is_not_gitdir) + die(_("--3way outside a repository")); + check_index = 1; + } if (apply_with_reject) apply = apply_verbosely = 1; if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor)) diff --git a/builtin/archive.c b/builtin/archive.c index 931956def..9a1cfd3da 100644 --- a/builtin/archive.c +++ b/builtin/archive.c @@ -88,12 +88,12 @@ int cmd_archive(int argc, const char **argv, const char *prefix) const char *output = NULL; const char *remote = NULL; struct option local_opts[] = { - OPT_STRING('o', "output", &output, "file", - "write the archive to this file"), - OPT_STRING(0, "remote", &remote, "repo", - "retrieve the archive from remote repository <repo>"), - OPT_STRING(0, "exec", &exec, "cmd", - "path to the remote git-upload-archive command"), + OPT_STRING('o', "output", &output, N_("file"), + N_("write the archive to this file")), + OPT_STRING(0, "remote", &remote, N_("repo"), + N_("retrieve the archive from remote repository <repo>")), + OPT_STRING(0, "exec", &exec, N_("command"), + N_("path to the remote git-upload-archive command")), OPT_END() }; diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c index 8d325a517..e3884e3bb 100644 --- a/builtin/bisect--helper.c +++ b/builtin/bisect--helper.c @@ -4,7 +4,7 @@ #include "bisect.h" static const char * const git_bisect_helper_usage[] = { - "git bisect--helper --next-all [--no-checkout]", + N_("git bisect--helper --next-all [--no-checkout]"), NULL }; @@ -14,9 +14,9 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) int no_checkout = 0; struct option options[] = { OPT_BOOLEAN(0, "next-all", &next_all, - "perform 'git bisect next'"), + N_("perform 'git bisect next'")), OPT_BOOLEAN(0, "no-checkout", &no_checkout, - "update BISECT_HEAD instead of checking out the current commit"), + N_("update BISECT_HEAD instead of checking out the current commit")), OPT_END() }; diff --git a/builtin/blame.c b/builtin/blame.c index cad4111a3..cfae56990 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -22,12 +22,12 @@ #include "utf8.h" #include "userdiff.h" -static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file"; +static char blame_usage[] = N_("git blame [options] [rev-opts] [rev] [--] file"); static const char *blame_opt_usage[] = { blame_usage, "", - "[rev-opts] are documented in git-rev-list(1)", + N_("[rev-opts] are documented in git-rev-list(1)"), NULL }; @@ -1425,7 +1425,7 @@ static void get_commit_info(struct commit *commit, int detailed) { int len; - const char *subject; + const char *subject, *encoding; char *reencoded, *message; static char author_name[1024]; static char author_mail[1024]; @@ -1446,7 +1446,8 @@ static void get_commit_info(struct commit *commit, die("Cannot read commit %s", sha1_to_hex(commit->object.sha1)); } - reencoded = reencode_commit_message(commit, NULL); + encoding = get_log_output_encoding(); + reencoded = logmsg_reencode(commit, encoding); message = reencoded ? reencoded : commit->buffer; ret->author = author_name; ret->author_mail = author_mail; @@ -2069,6 +2070,55 @@ static int git_blame_config(const char *var, const char *value, void *cb) return git_default_config(var, value, cb); } +static void verify_working_tree_path(struct commit *work_tree, const char *path) +{ + struct commit_list *parents; + + for (parents = work_tree->parents; parents; parents = parents->next) { + const unsigned char *commit_sha1 = parents->item->object.sha1; + unsigned char blob_sha1[20]; + unsigned mode; + + if (!get_tree_entry(commit_sha1, path, blob_sha1, &mode) && + sha1_object_info(blob_sha1, NULL) == OBJ_BLOB) + return; + } + die("no such path '%s' in HEAD", path); +} + +static struct commit_list **append_parent(struct commit_list **tail, const unsigned char *sha1) +{ + struct commit *parent; + + parent = lookup_commit_reference(sha1); + if (!parent) + die("no such commit %s", sha1_to_hex(sha1)); + return &commit_list_insert(parent, tail)->next; +} + +static void append_merge_parents(struct commit_list **tail) +{ + int merge_head; + const char *merge_head_file = git_path("MERGE_HEAD"); + struct strbuf line = STRBUF_INIT; + + merge_head = open(merge_head_file, O_RDONLY); + if (merge_head < 0) { + if (errno == ENOENT) + return; + die("cannot open '%s' for reading", merge_head_file); + } + + while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) { + unsigned char sha1[20]; + if (line.len < 40 || get_sha1_hex(line.buf, sha1)) + die("unknown line in '%s': %s", merge_head_file, line.buf); + tail = append_parent(tail, sha1); + } + close(merge_head); + strbuf_release(&line); +} + /* * Prepare a dummy commit that represents the work tree (or staged) item. * Note that annotating work tree item never works in the reverse. @@ -2079,6 +2129,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, { struct commit *commit; struct origin *origin; + struct commit_list **parent_tail, *parent; unsigned char head_sha1[20]; struct strbuf buf = STRBUF_INIT; const char *ident; @@ -2086,20 +2137,38 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, int size, len; struct cache_entry *ce; unsigned mode; - - if (get_sha1("HEAD", head_sha1)) - die("No such ref: HEAD"); + struct strbuf msg = STRBUF_INIT; time(&now); commit = xcalloc(1, sizeof(*commit)); - commit->parents = xcalloc(1, sizeof(*commit->parents)); - commit->parents->item = lookup_commit_reference(head_sha1); commit->object.parsed = 1; commit->date = now; commit->object.type = OBJ_COMMIT; + parent_tail = &commit->parents; + + if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL)) + die("no such ref: HEAD"); + + parent_tail = append_parent(parent_tail, head_sha1); + append_merge_parents(parent_tail); + verify_working_tree_path(commit, path); origin = make_origin(commit, path); + ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0); + strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n"); + for (parent = commit->parents; parent; parent = parent->next) + strbuf_addf(&msg, "parent %s\n", + sha1_to_hex(parent->item->object.sha1)); + strbuf_addf(&msg, + "author %s\n" + "committer %s\n\n" + "Version of %s from %s\n", + ident, ident, path, + (!contents_from ? path : + (!strcmp(contents_from, "-") ? "standard input" : contents_from))); + commit->buffer = strbuf_detach(&msg, NULL); + if (!contents_from || strcmp("-", contents_from)) { struct stat st; const char *read_from; @@ -2136,7 +2205,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, } else { /* Reading from stdin */ - contents_from = "standard input"; mode = 0; if (strbuf_read(&buf, 0, 0) < 0) die_errno("failed to read from stdin"); @@ -2169,7 +2237,8 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, ce = xcalloc(1, size); hashcpy(ce->sha1, origin->blob_sha1); memcpy(ce->name, path, len); - ce->ce_flags = create_ce_flags(len, 0); + ce->ce_flags = create_ce_flags(0); + ce->ce_namelen = len; ce->ce_mode = create_ce_mode(mode); add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); @@ -2180,16 +2249,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, */ cache_tree_invalidate_path(active_cache_tree, path); - commit->buffer = xmalloc(400); - ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0); - snprintf(commit->buffer, 400, - "tree 0000000000000000000000000000000000000000\n" - "parent %s\n" - "author %s\n" - "committer %s\n\n" - "Version of %s from %s\n", - sha1_to_hex(head_sha1), - ident, ident, path, contents_from ? contents_from : path); return commit; } @@ -2312,27 +2371,27 @@ int cmd_blame(int argc, const char **argv, const char *prefix) static const char *revs_file = NULL; static const char *contents_from = NULL; static const struct option options[] = { - OPT_BOOLEAN(0, "incremental", &incremental, "Show blame entries as we find them, incrementally"), - OPT_BOOLEAN('b', NULL, &blank_boundary, "Show blank SHA-1 for boundary commits (Default: off)"), - OPT_BOOLEAN(0, "root", &show_root, "Do not treat root commits as boundaries (Default: off)"), - OPT_BOOLEAN(0, "show-stats", &show_stats, "Show work cost statistics"), - OPT_BIT(0, "score-debug", &output_option, "Show output score for blame entries", OUTPUT_SHOW_SCORE), - OPT_BIT('f', "show-name", &output_option, "Show original filename (Default: auto)", OUTPUT_SHOW_NAME), - OPT_BIT('n', "show-number", &output_option, "Show original linenumber (Default: off)", OUTPUT_SHOW_NUMBER), - OPT_BIT('p', "porcelain", &output_option, "Show in a format designed for machine consumption", OUTPUT_PORCELAIN), - OPT_BIT(0, "line-porcelain", &output_option, "Show porcelain format with per-line commit information", OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN), - OPT_BIT('c', NULL, &output_option, "Use the same output mode as git-annotate (Default: off)", OUTPUT_ANNOTATE_COMPAT), - OPT_BIT('t', NULL, &output_option, "Show raw timestamp (Default: off)", OUTPUT_RAW_TIMESTAMP), - OPT_BIT('l', NULL, &output_option, "Show long commit SHA1 (Default: off)", OUTPUT_LONG_OBJECT_NAME), - OPT_BIT('s', NULL, &output_option, "Suppress author name and timestamp (Default: off)", OUTPUT_NO_AUTHOR), - OPT_BIT('e', "show-email", &output_option, "Show author email instead of name (Default: off)", OUTPUT_SHOW_EMAIL), - OPT_BIT('w', NULL, &xdl_opts, "Ignore whitespace differences", XDF_IGNORE_WHITESPACE), - OPT_BIT(0, "minimal", &xdl_opts, "Spend extra cycles to find better match", XDF_NEED_MINIMAL), - OPT_STRING('S', NULL, &revs_file, "file", "Use revisions from <file> instead of calling git-rev-list"), - OPT_STRING(0, "contents", &contents_from, "file", "Use <file>'s contents as the final image"), - { OPTION_CALLBACK, 'C', NULL, &opt, "score", "Find line copies within and across files", PARSE_OPT_OPTARG, blame_copy_callback }, - { OPTION_CALLBACK, 'M', NULL, &opt, "score", "Find line movements within and across files", PARSE_OPT_OPTARG, blame_move_callback }, - OPT_CALLBACK('L', NULL, &bottomtop, "n,m", "Process only line range n,m, counting from 1", blame_bottomtop_callback), + OPT_BOOLEAN(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")), + OPT_BOOLEAN('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")), + OPT_BOOLEAN(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")), + OPT_BOOLEAN(0, "show-stats", &show_stats, N_("Show work cost statistics")), + OPT_BIT(0, "score-debug", &output_option, N_("Show output score for blame entries"), OUTPUT_SHOW_SCORE), + OPT_BIT('f', "show-name", &output_option, N_("Show original filename (Default: auto)"), OUTPUT_SHOW_NAME), + OPT_BIT('n', "show-number", &output_option, N_("Show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER), + OPT_BIT('p', "porcelain", &output_option, N_("Show in a format designed for machine consumption"), OUTPUT_PORCELAIN), + OPT_BIT(0, "line-porcelain", &output_option, N_("Show porcelain format with per-line commit information"), OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN), + OPT_BIT('c', NULL, &output_option, N_("Use the same output mode as git-annotate (Default: off)"), OUTPUT_ANNOTATE_COMPAT), + OPT_BIT('t', NULL, &output_option, N_("Show raw timestamp (Default: off)"), OUTPUT_RAW_TIMESTAMP), + OPT_BIT('l', NULL, &output_option, N_("Show long commit SHA1 (Default: off)"), OUTPUT_LONG_OBJECT_NAME), + OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR), + OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL), + OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE), + 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 <file> instead of calling git-rev-list")), + OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")), + { OPTION_CALLBACK, 'C', NULL, &opt, N_("score"), N_("Find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback }, + { OPTION_CALLBACK, 'M', NULL, &opt, N_("score"), N_("Find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback }, + OPT_CALLBACK('L', NULL, &bottomtop, N_("n,m"), N_("Process only line range n,m, counting from 1"), blame_bottomtop_callback), OPT__ABBREV(&abbrev), OPT_END() }; diff --git a/builtin/branch.c b/builtin/branch.c index 0e060f2e4..1ec9c0261 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -17,12 +17,13 @@ #include "revision.h" #include "string-list.h" #include "column.h" +#include "utf8.h" static const char * const builtin_branch_usage[] = { - "git branch [options] [-r | -a] [--merged | --no-merged]", - "git branch [options] [-l] [-f] <branchname> [<start-point>]", - "git branch [options] [-r] (-d | -D) <branchname>...", - "git branch [options] (-m | -M) [<oldbranch>] <newbranch>", + N_("git branch [options] [-r | -a] [--merged | --no-merged]"), + N_("git branch [options] [-l] [-f] <branchname> [<start-point>]"), + N_("git branch [options] [-r] (-d | -D) <branchname>..."), + N_("git branch [options] (-m | -M) [<oldbranch>] <newbranch>"), NULL }; @@ -129,7 +130,7 @@ static int branch_merged(int kind, const char *name, if (!reference_rev) reference_rev = head_rev; - merged = in_merge_bases(rev, &reference_rev, 1); + merged = in_merge_bases(rev, reference_rev); /* * After the safety valve is fully redefined to "check with @@ -139,7 +140,7 @@ static int branch_merged(int kind, const char *name, * a gentle reminder is in order. */ if ((head_rev != reference_rev) && - in_merge_bases(rev, &head_rev, 1) != merged) { + in_merge_bases(rev, head_rev) != merged) { if (merged) warning(_("deleting branch '%s' that has been merged to\n" " '%s', but not yet merged to HEAD."), @@ -153,10 +154,37 @@ static int branch_merged(int kind, const char *name, return merged; } +static int check_branch_commit(const char *branchname, const char *refname, + unsigned char *sha1, struct commit *head_rev, + int kinds, int force) +{ + struct commit *rev = lookup_commit_reference(sha1); + if (!rev) { + error(_("Couldn't look up commit object for '%s'"), refname); + return -1; + } + if (!force && !branch_merged(kinds, branchname, rev, head_rev)) { + error(_("The branch '%s' is not fully merged.\n" + "If you are sure you want to delete it, " + "run 'git branch -D %s'."), branchname, branchname); + return -1; + } + return 0; +} + +static void delete_branch_config(const char *branchname) +{ + struct strbuf buf = STRBUF_INIT; + strbuf_addf(&buf, "branch.%s", branchname); + if (git_config_rename_section(buf.buf, NULL) < 0) + warning(_("Update of config-file failed")); + strbuf_release(&buf); +} + static int delete_branches(int argc, const char **argv, int force, int kinds, int quiet) { - struct commit *rev, *head_rev = NULL; + struct commit *head_rev = NULL; unsigned char sha1[20]; char *name = NULL; const char *fmt; @@ -186,6 +214,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, die(_("Couldn't look up commit object for HEAD")); } for (i = 0; i < argc; i++, strbuf_release(&bname)) { + const char *target; + int flags = 0; + strbuf_branchname(&bname, argv[i]); if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) { error(_("Cannot delete the branch '%s' " @@ -196,8 +227,10 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, free(name); - name = xstrdup(mkpath(fmt, bname.buf)); - if (read_ref(name, sha1)) { + name = mkpathdup(fmt, bname.buf); + target = resolve_ref_unsafe(name, sha1, 0, &flags); + if (!target || + (!(flags & REF_ISSYMREF) && is_null_sha1(sha1))) { error(remote_branch ? _("remote branch '%s' not found.") : _("branch '%s' not found."), bname.buf); @@ -205,40 +238,31 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, continue; } - rev = lookup_commit_reference(sha1); - if (!rev) { - error(_("Couldn't look up commit object for '%s'"), name); - ret = 1; - continue; - } - - if (!force && !branch_merged(kinds, bname.buf, rev, head_rev)) { - error(_("The branch '%s' is not fully merged.\n" - "If you are sure you want to delete it, " - "run 'git branch -D %s'."), bname.buf, bname.buf); + if (!(flags & REF_ISSYMREF) && + check_branch_commit(bname.buf, name, sha1, head_rev, kinds, + force)) { ret = 1; continue; } - if (delete_ref(name, sha1, 0)) { + if (delete_ref(name, sha1, REF_NODEREF)) { error(remote_branch ? _("Error deleting remote branch '%s'") : _("Error deleting branch '%s'"), bname.buf); ret = 1; - } else { - struct strbuf buf = STRBUF_INIT; - if (!quiet) - printf(remote_branch - ? _("Deleted remote branch %s (was %s).\n") - : _("Deleted branch %s (was %s).\n"), - bname.buf, - find_unique_abbrev(sha1, DEFAULT_ABBREV)); - strbuf_addf(&buf, "branch.%s", bname.buf); - if (git_config_rename_section(buf.buf, NULL) < 0) - warning(_("Update of config-file failed")); - strbuf_release(&buf); + continue; + } + if (!quiet) { + printf(remote_branch + ? _("Deleted remote branch %s (was %s).\n") + : _("Deleted branch %s (was %s).\n"), + bname.buf, + (flags & REF_ISSYMREF) + ? target + : find_unique_abbrev(sha1, DEFAULT_ABBREV)); } + delete_branch_config(bname.buf); } free(name); @@ -249,7 +273,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, struct ref_item { char *name; char *dest; - unsigned int kind, len; + unsigned int kind, width; struct commit *commit; }; @@ -354,14 +378,14 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, newitem->name = xstrdup(refname); newitem->kind = kind; newitem->commit = commit; - newitem->len = strlen(refname); + newitem->width = utf8_strwidth(refname); newitem->dest = resolve_symref(orig_refname, prefix); /* adjust for "remotes/" */ if (newitem->kind == REF_REMOTE_BRANCH && ref_list->kinds != REF_REMOTE_BRANCH) - newitem->len += 8; - if (newitem->len > ref_list->maxwidth) - ref_list->maxwidth = newitem->len; + newitem->width += 8; + if (newitem->width > ref_list->maxwidth) + ref_list->maxwidth = newitem->width; return 0; } @@ -490,11 +514,12 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, } strbuf_addf(&name, "%s%s", prefix, item->name); - if (verbose) + if (verbose) { + int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf); strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color), - maxwidth, name.buf, + maxwidth + utf8_compensation, name.buf, branch_get_color(BRANCH_COLOR_RESET)); - else + } else strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color), name.buf, branch_get_color(BRANCH_COLOR_RESET)); @@ -519,8 +544,8 @@ static int calc_maxwidth(struct ref_list *refs) for (i = 0; i < refs->index; i++) { if (!matches_merge_filter(refs->list[i].commit)) continue; - if (refs->list[i].len > w) - w = refs->list[i].len; + if (refs->list[i].width > w) + w = refs->list[i].width; } return w; } @@ -533,12 +558,12 @@ static void show_detached(struct ref_list *ref_list) if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) { struct ref_item item; item.name = xstrdup(_("(no branch)")); - item.len = strlen(item.name); + item.width = utf8_strwidth(item.name); item.kind = REF_LOCAL_BRANCH; item.dest = NULL; item.commit = head_commit; - if (item.len > ref_list->maxwidth) - ref_list->maxwidth = item.len; + if (item.width > ref_list->maxwidth) + ref_list->maxwidth = item.width; print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, ""); free(item.name); } @@ -712,62 +737,65 @@ int cmd_branch(int argc, const char **argv, const char *prefix) int delete = 0, rename = 0, force_create = 0, list = 0; int verbose = 0, abbrev = -1, detached = 0; int reflog = 0, edit_description = 0; - int quiet = 0; + int quiet = 0, unset_upstream = 0; + const char *new_upstream = NULL; enum branch_track track; int kinds = REF_LOCAL_BRANCH; struct commit_list *with_commit = NULL; struct option options[] = { - OPT_GROUP("Generic options"), + OPT_GROUP(N_("Generic options")), OPT__VERBOSE(&verbose, - "show hash and subject, give twice for upstream branch"), - OPT__QUIET(&quiet, "suppress informational messages"), - OPT_SET_INT('t', "track", &track, "set up tracking mode (see git-pull(1))", + N_("show hash and subject, give twice for upstream branch")), + OPT__QUIET(&quiet, N_("suppress informational messages")), + OPT_SET_INT('t', "track", &track, N_("set up tracking mode (see git-pull(1))"), BRANCH_TRACK_EXPLICIT), - OPT_SET_INT( 0, "set-upstream", &track, "change upstream info", + OPT_SET_INT( 0, "set-upstream", &track, N_("change upstream info"), BRANCH_TRACK_OVERRIDE), - OPT__COLOR(&branch_use_color, "use colored output"), - OPT_SET_INT('r', "remotes", &kinds, "act on remote-tracking branches", + OPT_STRING('u', "set-upstream-to", &new_upstream, "upstream", "change the upstream info"), + OPT_BOOLEAN(0, "unset-upstream", &unset_upstream, "Unset the upstream info"), + OPT__COLOR(&branch_use_color, N_("use colored output")), + OPT_SET_INT('r', "remotes", &kinds, N_("act on remote-tracking branches"), REF_REMOTE_BRANCH), { - OPTION_CALLBACK, 0, "contains", &with_commit, "commit", - "print only branches that contain the commit", + OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"), + N_("print only branches that contain the commit"), PARSE_OPT_LASTARG_DEFAULT, parse_opt_with_commit, (intptr_t)"HEAD", }, { - OPTION_CALLBACK, 0, "with", &with_commit, "commit", - "print only branches that contain the commit", + OPTION_CALLBACK, 0, "with", &with_commit, N_("commit"), + N_("print only branches that contain the commit"), PARSE_OPT_HIDDEN | PARSE_OPT_LASTARG_DEFAULT, parse_opt_with_commit, (intptr_t) "HEAD", }, OPT__ABBREV(&abbrev), - OPT_GROUP("Specific git-branch actions:"), - OPT_SET_INT('a', "all", &kinds, "list both remote-tracking and local branches", + OPT_GROUP(N_("Specific git-branch actions:")), + OPT_SET_INT('a', "all", &kinds, N_("list both remote-tracking and local branches"), REF_REMOTE_BRANCH | REF_LOCAL_BRANCH), - OPT_BIT('d', "delete", &delete, "delete fully merged branch", 1), - OPT_BIT('D', NULL, &delete, "delete branch (even if not merged)", 2), - OPT_BIT('m', "move", &rename, "move/rename a branch and its reflog", 1), - OPT_BIT('M', NULL, &rename, "move/rename a branch, even if target exists", 2), - OPT_BOOLEAN(0, "list", &list, "list branch names"), - OPT_BOOLEAN('l', "create-reflog", &reflog, "create the branch's reflog"), + OPT_BIT('d', "delete", &delete, N_("delete fully merged branch"), 1), + OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2), + OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1), + OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2), + OPT_BOOLEAN(0, "list", &list, N_("list branch names")), + OPT_BOOLEAN('l', "create-reflog", &reflog, N_("create the branch's reflog")), OPT_BOOLEAN(0, "edit-description", &edit_description, - "edit the description for the branch"), - OPT__FORCE(&force_create, "force creation (when already exists)"), + N_("edit the description for the branch")), + OPT__FORCE(&force_create, N_("force creation (when already exists)")), { OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref, - "commit", "print only not merged branches", + N_("commit"), N_("print only not merged branches"), PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG, opt_parse_merge_filter, (intptr_t) "HEAD", }, { OPTION_CALLBACK, 0, "merged", &merge_filter_ref, - "commit", "print only merged branches", + N_("commit"), N_("print only merged branches"), PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG, opt_parse_merge_filter, (intptr_t) "HEAD", }, - OPT_COLUMN(0, "column", &colopts, "list branches in columns"), + OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")), OPT_END(), }; @@ -794,10 +822,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, builtin_branch_usage, 0); - if (!delete && !rename && !edit_description && argc == 0) + if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0) list = 1; - if (!!delete + !!rename + !!force_create + !!list > 1) + if (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1) usage_with_options(builtin_branch_usage, options); if (abbrev == -1) @@ -852,11 +880,62 @@ int cmd_branch(int argc, const char **argv, const char *prefix) rename_branch(argv[0], argv[1], rename > 1); else usage_with_options(builtin_branch_usage, options); + } else if (new_upstream) { + struct branch *branch = branch_get(argv[0]); + + if (!ref_exists(branch->refname)) + die(_("branch '%s' does not exist"), branch->name); + + /* + * create_branch takes care of setting up the tracking + * info and making sure new_upstream is correct + */ + create_branch(head, branch->name, new_upstream, 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE); + } else if (unset_upstream) { + struct branch *branch = branch_get(argv[0]); + struct strbuf buf = STRBUF_INIT; + + if (!branch_has_merge_config(branch)) { + die(_("Branch '%s' has no upstream information"), branch->name); + } + + strbuf_addf(&buf, "branch.%s.remote", branch->name); + git_config_set_multivar(buf.buf, NULL, NULL, 1); + strbuf_reset(&buf); + strbuf_addf(&buf, "branch.%s.merge", branch->name); + git_config_set_multivar(buf.buf, NULL, NULL, 1); + strbuf_release(&buf); } else if (argc > 0 && argc <= 2) { + struct branch *branch = branch_get(argv[0]); + int branch_existed = 0, remote_tracking = 0; + struct strbuf buf = STRBUF_INIT; + if (kinds != REF_LOCAL_BRANCH) die(_("-a and -r options to 'git branch' do not make sense with a branch name")); + + if (track == BRANCH_TRACK_OVERRIDE) + fprintf(stderr, _("The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to\n")); + + strbuf_addf(&buf, "refs/remotes/%s", branch->name); + remote_tracking = ref_exists(buf.buf); + strbuf_release(&buf); + + branch_existed = ref_exists(branch->refname); create_branch(head, argv[0], (argc == 2) ? argv[1] : head, force_create, reflog, 0, quiet, track); + + /* + * We only show the instructions if the user gave us + * one branch which doesn't exist locally, but is the + * name of a remote-tracking branch. + */ + if (argc == 1 && track == BRANCH_TRACK_OVERRIDE && + !branch_existed && remote_tracking) { + fprintf(stderr, _("\nIf you wanted to make '%s' track '%s', do this:\n\n"), head, branch->name); + fprintf(stderr, _(" git branch -d %s\n"), branch->name); + fprintf(stderr, _(" git branch --set-upstream-to %s\n"), branch->name); + } + } else usage_with_options(builtin_branch_usage, options); diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 60568f9c3..00528ddc3 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -91,7 +91,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name) unsigned long size; struct object_context obj_context; - if (get_sha1_with_context(obj_name, sha1, &obj_context)) + if (get_sha1_with_context(obj_name, 0, sha1, &obj_context)) die("Not a valid object name %s", obj_name); buf = NULL; @@ -244,8 +244,8 @@ static int batch_objects(int print_contents) } static const char * const cat_file_usage[] = { - "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>", - "git cat-file (--batch|--batch-check) < <list_of_objects>", + N_("git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"), + N_("git cat-file (--batch|--batch-check) < <list_of_objects>"), NULL }; @@ -263,19 +263,19 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix) const char *exp_type = NULL, *obj_name = NULL; const struct option options[] = { - OPT_GROUP("<type> can be one of: blob, tree, commit, tag"), - OPT_SET_INT('t', NULL, &opt, "show object type", 't'), - OPT_SET_INT('s', NULL, &opt, "show object size", 's'), + OPT_GROUP(N_("<type> can be one of: blob, tree, commit, tag")), + OPT_SET_INT('t', NULL, &opt, N_("show object type"), 't'), + OPT_SET_INT('s', NULL, &opt, N_("show object size"), 's'), OPT_SET_INT('e', NULL, &opt, - "exit with zero when there's no error", 'e'), - OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'), + N_("exit with zero when there's no error"), 'e'), + OPT_SET_INT('p', NULL, &opt, N_("pretty-print object's content"), 'p'), OPT_SET_INT(0, "textconv", &opt, - "for blob objects, run textconv on object's content", 'c'), + N_("for blob objects, run textconv on object's content"), 'c'), OPT_SET_INT(0, "batch", &batch, - "show info and content of objects fed from the standard input", + N_("show info and content of objects fed from the standard input"), BATCH), OPT_SET_INT(0, "batch-check", &batch, - "show info about objects fed from the standard input", + N_("show info about objects fed from the standard input"), BATCH_CHECK), OPT_END() }; diff --git a/builtin/check-attr.c b/builtin/check-attr.c index 44c421eb0..075d01d30 100644 --- a/builtin/check-attr.c +++ b/builtin/check-attr.c @@ -8,19 +8,19 @@ static int all_attrs; static int cached_attrs; static int stdin_paths; static const char * const check_attr_usage[] = { -"git check-attr [-a | --all | attr...] [--] pathname...", -"git check-attr --stdin [-a | --all | attr...] < <list-of-paths>", +N_("git check-attr [-a | --all | attr...] [--] pathname..."), +N_("git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>"), NULL }; static int null_term_line; static const struct option check_attr_options[] = { - OPT_BOOLEAN('a', "all", &all_attrs, "report all attributes set on file"), - OPT_BOOLEAN(0, "cached", &cached_attrs, "use .gitattributes only from the index"), - OPT_BOOLEAN(0 , "stdin", &stdin_paths, "read file names from stdin"), + OPT_BOOLEAN('a', "all", &all_attrs, N_("report all attributes set on file")), + OPT_BOOLEAN(0, "cached", &cached_attrs, N_("use .gitattributes only from the index")), + OPT_BOOLEAN(0 , "stdin", &stdin_paths, N_("read file names from stdin")), OPT_BOOLEAN('z', NULL, &null_term_line, - "input paths are terminated by a null character"), + N_("input paths are terminated by a null character")), OPT_END() }; diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index c16d82b7d..b1feda7d5 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -123,7 +123,7 @@ static void checkout_all(const char *prefix, int prefix_length) } static const char * const builtin_checkout_index_usage[] = { - "git checkout-index [options] [--] [<file>...]", + N_("git checkout-index [options] [--] [<file>...]"), NULL }; @@ -184,27 +184,27 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) int force = 0, quiet = 0, not_new = 0; struct option builtin_checkout_index_options[] = { OPT_BOOLEAN('a', "all", &all, - "checks out all files in the index"), - OPT__FORCE(&force, "forces overwrite of existing files"), + N_("check out all files in the index")), + OPT__FORCE(&force, N_("force overwrite of existing files")), OPT__QUIET(&quiet, - "no warning for existing files and files not in index"), + N_("no warning for existing files and files not in index")), OPT_BOOLEAN('n', "no-create", ¬_new, - "don't checkout new files"), + N_("don't checkout new files")), { OPTION_CALLBACK, 'u', "index", &newfd, NULL, - "update stat information in the index file", + N_("update stat information in the index file"), PARSE_OPT_NOARG, option_parse_u }, { OPTION_CALLBACK, 'z', NULL, NULL, NULL, - "paths are separated with NUL character", + N_("paths are separated with NUL character"), PARSE_OPT_NOARG, option_parse_z }, OPT_BOOLEAN(0, "stdin", &read_from_stdin, - "read list of paths from the standard input"), + N_("read list of paths from the standard input")), OPT_BOOLEAN(0, "temp", &to_tempfile, - "write the content to temporary files"), - OPT_CALLBACK(0, "prefix", NULL, "string", - "when creating files, prepend <string>", + N_("write the content to temporary files")), + OPT_CALLBACK(0, "prefix", NULL, N_("string"), + N_("when creating files, prepend <string>"), option_parse_prefix), OPT_CALLBACK(0, "stage", NULL, NULL, - "copy out the files from named stage", + N_("copy out the files from named stage"), option_parse_stage), OPT_END() }; diff --git a/builtin/checkout.c b/builtin/checkout.c index 45aa0a870..a9c1b5a95 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -22,29 +22,31 @@ #include "argv-array.h" static const char * const checkout_usage[] = { - "git checkout [options] <branch>", - "git checkout [options] [<branch>] -- <file>...", + N_("git checkout [options] <branch>"), + N_("git checkout [options] [<branch>] -- <file>..."), NULL, }; struct checkout_opts { + int patch_mode; int quiet; int merge; int force; int force_detach; int writeout_stage; - int writeout_error; int overwrite_ignore; - /* not set by parse_options */ - int branch_exists; - const char *new_branch; const char *new_branch_force; const char *new_orphan_branch; int new_branch_log; enum branch_track track; struct diff_options diff_options; + + int branch_exists; + const char *prefix; + const char **pathspec; + struct tree *source_tree; }; static int post_checkout_hook(struct commit *old, struct commit *new, @@ -73,7 +75,8 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen, hashcpy(ce->sha1, sha1); memcpy(ce->name, base, baselen); memcpy(ce->name + baselen, pathname, len - baselen); - ce->ce_flags = create_ce_flags(len, 0) | CE_UPDATE; + ce->ce_flags = create_ce_flags(0) | CE_UPDATE; + ce->ce_namelen = len; ce->ce_mode = create_ce_mode(mode); add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); return 0; @@ -214,8 +217,8 @@ static int checkout_merged(int pos, struct checkout *state) return status; } -static int checkout_paths(struct tree *source_tree, const char **pathspec, - const char *prefix, struct checkout_opts *opts) +static int checkout_paths(const struct checkout_opts *opts, + const char *revision) { int pos; struct checkout state; @@ -227,37 +230,65 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec, int stage = opts->writeout_stage; int merge = opts->merge; int newfd; - struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); + struct lock_file *lock_file; + + if (opts->track != BRANCH_TRACK_UNSPECIFIED) + die(_("'%s' cannot be used with updating paths"), "--track"); + + if (opts->new_branch_log) + die(_("'%s' cannot be used with updating paths"), "-l"); + + if (opts->force && opts->patch_mode) + die(_("'%s' cannot be used with updating paths"), "-f"); + + if (opts->force_detach) + die(_("'%s' cannot be used with updating paths"), "--detach"); + + if (opts->merge && opts->patch_mode) + die(_("'%s' cannot be used with %s"), "--merge", "--patch"); + + if (opts->force && opts->merge) + die(_("'%s' cannot be used with %s"), "-f", "-m"); + + if (opts->new_branch) + die(_("Cannot update paths and switch to branch '%s' at the same time."), + opts->new_branch); + + if (opts->patch_mode) + return run_add_interactive(revision, "--patch=checkout", + opts->pathspec); + + lock_file = xcalloc(1, sizeof(struct lock_file)); newfd = hold_locked_index(lock_file, 1); - if (read_cache_preload(pathspec) < 0) + if (read_cache_preload(opts->pathspec) < 0) return error(_("corrupt index file")); - if (source_tree) - read_tree_some(source_tree, pathspec); + if (opts->source_tree) + read_tree_some(opts->source_tree, opts->pathspec); - for (pos = 0; pathspec[pos]; pos++) + for (pos = 0; opts->pathspec[pos]; pos++) ; ps_matched = xcalloc(1, pos); for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; - if (source_tree && !(ce->ce_flags & CE_UPDATE)) + if (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) continue; - match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, ps_matched); + match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, ps_matched); } - if (report_path_error(ps_matched, pathspec, prefix)) + if (report_path_error(ps_matched, opts->pathspec, opts->prefix)) return 1; /* "checkout -m path" to recreate conflicted state */ if (opts->merge) - unmerge_cache(pathspec); + unmerge_cache(opts->pathspec); /* Any unmerged paths? */ for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; - if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) { + if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) { if (!ce_stage(ce)) continue; if (opts->force) { @@ -282,9 +313,9 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec, state.refresh_cache = 1; for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; - if (source_tree && !(ce->ce_flags & CE_UPDATE)) + if (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) continue; - if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) { + if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) { if (!ce_stage(ce)) { errs |= checkout_entry(ce, &state, NULL); continue; @@ -308,7 +339,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec, return errs; } -static void show_local_changes(struct object *head, struct diff_options *opts) +static void show_local_changes(struct object *head, + const struct diff_options *opts) { struct rev_info rev; /* I think we want full paths, even if we're in a subdirectory. */ @@ -330,7 +362,8 @@ static void describe_detached_head(const char *msg, struct commit *commit) strbuf_release(&sb); } -static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree) +static int reset_tree(struct tree *tree, const struct checkout_opts *o, + int worktree, int *writeout_error) { struct unpack_trees_options opts; struct tree_desc tree_desc; @@ -349,7 +382,7 @@ static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree) init_tree_desc(&tree_desc, tree->buffer, tree->size); switch (unpack_trees(1, &tree_desc, &opts)) { case -2: - o->writeout_error = 1; + *writeout_error = 1; /* * We return 0 nevertheless, as the index is all right * and more importantly we have made best efforts to @@ -380,8 +413,10 @@ static void setup_branch_path(struct branch_info *branch) branch->path = strbuf_detach(&buf, NULL); } -static int merge_working_tree(struct checkout_opts *opts, - struct branch_info *old, struct branch_info *new) +static int merge_working_tree(const struct checkout_opts *opts, + struct branch_info *old, + struct branch_info *new, + int *writeout_error) { int ret; struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); @@ -392,7 +427,7 @@ static int merge_working_tree(struct checkout_opts *opts, resolve_undo_clear(); if (opts->force) { - ret = reset_tree(new->commit->tree, opts, 1); + ret = reset_tree(new->commit->tree, opts, 1, writeout_error); if (ret) return ret; } else { @@ -478,7 +513,8 @@ static int merge_working_tree(struct checkout_opts *opts, o.verbosity = 0; work = write_tree_from_memory(&o); - ret = reset_tree(new->commit->tree, opts, 1); + ret = reset_tree(new->commit->tree, opts, 1, + writeout_error); if (ret) return ret; o.ancestor = old->name; @@ -486,7 +522,8 @@ static int merge_working_tree(struct checkout_opts *opts, o.branch2 = "local"; merge_trees(&o, new->commit->tree, work, old->commit->tree, &result); - ret = reset_tree(new->commit->tree, opts, 0); + ret = reset_tree(new->commit->tree, opts, 0, + writeout_error); if (ret) return ret; } @@ -513,7 +550,7 @@ static void report_tracking(struct branch_info *new) strbuf_release(&sb); } -static void update_refs_for_switch(struct checkout_opts *opts, +static void update_refs_for_switch(const struct checkout_opts *opts, struct branch_info *old, struct branch_info *new) { @@ -700,13 +737,14 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new) free(refs.objects); } -static int switch_branches(struct checkout_opts *opts, struct branch_info *new) +static int switch_branches(const struct checkout_opts *opts, + struct branch_info *new) { int ret = 0; struct branch_info old; void *path_to_free; unsigned char rev[20]; - int flag; + int flag, writeout_error = 0; memset(&old, 0, sizeof(old)); old.path = path_to_free = resolve_refdup("HEAD", rev, 0, &flag); old.commit = lookup_commit_reference_gently(rev, 1); @@ -724,7 +762,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) parse_commit(new->commit); } - ret = merge_working_tree(opts, &old, new); + ret = merge_working_tree(opts, &old, new, &writeout_error); if (ret) { free(path_to_free); return ret; @@ -737,7 +775,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) ret = post_checkout_hook(old.commit, new->commit, 1); free(path_to_free); - return ret || opts->writeout_error; + return ret || writeout_error; } static int git_checkout_config(const char *var, const char *value, void *cb) @@ -754,12 +792,6 @@ static int git_checkout_config(const char *var, const char *value, void *cb) return git_xmerge_config(var, value, NULL); } -static int interactive_checkout(const char *revision, const char **pathspec, - struct checkout_opts *opts) -{ - return run_add_interactive(revision, "--patch=checkout", pathspec); -} - struct tracking_name_data { const char *name; char *remote; @@ -909,7 +941,7 @@ static int parse_branchname_arg(int argc, const char **argv, return argcount; } -static int switch_unborn_to_new_branch(struct checkout_opts *opts) +static int switch_unborn_to_new_branch(const struct checkout_opts *opts) { int status; struct strbuf branch_ref = STRBUF_INIT; @@ -919,41 +951,86 @@ static int switch_unborn_to_new_branch(struct checkout_opts *opts) strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch); status = create_symref("HEAD", branch_ref.buf, "checkout -b"); strbuf_release(&branch_ref); + if (!opts->quiet) + fprintf(stderr, _("Switched to a new branch '%s'\n"), + opts->new_branch); return status; } +static int checkout_branch(struct checkout_opts *opts, + struct branch_info *new) +{ + if (opts->pathspec) + die(_("paths cannot be used with switching branches")); + + if (opts->patch_mode) + die(_("'%s' cannot be used with switching branches"), + "--patch"); + + if (opts->writeout_stage) + die(_("'%s' cannot be used with switching branches"), + "--ours/--theirs"); + + if (opts->force && opts->merge) + die(_("'%s' cannot be used with '%s'"), "-f", "-m"); + + if (opts->force_detach && opts->new_branch) + die(_("'%s' cannot be used with '%s'"), + "--detach", "-b/-B/--orphan"); + + if (opts->new_orphan_branch) { + if (opts->track != BRANCH_TRACK_UNSPECIFIED) + die(_("'%s' cannot be used with '%s'"), "--orphan", "-t"); + } else if (opts->force_detach) { + if (opts->track != BRANCH_TRACK_UNSPECIFIED) + die(_("'%s' cannot be used with '%s'"), "--detach", "-t"); + } else if (opts->track == BRANCH_TRACK_UNSPECIFIED) + opts->track = git_branch_track; + + if (new->name && !new->commit) + die(_("Cannot switch branch to a non-commit '%s'"), + new->name); + + if (!new->commit && opts->new_branch) { + unsigned char rev[20]; + int flag; + + if (!read_ref_full("HEAD", rev, 0, &flag) && + (flag & REF_ISSYMREF) && is_null_sha1(rev)) + return switch_unborn_to_new_branch(opts); + } + return switch_branches(opts, new); +} + int cmd_checkout(int argc, const char **argv, const char *prefix) { struct checkout_opts opts; - unsigned char rev[20]; struct branch_info new; - struct tree *source_tree = NULL; char *conflict_style = NULL; - int patch_mode = 0; int dwim_new_local_branch = 1; struct option options[] = { - OPT__QUIET(&opts.quiet, "suppress progress reporting"), - OPT_STRING('b', NULL, &opts.new_branch, "branch", - "create and checkout a new branch"), - OPT_STRING('B', NULL, &opts.new_branch_force, "branch", - "create/reset and checkout a branch"), - OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"), - OPT_BOOLEAN(0, "detach", &opts.force_detach, "detach the HEAD at named commit"), - OPT_SET_INT('t', "track", &opts.track, "set upstream info for new branch", + OPT__QUIET(&opts.quiet, N_("suppress progress reporting")), + OPT_STRING('b', NULL, &opts.new_branch, N_("branch"), + N_("create and checkout a new branch")), + OPT_STRING('B', NULL, &opts.new_branch_force, N_("branch"), + N_("create/reset and checkout a branch")), + OPT_BOOLEAN('l', NULL, &opts.new_branch_log, N_("create reflog for new branch")), + OPT_BOOLEAN(0, "detach", &opts.force_detach, N_("detach the HEAD at named commit")), + OPT_SET_INT('t', "track", &opts.track, N_("set upstream info for new branch"), BRANCH_TRACK_EXPLICIT), - OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"), - OPT_SET_INT('2', "ours", &opts.writeout_stage, "checkout our version for unmerged files", + OPT_STRING(0, "orphan", &opts.new_orphan_branch, N_("new branch"), N_("new unparented branch")), + OPT_SET_INT('2', "ours", &opts.writeout_stage, N_("checkout our version for unmerged files"), 2), - OPT_SET_INT('3', "theirs", &opts.writeout_stage, "checkout their version for unmerged files", + OPT_SET_INT('3', "theirs", &opts.writeout_stage, N_("checkout their version for unmerged files"), 3), - OPT__FORCE(&opts.force, "force checkout (throw away local modifications)"), - OPT_BOOLEAN('m', "merge", &opts.merge, "perform a 3-way merge with the new branch"), - OPT_BOOLEAN(0, "overwrite-ignore", &opts.overwrite_ignore, "update ignored files (default)"), - OPT_STRING(0, "conflict", &conflict_style, "style", - "conflict style (merge or diff3)"), - OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"), + OPT__FORCE(&opts.force, N_("force checkout (throw away local modifications)")), + OPT_BOOLEAN('m', "merge", &opts.merge, N_("perform a 3-way merge with the new branch")), + OPT_BOOLEAN(0, "overwrite-ignore", &opts.overwrite_ignore, N_("update ignored files (default)")), + OPT_STRING(0, "conflict", &conflict_style, N_("style"), + N_("conflict style (merge or diff3)")), + OPT_BOOLEAN('p', "patch", &opts.patch_mode, N_("select hunks interactively")), { OPTION_BOOLEAN, 0, "guess", &dwim_new_local_branch, NULL, - "second guess 'git checkout no-such-branch'", + N_("second guess 'git checkout no-such-branch'"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN }, OPT_END(), }; @@ -961,6 +1038,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) memset(&opts, 0, sizeof(opts)); memset(&new, 0, sizeof(new)); opts.overwrite_ignore = 1; + opts.prefix = prefix; gitmodules_config(); git_config(git_checkout_config, &opts); @@ -970,26 +1048,27 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, checkout_usage, PARSE_OPT_KEEP_DASHDASH); - /* we can assume from now on new_branch = !new_branch_force */ - if (opts.new_branch && opts.new_branch_force) - die(_("-B cannot be used with -b")); + if (conflict_style) { + opts.merge = 1; /* implied */ + git_xmerge_config("merge.conflictstyle", conflict_style, NULL); + } + + if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1) + die(_("-b, -B and --orphan are mutually exclusive")); - /* copy -B over to -b, so that we can just check the latter */ + /* + * From here on, new_branch will contain the branch to be checked out, + * and new_branch_force and new_orphan_branch will tell us which one of + * -b/-B/--orphan is being used. + */ if (opts.new_branch_force) opts.new_branch = opts.new_branch_force; - if (patch_mode && (opts.track > 0 || opts.new_branch - || opts.new_branch_log || opts.merge || opts.force - || opts.force_detach)) - die (_("--patch is incompatible with all other options")); - - if (opts.force_detach && (opts.new_branch || opts.new_orphan_branch)) - die(_("--detach cannot be used with -b/-B/--orphan")); - if (opts.force_detach && 0 < opts.track) - die(_("--detach cannot be used with -t")); + if (opts.new_orphan_branch) + opts.new_branch = opts.new_orphan_branch; - /* --track without -b should DWIM */ - if (0 < opts.track && !opts.new_branch) { + /* --track without -b/-B/--orphan should DWIM */ + if (opts.track != BRANCH_TRACK_UNSPECIFIED && !opts.new_branch) { const char *argv0 = argv[0]; if (!argc || !strcmp(argv0, "--")) die (_("--track needs a branch name")); @@ -1003,22 +1082,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) opts.new_branch = argv0 + 1; } - if (opts.new_orphan_branch) { - if (opts.new_branch) - die(_("--orphan and -b|-B are mutually exclusive")); - if (opts.track > 0) - die(_("--orphan cannot be used with -t")); - opts.new_branch = opts.new_orphan_branch; - } - - if (conflict_style) { - opts.merge = 1; /* implied */ - git_xmerge_config("merge.conflictstyle", conflict_style, NULL); - } - - if (opts.force && opts.merge) - die(_("git checkout: -f and -m are incompatible")); - /* * Extract branch name from command line arguments, so * all that is left is pathspecs. @@ -1033,73 +1096,56 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) * remote branches, erroring out for invalid or ambiguous cases. */ if (argc) { + unsigned char rev[20]; int dwim_ok = - !patch_mode && + !opts.patch_mode && dwim_new_local_branch && opts.track == BRANCH_TRACK_UNSPECIFIED && !opts.new_branch; int n = parse_branchname_arg(argc, argv, dwim_ok, - &new, &source_tree, rev, &opts.new_branch); + &new, &opts.source_tree, + rev, &opts.new_branch); argv += n; argc -= n; } - if (opts.track == BRANCH_TRACK_UNSPECIFIED) - opts.track = git_branch_track; - if (argc) { - const char **pathspec = get_pathspec(prefix, argv); + opts.pathspec = get_pathspec(prefix, argv); - if (!pathspec) + if (!opts.pathspec) die(_("invalid path specification")); - if (patch_mode) - return interactive_checkout(new.name, pathspec, &opts); - - /* Checkout paths */ - if (opts.new_branch) { - if (argc == 1) { - die(_("git checkout: updating paths is incompatible with switching branches.\nDid you intend to checkout '%s' which can not be resolved as commit?"), argv[0]); - } else { - die(_("git checkout: updating paths is incompatible with switching branches.")); - } - } + /* + * Try to give more helpful suggestion. + * new_branch && argc > 1 will be caught later. + */ + if (opts.new_branch && argc == 1) + die(_("Cannot update paths and switch to branch '%s' at the same time.\n" + "Did you intend to checkout '%s' which can not be resolved as commit?"), + opts.new_branch, argv[0]); if (opts.force_detach) - die(_("git checkout: --detach does not take a path argument")); + die(_("git checkout: --detach does not take a path argument '%s'"), + argv[0]); if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge) - die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index.")); - - return checkout_paths(source_tree, pathspec, prefix, &opts); + die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\n" + "checking out of the index.")); } - if (patch_mode) - return interactive_checkout(new.name, NULL, &opts); - if (opts.new_branch) { struct strbuf buf = STRBUF_INIT; - opts.branch_exists = validate_new_branchname(opts.new_branch, &buf, - !!opts.new_branch_force, - !!opts.new_branch_force); + opts.branch_exists = + validate_new_branchname(opts.new_branch, &buf, + !!opts.new_branch_force, + !!opts.new_branch_force); strbuf_release(&buf); } - if (new.name && !new.commit) { - die(_("Cannot switch branch to a non-commit.")); - } - if (opts.writeout_stage) - die(_("--ours/--theirs is incompatible with switching branches.")); - - if (!new.commit && opts.new_branch) { - unsigned char rev[20]; - int flag; - - if (!read_ref_full("HEAD", rev, 0, &flag) && - (flag & REF_ISSYMREF) && is_null_sha1(rev)) - return switch_unborn_to_new_branch(&opts); - } - return switch_branches(&opts, &new); + if (opts.patch_mode || opts.pathspec) + return checkout_paths(&opts, new.name); + else + return checkout_branch(&opts, &new); } diff --git a/builtin/clean.c b/builtin/clean.c index 0c7b3d0f4..69c1cda90 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -16,7 +16,7 @@ static int force = -1; /* unset */ static const char *const builtin_clean_usage[] = { - "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>...", + N_("git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."), NULL }; @@ -48,16 +48,16 @@ int cmd_clean(int argc, const char **argv, const char *prefix) const char *qname; char *seen = NULL; struct option options[] = { - OPT__QUIET(&quiet, "do not print names of files removed"), - OPT__DRY_RUN(&show_only, "dry run"), - OPT__FORCE(&force, "force"), + OPT__QUIET(&quiet, N_("do not print names of files removed")), + OPT__DRY_RUN(&show_only, N_("dry run")), + OPT__FORCE(&force, N_("force")), OPT_BOOLEAN('d', NULL, &remove_directories, - "remove whole directories"), - { OPTION_CALLBACK, 'e', "exclude", &exclude_list, "pattern", - "add <pattern> to ignore rules", PARSE_OPT_NONEG, exclude_cb }, - OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"), + N_("remove whole directories")), + { OPTION_CALLBACK, 'e', "exclude", &exclude_list, N_("pattern"), + N_("add <pattern> to ignore rules"), PARSE_OPT_NONEG, exclude_cb }, + OPT_BOOLEAN('x', NULL, &ignored, N_("remove ignored files, too")), OPT_BOOLEAN('X', NULL, &ignored_only, - "remove only ignored files"), + N_("remove only ignored files")), OPT_END() }; diff --git a/builtin/clone.c b/builtin/clone.c index 920ef7f8c..ec2f75b4f 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -33,12 +33,12 @@ * */ static const char * const builtin_clone_usage[] = { - "git clone [options] [--] <repo> [<dir>]", + N_("git clone [options] [--] <repo> [<dir>]"), NULL }; static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1; -static int option_local, option_no_hardlinks, option_shared, option_recursive; +static int option_local = -1, option_no_hardlinks, option_shared, option_recursive; static char *option_template, *option_depth; static char *option_origin = NULL; static char *option_branch = NULL; @@ -61,43 +61,43 @@ static int opt_parse_reference(const struct option *opt, const char *arg, int un static struct option builtin_clone_options[] = { OPT__VERBOSITY(&option_verbosity), OPT_BOOL(0, "progress", &option_progress, - "force progress reporting"), + N_("force progress reporting")), OPT_BOOLEAN('n', "no-checkout", &option_no_checkout, - "don't create a checkout"), - OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"), + N_("don't create a checkout")), + OPT_BOOLEAN(0, "bare", &option_bare, N_("create a bare repository")), { OPTION_BOOLEAN, 0, "naked", &option_bare, NULL, - "create a bare repository", + N_("create a bare repository"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN }, OPT_BOOLEAN(0, "mirror", &option_mirror, - "create a mirror repository (implies bare)"), - OPT_BOOLEAN('l', "local", &option_local, - "to clone from a local repository"), + N_("create a mirror repository (implies bare)")), + OPT_BOOL('l', "local", &option_local, + N_("to clone from a local repository")), OPT_BOOLEAN(0, "no-hardlinks", &option_no_hardlinks, - "don't use local hardlinks, always copy"), + N_("don't use local hardlinks, always copy")), OPT_BOOLEAN('s', "shared", &option_shared, - "setup as shared repository"), + N_("setup as shared repository")), OPT_BOOLEAN(0, "recursive", &option_recursive, - "initialize submodules in the clone"), + N_("initialize submodules in the clone")), OPT_BOOLEAN(0, "recurse-submodules", &option_recursive, - "initialize submodules in the clone"), - OPT_STRING(0, "template", &option_template, "template-directory", - "directory from which templates will be used"), - OPT_CALLBACK(0 , "reference", &option_reference, "repo", - "reference repository", &opt_parse_reference), - OPT_STRING('o', "origin", &option_origin, "name", - "use <name> instead of 'origin' to track upstream"), - OPT_STRING('b', "branch", &option_branch, "branch", - "checkout <branch> instead of the remote's HEAD"), - OPT_STRING('u', "upload-pack", &option_upload_pack, "path", - "path to git-upload-pack on the remote"), - OPT_STRING(0, "depth", &option_depth, "depth", - "create a shallow clone of that depth"), + N_("initialize submodules in the clone")), + OPT_STRING(0, "template", &option_template, N_("template-directory"), + N_("directory from which templates will be used")), + OPT_CALLBACK(0 , "reference", &option_reference, N_("repo"), + N_("reference repository"), &opt_parse_reference), + OPT_STRING('o', "origin", &option_origin, N_("name"), + N_("use <name> instead of 'origin' to track upstream")), + OPT_STRING('b', "branch", &option_branch, N_("branch"), + N_("checkout <branch> instead of the remote's HEAD")), + OPT_STRING('u', "upload-pack", &option_upload_pack, N_("path"), + N_("path to git-upload-pack on the remote")), + OPT_STRING(0, "depth", &option_depth, N_("depth"), + N_("create a shallow clone of that depth")), OPT_BOOL(0, "single-branch", &option_single_branch, - "clone only one branch, HEAD or --branch"), - OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir", - "separate git dir from working tree"), - OPT_STRING_LIST('c', "config", &option_config, "key=value", - "set config inside the new repository"), + N_("clone only one branch, HEAD or --branch")), + OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"), + N_("separate git dir from working tree")), + OPT_STRING_LIST('c', "config", &option_config, N_("key=value"), + N_("set config inside the new repository")), OPT_END() }; @@ -236,7 +236,7 @@ static int add_one_reference(struct string_list_item *item, void *cb_data) /* Beware: real_path() and mkpath() return static buffer */ ref_git = xstrdup(real_path(item->string)); if (is_directory(mkpath("%s/.git/objects", ref_git))) { - char *ref_git_git = xstrdup(mkpath("%s/.git", ref_git)); + char *ref_git_git = mkpathdup("%s/.git", ref_git); free(ref_git); ref_git = ref_git_git; } else if (!is_directory(mkpath("%s/objects", ref_git))) @@ -342,7 +342,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest, if (!option_no_hardlinks) { if (!link(src->buf, dest->buf)) continue; - if (option_local) + if (option_local > 0) die_errno(_("failed to create link '%s'"), dest->buf); option_no_hardlinks = 1; } @@ -610,6 +610,54 @@ static void write_config(struct string_list *config) } } +static void write_refspec_config(const char* src_ref_prefix, + const struct ref* our_head_points_at, + const struct ref* remote_head_points_at, struct strbuf* branch_top) +{ + struct strbuf key = STRBUF_INIT; + struct strbuf value = STRBUF_INIT; + + if (option_mirror || !option_bare) { + if (option_single_branch && !option_mirror) { + if (option_branch) { + if (strstr(our_head_points_at->name, "refs/tags/")) + strbuf_addf(&value, "+%s:%s", our_head_points_at->name, + our_head_points_at->name); + else + strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name, + branch_top->buf, option_branch); + } else if (remote_head_points_at) { + strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name, + branch_top->buf, + skip_prefix(remote_head_points_at->name, "refs/heads/")); + } + /* + * otherwise, the next "git fetch" will + * simply fetch from HEAD without updating + * any remote tracking branch, which is what + * we want. + */ + } else { + strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top->buf); + } + /* Configure the remote */ + if (value.len) { + strbuf_addf(&key, "remote.%s.fetch", option_origin); + git_config_set_multivar(key.buf, value.buf, "^$", 0); + strbuf_reset(&key); + + if (option_mirror) { + strbuf_addf(&key, "remote.%s.mirror", option_origin); + git_config_set(key.buf, "true"); + strbuf_reset(&key); + } + } + } + + strbuf_release(&key); + strbuf_release(&value); +} + int cmd_clone(int argc, const char **argv, const char *prefix) { int is_bundle = 0, is_local; @@ -671,7 +719,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) die(_("repository '%s' does not exist"), repo_name); else repo = repo_name; - is_local = path && !is_bundle; + is_local = option_local != 0 && path && !is_bundle; if (is_local && option_depth) warning(_("--depth is ignored in local clones; use file:// instead.")); @@ -700,7 +748,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) git_dir = xstrdup(dir); else { work_tree = dir; - git_dir = xstrdup(mkpath("%s/.git", dir)); + git_dir = mkpathdup("%s/.git", dir); } if (!option_bare) { @@ -755,20 +803,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) } strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf); - - if (option_mirror || !option_bare) { - /* Configure the remote */ - strbuf_addf(&key, "remote.%s.fetch", option_origin); - git_config_set_multivar(key.buf, value.buf, "^$", 0); - strbuf_reset(&key); - - if (option_mirror) { - strbuf_addf(&key, "remote.%s.mirror", option_origin); - git_config_set(key.buf, "true"); - strbuf_reset(&key); - } - } - strbuf_addf(&key, "remote.%s.url", option_origin); git_config_set(key.buf, repo); strbuf_reset(&key); @@ -853,6 +887,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix) "refs/heads/master"); } + write_refspec_config(src_ref_prefix, our_head_points_at, + remote_head_points_at, &branch_top); + if (is_local) clone_local(path, git_dir); else if (refs && complete_refs_before_fetch) diff --git a/builtin/column.c b/builtin/column.c index 5ea798a7c..e125a55fc 100644 --- a/builtin/column.c +++ b/builtin/column.c @@ -6,7 +6,7 @@ #include "column.h" static const char * const builtin_column_usage[] = { - "git column [options]", + N_("git column [options]"), NULL }; static unsigned int colopts; @@ -23,13 +23,13 @@ int cmd_column(int argc, const char **argv, const char *prefix) struct column_options copts; const char *command = NULL, *real_command = NULL; struct option options[] = { - OPT_STRING(0, "command", &real_command, "name", "lookup config vars"), - OPT_COLUMN(0, "mode", &colopts, "layout to use"), - OPT_INTEGER(0, "raw-mode", &colopts, "layout to use"), - OPT_INTEGER(0, "width", &copts.width, "Maximum width"), - OPT_STRING(0, "indent", &copts.indent, "string", "Padding space on left border"), - OPT_INTEGER(0, "nl", &copts.nl, "Padding space on right border"), - OPT_INTEGER(0, "padding", &copts.padding, "Padding space between columns"), + OPT_STRING(0, "command", &real_command, N_("name"), N_("lookup config vars")), + OPT_COLUMN(0, "mode", &colopts, N_("layout to use")), + OPT_INTEGER(0, "raw-mode", &colopts, N_("layout to use")), + OPT_INTEGER(0, "width", &copts.width, N_("Maximum width")), + OPT_STRING(0, "indent", &copts.indent, N_("string"), N_("Padding space on left border")), + OPT_INTEGER(0, "nl", &copts.nl, N_("Padding space on right border")), + OPT_INTEGER(0, "padding", &copts.padding, N_("Padding space between columns")), OPT_END() }; diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index a0df12ce1..eac901a0e 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -54,7 +54,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) unsigned char sha1[20]; if (argc <= ++i) usage(commit_tree_usage); - if (get_sha1(argv[i], sha1)) + if (get_sha1_commit(argv[i], sha1)) die("Not a valid object name %s", argv[i]); assert_sha1_type(sha1, OBJ_COMMIT); new_parent(lookup_commit(sha1), &parents); @@ -101,7 +101,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) continue; } - if (get_sha1(arg, tree_sha1)) + if (get_sha1_tree(arg, tree_sha1)) die("Not a valid object name %s", arg); if (got_tree) die("Cannot give more than one trees"); diff --git a/builtin/commit.c b/builtin/commit.c index 62028e7b4..d6dd3df8b 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -28,14 +28,15 @@ #include "submodule.h" #include "gpg-interface.h" #include "column.h" +#include "sequencer.h" static const char * const builtin_commit_usage[] = { - "git commit [options] [--] <filepattern>...", + N_("git commit [options] [--] <filepattern>..."), NULL }; static const char * const builtin_status_usage[] = { - "git status [options] [--] <filepattern>...", + N_("git status [options] [--] <filepattern>..."), NULL }; @@ -111,10 +112,11 @@ static const char *only_include_assumed; static struct strbuf message = STRBUF_INIT; static enum { + STATUS_FORMAT_NONE = 0, STATUS_FORMAT_LONG, STATUS_FORMAT_SHORT, STATUS_FORMAT_PORCELAIN -} status_format = STATUS_FORMAT_LONG; +} status_format; static int opt_parse_m(const struct option *opt, const char *arg, int unset) { @@ -453,6 +455,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int case STATUS_FORMAT_PORCELAIN: wt_porcelain_print(s); break; + case STATUS_FORMAT_NONE: case STATUS_FORMAT_LONG: wt_status_print(s); break; @@ -466,8 +469,6 @@ static int is_a_merge(const struct commit *current_head) return !!(current_head->parents && current_head->parents->next); } -static const char sign_off_header[] = "Signed-off-by: "; - static void export_one(const char *var, const char *s, const char *e, int hack) { struct strbuf buf = STRBUF_INIT; @@ -552,47 +553,6 @@ static void determine_author_info(struct strbuf *author_ident) } } -static int ends_rfc2822_footer(struct strbuf *sb) -{ - int ch; - int hit = 0; - int i, j, k; - int len = sb->len; - int first = 1; - const char *buf = sb->buf; - - for (i = len - 1; i > 0; i--) { - if (hit && buf[i] == '\n') - break; - hit = (buf[i] == '\n'); - } - - while (i < len - 1 && buf[i] == '\n') - i++; - - for (; i < len; i = k) { - for (k = i; k < len && buf[k] != '\n'; k++) - ; /* do nothing */ - k++; - - if ((buf[k] == ' ' || buf[k] == '\t') && !first) - continue; - - first = 0; - - for (j = 0; i + j < len; j++) { - ch = buf[i + j]; - if (ch == ':') - break; - if (isalnum(ch) || - (ch == '-')) - continue; - return 0; - } - } - return 1; -} - static char *cut_ident_timestamp_part(char *string) { char *ket = strrchr(string, '>'); @@ -717,21 +677,30 @@ static int prepare_to_commit(const char *index_file, const char *prefix, stripspace(&sb, 0); if (signoff) { - struct strbuf sob = STRBUF_INIT; - int i; - - strbuf_addstr(&sob, sign_off_header); - strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"), - getenv("GIT_COMMITTER_EMAIL"))); - strbuf_addch(&sob, '\n'); - for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--) - ; /* do nothing */ - if (prefixcmp(sb.buf + i, sob.buf)) { - if (!i || !ends_rfc2822_footer(&sb)) - strbuf_addch(&sb, '\n'); - strbuf_addbuf(&sb, &sob); + /* + * See if we have a Conflicts: block at the end. If yes, count + * its size, so we can ignore it. + */ + int ignore_footer = 0; + int i, eol, previous = 0; + const char *nl; + + for (i = 0; i < sb.len; i++) { + nl = memchr(sb.buf + i, '\n', sb.len - i); + if (nl) + eol = nl - sb.buf; + else + eol = sb.len; + if (!prefixcmp(sb.buf + previous, "\nConflicts:\n")) { + ignore_footer = sb.len - previous; + break; + } + while (i < eol) + i++; + previous = eol; } - strbuf_release(&sob); + + append_signoff(&sb, ignore_footer); } if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len) @@ -786,7 +755,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, ident_shown++ ? "" : "\n", author_ident->buf); - if (!user_ident_sufficiently_given()) + if (!committer_ident_sufficiently_given()) status_printf_ln(s, GIT_COLOR_NORMAL, _("%s" "Committer: %s"), @@ -1091,9 +1060,13 @@ static int parse_and_validate_options(int argc, const char *argv[], if (all && argc > 0) die(_("Paths with -a does not make sense.")); - if (s->null_termination && status_format == STATUS_FORMAT_LONG) - status_format = STATUS_FORMAT_PORCELAIN; - if (status_format != STATUS_FORMAT_LONG) + if (s->null_termination) { + if (status_format == STATUS_FORMAT_NONE) + status_format = STATUS_FORMAT_PORCELAIN; + else if (status_format == STATUS_FORMAT_LONG) + die(_("--long and -z are incompatible")); + } + if (status_format != STATUS_FORMAT_NONE) dry_run = 1; return argc; @@ -1184,26 +1157,29 @@ int cmd_status(int argc, const char **argv, const char *prefix) int fd; unsigned char sha1[20]; static struct option builtin_status_options[] = { - OPT__VERBOSE(&verbose, "be verbose"), + OPT__VERBOSE(&verbose, N_("be verbose")), OPT_SET_INT('s', "short", &status_format, - "show status concisely", STATUS_FORMAT_SHORT), + N_("show status concisely"), STATUS_FORMAT_SHORT), OPT_BOOLEAN('b', "branch", &s.show_branch, - "show branch information"), + N_("show branch information")), OPT_SET_INT(0, "porcelain", &status_format, - "machine-readable output", + N_("machine-readable output"), STATUS_FORMAT_PORCELAIN), + OPT_SET_INT(0, "long", &status_format, + N_("show status in long format (default)"), + STATUS_FORMAT_LONG), OPT_BOOLEAN('z', "null", &s.null_termination, - "terminate entries with NUL"), + N_("terminate entries with NUL")), { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, - "mode", - "show untracked files, optional modes: all, normal, no. (Default: all)", + N_("mode"), + N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, OPT_BOOLEAN(0, "ignored", &show_ignored_in_status, - "show ignored files"), - { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, "when", - "ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)", + N_("show ignored files")), + { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"), + N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, - OPT_COLUMN(0, "column", &s.colopts, "list untracked files in columns"), + OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")), OPT_END(), }; @@ -1219,8 +1195,12 @@ int cmd_status(int argc, const char **argv, const char *prefix) builtin_status_usage, 0); finalize_colopts(&s.colopts, -1); - if (s.null_termination && status_format == STATUS_FORMAT_LONG) - status_format = STATUS_FORMAT_PORCELAIN; + if (s.null_termination) { + if (status_format == STATUS_FORMAT_NONE) + status_format = STATUS_FORMAT_PORCELAIN; + else if (status_format == STATUS_FORMAT_LONG) + die(_("--long and -z are incompatible")); + } handle_untracked_files_arg(&s); if (show_ignored_in_status) @@ -1249,6 +1229,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) case STATUS_FORMAT_PORCELAIN: wt_porcelain_print(&s); break; + case STATUS_FORMAT_NONE: case STATUS_FORMAT_LONG: s.verbose = verbose; s.ignore_submodule_arg = ignore_submodule_arg; @@ -1284,7 +1265,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1, strbuf_addstr(&format, "\n Author: "); strbuf_addbuf_percentquote(&format, &author_ident); } - if (!user_ident_sufficiently_given()) { + if (!committer_ident_sufficiently_given()) { strbuf_addstr(&format, "\n Committer: "); strbuf_addbuf_percentquote(&format, &committer_ident); if (advice_implicit_identity) { @@ -1384,53 +1365,56 @@ int cmd_commit(int argc, const char **argv, const char *prefix) { static struct wt_status s; static struct option builtin_commit_options[] = { - OPT__QUIET(&quiet, "suppress summary after successful commit"), - OPT__VERBOSE(&verbose, "show diff in commit message template"), - - OPT_GROUP("Commit message options"), - OPT_FILENAME('F', "file", &logfile, "read message from file"), - OPT_STRING(0, "author", &force_author, "author", "override author for commit"), - OPT_STRING(0, "date", &force_date, "date", "override date for commit"), - OPT_CALLBACK('m', "message", &message, "message", "commit message", opt_parse_m), - OPT_STRING('c', "reedit-message", &edit_message, "commit", "reuse and edit message from specified commit"), - OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"), - OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"), - OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"), - OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C/-c/--amend)"), - OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"), - OPT_FILENAME('t', "template", &template_file, "use specified template file"), - OPT_BOOL('e', "edit", &edit_flag, "force edit of commit"), - OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"), - OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"), - { OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id", - "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, + OPT__QUIET(&quiet, N_("suppress summary after successful commit")), + OPT__VERBOSE(&verbose, N_("show diff in commit message template")), + + OPT_GROUP(N_("Commit message options")), + OPT_FILENAME('F', "file", &logfile, N_("read message from file")), + OPT_STRING(0, "author", &force_author, N_("author"), N_("override author for commit")), + OPT_STRING(0, "date", &force_date, N_("date"), N_("override date for commit")), + OPT_CALLBACK('m', "message", &message, N_("message"), N_("commit message"), opt_parse_m), + OPT_STRING('c', "reedit-message", &edit_message, N_("commit"), N_("reuse and edit message from specified commit")), + OPT_STRING('C', "reuse-message", &use_message, N_("commit"), N_("reuse message from specified commit")), + OPT_STRING(0, "fixup", &fixup_message, N_("commit"), N_("use autosquash formatted message to fixup specified commit")), + OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")), + OPT_BOOLEAN(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")), + OPT_BOOLEAN('s', "signoff", &signoff, N_("add Signed-off-by:")), + OPT_FILENAME('t', "template", &template_file, N_("use specified template file")), + OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")), + OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")), + OPT_BOOLEAN(0, "status", &include_status, N_("include status in commit message template")), + { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key id"), + N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, /* end commit message options */ - OPT_GROUP("Commit contents options"), - OPT_BOOLEAN('a', "all", &all, "commit all changed files"), - OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"), - OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"), - OPT_BOOLEAN('p', "patch", &patch_interactive, "interactively add changes"), - OPT_BOOLEAN('o', "only", &only, "commit only specified files"), - OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), - OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"), - OPT_SET_INT(0, "short", &status_format, "show status concisely", + OPT_GROUP(N_("Commit contents options")), + OPT_BOOLEAN('a', "all", &all, N_("commit all changed files")), + OPT_BOOLEAN('i', "include", &also, N_("add specified files to index for commit")), + OPT_BOOLEAN(0, "interactive", &interactive, N_("interactively add files")), + OPT_BOOLEAN('p', "patch", &patch_interactive, N_("interactively add changes")), + OPT_BOOLEAN('o', "only", &only, N_("commit only specified files")), + OPT_BOOLEAN('n', "no-verify", &no_verify, N_("bypass pre-commit hook")), + OPT_BOOLEAN(0, "dry-run", &dry_run, N_("show what would be committed")), + OPT_SET_INT(0, "short", &status_format, N_("show status concisely"), STATUS_FORMAT_SHORT), - OPT_BOOLEAN(0, "branch", &s.show_branch, "show branch information"), + OPT_BOOLEAN(0, "branch", &s.show_branch, N_("show branch information")), OPT_SET_INT(0, "porcelain", &status_format, - "machine-readable output", STATUS_FORMAT_PORCELAIN), + N_("machine-readable output"), STATUS_FORMAT_PORCELAIN), + OPT_SET_INT(0, "long", &status_format, + N_("show status in long format (default)"), + STATUS_FORMAT_LONG), OPT_BOOLEAN('z', "null", &s.null_termination, - "terminate entries with NUL"), - OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), - OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"), - { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, + N_("terminate entries with NUL")), + OPT_BOOLEAN(0, "amend", &amend, N_("amend previous commit")), + OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")), + { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, /* end commit contents options */ { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL, - "ok to record an empty change", + N_("ok to record an empty change"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN }, { OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL, - "ok to record a change with an empty message", + N_("ok to record a change with an empty message"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN }, OPT_END() @@ -1452,6 +1436,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) usage_with_options(builtin_commit_usage, builtin_commit_options); wt_status_prepare(&s); + gitmodules_config(); git_config(git_commit_config, &s); determine_whence(&s); s.colopts = 0; diff --git a/builtin/config.c b/builtin/config.c index b44277c23..33c9bf9d8 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -4,7 +4,7 @@ #include "parse-options.h" static const char *const builtin_config_usage[] = { - "git config [options]", + N_("git config [options]"), NULL }; @@ -15,7 +15,6 @@ static int show_keys; static int use_key_regexp; static int do_all; static int do_not_match; -static int seen; static char delim = '='; static char key_delim = ' '; static char term = '\n'; @@ -49,33 +48,33 @@ static int respect_includes = -1; #define TYPE_PATH (1<<3) static struct option builtin_config_options[] = { - OPT_GROUP("Config file location"), - OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"), - OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"), - OPT_BOOLEAN(0, "local", &use_local_config, "use repository config file"), - OPT_STRING('f', "file", &given_config_file, "file", "use given config file"), - OPT_GROUP("Action"), - OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET), - OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL), - OPT_BIT(0, "get-regexp", &actions, "get values for regexp: name-regex [value-regex]", ACTION_GET_REGEXP), - OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name value [value_regex]", ACTION_REPLACE_ALL), - OPT_BIT(0, "add", &actions, "adds a new variable: name value", ACTION_ADD), - OPT_BIT(0, "unset", &actions, "removes a variable: name [value-regex]", ACTION_UNSET), - OPT_BIT(0, "unset-all", &actions, "removes all matches: name [value-regex]", ACTION_UNSET_ALL), - OPT_BIT(0, "rename-section", &actions, "rename section: old-name new-name", ACTION_RENAME_SECTION), - OPT_BIT(0, "remove-section", &actions, "remove a section: name", ACTION_REMOVE_SECTION), - OPT_BIT('l', "list", &actions, "list all", ACTION_LIST), - OPT_BIT('e', "edit", &actions, "opens an editor", ACTION_EDIT), - OPT_STRING(0, "get-color", &get_color_slot, "slot", "find the color configured: [default]"), - OPT_STRING(0, "get-colorbool", &get_colorbool_slot, "slot", "find the color setting: [stdout-is-tty]"), - OPT_GROUP("Type"), - OPT_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL), - OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT), - OPT_BIT(0, "bool-or-int", &types, "value is --bool or --int", TYPE_BOOL_OR_INT), - OPT_BIT(0, "path", &types, "value is a path (file or directory name)", TYPE_PATH), - OPT_GROUP("Other"), - OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"), - OPT_BOOL(0, "includes", &respect_includes, "respect include directives on lookup"), + OPT_GROUP(N_("Config file location")), + OPT_BOOLEAN(0, "global", &use_global_config, N_("use global config file")), + OPT_BOOLEAN(0, "system", &use_system_config, N_("use system config file")), + OPT_BOOLEAN(0, "local", &use_local_config, N_("use repository config file")), + OPT_STRING('f', "file", &given_config_file, N_("file"), N_("use given config file")), + OPT_GROUP(N_("Action")), + OPT_BIT(0, "get", &actions, N_("get value: name [value-regex]"), ACTION_GET), + OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-regex]"), ACTION_GET_ALL), + OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-regex]"), ACTION_GET_REGEXP), + OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value_regex]"), ACTION_REPLACE_ALL), + OPT_BIT(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD), + OPT_BIT(0, "unset", &actions, N_("remove a variable: name [value-regex]"), ACTION_UNSET), + OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-regex]"), ACTION_UNSET_ALL), + OPT_BIT(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION), + OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION), + OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST), + OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT), + OPT_STRING(0, "get-color", &get_color_slot, N_("slot"), N_("find the color configured: [default]")), + OPT_STRING(0, "get-colorbool", &get_colorbool_slot, N_("slot"), N_("find the color setting: [stdout-is-tty]")), + OPT_GROUP(N_("Type")), + OPT_BIT(0, "bool", &types, N_("value is \"true\" or \"false\""), TYPE_BOOL), + OPT_BIT(0, "int", &types, N_("value is decimal number"), TYPE_INT), + OPT_BIT(0, "bool-or-int", &types, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), + OPT_BIT(0, "path", &types, N_("value is a path (file or directory name)"), TYPE_PATH), + OPT_GROUP(N_("Other")), + OPT_BOOLEAN('z', "null", &end_null, N_("terminate values with NUL byte")), + OPT_BOOL(0, "includes", &respect_includes, N_("respect include directives on lookup")), OPT_END(), }; @@ -95,12 +94,19 @@ static int show_all_config(const char *key_, const char *value_, void *cb) return 0; } -static int show_config(const char *key_, const char *value_, void *cb) +struct strbuf_list { + struct strbuf *items; + int nr; + int alloc; +}; + +static int collect_config(const char *key_, const char *value_, void *cb) { + struct strbuf_list *values = cb; + struct strbuf *buf; char value[256]; const char *vptr = value; int must_free_vptr = 0; - int dup_error = 0; int must_print_delim = 0; if (!use_key_regexp && strcmp(key_, key)) @@ -111,12 +117,14 @@ static int show_config(const char *key_, const char *value_, void *cb) (do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0))) return 0; + ALLOC_GROW(values->items, values->nr + 1, values->alloc); + buf = &values->items[values->nr++]; + strbuf_init(buf, 0); + if (show_keys) { - printf("%s", key_); + strbuf_addstr(buf, key_); must_print_delim = 1; } - if (seen && !do_all) - dup_error = 1; if (types == TYPE_INT) sprintf(value, "%d", git_config_int(key_, value_?value_:"")); else if (types == TYPE_BOOL) @@ -129,7 +137,8 @@ static int show_config(const char *key_, const char *value_, void *cb) else sprintf(value, "%d", v); } else if (types == TYPE_PATH) { - git_config_pathname(&vptr, key_, value_); + if (git_config_pathname(&vptr, key_, value_) < 0) + return -1; must_free_vptr = 1; } else if (value_) { vptr = value_; @@ -138,16 +147,12 @@ static int show_config(const char *key_, const char *value_, void *cb) vptr = ""; must_print_delim = 0; } - seen++; - if (dup_error) { - error("More than one value for the key %s: %s", - key_, vptr); - } - else { - if (must_print_delim) - printf("%c", key_delim); - printf("%s%c", vptr, term); - } + + if (must_print_delim) + strbuf_addch(buf, key_delim); + strbuf_addstr(buf, vptr); + strbuf_addch(buf, term); + if (must_free_vptr) /* If vptr must be freed, it's a pointer to a * dynamically allocated buffer, it's safe to cast to @@ -161,21 +166,8 @@ static int show_config(const char *key_, const char *value_, void *cb) static int get_value(const char *key_, const char *regex_) { int ret = CONFIG_GENERIC_ERROR; - char *global = NULL, *repo_config = NULL; - const char *system_wide = NULL, *local; - struct config_include_data inc = CONFIG_INCLUDE_INIT; - config_fn_t fn; - void *data; - - local = given_config_file; - if (!local) { - const char *home = getenv("HOME"); - local = repo_config = git_pathdup("config"); - if (home) - global = xstrdup(mkpath("%s/.gitconfig", home)); - if (git_config_system()) - system_wide = git_etc_gitconfig(); - } + struct strbuf_list values = {NULL}; + int i; if (use_key_regexp) { char *tl; @@ -197,7 +189,8 @@ static int get_value(const char *key_, const char *regex_) key_regexp = (regex_t*)xmalloc(sizeof(regex_t)); if (regcomp(key_regexp, key, REG_EXTENDED)) { fprintf(stderr, "Invalid key pattern: %s\n", key_); - free(key); + free(key_regexp); + key_regexp = NULL; ret = CONFIG_INVALID_PATTERN; goto free_strings; } @@ -217,48 +210,37 @@ static int get_value(const char *key_, const char *regex_) regexp = (regex_t*)xmalloc(sizeof(regex_t)); if (regcomp(regexp, regex_, REG_EXTENDED)) { fprintf(stderr, "Invalid pattern: %s\n", regex_); + free(regexp); + regexp = NULL; ret = CONFIG_INVALID_PATTERN; goto free_strings; } } - fn = show_config; - data = NULL; - if (respect_includes) { - inc.fn = fn; - inc.data = data; - fn = git_config_include; - data = &inc; - } - - if (do_all && system_wide) - git_config_from_file(fn, system_wide, data); - if (do_all && global) - git_config_from_file(fn, global, data); - if (do_all) - git_config_from_file(fn, local, data); - git_config_from_parameters(fn, data); - if (!do_all && !seen) - git_config_from_file(fn, local, data); - if (!do_all && !seen && global) - git_config_from_file(fn, global, data); - if (!do_all && !seen && system_wide) - git_config_from_file(fn, system_wide, data); + git_config_with_options(collect_config, &values, + given_config_file, respect_includes); + + ret = !values.nr; + for (i = 0; i < values.nr; i++) { + struct strbuf *buf = values.items + i; + if (do_all || i == values.nr - 1) + fwrite(buf->buf, 1, buf->len, stdout); + strbuf_release(buf); + } + free(values.items); + +free_strings: free(key); + if (key_regexp) { + regfree(key_regexp); + free(key_regexp); + } if (regexp) { regfree(regexp); free(regexp); } - if (do_all) - ret = !seen; - else - ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1; - -free_strings: - free(repo_config); - free(global); return ret; } @@ -383,13 +365,25 @@ int cmd_config(int argc, const char **argv, const char *prefix) } if (use_global_config) { - char *home = getenv("HOME"); - if (home) { - char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); - given_config_file = user_config; - } else { + char *user_config = NULL; + char *xdg_config = NULL; + + home_config_paths(&user_config, &xdg_config, "config"); + + if (!user_config) + /* + * It is unknown if HOME/.gitconfig exists, so + * we do not know if we should write to XDG + * location; error out even if XDG_CONFIG_HOME + * is set and points at a sane location. + */ die("$HOME not set"); - } + + if (access_or_warn(user_config, R_OK) && + xdg_config && !access_or_warn(xdg_config, R_OK)) + given_config_file = xdg_config; + else + given_config_file = user_config; } else if (use_system_config) given_config_file = git_etc_gitconfig(); diff --git a/builtin/count-objects.c b/builtin/count-objects.c index c37cb98c3..9afaa88f7 100644 --- a/builtin/count-objects.c +++ b/builtin/count-objects.c @@ -66,7 +66,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose, } static char const * const count_objects_usage[] = { - "git count-objects [-v]", + N_("git count-objects [-v]"), NULL }; @@ -79,7 +79,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix) unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0; off_t loose_size = 0; struct option opts[] = { - OPT__VERBOSE(&verbose, "be verbose"), + OPT__VERBOSE(&verbose, N_("be verbose")), OPT_END(), }; diff --git a/builtin/credential.c b/builtin/credential.c new file mode 100644 index 000000000..0412fa00f --- /dev/null +++ b/builtin/credential.c @@ -0,0 +1,31 @@ +#include "git-compat-util.h" +#include "credential.h" +#include "builtin.h" + +static const char usage_msg[] = + "git credential [fill|approve|reject]"; + +int cmd_credential(int argc, const char **argv, const char *prefix) +{ + const char *op; + struct credential c = CREDENTIAL_INIT; + + op = argv[1]; + if (!op) + usage(usage_msg); + + if (credential_read(&c, stdin) < 0) + die("unable to read credential from stdin"); + + if (!strcmp(op, "fill")) { + credential_fill(&c); + credential_write(&c, stdout); + } else if (!strcmp(op, "approve")) { + credential_approve(&c); + } else if (!strcmp(op, "reject")) { + credential_reject(&c); + } else { + usage(usage_msg); + } + return 0; +} diff --git a/builtin/describe.c b/builtin/describe.c index 9f63067f5..04c185b1f 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -12,8 +12,8 @@ #define MAX_TAGS (FLAG_BITS - 1) static const char * const describe_usage[] = { - "git describe [options] <committish>*", - "git describe [options] --dirty", + N_("git describe [options] <committish>*"), + N_("git describe [options] --dirty"), NULL }; @@ -144,7 +144,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void if (!all && !might_be_tag) return 0; - if (!peel_ref(path, peeled) && !is_null_sha1(peeled)) { + if (!peel_ref(path, peeled)) { is_tag = !!hashcmp(sha1, peeled); } else { hashcpy(peeled, sha1); @@ -400,22 +400,22 @@ int cmd_describe(int argc, const char **argv, const char *prefix) { int contains = 0; struct option options[] = { - OPT_BOOLEAN(0, "contains", &contains, "find the tag that comes after the commit"), - OPT_BOOLEAN(0, "debug", &debug, "debug search strategy on stderr"), - OPT_BOOLEAN(0, "all", &all, "use any ref in .git/refs"), - OPT_BOOLEAN(0, "tags", &tags, "use any tag in .git/refs/tags"), - OPT_BOOLEAN(0, "long", &longformat, "always use long format"), + OPT_BOOLEAN(0, "contains", &contains, N_("find the tag that comes after the commit")), + OPT_BOOLEAN(0, "debug", &debug, N_("debug search strategy on stderr")), + OPT_BOOLEAN(0, "all", &all, N_("use any ref in .git/refs")), + OPT_BOOLEAN(0, "tags", &tags, N_("use any tag in .git/refs/tags")), + OPT_BOOLEAN(0, "long", &longformat, N_("always use long format")), OPT__ABBREV(&abbrev), OPT_SET_INT(0, "exact-match", &max_candidates, - "only output exact matches", 0), + N_("only output exact matches"), 0), OPT_INTEGER(0, "candidates", &max_candidates, - "consider <n> most recent tags (default: 10)"), - OPT_STRING(0, "match", &pattern, "pattern", - "only consider tags matching <pattern>"), + N_("consider <n> most recent tags (default: 10)")), + OPT_STRING(0, "match", &pattern, N_("pattern"), + N_("only consider tags matching <pattern>")), OPT_BOOLEAN(0, "always", &always, - "show abbreviated commit object as fallback"), - {OPTION_STRING, 0, "dirty", &dirty, "mark", - "append <mark> on dirty working tree (default: \"-dirty\")", + N_("show abbreviated commit object as fallback")), + {OPTION_STRING, 0, "dirty", &dirty, N_("mark"), + N_("append <mark> on dirty working tree (default: \"-dirty\")"), PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"}, OPT_END(), }; diff --git a/builtin/diff-index.c b/builtin/diff-index.c index 2eb32bd9d..1c737f792 100644 --- a/builtin/diff-index.c +++ b/builtin/diff-index.c @@ -41,9 +41,13 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) if (rev.pending.nr != 1 || rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1) usage(diff_cache_usage); - if (!cached) + if (!cached) { setup_work_tree(); - if (read_cache() < 0) { + if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) { + perror("read_cache_preload"); + return -1; + } + } else if (read_cache() < 0) { perror("read_cache"); return -1; } diff --git a/builtin/diff.c b/builtin/diff.c index 9650be2c5..8c2af6cb4 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -130,8 +130,6 @@ static int builtin_diff_index(struct rev_info *revs, usage(builtin_diff_usage); argv++; argc--; } - if (!cached) - setup_work_tree(); /* * Make sure there is one revision (i.e. pending object), * and there is no revision filtering parameters. @@ -140,8 +138,14 @@ static int builtin_diff_index(struct rev_info *revs, revs->max_count != -1 || revs->min_age != -1 || revs->max_age != -1) usage(builtin_diff_usage); - if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) { - perror("read_cache_preload"); + if (!cached) { + setup_work_tree(); + if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) { + perror("read_cache_preload"); + return -1; + } + } else if (read_cache() < 0) { + perror("read_cache"); return -1; } return run_diff_index(revs, cached); @@ -418,19 +422,3 @@ int cmd_diff(int argc, const char **argv, const char *prefix) refresh_index_quietly(); return result; } - -void setup_diff_pager(struct diff_options *opt) -{ - /* - * If the user asked for our exit code, then either they want --quiet - * or --exit-code. We should definitely not bother with a pager in the - * former case, as we will generate no output. Since we still properly - * report our exit code even when a pager is run, we _could_ run a - * pager with --exit-code. But since we have not done so historically, - * and because it is easy to find people oneline advising "git diff - * --exit-code" in hooks and other scripts, we do not do so. - */ - if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) && - check_pager_config("diff") != 0) - setup_pager(); -} diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 9ab6db3fb..12220ad8d 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -19,7 +19,7 @@ #include "quote.h" static const char *fast_export_usage[] = { - "git fast-export [rev-list-opts]", + N_("git fast-export [rev-list-opts]"), NULL }; @@ -632,24 +632,24 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) char *export_filename = NULL, *import_filename = NULL; struct option options[] = { OPT_INTEGER(0, "progress", &progress, - "show progress after <n> objects"), - OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, "mode", - "select handling of signed tags", + N_("show progress after <n> objects")), + OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, N_("mode"), + N_("select handling of signed tags"), parse_opt_signed_tag_mode), - OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, "mode", - "select handling of tags that tag filtered objects", + OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, N_("mode"), + N_("select handling of tags that tag filtered objects"), parse_opt_tag_of_filtered_mode), - OPT_STRING(0, "export-marks", &export_filename, "file", - "Dump marks to this file"), - OPT_STRING(0, "import-marks", &import_filename, "file", - "Import marks from this file"), + OPT_STRING(0, "export-marks", &export_filename, N_("file"), + N_("Dump marks to this file")), + OPT_STRING(0, "import-marks", &import_filename, N_("file"), + N_("Import marks from this file")), OPT_BOOLEAN(0, "fake-missing-tagger", &fake_missing_tagger, - "Fake a tagger when tags lack one"), + N_("Fake a tagger when tags lack one")), OPT_BOOLEAN(0, "full-tree", &full_tree, - "Output full tree for each commit"), + N_("Output full tree for each commit")), OPT_BOOLEAN(0, "use-done-feature", &use_done_feature, - "Use the done feature to terminate the stream"), - OPT_BOOL(0, "no-data", &no_data, "Skip output of blob data"), + N_("Use the done feature to terminate the stream")), + OPT_BOOL(0, "no-data", &no_data, N_("Skip output of blob data")), OPT_END() }; diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index 149db8872..940ae35dc 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -1,916 +1,29 @@ #include "builtin.h" -#include "refs.h" #include "pkt-line.h" -#include "commit.h" -#include "tag.h" -#include "exec_cmd.h" -#include "pack.h" -#include "sideband.h" #include "fetch-pack.h" -#include "remote.h" -#include "run-command.h" -#include "transport.h" - -static int transfer_unpack_limit = -1; -static int fetch_unpack_limit = -1; -static int unpack_limit = 100; -static int prefer_ofs_delta = 1; -static int no_done; -static int fetch_fsck_objects = -1; -static int transfer_fsck_objects = -1; -static struct fetch_pack_args args = { - /* .uploadpack = */ "git-upload-pack", -}; static const char fetch_pack_usage[] = "git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] " "[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] " "[--no-progress] [-v] [<host>:]<directory> [<refs>...]"; -#define COMPLETE (1U << 0) -#define COMMON (1U << 1) -#define COMMON_REF (1U << 2) -#define SEEN (1U << 3) -#define POPPED (1U << 4) - -static int marked; - -/* - * After sending this many "have"s if we do not get any new ACK , we - * give up traversing our history. - */ -#define MAX_IN_VAIN 256 - -static struct commit_list *rev_list; -static int non_common_revs, multi_ack, use_sideband; - -static void rev_list_push(struct commit *commit, int mark) -{ - if (!(commit->object.flags & mark)) { - commit->object.flags |= mark; - - if (!(commit->object.parsed)) - if (parse_commit(commit)) - return; - - commit_list_insert_by_date(commit, &rev_list); - - if (!(commit->object.flags & COMMON)) - non_common_revs++; - } -} - -static int rev_list_insert_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) -{ - struct object *o = deref_tag(parse_object(sha1), refname, 0); - - if (o && o->type == OBJ_COMMIT) - rev_list_push((struct commit *)o, SEEN); - - return 0; -} - -static int clear_marks(const char *refname, const unsigned char *sha1, int flag, void *cb_data) -{ - struct object *o = deref_tag(parse_object(sha1), refname, 0); - - if (o && o->type == OBJ_COMMIT) - clear_commit_marks((struct commit *)o, - COMMON | COMMON_REF | SEEN | POPPED); - return 0; -} - -/* - This function marks a rev and its ancestors as common. - In some cases, it is desirable to mark only the ancestors (for example - when only the server does not yet know that they are common). -*/ - -static void mark_common(struct commit *commit, - int ancestors_only, int dont_parse) -{ - if (commit != NULL && !(commit->object.flags & COMMON)) { - struct object *o = (struct object *)commit; - - if (!ancestors_only) - o->flags |= COMMON; - - if (!(o->flags & SEEN)) - rev_list_push(commit, SEEN); - else { - struct commit_list *parents; - - if (!ancestors_only && !(o->flags & POPPED)) - non_common_revs--; - if (!o->parsed && !dont_parse) - if (parse_commit(commit)) - return; - - for (parents = commit->parents; - parents; - parents = parents->next) - mark_common(parents->item, 0, dont_parse); - } - } -} - -/* - Get the next rev to send, ignoring the common. -*/ - -static const unsigned char *get_rev(void) -{ - struct commit *commit = NULL; - - while (commit == NULL) { - unsigned int mark; - struct commit_list *parents; - - if (rev_list == NULL || non_common_revs == 0) - return NULL; - - commit = rev_list->item; - if (!commit->object.parsed) - parse_commit(commit); - parents = commit->parents; - - commit->object.flags |= POPPED; - if (!(commit->object.flags & COMMON)) - non_common_revs--; - - if (commit->object.flags & COMMON) { - /* do not send "have", and ignore ancestors */ - commit = NULL; - mark = COMMON | SEEN; - } else if (commit->object.flags & COMMON_REF) - /* send "have", and ignore ancestors */ - mark = COMMON | SEEN; - else - /* send "have", also for its ancestors */ - mark = SEEN; - - while (parents) { - if (!(parents->item->object.flags & SEEN)) - rev_list_push(parents->item, mark); - if (mark & COMMON) - mark_common(parents->item, 1, 0); - parents = parents->next; - } - - rev_list = rev_list->next; - } - - return commit->object.sha1; -} - -enum ack_type { - NAK = 0, - ACK, - ACK_continue, - ACK_common, - ACK_ready -}; - -static void consume_shallow_list(int fd) -{ - if (args.stateless_rpc && args.depth > 0) { - /* If we sent a depth we will get back "duplicate" - * shallow and unshallow commands every time there - * is a block of have lines exchanged. - */ - char line[1000]; - while (packet_read_line(fd, line, sizeof(line))) { - if (!prefixcmp(line, "shallow ")) - continue; - if (!prefixcmp(line, "unshallow ")) - continue; - die("git fetch-pack: expected shallow list"); - } - } -} - -struct write_shallow_data { - struct strbuf *out; - int use_pack_protocol; - int count; -}; - -static int write_one_shallow(const struct commit_graft *graft, void *cb_data) -{ - struct write_shallow_data *data = cb_data; - const char *hex = sha1_to_hex(graft->sha1); - data->count++; - if (data->use_pack_protocol) - packet_buf_write(data->out, "shallow %s", hex); - else { - strbuf_addstr(data->out, hex); - strbuf_addch(data->out, '\n'); - } - return 0; -} - -static int write_shallow_commits(struct strbuf *out, int use_pack_protocol) -{ - struct write_shallow_data data; - data.out = out; - data.use_pack_protocol = use_pack_protocol; - data.count = 0; - for_each_commit_graft(write_one_shallow, &data); - return data.count; -} - -static enum ack_type get_ack(int fd, unsigned char *result_sha1) -{ - static char line[1000]; - int len = packet_read_line(fd, line, sizeof(line)); - - if (!len) - die("git fetch-pack: expected ACK/NAK, got EOF"); - if (line[len-1] == '\n') - line[--len] = 0; - if (!strcmp(line, "NAK")) - return NAK; - if (!prefixcmp(line, "ACK ")) { - if (!get_sha1_hex(line+4, result_sha1)) { - if (strstr(line+45, "continue")) - return ACK_continue; - if (strstr(line+45, "common")) - return ACK_common; - if (strstr(line+45, "ready")) - return ACK_ready; - return ACK; - } - } - die("git fetch_pack: expected ACK/NAK, got '%s'", line); -} - -static void send_request(int fd, struct strbuf *buf) -{ - if (args.stateless_rpc) { - send_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX); - packet_flush(fd); - } else - safe_write(fd, buf->buf, buf->len); -} - -static void insert_one_alternate_ref(const struct ref *ref, void *unused) -{ - rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL); -} - -#define INITIAL_FLUSH 16 -#define PIPESAFE_FLUSH 32 -#define LARGE_FLUSH 1024 - -static int next_flush(int count) -{ - int flush_limit = args.stateless_rpc ? LARGE_FLUSH : PIPESAFE_FLUSH; - - if (count < flush_limit) - count <<= 1; - else - count += flush_limit; - return count; -} - -static int find_common(int fd[2], unsigned char *result_sha1, - struct ref *refs) -{ - int fetching; - int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval; - const unsigned char *sha1; - unsigned in_vain = 0; - int got_continue = 0; - int got_ready = 0; - struct strbuf req_buf = STRBUF_INIT; - size_t state_len = 0; - - if (args.stateless_rpc && multi_ack == 1) - die("--stateless-rpc requires multi_ack_detailed"); - if (marked) - for_each_ref(clear_marks, NULL); - marked = 1; - - for_each_ref(rev_list_insert_ref, NULL); - for_each_alternate_ref(insert_one_alternate_ref, NULL); - - fetching = 0; - for ( ; refs ; refs = refs->next) { - unsigned char *remote = refs->old_sha1; - const char *remote_hex; - struct object *o; - - /* - * If that object is complete (i.e. it is an ancestor of a - * local ref), we tell them we have it but do not have to - * tell them about its ancestors, which they already know - * about. - * - * We use lookup_object here because we are only - * interested in the case we *know* the object is - * reachable and we have already scanned it. - */ - if (((o = lookup_object(remote)) != NULL) && - (o->flags & COMPLETE)) { - continue; - } - - remote_hex = sha1_to_hex(remote); - if (!fetching) { - struct strbuf c = STRBUF_INIT; - if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed"); - if (multi_ack == 1) strbuf_addstr(&c, " multi_ack"); - if (no_done) strbuf_addstr(&c, " no-done"); - if (use_sideband == 2) strbuf_addstr(&c, " side-band-64k"); - if (use_sideband == 1) strbuf_addstr(&c, " side-band"); - if (args.use_thin_pack) strbuf_addstr(&c, " thin-pack"); - if (args.no_progress) strbuf_addstr(&c, " no-progress"); - if (args.include_tag) strbuf_addstr(&c, " include-tag"); - if (prefer_ofs_delta) strbuf_addstr(&c, " ofs-delta"); - packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf); - strbuf_release(&c); - } else - packet_buf_write(&req_buf, "want %s\n", remote_hex); - fetching++; - } - - if (!fetching) { - strbuf_release(&req_buf); - packet_flush(fd[1]); - return 1; - } - - if (is_repository_shallow()) - write_shallow_commits(&req_buf, 1); - if (args.depth > 0) - packet_buf_write(&req_buf, "deepen %d", args.depth); - packet_buf_flush(&req_buf); - state_len = req_buf.len; - - if (args.depth > 0) { - char line[1024]; - unsigned char sha1[20]; - - send_request(fd[1], &req_buf); - while (packet_read_line(fd[0], line, sizeof(line))) { - if (!prefixcmp(line, "shallow ")) { - if (get_sha1_hex(line + 8, sha1)) - die("invalid shallow line: %s", line); - register_shallow(sha1); - continue; - } - if (!prefixcmp(line, "unshallow ")) { - if (get_sha1_hex(line + 10, sha1)) - die("invalid unshallow line: %s", line); - if (!lookup_object(sha1)) - die("object not found: %s", line); - /* make sure that it is parsed as shallow */ - if (!parse_object(sha1)) - die("error in object: %s", line); - if (unregister_shallow(sha1)) - die("no shallow found: %s", line); - continue; - } - die("expected shallow/unshallow, got %s", line); - } - } else if (!args.stateless_rpc) - send_request(fd[1], &req_buf); - - if (!args.stateless_rpc) { - /* If we aren't using the stateless-rpc interface - * we don't need to retain the headers. - */ - strbuf_setlen(&req_buf, 0); - state_len = 0; - } - - flushes = 0; - retval = -1; - while ((sha1 = get_rev())) { - packet_buf_write(&req_buf, "have %s\n", sha1_to_hex(sha1)); - if (args.verbose) - fprintf(stderr, "have %s\n", sha1_to_hex(sha1)); - in_vain++; - if (flush_at <= ++count) { - int ack; - - packet_buf_flush(&req_buf); - send_request(fd[1], &req_buf); - strbuf_setlen(&req_buf, state_len); - flushes++; - flush_at = next_flush(count); - - /* - * We keep one window "ahead" of the other side, and - * will wait for an ACK only on the next one - */ - if (!args.stateless_rpc && count == INITIAL_FLUSH) - continue; - - consume_shallow_list(fd[0]); - do { - ack = get_ack(fd[0], result_sha1); - if (args.verbose && ack) - fprintf(stderr, "got ack %d %s\n", ack, - sha1_to_hex(result_sha1)); - switch (ack) { - case ACK: - flushes = 0; - multi_ack = 0; - retval = 0; - goto done; - case ACK_common: - case ACK_ready: - case ACK_continue: { - struct commit *commit = - lookup_commit(result_sha1); - if (!commit) - die("invalid commit %s", sha1_to_hex(result_sha1)); - if (args.stateless_rpc - && ack == ACK_common - && !(commit->object.flags & COMMON)) { - /* We need to replay the have for this object - * on the next RPC request so the peer knows - * it is in common with us. - */ - const char *hex = sha1_to_hex(result_sha1); - packet_buf_write(&req_buf, "have %s\n", hex); - state_len = req_buf.len; - } - mark_common(commit, 0, 1); - retval = 0; - in_vain = 0; - got_continue = 1; - if (ack == ACK_ready) { - rev_list = NULL; - got_ready = 1; - } - break; - } - } - } while (ack); - flushes--; - if (got_continue && MAX_IN_VAIN < in_vain) { - if (args.verbose) - fprintf(stderr, "giving up\n"); - break; /* give up */ - } - } - } -done: - if (!got_ready || !no_done) { - packet_buf_write(&req_buf, "done\n"); - send_request(fd[1], &req_buf); - } - if (args.verbose) - fprintf(stderr, "done\n"); - if (retval != 0) { - multi_ack = 0; - flushes++; - } - strbuf_release(&req_buf); - - consume_shallow_list(fd[0]); - while (flushes || multi_ack) { - int ack = get_ack(fd[0], result_sha1); - if (ack) { - if (args.verbose) - fprintf(stderr, "got ack (%d) %s\n", ack, - sha1_to_hex(result_sha1)); - if (ack == ACK) - return 0; - multi_ack = 1; - continue; - } - flushes--; - } - /* it is no error to fetch into a completely empty repo */ - return count ? retval : 0; -} - -static struct commit_list *complete; - -static int mark_complete(const char *refname, const unsigned char *sha1, int flag, void *cb_data) -{ - struct object *o = parse_object(sha1); - - while (o && o->type == OBJ_TAG) { - struct tag *t = (struct tag *) o; - if (!t->tagged) - break; /* broken repository */ - o->flags |= COMPLETE; - o = parse_object(t->tagged->sha1); - } - if (o && o->type == OBJ_COMMIT) { - struct commit *commit = (struct commit *)o; - if (!(commit->object.flags & COMPLETE)) { - commit->object.flags |= COMPLETE; - commit_list_insert_by_date(commit, &complete); - } - } - return 0; -} - -static void mark_recent_complete_commits(unsigned long cutoff) -{ - while (complete && cutoff <= complete->item->date) { - if (args.verbose) - fprintf(stderr, "Marking %s as complete\n", - sha1_to_hex(complete->item->object.sha1)); - pop_most_recent_commit(&complete, COMPLETE); - } -} - -static void filter_refs(struct ref **refs, int nr_match, char **match) -{ - struct ref **return_refs; - struct ref *newlist = NULL; - struct ref **newtail = &newlist; - struct ref *ref, *next; - struct ref *fastarray[32]; - int match_pos; - - if (nr_match && !args.fetch_all) { - if (ARRAY_SIZE(fastarray) < nr_match) - return_refs = xcalloc(nr_match, sizeof(struct ref *)); - else { - return_refs = fastarray; - memset(return_refs, 0, sizeof(struct ref *) * nr_match); - } - } - else - return_refs = NULL; - - match_pos = 0; - for (ref = *refs; ref; ref = next) { - next = ref->next; - if (!memcmp(ref->name, "refs/", 5) && - check_refname_format(ref->name + 5, 0)) - ; /* trash */ - else if (args.fetch_all && - (!args.depth || prefixcmp(ref->name, "refs/tags/") )) { - *newtail = ref; - ref->next = NULL; - newtail = &ref->next; - continue; - } - else { - int cmp = -1; - while (match_pos < nr_match) { - cmp = strcmp(ref->name, match[match_pos]); - if (cmp < 0) /* definitely do not have it */ - break; - else if (cmp == 0) { /* definitely have it */ - match[match_pos][0] = '\0'; - return_refs[match_pos] = ref; - break; - } - else /* might have it; keep looking */ - match_pos++; - } - if (!cmp) - continue; /* we will link it later */ - } - free(ref); - } - - if (!args.fetch_all) { - int i; - for (i = 0; i < nr_match; i++) { - ref = return_refs[i]; - if (ref) { - *newtail = ref; - ref->next = NULL; - newtail = &ref->next; - } - } - if (return_refs != fastarray) - free(return_refs); - } - *refs = newlist; -} - -static void mark_alternate_complete(const struct ref *ref, void *unused) -{ - mark_complete(NULL, ref->old_sha1, 0, NULL); -} - -static int everything_local(struct ref **refs, int nr_match, char **match) -{ - struct ref *ref; - int retval; - unsigned long cutoff = 0; - - save_commit_buffer = 0; - - for (ref = *refs; ref; ref = ref->next) { - struct object *o; - - o = parse_object(ref->old_sha1); - if (!o) - continue; - - /* We already have it -- which may mean that we were - * in sync with the other side at some time after - * that (it is OK if we guess wrong here). - */ - if (o->type == OBJ_COMMIT) { - struct commit *commit = (struct commit *)o; - if (!cutoff || cutoff < commit->date) - cutoff = commit->date; - } - } - - if (!args.depth) { - for_each_ref(mark_complete, NULL); - for_each_alternate_ref(mark_alternate_complete, NULL); - if (cutoff) - mark_recent_complete_commits(cutoff); - } - - /* - * Mark all complete remote refs as common refs. - * Don't mark them common yet; the server has to be told so first. - */ - for (ref = *refs; ref; ref = ref->next) { - struct object *o = deref_tag(lookup_object(ref->old_sha1), - NULL, 0); - - if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE)) - continue; - - if (!(o->flags & SEEN)) { - rev_list_push((struct commit *)o, COMMON_REF | SEEN); - - mark_common((struct commit *)o, 1, 1); - } - } - - filter_refs(refs, nr_match, match); - - for (retval = 1, ref = *refs; ref ; ref = ref->next) { - const unsigned char *remote = ref->old_sha1; - unsigned char local[20]; - struct object *o; - - o = lookup_object(remote); - if (!o || !(o->flags & COMPLETE)) { - retval = 0; - if (!args.verbose) - continue; - fprintf(stderr, - "want %s (%s)\n", sha1_to_hex(remote), - ref->name); - continue; - } - - hashcpy(ref->new_sha1, local); - if (!args.verbose) - continue; - fprintf(stderr, - "already have %s (%s)\n", sha1_to_hex(remote), - ref->name); - } - return retval; -} - -static int sideband_demux(int in, int out, void *data) -{ - int *xd = data; - - int ret = recv_sideband("fetch-pack", xd[0], out); - close(out); - return ret; -} - -static int get_pack(int xd[2], char **pack_lockfile) -{ - struct async demux; - const char *argv[20]; - char keep_arg[256]; - char hdr_arg[256]; - const char **av; - int do_keep = args.keep_pack; - struct child_process cmd; - - memset(&demux, 0, sizeof(demux)); - if (use_sideband) { - /* xd[] is talking with upload-pack; subprocess reads from - * xd[0], spits out band#2 to stderr, and feeds us band#1 - * through demux->out. - */ - demux.proc = sideband_demux; - demux.data = xd; - demux.out = -1; - if (start_async(&demux)) - die("fetch-pack: unable to fork off sideband" - " demultiplexer"); - } - else - demux.out = xd[0]; - - memset(&cmd, 0, sizeof(cmd)); - cmd.argv = argv; - av = argv; - *hdr_arg = 0; - if (!args.keep_pack && unpack_limit) { - struct pack_header header; - - if (read_pack_header(demux.out, &header)) - die("protocol error: bad pack header"); - snprintf(hdr_arg, sizeof(hdr_arg), - "--pack_header=%"PRIu32",%"PRIu32, - ntohl(header.hdr_version), ntohl(header.hdr_entries)); - if (ntohl(header.hdr_entries) < unpack_limit) - do_keep = 0; - else - do_keep = 1; - } - - if (do_keep) { - if (pack_lockfile) - cmd.out = -1; - *av++ = "index-pack"; - *av++ = "--stdin"; - if (!args.quiet && !args.no_progress) - *av++ = "-v"; - if (args.use_thin_pack) - *av++ = "--fix-thin"; - if (args.lock_pack || unpack_limit) { - int s = sprintf(keep_arg, - "--keep=fetch-pack %"PRIuMAX " on ", (uintmax_t) getpid()); - if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) - strcpy(keep_arg + s, "localhost"); - *av++ = keep_arg; - } - } - else { - *av++ = "unpack-objects"; - if (args.quiet || args.no_progress) - *av++ = "-q"; - } - if (*hdr_arg) - *av++ = hdr_arg; - if (fetch_fsck_objects >= 0 - ? fetch_fsck_objects - : transfer_fsck_objects >= 0 - ? transfer_fsck_objects - : 0) - *av++ = "--strict"; - *av++ = NULL; - - cmd.in = demux.out; - cmd.git_cmd = 1; - if (start_command(&cmd)) - die("fetch-pack: unable to fork off %s", argv[0]); - if (do_keep && pack_lockfile) { - *pack_lockfile = index_pack_lockfile(cmd.out); - close(cmd.out); - } - - if (finish_command(&cmd)) - die("%s failed", argv[0]); - if (use_sideband && finish_async(&demux)) - die("error in sideband demultiplexer"); - return 0; -} - -static struct ref *do_fetch_pack(int fd[2], - const struct ref *orig_ref, - int nr_match, - char **match, - char **pack_lockfile) -{ - struct ref *ref = copy_ref_list(orig_ref); - unsigned char sha1[20]; - - sort_ref_list(&ref, ref_compare_name); - - if (is_repository_shallow() && !server_supports("shallow")) - die("Server does not support shallow clients"); - if (server_supports("multi_ack_detailed")) { - if (args.verbose) - fprintf(stderr, "Server supports multi_ack_detailed\n"); - multi_ack = 2; - if (server_supports("no-done")) { - if (args.verbose) - fprintf(stderr, "Server supports no-done\n"); - if (args.stateless_rpc) - no_done = 1; - } - } - else if (server_supports("multi_ack")) { - if (args.verbose) - fprintf(stderr, "Server supports multi_ack\n"); - multi_ack = 1; - } - if (server_supports("side-band-64k")) { - if (args.verbose) - fprintf(stderr, "Server supports side-band-64k\n"); - use_sideband = 2; - } - else if (server_supports("side-band")) { - if (args.verbose) - fprintf(stderr, "Server supports side-band\n"); - use_sideband = 1; - } - if (server_supports("ofs-delta")) { - if (args.verbose) - fprintf(stderr, "Server supports ofs-delta\n"); - } else - prefer_ofs_delta = 0; - if (everything_local(&ref, nr_match, match)) { - packet_flush(fd[1]); - goto all_done; - } - if (find_common(fd, sha1, ref) < 0) - if (!args.keep_pack) - /* When cloning, it is not unusual to have - * no common commit. - */ - warning("no common commits"); - - if (args.stateless_rpc) - packet_flush(fd[1]); - if (get_pack(fd, pack_lockfile)) - die("git fetch-pack: fetch failed."); - - all_done: - return ref; -} - -static int remove_duplicates(int nr_heads, char **heads) -{ - int src, dst; - - if (!nr_heads) - return 0; - - for (src = dst = 1; src < nr_heads; src++) - if (strcmp(heads[src], heads[dst-1])) - heads[dst++] = heads[src]; - return dst; -} - -static int fetch_pack_config(const char *var, const char *value, void *cb) -{ - if (strcmp(var, "fetch.unpacklimit") == 0) { - fetch_unpack_limit = git_config_int(var, value); - return 0; - } - - if (strcmp(var, "transfer.unpacklimit") == 0) { - transfer_unpack_limit = git_config_int(var, value); - return 0; - } - - if (strcmp(var, "repack.usedeltabaseoffset") == 0) { - prefer_ofs_delta = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "fetch.fsckobjects")) { - fetch_fsck_objects = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "transfer.fsckobjects")) { - transfer_fsck_objects = git_config_bool(var, value); - return 0; - } - - return git_default_config(var, value, cb); -} - -static struct lock_file lock; - -static void fetch_pack_setup(void) -{ - static int did_setup; - if (did_setup) - return; - git_config(fetch_pack_config, NULL); - if (0 <= transfer_unpack_limit) - unpack_limit = transfer_unpack_limit; - else if (0 <= fetch_unpack_limit) - unpack_limit = fetch_unpack_limit; - did_setup = 1; -} - int cmd_fetch_pack(int argc, const char **argv, const char *prefix) { int i, ret; struct ref *ref = NULL; const char *dest = NULL; - int alloc_heads = 0, nr_heads = 0; - char **heads = NULL; + struct string_list sought = STRING_LIST_INIT_DUP; int fd[2]; char *pack_lockfile = NULL; char **pack_lockfile_ptr = NULL; struct child_process *conn; + struct fetch_pack_args args; packet_trace_identity("fetch-pack"); + memset(&args, 0, sizeof(args)); + args.uploadpack = "git-upload-pack"; + for (i = 1; i < argc && *argv[i] == '-'; i++) { const char *arg = argv[i]; @@ -980,9 +93,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) * Copy refs from cmdline to growable list, then append any * refs from the standard input: */ - ALLOC_GROW(heads, argc - i, alloc_heads); for (; i < argc; i++) - heads[nr_heads++] = xstrdup(argv[i]); + string_list_append(&sought, xstrdup(argv[i])); if (args.stdin_refs) { if (args.stateless_rpc) { /* in stateless RPC mode we use pkt-line to read @@ -995,17 +107,14 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) break; if (line[n-1] == '\n') n--; - ALLOC_GROW(heads, nr_heads + 1, alloc_heads); - heads[nr_heads++] = xmemdupz(line, n); + string_list_append(&sought, xmemdupz(line, n)); } } else { /* read from stdin one ref per line, until EOF */ struct strbuf line = STRBUF_INIT; - while (strbuf_getline(&line, stdin, '\n') != EOF) { - ALLOC_GROW(heads, nr_heads + 1, alloc_heads); - heads[nr_heads++] = strbuf_detach(&line, NULL); - } + while (strbuf_getline(&line, stdin, '\n') != EOF) + string_list_append(&sought, strbuf_detach(&line, NULL)); strbuf_release(&line); } } @@ -1022,7 +131,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) get_remote_heads(fd[0], &ref, 0, NULL); ref = fetch_pack(&args, fd, conn, ref, dest, - nr_heads, heads, pack_lockfile_ptr); + &sought, pack_lockfile_ptr); if (pack_lockfile) { printf("lock %s\n", pack_lockfile); fflush(stdout); @@ -1030,21 +139,18 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) close(fd[0]); close(fd[1]); if (finish_connect(conn)) - ref = NULL; - ret = !ref; + return 1; - if (!ret && nr_heads) { - /* If the heads to pull were given, we should have - * consumed all of them by matching the remote. - * Otherwise, 'git fetch remote no-such-ref' would - * silently succeed without issuing an error. - */ - for (i = 0; i < nr_heads; i++) - if (heads[i] && heads[i][0]) { - error("no such remote ref %s", heads[i]); - ret = 1; - } - } + ret = !ref || sought.nr; + + /* + * If the heads to pull were given, we should have consumed + * all of them by matching the remote. Otherwise, 'git fetch + * remote no-such-ref' would silently succeed without issuing + * an error. + */ + for (i = 0; i < sought.nr; i++) + error("no such remote ref %s", sought.items[i].string); while (ref) { printf("%s %s\n", sha1_to_hex(ref->old_sha1), ref->name); @@ -1053,72 +159,3 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) return ret; } - -static int compare_heads(const void *a, const void *b) -{ - return strcmp(*(const char **)a, *(const char **)b); -} - -struct ref *fetch_pack(struct fetch_pack_args *my_args, - int fd[], struct child_process *conn, - const struct ref *ref, - const char *dest, - int nr_heads, - char **heads, - char **pack_lockfile) -{ - struct stat st; - struct ref *ref_cpy; - - fetch_pack_setup(); - if (&args != my_args) - memcpy(&args, my_args, sizeof(args)); - if (args.depth > 0) { - if (stat(git_path("shallow"), &st)) - st.st_mtime = 0; - } - - if (heads && nr_heads) { - qsort(heads, nr_heads, sizeof(*heads), compare_heads); - nr_heads = remove_duplicates(nr_heads, heads); - } - - if (!ref) { - packet_flush(fd[1]); - die("no matching remote head"); - } - ref_cpy = do_fetch_pack(fd, ref, nr_heads, heads, pack_lockfile); - - if (args.depth > 0) { - struct cache_time mtime; - struct strbuf sb = STRBUF_INIT; - char *shallow = git_path("shallow"); - int fd; - - mtime.sec = st.st_mtime; - mtime.nsec = ST_MTIME_NSEC(st); - if (stat(shallow, &st)) { - if (mtime.sec) - die("shallow file was removed during fetch"); - } else if (st.st_mtime != mtime.sec -#ifdef USE_NSEC - || ST_MTIME_NSEC(st) != mtime.nsec -#endif - ) - die("shallow file was changed during fetch"); - - fd = hold_lock_file_for_update(&lock, shallow, - LOCK_DIE_ON_ERROR); - if (!write_shallow_commits(&sb, 0) - || write_in_full(fd, sb.buf, sb.len) != sb.len) { - unlink_or_warn(shallow); - rollback_lock_file(&lock); - } else { - commit_lock_file(&lock); - } - strbuf_release(&sb); - } - - reprepare_packed_git(); - return ref_cpy; -} diff --git a/builtin/fetch.c b/builtin/fetch.c index bb9a0743f..4b5a89839 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -14,12 +14,13 @@ #include "transport.h" #include "submodule.h" #include "connected.h" +#include "argv-array.h" static const char * const builtin_fetch_usage[] = { - "git fetch [<options>] [<repository> [<refspec>...]]", - "git fetch [<options>] <group>", - "git fetch --multiple [<options>] [(<repository> | <group>)...]", - "git fetch --all [<options>]", + N_("git fetch [<options>] [<repository> [<refspec>...]]"), + N_("git fetch [<options>] <group>"), + N_("git fetch --multiple [<options>] [(<repository> | <group>)...]"), + N_("git fetch --all [<options>]"), NULL }; @@ -56,36 +57,36 @@ static int option_parse_recurse_submodules(const struct option *opt, static struct option builtin_fetch_options[] = { OPT__VERBOSITY(&verbosity), OPT_BOOLEAN(0, "all", &all, - "fetch from all remotes"), + N_("fetch from all remotes")), OPT_BOOLEAN('a', "append", &append, - "append to .git/FETCH_HEAD instead of overwriting"), - OPT_STRING(0, "upload-pack", &upload_pack, "path", - "path to upload pack on remote end"), - OPT__FORCE(&force, "force overwrite of local branch"), + N_("append to .git/FETCH_HEAD instead of overwriting")), + OPT_STRING(0, "upload-pack", &upload_pack, N_("path"), + N_("path to upload pack on remote end")), + OPT__FORCE(&force, N_("force overwrite of local branch")), OPT_BOOLEAN('m', "multiple", &multiple, - "fetch from multiple remotes"), + N_("fetch from multiple remotes")), OPT_SET_INT('t', "tags", &tags, - "fetch all tags and associated objects", TAGS_SET), + N_("fetch all tags and associated objects"), TAGS_SET), OPT_SET_INT('n', NULL, &tags, - "do not fetch all tags (--no-tags)", TAGS_UNSET), + N_("do not fetch all tags (--no-tags)"), TAGS_UNSET), OPT_BOOLEAN('p', "prune", &prune, - "prune remote-tracking branches no longer on remote"), - { OPTION_CALLBACK, 0, "recurse-submodules", NULL, "on-demand", - "control recursive fetching of submodules", + N_("prune remote-tracking branches no longer on remote")), + { OPTION_CALLBACK, 0, "recurse-submodules", NULL, N_("on-demand"), + N_("control recursive fetching of submodules"), PARSE_OPT_OPTARG, option_parse_recurse_submodules }, OPT_BOOLEAN(0, "dry-run", &dry_run, - "dry run"), - OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"), + N_("dry run")), + OPT_BOOLEAN('k', "keep", &keep, N_("keep downloaded pack")), OPT_BOOLEAN('u', "update-head-ok", &update_head_ok, - "allow updating of HEAD ref"), - OPT_BOOL(0, "progress", &progress, "force progress reporting"), - OPT_STRING(0, "depth", &depth, "depth", - "deepen history of shallow clone"), - { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "dir", - "prepend this to submodule path output", PARSE_OPT_HIDDEN }, + N_("allow updating of HEAD ref")), + OPT_BOOL(0, "progress", &progress, N_("force progress reporting")), + OPT_STRING(0, "depth", &depth, N_("depth"), + N_("deepen history of shallow clone")), + { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"), + N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN }, { OPTION_STRING, 0, "recurse-submodules-default", &recurse_submodules_default, NULL, - "default mode for recursion", PARSE_OPT_HIDDEN }, + N_("default mode for recursion"), PARSE_OPT_HIDDEN }, OPT_END() }; @@ -255,9 +256,8 @@ static int update_local_ref(struct ref *ref, if (!hashcmp(ref->old_sha1, ref->new_sha1)) { if (verbosity > 0) strbuf_addf(display, "= %-*s %-*s -> %s", - TRANSPORT_SUMMARY_WIDTH, - _("[up to date]"), REFCOL_WIDTH, - remote, pretty_ref); + TRANSPORT_SUMMARY(_("[up to date]")), + REFCOL_WIDTH, remote, pretty_ref); return 0; } @@ -271,7 +271,7 @@ static int update_local_ref(struct ref *ref, */ strbuf_addf(display, _("! %-*s %-*s -> %s (can't fetch in current branch)"), - TRANSPORT_SUMMARY_WIDTH, _("[rejected]"), + TRANSPORT_SUMMARY(_("[rejected]")), REFCOL_WIDTH, remote, pretty_ref); return 1; } @@ -282,7 +282,7 @@ static int update_local_ref(struct ref *ref, r = s_update_ref("updating tag", ref, 0); strbuf_addf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-', - TRANSPORT_SUMMARY_WIDTH, _("[tag update]"), + TRANSPORT_SUMMARY(_("[tag update]")), REFCOL_WIDTH, remote, pretty_ref, r ? _(" (unable to update local ref)") : ""); return r; @@ -317,13 +317,13 @@ static int update_local_ref(struct ref *ref, r = s_update_ref(msg, ref, 0); strbuf_addf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*', - TRANSPORT_SUMMARY_WIDTH, what, + TRANSPORT_SUMMARY(what), REFCOL_WIDTH, remote, pretty_ref, r ? _(" (unable to update local ref)") : ""); return r; } - if (in_merge_bases(current, &updated, 1)) { + if (in_merge_bases(current, updated)) { char quickref[83]; int r; strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); @@ -357,7 +357,7 @@ static int update_local_ref(struct ref *ref, return r; } else { strbuf_addf(display, "! %-*s %-*s -> %s %s", - TRANSPORT_SUMMARY_WIDTH, _("[rejected]"), + TRANSPORT_SUMMARY(_("[rejected]")), REFCOL_WIDTH, remote, pretty_ref, _("(non-fast-forward)")); return 1; @@ -554,7 +554,7 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map) result |= delete_ref(ref->name, NULL, 0); if (verbosity >= 0) { fprintf(stderr, " x %-*s %-*s -> %s\n", - TRANSPORT_SUMMARY_WIDTH, _("[deleted]"), + TRANSPORT_SUMMARY(_("[deleted]")), REFCOL_WIDTH, _("(none)"), prettify_refname(ref->name)); warn_dangling_symref(stderr, dangling_msg, ref->name); } @@ -841,38 +841,39 @@ static int add_remote_or_group(const char *name, struct string_list *list) return 1; } -static void add_options_to_argv(int *argc, const char **argv) +static void add_options_to_argv(struct argv_array *argv) { if (dry_run) - argv[(*argc)++] = "--dry-run"; + argv_array_push(argv, "--dry-run"); if (prune) - argv[(*argc)++] = "--prune"; + argv_array_push(argv, "--prune"); if (update_head_ok) - argv[(*argc)++] = "--update-head-ok"; + argv_array_push(argv, "--update-head-ok"); if (force) - argv[(*argc)++] = "--force"; + argv_array_push(argv, "--force"); if (keep) - argv[(*argc)++] = "--keep"; + argv_array_push(argv, "--keep"); if (recurse_submodules == RECURSE_SUBMODULES_ON) - argv[(*argc)++] = "--recurse-submodules"; + argv_array_push(argv, "--recurse-submodules"); else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) - argv[(*argc)++] = "--recurse-submodules=on-demand"; + argv_array_push(argv, "--recurse-submodules=on-demand"); + if (tags == TAGS_SET) + argv_array_push(argv, "--tags"); + else if (tags == TAGS_UNSET) + argv_array_push(argv, "--no-tags"); if (verbosity >= 2) - argv[(*argc)++] = "-v"; + argv_array_push(argv, "-v"); if (verbosity >= 1) - argv[(*argc)++] = "-v"; + argv_array_push(argv, "-v"); else if (verbosity < 0) - argv[(*argc)++] = "-q"; + argv_array_push(argv, "-q"); } static int fetch_multiple(struct string_list *list) { int i, result = 0; - const char *argv[12] = { "fetch", "--append" }; - int argc = 2; - - add_options_to_argv(&argc, argv); + struct argv_array argv = ARGV_ARRAY_INIT; if (!append && !dry_run) { int errcode = truncate_fetch_head(); @@ -880,18 +881,22 @@ static int fetch_multiple(struct string_list *list) return errcode; } + argv_array_pushl(&argv, "fetch", "--append", NULL); + add_options_to_argv(&argv); + for (i = 0; i < list->nr; i++) { const char *name = list->items[i].string; - argv[argc] = name; - argv[argc + 1] = NULL; + argv_array_push(&argv, name); if (verbosity >= 0) printf(_("Fetching %s\n"), name); - if (run_command_v_opt(argv, RUN_GIT_CMD)) { + if (run_command_v_opt(argv.argv, RUN_GIT_CMD)) { error(_("Could not fetch %s"), name); result = 1; } + argv_array_pop(&argv); } + argv_array_clear(&argv); return result; } @@ -1007,13 +1012,14 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) } if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) { - const char *options[10]; - int num_options = 0; - add_options_to_argv(&num_options, options); - result = fetch_populated_submodules(num_options, options, + struct argv_array options = ARGV_ARRAY_INIT; + + add_options_to_argv(&options); + result = fetch_populated_submodules(&options, submodule_prefix, recurse_submodules, verbosity < 0); + argv_array_clear(&options); } /* All names were strdup()ed or strndup()ed */ diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 2c4d435da..e2e27b2c4 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -10,7 +10,7 @@ #include "gpg-interface.h" static const char * const fmt_merge_msg_usage[] = { - "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]", + N_("git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"), NULL }; @@ -650,16 +650,16 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) const char *message = NULL; int shortlog_len = -1; struct option options[] = { - { OPTION_INTEGER, 0, "log", &shortlog_len, "n", - "populate log with at most <n> entries from shortlog", + { OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"), + N_("populate log with at most <n> entries from shortlog"), PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN }, - { OPTION_INTEGER, 0, "summary", &shortlog_len, "n", - "alias for --log (deprecated)", + { OPTION_INTEGER, 0, "summary", &shortlog_len, N_("n"), + N_("alias for --log (deprecated)"), PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN, NULL, DEFAULT_MERGE_LOG_LEN }, - OPT_STRING('m', "message", &message, "text", - "use <text> as start of message"), - OPT_FILENAME('F', "file", &inpath, "file to read from"), + OPT_STRING('m', "message", &message, N_("text"), + N_("use <text> as start of message")), + OPT_FILENAME('F', "file", &inpath, N_("file to read from")), OPT_END() }; diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 0c5294e5e..7f059c31d 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -976,7 +976,7 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset) } static char const * const for_each_ref_usage[] = { - "git for-each-ref [options] [<pattern>]", + N_("git for-each-ref [options] [<pattern>]"), NULL }; @@ -991,19 +991,19 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix) struct option opts[] = { OPT_BIT('s', "shell", "e_style, - "quote placeholders suitably for shells", QUOTE_SHELL), + N_("quote placeholders suitably for shells"), QUOTE_SHELL), OPT_BIT('p', "perl", "e_style, - "quote placeholders suitably for perl", QUOTE_PERL), + N_("quote placeholders suitably for perl"), QUOTE_PERL), OPT_BIT(0 , "python", "e_style, - "quote placeholders suitably for python", QUOTE_PYTHON), + N_("quote placeholders suitably for python"), QUOTE_PYTHON), OPT_BIT(0 , "tcl", "e_style, - "quote placeholders suitably for tcl", QUOTE_TCL), + N_("quote placeholders suitably for tcl"), QUOTE_TCL), OPT_GROUP(""), - OPT_INTEGER( 0 , "count", &maxcount, "show only <n> matched refs"), - OPT_STRING( 0 , "format", &format, "format", "format to use for the output"), - OPT_CALLBACK(0 , "sort", sort_tail, "key", - "field name to sort on", &opt_parse_sort), + OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")), + OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")), + OPT_CALLBACK(0 , "sort", sort_tail, N_("key"), + N_("field name to sort on"), &opt_parse_sort), OPT_END(), }; diff --git a/builtin/fsck.c b/builtin/fsck.c index a710227a6..bb9a2cd44 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -605,23 +605,23 @@ static int fsck_cache_tree(struct cache_tree *it) } static char const * const fsck_usage[] = { - "git fsck [options] [<object>...]", + N_("git fsck [options] [<object>...]"), NULL }; static struct option fsck_opts[] = { - OPT__VERBOSE(&verbose, "be verbose"), - OPT_BOOLEAN(0, "unreachable", &show_unreachable, "show unreachable objects"), - OPT_BOOL(0, "dangling", &show_dangling, "show dangling objects"), - OPT_BOOLEAN(0, "tags", &show_tags, "report tags"), - OPT_BOOLEAN(0, "root", &show_root, "report root nodes"), - OPT_BOOLEAN(0, "cache", &keep_cache_objects, "make index objects head nodes"), - OPT_BOOLEAN(0, "reflogs", &include_reflogs, "make reflogs head nodes (default)"), - OPT_BOOLEAN(0, "full", &check_full, "also consider packs and alternate objects"), - OPT_BOOLEAN(0, "strict", &check_strict, "enable more strict checking"), + OPT__VERBOSE(&verbose, N_("be verbose")), + OPT_BOOLEAN(0, "unreachable", &show_unreachable, N_("show unreachable objects")), + OPT_BOOL(0, "dangling", &show_dangling, N_("show dangling objects")), + OPT_BOOLEAN(0, "tags", &show_tags, N_("report tags")), + OPT_BOOLEAN(0, "root", &show_root, N_("report root nodes")), + OPT_BOOLEAN(0, "cache", &keep_cache_objects, N_("make index objects head nodes")), + OPT_BOOLEAN(0, "reflogs", &include_reflogs, N_("make reflogs head nodes (default)")), + OPT_BOOLEAN(0, "full", &check_full, N_("also consider packs and alternate objects")), + OPT_BOOLEAN(0, "strict", &check_strict, N_("enable more strict checking")), OPT_BOOLEAN(0, "lost-found", &write_lost_and_found, - "write dangling objects in .git/lost-found"), - OPT_BOOL(0, "progress", &show_progress, "show progress"), + N_("write dangling objects in .git/lost-found")), + OPT_BOOL(0, "progress", &show_progress, N_("show progress")), OPT_END(), }; diff --git a/builtin/gc.c b/builtin/gc.c index 9b4232c8f..6be6c8d65 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -19,7 +19,7 @@ #define FAILED_RUN "failed to run %s" static const char * const builtin_gc_usage[] = { - "git gc [options]", + N_("git gc [options]"), NULL }; @@ -174,12 +174,12 @@ int cmd_gc(int argc, const char **argv, const char *prefix) int quiet = 0; struct option builtin_gc_options[] = { - OPT__QUIET(&quiet, "suppress progress reporting"), - { OPTION_STRING, 0, "prune", &prune_expire, "date", - "prune unreferenced objects", + OPT__QUIET(&quiet, N_("suppress progress reporting")), + { OPTION_STRING, 0, "prune", &prune_expire, N_("date"), + N_("prune unreferenced objects"), PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire }, - OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"), - OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"), + OPT_BOOLEAN(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")), + OPT_BOOLEAN(0, "auto", &auto_gc, N_("enable auto-gc mode")), OPT_END() }; @@ -217,9 +217,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix) */ if (!need_to_gc()) return 0; - if (quiet) - fprintf(stderr, _("Auto packing the repository for optimum performance.\n")); - else + if (!quiet) fprintf(stderr, _("Auto packing the repository for optimum performance. You may also\n" "run \"git gc\" manually. See " diff --git a/builtin/grep.c b/builtin/grep.c index 29adb0ac9..0e1b6c860 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -19,7 +19,7 @@ #include "dir.h" static char const * const grep_usage[] = { - "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]", + N_("git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"), NULL }; @@ -86,7 +86,7 @@ static pthread_cond_t cond_result; static int skip_first_line; static void add_work(struct grep_opt *opt, enum grep_source_type type, - const char *name, const void *id) + const char *name, const char *path, const void *id) { grep_lock(); @@ -94,7 +94,7 @@ static void add_work(struct grep_opt *opt, enum grep_source_type type, pthread_cond_wait(&cond_write, &grep_mutex); } - grep_source_init(&todo[todo_end].source, type, name, id); + grep_source_init(&todo[todo_end].source, type, name, path, id); if (opt->binary != GREP_BINARY_TEXT) grep_source_load_driver(&todo[todo_end].source); todo[todo_end].done = 0; @@ -209,6 +209,7 @@ static void start_threads(struct grep_opt *opt) int err; struct grep_opt *o = grep_opt_dup(opt); o->output = strbuf_out; + o->debug = 0; compile_grep_patterns(o); err = pthread_create(&threads[i], NULL, run, o); @@ -260,51 +261,12 @@ static int wait_all(void) } #endif -static int grep_config(const char *var, const char *value, void *cb) +static int grep_cmd_config(const char *var, const char *value, void *cb) { - struct grep_opt *opt = cb; - char *color = NULL; - - if (userdiff_config(var, value) < 0) - return -1; - - if (!strcmp(var, "grep.extendedregexp")) { - if (git_config_bool(var, value)) - opt->regflags |= REG_EXTENDED; - else - opt->regflags &= ~REG_EXTENDED; - return 0; - } - - if (!strcmp(var, "grep.linenumber")) { - opt->linenum = git_config_bool(var, value); - return 0; - } - - if (!strcmp(var, "color.grep")) - opt->color = git_config_colorbool(var, value); - else if (!strcmp(var, "color.grep.context")) - color = opt->color_context; - else if (!strcmp(var, "color.grep.filename")) - color = opt->color_filename; - else if (!strcmp(var, "color.grep.function")) - color = opt->color_function; - else if (!strcmp(var, "color.grep.linenumber")) - color = opt->color_lineno; - else if (!strcmp(var, "color.grep.match")) - color = opt->color_match; - else if (!strcmp(var, "color.grep.selected")) - color = opt->color_selected; - else if (!strcmp(var, "color.grep.separator")) - color = opt->color_sep; - else - return git_color_default_config(var, value, cb); - if (color) { - if (!value) - return config_error_nonbool(var); - color_parse(value, var, color); - } - return 0; + int st = grep_config(var, value, cb); + if (git_color_default_config(var, value, cb) < 0) + st = -1; + return st; } static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size) @@ -318,7 +280,8 @@ static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type } static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, - const char *filename, int tree_name_len) + const char *filename, int tree_name_len, + const char *path) { struct strbuf pathbuf = STRBUF_INIT; @@ -332,7 +295,7 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, #ifndef NO_PTHREADS if (use_threads) { - add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, sha1); + add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1); strbuf_release(&pathbuf); return 0; } else @@ -341,7 +304,7 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, struct grep_source gs; int hit; - grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, sha1); + grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1); strbuf_release(&pathbuf); hit = grep_source(opt, &gs); @@ -361,7 +324,7 @@ static int grep_file(struct grep_opt *opt, const char *filename) #ifndef NO_PTHREADS if (use_threads) { - add_work(opt, GREP_SOURCE_FILE, buf.buf, filename); + add_work(opt, GREP_SOURCE_FILE, buf.buf, filename, filename); strbuf_release(&buf); return 0; } else @@ -370,7 +333,7 @@ static int grep_file(struct grep_opt *opt, const char *filename) struct grep_source gs; int hit; - grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename); + grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename); strbuf_release(&buf); hit = grep_source(opt, &gs); @@ -426,7 +389,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) { if (ce_stage(ce)) continue; - hit |= grep_sha1(opt, ce->sha1, ce->name, 0); + hit |= grep_sha1(opt, ce->sha1, ce->name, 0, ce->name); } else hit |= grep_file(opt, ce->name); @@ -444,7 +407,8 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int } static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, - struct tree_desc *tree, struct strbuf *base, int tn_len) + struct tree_desc *tree, struct strbuf *base, int tn_len, + int check_attr) { int hit = 0; enum interesting match = entry_not_interesting; @@ -465,7 +429,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, strbuf_add(base, entry.path, te_len); if (S_ISREG(entry.mode)) { - hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len); + hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len, + check_attr ? base->buf + tn_len : NULL); } else if (S_ISDIR(entry.mode)) { enum object_type type; @@ -480,7 +445,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, strbuf_addch(base, '/'); init_tree_desc(&sub, data, size); - hit |= grep_tree(opt, pathspec, &sub, base, tn_len); + hit |= grep_tree(opt, pathspec, &sub, base, tn_len, + check_attr); free(data); } strbuf_setlen(base, old_baselen); @@ -495,7 +461,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, struct object *obj, const char *name) { if (obj->type == OBJ_BLOB) - return grep_sha1(opt, obj->sha1, name, 0); + return grep_sha1(opt, obj->sha1, name, 0, NULL); if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) { struct tree_desc tree; void *data; @@ -518,7 +484,8 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, strbuf_addch(&base, ':'); } init_tree_desc(&tree, data, size); - hit = grep_tree(opt, pathspec, &tree, &base, base.len); + hit = grep_tree(opt, pathspec, &tree, &base, base.len, + obj->type == OBJ_COMMIT); strbuf_release(&base); free(data); return hit; @@ -669,95 +636,88 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int i; int dummy; int use_index = 1; - enum { - pattern_type_unspecified = 0, - pattern_type_bre, - pattern_type_ere, - pattern_type_fixed, - pattern_type_pcre, - }; - int pattern_type = pattern_type_unspecified; + int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED; struct option options[] = { OPT_BOOLEAN(0, "cached", &cached, - "search in index instead of in the work tree"), + N_("search in index instead of in the work tree")), OPT_NEGBIT(0, "no-index", &use_index, - "finds in contents not managed by git", 1), + N_("find in contents not managed by git"), 1), OPT_BOOLEAN(0, "untracked", &untracked, - "search in both tracked and untracked files"), + N_("search in both tracked and untracked files")), OPT_SET_INT(0, "exclude-standard", &opt_exclude, - "search also in ignored files", 1), + N_("search also in ignored files"), 1), OPT_GROUP(""), OPT_BOOLEAN('v', "invert-match", &opt.invert, - "show non-matching lines"), + N_("show non-matching lines")), OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case, - "case insensitive matching"), + N_("case insensitive matching")), OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp, - "match patterns only at word boundaries"), + N_("match patterns only at word boundaries")), OPT_SET_INT('a', "text", &opt.binary, - "process binary files as text", GREP_BINARY_TEXT), + N_("process binary files as text"), GREP_BINARY_TEXT), OPT_SET_INT('I', NULL, &opt.binary, - "don't match patterns in binary files", + N_("don't match patterns in binary files"), GREP_BINARY_NOMATCH), - { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, "depth", - "descend at most <depth> levels", PARSE_OPT_NONEG, + { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"), + N_("descend at most <depth> levels"), PARSE_OPT_NONEG, NULL, 1 }, OPT_GROUP(""), - OPT_SET_INT('E', "extended-regexp", &pattern_type, - "use extended POSIX regular expressions", - pattern_type_ere), - OPT_SET_INT('G', "basic-regexp", &pattern_type, - "use basic POSIX regular expressions (default)", - pattern_type_bre), - OPT_SET_INT('F', "fixed-strings", &pattern_type, - "interpret patterns as fixed strings", - pattern_type_fixed), - OPT_SET_INT('P', "perl-regexp", &pattern_type, - "use Perl-compatible regular expressions", - pattern_type_pcre), + OPT_SET_INT('E', "extended-regexp", &pattern_type_arg, + N_("use extended POSIX regular expressions"), + GREP_PATTERN_TYPE_ERE), + OPT_SET_INT('G', "basic-regexp", &pattern_type_arg, + N_("use basic POSIX regular expressions (default)"), + GREP_PATTERN_TYPE_BRE), + OPT_SET_INT('F', "fixed-strings", &pattern_type_arg, + N_("interpret patterns as fixed strings"), + GREP_PATTERN_TYPE_FIXED), + OPT_SET_INT('P', "perl-regexp", &pattern_type_arg, + N_("use Perl-compatible regular expressions"), + GREP_PATTERN_TYPE_PCRE), OPT_GROUP(""), - OPT_BOOLEAN('n', "line-number", &opt.linenum, "show line numbers"), - OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1), - OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1), + OPT_BOOLEAN('n', "line-number", &opt.linenum, N_("show line numbers")), + OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1), + OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1), OPT_NEGBIT(0, "full-name", &opt.relative, - "show filenames relative to top directory", 1), + N_("show filenames relative to top directory"), 1), OPT_BOOLEAN('l', "files-with-matches", &opt.name_only, - "show only filenames instead of matching lines"), + N_("show only filenames instead of matching lines")), OPT_BOOLEAN(0, "name-only", &opt.name_only, - "synonym for --files-with-matches"), + N_("synonym for --files-with-matches")), OPT_BOOLEAN('L', "files-without-match", &opt.unmatch_name_only, - "show only the names of files without match"), + N_("show only the names of files without match")), OPT_BOOLEAN('z', "null", &opt.null_following_name, - "print NUL after filenames"), + N_("print NUL after filenames")), OPT_BOOLEAN('c', "count", &opt.count, - "show the number of matches instead of matching lines"), - OPT__COLOR(&opt.color, "highlight matches"), + N_("show the number of matches instead of matching lines")), + OPT__COLOR(&opt.color, N_("highlight matches")), OPT_BOOLEAN(0, "break", &opt.file_break, - "print empty line between matches from different files"), + N_("print empty line between matches from different files")), OPT_BOOLEAN(0, "heading", &opt.heading, - "show filename only once above matches from same file"), + N_("show filename only once above matches from same file")), OPT_GROUP(""), - OPT_CALLBACK('C', "context", &opt, "n", - "show <n> context lines before and after matches", + OPT_CALLBACK('C', "context", &opt, N_("n"), + N_("show <n> context lines before and after matches"), context_callback), OPT_INTEGER('B', "before-context", &opt.pre_context, - "show <n> context lines before matches"), + N_("show <n> context lines before matches")), OPT_INTEGER('A', "after-context", &opt.post_context, - "show <n> context lines after matches"), - OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM", + N_("show <n> context lines after matches")), + OPT_NUMBER_CALLBACK(&opt, N_("shortcut for -C NUM"), context_callback), OPT_BOOLEAN('p', "show-function", &opt.funcname, - "show a line with the function name before matches"), + N_("show a line with the function name before matches")), OPT_BOOLEAN('W', "function-context", &opt.funcbody, - "show the surrounding function"), + N_("show the surrounding function")), OPT_GROUP(""), - OPT_CALLBACK('f', NULL, &opt, "file", - "read patterns from file", file_callback), - { OPTION_CALLBACK, 'e', NULL, &opt, "pattern", - "match <pattern>", PARSE_OPT_NONEG, pattern_callback }, + OPT_CALLBACK('f', NULL, &opt, N_("file"), + N_("read patterns from file"), file_callback), + { OPTION_CALLBACK, 'e', NULL, &opt, N_("pattern"), + N_("match <pattern>"), PARSE_OPT_NONEG, pattern_callback }, { OPTION_CALLBACK, 0, "and", &opt, NULL, - "combine patterns specified with -e", + N_("combine patterns specified with -e"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback }, OPT_BOOLEAN(0, "or", &dummy, ""), { OPTION_CALLBACK, 0, "not", &opt, NULL, "", @@ -769,16 +729,19 @@ int cmd_grep(int argc, const char **argv, const char *prefix) PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH, close_callback }, OPT__QUIET(&opt.status_only, - "indicate hit with exit status without output"), + N_("indicate hit with exit status without output")), OPT_BOOLEAN(0, "all-match", &opt.all_match, - "show only matches from files that match all patterns"), + N_("show only matches from files that match all patterns")), + { OPTION_SET_INT, 0, "debug", &opt.debug, NULL, + N_("show parse tree for grep expression"), + PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1 }, OPT_GROUP(""), { OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager, - "pager", "show matching files in the pager", + N_("pager"), N_("show matching files in the pager"), PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager }, OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored, - "allow calling of grep(1) (ignored by this build)"), - { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage", + N_("allow calling of grep(1) (ignored by this build)")), + { OPTION_CALLBACK, 0, "help-all", &options, NULL, N_("show usage"), PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback }, OPT_END() }; @@ -790,25 +753,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(grep_usage, options); - memset(&opt, 0, sizeof(opt)); - opt.prefix = prefix; - opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0; - opt.relative = 1; - opt.pathname = 1; - opt.pattern_tail = &opt.pattern_list; - opt.header_tail = &opt.header_list; - opt.regflags = REG_NEWLINE; - opt.max_depth = -1; - - strcpy(opt.color_context, ""); - strcpy(opt.color_filename, ""); - strcpy(opt.color_function, ""); - strcpy(opt.color_lineno, ""); - strcpy(opt.color_match, GIT_COLOR_BOLD_RED); - strcpy(opt.color_selected, ""); - strcpy(opt.color_sep, GIT_COLOR_CYAN); - opt.color = -1; - git_config(grep_config, &opt); + init_grep_defaults(); + git_config(grep_cmd_config, NULL); + grep_init(&opt, prefix); /* * If there is no -- then the paths must exist in the working @@ -824,28 +771,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_STOP_AT_NON_OPTION | PARSE_OPT_NO_INTERNAL_HELP); - switch (pattern_type) { - case pattern_type_fixed: - opt.fixed = 1; - opt.pcre = 0; - break; - case pattern_type_bre: - opt.fixed = 0; - opt.pcre = 0; - opt.regflags &= ~REG_EXTENDED; - break; - case pattern_type_ere: - opt.fixed = 0; - opt.pcre = 0; - opt.regflags |= REG_EXTENDED; - break; - case pattern_type_pcre: - opt.fixed = 0; - opt.pcre = 1; - break; - default: - break; /* nothing */ - } + grep_commit_pattern_type(pattern_type_arg, &opt); if (use_index && !startup_info->have_repository) /* die the same way as if we did it at the beginning */ diff --git a/builtin/hash-object.c b/builtin/hash-object.c index 33911fd5e..8d184f1a9 100644 --- a/builtin/hash-object.c +++ b/builtin/hash-object.c @@ -57,8 +57,8 @@ static void hash_stdin_paths(const char *type, int write_objects) } static const char * const hash_object_usage[] = { - "git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>...", - "git hash-object --stdin-paths < <list-of-paths>", + N_("git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>..."), + N_("git hash-object --stdin-paths < <list-of-paths>"), NULL }; @@ -69,12 +69,12 @@ static int stdin_paths; static const char *vpath; static const struct option hash_object_options[] = { - OPT_STRING('t', NULL, &type, "type", "object type"), - OPT_BOOLEAN('w', NULL, &write_object, "write the object into the object database"), - OPT_BOOLEAN( 0 , "stdin", &hashstdin, "read the object from stdin"), - OPT_BOOLEAN( 0 , "stdin-paths", &stdin_paths, "read file names from stdin"), - OPT_BOOLEAN( 0 , "no-filters", &no_filters, "store file as is without filters"), - OPT_STRING( 0 , "path", &vpath, "file", "process file as it were from this path"), + OPT_STRING('t', NULL, &type, N_("type"), N_("object type")), + OPT_BOOLEAN('w', NULL, &write_object, N_("write the object into the object database")), + OPT_BOOLEAN( 0 , "stdin", &hashstdin, N_("read the object from stdin")), + OPT_BOOLEAN( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")), + OPT_BOOLEAN( 0 , "no-filters", &no_filters, N_("store file as is without filters")), + OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")), OPT_END() }; diff --git a/builtin/help.c b/builtin/help.c index 43d3c8444..bd86253d8 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -12,6 +12,10 @@ #include "column.h" #include "help.h" +#ifndef DEFAULT_HELP_FORMAT +#define DEFAULT_HELP_FORMAT "man" +#endif + static struct man_viewer_list { struct man_viewer_list *next; char name[FLEX_ARRAY]; @@ -30,21 +34,23 @@ enum help_format { HELP_FORMAT_WEB }; +static const char *html_path; + static int show_all = 0; static unsigned int colopts; static enum help_format help_format = HELP_FORMAT_NONE; static struct option builtin_help_options[] = { - OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), - OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), - OPT_SET_INT('w', "web", &help_format, "show manual in web browser", + OPT_BOOLEAN('a', "all", &show_all, N_("print all available commands")), + OPT_SET_INT('m', "man", &help_format, N_("show man page"), HELP_FORMAT_MAN), + OPT_SET_INT('w', "web", &help_format, N_("show manual in web browser"), HELP_FORMAT_WEB), - OPT_SET_INT('i', "info", &help_format, "show info page", + OPT_SET_INT('i', "info", &help_format, N_("show info page"), HELP_FORMAT_INFO), OPT_END(), }; static const char * const builtin_help_usage[] = { - "git help [--all] [--man|--web|--info] [command]", + N_("git help [--all] [--man|--web|--info] [command]"), NULL }; @@ -261,6 +267,12 @@ static int git_help_config(const char *var, const char *value, void *cb) help_format = parse_help_format(value); return 0; } + if (!strcmp(var, "help.htmlpath")) { + if (!value) + return config_error_nonbool(var); + html_path = xstrdup(value); + return 0; + } if (!strcmp(var, "man.viewer")) { if (!value) return config_error_nonbool(var); @@ -383,12 +395,15 @@ static void show_info_page(const char *git_cmd) static void get_html_page_path(struct strbuf *page_path, const char *page) { struct stat st; - const char *html_path = system_path(GIT_HTML_PATH); + if (!html_path) + html_path = system_path(GIT_HTML_PATH); /* Check that we have a git documentation directory. */ - if (stat(mkpath("%s/git.html", html_path), &st) - || !S_ISREG(st.st_mode)) - die(_("'%s': not a documentation directory."), html_path); + if (!strstr(html_path, "://")) { + if (stat(mkpath("%s/git.html", html_path), &st) + || !S_ISREG(st.st_mode)) + die("'%s': not a documentation directory.", html_path); + } strbuf_init(page_path, 0); strbuf_addf(page_path, "%s/%s.html", html_path, page); @@ -447,6 +462,8 @@ int cmd_help(int argc, const char **argv, const char *prefix) if (parsed_help_format != HELP_FORMAT_NONE) help_format = parsed_help_format; + if (help_format == HELP_FORMAT_NONE) + help_format = parse_help_format(DEFAULT_HELP_FORMAT); alias = alias_lookup(argv[0]); if (alias && !is_git_command(argv[0])) { diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 470547835..43d364b8d 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -9,6 +9,7 @@ #include "progress.h" #include "fsck.h" #include "exec_cmd.h" +#include "streaming.h" #include "thread-utils.h" static const char index_pack_usage[] = @@ -290,7 +291,7 @@ static void parse_pack_header(void) if (hdr->hdr_signature != htonl(PACK_SIGNATURE)) die(_("pack signature mismatch")); if (!pack_version_ok(hdr->hdr_version)) - die("pack version %"PRIu32" unsupported", + die(_("pack version %"PRIu32" unsupported"), ntohl(hdr->hdr_version)); nr_objects = ntohl(hdr->hdr_entries); @@ -384,30 +385,62 @@ static void unlink_base_data(struct base_data *c) free_base_data(c); } -static void *unpack_entry_data(unsigned long offset, unsigned long size) +static int is_delta_type(enum object_type type) +{ + return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA); +} + +static void *unpack_entry_data(unsigned long offset, unsigned long size, + enum object_type type, unsigned char *sha1) { + static char fixed_buf[8192]; int status; git_zstream stream; - void *buf = xmalloc(size); + void *buf; + git_SHA_CTX c; + char hdr[32]; + int hdrlen; + + if (!is_delta_type(type)) { + hdrlen = sprintf(hdr, "%s %lu", typename(type), size) + 1; + git_SHA1_Init(&c); + git_SHA1_Update(&c, hdr, hdrlen); + } else + sha1 = NULL; + if (type == OBJ_BLOB && size > big_file_threshold) + buf = fixed_buf; + else + buf = xmalloc(size); memset(&stream, 0, sizeof(stream)); git_inflate_init(&stream); stream.next_out = buf; - stream.avail_out = size; + stream.avail_out = buf == fixed_buf ? sizeof(fixed_buf) : size; do { + unsigned char *last_out = stream.next_out; stream.next_in = fill(1); stream.avail_in = input_len; status = git_inflate(&stream, 0); use(input_len - stream.avail_in); + if (sha1) + git_SHA1_Update(&c, last_out, stream.next_out - last_out); + if (buf == fixed_buf) { + stream.next_out = buf; + stream.avail_out = sizeof(fixed_buf); + } } while (status == Z_OK); if (stream.total_out != size || status != Z_STREAM_END) bad_object(offset, _("inflate returned %d"), status); git_inflate_end(&stream); - return buf; + if (sha1) + git_SHA1_Final(sha1, &c); + return buf == fixed_buf ? NULL : buf; } -static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_base) +static void *unpack_raw_entry(struct object_entry *obj, + union delta_base *delta_base, + unsigned char *sha1) { unsigned char *p; unsigned long size, c; @@ -467,12 +500,14 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_ } obj->hdr_size = consumed_bytes - obj->idx.offset; - data = unpack_entry_data(obj->idx.offset, obj->size); + data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, sha1); obj->idx.crc32 = input_crc32; return data; } -static void *get_data_from_pack(struct object_entry *obj) +static void *unpack_data(struct object_entry *obj, + int (*consume)(const unsigned char *, unsigned long, void *), + void *cb_data) { off_t from = obj[0].idx.offset + obj[0].hdr_size; unsigned long len = obj[1].idx.offset - from; @@ -480,13 +515,13 @@ static void *get_data_from_pack(struct object_entry *obj) git_zstream stream; int status; - data = xmalloc(obj->size); + data = xmalloc(consume ? 64*1024 : obj->size); inbuf = xmalloc((len < 64*1024) ? len : 64*1024); memset(&stream, 0, sizeof(stream)); git_inflate_init(&stream); stream.next_out = data; - stream.avail_out = obj->size; + stream.avail_out = consume ? 64*1024 : obj->size; do { ssize_t n = (len < 64*1024) ? len : 64*1024; @@ -502,7 +537,20 @@ static void *get_data_from_pack(struct object_entry *obj) len -= n; stream.next_in = inbuf; stream.avail_in = n; - status = git_inflate(&stream, 0); + if (!consume) + status = git_inflate(&stream, 0); + else { + do { + status = git_inflate(&stream, 0); + if (consume(data, stream.next_out - data, cb_data)) { + free(inbuf); + free(data); + return NULL; + } + stream.next_out = data; + stream.avail_out = 64*1024; + } while (status == Z_OK && stream.avail_in); + } } while (len && status == Z_OK && !stream.avail_in); /* This has been inflated OK when first encountered, so... */ @@ -511,9 +559,18 @@ static void *get_data_from_pack(struct object_entry *obj) git_inflate_end(&stream); free(inbuf); + if (consume) { + free(data); + data = NULL; + } return data; } +static void *get_data_from_pack(struct object_entry *obj) +{ + return unpack_data(obj, NULL, NULL); +} + static int compare_delta_bases(const union delta_base *base1, const union delta_base *base2, enum object_type type1, @@ -568,25 +625,102 @@ static void find_delta_children(const union delta_base *base, *last_index = last; } -static void sha1_object(const void *data, unsigned long size, - enum object_type type, unsigned char *sha1) +struct compare_data { + struct object_entry *entry; + struct git_istream *st; + unsigned char *buf; + unsigned long buf_size; +}; + +static int compare_objects(const unsigned char *buf, unsigned long size, + void *cb_data) +{ + struct compare_data *data = cb_data; + + if (data->buf_size < size) { + free(data->buf); + data->buf = xmalloc(size); + data->buf_size = size; + } + + while (size) { + ssize_t len = read_istream(data->st, data->buf, size); + if (len == 0) + die(_("SHA1 COLLISION FOUND WITH %s !"), + sha1_to_hex(data->entry->idx.sha1)); + if (len < 0) + die(_("unable to read %s"), + sha1_to_hex(data->entry->idx.sha1)); + if (memcmp(buf, data->buf, len)) + die(_("SHA1 COLLISION FOUND WITH %s !"), + sha1_to_hex(data->entry->idx.sha1)); + size -= len; + buf += len; + } + return 0; +} + +static int check_collison(struct object_entry *entry) +{ + struct compare_data data; + enum object_type type; + unsigned long size; + + if (entry->size <= big_file_threshold || entry->type != OBJ_BLOB) + return -1; + + memset(&data, 0, sizeof(data)); + data.entry = entry; + data.st = open_istream(entry->idx.sha1, &type, &size, NULL); + if (!data.st) + return -1; + if (size != entry->size || type != entry->type) + die(_("SHA1 COLLISION FOUND WITH %s !"), + sha1_to_hex(entry->idx.sha1)); + unpack_data(entry, compare_objects, &data); + close_istream(data.st); + free(data.buf); + return 0; +} + +static void sha1_object(const void *data, struct object_entry *obj_entry, + unsigned long size, enum object_type type, + const unsigned char *sha1) { - hash_sha1_file(data, size, typename(type), sha1); + void *new_data = NULL; + int collision_test_needed; + + assert(data || obj_entry); + read_lock(); - if (has_sha1_file(sha1)) { + collision_test_needed = has_sha1_file(sha1); + read_unlock(); + + if (collision_test_needed && !data) { + read_lock(); + if (!check_collison(obj_entry)) + collision_test_needed = 0; + read_unlock(); + } + if (collision_test_needed) { void *has_data; enum object_type has_type; unsigned long has_size; + read_lock(); + has_type = sha1_object_info(sha1, &has_size); + if (has_type != type || has_size != size) + die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1)); has_data = read_sha1_file(sha1, &has_type, &has_size); read_unlock(); + if (!data) + data = new_data = get_data_from_pack(obj_entry); if (!has_data) die(_("cannot read existing object %s"), sha1_to_hex(sha1)); if (size != has_size || type != has_type || memcmp(data, has_data, size) != 0) die(_("SHA1 COLLISION FOUND WITH %s !"), sha1_to_hex(sha1)); free(has_data); - } else - read_unlock(); + } if (strict) { read_lock(); @@ -601,6 +735,9 @@ static void sha1_object(const void *data, unsigned long size, int eaten; void *buf = (void *) data; + if (!buf) + buf = new_data = get_data_from_pack(obj_entry); + /* * we do not need to free the memory here, as the * buf is deleted by the caller. @@ -625,11 +762,8 @@ static void sha1_object(const void *data, unsigned long size, } read_unlock(); } -} -static int is_delta_type(enum object_type type) -{ - return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA); + free(new_data); } /* @@ -711,7 +845,9 @@ static void resolve_delta(struct object_entry *delta_obj, free(delta_data); if (!result->data) bad_object(delta_obj->idx.offset, _("failed to apply delta")); - sha1_object(result->data, result->size, delta_obj->real_type, + hash_sha1_file(result->data, result->size, + typename(delta_obj->real_type), delta_obj->idx.sha1); + sha1_object(result->data, NULL, result->size, delta_obj->real_type, delta_obj->idx.sha1); counter_lock(); nr_resolved_deltas++; @@ -841,7 +977,7 @@ static void *threaded_second_pass(void *data) */ static void parse_pack_objects(unsigned char *sha1) { - int i; + int i, nr_delays = 0; struct delta_entry *delta = deltas; struct stat st; @@ -851,14 +987,18 @@ static void parse_pack_objects(unsigned char *sha1) nr_objects); for (i = 0; i < nr_objects; i++) { struct object_entry *obj = &objects[i]; - void *data = unpack_raw_entry(obj, &delta->base); + void *data = unpack_raw_entry(obj, &delta->base, obj->idx.sha1); obj->real_type = obj->type; if (is_delta_type(obj->type)) { nr_deltas++; delta->obj_no = i; delta++; + } else if (!data) { + /* large blobs, check later */ + obj->real_type = OBJ_BAD; + nr_delays++; } else - sha1_object(data, obj->size, obj->type, obj->idx.sha1); + sha1_object(data, NULL, obj->size, obj->type, obj->idx.sha1); free(data); display_progress(progress, i+1); } @@ -878,6 +1018,17 @@ static void parse_pack_objects(unsigned char *sha1) if (S_ISREG(st.st_mode) && lseek(input_fd, 0, SEEK_CUR) - input_len != st.st_size) die(_("pack has junk at the end")); + + for (i = 0; i < nr_objects; i++) { + struct object_entry *obj = &objects[i]; + if (obj->real_type != OBJ_BAD) + continue; + obj->real_type = obj->type; + sha1_object(NULL, obj, obj->size, obj->type, obj->idx.sha1); + nr_delays--; + } + if (nr_delays) + die(_("confusion beyond insanity in parse_pack_objects()")); } /* @@ -910,7 +1061,8 @@ static void resolve_deltas(void) int ret = pthread_create(&thread_data[i].thread, NULL, threaded_second_pass, thread_data + i); if (ret) - die("unable to create thread: %s", strerror(ret)); + die(_("unable to create thread: %s"), + strerror(ret)); } for (i = 0; i < nr_threads; i++) pthread_join(thread_data[i].thread, NULL); @@ -957,7 +1109,7 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha * sizeof(*objects)); f = sha1fd(output_fd, curr_pack); fix_unresolved_deltas(f, nr_unresolved); - sprintf(msg, "completed with %d local objects", + sprintf(msg, _("completed with %d local objects"), nr_objects - nr_objects_initial); stop_progress_msg(&progress, msg); sha1close(f, tail_sha1, 0); @@ -966,8 +1118,8 @@ static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned cha curr_pack, nr_objects, read_sha1, consumed_bytes-20); if (hashcmp(read_sha1, tail_sha1) != 0) - die("Unexpected tail checksum for %s " - "(disk corruption?)", curr_pack); + die(_("Unexpected tail checksum for %s " + "(disk corruption?)"), curr_pack); } if (nr_deltas != nr_resolved_deltas) die(Q_("pack has %d unresolved delta", @@ -1176,17 +1328,17 @@ static int git_index_pack_config(const char *k, const char *v, void *cb) if (!strcmp(k, "pack.indexversion")) { opts->version = git_config_int(k, v); if (opts->version > 2) - die("bad pack.indexversion=%"PRIu32, opts->version); + die(_("bad pack.indexversion=%"PRIu32), opts->version); return 0; } if (!strcmp(k, "pack.threads")) { nr_threads = git_config_int(k, v); if (nr_threads < 0) - die("invalid number of threads specified (%d)", + die(_("invalid number of threads specified (%d)"), nr_threads); #ifdef NO_PTHREADS if (nr_threads != 1) - warning("no threads support, ignoring %s", k); + warning(_("no threads support, ignoring %s"), k); nr_threads = 1; #endif return 0; @@ -1359,8 +1511,8 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix) usage(index_pack_usage); #ifdef NO_PTHREADS if (nr_threads != 1) - warning("no threads support, " - "ignoring %s", arg); + warning(_("no threads support, " + "ignoring %s"), arg); nr_threads = 1; #endif } else if (!prefixcmp(arg, "--pack_header=")) { diff --git a/builtin/init-db.c b/builtin/init-db.c index 0dacb8b79..78aa3872d 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -290,6 +290,7 @@ static int create_default_files(const char *template_path) strcpy(path + len, "CoNfIg"); if (!access(path, F_OK)) git_config_set("core.ignorecase", "true"); + probe_utf8_pathname_composition(path, len); } return reinit; @@ -463,7 +464,7 @@ static int shared_callback(const struct option *opt, const char *arg, int unset) } static const char *const init_db_usage[] = { - "git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]", + N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]"), NULL }; @@ -481,17 +482,17 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) const char *template_dir = NULL; unsigned int flags = 0; const struct option init_db_options[] = { - OPT_STRING(0, "template", &template_dir, "template-directory", - "directory from which templates will be used"), + OPT_STRING(0, "template", &template_dir, N_("template-directory"), + N_("directory from which templates will be used")), OPT_SET_INT(0, "bare", &is_bare_repository_cfg, - "create a bare repository", 1), + N_("create a bare repository"), 1), { OPTION_CALLBACK, 0, "shared", &init_shared_repository, - "permissions", - "specify that the git repository is to be shared amongst several users", + N_("permissions"), + N_("specify that the git repository is to be shared amongst several users"), PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0}, - OPT_BIT('q', "quiet", &flags, "be quiet", INIT_DB_QUIET), - OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir", - "separate git dir from working tree"), + OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET), + OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"), + N_("separate git dir from working tree")), OPT_END() }; diff --git a/builtin/log.c b/builtin/log.c index a8249d3c0..e7b7db1ca 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -21,6 +21,7 @@ #include "parse-options.h" #include "branch.h" #include "streaming.h" +#include "version.h" /* Set a default date-time format for git log ("log.date" config variable) */ static const char *default_date_mode = NULL; @@ -33,8 +34,8 @@ static const char *fmt_patch_subject_prefix = "PATCH"; static const char *fmt_pretty; static const char * const builtin_log_usage[] = { - "git log [<options>] [<since>..<until>] [[--] <path>...]\n" - " or: git show [options] <object>...", + N_("git log [<options>] [<since>..<until>] [[--] <path>...]\n") + N_(" or: git show [options] <object>..."), NULL }; @@ -96,9 +97,9 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix, int quiet = 0, source = 0; const struct option builtin_log_options[] = { - OPT_BOOLEAN(0, "quiet", &quiet, "suppress diff output"), - OPT_BOOLEAN(0, "source", &source, "show source"), - { OPTION_CALLBACK, 0, "decorate", NULL, NULL, "decorate options", + OPT_BOOLEAN(0, "quiet", &quiet, N_("suppress diff output")), + OPT_BOOLEAN(0, "source", &source, N_("show source")), + { OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"), PARSE_OPT_OPTARG, decorate_callback}, OPT_END() }; @@ -350,7 +351,8 @@ static int git_log_config(const char *var, const char *value, void *cb) } if (!prefixcmp(var, "color.decorate.")) return parse_decorate_color_config(var, 15, value); - + if (grep_config(var, value, cb) < 0) + return -1; return git_diff_ui_config(var, value, cb); } @@ -359,6 +361,7 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix) struct rev_info rev; struct setup_revision_opt opt; + init_grep_defaults(); git_config(git_log_config, NULL); init_revisions(&rev, prefix); @@ -366,6 +369,7 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix) rev.simplify_history = 0; memset(&opt, 0, sizeof(opt)); opt.def = "HEAD"; + opt.revarg_opt = REVARG_COMMITTISH; cmd_log_init(argc, argv, prefix, &rev, &opt); if (!rev.diffopt.output_format) rev.diffopt.output_format = DIFF_FORMAT_RAW; @@ -448,13 +452,14 @@ int cmd_show(int argc, const char **argv, const char *prefix) struct pathspec match_all; int i, count, ret = 0; + init_grep_defaults(); git_config(git_log_config, NULL); init_pathspec(&match_all, NULL); init_revisions(&rev, prefix); rev.diff = 1; rev.always_show_header = 1; - rev.no_walk = 1; + rev.no_walk = REVISION_WALK_NO_WALK_SORTED; rev.diffopt.stat_width = -1; /* Scale to real terminal size */ memset(&opt, 0, sizeof(opt)); @@ -528,6 +533,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix) struct rev_info rev; struct setup_revision_opt opt; + init_grep_defaults(); git_config(git_log_config, NULL); init_revisions(&rev, prefix); @@ -550,12 +556,14 @@ int cmd_log(int argc, const char **argv, const char *prefix) struct rev_info rev; struct setup_revision_opt opt; + init_grep_defaults(); git_config(git_log_config, NULL); init_revisions(&rev, prefix); rev.always_show_header = 1; memset(&opt, 0, sizeof(opt)); opt.def = "HEAD"; + opt.revarg_opt = REVARG_COMMITTISH; cmd_log_init(argc, argv, prefix, &rev, &opt); return cmd_log_walk(&rev); } @@ -693,7 +701,7 @@ static int reopen_stdout(struct commit *commit, const char *subject, return 0; } -static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const char *prefix) +static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids) { struct rev_info check_rev; struct commit *commit; @@ -714,7 +722,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const cha init_patch_ids(ids); /* given a range a..b get all patch ids for b..a */ - init_revisions(&check_rev, prefix); + init_revisions(&check_rev, rev->prefix); + check_rev.max_parents = 1; o1->flags ^= UNINTERESTING; o2->flags ^= UNINTERESTING; add_pending_object(&check_rev, o1, "o1"); @@ -723,10 +732,6 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const cha die(_("revision walk setup failed")); while ((commit = get_revision(&check_rev)) != NULL) { - /* ignore merges */ - if (commit->parents && commit->parents->next) - continue; - add_commit_patch_id(commit, ids); } @@ -887,7 +892,7 @@ static const char *set_outdir(const char *prefix, const char *output_directory) } static const char * const builtin_format_patch_usage[] = { - "git format-patch [options] [<since> | <revision range>]", + N_("git format-patch [options] [<since> | <revision range>]"), NULL }; @@ -1060,67 +1065,68 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) char *branch_name = NULL; const struct option builtin_format_patch_options[] = { { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL, - "use [PATCH n/m] even with a single patch", + N_("use [PATCH n/m] even with a single patch"), PARSE_OPT_NOARG, numbered_callback }, { OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL, - "use [PATCH] even with multiple patches", + N_("use [PATCH] even with multiple patches"), PARSE_OPT_NOARG, no_numbered_callback }, - OPT_BOOLEAN('s', "signoff", &do_signoff, "add Signed-off-by:"), + OPT_BOOLEAN('s', "signoff", &do_signoff, N_("add Signed-off-by:")), OPT_BOOLEAN(0, "stdout", &use_stdout, - "print patches to standard out"), + N_("print patches to standard out")), OPT_BOOLEAN(0, "cover-letter", &cover_letter, - "generate a cover letter"), + N_("generate a cover letter")), OPT_BOOLEAN(0, "numbered-files", &numbered_files, - "use simple number sequence for output file names"), - OPT_STRING(0, "suffix", &fmt_patch_suffix, "sfx", - "use <sfx> instead of '.patch'"), + N_("use simple number sequence for output file names")), + OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"), + N_("use <sfx> instead of '.patch'")), OPT_INTEGER(0, "start-number", &start_number, - "start numbering patches at <n> instead of 1"), - { OPTION_CALLBACK, 0, "subject-prefix", &rev, "prefix", - "Use [<prefix>] instead of [PATCH]", + N_("start numbering patches at <n> instead of 1")), + { OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"), + N_("Use [<prefix>] instead of [PATCH]"), PARSE_OPT_NONEG, subject_prefix_callback }, { OPTION_CALLBACK, 'o', "output-directory", &output_directory, - "dir", "store resulting files in <dir>", + N_("dir"), N_("store resulting files in <dir>"), PARSE_OPT_NONEG, output_directory_callback }, { OPTION_CALLBACK, 'k', "keep-subject", &rev, NULL, - "don't strip/add [PATCH]", + N_("don't strip/add [PATCH]"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback }, OPT_BOOLEAN(0, "no-binary", &no_binary_diff, - "don't output binary diffs"), + N_("don't output binary diffs")), OPT_BOOLEAN(0, "ignore-if-in-upstream", &ignore_if_in_upstream, - "don't include a patch matching a commit upstream"), + N_("don't include a patch matching a commit upstream")), { OPTION_BOOLEAN, 'p', "no-stat", &use_patch_format, NULL, - "show patch format instead of default (patch + stat)", + N_("show patch format instead of default (patch + stat)"), PARSE_OPT_NONEG | PARSE_OPT_NOARG }, - OPT_GROUP("Messaging"), - { OPTION_CALLBACK, 0, "add-header", NULL, "header", - "add email header", 0, header_callback }, - { OPTION_CALLBACK, 0, "to", NULL, "email", "add To: header", + OPT_GROUP(N_("Messaging")), + { OPTION_CALLBACK, 0, "add-header", NULL, N_("header"), + N_("add email header"), 0, header_callback }, + { OPTION_CALLBACK, 0, "to", NULL, N_("email"), N_("add To: header"), 0, to_callback }, - { OPTION_CALLBACK, 0, "cc", NULL, "email", "add Cc: header", + { OPTION_CALLBACK, 0, "cc", NULL, N_("email"), N_("add Cc: header"), 0, cc_callback }, - OPT_STRING(0, "in-reply-to", &in_reply_to, "message-id", - "make first mail a reply to <message-id>"), - { OPTION_CALLBACK, 0, "attach", &rev, "boundary", - "attach the patch", PARSE_OPT_OPTARG, + OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"), + N_("make first mail a reply to <message-id>")), + { OPTION_CALLBACK, 0, "attach", &rev, N_("boundary"), + N_("attach the patch"), PARSE_OPT_OPTARG, attach_callback }, - { OPTION_CALLBACK, 0, "inline", &rev, "boundary", - "inline the patch", + { OPTION_CALLBACK, 0, "inline", &rev, N_("boundary"), + N_("inline the patch"), PARSE_OPT_OPTARG | PARSE_OPT_NONEG, inline_callback }, - { OPTION_CALLBACK, 0, "thread", &thread, "style", - "enable message threading, styles: shallow, deep", + { OPTION_CALLBACK, 0, "thread", &thread, N_("style"), + N_("enable message threading, styles: shallow, deep"), PARSE_OPT_OPTARG, thread_callback }, - OPT_STRING(0, "signature", &signature, "signature", - "add a signature"), + OPT_STRING(0, "signature", &signature, N_("signature"), + N_("add a signature")), OPT_BOOLEAN(0, "quiet", &quiet, - "don't print the patch filenames"), + N_("don't print the patch filenames")), OPT_END() }; extra_hdr.strdup_strings = 1; extra_to.strdup_strings = 1; extra_cc.strdup_strings = 1; + init_grep_defaults(); git_config(git_format_config, NULL); init_revisions(&rev, prefix); rev.commit_format = CMIT_FMT_EMAIL; @@ -1131,6 +1137,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) rev.subject_prefix = fmt_patch_subject_prefix; memset(&s_r_opt, 0, sizeof(s_r_opt)); s_r_opt.def = "HEAD"; + s_r_opt.revarg_opt = REVARG_COMMITTISH; if (default_attach) { rev.mime_boundary = default_attach; @@ -1302,7 +1309,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0) return 0; } - get_patch_ids(&rev, &ids, prefix); + get_patch_ids(&rev, &ids); } if (!use_stdout) @@ -1439,7 +1446,7 @@ static int add_pending_commit(const char *arg, struct rev_info *revs, int flags) } static const char * const cherry_usage[] = { - "git cherry [-v] [<upstream> [<head> [<limit>]]]", + N_("git cherry [-v] [<upstream> [<head> [<limit>]]]"), NULL }; @@ -1473,7 +1480,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) struct option options[] = { OPT__ABBREV(&abbrev), - OPT__VERBOSE(&verbose, "be verbose"), + OPT__VERBOSE(&verbose, N_("be verbose")), OPT_END() }; @@ -1504,10 +1511,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) } init_revisions(&revs, prefix); - revs.diff = 1; - revs.combine_merges = 0; - revs.ignore_merges = 1; - DIFF_OPT_SET(&revs.diffopt, RECURSIVE); + revs.max_parents = 1; if (add_pending_commit(head, &revs, 0)) die(_("Unknown commit %s"), head); @@ -1521,7 +1525,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) return 0; } - get_patch_ids(&revs, &ids, prefix); + get_patch_ids(&revs, &ids); if (limit && add_pending_commit(limit, &revs, UNINTERESTING)) die(_("Unknown commit %s"), limit); @@ -1530,10 +1534,6 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) if (prepare_revision_walk(&revs)) die(_("revision walk setup failed")); while ((commit = get_revision(&revs)) != NULL) { - /* ignore merges */ - if (commit->parents && commit->parents->next) - continue; - commit_list_insert(commit, &list); } diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 31b3f2d90..b5434af0c 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -405,7 +405,7 @@ int report_path_error(const char *ps_matched, const char **pathspec, const char } static const char * const ls_files_usage[] = { - "git ls-files [options] [<file>...]", + N_("git ls-files [options] [<file>...]"), NULL }; @@ -457,57 +457,57 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) struct dir_struct dir; struct option builtin_ls_files_options[] = { { OPTION_CALLBACK, 'z', NULL, NULL, NULL, - "paths are separated with NUL character", + N_("paths are separated with NUL character"), PARSE_OPT_NOARG, option_parse_z }, OPT_BOOLEAN('t', NULL, &show_tag, - "identify the file status with tags"), + N_("identify the file status with tags")), OPT_BOOLEAN('v', NULL, &show_valid_bit, - "use lowercase letters for 'assume unchanged' files"), + N_("use lowercase letters for 'assume unchanged' files")), OPT_BOOLEAN('c', "cached", &show_cached, - "show cached files in the output (default)"), + N_("show cached files in the output (default)")), OPT_BOOLEAN('d', "deleted", &show_deleted, - "show deleted files in the output"), + N_("show deleted files in the output")), OPT_BOOLEAN('m', "modified", &show_modified, - "show modified files in the output"), + N_("show modified files in the output")), OPT_BOOLEAN('o', "others", &show_others, - "show other files in the output"), + N_("show other files in the output")), OPT_BIT('i', "ignored", &dir.flags, - "show ignored files in the output", + N_("show ignored files in the output"), DIR_SHOW_IGNORED), OPT_BOOLEAN('s', "stage", &show_stage, - "show staged contents' object name in the output"), + N_("show staged contents' object name in the output")), OPT_BOOLEAN('k', "killed", &show_killed, - "show files on the filesystem that need to be removed"), + N_("show files on the filesystem that need to be removed")), OPT_BIT(0, "directory", &dir.flags, - "show 'other' directories' name only", + N_("show 'other' directories' name only"), DIR_SHOW_OTHER_DIRECTORIES), OPT_NEGBIT(0, "empty-directory", &dir.flags, - "don't show empty directories", + N_("don't show empty directories"), DIR_HIDE_EMPTY_DIRECTORIES), OPT_BOOLEAN('u', "unmerged", &show_unmerged, - "show unmerged files in the output"), + N_("show unmerged files in the output")), OPT_BOOLEAN(0, "resolve-undo", &show_resolve_undo, - "show resolve-undo information"), - { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], "pattern", - "skip files matching pattern", + N_("show resolve-undo information")), + { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], N_("pattern"), + N_("skip files matching pattern"), 0, option_parse_exclude }, - { OPTION_CALLBACK, 'X', "exclude-from", &dir, "file", - "exclude patterns are read from <file>", + { OPTION_CALLBACK, 'X', "exclude-from", &dir, N_("file"), + N_("exclude patterns are read from <file>"), 0, option_parse_exclude_from }, - OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, "file", - "read additional per-directory exclude patterns in <file>"), + OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, N_("file"), + N_("read additional per-directory exclude patterns in <file>")), { OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL, - "add the standard git exclusions", + N_("add the standard git exclusions"), PARSE_OPT_NOARG, option_parse_exclude_standard }, { OPTION_SET_INT, 0, "full-name", &prefix_len, NULL, - "make the output relative to the project top directory", + N_("make the output relative to the project top directory"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL }, OPT_BOOLEAN(0, "error-unmatch", &error_unmatch, - "if any <file> is not in the index, treat this as an error"), - OPT_STRING(0, "with-tree", &with_tree, "tree-ish", - "pretend that paths removed since <tree-ish> are still present"), + N_("if any <file> is not in the index, treat this as an error")), + OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"), + N_("pretend that paths removed since <tree-ish> are still present")), OPT__ABBREV(&abbrev), - OPT_BOOLEAN(0, "debug", &debug_mode, "show debugging data"), + OPT_BOOLEAN(0, "debug", &debug_mode, N_("show debugging data")), OPT_END() }; diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c index 41c88a98a..25e83cfe9 100644 --- a/builtin/ls-remote.c +++ b/builtin/ls-remote.c @@ -5,7 +5,7 @@ static const char ls_remote_usage[] = "git ls-remote [--heads] [--tags] [-u <exec> | --upload-pack <exec>]\n" -" [-q|--quiet] [--exit-code] [<repository> [<refs>...]]"; +" [-q|--quiet] [--exit-code] [--get-url] [<repository> [<refs>...]]"; /* * Is there one among the list of patterns that match the tail part diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c index 6b666e1e8..235c17cc0 100644 --- a/builtin/ls-tree.c +++ b/builtin/ls-tree.c @@ -24,7 +24,7 @@ static int chomp_prefix; static const char *ls_tree_prefix; static const char * const ls_tree_usage[] = { - "git ls-tree [<options>] <tree-ish> [<path>...]", + N_("git ls-tree [<options>] <tree-ish> [<path>...]"), NULL }; @@ -122,25 +122,25 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix) struct tree *tree; int i, full_tree = 0; const struct option ls_tree_options[] = { - OPT_BIT('d', NULL, &ls_options, "only show trees", + OPT_BIT('d', NULL, &ls_options, N_("only show trees"), LS_TREE_ONLY), - OPT_BIT('r', NULL, &ls_options, "recurse into subtrees", + OPT_BIT('r', NULL, &ls_options, N_("recurse into subtrees"), LS_RECURSIVE), - OPT_BIT('t', NULL, &ls_options, "show trees when recursing", + OPT_BIT('t', NULL, &ls_options, N_("show trees when recursing"), LS_SHOW_TREES), OPT_SET_INT('z', NULL, &line_termination, - "terminate entries with NUL byte", 0), - OPT_BIT('l', "long", &ls_options, "include object size", + N_("terminate entries with NUL byte"), 0), + OPT_BIT('l', "long", &ls_options, N_("include object size"), LS_SHOW_SIZE), - OPT_BIT(0, "name-only", &ls_options, "list only filenames", + OPT_BIT(0, "name-only", &ls_options, N_("list only filenames"), LS_NAME_ONLY), - OPT_BIT(0, "name-status", &ls_options, "list only filenames", + OPT_BIT(0, "name-status", &ls_options, N_("list only filenames"), LS_NAME_ONLY), OPT_SET_INT(0, "full-name", &chomp_prefix, - "use full path names", 0), + N_("use full path names"), 0), OPT_BOOLEAN(0, "full-tree", &full_tree, - "list entire tree; not just current directory " - "(implies --full-name)"), + N_("list entire tree; not just current directory " + "(implies --full-name)")), OPT__ABBREV(&abbrev), OPT_END() }; diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c index eaf9e157a..24a772d8e 100644 --- a/builtin/mailinfo.c +++ b/builtin/mailinfo.c @@ -19,9 +19,6 @@ static struct strbuf email = STRBUF_INIT; static enum { TE_DONTCARE, TE_QP, TE_BASE64 } transfer_encoding; -static enum { - TYPE_TEXT, TYPE_OTHER -} message_type; static struct strbuf charset = STRBUF_INIT; static int patch_lines; @@ -160,10 +157,9 @@ static int slurp_attr(const char *line, const char *name, struct strbuf *attr) const char *ends, *ap = strcasestr(line, name); size_t sz; - if (!ap) { - strbuf_setlen(attr, 0); + strbuf_setlen(attr, 0); + if (!ap) return 0; - } ap += strlen(name); if (*ap == '"') { ap++; @@ -185,8 +181,6 @@ static void handle_content_type(struct strbuf *line) struct strbuf *boundary = xmalloc(sizeof(struct strbuf)); strbuf_init(boundary, line->len); - if (!strcasestr(line->buf, "text/")) - message_type = TYPE_OTHER; if (slurp_attr(line->buf, "boundary=", boundary)) { strbuf_insert(boundary, 0, "--", 2); if (++content_top > &content[MAX_BOUNDARIES]) { @@ -232,7 +226,9 @@ static void cleanup_subject(struct strbuf *subject) case 'r': case 'R': if (subject->len <= at + 3) break; - if (!memcmp(subject->buf + at + 1, "e:", 2)) { + if ((subject->buf[at + 1] == 'e' || + subject->buf[at + 1] == 'E') && + subject->buf[at + 2] == ':') { strbuf_remove(subject, at, 3); continue; } @@ -481,37 +477,14 @@ static struct strbuf *decode_b_segment(const struct strbuf *b_seg) return out; } -/* - * When there is no known charset, guess. - * - * Right now we assume that if the target is UTF-8 (the default), - * and it already looks like UTF-8 (which includes US-ASCII as its - * subset, of course) then that is what it is and there is nothing - * to do. - * - * Otherwise, we default to assuming it is Latin1 for historical - * reasons. - */ -static const char *guess_charset(const struct strbuf *line, const char *target_charset) -{ - if (is_encoding_utf8(target_charset)) { - if (is_utf8(line->buf)) - return NULL; - } - return "ISO8859-1"; -} - static void convert_to_utf8(struct strbuf *line, const char *charset) { char *out; - if (!charset || !*charset) { - charset = guess_charset(line, metainfo_charset); - if (!charset) - return; - } + if (!charset || !*charset) + return; - if (!strcasecmp(metainfo_charset, charset)) + if (same_encoding(metainfo_charset, charset)) return; out = reencode_string(line->buf, metainfo_charset, charset); if (!out) @@ -680,7 +653,6 @@ again: /* set some defaults */ transfer_encoding = TE_DONTCARE; strbuf_reset(&charset); - message_type = TYPE_TEXT; /* slurp in this section's info */ while (read_one_header_line(&line, fin)) @@ -894,11 +866,6 @@ static void handle_body(void) strbuf_insert(&line, 0, prev.buf, prev.len); strbuf_reset(&prev); - /* binary data most likely doesn't have newlines */ - if (message_type != TYPE_TEXT) { - handle_filter(&line); - break; - } /* * This is a decoded line that may contain * multiple new lines. Pass only one chunk diff --git a/builtin/merge-base.c b/builtin/merge-base.c index 4f30f1b0c..1bc799104 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -23,9 +23,10 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all) } static const char * const merge_base_usage[] = { - "git merge-base [-a|--all] <commit> <commit>...", - "git merge-base [-a|--all] --octopus <commit>...", - "git merge-base --independent <commit>...", + N_("git merge-base [-a|--all] <commit> <commit>..."), + N_("git merge-base [-a|--all] --octopus <commit>..."), + N_("git merge-base --independent <commit>..."), + N_("git merge-base --is-ancestor <commit> <commit>"), NULL }; @@ -70,6 +71,20 @@ static int handle_octopus(int count, const char **args, int reduce, int show_all return 0; } +static int handle_is_ancestor(int argc, const char **argv) +{ + struct commit *one, *two; + + if (argc != 2) + die("--is-ancestor takes exactly two commits"); + one = get_commit_reference(argv[0]); + two = get_commit_reference(argv[1]); + if (in_merge_bases(one, two)) + return 0; + else + return 1; +} + int cmd_merge_base(int argc, const char **argv, const char *prefix) { struct commit **rev; @@ -77,11 +92,14 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix) int show_all = 0; int octopus = 0; int reduce = 0; + int is_ancestor = 0; struct option options[] = { - OPT_BOOLEAN('a', "all", &show_all, "output all common ancestors"), - OPT_BOOLEAN(0, "octopus", &octopus, "find ancestors for a single n-way merge"), - OPT_BOOLEAN(0, "independent", &reduce, "list revs not reachable from others"), + OPT_BOOLEAN('a', "all", &show_all, N_("output all common ancestors")), + OPT_BOOLEAN(0, "octopus", &octopus, N_("find ancestors for a single n-way merge")), + OPT_BOOLEAN(0, "independent", &reduce, N_("list revs not reachable from others")), + OPT_BOOLEAN(0, "is-ancestor", &is_ancestor, + N_("is the first one ancestor of the other?")), OPT_END() }; @@ -89,6 +107,10 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0); if (!octopus && !reduce && argc < 2) usage_with_options(merge_base_usage, options); + if (is_ancestor && (show_all | octopus | reduce)) + die("--is-ancestor cannot be used with other options"); + if (is_ancestor) + return handle_is_ancestor(argc, argv); if (reduce && (show_all || octopus)) die("--independent cannot be used with other options"); diff --git a/builtin/merge-file.c b/builtin/merge-file.c index 6f0efef43..c0570f240 100644 --- a/builtin/merge-file.c +++ b/builtin/merge-file.c @@ -5,7 +5,7 @@ #include "parse-options.h" static const char *const merge_file_usage[] = { - "git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2", + N_("git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2"), NULL }; @@ -30,19 +30,19 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix) int quiet = 0; int prefixlen = 0; struct option options[] = { - OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"), - OPT_SET_INT(0, "diff3", &xmp.style, "use a diff3 based merge", XDL_MERGE_DIFF3), - OPT_SET_INT(0, "ours", &xmp.favor, "for conflicts, use our version", + OPT_BOOLEAN('p', "stdout", &to_stdout, N_("send results to standard output")), + OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3), + OPT_SET_INT(0, "ours", &xmp.favor, N_("for conflicts, use our version"), XDL_MERGE_FAVOR_OURS), - OPT_SET_INT(0, "theirs", &xmp.favor, "for conflicts, use their version", + OPT_SET_INT(0, "theirs", &xmp.favor, N_("for conflicts, use their version"), XDL_MERGE_FAVOR_THEIRS), - OPT_SET_INT(0, "union", &xmp.favor, "for conflicts, use a union version", + OPT_SET_INT(0, "union", &xmp.favor, N_("for conflicts, use a union version"), XDL_MERGE_FAVOR_UNION), OPT_INTEGER(0, "marker-size", &xmp.marker_size, - "for conflicts, use this marker size"), - OPT__QUIET(&quiet, "do not warn about conflicts"), - OPT_CALLBACK('L', NULL, names, "name", - "set labels for file1/orig_file/file2", &label_cb), + N_("for conflicts, use this marker size")), + OPT__QUIET(&quiet, N_("do not warn about conflicts")), + OPT_CALLBACK('L', NULL, names, N_("name"), + N_("set labels for file1/orig_file/file2"), &label_cb), OPT_END(), }; diff --git a/builtin/merge.c b/builtin/merge.c index e81fde6d7..3a31c4bc2 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -40,9 +40,9 @@ struct strategy { }; static const char * const builtin_merge_usage[] = { - "git merge [options] [<commit>...]", - "git merge [options] <msg> HEAD <commit>", - "git merge --abort", + N_("git merge [options] [<commit>...]"), + N_("git merge [options] <msg> HEAD <commit>"), + N_("git merge --abort"), NULL }; @@ -180,39 +180,39 @@ static int option_parse_n(const struct option *opt, static struct option builtin_merge_options[] = { { OPTION_CALLBACK, 'n', NULL, NULL, NULL, - "do not show a diffstat at the end of the merge", + N_("do not show a diffstat at the end of the merge"), PARSE_OPT_NOARG, option_parse_n }, OPT_BOOLEAN(0, "stat", &show_diffstat, - "show a diffstat at the end of the merge"), - OPT_BOOLEAN(0, "summary", &show_diffstat, "(synonym to --stat)"), - { OPTION_INTEGER, 0, "log", &shortlog_len, "n", - "add (at most <n>) entries from shortlog to merge commit message", + N_("show a diffstat at the end of the merge")), + OPT_BOOLEAN(0, "summary", &show_diffstat, N_("(synonym to --stat)")), + { OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"), + N_("add (at most <n>) entries from shortlog to merge commit message"), PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN }, OPT_BOOLEAN(0, "squash", &squash, - "create a single commit instead of doing a merge"), + N_("create a single commit instead of doing a merge")), OPT_BOOLEAN(0, "commit", &option_commit, - "perform a commit if the merge succeeds (default)"), + N_("perform a commit if the merge succeeds (default)")), OPT_BOOL('e', "edit", &option_edit, - "edit message before committing"), + N_("edit message before committing")), OPT_BOOLEAN(0, "ff", &allow_fast_forward, - "allow fast-forward (default)"), + N_("allow fast-forward (default)")), OPT_BOOLEAN(0, "ff-only", &fast_forward_only, - "abort if fast-forward is not possible"), + N_("abort if fast-forward is not possible")), OPT_RERERE_AUTOUPDATE(&allow_rerere_auto), - OPT_CALLBACK('s', "strategy", &use_strategies, "strategy", - "merge strategy to use", option_parse_strategy), - OPT_CALLBACK('X', "strategy-option", &xopts, "option=value", - "option for selected merge strategy", option_parse_x), - OPT_CALLBACK('m', "message", &merge_msg, "message", - "merge commit message (for a non-fast-forward merge)", + OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"), + N_("merge strategy to use"), option_parse_strategy), + OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"), + N_("option for selected merge strategy"), option_parse_x), + OPT_CALLBACK('m', "message", &merge_msg, N_("message"), + N_("merge commit message (for a non-fast-forward merge)"), option_parse_message), OPT__VERBOSITY(&verbosity), OPT_BOOLEAN(0, "abort", &abort_current_merge, - "abort the current in-progress merge"), - OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1), - { OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id", - "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, - OPT_BOOLEAN(0, "overwrite-ignore", &overwrite_ignore, "update ignored files (default)"), + N_("abort the current in-progress merge")), + OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1), + { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key id"), + N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, + OPT_BOOLEAN(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")), OPT_END() }; @@ -628,59 +628,6 @@ static void write_tree_trivial(unsigned char *sha1) die(_("git write-tree failed to write a tree")); } -static const char *merge_argument(struct commit *commit) -{ - if (commit) - return sha1_to_hex(commit->object.sha1); - else - return EMPTY_TREE_SHA1_HEX; -} - -int try_merge_command(const char *strategy, size_t xopts_nr, - const char **xopts, struct commit_list *common, - const char *head_arg, struct commit_list *remotes) -{ - const char **args; - int i = 0, x = 0, ret; - struct commit_list *j; - struct strbuf buf = STRBUF_INIT; - - args = xmalloc((4 + xopts_nr + commit_list_count(common) + - commit_list_count(remotes)) * sizeof(char *)); - strbuf_addf(&buf, "merge-%s", strategy); - args[i++] = buf.buf; - for (x = 0; x < xopts_nr; x++) { - char *s = xmalloc(strlen(xopts[x])+2+1); - strcpy(s, "--"); - strcpy(s+2, xopts[x]); - args[i++] = s; - } - for (j = common; j; j = j->next) - args[i++] = xstrdup(merge_argument(j->item)); - args[i++] = "--"; - args[i++] = head_arg; - for (j = remotes; j; j = j->next) - args[i++] = xstrdup(merge_argument(j->item)); - args[i] = NULL; - ret = run_command_v_opt(args, RUN_GIT_CMD); - strbuf_release(&buf); - i = 1; - for (x = 0; x < xopts_nr; x++) - free((void *)args[i++]); - for (j = common; j; j = j->next) - free((void *)args[i++]); - i += 2; - for (j = remotes; j; j = j->next) - free((void *)args[i++]); - free(args); - discard_cache(); - if (read_cache() < 0) - die(_("failed to read the cache")); - resolve_undo_clear(); - - return ret; -} - static int try_merge_strategy(const char *strategy, struct commit_list *common, struct commit_list *remoteheads, struct commit *head, const char *head_arg) @@ -762,56 +709,6 @@ static int count_unmerged_entries(void) return ret; } -int checkout_fast_forward(const unsigned char *head, const unsigned char *remote) -{ - struct tree *trees[MAX_UNPACK_TREES]; - struct unpack_trees_options opts; - struct tree_desc t[MAX_UNPACK_TREES]; - int i, fd, nr_trees = 0; - struct dir_struct dir; - struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); - - refresh_cache(REFRESH_QUIET); - - fd = hold_locked_index(lock_file, 1); - - memset(&trees, 0, sizeof(trees)); - memset(&opts, 0, sizeof(opts)); - memset(&t, 0, sizeof(t)); - if (overwrite_ignore) { - memset(&dir, 0, sizeof(dir)); - dir.flags |= DIR_SHOW_IGNORED; - setup_standard_excludes(&dir); - opts.dir = &dir; - } - - opts.head_idx = 1; - opts.src_index = &the_index; - opts.dst_index = &the_index; - opts.update = 1; - opts.verbose_update = 1; - opts.merge = 1; - opts.fn = twoway_merge; - setup_unpack_trees_porcelain(&opts, "merge"); - - trees[nr_trees] = parse_tree_indirect(head); - if (!trees[nr_trees++]) - return -1; - trees[nr_trees] = parse_tree_indirect(remote); - if (!trees[nr_trees++]) - return -1; - for (i = 0; i < nr_trees; i++) { - parse_tree(trees[i]); - init_tree_desc(t+i, trees[i]->buffer, trees[i]->size); - } - if (unpack_trees(nr_trees, t, &opts)) - return -1; - if (write_cache(fd, active_cache, active_nr) || - commit_locked_index(lock_file)) - die(_("unable to write new index file")); - return 0; -} - static void split_merge_strategies(const char *string, struct strategy **list, int *nr, int *alloc) { @@ -903,8 +800,9 @@ static void prepare_to_commit(struct commit_list *remoteheads) if (0 < option_edit) strbuf_add_lines(&msg, "# ", comment, strlen(comment)); write_merge_msg(&msg); - run_hook(get_index_file(), "prepare-commit-msg", - git_path("MERGE_MSG"), "merge", NULL, NULL); + if (run_hook(get_index_file(), "prepare-commit-msg", + git_path("MERGE_MSG"), "merge", NULL, NULL)) + abort_commit(remoteheads, NULL); if (0 < option_edit) { if (launch_editor(git_path("MERGE_MSG"), NULL, NULL)) abort_commit(remoteheads, NULL); @@ -1424,7 +1322,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix) } if (checkout_fast_forward(head_commit->object.sha1, - commit->object.sha1)) { + commit->object.sha1, + overwrite_ignore)) { ret = 1; goto done; } diff --git a/builtin/mktree.c b/builtin/mktree.c index 4ae1c412d..f92ba404a 100644 --- a/builtin/mktree.c +++ b/builtin/mktree.c @@ -64,7 +64,7 @@ static void write_tree(unsigned char *sha1) } static const char *mktree_usage[] = { - "git mktree [-z] [--missing] [--batch]", + N_("git mktree [-z] [--missing] [--batch]"), NULL }; @@ -150,9 +150,9 @@ int cmd_mktree(int ac, const char **av, const char *prefix) int got_eof = 0; const struct option option[] = { - OPT_SET_INT('z', NULL, &line_termination, "input is NUL terminated", '\0'), - OPT_SET_INT( 0 , "missing", &allow_missing, "allow missing objects", 1), - OPT_SET_INT( 0 , "batch", &is_batch_mode, "allow creation of more than one tree", 1), + OPT_SET_INT('z', NULL, &line_termination, N_("input is NUL terminated"), '\0'), + OPT_SET_INT( 0 , "missing", &allow_missing, N_("allow missing objects"), 1), + OPT_SET_INT( 0 , "batch", &is_batch_mode, N_("allow creation of more than one tree"), 1), OPT_END() }; diff --git a/builtin/mv.c b/builtin/mv.c index 2a144b011..034fec92a 100644 --- a/builtin/mv.c +++ b/builtin/mv.c @@ -11,7 +11,7 @@ #include "parse-options.h" static const char * const builtin_mv_usage[] = { - "git mv [options] <source>... <destination>", + N_("git mv [options] <source>... <destination>"), NULL }; @@ -59,10 +59,10 @@ int cmd_mv(int argc, const char **argv, const char *prefix) int i, newfd; int verbose = 0, show_only = 0, force = 0, ignore_errors = 0; struct option builtin_mv_options[] = { - OPT__VERBOSE(&verbose, "be verbose"), - OPT__DRY_RUN(&show_only, "dry run"), - OPT__FORCE(&force, "force move/rename even if target exists"), - OPT_BOOLEAN('k', NULL, &ignore_errors, "skip move/rename errors"), + OPT__VERBOSE(&verbose, N_("be verbose")), + OPT__DRY_RUN(&show_only, N_("dry run")), + OPT__FORCE(&force, N_("force move/rename even if target exists")), + OPT_BOOLEAN('k', NULL, &ignore_errors, N_("skip move/rename errors")), OPT_END(), }; const char **source, **destination, **dest_path; diff --git a/builtin/name-rev.c b/builtin/name-rev.c index 1b374583c..623824797 100644 --- a/builtin/name-rev.c +++ b/builtin/name-rev.c @@ -172,9 +172,9 @@ static void show_name(const struct object *obj, } static char const * const name_rev_usage[] = { - "git name-rev [options] <commit>...", - "git name-rev [options] --all", - "git name-rev [options] --stdin", + N_("git name-rev [options] <commit>..."), + N_("git name-rev [options] --all"), + N_("git name-rev [options] --stdin"), NULL }; @@ -226,16 +226,16 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix) int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0; struct name_ref_data data = { 0, 0, NULL }; struct option opts[] = { - OPT_BOOLEAN(0, "name-only", &data.name_only, "print only names (no SHA-1)"), - OPT_BOOLEAN(0, "tags", &data.tags_only, "only use tags to name the commits"), - OPT_STRING(0, "refs", &data.ref_filter, "pattern", - "only use refs matching <pattern>"), + OPT_BOOLEAN(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")), + OPT_BOOLEAN(0, "tags", &data.tags_only, N_("only use tags to name the commits")), + OPT_STRING(0, "refs", &data.ref_filter, N_("pattern"), + N_("only use refs matching <pattern>")), OPT_GROUP(""), - OPT_BOOLEAN(0, "all", &all, "list all commits reachable from all refs"), - OPT_BOOLEAN(0, "stdin", &transform_stdin, "read from stdin"), - OPT_BOOLEAN(0, "undefined", &allow_undefined, "allow to print `undefined` names"), + OPT_BOOLEAN(0, "all", &all, N_("list all commits reachable from all refs")), + OPT_BOOLEAN(0, "stdin", &transform_stdin, N_("read from stdin")), + OPT_BOOLEAN(0, "undefined", &allow_undefined, N_("allow to print `undefined` names")), OPT_BOOLEAN(0, "always", &always, - "show abbreviated commit object as fallback"), + N_("show abbreviated commit object as fallback")), OPT_END(), }; diff --git a/builtin/notes.c b/builtin/notes.c index 3644d140e..453457adb 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -19,72 +19,75 @@ #include "string-list.h" #include "notes-merge.h" +static void commit_notes(struct notes_tree *t, const char *msg); +static combine_notes_fn parse_combine_notes_fn(const char *v); + static const char * const git_notes_usage[] = { - "git notes [--ref <notes_ref>] [list [<object>]]", - "git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]", - "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>", - "git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]", - "git notes [--ref <notes_ref>] edit [<object>]", - "git notes [--ref <notes_ref>] show [<object>]", - "git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>", - "git notes merge --commit [-v | -q]", - "git notes merge --abort [-v | -q]", - "git notes [--ref <notes_ref>] remove [<object>...]", - "git notes [--ref <notes_ref>] prune [-n | -v]", - "git notes [--ref <notes_ref>] get-ref", + N_("git notes [--ref <notes_ref>] [list [<object>]]"), + N_("git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), + N_("git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"), + N_("git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), + N_("git notes [--ref <notes_ref>] edit [<object>]"), + N_("git notes [--ref <notes_ref>] show [<object>]"), + N_("git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"), + N_("git notes merge --commit [-v | -q]"), + N_("git notes merge --abort [-v | -q]"), + N_("git notes [--ref <notes_ref>] remove [<object>...]"), + N_("git notes [--ref <notes_ref>] prune [-n | -v]"), + N_("git notes [--ref <notes_ref>] get-ref"), NULL }; static const char * const git_notes_list_usage[] = { - "git notes [list [<object>]]", + N_("git notes [list [<object>]]"), NULL }; static const char * const git_notes_add_usage[] = { - "git notes add [<options>] [<object>]", + N_("git notes add [<options>] [<object>]"), NULL }; static const char * const git_notes_copy_usage[] = { - "git notes copy [<options>] <from-object> <to-object>", - "git notes copy --stdin [<from-object> <to-object>]...", + N_("git notes copy [<options>] <from-object> <to-object>"), + N_("git notes copy --stdin [<from-object> <to-object>]..."), NULL }; static const char * const git_notes_append_usage[] = { - "git notes append [<options>] [<object>]", + N_("git notes append [<options>] [<object>]"), NULL }; static const char * const git_notes_edit_usage[] = { - "git notes edit [<object>]", + N_("git notes edit [<object>]"), NULL }; static const char * const git_notes_show_usage[] = { - "git notes show [<object>]", + N_("git notes show [<object>]"), NULL }; static const char * const git_notes_merge_usage[] = { - "git notes merge [<options>] <notes_ref>", - "git notes merge --commit [<options>]", - "git notes merge --abort [<options>]", + N_("git notes merge [<options>] <notes_ref>"), + N_("git notes merge --commit [<options>]"), + N_("git notes merge --abort [<options>]"), NULL }; static const char * const git_notes_remove_usage[] = { - "git notes remove [<object>]", + N_("git notes remove [<object>]"), NULL }; static const char * const git_notes_prune_usage[] = { - "git notes prune [<options>]", + N_("git notes prune [<options>]"), NULL }; static const char * const git_notes_get_ref_usage[] = { - "git notes get-ref", + N_("git notes get-ref"), NULL }; @@ -288,7 +291,7 @@ static int parse_reedit_arg(const struct option *opt, const char *arg, int unset return parse_reuse_arg(opt, arg, unset); } -void commit_notes(struct notes_tree *t, const char *msg) +static void commit_notes(struct notes_tree *t, const char *msg) { struct strbuf buf = STRBUF_INIT; unsigned char commit_sha1[20]; @@ -312,7 +315,7 @@ void commit_notes(struct notes_tree *t, const char *msg) strbuf_release(&buf); } -combine_notes_fn parse_combine_notes_fn(const char *v) +static combine_notes_fn parse_combine_notes_fn(const char *v) { if (!strcasecmp(v, "overwrite")) return combine_notes_overwrite; @@ -531,19 +534,19 @@ static int add(int argc, const char **argv, const char *prefix) const unsigned char *note; struct msg_arg msg = { 0, 0, STRBUF_INIT }; struct option options[] = { - { OPTION_CALLBACK, 'm', "message", &msg, "msg", - "note contents as a string", PARSE_OPT_NONEG, + { OPTION_CALLBACK, 'm', "message", &msg, N_("message"), + N_("note contents as a string"), PARSE_OPT_NONEG, parse_msg_arg}, - { OPTION_CALLBACK, 'F', "file", &msg, "file", - "note contents in a file", PARSE_OPT_NONEG, + { OPTION_CALLBACK, 'F', "file", &msg, N_("file"), + N_("note contents in a file"), PARSE_OPT_NONEG, parse_file_arg}, - { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object", - "reuse and edit specified note object", PARSE_OPT_NONEG, + { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"), + N_("reuse and edit specified note object"), PARSE_OPT_NONEG, parse_reedit_arg}, - { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object", - "reuse specified note object", PARSE_OPT_NONEG, + { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"), + N_("reuse specified note object"), PARSE_OPT_NONEG, parse_reuse_arg}, - OPT__FORCE(&force, "replace existing notes"), + OPT__FORCE(&force, N_("replace existing notes")), OPT_END() }; @@ -611,11 +614,11 @@ static int copy(int argc, const char **argv, const char *prefix) struct notes_tree *t; const char *rewrite_cmd = NULL; struct option options[] = { - OPT__FORCE(&force, "replace existing notes"), - OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"), - OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command", - "load rewriting config for <command> (implies " - "--stdin)"), + OPT__FORCE(&force, N_("replace existing notes")), + OPT_BOOLEAN(0, "stdin", &from_stdin, N_("read objects from stdin")), + OPT_STRING(0, "for-rewrite", &rewrite_cmd, N_("command"), + N_("load rewriting config for <command> (implies " + "--stdin)")), OPT_END() }; @@ -688,17 +691,17 @@ static int append_edit(int argc, const char **argv, const char *prefix) const char * const *usage; struct msg_arg msg = { 0, 0, STRBUF_INIT }; struct option options[] = { - { OPTION_CALLBACK, 'm', "message", &msg, "msg", - "note contents as a string", PARSE_OPT_NONEG, + { OPTION_CALLBACK, 'm', "message", &msg, N_("message"), + N_("note contents as a string"), PARSE_OPT_NONEG, parse_msg_arg}, - { OPTION_CALLBACK, 'F', "file", &msg, "file", - "note contents in a file", PARSE_OPT_NONEG, + { OPTION_CALLBACK, 'F', "file", &msg, N_("file"), + N_("note contents in a file"), PARSE_OPT_NONEG, parse_file_arg}, - { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object", - "reuse and edit specified note object", PARSE_OPT_NONEG, + { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"), + N_("reuse and edit specified note object"), PARSE_OPT_NONEG, parse_reedit_arg}, - { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object", - "reuse specified note object", PARSE_OPT_NONEG, + { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"), + N_("reuse specified note object"), PARSE_OPT_NONEG, parse_reuse_arg}, OPT_END() }; @@ -861,19 +864,19 @@ static int merge(int argc, const char **argv, const char *prefix) int verbosity = 0, result; const char *strategy = NULL; struct option options[] = { - OPT_GROUP("General options"), + OPT_GROUP(N_("General options")), OPT__VERBOSITY(&verbosity), - OPT_GROUP("Merge options"), - OPT_STRING('s', "strategy", &strategy, "strategy", - "resolve notes conflicts using the given strategy " - "(manual/ours/theirs/union/cat_sort_uniq)"), - OPT_GROUP("Committing unmerged notes"), + OPT_GROUP(N_("Merge options")), + OPT_STRING('s', "strategy", &strategy, N_("strategy"), + N_("resolve notes conflicts using the given strategy " + "(manual/ours/theirs/union/cat_sort_uniq)")), + OPT_GROUP(N_("Committing unmerged notes")), { OPTION_BOOLEAN, 0, "commit", &do_commit, NULL, - "finalize notes merge by committing unmerged notes", + N_("finalize notes merge by committing unmerged notes"), PARSE_OPT_NOARG | PARSE_OPT_NONEG }, - OPT_GROUP("Aborting notes merge resolution"), + OPT_GROUP(N_("Aborting notes merge resolution")), { OPTION_BOOLEAN, 0, "abort", &do_abort, NULL, - "abort notes merge", + N_("abort notes merge"), PARSE_OPT_NOARG | PARSE_OPT_NONEG }, OPT_END() }; @@ -980,10 +983,10 @@ static int remove_cmd(int argc, const char **argv, const char *prefix) int from_stdin = 0; struct option options[] = { OPT_BIT(0, "ignore-missing", &flag, - "attempt to remove non-existent note is not an error", + N_("attempt to remove non-existent note is not an error"), IGNORE_MISSING), OPT_BOOLEAN(0, "stdin", &from_stdin, - "read object names from the standard input"), + N_("read object names from the standard input")), OPT_END() }; struct notes_tree *t; @@ -1064,8 +1067,8 @@ int cmd_notes(int argc, const char **argv, const char *prefix) int result; const char *override_notes_ref = NULL; struct option options[] = { - OPT_STRING(0, "ref", &override_notes_ref, "notes_ref", - "use notes from <notes_ref>"), + OPT_STRING(0, "ref", &override_notes_ref, N_("notes_ref"), + N_("use notes from <notes_ref>")), OPT_END() }; diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index ccfcbad14..f069462cb 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -16,11 +16,12 @@ #include "list-objects.h" #include "progress.h" #include "refs.h" +#include "streaming.h" #include "thread-utils.h" static const char *pack_usage[] = { - "git pack-objects --stdout [options...] [< ref-list | < object-list]", - "git pack-objects [options...] base-name [< ref-list | < object-list]", + N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"), + N_("git pack-objects [options...] base-name [< ref-list | < object-list]"), NULL }; @@ -150,6 +151,46 @@ static unsigned long do_compress(void **pptr, unsigned long size) return stream.total_out; } +static unsigned long write_large_blob_data(struct git_istream *st, struct sha1file *f, + const unsigned char *sha1) +{ + git_zstream stream; + unsigned char ibuf[1024 * 16]; + unsigned char obuf[1024 * 16]; + unsigned long olen = 0; + + memset(&stream, 0, sizeof(stream)); + git_deflate_init(&stream, pack_compression_level); + + for (;;) { + ssize_t readlen; + int zret = Z_OK; + readlen = read_istream(st, ibuf, sizeof(ibuf)); + if (readlen == -1) + die(_("unable to read %s"), sha1_to_hex(sha1)); + + stream.next_in = ibuf; + stream.avail_in = readlen; + while ((stream.avail_in || readlen == 0) && + (zret == Z_OK || zret == Z_BUF_ERROR)) { + stream.next_out = obuf; + stream.avail_out = sizeof(obuf); + zret = git_deflate(&stream, readlen ? 0 : Z_FINISH); + sha1write(f, obuf, stream.next_out - obuf); + olen += stream.next_out - obuf; + } + if (stream.avail_in) + die(_("deflate error (%d)"), zret); + if (readlen == 0) { + if (zret != Z_STREAM_END) + die(_("deflate error (%d)"), zret); + break; + } + } + git_deflate_end(&stream); + return olen; +} + /* * we are going to reuse the existing object data as is. make * sure it is not corrupt. @@ -208,11 +249,18 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent unsigned hdrlen; enum object_type type; void *buf; + struct git_istream *st = NULL; if (!usable_delta) { - buf = read_sha1_file(entry->idx.sha1, &type, &size); - if (!buf) - die("unable to read %s", sha1_to_hex(entry->idx.sha1)); + if (entry->type == OBJ_BLOB && + entry->size > big_file_threshold && + (st = open_istream(entry->idx.sha1, &type, &size, NULL)) != NULL) + buf = NULL; + else { + buf = read_sha1_file(entry->idx.sha1, &type, &size); + if (!buf) + die(_("unable to read %s"), sha1_to_hex(entry->idx.sha1)); + } /* * make sure no cached delta data remains from a * previous attempt before a pack split occurred. @@ -233,7 +281,9 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent OBJ_OFS_DELTA : OBJ_REF_DELTA; } - if (entry->z_delta_size) + if (st) /* large blob case, just assume we don't compress well */ + datalen = size; + else if (entry->z_delta_size) datalen = entry->z_delta_size; else datalen = do_compress(&buf, size); @@ -256,6 +306,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent while (ofs >>= 7) dheader[--pos] = 128 | (--ofs & 127); if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) { + if (st) + close_istream(st); free(buf); return 0; } @@ -268,6 +320,8 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent * an additional 20 bytes for the base sha1. */ if (limit && hdrlen + 20 + datalen + 20 >= limit) { + if (st) + close_istream(st); free(buf); return 0; } @@ -276,13 +330,20 @@ static unsigned long write_no_reuse_object(struct sha1file *f, struct object_ent hdrlen += 20; } else { if (limit && hdrlen + datalen + 20 >= limit) { + if (st) + close_istream(st); free(buf); return 0; } sha1write(f, header, hdrlen); } - sha1write(f, buf, datalen); - free(buf); + if (st) { + datalen = write_large_blob_data(st, f, entry->idx.sha1); + close_istream(st); + } else { + sha1write(f, buf, datalen); + free(buf); + } return hdrlen + datalen; } @@ -1972,7 +2033,6 @@ static int add_ref_tag(const char *path, const unsigned char *sha1, int flag, vo if (!prefixcmp(path, "refs/tags/") && /* is a tag? */ !peel_ref(path, peeled) && /* peelable? */ - !is_null_sha1(peeled) && /* annotated tag? */ locate_object_entry(peeled)) /* object packed? */ add_object_entry(sha1, OBJ_TAG, NULL, 0); return 0; @@ -2312,7 +2372,7 @@ static void get_object_list(int ac, const char **av) } die("not a rev '%s'", line); } - if (handle_revision_arg(line, &revs, flags, 1)) + if (handle_revision_arg(line, &revs, flags, REVARG_CANNOT_BE_FILENAME)) die("bad revision '%s'", line); } @@ -2384,67 +2444,67 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0; struct option pack_objects_options[] = { OPT_SET_INT('q', "quiet", &progress, - "do not show progress meter", 0), + N_("do not show progress meter"), 0), OPT_SET_INT(0, "progress", &progress, - "show progress meter", 1), + N_("show progress meter"), 1), OPT_SET_INT(0, "all-progress", &progress, - "show progress meter during object writing phase", 2), + N_("show progress meter during object writing phase"), 2), OPT_BOOL(0, "all-progress-implied", &all_progress_implied, - "similar to --all-progress when progress meter is shown"), - { OPTION_CALLBACK, 0, "index-version", NULL, "version[,offset]", - "write the pack index file in the specified idx format version", + N_("similar to --all-progress when progress meter is shown")), + { OPTION_CALLBACK, 0, "index-version", NULL, N_("version[,offset]"), + N_("write the pack index file in the specified idx format version"), 0, option_parse_index_version }, OPT_ULONG(0, "max-pack-size", &pack_size_limit, - "maximum size of each output pack file"), + N_("maximum size of each output pack file")), OPT_BOOL(0, "local", &local, - "ignore borrowed objects from alternate object store"), + N_("ignore borrowed objects from alternate object store")), OPT_BOOL(0, "incremental", &incremental, - "ignore packed objects"), + N_("ignore packed objects")), OPT_INTEGER(0, "window", &window, - "limit pack window by objects"), + N_("limit pack window by objects")), OPT_ULONG(0, "window-memory", &window_memory_limit, - "limit pack window by memory in addition to object limit"), + N_("limit pack window by memory in addition to object limit")), OPT_INTEGER(0, "depth", &depth, - "maximum length of delta chain allowed in the resulting pack"), + N_("maximum length of delta chain allowed in the resulting pack")), OPT_BOOL(0, "reuse-delta", &reuse_delta, - "reuse existing deltas"), + N_("reuse existing deltas")), OPT_BOOL(0, "reuse-object", &reuse_object, - "reuse existing objects"), + N_("reuse existing objects")), OPT_BOOL(0, "delta-base-offset", &allow_ofs_delta, - "use OFS_DELTA objects"), + N_("use OFS_DELTA objects")), OPT_INTEGER(0, "threads", &delta_search_threads, - "use threads when searching for best delta matches"), + N_("use threads when searching for best delta matches")), OPT_BOOL(0, "non-empty", &non_empty, - "do not create an empty pack output"), + N_("do not create an empty pack output")), OPT_BOOL(0, "revs", &use_internal_rev_list, - "read revision arguments from standard input"), + N_("read revision arguments from standard input")), { OPTION_SET_INT, 0, "unpacked", &rev_list_unpacked, NULL, - "limit the objects to those that are not yet packed", + N_("limit the objects to those that are not yet packed"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, { OPTION_SET_INT, 0, "all", &rev_list_all, NULL, - "include objects reachable from any reference", + N_("include objects reachable from any reference"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, { OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL, - "include objects referred by reflog entries", + N_("include objects referred by reflog entries"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, OPT_BOOL(0, "stdout", &pack_to_stdout, - "output pack to stdout"), + N_("output pack to stdout")), OPT_BOOL(0, "include-tag", &include_tag, - "include tag objects that refer to objects to be packed"), + N_("include tag objects that refer to objects to be packed")), OPT_BOOL(0, "keep-unreachable", &keep_unreachable, - "keep unreachable objects"), - { OPTION_CALLBACK, 0, "unpack-unreachable", NULL, "time", - "unpack unreachable objects newer than <time>", + N_("keep unreachable objects")), + { OPTION_CALLBACK, 0, "unpack-unreachable", NULL, N_("time"), + N_("unpack unreachable objects newer than <time>"), PARSE_OPT_OPTARG, option_parse_unpack_unreachable }, OPT_BOOL(0, "thin", &thin, - "create thin packs"), + N_("create thin packs")), OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep, - "ignore packs that have companion .keep file"), + N_("ignore packs that have companion .keep file")), OPT_INTEGER(0, "compression", &pack_compression_level, - "pack compression level"), + N_("pack compression level")), OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents, - "do not hide commits by grafts", 0), + N_("do not hide commits by grafts"), 0), OPT_END(), }; diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c index f5c6afc5d..649c3aaa9 100644 --- a/builtin/pack-redundant.c +++ b/builtin/pack-redundant.c @@ -301,14 +301,14 @@ static void pll_free(struct pll *l) */ static struct pll * get_permutations(struct pack_list *list, int n) { - struct pll *subset, *ret = NULL, *new_pll = NULL, *pll; + struct pll *subset, *ret = NULL, *new_pll = NULL; if (list == NULL || pack_list_size(list) < n || n == 0) return NULL; if (n == 1) { while (list) { - new_pll = xmalloc(sizeof(pll)); + new_pll = xmalloc(sizeof(*new_pll)); new_pll->pl = NULL; pack_list_insert(&new_pll->pl, list); new_pll->next = ret; @@ -321,7 +321,7 @@ static struct pll * get_permutations(struct pack_list *list, int n) while (list->next) { subset = get_permutations(list->next, n - 1); while (subset) { - new_pll = xmalloc(sizeof(pll)); + new_pll = xmalloc(sizeof(*new_pll)); new_pll->pl = subset->pl; pack_list_insert(&new_pll->pl, list); new_pll->next = ret; diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c index 39a9d89fb..b5a0f88eb 100644 --- a/builtin/pack-refs.c +++ b/builtin/pack-refs.c @@ -3,7 +3,7 @@ #include "pack-refs.h" static char const * const pack_refs_usage[] = { - "git pack-refs [options]", + N_("git pack-refs [options]"), NULL }; @@ -11,8 +11,8 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix) { unsigned int flags = PACK_REFS_PRUNE; struct option opts[] = { - OPT_BIT(0, "all", &flags, "pack everything", PACK_REFS_ALL), - OPT_BIT(0, "prune", &flags, "prune loose refs (default)", PACK_REFS_PRUNE), + OPT_BIT(0, "all", &flags, N_("pack everything"), PACK_REFS_ALL), + OPT_BIT(0, "prune", &flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE), OPT_END(), }; if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0)) diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c index b58a2e1eb..83382c1fe 100644 --- a/builtin/prune-packed.c +++ b/builtin/prune-packed.c @@ -4,7 +4,7 @@ #include "parse-options.h" static const char * const prune_packed_usage[] = { - "git prune-packed [-n|--dry-run] [-q|--quiet]", + N_("git prune-packed [-n|--dry-run] [-q|--quiet]"), NULL }; @@ -73,8 +73,8 @@ int cmd_prune_packed(int argc, const char **argv, const char *prefix) { int opts = isatty(2) ? VERBOSE : 0; const struct option prune_packed_options[] = { - OPT_BIT('n', "dry-run", &opts, "dry run", DRY_RUN), - OPT_NEGBIT('q', "quiet", &opts, "be quiet", VERBOSE), + OPT_BIT('n', "dry-run", &opts, N_("dry run"), DRY_RUN), + OPT_NEGBIT('q', "quiet", &opts, N_("be quiet"), VERBOSE), OPT_END() }; diff --git a/builtin/prune.c b/builtin/prune.c index b99b635e4..8cb8b9186 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -9,7 +9,7 @@ #include "dir.h" static const char * const prune_usage[] = { - "git prune [-n] [-v] [--expire <time>] [--] [<head>...]", + N_("git prune [-n] [-v] [--expire <time>] [--] [<head>...]"), NULL }; static int show_only; @@ -25,7 +25,8 @@ static int prune_tmp_object(const char *path, const char *filename) return error("Could not stat '%s'", fullpath); if (st.st_mtime > expire) return 0; - printf("Removing stale temporary file %s\n", fullpath); + if (show_only || verbose) + printf("Removing stale temporary file %s\n", fullpath); if (!show_only) unlink_or_warn(fullpath); return 0; @@ -128,11 +129,11 @@ int cmd_prune(int argc, const char **argv, const char *prefix) struct rev_info revs; struct progress *progress = NULL; const struct option options[] = { - OPT__DRY_RUN(&show_only, "do not remove, show only"), - OPT__VERBOSE(&verbose, "report pruned objects"), - OPT_BOOL(0, "progress", &show_progress, "show progress"), + OPT__DRY_RUN(&show_only, N_("do not remove, show only")), + OPT__VERBOSE(&verbose, N_("report pruned objects")), + OPT_BOOL(0, "progress", &show_progress, N_("show progress")), OPT_DATE(0, "expire", &expire, - "expire objects older than <time>"), + N_("expire objects older than <time>")), OPT_END() }; char *s; @@ -168,7 +169,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix) prune_packed_objects(show_only); remove_temporary_files(get_object_directory()); - s = xstrdup(mkpath("%s/pack", get_object_directory())); + s = mkpathdup("%s/pack", get_object_directory()); remove_temporary_files(s); free(s); return 0; diff --git a/builtin/push.c b/builtin/push.c index fdfcc6c71..db9ba30b0 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -11,7 +11,7 @@ #include "submodule.h" static const char * const push_usage[] = { - "git push [<options>] [<repository> [<refspec>...]]", + N_("git push [<options>] [<repository> [<refspec>...]]"), NULL, }; @@ -147,12 +147,37 @@ static void setup_push_upstream(struct remote *remote, int simple) add_refspec(refspec.buf); } +static char warn_unspecified_push_default_msg[] = +N_("push.default is unset; its implicit value is changing in\n" + "Git 2.0 from 'matching' to 'simple'. To squelch this message\n" + "and maintain the current behavior after the default changes, use:\n" + "\n" + " git config --global push.default matching\n" + "\n" + "To squelch this message and adopt the new behavior now, use:\n" + "\n" + " git config --global push.default simple\n" + "\n" + "See 'git help config' and search for 'push.default' for further information.\n" + "(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n" + "'current' instead of 'simple' if you sometimes use older versions of Git)"); + +static void warn_unspecified_push_default_configuration(void) +{ + static int warn_once; + + if (warn_once++) + return; + warning("%s\n", _(warn_unspecified_push_default_msg)); +} + static void setup_default_push_refspecs(struct remote *remote) { switch (push_default) { default: case PUSH_DEFAULT_UNSPECIFIED: default_matching_used = 1; + warn_unspecified_push_default_configuration(); /* fallthru */ case PUSH_DEFAULT_MATCHING: add_refspec(":"); @@ -186,8 +211,8 @@ static const char message_advice_pull_before_push[] = static const char message_advice_use_upstream[] = N_("Updates were rejected because a pushed branch tip is behind its remote\n" "counterpart. If you did not intend to push that branch, you may want to\n" - "specify branches to push or set the 'push.default' configuration\n" - "variable to 'current' or 'upstream' to push only the current branch."); + "specify branches to push or set the 'push.default' configuration variable\n" + "to 'simple', 'current' or 'upstream' to push only the current branch."); static const char message_advice_checkout_pull_push[] = N_("Updates were rejected because a pushed branch tip is behind its remote\n" @@ -354,25 +379,25 @@ int cmd_push(int argc, const char **argv, const char *prefix) const char *repo = NULL; /* default repository */ struct option options[] = { OPT__VERBOSITY(&verbosity), - OPT_STRING( 0 , "repo", &repo, "repository", "repository"), - OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL), - OPT_BIT( 0 , "mirror", &flags, "mirror all refs", + OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")), + OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL), + OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"), (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)), - OPT_BOOLEAN( 0, "delete", &deleterefs, "delete refs"), - OPT_BOOLEAN( 0 , "tags", &tags, "push tags (can't be used with --all or --mirror)"), - OPT_BIT('n' , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN), - OPT_BIT( 0, "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN), - OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE), - { OPTION_CALLBACK, 0, "recurse-submodules", &flags, "check", - "controls recursive pushing of submodules", + OPT_BOOLEAN( 0, "delete", &deleterefs, N_("delete refs")), + OPT_BOOLEAN( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")), + OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN), + OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN), + OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE), + { OPTION_CALLBACK, 0, "recurse-submodules", &flags, N_("check"), + N_("control recursive pushing of submodules"), PARSE_OPT_OPTARG, option_parse_recurse_submodules }, - OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"), - OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"), - OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"), - OPT_BIT('u', "set-upstream", &flags, "set upstream for git pull/status", + OPT_BOOLEAN( 0 , "thin", &thin, N_("use thin pack")), + OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", N_("receive pack program")), + OPT_STRING( 0 , "exec", &receivepack, "receive-pack", N_("receive pack program")), + OPT_BIT('u', "set-upstream", &flags, N_("set upstream for git pull/status"), TRANSPORT_PUSH_SET_UPSTREAM), - OPT_BOOL(0, "progress", &progress, "force progress reporting"), - OPT_BIT(0, "prune", &flags, "prune locally removed refs", + OPT_BOOL(0, "progress", &progress, N_("force progress reporting")), + OPT_BIT(0, "prune", &flags, N_("prune locally removed refs"), TRANSPORT_PUSH_PRUNE), OPT_END() }; diff --git a/builtin/read-tree.c b/builtin/read-tree.c index df6c4c881..042ac1b84 100644 --- a/builtin/read-tree.c +++ b/builtin/read-tree.c @@ -33,7 +33,7 @@ static int list_tree(unsigned char *sha1) } static const char * const read_tree_usage[] = { - "git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])", + N_("git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"), NULL }; @@ -104,37 +104,37 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) struct unpack_trees_options opts; int prefix_set = 0; const struct option read_tree_options[] = { - { OPTION_CALLBACK, 0, "index-output", NULL, "file", - "write resulting index to <file>", + { OPTION_CALLBACK, 0, "index-output", NULL, N_("file"), + N_("write resulting index to <file>"), PARSE_OPT_NONEG, index_output_cb }, OPT_SET_INT(0, "empty", &read_empty, - "only empty the index", 1), - OPT__VERBOSE(&opts.verbose_update, "be verbose"), - OPT_GROUP("Merging"), + N_("only empty the index"), 1), + OPT__VERBOSE(&opts.verbose_update, N_("be verbose")), + OPT_GROUP(N_("Merging")), OPT_SET_INT('m', NULL, &opts.merge, - "perform a merge in addition to a read", 1), + N_("perform a merge in addition to a read"), 1), OPT_SET_INT(0, "trivial", &opts.trivial_merges_only, - "3-way merge if no file level merging required", 1), + N_("3-way merge if no file level merging required"), 1), OPT_SET_INT(0, "aggressive", &opts.aggressive, - "3-way merge in presence of adds and removes", 1), + N_("3-way merge in presence of adds and removes"), 1), OPT_SET_INT(0, "reset", &opts.reset, - "same as -m, but discard unmerged entries", 1), - { OPTION_STRING, 0, "prefix", &opts.prefix, "<subdirectory>/", - "read the tree into the index under <subdirectory>/", + N_("same as -m, but discard unmerged entries"), 1), + { OPTION_STRING, 0, "prefix", &opts.prefix, N_("<subdirectory>/"), + N_("read the tree into the index under <subdirectory>/"), PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP }, OPT_SET_INT('u', NULL, &opts.update, - "update working tree with merge result", 1), + N_("update working tree with merge result"), 1), { OPTION_CALLBACK, 0, "exclude-per-directory", &opts, - "gitignore", - "allow explicitly ignored files to be overwritten", + 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, - "don't check the working tree after merging", 1), - OPT__DRY_RUN(&opts.dry_run, "don't update the index or the work tree"), + N_("don't check the working tree after merging"), 1), + 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, - "skip applying sparse checkout filter", 1), + N_("skip applying sparse checkout filter"), 1), OPT_SET_INT(0, "debug-unpack", &opts.debug_unpack, - "debug unpack-trees", 1), + N_("debug unpack-trees"), 1), OPT_END() }; diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 3f05d971e..ff781febc 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -12,6 +12,7 @@ #include "string-list.h" #include "sha1-array.h" #include "connected.h" +#include "version.h" static const char receive_pack_usage[] = "git receive-pack <git-dir>"; @@ -121,10 +122,11 @@ static void show_ref(const char *path, const unsigned char *sha1) if (sent_capabilities) packet_write(1, "%s %s\n", sha1_to_hex(sha1), path); else - packet_write(1, "%s %s%c%s%s\n", + packet_write(1, "%s %s%c%s%s agent=%s\n", sha1_to_hex(sha1), path, 0, " report-status delete-refs side-band-64k quiet", - prefer_ofs_delta ? " ofs-delta" : ""); + prefer_ofs_delta ? " ofs-delta" : "", + git_user_agent_sanitized()); sent_capabilities = 1; } @@ -478,7 +480,6 @@ static const char *update(struct command *cmd) !prefixcmp(name, "refs/heads/")) { struct object *old_object, *new_object; struct commit *old_commit, *new_commit; - struct commit_list *bases, *ent; old_object = parse_object(old_sha1); new_object = parse_object(new_sha1); @@ -491,12 +492,7 @@ static const char *update(struct command *cmd) } old_commit = (struct commit *)old_object; new_commit = (struct commit *)new_object; - bases = get_merge_bases(old_commit, new_commit, 1); - for (ent = bases; ent; ent = ent->next) - if (!hashcmp(old_sha1, ent->item->object.sha1)) - break; - free_commit_list(bases); - if (!ent) { + if (!in_merge_bases(old_commit, new_commit)) { rp_error("denying non-fast-forward %s" " (you should pull first)", name); return "non-fast-forward"; @@ -699,7 +695,7 @@ static void execute_commands(struct command *commands, const char *unpacker_erro if (unpacker_error) { for (cmd = commands; cmd; cmd = cmd->next) - cmd->error_string = "n/a (unpacker error)"; + cmd->error_string = "unpacker error"; return; } @@ -799,7 +795,7 @@ static const char *parse_pack_header(struct pack_header *hdr) static const char *pack_lockfile; -static const char *unpack(void) +static const char *unpack(int err_fd) { struct pack_header hdr; const char *hdr_err; @@ -819,6 +815,7 @@ static const char *unpack(void) if (ntohl(hdr.hdr_entries) < unpack_limit) { int code, i = 0; + struct child_process child; const char *unpacker[5]; unpacker[i++] = "unpack-objects"; if (quiet) @@ -827,7 +824,12 @@ static const char *unpack(void) unpacker[i++] = "--strict"; unpacker[i++] = hdr_arg; unpacker[i++] = NULL; - code = run_command_v_opt(unpacker, RUN_GIT_CMD); + memset(&child, 0, sizeof(child)); + child.argv = unpacker; + child.no_stdout = 1; + child.err = err_fd; + child.git_cmd = 1; + code = run_command(&child); if (!code) return NULL; return "unpack-objects abnormal exit"; @@ -852,6 +854,7 @@ static const char *unpack(void) memset(&ip, 0, sizeof(ip)); ip.argv = keeper; ip.out = -1; + ip.err = err_fd; ip.git_cmd = 1; status = start_command(&ip); if (status) { @@ -868,6 +871,26 @@ static const char *unpack(void) } } +static const char *unpack_with_sideband(void) +{ + struct async muxer; + const char *ret; + + if (!use_sideband) + return unpack(0); + + memset(&muxer, 0, sizeof(muxer)); + muxer.proc = copy_to_sideband; + muxer.in = -1; + if (start_async(&muxer)) + return NULL; + + ret = unpack(muxer.in); + + finish_async(&muxer); + return ret; +} + static void report(struct command *commands, const char *unpack_status) { struct command *cmd; @@ -965,7 +988,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) const char *unpack_status = NULL; if (!delete_only(commands)) - unpack_status = unpack(); + unpack_status = unpack_with_sideband(); execute_commands(commands, unpack_status); if (pack_lockfile) unlink_or_warn(pack_lockfile); diff --git a/builtin/reflog.c b/builtin/reflog.c index 062d7dad1..b3c9e27bd 100644 --- a/builtin/reflog.c +++ b/builtin/reflog.c @@ -330,8 +330,10 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1, printf("keep %s", message); return 0; prune: - if (!cb->newlog || cb->cmd->verbose) - printf("%sprune %s", cb->newlog ? "" : "would ", message); + if (!cb->newlog) + printf("would prune %s", message); + else if (cb->cmd->verbose) + printf("prune %s", message); return 0; } diff --git a/builtin/remote.c b/builtin/remote.c index 920262d76..937484d7c 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -8,66 +8,66 @@ #include "refs.h" static const char * const builtin_remote_usage[] = { - "git remote [-v | --verbose]", - "git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>", - "git remote rename <old> <new>", - "git remote rm <name>", - "git remote set-head <name> (-a | -d | <branch>)", - "git remote [-v | --verbose] show [-n] <name>", - "git remote prune [-n | --dry-run] <name>", - "git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]", - "git remote set-branches [--add] <name> <branch>...", - "git remote set-url [--push] <name> <newurl> [<oldurl>]", - "git remote set-url --add <name> <newurl>", - "git remote set-url --delete <name> <url>", + N_("git remote [-v | --verbose]"), + N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>"), + N_("git remote rename <old> <new>"), + N_("git remote remove <name>"), + N_("git remote set-head <name> (-a | -d | <branch>)"), + N_("git remote [-v | --verbose] show [-n] <name>"), + N_("git remote prune [-n | --dry-run] <name>"), + N_("git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"), + N_("git remote set-branches [--add] <name> <branch>..."), + N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"), + N_("git remote set-url --add <name> <newurl>"), + N_("git remote set-url --delete <name> <url>"), NULL }; static const char * const builtin_remote_add_usage[] = { - "git remote add [<options>] <name> <url>", + N_("git remote add [<options>] <name> <url>"), NULL }; static const char * const builtin_remote_rename_usage[] = { - "git remote rename <old> <new>", + N_("git remote rename <old> <new>"), NULL }; static const char * const builtin_remote_rm_usage[] = { - "git remote rm <name>", + N_("git remote remove <name>"), NULL }; static const char * const builtin_remote_sethead_usage[] = { - "git remote set-head <name> (-a | -d | <branch>])", + N_("git remote set-head <name> (-a | -d | <branch>)"), NULL }; static const char * const builtin_remote_setbranches_usage[] = { - "git remote set-branches <name> <branch>...", - "git remote set-branches --add <name> <branch>...", + N_("git remote set-branches <name> <branch>..."), + N_("git remote set-branches --add <name> <branch>..."), NULL }; static const char * const builtin_remote_show_usage[] = { - "git remote show [<options>] <name>", + N_("git remote show [<options>] <name>"), NULL }; static const char * const builtin_remote_prune_usage[] = { - "git remote prune [<options>] <name>", + N_("git remote prune [<options>] <name>"), NULL }; static const char * const builtin_remote_update_usage[] = { - "git remote update [<options>] [<group> | <remote>]...", + N_("git remote update [<options>] [<group> | <remote>]..."), NULL }; static const char * const builtin_remote_seturl_usage[] = { - "git remote set-url [--push] <name> <newurl> [<oldurl>]", - "git remote set-url --add <name> <newurl>", - "git remote set-url --delete <name> <url>", + N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"), + N_("git remote set-url --add <name> <newurl>"), + N_("git remote set-url --delete <name> <url>"), NULL }; @@ -160,17 +160,17 @@ static int add(int argc, const char **argv) int i; struct option options[] = { - OPT_BOOLEAN('f', "fetch", &fetch, "fetch the remote branches"), + OPT_BOOLEAN('f', "fetch", &fetch, N_("fetch the remote branches")), OPT_SET_INT(0, "tags", &fetch_tags, - "import all tags and associated objects when fetching", + N_("import all tags and associated objects when fetching"), TAGS_SET), OPT_SET_INT(0, NULL, &fetch_tags, - "or do not fetch any tag at all (--no-tags)", TAGS_UNSET), - OPT_STRING_LIST('t', "track", &track, "branch", - "branch(es) to track"), - OPT_STRING('m', "master", &master, "branch", "master branch"), - { OPTION_CALLBACK, 0, "mirror", &mirror, "push|fetch", - "set up remote as a mirror to push to or fetch from", + N_("or do not fetch any tag at all (--no-tags)"), TAGS_UNSET), + OPT_STRING_LIST('t', "track", &track, N_("branch"), + N_("branch(es) to track")), + OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")), + { OPTION_CALLBACK, 0, "mirror", &mirror, N_("push|fetch"), + N_("set up remote as a mirror to push to or fetch from"), PARSE_OPT_OPTARG, parse_mirror_opt }, OPT_END() }; @@ -1088,7 +1088,7 @@ static int show(int argc, const char **argv) { int no_query = 0, result = 0, query_flag = 0; struct option options[] = { - OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"), + OPT_BOOLEAN('n', NULL, &no_query, N_("do not query remotes")), OPT_END() }; struct ref_states states; @@ -1196,9 +1196,9 @@ static int set_head(int argc, const char **argv) struct option options[] = { OPT_BOOLEAN('a', "auto", &opt_a, - "set refs/remotes/<name>/HEAD according to remote"), + N_("set refs/remotes/<name>/HEAD according to remote")), OPT_BOOLEAN('d', "delete", &opt_d, - "delete refs/remotes/<name>/HEAD"), + N_("delete refs/remotes/<name>/HEAD")), OPT_END() }; argc = parse_options(argc, argv, NULL, options, builtin_remote_sethead_usage, @@ -1250,7 +1250,7 @@ static int prune(int argc, const char **argv) { int dry_run = 0, result = 0; struct option options[] = { - OPT__DRY_RUN(&dry_run, "dry run"), + OPT__DRY_RUN(&dry_run, N_("dry run")), OPT_END() }; @@ -1318,7 +1318,7 @@ static int update(int argc, const char **argv) int i, prune = 0; struct option options[] = { OPT_BOOLEAN('p', "prune", &prune, - "prune remotes after fetching"), + N_("prune remotes after fetching")), OPT_END() }; const char **fetch_argv; @@ -1404,7 +1404,7 @@ static int set_branches(int argc, const char **argv) { int add_mode = 0; struct option options[] = { - OPT_BOOLEAN('\0', "add", &add_mode, "add branch"), + OPT_BOOLEAN('\0', "add", &add_mode, N_("add branch")), OPT_END() }; @@ -1433,11 +1433,11 @@ static int set_url(int argc, const char **argv) struct strbuf name_buf = STRBUF_INIT; struct option options[] = { OPT_BOOLEAN('\0', "push", &push_mode, - "manipulate push URLs"), + N_("manipulate push URLs")), OPT_BOOLEAN('\0', "add", &add_mode, - "add URL"), + N_("add URL")), OPT_BOOLEAN('\0', "delete", &delete_mode, - "delete URLs"), + N_("delete URLs")), OPT_END() }; argc = parse_options(argc, argv, NULL, options, builtin_remote_seturl_usage, @@ -1566,7 +1566,7 @@ static int show_all(void) int cmd_remote(int argc, const char **argv, const char *prefix) { struct option options[] = { - OPT__VERBOSE(&verbose, "be verbose; must be placed before a subcommand"), + OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")), OPT_END() }; int result; @@ -1580,7 +1580,7 @@ int cmd_remote(int argc, const char **argv, const char *prefix) result = add(argc, argv); else if (!strcmp(argv[0], "rename")) result = mv(argc, argv); - else if (!strcmp(argv[0], "rm")) + else if (!strcmp(argv[0], "rm") || !strcmp(argv[0], "remove")) result = rm(argc, argv); else if (!strcmp(argv[0], "set-head")) result = set_head(argc, argv); diff --git a/builtin/replace.c b/builtin/replace.c index 4a8970e9c..398ccd5ea 100644 --- a/builtin/replace.c +++ b/builtin/replace.c @@ -14,9 +14,9 @@ #include "parse-options.h" static const char * const git_replace_usage[] = { - "git replace [-f] <object> <replacement>", - "git replace -d <object>...", - "git replace -l [<pattern>]", + N_("git replace [-f] <object> <replacement>"), + N_("git replace -d <object>..."), + N_("git replace -l [<pattern>]"), NULL }; @@ -46,24 +46,27 @@ typedef int (*each_replace_name_fn)(const char *name, const char *ref, static int for_each_replace_name(const char **argv, each_replace_name_fn fn) { - const char **p; + const char **p, *full_hex; char ref[PATH_MAX]; int had_error = 0; unsigned char sha1[20]; for (p = argv; *p; p++) { - if (snprintf(ref, sizeof(ref), "refs/replace/%s", *p) - >= sizeof(ref)) { - error("replace ref name too long: %.*s...", 50, *p); + if (get_sha1(*p, sha1)) { + error("Failed to resolve '%s' as a valid ref.", *p); had_error = 1; continue; } + full_hex = sha1_to_hex(sha1); + snprintf(ref, sizeof(ref), "refs/replace/%s", full_hex); + /* read_ref() may reuse the buffer */ + full_hex = ref + strlen("refs/replace/"); if (read_ref(ref, sha1)) { - error("replace ref '%s' not found.", *p); + error("replace ref '%s' not found.", full_hex); had_error = 1; continue; } - if (fn(*p, ref, sha1)) + if (fn(full_hex, ref, sha1)) had_error = 1; } return had_error; @@ -115,9 +118,9 @@ int cmd_replace(int argc, const char **argv, const char *prefix) { int list = 0, delete = 0, force = 0; struct option options[] = { - OPT_BOOLEAN('l', NULL, &list, "list replace refs"), - OPT_BOOLEAN('d', NULL, &delete, "delete replace refs"), - OPT_BOOLEAN('f', NULL, &force, "replace the ref if it exists"), + OPT_BOOLEAN('l', NULL, &list, N_("list replace refs")), + OPT_BOOLEAN('d', NULL, &delete, N_("delete replace refs")), + OPT_BOOLEAN('f', NULL, &force, N_("replace the ref if it exists")), OPT_END() }; diff --git a/builtin/rerere.c b/builtin/rerere.c index 08213c7c0..dc1708e6d 100644 --- a/builtin/rerere.c +++ b/builtin/rerere.c @@ -8,7 +8,7 @@ #include "xdiff-interface.h" static const char * const rerere_usage[] = { - "git rerere [clear | forget path... | status | remaining | diff | gc]", + N_("git rerere [clear | forget path... | status | remaining | diff | gc]"), NULL, }; @@ -53,7 +53,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix) struct option options[] = { OPT_SET_INT(0, "rerere-autoupdate", &autoupdate, - "register clean resolutions in index", 1), + N_("register clean resolutions in index"), 1), OPT_END(), }; diff --git a/builtin/reset.c b/builtin/reset.c index 4cc34c908..915cc9f86 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -22,9 +22,9 @@ #include "cache-tree.h" static const char * const git_reset_usage[] = { - "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]", - "git reset [-q] <commit> [--] <paths>...", - "git reset --patch [<commit>] [--] [<paths>...]", + N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"), + N_("git reset [-q] <commit> [--] <paths>..."), + N_("git reset --patch [<commit>] [--] [<paths>...]"), NULL }; @@ -235,17 +235,17 @@ int cmd_reset(int argc, const char **argv, const char *prefix) struct commit *commit; struct strbuf msg = STRBUF_INIT; const struct option options[] = { - OPT__QUIET(&quiet, "be quiet, only report errors"), + OPT__QUIET(&quiet, N_("be quiet, only report errors")), OPT_SET_INT(0, "mixed", &reset_type, - "reset HEAD and index", MIXED), - OPT_SET_INT(0, "soft", &reset_type, "reset only HEAD", SOFT), + N_("reset HEAD and index"), MIXED), + OPT_SET_INT(0, "soft", &reset_type, N_("reset only HEAD"), SOFT), OPT_SET_INT(0, "hard", &reset_type, - "reset HEAD, index and working tree", HARD), + N_("reset HEAD, index and working tree"), HARD), OPT_SET_INT(0, "merge", &reset_type, - "reset HEAD, index and working tree", MERGE), + N_("reset HEAD, index and working tree"), MERGE), OPT_SET_INT(0, "keep", &reset_type, - "reset HEAD but keep local changes", KEEP), - OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"), + N_("reset HEAD but keep local changes"), KEEP), + OPT_BOOLEAN('p', "patch", &patch_mode, N_("select hunks interactively")), OPT_END() }; @@ -276,7 +276,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) * Otherwise, argv[i] could be either <rev> or <paths> and * has to be unambiguous. */ - else if (!get_sha1(argv[i], sha1)) { + else if (!get_sha1_committish(argv[i], sha1)) { /* * Ok, argv[i] looks like a rev; it should not * be a filename. @@ -289,9 +289,15 @@ int cmd_reset(int argc, const char **argv, const char *prefix) } } - if (get_sha1(rev, sha1)) + if (get_sha1_committish(rev, sha1)) die(_("Failed to resolve '%s' as a valid ref."), rev); + /* + * NOTE: As "git reset $treeish -- $path" should be usable on + * any tree-ish, this is not strictly correct. We are not + * moving the HEAD to any commit; we are merely resetting the + * entries in the index to that of a treeish. + */ commit = lookup_commit_reference(sha1); if (!commit) die(_("Could not parse object '%s'."), rev); diff --git a/builtin/rev-list.c b/builtin/rev-list.c index ff5a38372..67701be55 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -201,55 +201,6 @@ static void show_edge(struct commit *commit) printf("-%s\n", sha1_to_hex(commit->object.sha1)); } -static inline int log2i(int n) -{ - int log2 = 0; - - for (; n > 1; n >>= 1) - log2++; - - return log2; -} - -static inline int exp2i(int n) -{ - return 1 << n; -} - -/* - * Estimate the number of bisect steps left (after the current step) - * - * For any x between 0 included and 2^n excluded, the probability for - * n - 1 steps left looks like: - * - * P(2^n + x) == (2^n - x) / (2^n + x) - * - * and P(2^n + x) < 0.5 means 2^n < 3x - */ -int estimate_bisect_steps(int all) -{ - int n, x, e; - - if (all < 3) - return 0; - - n = log2i(all); - e = exp2i(n); - x = all - e; - - return (e < 3 * x) ? n : n - 1; -} - -void print_commit_list(struct commit_list *list, - const char *format_cur, - const char *format_last) -{ - for ( ; list; list = list->next) { - const char *format = list->next ? format_cur : format_last; - printf(format, sha1_to_hex(list->item->object.sha1)); - } -} - static void print_var_str(const char *var, const char *val) { printf("%s='%s'\n", var, val); diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 47b4e7adb..f267a1d3b 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -195,6 +195,12 @@ static int anti_reference(const char *refname, const unsigned char *sha1, int fl return 0; } +static int show_abbrev(const unsigned char *sha1, void *cb_data) +{ + show_rev(NORMAL, sha1, NULL); + return 0; +} + static void show_datestring(const char *flag, const char *datestr) { static char buffer[100]; @@ -250,7 +256,7 @@ static int try_difference(const char *arg) return 0; } - if (!get_sha1(this, sha1) && !get_sha1(next, end)) { + if (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) { show_rev(NORMAL, end, next); show_rev(symmetric ? NORMAL : REVERSED, sha1, this); if (symmetric) { @@ -290,7 +296,7 @@ static int try_parent_shorthands(const char *arg) return 0; *dotdot = 0; - if (get_sha1(arg, sha1)) + if (get_sha1_committish(arg, sha1)) return 0; if (!parents_only) @@ -330,15 +336,15 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) { static int keep_dashdash = 0, stop_at_non_option = 0; static char const * const parseopt_usage[] = { - "git rev-parse --parseopt [options] -- [<args>...]", + N_("git rev-parse --parseopt [options] -- [<args>...]"), NULL }; static struct option parseopt_opts[] = { OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash, - "keep the `--` passed as an arg"), + N_("keep the `--` passed as an arg")), OPT_BOOLEAN(0, "stop-at-non-option", &stop_at_non_option, - "stop parsing after the " - "first non-option argument"), + N_("stop parsing after the " + "first non-option argument")), OPT_END(), }; @@ -455,11 +461,11 @@ static void die_no_single_rev(int quiet) } static const char builtin_rev_parse_usage[] = -"git rev-parse --parseopt [options] -- [<args>...]\n" -" or: git rev-parse --sq-quote [<arg>...]\n" -" or: git rev-parse [options] [<arg>...]\n" -"\n" -"Run \"git rev-parse --parseopt -h\" for more information on the first usage."; +N_("git rev-parse --parseopt [options] -- [<args>...]\n" + " or: git rev-parse --sq-quote [<arg>...]\n" + " or: git rev-parse [options] [<arg>...]\n" + "\n" + "Run \"git rev-parse --parseopt -h\" for more information on the first usage."); int cmd_rev_parse(int argc, const char **argv, const char *prefix) { @@ -601,6 +607,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) for_each_ref(show_reference, NULL); continue; } + if (!prefixcmp(arg, "--disambiguate=")) { + for_each_abbrev(arg + 15, show_abbrev, NULL); + continue; + } if (!strcmp(arg, "--bisect")) { for_each_ref_in("refs/bisect/bad", show_reference, NULL); for_each_ref_in("refs/bisect/good", anti_reference, NULL); diff --git a/builtin/revert.c b/builtin/revert.c index 82d1bf844..c5e36b94c 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -19,14 +19,14 @@ */ static const char * const revert_usage[] = { - "git revert [options] <commit-ish>", - "git revert <subcommand>", + N_("git revert [options] <commit-ish>"), + N_("git revert <subcommand>"), NULL }; static const char * const cherry_pick_usage[] = { - "git cherry-pick [options] <commit-ish>", - "git cherry-pick <subcommand>", + N_("git cherry-pick [options] <commit-ish>"), + N_("git cherry-pick <subcommand>"), NULL }; @@ -100,18 +100,19 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts) int contin = 0; int rollback = 0; struct option options[] = { - OPT_BOOLEAN(0, "quit", &remove_state, "end revert or cherry-pick sequence"), - OPT_BOOLEAN(0, "continue", &contin, "resume revert or cherry-pick sequence"), - OPT_BOOLEAN(0, "abort", &rollback, "cancel revert or cherry-pick sequence"), - OPT_BOOLEAN('n', "no-commit", &opts->no_commit, "don't automatically commit"), - OPT_BOOLEAN('e', "edit", &opts->edit, "edit the commit message"), + OPT_BOOLEAN(0, "quit", &remove_state, N_("end revert or cherry-pick sequence")), + OPT_BOOLEAN(0, "continue", &contin, N_("resume revert or cherry-pick sequence")), + OPT_BOOLEAN(0, "abort", &rollback, N_("cancel revert or cherry-pick sequence")), + OPT_BOOLEAN('n', "no-commit", &opts->no_commit, N_("don't automatically commit")), + OPT_BOOLEAN('e', "edit", &opts->edit, N_("edit the commit message")), OPT_NOOP_NOARG('r', NULL), - OPT_BOOLEAN('s', "signoff", &opts->signoff, "add Signed-off-by:"), - OPT_INTEGER('m', "mainline", &opts->mainline, "parent number"), + OPT_BOOLEAN('s', "signoff", &opts->signoff, N_("add Signed-off-by:")), + OPT_INTEGER('m', "mainline", &opts->mainline, N_("parent number")), OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto), - OPT_STRING(0, "strategy", &opts->strategy, "strategy", "merge strategy"), - OPT_CALLBACK('X', "strategy-option", &opts, "option", - "option for merge strategy", option_parse_x), + OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")), + OPT_CALLBACK('X', "strategy-option", &opts, N_("option"), + N_("option for merge strategy"), option_parse_x), + OPT_END(), OPT_END(), OPT_END(), OPT_END(), @@ -121,10 +122,11 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts) if (opts->action == REPLAY_PICK) { struct option cp_extra[] = { - OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"), - OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"), - OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve initially empty commits"), - OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_redundant_commits, "keep redundant, empty commits"), + OPT_BOOLEAN('x', NULL, &opts->record_origin, N_("append commit name")), + OPT_BOOLEAN(0, "ff", &opts->allow_ff, N_("allow fast-forward")), + OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")), + OPT_BOOLEAN(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")), + OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("keep redundant, empty commits")), OPT_END(), }; if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra)) @@ -193,7 +195,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts) struct setup_revision_opt s_r_opt; opts->revs = xmalloc(sizeof(*opts->revs)); init_revisions(opts->revs, NULL); - opts->revs->no_walk = 1; + opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED; if (argc < 2) usage_with_options(usage_str, options); memset(&s_r_opt, 0, sizeof(s_r_opt)); diff --git a/builtin/rm.c b/builtin/rm.c index 90c8a5047..dabfcf689 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -9,17 +9,67 @@ #include "cache-tree.h" #include "tree-walk.h" #include "parse-options.h" +#include "submodule.h" static const char * const builtin_rm_usage[] = { - "git rm [options] [--] <file>...", + N_("git rm [options] [--] <file>..."), NULL }; static struct { int nr, alloc; - const char **name; + struct { + const char *name; + char is_submodule; + } *entry; } list; +static int get_ours_cache_pos(const char *path, int pos) +{ + int i = -pos - 1; + + while ((i < active_nr) && !strcmp(active_cache[i]->name, path)) { + if (ce_stage(active_cache[i]) == 2) + return i; + i++; + } + return -1; +} + +static int check_submodules_use_gitfiles(void) +{ + int i; + int errs = 0; + + for (i = 0; i < list.nr; i++) { + const char *name = list.entry[i].name; + int pos; + struct cache_entry *ce; + struct stat st; + + pos = cache_name_pos(name, strlen(name)); + if (pos < 0) { + pos = get_ours_cache_pos(name, pos); + if (pos < 0) + continue; + } + ce = active_cache[pos]; + + if (!S_ISGITLINK(ce->ce_mode) || + (lstat(ce->name, &st) < 0) || + is_empty_dir(name)) + continue; + + if (!submodule_uses_gitfile(name)) + errs = error(_("submodule '%s' (or one of its nested " + "submodules) uses a .git directory\n" + "(use 'rm -rf' if you really want to remove " + "it including all of its history)"), name); + } + + return errs; +} + static int check_local_mod(unsigned char *head, int index_only) { /* @@ -37,15 +87,26 @@ static int check_local_mod(unsigned char *head, int index_only) struct stat st; int pos; struct cache_entry *ce; - const char *name = list.name[i]; + const char *name = list.entry[i].name; unsigned char sha1[20]; unsigned mode; int local_changes = 0; int staged_changes = 0; pos = cache_name_pos(name, strlen(name)); - if (pos < 0) - continue; /* removing unmerged entry */ + if (pos < 0) { + /* + * Skip unmerged entries except for populated submodules + * that could lose history when removed. + */ + pos = get_ours_cache_pos(name, pos); + if (pos < 0) + continue; + + if (!S_ISGITLINK(active_cache[pos]->ce_mode) || + is_empty_dir(name)) + continue; + } ce = active_cache[pos]; if (lstat(ce->name, &st) < 0) { @@ -58,9 +119,10 @@ static int check_local_mod(unsigned char *head, int index_only) /* if a file was removed and it is now a * directory, that is the same as ENOENT as * far as git is concerned; we do not track - * directories. + * directories unless they are submodules. */ - continue; + if (!S_ISGITLINK(ce->ce_mode)) + continue; } /* @@ -80,8 +142,11 @@ static int check_local_mod(unsigned char *head, int index_only) /* * Is the index different from the file in the work tree? + * If it's a submodule, is its work tree modified? */ - if (ce_match_stat(ce, &st, 0)) + if (ce_match_stat(ce, &st, 0) || + (S_ISGITLINK(ce->ce_mode) && + !ok_to_remove_submodule(ce->name))) local_changes = 1; /* @@ -115,10 +180,18 @@ static int check_local_mod(unsigned char *head, int index_only) errs = error(_("'%s' has changes staged in the index\n" "(use --cached to keep the file, " "or -f to force removal)"), name); - if (local_changes) - errs = error(_("'%s' has local modifications\n" - "(use --cached to keep the file, " - "or -f to force removal)"), name); + if (local_changes) { + if (S_ISGITLINK(ce->ce_mode) && + !submodule_uses_gitfile(name)) { + errs = error(_("submodule '%s' (or one of its nested " + "submodules) uses a .git directory\n" + "(use 'rm -rf' if you really want to remove " + "it including all of its history)"), name); + } else + errs = error(_("'%s' has local modifications\n" + "(use --cached to keep the file, " + "or -f to force removal)"), name); + } } } return errs; @@ -130,13 +203,13 @@ static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0; static int ignore_unmatch = 0; static struct option builtin_rm_options[] = { - OPT__DRY_RUN(&show_only, "dry run"), - OPT__QUIET(&quiet, "do not list removed files"), - OPT_BOOLEAN( 0 , "cached", &index_only, "only remove from the index"), - OPT__FORCE(&force, "override the up-to-date check"), - OPT_BOOLEAN('r', NULL, &recursive, "allow recursive removal"), + OPT__DRY_RUN(&show_only, N_("dry run")), + OPT__QUIET(&quiet, N_("do not list removed files")), + OPT_BOOLEAN( 0 , "cached", &index_only, N_("only remove from the index")), + OPT__FORCE(&force, N_("override the up-to-date check")), + OPT_BOOLEAN('r', NULL, &recursive, N_("allow recursive removal")), OPT_BOOLEAN( 0 , "ignore-unmatch", &ignore_unmatch, - "exit with a zero status even if nothing matched"), + N_("exit with a zero status even if nothing matched")), OPT_END(), }; @@ -161,6 +234,21 @@ int cmd_rm(int argc, const char **argv, const char *prefix) if (read_cache() < 0) die(_("index file corrupt")); + /* + * Drop trailing directory separators from directories so we'll find + * submodules in the index. + */ + for (i = 0; i < argc; i++) { + size_t pathlen = strlen(argv[i]); + if (pathlen && is_dir_sep(argv[i][pathlen - 1]) && + is_directory(argv[i])) { + do { + pathlen--; + } while (pathlen && is_dir_sep(argv[i][pathlen - 1])); + argv[i] = xmemdupz(argv[i], pathlen); + } + } + pathspec = get_pathspec(prefix, argv); refresh_index(&the_index, REFRESH_QUIET, pathspec, NULL, NULL); @@ -173,8 +261,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix) struct cache_entry *ce = active_cache[i]; if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen)) continue; - ALLOC_GROW(list.name, list.nr + 1, list.alloc); - list.name[list.nr++] = ce->name; + ALLOC_GROW(list.entry, list.nr + 1, list.alloc); + list.entry[list.nr].name = ce->name; + list.entry[list.nr++].is_submodule = S_ISGITLINK(ce->ce_mode); } if (pathspec) { @@ -215,6 +304,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix) hashclr(sha1); if (check_local_mod(sha1, index_only)) exit(1); + } else if (!index_only) { + if (check_submodules_use_gitfiles()) + exit(1); } /* @@ -222,7 +314,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) * the index unless all of them succeed. */ for (i = 0; i < list.nr; i++) { - const char *path = list.name[i]; + const char *path = list.entry[i].name; if (!quiet) printf("rm '%s'\n", path); @@ -244,7 +336,25 @@ int cmd_rm(int argc, const char **argv, const char *prefix) if (!index_only) { int removed = 0; for (i = 0; i < list.nr; i++) { - const char *path = list.name[i]; + const char *path = list.entry[i].name; + if (list.entry[i].is_submodule) { + if (is_empty_dir(path)) { + if (!rmdir(path)) { + removed = 1; + continue; + } + } else { + struct strbuf buf = STRBUF_INIT; + strbuf_addstr(&buf, path); + if (!remove_dir_recursively(&buf, 0)) { + removed = 1; + strbuf_release(&buf); + continue; + } + strbuf_release(&buf); + /* Fallthrough and let remove_path() fail. */ + } + } if (!remove_path(path)) { removed = 1; continue; diff --git a/builtin/send-pack.c b/builtin/send-pack.c index d5d7105ba..d34201372 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -8,6 +8,7 @@ #include "send-pack.h" #include "quote.h" #include "transport.h" +#include "version.h" static const char send_pack_usage[] = "git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" @@ -15,164 +16,6 @@ static const char send_pack_usage[] = static struct send_pack_args args; -static int feed_object(const unsigned char *sha1, int fd, int negative) -{ - char buf[42]; - - if (negative && !has_sha1_file(sha1)) - return 1; - - memcpy(buf + negative, sha1_to_hex(sha1), 40); - if (negative) - buf[0] = '^'; - buf[40 + negative] = '\n'; - return write_or_whine(fd, buf, 41 + negative, "send-pack: send refs"); -} - -/* - * Make a pack stream and spit it out into file descriptor fd - */ -static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args) -{ - /* - * The child becomes pack-objects --revs; we feed - * the revision parameters to it via its stdin and - * let its stdout go back to the other end. - */ - const char *argv[] = { - "pack-objects", - "--all-progress-implied", - "--revs", - "--stdout", - NULL, - NULL, - NULL, - NULL, - NULL, - }; - struct child_process po; - int i; - - i = 4; - if (args->use_thin_pack) - argv[i++] = "--thin"; - if (args->use_ofs_delta) - argv[i++] = "--delta-base-offset"; - if (args->quiet || !args->progress) - argv[i++] = "-q"; - if (args->progress) - argv[i++] = "--progress"; - memset(&po, 0, sizeof(po)); - po.argv = argv; - po.in = -1; - po.out = args->stateless_rpc ? -1 : fd; - po.git_cmd = 1; - if (start_command(&po)) - die_errno("git pack-objects failed"); - - /* - * We feed the pack-objects we just spawned with revision - * parameters by writing to the pipe. - */ - for (i = 0; i < extra->nr; i++) - if (!feed_object(extra->array[i], po.in, 1)) - break; - - while (refs) { - if (!is_null_sha1(refs->old_sha1) && - !feed_object(refs->old_sha1, po.in, 1)) - break; - if (!is_null_sha1(refs->new_sha1) && - !feed_object(refs->new_sha1, po.in, 0)) - break; - refs = refs->next; - } - - close(po.in); - - if (args->stateless_rpc) { - char *buf = xmalloc(LARGE_PACKET_MAX); - while (1) { - ssize_t n = xread(po.out, buf, LARGE_PACKET_MAX); - if (n <= 0) - break; - send_sideband(fd, -1, buf, n, LARGE_PACKET_MAX); - } - free(buf); - close(po.out); - po.out = -1; - } - - if (finish_command(&po)) - return -1; - return 0; -} - -static int receive_status(int in, struct ref *refs) -{ - struct ref *hint; - char line[1000]; - int ret = 0; - int len = packet_read_line(in, line, sizeof(line)); - if (len < 10 || memcmp(line, "unpack ", 7)) - return error("did not receive remote status"); - if (memcmp(line, "unpack ok\n", 10)) { - char *p = line + strlen(line) - 1; - if (*p == '\n') - *p = '\0'; - error("unpack failed: %s", line + 7); - ret = -1; - } - hint = NULL; - while (1) { - char *refname; - char *msg; - len = packet_read_line(in, line, sizeof(line)); - if (!len) - break; - if (len < 3 || - (memcmp(line, "ok ", 3) && memcmp(line, "ng ", 3))) { - fprintf(stderr, "protocol error: %s\n", line); - ret = -1; - break; - } - - line[strlen(line)-1] = '\0'; - refname = line + 3; - msg = strchr(refname, ' '); - if (msg) - *msg++ = '\0'; - - /* first try searching at our hint, falling back to all refs */ - if (hint) - hint = find_ref_by_name(hint, refname); - if (!hint) - hint = find_ref_by_name(refs, refname); - if (!hint) { - warning("remote reported status on unknown ref: %s", - refname); - continue; - } - if (hint->status != REF_STATUS_EXPECTING_REPORT) { - warning("remote reported status on unexpected ref: %s", - refname); - continue; - } - - if (line[0] == 'o' && line[1] == 'k') - hint->status = REF_STATUS_OK; - else { - hint->status = REF_STATUS_REMOTE_REJECT; - ret = -1; - } - if (msg) - hint->remote_status = xstrdup(msg); - /* start our next search from the next ref */ - hint = hint->next; - } - return ret; -} - static void print_helper_status(struct ref *ref) { struct strbuf buf = STRBUF_INIT; @@ -226,173 +69,6 @@ static void print_helper_status(struct ref *ref) strbuf_release(&buf); } -static int sideband_demux(int in, int out, void *data) -{ - int *fd = data, ret; -#ifdef NO_PTHREADS - close(fd[1]); -#endif - ret = recv_sideband("send-pack", fd[0], out); - close(out); - return ret; -} - -int send_pack(struct send_pack_args *args, - int fd[], struct child_process *conn, - struct ref *remote_refs, - struct extra_have_objects *extra_have) -{ - int in = fd[0]; - int out = fd[1]; - struct strbuf req_buf = STRBUF_INIT; - struct ref *ref; - int new_refs; - int allow_deleting_refs = 0; - int status_report = 0; - int use_sideband = 0; - int quiet_supported = 0; - unsigned cmds_sent = 0; - int ret; - struct async demux; - - /* Does the other end support the reporting? */ - if (server_supports("report-status")) - status_report = 1; - if (server_supports("delete-refs")) - allow_deleting_refs = 1; - if (server_supports("ofs-delta")) - args->use_ofs_delta = 1; - if (server_supports("side-band-64k")) - use_sideband = 1; - if (server_supports("quiet")) - quiet_supported = 1; - - if (!remote_refs) { - fprintf(stderr, "No refs in common and none specified; doing nothing.\n" - "Perhaps you should specify a branch such as 'master'.\n"); - return 0; - } - - /* - * Finally, tell the other end! - */ - new_refs = 0; - for (ref = remote_refs; ref; ref = ref->next) { - if (!ref->peer_ref && !args->send_mirror) - continue; - - /* Check for statuses set by set_ref_status_for_push() */ - switch (ref->status) { - case REF_STATUS_REJECT_NONFASTFORWARD: - case REF_STATUS_UPTODATE: - continue; - default: - ; /* do nothing */ - } - - if (ref->deletion && !allow_deleting_refs) { - ref->status = REF_STATUS_REJECT_NODELETE; - continue; - } - - if (!ref->deletion) - new_refs++; - - if (args->dry_run) { - ref->status = REF_STATUS_OK; - } else { - char *old_hex = sha1_to_hex(ref->old_sha1); - char *new_hex = sha1_to_hex(ref->new_sha1); - int quiet = quiet_supported && (args->quiet || !args->progress); - - if (!cmds_sent && (status_report || use_sideband || args->quiet)) { - packet_buf_write(&req_buf, "%s %s %s%c%s%s%s", - old_hex, new_hex, ref->name, 0, - status_report ? " report-status" : "", - use_sideband ? " side-band-64k" : "", - quiet ? " quiet" : ""); - } - else - packet_buf_write(&req_buf, "%s %s %s", - old_hex, new_hex, ref->name); - ref->status = status_report ? - REF_STATUS_EXPECTING_REPORT : - REF_STATUS_OK; - cmds_sent++; - } - } - - if (args->stateless_rpc) { - if (!args->dry_run && cmds_sent) { - packet_buf_flush(&req_buf); - send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX); - } - } else { - safe_write(out, req_buf.buf, req_buf.len); - packet_flush(out); - } - strbuf_release(&req_buf); - - if (use_sideband && cmds_sent) { - memset(&demux, 0, sizeof(demux)); - demux.proc = sideband_demux; - demux.data = fd; - demux.out = -1; - if (start_async(&demux)) - die("send-pack: unable to fork off sideband demultiplexer"); - in = demux.out; - } - - if (new_refs && cmds_sent) { - if (pack_objects(out, remote_refs, extra_have, args) < 0) { - for (ref = remote_refs; ref; ref = ref->next) - ref->status = REF_STATUS_NONE; - if (args->stateless_rpc) - close(out); - if (git_connection_is_socket(conn)) - shutdown(fd[0], SHUT_WR); - if (use_sideband) - finish_async(&demux); - return -1; - } - } - if (args->stateless_rpc && cmds_sent) - packet_flush(out); - - if (status_report && cmds_sent) - ret = receive_status(in, remote_refs); - else - ret = 0; - if (args->stateless_rpc) - packet_flush(out); - - if (use_sideband && cmds_sent) { - if (finish_async(&demux)) { - error("error in sideband demultiplexer"); - ret = -1; - } - close(demux.out); - } - - if (ret < 0) - return ret; - - if (args->porcelain) - return 0; - - for (ref = remote_refs; ref; ref = ref->next) { - switch (ref->status) { - case REF_STATUS_NONE: - case REF_STATUS_UPTODATE: - case REF_STATUS_OK: - break; - default: - return -1; - } - } - return 0; -} - int cmd_send_pack(int argc, const char **argv, const char *prefix) { int i, nr_refspecs = 0; diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 37f3193a3..83605143a 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -10,9 +10,9 @@ #include "parse-options.h" static char const * const shortlog_usage[] = { - "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]", + N_("git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"), "", - "[rev-opts] are documented in git-rev-list(1)", + N_("[rev-opts] are documented in git-rev-list(1)"), NULL }; @@ -250,13 +250,13 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) static const struct option options[] = { OPT_BOOLEAN('n', "numbered", &log.sort_by_number, - "sort output according to the number of commits per author"), + N_("sort output according to the number of commits per author")), OPT_BOOLEAN('s', "summary", &log.summary, - "Suppress commit descriptions, only provides commit count"), + N_("Suppress commit descriptions, only provides commit count")), OPT_BOOLEAN('e', "email", &log.email, - "Show the email address of each author"), - { OPTION_CALLBACK, 'w', NULL, &log, "w[,i1[,i2]]", - "Linewrap output", PARSE_OPT_OPTARG, &parse_wrap_args }, + N_("Show the email address of each author")), + { OPTION_CALLBACK, 'w', NULL, &log, N_("w[,i1[,i2]]"), + N_("Linewrap output"), PARSE_OPT_OPTARG, &parse_wrap_args }, OPT_END(), }; @@ -306,9 +306,8 @@ parse_done: static void add_wrapped_shortlog_msg(struct strbuf *sb, const char *s, const struct shortlog *log) { - int col = strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap); - if (col != log->wrap) - strbuf_addch(sb, '\n'); + strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap); + strbuf_addch(sb, '\n'); } void shortlog_output(struct shortlog *log) diff --git a/builtin/show-branch.c b/builtin/show-branch.c index a59e088cf..d208fd6c6 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -6,8 +6,8 @@ #include "parse-options.h" static const char* show_branch_usage[] = { - "git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]", - "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]", + N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"), + N_("git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"), NULL }; @@ -648,36 +648,36 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) const char *reflog_base = NULL; struct option builtin_show_branch_options[] = { OPT_BOOLEAN('a', "all", &all_heads, - "show remote-tracking and local branches"), + N_("show remote-tracking and local branches")), OPT_BOOLEAN('r', "remotes", &all_remotes, - "show remote-tracking branches"), + N_("show remote-tracking branches")), OPT__COLOR(&showbranch_use_color, - "color '*!+-' corresponding to the branch"), - { OPTION_INTEGER, 0, "more", &extra, "n", - "show <n> more commits after the common ancestor", + N_("color '*!+-' corresponding to the branch")), + { OPTION_INTEGER, 0, "more", &extra, N_("n"), + N_("show <n> more commits after the common ancestor"), PARSE_OPT_OPTARG, NULL, (intptr_t)1 }, - OPT_SET_INT(0, "list", &extra, "synonym to more=-1", -1), - OPT_BOOLEAN(0, "no-name", &no_name, "suppress naming strings"), + OPT_SET_INT(0, "list", &extra, N_("synonym to more=-1"), -1), + OPT_BOOLEAN(0, "no-name", &no_name, N_("suppress naming strings")), OPT_BOOLEAN(0, "current", &with_current_branch, - "include the current branch"), + N_("include the current branch")), OPT_BOOLEAN(0, "sha1-name", &sha1_name, - "name commits with their object names"), + N_("name commits with their object names")), OPT_BOOLEAN(0, "merge-base", &merge_base, - "show possible merge bases"), + N_("show possible merge bases")), OPT_BOOLEAN(0, "independent", &independent, - "show refs unreachable from any other ref"), + N_("show refs unreachable from any other ref")), OPT_BOOLEAN(0, "topo-order", &lifo, - "show commits in topological order"), + N_("show commits in topological order")), OPT_BOOLEAN(0, "topics", &topics, - "show only commits not on the first branch"), + N_("show only commits not on the first branch")), OPT_SET_INT(0, "sparse", &dense, - "show merges reachable from only one tip", 0), + N_("show merges reachable from only one tip"), 0), OPT_SET_INT(0, "date-order", &lifo, - "show commits where no parent comes before its " - "children", 0), - { OPTION_CALLBACK, 'g', "reflog", &reflog_base, "<n>[,<base>]", - "show <n> most recent ref-log entries starting at " - "base", + N_("show commits where no parent comes before its " + "children"), 0), + { OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"), + N_("show <n> most recent ref-log entries starting at " + "base"), PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parse_reflog_param }, OPT_END() diff --git a/builtin/show-ref.c b/builtin/show-ref.c index 391166190..8d9b76a02 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -7,8 +7,8 @@ #include "parse-options.h" static const char * const show_ref_usage[] = { - "git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] ", - "git show-ref --exclude-existing[=pattern] < ref-list", + N_("git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "), + N_("git show-ref --exclude-existing[=pattern] < ref-list"), NULL }; @@ -28,7 +28,6 @@ static void show_one(const char *refname, const unsigned char *sha1) static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata) { - struct object *obj; const char *hex; unsigned char peeled[20]; @@ -79,25 +78,9 @@ match: if (!deref_tags) return 0; - if ((flag & REF_ISPACKED) && !peel_ref(refname, peeled)) { - if (!is_null_sha1(peeled)) { - hex = find_unique_abbrev(peeled, abbrev); - printf("%s %s^{}\n", hex, refname); - } - } - else { - obj = parse_object(sha1); - if (!obj) - die("git show-ref: bad ref %s (%s)", refname, - sha1_to_hex(sha1)); - if (obj->type == OBJ_TAG) { - obj = deref_tag(obj, refname, 0); - if (!obj) - die("git show-ref: bad tag at ref %s (%s)", refname, - sha1_to_hex(sha1)); - hex = find_unique_abbrev(obj->sha1, abbrev); - printf("%s %s^{}\n", hex, refname); - } + if (!peel_ref(refname, peeled)) { + hex = find_unique_abbrev(peeled, abbrev); + printf("%s %s^{}\n", hex, refname); } return 0; } @@ -179,26 +162,26 @@ static int help_callback(const struct option *opt, const char *arg, int unset) } static const struct option show_ref_options[] = { - OPT_BOOLEAN(0, "tags", &tags_only, "only show tags (can be combined with heads)"), - OPT_BOOLEAN(0, "heads", &heads_only, "only show heads (can be combined with tags)"), - OPT_BOOLEAN(0, "verify", &verify, "stricter reference checking, " - "requires exact ref path"), + OPT_BOOLEAN(0, "tags", &tags_only, N_("only show tags (can be combined with heads)")), + OPT_BOOLEAN(0, "heads", &heads_only, N_("only show heads (can be combined with tags)")), + OPT_BOOLEAN(0, "verify", &verify, N_("stricter reference checking, " + "requires exact ref path")), { OPTION_BOOLEAN, 'h', NULL, &show_head, NULL, - "show the HEAD reference", + N_("show the HEAD reference"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN }, - OPT_BOOLEAN(0, "head", &show_head, "show the HEAD reference"), + OPT_BOOLEAN(0, "head", &show_head, N_("show the HEAD reference")), OPT_BOOLEAN('d', "dereference", &deref_tags, - "dereference tags into object IDs"), - { OPTION_CALLBACK, 's', "hash", &abbrev, "n", - "only show SHA1 hash using <n> digits", + N_("dereference tags into object IDs")), + { OPTION_CALLBACK, 's', "hash", &abbrev, N_("n"), + N_("only show SHA1 hash using <n> digits"), PARSE_OPT_OPTARG, &hash_callback }, OPT__ABBREV(&abbrev), OPT__QUIET(&quiet, - "do not print results to stdout (useful with --verify)"), + N_("do not print results to stdout (useful with --verify)")), { OPTION_CALLBACK, 0, "exclude-existing", &exclude_existing_arg, - "pattern", "show refs from stdin that aren't in local repository", + N_("pattern"), N_("show refs from stdin that aren't in local repository"), PARSE_OPT_OPTARG | PARSE_OPT_NONEG, exclude_existing_callback }, - { OPTION_CALLBACK, 0, "help-all", NULL, NULL, "show usage", + { OPTION_CALLBACK, 0, "help-all", NULL, NULL, N_("show usage"), PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback }, OPT_END() }; diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c index 801d62ece..f48195942 100644 --- a/builtin/symbolic-ref.c +++ b/builtin/symbolic-ref.c @@ -4,13 +4,12 @@ #include "parse-options.h" static const char * const git_symbolic_ref_usage[] = { - "git symbolic-ref [options] name [ref]", + N_("git symbolic-ref [options] name [ref]"), + N_("git symbolic-ref -d [-q] name"), NULL }; -static int shorten; - -static void check_symref(const char *HEAD, int quiet) +static int check_symref(const char *HEAD, int quiet, int shorten, int print) { unsigned char sha1[20]; int flag; @@ -22,22 +21,26 @@ static void check_symref(const char *HEAD, int quiet) if (!quiet) die("ref %s is not a symbolic ref", HEAD); else - exit(1); + return 1; + } + if (print) { + if (shorten) + refname = shorten_unambiguous_ref(refname, 0); + puts(refname); } - if (shorten) - refname = shorten_unambiguous_ref(refname, 0); - puts(refname); + return 0; } int cmd_symbolic_ref(int argc, const char **argv, const char *prefix) { - int quiet = 0; + int quiet = 0, delete = 0, shorten = 0, ret = 0; const char *msg = NULL; struct option options[] = { OPT__QUIET(&quiet, - "suppress error message for non-symbolic (detached) refs"), - OPT_BOOL(0, "short", &shorten, "shorten ref output"), - OPT_STRING('m', NULL, &msg, "reason", "reason of the update"), + N_("suppress error message for non-symbolic (detached) refs")), + OPT_BOOL('d', "delete", &delete, N_("delete symbolic ref")), + OPT_BOOL(0, "short", &shorten, N_("shorten ref output")), + OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")), OPT_END(), }; @@ -46,9 +49,19 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix) git_symbolic_ref_usage, 0); if (msg &&!*msg) die("Refusing to perform update with empty message"); + + if (delete) { + if (argc != 1) + usage_with_options(git_symbolic_ref_usage, options); + ret = check_symref(argv[0], 1, 0, 0); + if (ret) + die("Cannot delete %s, not a symbolic ref", argv[0]); + return delete_ref(argv[0], NULL, REF_NODEREF); + } + switch (argc) { case 1: - check_symref(argv[0], quiet); + ret = check_symref(argv[0], quiet, shorten, 1); break; case 2: if (!strcmp(argv[0], "HEAD") && @@ -59,5 +72,5 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix) default: usage_with_options(git_symbolic_ref_usage, options); } - return 0; + return ret; } diff --git a/builtin/tag.c b/builtin/tag.c index 7b1be85e4..9c3e0673d 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -19,11 +19,11 @@ #include "column.h" static const char * const git_tag_usage[] = { - "git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]", - "git tag -d <tagname>...", - "git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] " - "\n\t\t[<pattern>...]", - "git tag -v <tagname>...", + N_("git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"), + N_("git tag -d <tagname>..."), + N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] " + "\n\t\t[<pattern>...]"), + N_("git tag -v <tagname>..."), NULL }; @@ -444,37 +444,37 @@ int cmd_tag(int argc, const char **argv, const char *prefix) struct msg_arg msg = { 0, STRBUF_INIT }; struct commit_list *with_commit = NULL; struct option options[] = { - OPT_BOOLEAN('l', "list", &list, "list tag names"), - { OPTION_INTEGER, 'n', NULL, &lines, "n", - "print <n> lines of each tag message", + OPT_BOOLEAN('l', "list", &list, N_("list tag names")), + { OPTION_INTEGER, 'n', NULL, &lines, N_("n"), + N_("print <n> lines of each tag message"), PARSE_OPT_OPTARG, NULL, 1 }, - OPT_BOOLEAN('d', "delete", &delete, "delete tags"), - OPT_BOOLEAN('v', "verify", &verify, "verify tags"), + OPT_BOOLEAN('d', "delete", &delete, N_("delete tags")), + OPT_BOOLEAN('v', "verify", &verify, N_("verify tags")), - OPT_GROUP("Tag creation options"), + OPT_GROUP(N_("Tag creation options")), OPT_BOOLEAN('a', "annotate", &annotate, - "annotated tag, needs a message"), - OPT_CALLBACK('m', "message", &msg, "message", - "tag message", parse_msg_arg), - OPT_FILENAME('F', "file", &msgfile, "read message from file"), - OPT_BOOLEAN('s', "sign", &opt.sign, "annotated and GPG-signed tag"), - OPT_STRING(0, "cleanup", &cleanup_arg, "mode", - "how to strip spaces and #comments from message"), - OPT_STRING('u', "local-user", &keyid, "key-id", - "use another key to sign the tag"), - OPT__FORCE(&force, "replace the tag if exists"), - OPT_COLUMN(0, "column", &colopts, "show tag list in columns"), - - OPT_GROUP("Tag listing options"), + N_("annotated tag, needs a message")), + OPT_CALLBACK('m', "message", &msg, N_("message"), + N_("tag message"), parse_msg_arg), + OPT_FILENAME('F', "file", &msgfile, N_("read message from file")), + OPT_BOOLEAN('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")), + OPT_STRING(0, "cleanup", &cleanup_arg, N_("mode"), + N_("how to strip spaces and #comments from message")), + OPT_STRING('u', "local-user", &keyid, N_("key id"), + N_("use another key to sign the tag")), + OPT__FORCE(&force, N_("replace the tag if exists")), + OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")), + + OPT_GROUP(N_("Tag listing options")), { - OPTION_CALLBACK, 0, "contains", &with_commit, "commit", - "print only tags that contain the commit", + OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"), + N_("print only tags that contain the commit"), PARSE_OPT_LASTARG_DEFAULT, parse_opt_with_commit, (intptr_t)"HEAD", }, { - OPTION_CALLBACK, 0, "points-at", NULL, "object", - "print only tags of the object", 0, parse_opt_points_at + OPTION_CALLBACK, 0, "points-at", NULL, N_("object"), + N_("print only tags of the object"), 0, parse_opt_points_at }, OPT_END() }; diff --git a/builtin/update-index.c b/builtin/update-index.c index 5a4e9ea55..ada1dff84 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -95,7 +95,8 @@ static int add_one_path(struct cache_entry *old, const char *path, int len, stru size = cache_entry_size(len); ce = xcalloc(1, size); memcpy(ce->name, path, len); - ce->ce_flags = len; + ce->ce_flags = create_ce_flags(0); + ce->ce_namelen = len; fill_stat_cache_info(ce, st); ce->ce_mode = ce_mode_from_stat(old, st->st_mode); @@ -229,7 +230,8 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, hashcpy(ce->sha1, sha1); memcpy(ce->name, path, len); - ce->ce_flags = create_ce_flags(len, stage); + ce->ce_flags = create_ce_flags(stage); + ce->ce_namelen = len; ce->ce_mode = create_ce_mode(mode); if (assume_unchanged) ce->ce_flags |= CE_VALID; @@ -396,7 +398,7 @@ static void read_index_info(int line_termination) } static const char * const update_index_usage[] = { - "git update-index [options] [--] [<file>...]", + N_("git update-index [options] [--] [<file>...]"), NULL }; @@ -427,7 +429,8 @@ static struct cache_entry *read_one_ent(const char *which, hashcpy(ce->sha1, sha1); memcpy(ce->name, path, namelen); - ce->ce_flags = create_ce_flags(namelen, stage); + ce->ce_flags = create_ce_flags(stage); + ce->ce_namelen = namelen; ce->ce_mode = create_ce_mode(mode); return ce; } @@ -590,6 +593,7 @@ struct refresh_params { static int refresh(struct refresh_params *o, unsigned int flag) { setup_work_tree(); + read_cache_preload(NULL); *o->has_errors |= refresh_cache(o->flags | flag); return 0; } @@ -711,83 +715,83 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) int parseopt_state = PARSE_OPT_UNKNOWN; struct option options[] = { OPT_BIT('q', NULL, &refresh_args.flags, - "continue refresh even when index needs update", + N_("continue refresh even when index needs update"), REFRESH_QUIET), OPT_BIT(0, "ignore-submodules", &refresh_args.flags, - "refresh: ignore submodules", + N_("refresh: ignore submodules"), REFRESH_IGNORE_SUBMODULES), OPT_SET_INT(0, "add", &allow_add, - "do not ignore new files", 1), + N_("do not ignore new files"), 1), OPT_SET_INT(0, "replace", &allow_replace, - "let files replace directories and vice-versa", 1), + N_("let files replace directories and vice-versa"), 1), OPT_SET_INT(0, "remove", &allow_remove, - "notice files missing from worktree", 1), + N_("notice files missing from worktree"), 1), OPT_BIT(0, "unmerged", &refresh_args.flags, - "refresh even if index contains unmerged entries", + N_("refresh even if index contains unmerged entries"), REFRESH_UNMERGED), {OPTION_CALLBACK, 0, "refresh", &refresh_args, NULL, - "refresh stat information", + N_("refresh stat information"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, refresh_callback}, {OPTION_CALLBACK, 0, "really-refresh", &refresh_args, NULL, - "like --refresh, but ignore assume-unchanged setting", + N_("like --refresh, but ignore assume-unchanged setting"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, really_refresh_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "cacheinfo", NULL, - "<mode> <object> <path>", - "add the specified entry to the index", + N_("<mode> <object> <path>"), + N_("add the specified entry to the index"), PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */ PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, (parse_opt_cb *) cacheinfo_callback}, - {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+/-)x", - "override the executable bit of the listed files", + {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, N_("(+/-)x"), + N_("override the executable bit of the listed files"), PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, chmod_callback}, {OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL, - "mark files as \"not changing\"", + N_("mark files as \"not changing\""), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, {OPTION_SET_INT, 0, "no-assume-unchanged", &mark_valid_only, NULL, - "clear assumed-unchanged bit", + N_("clear assumed-unchanged bit"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, {OPTION_SET_INT, 0, "skip-worktree", &mark_skip_worktree_only, NULL, - "mark files as \"index-only\"", + N_("mark files as \"index-only\""), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, {OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL, - "clear skip-worktree bit", + N_("clear skip-worktree bit"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, OPT_SET_INT(0, "info-only", &info_only, - "add to index only; do not add content to object database", 1), + N_("add to index only; do not add content to object database"), 1), OPT_SET_INT(0, "force-remove", &force_remove, - "remove named paths even if present in worktree", 1), + N_("remove named paths even if present in worktree"), 1), OPT_SET_INT('z', NULL, &line_termination, - "with --stdin: input lines are terminated by null bytes", '\0'), + N_("with --stdin: input lines are terminated by null bytes"), '\0'), {OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL, - "read list of paths to be updated from standard input", + N_("read list of paths to be updated from standard input"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) stdin_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &line_termination, NULL, - "add entries from standard input to the index", + N_("add entries from standard input to the index"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) stdin_cacheinfo_callback}, {OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL, - "repopulate stages #2 and #3 for the listed paths", + N_("repopulate stages #2 and #3 for the listed paths"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) unresolve_callback}, {OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL, - "only update entries that differ from HEAD", + N_("only update entries that differ from HEAD"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) reupdate_callback}, OPT_BIT(0, "ignore-missing", &refresh_args.flags, - "ignore files missing from worktree", + N_("ignore files missing from worktree"), REFRESH_IGNORE_MISSING), OPT_SET_INT(0, "verbose", &verbose, - "report actions to standard output", 1), + N_("report actions to standard output"), 1), {OPTION_CALLBACK, 0, "clear-resolve-undo", NULL, NULL, - "(for porcelains) forget saved unresolved conflicts", + N_("(for porcelains) forget saved unresolved conflicts"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, resolve_undo_clear_callback}, OPT_INTEGER(0, "index-version", &preferred_index_format, - "write index in this format"), + N_("write index in this format")), OPT_END() }; diff --git a/builtin/update-ref.c b/builtin/update-ref.c index 835c62ab1..51d268485 100644 --- a/builtin/update-ref.c +++ b/builtin/update-ref.c @@ -4,8 +4,8 @@ #include "parse-options.h" static const char * const git_update_ref_usage[] = { - "git update-ref [options] -d <refname> [<oldval>]", - "git update-ref [options] <refname> <newval> [<oldval>]", + N_("git update-ref [options] -d <refname> [<oldval>]"), + N_("git update-ref [options] <refname> <newval> [<oldval>]"), NULL }; @@ -15,10 +15,10 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) unsigned char sha1[20], oldsha1[20]; int delete = 0, no_deref = 0, flags = 0; struct option options[] = { - OPT_STRING( 'm', NULL, &msg, "reason", "reason of the update"), - OPT_BOOLEAN('d', NULL, &delete, "deletes the reference"), + OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")), + OPT_BOOLEAN('d', NULL, &delete, N_("delete the reference")), OPT_BOOLEAN( 0 , "no-deref", &no_deref, - "update <refname> not the one it points to"), + N_("update <refname> not the one it points to")), OPT_END(), }; diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c index 0d63c4498..6c8cc3edc 100644 --- a/builtin/update-server-info.c +++ b/builtin/update-server-info.c @@ -3,7 +3,7 @@ #include "parse-options.h" static const char * const update_server_info_usage[] = { - "git update-server-info [--force]", + N_("git update-server-info [--force]"), NULL }; @@ -11,7 +11,7 @@ int cmd_update_server_info(int argc, const char **argv, const char *prefix) { int force = 0; struct option options[] = { - OPT__FORCE(&force, "update the info files from scratch"), + OPT__FORCE(&force, N_("update the info files from scratch")), OPT_END() }; diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c index e841b4a38..66cd2df0f 100644 --- a/builtin/verify-pack.c +++ b/builtin/verify-pack.c @@ -53,7 +53,7 @@ static int verify_one_pack(const char *path, unsigned int flags) } static const char * const verify_pack_usage[] = { - "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>...", + N_("git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."), NULL }; @@ -63,9 +63,9 @@ int cmd_verify_pack(int argc, const char **argv, const char *prefix) unsigned int flags = 0; int i; const struct option verify_pack_options[] = { - OPT_BIT('v', "verbose", &flags, "verbose", + OPT_BIT('v', "verbose", &flags, N_("verbose"), VERIFY_PACK_VERBOSE), - OPT_BIT('s', "stat-only", &flags, "show statistics only", + OPT_BIT('s', "stat-only", &flags, N_("show statistics only"), VERIFY_PACK_STAT_ONLY), OPT_END() }; diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c index 986789f70..a8eee886a 100644 --- a/builtin/verify-tag.c +++ b/builtin/verify-tag.c @@ -14,7 +14,7 @@ #include "gpg-interface.h" static const char * const verify_tag_usage[] = { - "git verify-tag [-v|--verbose] <tag>...", + N_("git verify-tag [-v|--verbose] <tag>..."), NULL }; @@ -70,7 +70,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix) { int i = 1, verbose = 0, had_error = 0; const struct option verify_tag_options[] = { - OPT__VERBOSE(&verbose, "print tag contents"), + OPT__VERBOSE(&verbose, N_("print tag contents")), OPT_END() }; diff --git a/builtin/write-tree.c b/builtin/write-tree.c index b223af416..084c0df78 100644 --- a/builtin/write-tree.c +++ b/builtin/write-tree.c @@ -10,7 +10,7 @@ #include "parse-options.h" static const char * const write_tree_usage[] = { - "git write-tree [--missing-ok] [--prefix=<prefix>/]", + N_("git write-tree [--missing-ok] [--prefix=<prefix>/]"), NULL }; @@ -21,13 +21,13 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix) unsigned char sha1[20]; const char *me = "git-write-tree"; struct option write_tree_options[] = { - OPT_BIT(0, "missing-ok", &flags, "allow missing objects", + OPT_BIT(0, "missing-ok", &flags, N_("allow missing objects"), WRITE_TREE_MISSING_OK), - { OPTION_STRING, 0, "prefix", &prefix, "<prefix>/", - "write tree object for a subdirectory <prefix>" , + { OPTION_STRING, 0, "prefix", &prefix, N_("<prefix>/"), + N_("write tree object for a subdirectory <prefix>") , PARSE_OPT_LITERAL_ARGHELP }, { OPTION_BIT, 0, "ignore-cache-tree", &flags, NULL, - "only useful for debugging", + N_("only useful for debugging"), PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, NULL, WRITE_TREE_IGNORE_CACHE_TREE }, OPT_END() diff --git a/cache-tree.c b/cache-tree.c index 28ed6574a..37e4d008b 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -166,12 +166,8 @@ static int verify_cache(struct cache_entry **cache, fprintf(stderr, "...\n"); break; } - if (ce_stage(ce)) - fprintf(stderr, "%s: unmerged (%s)\n", - ce->name, sha1_to_hex(ce->sha1)); - else - fprintf(stderr, "%s: not added yet\n", - ce->name); + fprintf(stderr, "%s: unmerged (%s)\n", + ce->name, sha1_to_hex(ce->sha1)); } } if (funny) @@ -242,13 +238,17 @@ static int update_one(struct cache_tree *it, int entries, const char *base, int baselen, + int *skip_count, int flags) { struct strbuf buffer; int missing_ok = flags & WRITE_TREE_MISSING_OK; int dryrun = flags & WRITE_TREE_DRY_RUN; + int to_invalidate = 0; int i; + *skip_count = 0; + if (0 <= it->entry_count && has_sha1_file(it->sha1)) return it->entry_count; @@ -263,11 +263,12 @@ static int update_one(struct cache_tree *it, /* * Find the subtrees and update them. */ - for (i = 0; i < entries; i++) { + i = 0; + while (i < entries) { struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; - int pathlen, sublen, subcnt; + int pathlen, sublen, subcnt, subskip; path = ce->name; pathlen = ce_namelen(ce); @@ -275,8 +276,10 @@ static int update_one(struct cache_tree *it, break; /* at the end of this level */ slash = strchr(path + baselen, '/'); - if (!slash) + if (!slash) { + i++; continue; + } /* * a/bbb/c (base = a/, slash = /c) * ==> @@ -290,10 +293,13 @@ static int update_one(struct cache_tree *it, cache + i, entries - i, path, baselen + sublen + 1, + &subskip, flags); if (subcnt < 0) return subcnt; - i += subcnt - 1; + i += subcnt; + sub->count = subcnt; /* to be used in the next loop */ + *skip_count += subskip; sub->used = 1; } @@ -304,7 +310,8 @@ static int update_one(struct cache_tree *it, */ strbuf_init(&buffer, 8192); - for (i = 0; i < entries; i++) { + i = 0; + while (i < entries) { struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; @@ -324,14 +331,17 @@ static int update_one(struct cache_tree *it, if (!sub) die("cache-tree.c: '%.*s' in '%s' not found", entlen, path + baselen, path); - i += sub->cache_tree->entry_count - 1; + i += sub->count; sha1 = sub->cache_tree->sha1; mode = S_IFDIR; + if (sub->cache_tree->entry_count < 0) + to_invalidate = 1; } else { sha1 = ce->sha1; mode = ce->ce_mode; entlen = pathlen - baselen; + i++; } if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) { strbuf_release(&buffer); @@ -339,8 +349,25 @@ static int update_one(struct cache_tree *it, mode, sha1_to_hex(sha1), entlen+baselen, path); } - if (ce->ce_flags & (CE_REMOVE | CE_INTENT_TO_ADD)) - continue; /* entry being removed or placeholder */ + /* + * CE_REMOVE entries are removed before the index is + * written to disk. Skip them to remain consistent + * with the future on-disk index. + */ + if (ce->ce_flags & CE_REMOVE) { + *skip_count = *skip_count + 1; + continue; + } + + /* + * CE_INTENT_TO_ADD entries exist on on-disk index but + * they are not part of generated trees. Invalidate up + * to root to force cache-tree users to read elsewhere. + */ + if (ce->ce_flags & CE_INTENT_TO_ADD) { + to_invalidate = 1; + continue; + } strbuf_grow(&buffer, entlen + 100); strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0'); @@ -360,7 +387,7 @@ static int update_one(struct cache_tree *it, } strbuf_release(&buffer); - it->entry_count = i; + it->entry_count = to_invalidate ? -1 : i - *skip_count; #if DEBUG fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n", it->entry_count, it->subtree_nr, @@ -374,11 +401,11 @@ int cache_tree_update(struct cache_tree *it, int entries, int flags) { - int i; + int i, skip; i = verify_cache(cache, entries, flags); if (i) return i; - i = update_one(it, cache, entries, "", 0, flags); + i = update_one(it, cache, entries, "", 0, &skip, flags); if (i < 0) return i; return 0; diff --git a/cache-tree.h b/cache-tree.h index d8cb2e9e3..55d0f59f2 100644 --- a/cache-tree.h +++ b/cache-tree.h @@ -7,6 +7,7 @@ struct cache_tree; struct cache_tree_sub { struct cache_tree *cache_tree; + int count; /* internally used by update_one() */ int namelen; int used; char name[FLEX_ARRAY]; @@ -128,13 +128,13 @@ struct cache_entry { unsigned int ce_gid; unsigned int ce_size; unsigned int ce_flags; + unsigned int ce_namelen; unsigned char sha1[20]; struct cache_entry *next; struct cache_entry *dir_next; char name[FLEX_ARRAY]; /* more */ }; -#define CE_NAMEMASK (0x0fff) #define CE_STAGEMASK (0x3000) #define CE_EXTENDED (0x4000) #define CE_VALID (0x8000) @@ -198,21 +198,12 @@ static inline void copy_cache_entry(struct cache_entry *dst, struct cache_entry dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state; } -static inline unsigned create_ce_flags(size_t len, unsigned stage) +static inline unsigned create_ce_flags(unsigned stage) { - if (len >= CE_NAMEMASK) - len = CE_NAMEMASK; - return (len | (stage << CE_STAGESHIFT)); -} - -static inline size_t ce_namelen(const struct cache_entry *ce) -{ - size_t len = ce->ce_flags & CE_NAMEMASK; - if (len < CE_NAMEMASK) - return len; - return strlen(ce->name + CE_NAMEMASK) + CE_NAMEMASK; + return (stage << CE_STAGESHIFT); } +#define ce_namelen(ce) ((ce)->ce_namelen) #define ce_size(ce) cache_entry_size(ce_namelen(ce)) #define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT) #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE) @@ -563,6 +554,7 @@ extern int read_replace_refs; extern int fsync_object_files; extern int core_preload_index; extern int core_apply_sparse_checkout; +extern int precomposed_unicode; enum branch_track { BRANCH_TRACK_UNSPECIFIED = -1, @@ -622,6 +614,8 @@ extern char *git_snpath(char *buf, size_t n, const char *fmt, ...) __attribute__((format (printf, 3, 4))); extern char *git_pathdup(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +extern char *mkpathdup(const char *fmt, ...) + __attribute__((format (printf, 1, 2))); /* Return a statically allocated filename matching the sha1 signature */ extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); @@ -711,6 +705,7 @@ int set_shared_perm(const char *path, int mode); int safe_create_leading_directories(char *path); int safe_create_leading_directories_const(const char *path); int mkdir_in_gitdir(const char *path); +extern void home_config_paths(char **global, char **xdg, char *file); extern char *expand_user_path(const char *path); const char *enter_repo(const char *path, int strict); static inline int is_absolute_path(const char *path) @@ -786,17 +781,25 @@ struct object_context { unsigned mode; }; +#define GET_SHA1_QUIETLY 01 +#define GET_SHA1_COMMIT 02 +#define GET_SHA1_COMMITTISH 04 +#define GET_SHA1_TREE 010 +#define GET_SHA1_TREEISH 020 +#define GET_SHA1_BLOB 040 +#define GET_SHA1_ONLY_TO_DIE 04000 + extern int get_sha1(const char *str, unsigned char *sha1); -extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int only_to_die, const char *prefix); -static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode) -{ - return get_sha1_with_mode_1(str, sha1, mode, 0, NULL); -} -extern int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *orc, int only_to_die, const char *prefix); -static inline int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc) -{ - return get_sha1_with_context_1(str, sha1, orc, 0, NULL); -} +extern int get_sha1_commit(const char *str, unsigned char *sha1); +extern int get_sha1_committish(const char *str, unsigned char *sha1); +extern int get_sha1_tree(const char *str, unsigned char *sha1); +extern int get_sha1_treeish(const char *str, unsigned char *sha1); +extern int get_sha1_blob(const char *str, unsigned char *sha1); +extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix); +extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc); + +typedef int each_abbrev_fn(const unsigned char *sha1, void *); +extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *); /* * Try to read a SHA1 in hexadecimal format from the 40 characters @@ -860,6 +863,7 @@ extern int validate_headref(const char *ref); extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2); extern int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2); extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2); +extern int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2); extern void *read_object_with_reference(const unsigned char *sha1, const char *required_type, @@ -897,9 +901,7 @@ extern const char *git_author_info(int); extern const char *git_committer_info(int); extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int); extern const char *fmt_name(const char *name, const char *email); -extern const char *ident_default_name(void); extern const char *ident_default_email(void); -extern const char *ident_default_date(void); extern const char *git_editor(void); extern const char *git_pager(int stdout_is_tty); extern int git_ident_config(const char *, const char *, void *); @@ -942,9 +944,7 @@ struct cache_def { extern int has_symlink_leading_path(const char *name, int len); extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int); extern int check_leading_path(const char *name, int len); -extern int threaded_check_leading_path(struct cache_def *cache, const char *name, int len); extern int has_dirs_only_path(const char *name, int len, int prefix_len); -extern int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len); extern void schedule_dir_for_removal(const char *name, int len); extern void remove_scheduled_dirs(void); @@ -1033,7 +1033,9 @@ struct extra_have_objects { }; extern struct ref **get_remote_heads(int in, struct ref **list, unsigned int flags, struct extra_have_objects *); extern int server_supports(const char *feature); -extern const char *parse_feature_request(const char *features, const char *feature); +extern int parse_feature_request(const char *features, const char *feature); +extern const char *server_feature_value(const char *feature, int *len_ret); +extern const char *parse_feature_value(const char *feature_list, const char *feature, int *len_ret); extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path); @@ -1147,11 +1149,8 @@ struct config_include_data { #define CONFIG_INCLUDE_INIT { 0 } extern int git_config_include(const char *name, const char *value, void *data); -#define IDENT_NAME_GIVEN 01 -#define IDENT_MAIL_GIVEN 02 -#define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN) -extern int user_ident_explicitly_given; -extern int user_ident_sufficiently_given(void); +extern int committer_ident_sufficiently_given(void); +extern int author_ident_sufficiently_given(void); extern const char *git_commit_encoding; extern const char *git_log_output_encoding; @@ -1181,6 +1180,7 @@ extern int pager_in_use(void); extern int pager_use_color; extern int term_columns(void); extern int decimal_width(int); +extern int check_pager_config(const char *cmd); extern const char *editor_program; extern const char *askpass_program; @@ -1201,7 +1201,6 @@ extern void alloc_report(void); /* trace.c */ __attribute__((format (printf, 1, 2))) extern void trace_printf(const char *format, ...); -extern void trace_vprintf(const char *key, const char *format, va_list ap); __attribute__((format (printf, 2, 3))) extern void trace_argv_printf(const char **argv, const char *format, ...); extern void trace_repo_setup(const char *prefix); @@ -1264,8 +1263,15 @@ struct startup_info { }; extern struct startup_info *startup_info; -/* builtin/merge.c */ -int checkout_fast_forward(const unsigned char *from, const unsigned char *to); +/* merge.c */ +struct commit_list; +int try_merge_command(const char *strategy, size_t xopts_nr, + const char **xopts, struct commit_list *common, + const char *head_arg, struct commit_list *remotes); +int checkout_fast_forward(const unsigned char *from, + const unsigned char *to, + int overwrite_ignore); + int sane_execvp(const char *file, char *const argv[]); diff --git a/command-list.txt b/command-list.txt index 14ea67af0..7e8cfec29 100644 --- a/command-list.txt +++ b/command-list.txt @@ -25,6 +25,9 @@ git-commit mainporcelain common git-commit-tree plumbingmanipulators git-config ancillarymanipulators git-count-objects ancillaryinterrogators +git-credential purehelpers +git-credential-cache purehelpers +git-credential-store purehelpers git-cvsexportcommit foreignscminterface git-cvsimport foreignscminterface git-cvsserver foreignscminterface @@ -113,6 +116,7 @@ git-show mainporcelain common git-show-branch ancillaryinterrogators git-show-index plumbinginterrogators git-show-ref plumbinginterrogators +git-sh-i18n purehelpers git-sh-setup purehelpers git-stash mainporcelain git-status mainporcelain common @@ -9,6 +9,8 @@ #include "gpg-interface.h" #include "mergesort.h" +static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **); + int save_commit_buffer = 1; const char *commit_type = "commit"; @@ -68,7 +70,7 @@ struct commit *lookup_commit_reference_by_name(const char *name) unsigned char sha1[20]; struct commit *commit; - if (get_sha1(name, sha1)) + if (get_sha1_committish(name, sha1)) return NULL; commit = lookup_commit_reference(sha1); if (!commit || parse_commit(commit)) @@ -607,30 +609,17 @@ static struct commit *interesting(struct commit_list *list) return NULL; } -static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos) +/* all input commits in one and twos[] must have been parsed! */ +static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos) { struct commit_list *list = NULL; struct commit_list *result = NULL; int i; - for (i = 0; i < n; i++) { - if (one == twos[i]) - /* - * We do not mark this even with RESULT so we do not - * have to clean it up. - */ - return commit_list_insert(one, &result); - } - - if (parse_commit(one)) - return NULL; - for (i = 0; i < n; i++) { - if (parse_commit(twos[i])) - return NULL; - } - one->object.flags |= PARENT1; commit_list_insert_by_date(one, &list); + if (!n) + return list; for (i = 0; i < n; i++) { twos[i]->object.flags |= PARENT2; commit_list_insert_by_date(twos[i], &list); @@ -669,9 +658,34 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co } } - /* Clean up the result to remove stale ones */ free_commit_list(list); - list = result; result = NULL; + return result; +} + +static struct commit_list *merge_bases_many(struct commit *one, int n, struct commit **twos) +{ + struct commit_list *list = NULL; + struct commit_list *result = NULL; + int i; + + for (i = 0; i < n; i++) { + if (one == twos[i]) + /* + * We do not mark this even with RESULT so we do not + * have to clean it up. + */ + return commit_list_insert(one, &result); + } + + if (parse_commit(one)) + return NULL; + for (i = 0; i < n; i++) { + if (parse_commit(twos[i])) + return NULL; + } + + list = paint_down_to_common(one, n, twos); + while (list) { struct commit_list *next = list->next; if (!(list->item->object.flags & STALE)) @@ -709,6 +723,62 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in) return ret; } +static int remove_redundant(struct commit **array, int cnt) +{ + /* + * Some commit in the array may be an ancestor of + * another commit. Move such commit to the end of + * the array, and return the number of commits that + * are independent from each other. + */ + struct commit **work; + unsigned char *redundant; + int *filled_index; + int i, j, filled; + + work = xcalloc(cnt, sizeof(*work)); + redundant = xcalloc(cnt, 1); + filled_index = xmalloc(sizeof(*filled_index) * (cnt - 1)); + + for (i = 0; i < cnt; i++) + parse_commit(array[i]); + for (i = 0; i < cnt; i++) { + struct commit_list *common; + + if (redundant[i]) + continue; + for (j = filled = 0; j < cnt; j++) { + if (i == j || redundant[j]) + continue; + filled_index[filled] = j; + work[filled++] = array[j]; + } + common = paint_down_to_common(array[i], filled, work); + if (array[i]->object.flags & PARENT2) + redundant[i] = 1; + for (j = 0; j < filled; j++) + if (work[j]->object.flags & PARENT1) + redundant[filled_index[j]] = 1; + clear_commit_marks(array[i], all_flags); + for (j = 0; j < filled; j++) + clear_commit_marks(work[j], all_flags); + free_commit_list(common); + } + + /* Now collect the result */ + memcpy(work, array, sizeof(*array) * cnt); + for (i = filled = 0; i < cnt; i++) + if (!redundant[i]) + array[filled++] = work[i]; + for (j = filled, i = 0; i < cnt; i++) + if (redundant[i]) + array[j++] = work[i]; + free(work); + free(redundant); + free(filled_index); + return filled; +} + struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos, @@ -717,7 +787,7 @@ struct commit_list *get_merge_bases_many(struct commit *one, struct commit_list *list; struct commit **rslt; struct commit_list *result; - int cnt, i, j; + int cnt, i; result = merge_bases_many(one, n, twos); for (i = 0; i < n; i++) { @@ -748,28 +818,11 @@ struct commit_list *get_merge_bases_many(struct commit *one, clear_commit_marks(one, all_flags); for (i = 0; i < n; i++) clear_commit_marks(twos[i], all_flags); - for (i = 0; i < cnt - 1; i++) { - for (j = i+1; j < cnt; j++) { - if (!rslt[i] || !rslt[j]) - continue; - result = merge_bases_many(rslt[i], 1, &rslt[j]); - clear_commit_marks(rslt[i], all_flags); - clear_commit_marks(rslt[j], all_flags); - for (list = result; list; list = list->next) { - if (rslt[i] == list->item) - rslt[i] = NULL; - if (rslt[j] == list->item) - rslt[j] = NULL; - } - } - } - /* Surviving ones in rslt[] are the independent results */ + cnt = remove_redundant(rslt, cnt); result = NULL; - for (i = 0; i < cnt; i++) { - if (rslt[i]) - commit_list_insert_by_date(rslt[i], &result); - } + for (i = 0; i < cnt; i++) + commit_list_insert_by_date(rslt[i], &result); free(rslt); return result; } @@ -780,6 +833,9 @@ struct commit_list *get_merge_bases(struct commit *one, struct commit *two, return get_merge_bases_many(one, 1, &two, cleanup); } +/* + * Is "commit" a decendant of one of the elements on the "with_commit" list? + */ int is_descendant_of(struct commit *commit, struct commit_list *with_commit) { if (!with_commit) @@ -789,28 +845,28 @@ int is_descendant_of(struct commit *commit, struct commit_list *with_commit) other = with_commit->item; with_commit = with_commit->next; - if (in_merge_bases(other, &commit, 1)) + if (in_merge_bases(other, commit)) return 1; } return 0; } -int in_merge_bases(struct commit *commit, struct commit **reference, int num) +/* + * Is "commit" an ancestor of (i.e. reachable from) the "reference"? + */ +int in_merge_bases(struct commit *commit, struct commit *reference) { - struct commit_list *bases, *b; + struct commit_list *bases; int ret = 0; - if (num == 1) - bases = get_merge_bases(commit, *reference, 1); - else - die("not yet"); - for (b = bases; b; b = b->next) { - if (!hashcmp(commit->object.sha1, b->item->object.sha1)) { - ret = 1; - break; - } - } + if (parse_commit(commit) || parse_commit(reference)) + return ret; + bases = paint_down_to_common(commit, 1, &reference); + if (commit->object.flags & PARENT2) + ret = 1; + clear_commit_marks(commit, all_flags); + clear_commit_marks(reference, all_flags); free_commit_list(bases); return ret; } @@ -819,51 +875,31 @@ struct commit_list *reduce_heads(struct commit_list *heads) { struct commit_list *p; struct commit_list *result = NULL, **tail = &result; - struct commit **other; - size_t num_head, num_other; + struct commit **array; + int num_head, i; if (!heads) return NULL; - /* Avoid unnecessary reallocations */ - for (p = heads, num_head = 0; p; p = p->next) - num_head++; - other = xcalloc(sizeof(*other), num_head); - - /* For each commit, see if it can be reached by others */ - for (p = heads; p; p = p->next) { - struct commit_list *q, *base; - - /* Do we already have this in the result? */ - for (q = result; q; q = q->next) - if (p->item == q->item) - break; - if (q) + /* Uniquify */ + for (p = heads; p; p = p->next) + p->item->object.flags &= ~STALE; + for (p = heads, num_head = 0; p; p = p->next) { + if (p->item->object.flags & STALE) continue; - - num_other = 0; - for (q = heads; q; q = q->next) { - if (p->item == q->item) - continue; - other[num_other++] = q->item; + p->item->object.flags |= STALE; + num_head++; + } + array = xcalloc(sizeof(*array), num_head); + for (p = heads, i = 0; p; p = p->next) { + if (p->item->object.flags & STALE) { + array[i++] = p->item; + p->item->object.flags &= ~STALE; } - if (num_other) - base = get_merge_bases_many(p->item, num_other, other, 1); - else - base = NULL; - /* - * If p->item does not have anything common with other - * commits, there won't be any merge base. If it is - * reachable from some of the others, p->item will be - * the merge base. If its history is connected with - * others, but p->item is not reachable by others, we - * will get something other than p->item back. - */ - if (!base || (base->item != p->item)) - tail = &(commit_list_insert(p->item, tail)->next); - free_commit_list(base); } - free(other); + num_head = remove_redundant(array, num_head); + for (i = 0; i < num_head; i++) + tail = &commit_list_insert(array[i], tail)->next; return result; } @@ -1044,8 +1080,9 @@ static int excluded_header_field(const char *field, size_t len, const char **exc return 0; } -struct commit_extra_header *read_commit_extra_header_lines(const char *buffer, size_t size, - const char **exclude) +static struct commit_extra_header *read_commit_extra_header_lines( + const char *buffer, size_t size, + const char **exclude) { struct commit_extra_header *extra = NULL, **tail = &extra, *it = NULL; const char *line, *next, *eof, *eob; @@ -1112,8 +1149,92 @@ int commit_tree(const struct strbuf *msg, unsigned char *tree, return result; } +static int find_invalid_utf8(const char *buf, int len) +{ + int offset = 0; + + while (len) { + unsigned char c = *buf++; + int bytes, bad_offset; + + len--; + offset++; + + /* Simple US-ASCII? No worries. */ + if (c < 0x80) + continue; + + bad_offset = offset-1; + + /* + * Count how many more high bits set: that's how + * many more bytes this sequence should have. + */ + bytes = 0; + while (c & 0x40) { + c <<= 1; + bytes++; + } + + /* Must be between 1 and 5 more bytes */ + if (bytes < 1 || bytes > 5) + return bad_offset; + + /* Do we *have* that many bytes? */ + if (len < bytes) + return bad_offset; + + offset += bytes; + len -= bytes; + + /* And verify that they are good continuation bytes */ + do { + if ((*buf++ & 0xc0) != 0x80) + return bad_offset; + } while (--bytes); + + /* We could/should check the value and length here too */ + } + return -1; +} + +/* + * This verifies that the buffer is in proper utf8 format. + * + * If it isn't, it assumes any non-utf8 characters are Latin1, + * and does the conversion. + * + * Fixme: we should probably also disallow overlong forms and + * invalid characters. But we don't do that currently. + */ +static int verify_utf8(struct strbuf *buf) +{ + int ok = 1; + long pos = 0; + + for (;;) { + int bad; + unsigned char c; + unsigned char replace[2]; + + bad = find_invalid_utf8(buf->buf + pos, buf->len - pos); + if (bad < 0) + return ok; + pos += bad; + ok = 0; + c = buf->buf[pos]; + strbuf_remove(buf, pos, 1); + + /* We know 'c' must be in the range 128-255 */ + replace[0] = 0xc0 + (c >> 6); + replace[1] = 0x80 + (c & 0x3f); + strbuf_insert(buf, pos, replace, 2); + pos += 2; + } +} + static const char commit_utf8_warn[] = -"Warning: commit message does not conform to UTF-8.\n" +"Warning: commit message did not conform to UTF-8.\n" "You may want to amend it after fixing the message, or set the config\n" "variable i18n.commitencoding to the encoding your project uses.\n"; @@ -1170,7 +1291,7 @@ int commit_tree_extended(const struct strbuf *msg, unsigned char *tree, strbuf_addbuf(&buffer, msg); /* And check the encoding */ - if (encoding_is_utf8 && !is_utf8(buffer.buf)) + if (encoding_is_utf8 && !verify_utf8(&buffer)) fprintf(stderr, commit_utf8_warn); if (sign_commit && do_sign_commit(&buffer, sign_commit)) @@ -1226,3 +1347,13 @@ struct commit_list **commit_list_append(struct commit *commit, new->next = NULL; return &new->next; } + +void print_commit_list(struct commit_list *list, + const char *format_cur, + const char *format_last) +{ + for ( ; list; list = list->next) { + const char *format = list->next ? format_cur : format_last; + printf(format, sha1_to_hex(list->item->object.sha1)); + } +} @@ -86,7 +86,7 @@ struct pretty_print_context { enum date_mode date_mode; unsigned date_mode_explicit:1; int need_8bit_cte; - int show_notes; + char *notes_message; struct reflog_walk_info *reflog_info; const char *output_encoding; }; @@ -99,8 +99,6 @@ extern int has_non_ascii(const char *text); struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */ extern char *logmsg_reencode(const struct commit *commit, const char *output_encoding); -extern char *reencode_commit_message(const struct commit *commit, - const char **encoding_p); extern void get_commit_format(const char *arg, struct rev_info *); extern const char *format_subject(struct strbuf *sb, const char *msg, const char *line_separator); @@ -171,7 +169,7 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads, int depth, int shallow_flag, int not_shallow_flag); int is_descendant_of(struct commit *, struct commit_list *); -int in_merge_bases(struct commit *, struct commit **, int); +int in_merge_bases(struct commit *, struct commit *); extern int interactive_add(int argc, const char **argv, const char *prefix, int patch); extern int run_add_interactive(const char *revision, const char *patch_mode, @@ -204,7 +202,6 @@ extern int commit_tree_extended(const struct strbuf *msg, unsigned char *tree, struct commit_extra_header *); extern struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **); -extern struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **); extern void free_commit_extra_headers(struct commit_extra_header *extra); @@ -223,4 +220,8 @@ struct commit *get_merge_parent(const char *name); extern int parse_signed_commit(const unsigned char *sha1, struct strbuf *message, struct strbuf *signature); +extern void print_commit_list(struct commit_list *list, + const char *format_cur, + const char *format_last); + #endif /* COMMIT_H */ diff --git a/compat/cygwin.c b/compat/cygwin.c index dfe9b3084..542885887 100644 --- a/compat/cygwin.c +++ b/compat/cygwin.c @@ -1,6 +1,13 @@ #define WIN32_LEAN_AND_MEAN +#ifdef CYGWIN_V15_WIN32API #include "../git-compat-util.h" #include "win32.h" +#else +#include <sys/stat.h> +#include <sys/errno.h> +#include "win32.h" +#include "../git-compat-util.h" +#endif #include "../cache.h" /* to read configuration */ static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts) diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c index 9473aed2b..b8b7dc254 100644 --- a/compat/fnmatch/fnmatch.c +++ b/compat/fnmatch/fnmatch.c @@ -135,9 +135,9 @@ extern int errno; # if !defined HAVE___STRCHRNUL && !defined _LIBC static char * -__strchrnul (s, c) - const char *s; - int c; +__strchrnul (const char *s, int c) + + { char *result = strchr (s, c); if (result == NULL) @@ -159,11 +159,11 @@ static int internal_fnmatch __P ((const char *pattern, const char *string, internal_function; static int internal_function -internal_fnmatch (pattern, string, no_leading_period, flags) - const char *pattern; - const char *string; - int no_leading_period; - int flags; +internal_fnmatch (const char *pattern, const char *string, int no_leading_period, int flags) + + + + { register const char *p = pattern, *n = string; register unsigned char c; @@ -345,7 +345,7 @@ internal_fnmatch (pattern, string, no_leading_period, flags) for (;;) { - if (c1 == CHAR_CLASS_MAX_LENGTH) + if (c1 > CHAR_CLASS_MAX_LENGTH) /* The name is too long and therefore the pattern is ill-formed. */ return FNM_NOMATCH; @@ -481,10 +481,10 @@ internal_fnmatch (pattern, string, no_leading_period, flags) int -fnmatch (pattern, string, flags) - const char *pattern; - const char *string; - int flags; +fnmatch (const char *pattern, const char *string, int flags) + + + { return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); } diff --git a/compat/mingw.c b/compat/mingw.c index afc892d6b..b67362558 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -256,6 +256,8 @@ int mingw_rmdir(const char *pathname) while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) { if (!is_file_in_use_error(GetLastError())) + errno = err_win_to_posix(GetLastError()); + if (errno != EACCES) break; if (!is_dir_empty(pathname)) { errno = ENOTEMPTY; @@ -271,7 +273,7 @@ int mingw_rmdir(const char *pathname) Sleep(delay[tries]); tries++; } - while (ret == -1 && is_file_in_use_error(GetLastError()) && + while (ret == -1 && errno == EACCES && is_file_in_use_error(GetLastError()) && ask_yes_no_if_possible("Deletion of directory '%s' failed. " "Should I try again?", pathname)) ret = rmdir(pathname); @@ -319,6 +321,31 @@ ssize_t mingw_write(int fd, const void *buf, size_t count) return write(fd, buf, min(count, 31 * 1024 * 1024)); } +static BOOL WINAPI ctrl_ignore(DWORD type) +{ + return TRUE; +} + +#undef fgetc +int mingw_fgetc(FILE *stream) +{ + int ch; + if (!isatty(_fileno(stream))) + return fgetc(stream); + + SetConsoleCtrlHandler(ctrl_ignore, TRUE); + while (1) { + ch = fgetc(stream); + if (ch != EOF || GetLastError() != ERROR_OPERATION_ABORTED) + break; + + /* Ctrl+C was pressed, simulate SIGINT and retry */ + mingw_raise(SIGINT); + } + SetConsoleCtrlHandler(ctrl_ignore, FALSE); + return ch; +} + #undef fopen FILE *mingw_fopen (const char *filename, const char *otype) { @@ -335,6 +362,28 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) return freopen(filename, otype, stream); } +#undef fflush +int mingw_fflush(FILE *stream) +{ + int ret = fflush(stream); + + /* + * write() is used behind the scenes of stdio output functions. + * Since git code does not check for errors after each stdio write + * operation, it can happen that write() is called by a later + * stdio function even if an earlier write() call failed. In the + * case of a pipe whose readable end was closed, only the first + * call to write() reports EPIPE on Windows. Subsequent write() + * calls report EINVAL. It is impossible to notice whether this + * fflush invocation triggered such a case, therefore, we have to + * catch all EINVAL errors whole-sale. + */ + if (ret && errno == EINVAL) + errno = EPIPE; + + return ret; +} + /* * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC. * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch. @@ -1524,7 +1573,7 @@ static HANDLE timer_event; static HANDLE timer_thread; static int timer_interval; static int one_shot; -static sig_handler_t timer_fn = SIG_DFL; +static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL; /* The timer works like this: * The thread, ticktack(), is a trivial routine that most of the time @@ -1538,10 +1587,7 @@ static sig_handler_t timer_fn = SIG_DFL; static unsigned __stdcall ticktack(void *dummy) { while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) { - if (timer_fn == SIG_DFL) - die("Alarm"); - if (timer_fn != SIG_IGN) - timer_fn(SIGALRM); + mingw_raise(SIGALRM); if (one_shot) break; } @@ -1632,12 +1678,49 @@ int sigaction(int sig, struct sigaction *in, struct sigaction *out) sig_handler_t mingw_signal(int sig, sig_handler_t handler) { sig_handler_t old = timer_fn; - if (sig != SIGALRM) + + switch (sig) { + case SIGALRM: + timer_fn = handler; + break; + + case SIGINT: + sigint_fn = handler; + break; + + default: return signal(sig, handler); - timer_fn = handler; + } + return old; } +#undef raise +int mingw_raise(int sig) +{ + switch (sig) { + case SIGALRM: + if (timer_fn == SIG_DFL) { + if (isatty(STDERR_FILENO)) + fputs("Alarm clock\n", stderr); + exit(128 + SIGALRM); + } else if (timer_fn != SIG_IGN) + timer_fn(SIGALRM); + return 0; + + case SIGINT: + if (sigint_fn == SIG_DFL) + exit(128 + SIGINT); + else if (sigint_fn != SIG_IGN) + sigint_fn(SIGINT); + return 0; + + default: + return raise(sig); + } +} + + static const char *make_backslash_path(const char *path) { static char buf[PATH_MAX + 1]; @@ -1699,21 +1782,6 @@ int link(const char *oldpath, const char *newpath) return 0; } -char *getpass(const char *prompt) -{ - struct strbuf buf = STRBUF_INIT; - - fputs(prompt, stderr); - for (;;) { - char c = _getch(); - if (c == '\r' || c == '\n') - break; - strbuf_addch(&buf, c); - } - fputs("\n", stderr); - return strbuf_detach(&buf, NULL); -} - pid_t waitpid(pid_t pid, int *status, int options) { HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, diff --git a/compat/mingw.h b/compat/mingw.h index 61a652138..685cd2c3d 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -55,8 +55,6 @@ struct passwd { char *pw_dir; }; -extern char *getpass(const char *prompt); - typedef void (__cdecl *sig_handler_t)(int); struct sigaction { sig_handler_t sa_handler; @@ -179,12 +177,18 @@ int mingw_open (const char *filename, int oflags, ...); ssize_t mingw_write(int fd, const void *buf, size_t count); #define write mingw_write +int mingw_fgetc(FILE *stream); +#define fgetc mingw_fgetc + FILE *mingw_fopen (const char *filename, const char *otype); #define fopen mingw_fopen FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream); #define freopen mingw_freopen +int mingw_fflush(FILE *stream); +#define fflush mingw_fflush + char *mingw_getcwd(char *pointer, int len); #define getcwd mingw_getcwd @@ -287,6 +291,9 @@ static inline unsigned int git_ntohl(unsigned int x) sig_handler_t mingw_signal(int sig, sig_handler_t handler); #define signal mingw_signal +int mingw_raise(int sig); +#define raise mingw_raise + /* * ANSI emulation wrappers */ diff --git a/compat/mkdir.c b/compat/mkdir.c new file mode 100644 index 000000000..9e253fb72 --- /dev/null +++ b/compat/mkdir.c @@ -0,0 +1,24 @@ +#include "../git-compat-util.h" +#undef mkdir + +/* for platforms that can't deal with a trailing '/' */ +int compat_mkdir_wo_trailing_slash(const char *dir, mode_t mode) +{ + int retval; + char *tmp_dir = NULL; + size_t len = strlen(dir); + + if (len && dir[len-1] == '/') { + if ((tmp_dir = strdup(dir)) == NULL) + return -1; + tmp_dir[len-1] = '\0'; + } + else + tmp_dir = (char *)dir; + + retval = mkdir(tmp_dir, mode); + if (tmp_dir != dir) + free(tmp_dir); + + return retval; +} diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c index d9a17a805..91c4e7f27 100644 --- a/compat/nedmalloc/nedmalloc.c +++ b/compat/nedmalloc/nedmalloc.c @@ -603,7 +603,10 @@ static NOINLINE mstate FindMSpace(nedpool *p, threadcache *tc, int *lastUsed, si } /* We really want to make sure this goes into memory now but we have to be careful of breaking aliasing rules, so write it twice */ - *((volatile struct malloc_state **) &p->m[end])=p->m[end]=temp; + { + volatile struct malloc_state **_m=(volatile struct malloc_state **) &p->m[end]; + *_m=(p->m[end]=temp); + } ACQUIRE_LOCK(&p->m[end]->mutex); /*printf("Created mspace idx %d\n", end);*/ RELEASE_LOCK(&p->mutex); diff --git a/compat/win32/poll.c b/compat/poll/poll.c index 403eaa7a3..7d226ecb2 100644 --- a/compat/win32/poll.c +++ b/compat/poll/poll.c @@ -24,7 +24,9 @@ # pragma GCC diagnostic ignored "-Wtype-limits" #endif -#include <malloc.h> +#if defined(WIN32) +# include <malloc.h> +#endif #include <sys/types.h> @@ -48,7 +50,9 @@ #else # include <sys/time.h> # include <sys/socket.h> -# include <sys/select.h> +# ifndef NO_SYS_SELECT_H +# include <sys/select.h> +# endif # include <unistd.h> #endif @@ -302,6 +306,10 @@ compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds) || socket_errno == ECONNABORTED || socket_errno == ENETRESET) happened |= POLLHUP; + /* some systems can't use recv() on non-socket, including HP NonStop */ + else if (/* (r == -1) && */ socket_errno == ENOTSOCK) + happened |= (POLLIN | POLLRDNORM) & sought; + else happened |= POLLERR; } @@ -349,7 +357,7 @@ poll (struct pollfd *pfd, nfds_t nfd, int timeout) /* EFAULT is not necessary to implement, but let's do it in the simplest case. */ - if (!pfd) + if (!pfd && nfd) { errno = EFAULT; return -1; diff --git a/compat/win32/poll.h b/compat/poll/poll.h index b7aa59d97..b7aa59d97 100644 --- a/compat/win32/poll.h +++ b/compat/poll/poll.h diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c new file mode 100644 index 000000000..8cf59558e --- /dev/null +++ b/compat/precompose_utf8.c @@ -0,0 +1,184 @@ +/* + * Converts filenames from decomposed unicode into precomposed unicode. + * Used on MacOS X. + */ + +#define PRECOMPOSE_UNICODE_C + +#include "cache.h" +#include "utf8.h" +#include "precompose_utf8.h" + +typedef char *iconv_ibp; +static const char *repo_encoding = "UTF-8"; +static const char *path_encoding = "UTF-8-MAC"; + +static size_t has_non_ascii(const char *s, size_t maxlen, size_t *strlen_c) +{ + const uint8_t *ptr = (const uint8_t *)s; + size_t strlen_chars = 0; + size_t ret = 0; + + if (!ptr || !*ptr) + return 0; + + while (*ptr && maxlen) { + if (*ptr & 0x80) + ret++; + strlen_chars++; + ptr++; + maxlen--; + } + if (strlen_c) + *strlen_c = strlen_chars; + + return ret; +} + + +void probe_utf8_pathname_composition(char *path, int len) +{ + static const char *auml_nfc = "\xc3\xa4"; + static const char *auml_nfd = "\x61\xcc\x88"; + int output_fd; + if (precomposed_unicode != -1) + return; /* We found it defined in the global config, respect it */ + strcpy(path + len, auml_nfc); + output_fd = open(path, O_CREAT|O_EXCL|O_RDWR, 0600); + if (output_fd >= 0) { + close(output_fd); + strcpy(path + len, auml_nfd); + /* Indicate to the user, that we can configure it to true */ + if (!access(path, R_OK)) + git_config_set("core.precomposeunicode", "false"); + /* To be backward compatible, set precomposed_unicode to 0 */ + precomposed_unicode = 0; + strcpy(path + len, auml_nfc); + if (unlink(path)) + die_errno(_("failed to unlink '%s'"), path); + } +} + + +void precompose_argv(int argc, const char **argv) +{ + int i = 0; + const char *oldarg; + char *newarg; + iconv_t ic_precompose; + + if (precomposed_unicode != 1) + return; + + ic_precompose = iconv_open(repo_encoding, path_encoding); + if (ic_precompose == (iconv_t) -1) + return; + + while (i < argc) { + size_t namelen; + oldarg = argv[i]; + if (has_non_ascii(oldarg, (size_t)-1, &namelen)) { + newarg = reencode_string_iconv(oldarg, namelen, ic_precompose); + if (newarg) + argv[i] = newarg; + } + i++; + } + iconv_close(ic_precompose); +} + + +PREC_DIR *precompose_utf8_opendir(const char *dirname) +{ + PREC_DIR *prec_dir = xmalloc(sizeof(PREC_DIR)); + prec_dir->dirent_nfc = xmalloc(sizeof(dirent_prec_psx)); + prec_dir->dirent_nfc->max_name_len = sizeof(prec_dir->dirent_nfc->d_name); + + prec_dir->dirp = opendir(dirname); + if (!prec_dir->dirp) { + free(prec_dir->dirent_nfc); + free(prec_dir); + return NULL; + } else { + int ret_errno = errno; + prec_dir->ic_precompose = iconv_open(repo_encoding, path_encoding); + /* if iconv_open() fails, die() in readdir() if needed */ + errno = ret_errno; + } + + return prec_dir; +} + +struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir) +{ + struct dirent *res; + res = readdir(prec_dir->dirp); + if (res) { + size_t namelenz = strlen(res->d_name) + 1; /* \0 */ + size_t new_maxlen = namelenz; + + int ret_errno = errno; + + if (new_maxlen > prec_dir->dirent_nfc->max_name_len) { + size_t new_len = sizeof(dirent_prec_psx) + new_maxlen - + sizeof(prec_dir->dirent_nfc->d_name); + + prec_dir->dirent_nfc = xrealloc(prec_dir->dirent_nfc, new_len); + prec_dir->dirent_nfc->max_name_len = new_maxlen; + } + + prec_dir->dirent_nfc->d_ino = res->d_ino; + prec_dir->dirent_nfc->d_type = res->d_type; + + if ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) { + if (prec_dir->ic_precompose == (iconv_t)-1) { + die("iconv_open(%s,%s) failed, but needed:\n" + " precomposed unicode is not supported.\n" + " If you wnat to use decomposed unicode, run\n" + " \"git config core.precomposeunicode false\"\n", + repo_encoding, path_encoding); + } else { + iconv_ibp cp = (iconv_ibp)res->d_name; + size_t inleft = namelenz; + char *outpos = &prec_dir->dirent_nfc->d_name[0]; + size_t outsz = prec_dir->dirent_nfc->max_name_len; + size_t cnt; + errno = 0; + cnt = iconv(prec_dir->ic_precompose, &cp, &inleft, &outpos, &outsz); + if (errno || inleft) { + /* + * iconv() failed and errno could be E2BIG, EILSEQ, EINVAL, EBADF + * MacOS X avoids illegal byte sequemces. + * If they occur on a mounted drive (e.g. NFS) it is not worth to + * die() for that, but rather let the user see the original name + */ + namelenz = 0; /* trigger strlcpy */ + } + } + } else + namelenz = 0; + + if (!namelenz) + strlcpy(prec_dir->dirent_nfc->d_name, res->d_name, + prec_dir->dirent_nfc->max_name_len); + + errno = ret_errno; + return prec_dir->dirent_nfc; + } + return NULL; +} + + +int precompose_utf8_closedir(PREC_DIR *prec_dir) +{ + int ret_value; + int ret_errno; + ret_value = closedir(prec_dir->dirp); + ret_errno = errno; + if (prec_dir->ic_precompose != (iconv_t)-1) + iconv_close(prec_dir->ic_precompose); + free(prec_dir->dirent_nfc); + free(prec_dir); + errno = ret_errno; + return ret_value; +} diff --git a/compat/precompose_utf8.h b/compat/precompose_utf8.h new file mode 100644 index 000000000..3b73585fc --- /dev/null +++ b/compat/precompose_utf8.h @@ -0,0 +1,45 @@ +#ifndef PRECOMPOSE_UNICODE_H +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> +#include <iconv.h> + + +typedef struct dirent_prec_psx { + ino_t d_ino; /* Posix */ + size_t max_name_len; /* See below */ + unsigned char d_type; /* available on all systems git runs on */ + + /* + * See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html + * NAME_MAX + 1 should be enough, but some systems have + * NAME_MAX=255 and strlen(d_name) may return 508 or 510 + * Solution: allocate more when needed, see precompose_utf8_readdir() + */ + char d_name[NAME_MAX+1]; +} dirent_prec_psx; + + +typedef struct { + iconv_t ic_precompose; + DIR *dirp; + struct dirent_prec_psx *dirent_nfc; +} PREC_DIR; + +void precompose_argv(int argc, const char **argv); +void probe_utf8_pathname_composition(char *, int); + +PREC_DIR *precompose_utf8_opendir(const char *dirname); +struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *dirp); +int precompose_utf8_closedir(PREC_DIR *dirp); + +#ifndef PRECOMPOSE_UNICODE_C +#define dirent dirent_prec_psx +#define opendir(n) precompose_utf8_opendir(n) +#define readdir(d) precompose_utf8_readdir(d) +#define closedir(d) precompose_utf8_closedir(d) +#define DIR PREC_DIR +#endif /* PRECOMPOSE_UNICODE_C */ + +#define PRECOMPOSE_UNICODE_H +#endif /* PRECOMPOSE_UNICODE_H */ diff --git a/compat/terminal.c b/compat/terminal.c index bbb038dd0..9b5e3d1bb 100644 --- a/compat/terminal.c +++ b/compat/terminal.c @@ -3,8 +3,22 @@ #include "sigchain.h" #include "strbuf.h" +#if defined(HAVE_DEV_TTY) || defined(WIN32) + +static void restore_term(void); + +static void restore_term_on_signal(int sig) +{ + restore_term(); + sigchain_pop(sig); + raise(sig); +} + #ifdef HAVE_DEV_TTY +#define INPUT_PATH "/dev/tty" +#define OUTPUT_PATH "/dev/tty" + static int term_fd = -1; static struct termios old_term; @@ -14,58 +28,109 @@ static void restore_term(void) return; tcsetattr(term_fd, TCSAFLUSH, &old_term); + close(term_fd); term_fd = -1; } -static void restore_term_on_signal(int sig) +static int disable_echo(void) { - restore_term(); - sigchain_pop(sig); - raise(sig); + struct termios t; + + term_fd = open("/dev/tty", O_RDWR); + if (tcgetattr(term_fd, &t) < 0) + goto error; + + old_term = t; + sigchain_push_common(restore_term_on_signal); + + t.c_lflag &= ~ECHO; + if (!tcsetattr(term_fd, TCSAFLUSH, &t)) + return 0; + +error: + close(term_fd); + term_fd = -1; + return -1; +} + +#elif defined(WIN32) + +#define INPUT_PATH "CONIN$" +#define OUTPUT_PATH "CONOUT$" +#define FORCE_TEXT "t" + +static HANDLE hconin = INVALID_HANDLE_VALUE; +static DWORD cmode; + +static void restore_term(void) +{ + if (hconin == INVALID_HANDLE_VALUE) + return; + + SetConsoleMode(hconin, cmode); + CloseHandle(hconin); + hconin = INVALID_HANDLE_VALUE; } +static int disable_echo(void) +{ + hconin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (hconin == INVALID_HANDLE_VALUE) + return -1; + + GetConsoleMode(hconin, &cmode); + sigchain_push_common(restore_term_on_signal); + if (!SetConsoleMode(hconin, cmode & (~ENABLE_ECHO_INPUT))) { + CloseHandle(hconin); + hconin = INVALID_HANDLE_VALUE; + return -1; + } + + return 0; +} + +#endif + +#ifndef FORCE_TEXT +#define FORCE_TEXT +#endif + char *git_terminal_prompt(const char *prompt, int echo) { static struct strbuf buf = STRBUF_INIT; int r; - FILE *fh; + FILE *input_fh, *output_fh; - fh = fopen("/dev/tty", "w+"); - if (!fh) + input_fh = fopen(INPUT_PATH, "r" FORCE_TEXT); + if (!input_fh) return NULL; - if (!echo) { - struct termios t; - - if (tcgetattr(fileno(fh), &t) < 0) { - fclose(fh); - return NULL; - } - - old_term = t; - term_fd = fileno(fh); - sigchain_push_common(restore_term_on_signal); - - t.c_lflag &= ~ECHO; - if (tcsetattr(fileno(fh), TCSAFLUSH, &t) < 0) { - term_fd = -1; - fclose(fh); - return NULL; - } + output_fh = fopen(OUTPUT_PATH, "w" FORCE_TEXT); + if (!output_fh) { + fclose(input_fh); + return NULL; + } + + if (!echo && disable_echo()) { + fclose(input_fh); + fclose(output_fh); + return NULL; } - fputs(prompt, fh); - fflush(fh); + fputs(prompt, output_fh); + fflush(output_fh); - r = strbuf_getline(&buf, fh, '\n'); + r = strbuf_getline(&buf, input_fh, '\n'); if (!echo) { - fseek(fh, SEEK_CUR, 0); - putc('\n', fh); - fflush(fh); + putc('\n', output_fh); + fflush(output_fh); } restore_term(); - fclose(fh); + fclose(input_fh); + fclose(output_fh); if (r == EOF) return NULL; @@ -10,8 +10,6 @@ #include "strbuf.h" #include "quote.h" -#define MAXNAME (256) - typedef struct config_file { struct config_file *prev; FILE *f; @@ -19,7 +17,7 @@ typedef struct config_file { int linenr; int eof; struct strbuf value; - char var[MAXNAME]; + struct strbuf var; } config_file; static config_file *cf; @@ -60,7 +58,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc path = buf.buf; } - if (!access(path, R_OK)) { + if (!access_or_die(path, R_OK)) { if (++inc->depth > MAX_INCLUDE_DEPTH) die(include_depth_advice, MAX_INCLUDE_DEPTH, path, cf && cf->name ? cf->name : "the command line"); @@ -260,7 +258,7 @@ static inline int iskeychar(int c) return isalnum(c) || c == '-'; } -static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) +static int get_value(config_fn_t fn, void *data, struct strbuf *name) { int c; char *value; @@ -272,11 +270,9 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) break; if (!iskeychar(c)) break; - name[len++] = tolower(c); - if (len >= MAXNAME) - return -1; + strbuf_addch(name, tolower(c)); } - name[len] = 0; + while (c == ' ' || c == '\t') c = get_next_char(); @@ -288,10 +284,10 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) if (!value) return -1; } - return fn(name, value, data); + return fn(name->buf, value, data); } -static int get_extended_base_var(char *name, int baselen, int c) +static int get_extended_base_var(struct strbuf *name, int c) { do { if (c == '\n') @@ -302,7 +298,7 @@ static int get_extended_base_var(char *name, int baselen, int c) /* We require the format to be '[base "extension"]' */ if (c != '"') return -1; - name[baselen++] = '.'; + strbuf_addch(name, '.'); for (;;) { int c = get_next_char(); @@ -315,37 +311,31 @@ static int get_extended_base_var(char *name, int baselen, int c) if (c == '\n') goto error_incomplete_line; } - name[baselen++] = c; - if (baselen > MAXNAME / 2) - return -1; + strbuf_addch(name, c); } /* Final ']' */ if (get_next_char() != ']') return -1; - return baselen; + return 0; error_incomplete_line: cf->linenr--; return -1; } -static int get_base_var(char *name) +static int get_base_var(struct strbuf *name) { - int baselen = 0; - for (;;) { int c = get_next_char(); if (cf->eof) return -1; if (c == ']') - return baselen; + return 0; if (isspace(c)) - return get_extended_base_var(name, baselen, c); + return get_extended_base_var(name, c); if (!iskeychar(c) && c != '.') return -1; - if (baselen > MAXNAME / 2) - return -1; - name[baselen++] = tolower(c); + strbuf_addch(name, tolower(c)); } } @@ -353,7 +343,7 @@ static int git_parse_file(config_fn_t fn, void *data) { int comment = 0; int baselen = 0; - char *var = cf->var; + struct strbuf *var = &cf->var; /* U+FEFF Byte Order Mark in UTF8 */ static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf"; @@ -389,17 +379,24 @@ static int git_parse_file(config_fn_t fn, void *data) continue; } if (c == '[') { - baselen = get_base_var(var); - if (baselen <= 0) + /* Reset prior to determining a new stem */ + strbuf_reset(var); + if (get_base_var(var) < 0 || var->len < 1) break; - var[baselen++] = '.'; - var[baselen] = 0; + strbuf_addch(var, '.'); + baselen = var->len; continue; } if (!isalpha(c)) break; - var[baselen] = tolower(c); - if (get_value(fn, data, var, baselen+1) < 0) + /* + * Truncate the var name back to the section header + * stem prior to grabbing the suffix part of the name + * and the value. + */ + strbuf_setlen(var, baselen); + strbuf_addch(var, tolower(c)); + if (get_value(fn, data, var) < 0) break; } die("bad config file line %d in %s", cf->linenr, cf->name); @@ -758,6 +755,11 @@ static int git_default_core_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.precomposeunicode")) { + precomposed_unicode = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.txt. */ return 0; } @@ -894,12 +896,14 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data) top.linenr = 1; top.eof = 0; strbuf_init(&top.value, 1024); + strbuf_init(&top.var, 1024); cf = ⊤ ret = git_parse_file(fn, data); /* pop config-file parsing state stack */ strbuf_release(&top.value); + strbuf_release(&top.var); cf = top.prev; fclose(f); @@ -929,25 +933,28 @@ int git_config_system(void) int git_config_early(config_fn_t fn, void *data, const char *repo_config) { int ret = 0, found = 0; - const char *home = NULL; + char *xdg_config = NULL; + char *user_config = NULL; + + home_config_paths(&user_config, &xdg_config, "config"); - if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) { + if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK)) { ret += git_config_from_file(fn, git_etc_gitconfig(), data); found += 1; } - home = getenv("HOME"); - if (home) { - char buf[PATH_MAX]; - char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home); - if (!access(user_config, R_OK)) { - ret += git_config_from_file(fn, user_config, data); - found += 1; - } + if (xdg_config && !access_or_die(xdg_config, R_OK)) { + ret += git_config_from_file(fn, xdg_config, data); + found += 1; + } + + if (user_config && !access_or_die(user_config, R_OK)) { + ret += git_config_from_file(fn, user_config, data); + found += 1; } - if (repo_config && !access(repo_config, R_OK)) { + if (repo_config && !access_or_die(repo_config, R_OK)) { ret += git_config_from_file(fn, repo_config, data); found += 1; } @@ -963,6 +970,8 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) break; } + free(xdg_config); + free(user_config); return ret == 0 ? found : ret; } @@ -1270,6 +1279,7 @@ int git_config_parse_key(const char *key, char **store_key, int *baselen_) out_free_ret_1: free(*store_key); + *store_key = NULL; return -CONFIG_INVALID_KEY; } diff --git a/config.mak.in b/config.mak.in index b2ba7104e..e8a9bb468 100644 --- a/config.mak.in +++ b/config.mak.in @@ -5,12 +5,10 @@ CC = @CC@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ -CC_LD_DYNPATH = @CC_LD_DYNPATH@ AR = @AR@ TAR = @TAR@ DIFF = @DIFF@ #INSTALL = @INSTALL@ # needs install-sh or install.sh in sources -TCLTK_PATH = @TCLTK_PATH@ prefix = @prefix@ exec_prefix = @exec_prefix@ @@ -20,58 +18,10 @@ datarootdir = @datarootdir@ template_dir = @datadir@/git-core/templates sysconfdir = @sysconfdir@ -mandir=@mandir@ +mandir = @mandir@ srcdir = @srcdir@ VPATH = @srcdir@ export exec_prefix mandir export srcdir VPATH - -ASCIIDOC7=@ASCIIDOC7@ -NEEDS_SSL_WITH_CRYPTO=@NEEDS_SSL_WITH_CRYPTO@ -NO_OPENSSL=@NO_OPENSSL@ -NO_CURL=@NO_CURL@ -NO_EXPAT=@NO_EXPAT@ -NO_LIBGEN_H=@NO_LIBGEN_H@ -HAVE_PATHS_H=@HAVE_PATHS_H@ -HAVE_LIBCHARSET_H=@HAVE_LIBCHARSET_H@ -NO_GETTEXT=@NO_GETTEXT@ -LIBC_CONTAINS_LIBINTL=@LIBC_CONTAINS_LIBINTL@ -NEEDS_LIBICONV=@NEEDS_LIBICONV@ -NEEDS_SOCKET=@NEEDS_SOCKET@ -NEEDS_RESOLV=@NEEDS_RESOLV@ -NEEDS_LIBGEN=@NEEDS_LIBGEN@ -NO_SYS_SELECT_H=@NO_SYS_SELECT_H@ -NO_D_INO_IN_DIRENT=@NO_D_INO_IN_DIRENT@ -NO_D_TYPE_IN_DIRENT=@NO_D_TYPE_IN_DIRENT@ -NO_SOCKADDR_STORAGE=@NO_SOCKADDR_STORAGE@ -NO_IPV6=@NO_IPV6@ -NO_HSTRERROR=@NO_HSTRERROR@ -NO_STRCASESTR=@NO_STRCASESTR@ -NO_STRTOK_R=@NO_STRTOK_R@ -NO_FNMATCH=@NO_FNMATCH@ -NO_FNMATCH_CASEFOLD=@NO_FNMATCH_CASEFOLD@ -NO_MEMMEM=@NO_MEMMEM@ -NO_STRLCPY=@NO_STRLCPY@ -NO_UINTMAX_T=@NO_UINTMAX_T@ -NO_STRTOUMAX=@NO_STRTOUMAX@ -NO_SETENV=@NO_SETENV@ -NO_UNSETENV=@NO_UNSETENV@ -NO_MKDTEMP=@NO_MKDTEMP@ -NO_MKSTEMPS=@NO_MKSTEMPS@ -NO_INET_NTOP=@NO_INET_NTOP@ -NO_INET_PTON=@NO_INET_PTON@ -NO_ICONV=@NO_ICONV@ -OLD_ICONV=@OLD_ICONV@ -NO_REGEX=@NO_REGEX@ -USE_LIBPCRE=@USE_LIBPCRE@ -NO_DEFLATE_BOUND=@NO_DEFLATE_BOUND@ -INLINE=@INLINE@ -SOCKLEN_T=@SOCKLEN_T@ -FREAD_READS_DIRECTORIES=@FREAD_READS_DIRECTORIES@ -SNPRINTF_RETURNS_BOGUS=@SNPRINTF_RETURNS_BOGUS@ -NO_PTHREADS=@NO_PTHREADS@ -PTHREAD_CFLAGS=@PTHREAD_CFLAGS@ -PTHREAD_LIBS=@PTHREAD_LIBS@ -CHARSET_LIB=@CHARSET_LIB@ diff --git a/configure.ac b/configure.ac index e1255506a..41ac9a5e2 100644 --- a/configure.ac +++ b/configure.ac @@ -3,11 +3,25 @@ ## Definitions of private macros. -# GIT_CONF_APPEND_LINE(LINE) -# -------------------------- -# Append LINE to file ${config_append} -AC_DEFUN([GIT_CONF_APPEND_LINE], - [echo "$1" >> "${config_append}"]) +# GIT_CONF_SUBST(VAL, VAR) +# ------------------------ +# Cause the line "VAR=VAL" to be eventually appended to ${config_file}. +AC_DEFUN([GIT_CONF_SUBST], +[AC_REQUIRE([GIT_CONF_SUBST_INIT]) +config_appended_defs="$config_appended_defs${newline}dnl +$1=m4_if([$#],[1],[${$1}],[$2])"]) + +# GIT_CONF_SUBST_INIT +# ------------------- +# Prepare shell variables and autoconf machine required by later calls +# to GIT_CONF_SUBST. +AC_DEFUN([GIT_CONF_SUBST_INIT], + [config_appended_defs=; newline=' +' + AC_CONFIG_COMMANDS([$config_file], + [echo "$config_appended_defs" >> "$config_file"], + [config_file=$config_file + config_appended_defs="$config_appended_defs"])]) # GIT_ARG_SET_PATH(PROGRAM) # ------------------------- @@ -29,13 +43,12 @@ AC_DEFUN([GIT_ARG_SET_PATH], # --without-PROGRAM is used. AC_DEFUN([GIT_CONF_APPEND_PATH], [m4_pushdef([GIT_UC_PROGRAM], m4_toupper([$1]))dnl - PROGRAM=GIT_UC_PROGRAM if test "$withval" = "no"; then if test -n "$2"; then GIT_UC_PROGRAM[]_PATH=$withval - AC_MSG_NOTICE([Disabling use of ${PROGRAM}]) - GIT_CONF_APPEND_LINE(NO_${PROGRAM}=YesPlease) - GIT_CONF_APPEND_LINE(${PROGRAM}_PATH=) + AC_MSG_NOTICE([Disabling use of GIT_UC_PROGRAM]) + GIT_CONF_SUBST([NO_]GIT_UC_PROGRAM, [YesPlease]) + GIT_CONF_SUBST(GIT_UC_PROGRAM[]_PATH, []) else AC_MSG_ERROR([You cannot use git without $1]) fi @@ -45,7 +58,7 @@ AC_DEFUN([GIT_CONF_APPEND_PATH], else GIT_UC_PROGRAM[]_PATH=$withval AC_MSG_NOTICE([Setting GIT_UC_PROGRAM[]_PATH to $withval]) - GIT_CONF_APPEND_LINE(${PROGRAM}_PATH=$withval) + GIT_CONF_SUBST(GIT_UC_PROGRAM[]_PATH, [$withval]) fi fi m4_popdef([GIT_UC_PROGRAM])]) @@ -58,7 +71,6 @@ AC_DEFUN([GIT_CONF_APPEND_PATH], # * Unset NO_PACKAGE for --with-PACKAGE without ARG AC_DEFUN([GIT_PARSE_WITH], [m4_pushdef([GIT_UC_PACKAGE], m4_toupper([$1]))dnl - PACKAGE=GIT_UC_PACKAGE if test "$withval" = "no"; then NO_[]GIT_UC_PACKAGE=YesPlease elif test "$withval" = "yes"; then @@ -67,7 +79,7 @@ AC_DEFUN([GIT_PARSE_WITH], NO_[]GIT_UC_PACKAGE= GIT_UC_PACKAGE[]DIR=$withval AC_MSG_NOTICE([Setting GIT_UC_PACKAGE[]DIR to $withval]) - GIT_CONF_APPEND_LINE(${PACKAGE}DIR=$withval) + GIT_CONF_SUBST(GIT_UC_PACKAGE[DIR], [$withval]) fi m4_popdef([GIT_UC_PACKAGE])]) @@ -87,7 +99,7 @@ AC_DEFUN([GIT_PARSE_WITH_SET_MAKE_VAR], [a value for $1 ($2). Maybe you do...?]) fi AC_MSG_NOTICE([Setting $2 to $withval]) - GIT_CONF_APPEND_LINE($2=$withval) + GIT_CONF_SUBST([$2], [$withval]) fi)])# GIT_PARSE_WITH_SET_MAKE_VAR # @@ -135,10 +147,9 @@ AC_INIT([git], [@@GIT_VERSION@@], [git@vger.kernel.org]) AC_CONFIG_SRCDIR([git.c]) config_file=config.mak.autogen -config_append=config.mak.append config_in=config.mak.in -echo "# ${config_append}. Generated by configure." > "${config_append}" +GIT_CONF_SUBST([AUTOCONFIGURED], [YesPlease]) # Directories holding "saner" versions of common or POSIX binaries. AC_ARG_WITH([sane-tool-path], @@ -150,7 +161,7 @@ AC_ARG_WITH([sane-tool-path], else AC_MSG_NOTICE([Setting SANE_TOOL_PATH to '$withval']) fi - GIT_CONF_APPEND_LINE([SANE_TOOL_PATH=$withval])], + GIT_CONF_SUBST([SANE_TOOL_PATH], [$withval])], [# If the "--with-sane-tool-path" option was not given, don't touch # SANE_TOOL_PATH here, but let defaults in Makefile take care of it. # This should minimize spurious differences in the behaviour of the @@ -169,7 +180,7 @@ AC_ARG_WITH([lib], else lib=$withval AC_MSG_NOTICE([Setting lib to '$lib']) - GIT_CONF_APPEND_LINE(lib=$withval) + GIT_CONF_SUBST([lib]) fi]) if test -z "$lib"; then @@ -205,7 +216,7 @@ AC_ARG_ENABLE([jsmin], [ JSMIN=$enableval; AC_MSG_NOTICE([Setting JSMIN to '$JSMIN' to enable JavaScript minifying]) - GIT_CONF_APPEND_LINE(JSMIN=$enableval); + GIT_CONF_SUBST([JSMIN]) ]) # Define option to enable CSS minification @@ -215,7 +226,7 @@ AC_ARG_ENABLE([cssmin], [ CSSMIN=$enableval; AC_MSG_NOTICE([Setting CSSMIN to '$CSSMIN' to enable CSS minifying]) - GIT_CONF_APPEND_LINE(CSSMIN=$enableval); + GIT_CONF_SUBST([CSSMIN]) ]) ## Site configuration (override autodetection) @@ -255,8 +266,10 @@ AS_HELP_STRING([], [ARG can be also prefix for libpcre library and hea else USE_LIBPCRE=YesPlease LIBPCREDIR=$withval - AC_MSG_NOTICE([Setting LIBPCREDIR to $withval]) - GIT_CONF_APPEND_LINE(LIBPCREDIR=$withval) + AC_MSG_NOTICE([Setting LIBPCREDIR to $LIBPCREDIR]) + dnl USE_LIBPCRE can still be modified below, so don't substitute + dnl it yet. + GIT_CONF_SUBST([LIBPCREDIR]) fi) # # Define NO_CURL if you do not have curl installed. git-http-pull and @@ -376,9 +389,10 @@ AC_MSG_NOTICE([CHECKS for programs]) AC_PROG_CC([cc gcc]) AC_C_INLINE case $ac_cv_c_inline in - inline | yes | no) ;; - *) AC_SUBST([INLINE], [$ac_cv_c_inline]) ;; + inline | yes | no) INLINE='';; + *) INLINE=$ac_cv_c_inline ;; esac +GIT_CONF_SUBST([INLINE]) # which switch to pass runtime path to dynamic libraries to the linker AC_CACHE_CHECK([if linker supports -R], git_cv_ld_dashr, [ @@ -388,7 +402,7 @@ AC_CACHE_CHECK([if linker supports -R], git_cv_ld_dashr, [ LDFLAGS="${SAVE_LDFLAGS}" ]) if test "$git_cv_ld_dashr" = "yes"; then - AC_SUBST(CC_LD_DYNPATH, [-R]) + CC_LD_DYNPATH=-R else AC_CACHE_CHECK([if linker supports -Wl,-rpath,], git_cv_ld_wl_rpath, [ SAVE_LDFLAGS="${LDFLAGS}" @@ -397,7 +411,7 @@ else LDFLAGS="${SAVE_LDFLAGS}" ]) if test "$git_cv_ld_wl_rpath" = "yes"; then - AC_SUBST(CC_LD_DYNPATH, [-Wl,-rpath,]) + CC_LD_DYNPATH=-Wl,-rpath, else AC_CACHE_CHECK([if linker supports -rpath], git_cv_ld_rpath, [ SAVE_LDFLAGS="${LDFLAGS}" @@ -406,52 +420,48 @@ else LDFLAGS="${SAVE_LDFLAGS}" ]) if test "$git_cv_ld_rpath" = "yes"; then - AC_SUBST(CC_LD_DYNPATH, [-rpath]) + CC_LD_DYNPATH=-rpath else + CC_LD_DYNPATH= AC_MSG_WARN([linker does not support runtime path to dynamic libraries]) fi fi fi +GIT_CONF_SUBST([CC_LD_DYNPATH]) #AC_PROG_INSTALL # needs install-sh or install.sh in sources AC_CHECK_TOOLS(AR, [gar ar], :) AC_CHECK_PROGS(TAR, [gtar tar]) AC_CHECK_PROGS(DIFF, [gnudiff gdiff diff]) # TCLTK_PATH will be set to some value if we want Tcl/Tk # or will be empty otherwise. -if test -z "$NO_TCLTK"; then +if test -n "$NO_TCLTK"; then + TCLTK_PATH= +else if test "$with_tcltk" = ""; then # No Tcl/Tk switches given. Do not check for Tcl/Tk, use bare 'wish'. TCLTK_PATH=wish - AC_SUBST(TCLTK_PATH) elif test "$with_tcltk" = "yes"; then # Tcl/Tk check requested. AC_CHECK_PROGS(TCLTK_PATH, [wish], ) else AC_MSG_RESULT([Using Tcl/Tk interpreter $with_tcltk]) TCLTK_PATH="$with_tcltk" - AC_SUBST(TCLTK_PATH) fi fi +GIT_CONF_SUBST([TCLTK_PATH]) AC_CHECK_PROGS(ASCIIDOC, [asciidoc]) if test -n "$ASCIIDOC"; then AC_MSG_CHECKING([for asciidoc version]) asciidoc_version=`$ASCIIDOC --version 2>/dev/null` case "${asciidoc_version}" in - asciidoc' '7*) - ASCIIDOC7=YesPlease - AC_MSG_RESULT([${asciidoc_version} > 7]) - ;; asciidoc' '8*) - ASCIIDOC7= AC_MSG_RESULT([${asciidoc_version}]) ;; *) - ASCIIDOC7= AC_MSG_RESULT([${asciidoc_version} (unknown)]) ;; esac fi -AC_SUBST(ASCIIDOC7) ## Checks for libraries. @@ -465,13 +475,13 @@ GIT_STASH_FLAGS($OPENSSLDIR) AC_CHECK_LIB([crypto], [SHA1_Init], [NEEDS_SSL_WITH_CRYPTO=], [AC_CHECK_LIB([ssl], [SHA1_Init], - [NEEDS_SSL_WITH_CRYPTO=YesPlease], - [NEEDS_SSL_WITH_CRYPTO= NO_OPENSSL=YesPlease])]) + [NEEDS_SSL_WITH_CRYPTO=YesPlease NO_OPENSSL=], + [NEEDS_SSL_WITH_CRYPTO= NO_OPENSSL=YesPlease])]) GIT_UNSTASH_FLAGS($OPENSSLDIR) -AC_SUBST(NEEDS_SSL_WITH_CRYPTO) -AC_SUBST(NO_OPENSSL) +GIT_CONF_SUBST([NEEDS_SSL_WITH_CRYPTO]) +GIT_CONF_SUBST([NO_OPENSSL]) # # Define USE_LIBPCRE if you have and want to use libpcre. git-grep will be @@ -488,7 +498,7 @@ AC_CHECK_LIB([pcre], [pcre_version], GIT_UNSTASH_FLAGS($LIBPCREDIR) -AC_SUBST(USE_LIBPCRE) +GIT_CONF_SUBST([USE_LIBPCRE]) fi @@ -505,7 +515,7 @@ AC_CHECK_LIB([curl], [curl_global_init], GIT_UNSTASH_FLAGS($CURLDIR) -AC_SUBST(NO_CURL) +GIT_CONF_SUBST([NO_CURL]) # # Define NO_EXPAT if you do not have expat installed. git-http-push is @@ -519,7 +529,7 @@ AC_CHECK_LIB([expat], [XML_ParserCreate], GIT_UNSTASH_FLAGS($EXPATDIR) -AC_SUBST(NO_EXPAT) +GIT_CONF_SUBST([NO_EXPAT]) # # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin and @@ -565,8 +575,8 @@ LIBS="$old_LIBS" GIT_UNSTASH_FLAGS($ICONVDIR) -AC_SUBST(NEEDS_LIBICONV) -AC_SUBST(NO_ICONV) +GIT_CONF_SUBST([NEEDS_LIBICONV]) +GIT_CONF_SUBST([NO_ICONV]) if test -n "$NO_ICONV"; then NEEDS_LIBICONV= @@ -593,7 +603,7 @@ LIBS="$old_LIBS" GIT_UNSTASH_FLAGS($ZLIB_PATH) -AC_SUBST(NO_DEFLATE_BOUND) +GIT_CONF_SUBST([NO_DEFLATE_BOUND]) # # Define NEEDS_SOCKET if linking with libc is not enough (SunOS, @@ -601,7 +611,7 @@ AC_SUBST(NO_DEFLATE_BOUND) AC_CHECK_LIB([c], [socket], [NEEDS_SOCKET=], [NEEDS_SOCKET=YesPlease]) -AC_SUBST(NEEDS_SOCKET) +GIT_CONF_SUBST([NEEDS_SOCKET]) test -n "$NEEDS_SOCKET" && LIBS="$LIBS -lsocket" # @@ -609,40 +619,43 @@ test -n "$NEEDS_SOCKET" && LIBS="$LIBS -lsocket" # libresolv provides some of the functions we would normally get # from libc. NEEDS_RESOLV= -AC_SUBST(NEEDS_RESOLV) # # Define NO_INET_NTOP if linking with -lresolv is not enough. # Solaris 2.7 in particular hos inet_ntop in -lresolv. NO_INET_NTOP= -AC_SUBST(NO_INET_NTOP) AC_CHECK_FUNC([inet_ntop], - [], + [], [AC_CHECK_LIB([resolv], [inet_ntop], - [NEEDS_RESOLV=YesPlease], + [NEEDS_RESOLV=YesPlease], [NO_INET_NTOP=YesPlease]) ]) +GIT_CONF_SUBST([NO_INET_NTOP]) # # Define NO_INET_PTON if linking with -lresolv is not enough. # Solaris 2.7 in particular hos inet_pton in -lresolv. NO_INET_PTON= -AC_SUBST(NO_INET_PTON) AC_CHECK_FUNC([inet_pton], - [], + [], [AC_CHECK_LIB([resolv], [inet_pton], - [NEEDS_RESOLV=YesPlease], + [NEEDS_RESOLV=YesPlease], [NO_INET_PTON=YesPlease]) ]) +GIT_CONF_SUBST([NO_INET_PTON]) # # Define NO_HSTRERROR if linking with -lresolv is not enough. # Solaris 2.6 in particular has no hstrerror, even in -lresolv. NO_HSTRERROR= AC_CHECK_FUNC([hstrerror], - [], + [], [AC_CHECK_LIB([resolv], [hstrerror], - [NEEDS_RESOLV=YesPlease], + [NEEDS_RESOLV=YesPlease], [NO_HSTRERROR=YesPlease]) ]) -AC_SUBST(NO_HSTRERROR) +GIT_CONF_SUBST([NO_HSTRERROR]) + +dnl This must go after all the possible places for its initialization, +dnl in the AC_CHECK_FUNC invocations above. +GIT_CONF_SUBST([NEEDS_RESOLV]) # # If any of the above tests determined that -lresolv is needed at # build-time, also set it here for remaining configure-time checks. @@ -651,13 +664,13 @@ test -n "$NEEDS_RESOLV" && LIBS="$LIBS -lresolv" AC_CHECK_LIB([c], [basename], [NEEDS_LIBGEN=], [NEEDS_LIBGEN=YesPlease]) -AC_SUBST(NEEDS_LIBGEN) +GIT_CONF_SUBST([NEEDS_LIBGEN]) test -n "$NEEDS_LIBGEN" && LIBS="$LIBS -lgen" AC_CHECK_LIB([c], [gettext], [LIBC_CONTAINS_LIBINTL=YesPlease], [LIBC_CONTAINS_LIBINTL=]) -AC_SUBST(LIBC_CONTAINS_LIBINTL) +GIT_CONF_SUBST([LIBC_CONTAINS_LIBINTL]) # # Define NO_GETTEXT if you don't want Git output to be translated. @@ -665,7 +678,7 @@ AC_SUBST(LIBC_CONTAINS_LIBINTL) AC_CHECK_HEADER([libintl.h], [NO_GETTEXT=], [NO_GETTEXT=YesPlease]) -AC_SUBST(NO_GETTEXT) +GIT_CONF_SUBST([NO_GETTEXT]) if test -z "$NO_GETTEXT"; then test -n "$LIBC_CONTAINS_LIBINTL" || LIBS="$LIBS -lintl" @@ -678,19 +691,19 @@ AC_MSG_NOTICE([CHECKS for header files]) AC_CHECK_HEADER([sys/select.h], [NO_SYS_SELECT_H=], [NO_SYS_SELECT_H=UnfortunatelyYes]) -AC_SUBST(NO_SYS_SELECT_H) +GIT_CONF_SUBST([NO_SYS_SELECT_H]) # # Define NO_SYS_POLL_H if you don't have sys/poll.h AC_CHECK_HEADER([sys/poll.h], [NO_SYS_POLL_H=], [NO_SYS_POLL_H=UnfortunatelyYes]) -AC_SUBST(NO_SYS_POLL_H) +GIT_CONF_SUBST([NO_SYS_POLL_H]) # # Define NO_INTTYPES_H if you don't have inttypes.h AC_CHECK_HEADER([inttypes.h], [NO_INTTYPES_H=], [NO_INTTYPES_H=UnfortunatelyYes]) -AC_SUBST(NO_INTTYPES_H) +GIT_CONF_SUBST([NO_INTTYPES_H]) # # Define OLD_ICONV if your library has an old iconv(), where the second # (input buffer pointer) parameter is declared with type (const char **). @@ -713,23 +726,24 @@ AC_COMPILE_IFELSE([OLDICONVTEST_SRC], GIT_UNSTASH_FLAGS($ICONVDIR) -AC_SUBST(OLD_ICONV) +GIT_CONF_SUBST([OLD_ICONV]) ## Checks for typedefs, structures, and compiler characteristics. AC_MSG_NOTICE([CHECKS for typedefs, structures, and compiler characteristics]) # TYPE_SOCKLEN_T case $ac_cv_type_socklen_t in - yes) ;; - *) AC_SUBST([SOCKLEN_T], [$git_cv_socklen_t_equiv]) ;; + yes) SOCKLEN_T='';; + *) SOCKLEN_T=$git_cv_socklen_t_equiv;; esac +GIT_CONF_SUBST([SOCKLEN_T]) # Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent. AC_CHECK_MEMBER(struct dirent.d_ino, [NO_D_INO_IN_DIRENT=], [NO_D_INO_IN_DIRENT=YesPlease], [#include <dirent.h>]) -AC_SUBST(NO_D_INO_IN_DIRENT) +GIT_CONF_SUBST([NO_D_INO_IN_DIRENT]) # # Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks # d_type in struct dirent (latest Cygwin -- will be fixed soonish). @@ -737,7 +751,7 @@ AC_CHECK_MEMBER(struct dirent.d_type, [NO_D_TYPE_IN_DIRENT=], [NO_D_TYPE_IN_DIRENT=YesPlease], [#include <dirent.h>]) -AC_SUBST(NO_D_TYPE_IN_DIRENT) +GIT_CONF_SUBST([NO_D_TYPE_IN_DIRENT]) # # Define NO_SOCKADDR_STORAGE if your platform does not have struct # sockaddr_storage. @@ -747,7 +761,7 @@ AC_CHECK_TYPE(struct sockaddr_storage, #include <sys/types.h> #include <sys/socket.h> ]) -AC_SUBST(NO_SOCKADDR_STORAGE) +GIT_CONF_SUBST([NO_SOCKADDR_STORAGE]) # # Define NO_IPV6 if you lack IPv6 support and getaddrinfo(). AC_CHECK_TYPE([struct addrinfo],[ @@ -759,7 +773,7 @@ AC_CHECK_TYPE([struct addrinfo],[ #include <sys/socket.h> #include <netdb.h> ]) -AC_SUBST(NO_IPV6) +GIT_CONF_SUBST([NO_IPV6]) # # Define NO_REGEX if you have no or inferior regex support in your C library. AC_CACHE_CHECK([whether the platform regex can handle null bytes], @@ -780,7 +794,7 @@ if test $ac_cv_c_excellent_regex = yes; then else NO_REGEX=YesPlease fi -AC_SUBST(NO_REGEX) +GIT_CONF_SUBST([NO_REGEX]) # # Define FREAD_READS_DIRECTORIES if your are on a system which succeeds # when attempting to read from an fopen'ed directory. @@ -800,7 +814,7 @@ if test $ac_cv_fread_reads_directories = yes; then else FREAD_READS_DIRECTORIES= fi -AC_SUBST(FREAD_READS_DIRECTORIES) +GIT_CONF_SUBST([FREAD_READS_DIRECTORIES]) # # Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf() # or vsnprintf() return -1 instead of number of characters which would @@ -834,7 +848,7 @@ if test $ac_cv_snprintf_returns_bogus = yes; then else SNPRINTF_RETURNS_BOGUS= fi -AC_SUBST(SNPRINTF_RETURNS_BOGUS) +GIT_CONF_SUBST([SNPRINTF_RETURNS_BOGUS]) ## Checks for library functions. @@ -845,47 +859,45 @@ AC_MSG_NOTICE([CHECKS for library functions]) AC_CHECK_HEADER([libgen.h], [NO_LIBGEN_H=], [NO_LIBGEN_H=YesPlease]) -AC_SUBST(NO_LIBGEN_H) +GIT_CONF_SUBST([NO_LIBGEN_H]) # # Define HAVE_PATHS_H if you have paths.h. AC_CHECK_HEADER([paths.h], [HAVE_PATHS_H=YesPlease], [HAVE_PATHS_H=]) -AC_SUBST(HAVE_PATHS_H) +GIT_CONF_SUBST([HAVE_PATHS_H]) # # Define HAVE_LIBCHARSET_H if have libcharset.h AC_CHECK_HEADER([libcharset.h], [HAVE_LIBCHARSET_H=YesPlease], [HAVE_LIBCHARSET_H=]) -AC_SUBST(HAVE_LIBCHARSET_H) +GIT_CONF_SUBST([HAVE_LIBCHARSET_H]) # Define CHARSET_LIB if libiconv does not export the locale_charset symbol # and libcharset does CHARSET_LIB= AC_CHECK_LIB([iconv], [locale_charset], [], [AC_CHECK_LIB([charset], [locale_charset], - [CHARSET_LIB=-lcharset]) - ] -) -AC_SUBST(CHARSET_LIB) + [CHARSET_LIB=-lcharset])]) +GIT_CONF_SUBST([CHARSET_LIB]) # # Define NO_STRCASESTR if you don't have strcasestr. GIT_CHECK_FUNC(strcasestr, [NO_STRCASESTR=], [NO_STRCASESTR=YesPlease]) -AC_SUBST(NO_STRCASESTR) +GIT_CONF_SUBST([NO_STRCASESTR]) # # Define NO_STRTOK_R if you don't have strtok_r GIT_CHECK_FUNC(strtok_r, [NO_STRTOK_R=], [NO_STRTOK_R=YesPlease]) -AC_SUBST(NO_STRTOK_R) +GIT_CONF_SUBST([NO_STRTOK_R]) # # Define NO_FNMATCH if you don't have fnmatch GIT_CHECK_FUNC(fnmatch, [NO_FNMATCH=], [NO_FNMATCH=YesPlease]) -AC_SUBST(NO_FNMATCH) +GIT_CONF_SUBST([NO_FNMATCH]) # # Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the # FNM_CASEFOLD GNU extension. @@ -907,19 +919,19 @@ if test $ac_cv_c_excellent_fnmatch = yes; then else NO_FNMATCH_CASEFOLD=YesPlease fi -AC_SUBST(NO_FNMATCH_CASEFOLD) +GIT_CONF_SUBST([NO_FNMATCH_CASEFOLD]) # # Define NO_MEMMEM if you don't have memmem. GIT_CHECK_FUNC(memmem, [NO_MEMMEM=], [NO_MEMMEM=YesPlease]) -AC_SUBST(NO_MEMMEM) +GIT_CONF_SUBST([NO_MEMMEM]) # # Define NO_STRLCPY if you don't have strlcpy. GIT_CHECK_FUNC(strlcpy, [NO_STRLCPY=], [NO_STRLCPY=YesPlease]) -AC_SUBST(NO_STRLCPY) +GIT_CONF_SUBST([NO_STRLCPY]) # # Define NO_UINTMAX_T if your platform does not have uintmax_t AC_CHECK_TYPE(uintmax_t, @@ -927,43 +939,43 @@ AC_CHECK_TYPE(uintmax_t, [NO_UINTMAX_T=YesPlease],[ #include <inttypes.h> ]) -AC_SUBST(NO_UINTMAX_T) +GIT_CONF_SUBST([NO_UINTMAX_T]) # # Define NO_STRTOUMAX if you don't have strtoumax in the C library. GIT_CHECK_FUNC(strtoumax, [NO_STRTOUMAX=], [NO_STRTOUMAX=YesPlease]) -AC_SUBST(NO_STRTOUMAX) +GIT_CONF_SUBST([NO_STRTOUMAX]) # # Define NO_SETENV if you don't have setenv in the C library. GIT_CHECK_FUNC(setenv, [NO_SETENV=], [NO_SETENV=YesPlease]) -AC_SUBST(NO_SETENV) +GIT_CONF_SUBST([NO_SETENV]) # # Define NO_UNSETENV if you don't have unsetenv in the C library. GIT_CHECK_FUNC(unsetenv, [NO_UNSETENV=], [NO_UNSETENV=YesPlease]) -AC_SUBST(NO_UNSETENV) +GIT_CONF_SUBST([NO_UNSETENV]) # # Define NO_MKDTEMP if you don't have mkdtemp in the C library. GIT_CHECK_FUNC(mkdtemp, [NO_MKDTEMP=], [NO_MKDTEMP=YesPlease]) -AC_SUBST(NO_MKDTEMP) +GIT_CONF_SUBST([NO_MKDTEMP]) # # Define NO_MKSTEMPS if you don't have mkstemps in the C library. GIT_CHECK_FUNC(mkstemps, [NO_MKSTEMPS=], [NO_MKSTEMPS=YesPlease]) -AC_SUBST(NO_MKSTEMPS) +GIT_CONF_SUBST([NO_MKSTEMPS]) # # Define NO_INITGROUPS if you don't have initgroups in the C library. GIT_CHECK_FUNC(initgroups, [NO_INITGROUPS=], [NO_INITGROUPS=YesPlease]) -AC_SUBST(NO_INITGROUPS) +GIT_CONF_SUBST([NO_INITGROUPS]) # # # Define NO_MMAP if you want to avoid mmap. @@ -1009,10 +1021,20 @@ if test -n "$USER_NOPTHREAD"; then # -D_REENTRANT' or some such. elif test -z "$PTHREAD_CFLAGS"; then threads_found=no - for opt in -mt -pthread -lpthread; do + # Attempt to compile and link some code using pthreads to determine + # required linker flags. The order is somewhat important here: We + # first try it without any extra flags, to catch systems where + # pthreads are part of the C library, then go on testing various other + # flags. We do so to avoid false positives. For example, on Mac OS X + # pthreads are part of the C library; moreover, the compiler allows us + # to add "-mt" to the CFLAGS (although it will do nothing except + # trigger a warning about an unused flag). Hence if we checked for + # "-mt" before "" we would end up picking it. But unfortunately this + # would then trigger compiler warnings on every single file we compile. + for opt in "" -mt -pthread -lpthread; do old_CFLAGS="$CFLAGS" CFLAGS="$opt $CFLAGS" - AC_MSG_CHECKING([Checking for POSIX Threads with '$opt']) + AC_MSG_CHECKING([for POSIX Threads with '$opt']) AC_LINK_IFELSE([PTHREADTEST_SRC], [AC_MSG_RESULT([yes]) NO_PTHREADS= @@ -1032,7 +1054,7 @@ elif test -z "$PTHREAD_CFLAGS"; then else old_CFLAGS="$CFLAGS" CFLAGS="$PTHREAD_CFLAGS $CFLAGS" - AC_MSG_CHECKING([Checking for POSIX Threads with '$PTHREAD_CFLAGS']) + AC_MSG_CHECKING([for POSIX Threads with '$PTHREAD_CFLAGS']) AC_LINK_IFELSE([PTHREADTEST_SRC], [AC_MSG_RESULT([yes]) NO_PTHREADS= @@ -1045,14 +1067,10 @@ fi CFLAGS="$old_CFLAGS" -AC_SUBST(PTHREAD_CFLAGS) -AC_SUBST(PTHREAD_LIBS) -AC_SUBST(NO_PTHREADS) +GIT_CONF_SUBST([PTHREAD_CFLAGS]) +GIT_CONF_SUBST([PTHREAD_LIBS]) +GIT_CONF_SUBST([NO_PTHREADS]) ## Output files -AC_CONFIG_FILES(["${config_file}":"${config_in}":"${config_append}"]) +AC_CONFIG_FILES(["${config_file}":"${config_in}"]) AC_OUTPUT - - -## Cleanup -rm -f "${config_append}" @@ -49,6 +49,16 @@ static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1 extra->nr++; } +static void die_initial_contact(int got_at_least_one_head) +{ + if (got_at_least_one_head) + die("The remote end hung up upon initial contact"); + else + die("Could not read from remote repository.\n\n" + "Please make sure you have the correct access rights\n" + "and the repository exists."); +} + /* * Read all the refs from the other end */ @@ -56,6 +66,8 @@ struct ref **get_remote_heads(int in, struct ref **list, unsigned int flags, struct extra_have_objects *extra_have) { + int got_at_least_one_head = 0; + *list = NULL; for (;;) { struct ref *ref; @@ -64,7 +76,10 @@ struct ref **get_remote_heads(int in, struct ref **list, char *name; int len, name_len; - len = packet_read_line(in, buffer, sizeof(buffer)); + len = packet_read(in, buffer, sizeof(buffer)); + if (len < 0) + die_initial_contact(got_at_least_one_head); + if (!len) break; if (buffer[len-1] == '\n') @@ -95,16 +110,12 @@ struct ref **get_remote_heads(int in, struct ref **list, hashcpy(ref->old_sha1, old_sha1); *list = ref; list = &ref->next; + got_at_least_one_head = 1; } return list; } -int server_supports(const char *feature) -{ - return !!parse_feature_request(server_capabilities, feature); -} - -const char *parse_feature_request(const char *feature_list, const char *feature) +const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp) { int len; @@ -116,14 +127,46 @@ const char *parse_feature_request(const char *feature_list, const char *feature) const char *found = strstr(feature_list, feature); if (!found) return NULL; - if ((feature_list == found || isspace(found[-1])) && - (!found[len] || isspace(found[len]) || found[len] == '=')) - return found; + if (feature_list == found || isspace(found[-1])) { + const char *value = found + len; + /* feature with no value (e.g., "thin-pack") */ + if (!*value || isspace(*value)) { + if (lenp) + *lenp = 0; + return value; + } + /* feature with a value (e.g., "agent=git/1.2.3") */ + else if (*value == '=') { + value++; + if (lenp) + *lenp = strcspn(value, " \t\n"); + return value; + } + /* + * otherwise we matched a substring of another feature; + * keep looking + */ + } feature_list = found + 1; } return NULL; } +int parse_feature_request(const char *feature_list, const char *feature) +{ + return !!parse_feature_value(feature_list, feature, NULL); +} + +const char *server_feature_value(const char *feature, int *len) +{ + return parse_feature_value(server_capabilities, feature, len); +} + +int server_supports(const char *feature) +{ + return !!server_feature_value(feature, NULL); +} + enum protocol { PROTO_LOCAL = 1, PROTO_SSH, diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 2e1b5e14b..0b77eb1fa 100755..100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -20,50 +20,8 @@ # 1) Copy this file to somewhere (e.g. ~/.git-completion.sh). # 2) Add the following line to your .bashrc/.zshrc: # source ~/.git-completion.sh -# -# 3) Consider changing your PS1 to also show the current branch: -# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ' -# ZSH: PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ ' -# -# The argument to __git_ps1 will be displayed only if you -# are currently in a git repository. The %s token will be -# the name of the current branch. -# -# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty -# value, unstaged (*) and staged (+) changes will be shown next -# to the branch name. You can configure this per-repository -# with the bash.showDirtyState variable, which defaults to true -# once GIT_PS1_SHOWDIRTYSTATE is enabled. -# -# You can also see if currently something is stashed, by setting -# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed, -# then a '$' will be shown next to the branch name. -# -# If you would like to see if there're untracked files, then you can -# set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're -# untracked files, then a '%' will be shown next to the branch name. -# -# If you would like to see the difference between HEAD and its -# upstream, set GIT_PS1_SHOWUPSTREAM="auto". A "<" indicates -# you are behind, ">" indicates you are ahead, and "<>" -# indicates you have diverged. You can further control -# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated -# list of values: -# verbose show number of commits ahead/behind (+/-) upstream -# legacy don't use the '--count' option available in recent -# versions of git-rev-list -# git always compare HEAD to @{upstream} -# svn always compare HEAD to your SVN upstream -# By default, __git_ps1 will compare HEAD to your SVN upstream -# if it can find one, or @{upstream} otherwise. Once you have -# set GIT_PS1_SHOWUPSTREAM, you can override it on a -# per-repository basis by setting the bash.showUpstream config -# variable. -# - -if [[ -n ${ZSH_VERSION-} ]]; then - autoload -U +X bashcompinit && bashcompinit -fi +# 3) Consider changing your PS1 to also show the current branch, +# see git-prompt.sh for details. case "$COMP_WORDBREAKS" in *:*) : great ;; @@ -74,9 +32,14 @@ esac # returns location of .git repo __gitdir () { + # Note: this function is duplicated in git-prompt.sh + # When updating it, make sure you update the other one to match. if [ -z "${1-}" ]; then if [ -n "${__git_dir-}" ]; then echo "$__git_dir" + elif [ -n "${GIT_DIR-}" ]; then + test -d "${GIT_DIR-}" || return 1 + echo "$GIT_DIR" elif [ -d .git ]; then echo .git else @@ -89,221 +52,6 @@ __gitdir () fi } -# stores the divergence from upstream in $p -# used by GIT_PS1_SHOWUPSTREAM -__git_ps1_show_upstream () -{ - local key value - local svn_remote svn_url_pattern count n - local upstream=git legacy="" verbose="" - - svn_remote=() - # get some config options from git-config - local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')" - while read -r key value; do - case "$key" in - bash.showupstream) - GIT_PS1_SHOWUPSTREAM="$value" - if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then - p="" - return - fi - ;; - svn-remote.*.url) - svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value" - svn_url_pattern+="\\|$value" - upstream=svn+git # default upstream is SVN if available, else git - ;; - esac - done <<< "$output" - - # parse configuration values - for option in ${GIT_PS1_SHOWUPSTREAM}; do - case "$option" in - git|svn) upstream="$option" ;; - verbose) verbose=1 ;; - legacy) legacy=1 ;; - esac - done - - # Find our upstream - case "$upstream" in - git) upstream="@{upstream}" ;; - svn*) - # get the upstream from the "git-svn-id: ..." in a commit message - # (git-svn uses essentially the same procedure internally) - local svn_upstream=($(git log --first-parent -1 \ - --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null)) - if [[ 0 -ne ${#svn_upstream[@]} ]]; then - svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]} - svn_upstream=${svn_upstream%@*} - local n_stop="${#svn_remote[@]}" - for ((n=1; n <= n_stop; n++)); do - svn_upstream=${svn_upstream#${svn_remote[$n]}} - done - - if [[ -z "$svn_upstream" ]]; then - # default branch name for checkouts with no layout: - upstream=${GIT_SVN_ID:-git-svn} - else - upstream=${svn_upstream#/} - fi - elif [[ "svn+git" = "$upstream" ]]; then - upstream="@{upstream}" - fi - ;; - esac - - # Find how many commits we are ahead/behind our upstream - if [[ -z "$legacy" ]]; then - count="$(git rev-list --count --left-right \ - "$upstream"...HEAD 2>/dev/null)" - else - # produce equivalent output to --count for older versions of git - local commits - if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)" - then - local commit behind=0 ahead=0 - for commit in $commits - do - case "$commit" in - "<"*) ((behind++)) ;; - *) ((ahead++)) ;; - esac - done - count="$behind $ahead" - else - count="" - fi - fi - - # calculate the result - if [[ -z "$verbose" ]]; then - case "$count" in - "") # no upstream - p="" ;; - "0 0") # equal to upstream - p="=" ;; - "0 "*) # ahead of upstream - p=">" ;; - *" 0") # behind upstream - p="<" ;; - *) # diverged from upstream - p="<>" ;; - esac - else - case "$count" in - "") # no upstream - p="" ;; - "0 0") # equal to upstream - p=" u=" ;; - "0 "*) # ahead of upstream - p=" u+${count#0 }" ;; - *" 0") # behind upstream - p=" u-${count% 0}" ;; - *) # diverged from upstream - p=" u+${count#* }-${count% *}" ;; - esac - fi - -} - - -# __git_ps1 accepts 0 or 1 arguments (i.e., format string) -# returns text to add to bash PS1 prompt (includes branch name) -__git_ps1 () -{ - local g="$(__gitdir)" - if [ -n "$g" ]; then - local r="" - local b="" - if [ -f "$g/rebase-merge/interactive" ]; then - r="|REBASE-i" - b="$(cat "$g/rebase-merge/head-name")" - elif [ -d "$g/rebase-merge" ]; then - r="|REBASE-m" - b="$(cat "$g/rebase-merge/head-name")" - else - if [ -d "$g/rebase-apply" ]; then - if [ -f "$g/rebase-apply/rebasing" ]; then - r="|REBASE" - elif [ -f "$g/rebase-apply/applying" ]; then - r="|AM" - else - r="|AM/REBASE" - fi - elif [ -f "$g/MERGE_HEAD" ]; then - r="|MERGING" - elif [ -f "$g/CHERRY_PICK_HEAD" ]; then - r="|CHERRY-PICKING" - elif [ -f "$g/BISECT_LOG" ]; then - r="|BISECTING" - fi - - b="$(git symbolic-ref HEAD 2>/dev/null)" || { - - b="$( - case "${GIT_PS1_DESCRIBE_STYLE-}" in - (contains) - git describe --contains HEAD ;; - (branch) - git describe --contains --all HEAD ;; - (describe) - git describe HEAD ;; - (* | default) - git describe --tags --exact-match HEAD ;; - esac 2>/dev/null)" || - - b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." || - b="unknown" - b="($b)" - } - fi - - local w="" - local i="" - local s="" - local u="" - local c="" - local p="" - - if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then - if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then - c="BARE:" - else - b="GIT_DIR!" - fi - elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then - if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then - if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then - git diff --no-ext-diff --quiet --exit-code || w="*" - if git rev-parse --quiet --verify HEAD >/dev/null; then - git diff-index --cached --quiet HEAD -- || i="+" - else - i="#" - fi - fi - fi - if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then - git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$" - fi - - if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then - if [ -n "$(git ls-files --others --exclude-standard)" ]; then - u="%" - fi - fi - - if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then - __git_ps1_show_upstream - fi - fi - - local f="$w$i$s$u" - printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p" - fi -} - __gitcomp_1 () { local c IFS=$' \t\n' @@ -417,7 +165,6 @@ __git_reassemble_comp_words_by_ref() } if ! type _get_comp_words_by_ref >/dev/null 2>&1; then -if [[ -z ${ZSH_VERSION:+set} ]]; then _get_comp_words_by_ref () { local exclude cur_ words_ cword_ @@ -445,32 +192,6 @@ _get_comp_words_by_ref () shift done } -else -_get_comp_words_by_ref () -{ - while [ $# -gt 0 ]; do - case "$1" in - cur) - cur=${COMP_WORDS[COMP_CWORD]} - ;; - prev) - prev=${COMP_WORDS[COMP_CWORD-1]} - ;; - words) - words=("${COMP_WORDS[@]}") - ;; - cword) - cword=$COMP_CWORD - ;; - -n) - # assume COMP_WORDBREAKS is already set sanely - shift - ;; - esac - shift - done -} -fi fi # Generates completion reply with compgen, appending a space to possible @@ -569,7 +290,7 @@ __git_refs () if [[ "$ref" == "$cur"* ]]; then echo "$ref" fi - done | uniq -u + done | sort | uniq -u fi return fi @@ -833,7 +554,7 @@ __git_list_porcelain_commands () { local i IFS=" "$'\n' __git_compute_all_commands - for i in "help" $__git_all_commands + for i in $__git_all_commands do case $i in *--*) : helper pattern;; @@ -1123,11 +844,15 @@ _git_branch () done case "$cur" in + --set-upstream-to=*) + __gitcomp "$(__git_refs)" "" "${cur##--set-upstream-to=}" + ;; --*) __gitcomp " --color --no-color --verbose --abbrev= --no-abbrev --track --no-track --contains --merged --no-merged - --set-upstream --edit-description --list + --set-upstream-to= --edit-description --list + --unset-upstream " ;; *) @@ -1233,6 +958,8 @@ _git_clone () --upload-pack --template= --depth + --single-branch + --branch " return ;; @@ -1262,7 +989,8 @@ _git_commit () --*) __gitcomp " --all --author= --signoff --verify --no-verify - --edit --amend --include --only --interactive + --edit --no-edit + --amend --include --only --interactive --dry-run --reuse-message= --reedit-message= --reset-author --file= --message= --template= --cleanup= --untracked-files --untracked-files= @@ -1319,7 +1047,7 @@ _git_diff () } __git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff - tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 + tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 codecompare " _git_difftool () @@ -1359,6 +1087,14 @@ _git_fetch () __git_complete_remote_or_refspec } +__git_format_patch_options=" + --stdout --attach --no-attach --thread --thread= --output-directory + --numbered --start-number --numbered-files --keep-subject --signoff + --signature --no-signature --in-reply-to= --cc= --full-index --binary + --not --all --cover-letter --no-prefix --src-prefix= --dst-prefix= + --inline --suffix= --ignore-if-in-upstream --subject-prefix= +" + _git_format_patch () { case "$cur" in @@ -1369,21 +1105,7 @@ _git_format_patch () return ;; --*) - __gitcomp " - --stdout --attach --no-attach --thread --thread= - --output-directory - --numbered --start-number - --numbered-files - --keep-subject - --signoff --signature --no-signature - --in-reply-to= --cc= - --full-index --binary - --not --all - --cover-letter - --no-prefix --src-prefix= --dst-prefix= - --inline --suffix= --ignore-if-in-upstream - --subject-prefix= - " + __gitcomp "$__git_format_patch_options" return ;; esac @@ -1797,6 +1519,12 @@ _git_send_email () __gitcomp "ssl tls" "" "${cur##--smtp-encryption=}" return ;; + --thread=*) + __gitcomp " + deep shallow + " "" "${cur##--thread=}" + return + ;; --*) __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to --compose --confirm= --dry-run --envelope-sender @@ -1806,11 +1534,12 @@ _git_send_email () --signed-off-by-cc --smtp-pass --smtp-server --smtp-server-port --smtp-encryption= --smtp-user --subject --suppress-cc= --suppress-from --thread --to - --validate --no-validate" + --validate --no-validate + $__git_format_patch_options" return ;; esac - COMPREPLY=() + __git_complete_revlist } _git_stage () @@ -2280,7 +2009,7 @@ _git_config () _git_remote () { - local subcommands="add rename rm set-head set-branches set-url show prune update" + local subcommands="add rename remove set-head set-branches set-url show prune update" local subcommand="$(__git_find_on_cmdline "$subcommands")" if [ -z "$subcommand" ]; then __gitcomp "$subcommands" @@ -2288,7 +2017,7 @@ _git_remote () fi case "$subcommand" in - rename|rm|set-url|show|prune) + rename|remove|set-url|show|prune) __gitcomp_nl "$(__git_remotes)" ;; set-head|set-branches) @@ -2672,20 +2401,71 @@ __gitk_main () __git_complete_revlist } -__git_func_wrap () -{ - if [[ -n ${ZSH_VERSION-} ]]; then - emulate -L bash - setopt KSH_TYPESET +if [[ -n ${ZSH_VERSION-} ]]; then + echo "WARNING: this script is deprecated, please see git-completion.zsh" 1>&2 - # workaround zsh's bug that leaves 'words' as a special - # variable in versions < 4.3.12 - typeset -h words + autoload -U +X compinit && compinit - # workaround zsh's bug that quotes spaces in the COMPREPLY - # array if IFS doesn't contain spaces. - typeset -h IFS - fi + __gitcomp () + { + emulate -L zsh + + local cur_="${3-$cur}" + + case "$cur_" in + --*=) + ;; + *) + local c IFS=$' \t\n' + local -a array + for c in ${=1}; do + c="$c${4-}" + case $c in + --*=*|*.) ;; + *) c="$c " ;; + esac + array+=("$c") + done + compset -P '*[=:]' + compadd -Q -S '' -p "${2-}" -a -- array && _ret=0 + ;; + esac + } + + __gitcomp_nl () + { + emulate -L zsh + + local IFS=$'\n' + compset -P '*[=:]' + compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0 + } + + __git_zsh_helper () + { + emulate -L ksh + local cur cword prev + cur=${words[CURRENT-1]} + prev=${words[CURRENT-2]} + let cword=CURRENT-1 + __${service}_main + } + + _git () + { + emulate -L zsh + local _ret=1 + __git_zsh_helper + let _ret && _default -S '' && _ret=0 + return _ret + } + + compdef _git git gitk + return +fi + +__git_func_wrap () +{ local cur words cword prev _get_comp_words_by_ref -n =: cur words cword prev $1 diff --git a/contrib/completion/git-completion.tcsh b/contrib/completion/git-completion.tcsh new file mode 100644 index 000000000..8aafb6331 --- /dev/null +++ b/contrib/completion/git-completion.tcsh @@ -0,0 +1,107 @@ +#!tcsh +# +# tcsh completion support for core Git. +# +# Copyright (C) 2012 Marc Khouzam <marc.khouzam@gmail.com> +# Distributed under the GNU General Public License, version 2.0. +# +# When sourced, this script will generate a new script that uses +# the git-completion.bash script provided by core Git. This new +# script can be used by tcsh to perform git completion. +# The current script also issues the necessary tcsh 'complete' +# commands. +# +# To use this completion script: +# +# 1) Copy both this file and the bash completion script to ${HOME}. +# You _must_ use the name ${HOME}/.git-completion.bash for the +# bash script. +# (e.g. ~/.git-completion.tcsh and ~/.git-completion.bash). +# 2) Add the following line to your .tcshrc/.cshrc: +# source ~/.git-completion.tcsh +# 3) For completion similar to bash, it is recommended to also +# add the following line to your .tcshrc/.cshrc: +# set autolist=ambiguous +# It will tell tcsh to list the possible completion choices. + +set __git_tcsh_completion_original_script = ${HOME}/.git-completion.bash +set __git_tcsh_completion_script = ${HOME}/.git-completion.tcsh.bash + +# Check that the user put the script in the right place +if ( ! -e ${__git_tcsh_completion_original_script} ) then + echo "git-completion.tcsh: Cannot find: ${__git_tcsh_completion_original_script}. Git completion will not work." + exit +endif + +cat << EOF > ${__git_tcsh_completion_script} +#!bash +# +# This script is GENERATED and will be overwritten automatically. +# Do not modify it directly. Instead, modify git-completion.tcsh +# and source it again. + +source ${__git_tcsh_completion_original_script} + +# Set COMP_WORDS in a way that can be handled by the bash script. +COMP_WORDS=(\$2) + +# The cursor is at the end of parameter #1. +# We must check for a space as the last character which will +# tell us that the previous word is complete and the cursor +# is on the next word. +if [ "\${2: -1}" == " " ]; then + # The last character is a space, so our location is at the end + # of the command-line array + COMP_CWORD=\${#COMP_WORDS[@]} +else + # The last character is not a space, so our location is on the + # last word of the command-line array, so we must decrement the + # count by 1 + COMP_CWORD=\$((\${#COMP_WORDS[@]}-1)) +fi + +# Call _git() or _gitk() of the bash script, based on the first argument +_\${1} + +IFS=\$'\n' +if [ \${#COMPREPLY[*]} -gt 0 ]; then + echo "\${COMPREPLY[*]}" | sort | uniq +else + # No completions suggested. In this case, we want tcsh to perform + # standard file completion. However, there does not seem to be way + # to tell tcsh to do that. To help the user, we try to simulate + # file completion directly in this script. + # + # Known issues: + # - Possible completions are shown with their directory prefix. + # - Completions containing shell variables are not handled. + # - Completions with ~ as the first character are not handled. + + # No file completion should be done unless we are completing beyond + # the git sub-command. An improvement on the bash completion :) + if [ \${COMP_CWORD} -gt 1 ]; then + TO_COMPLETE="\${COMP_WORDS[\${COMP_CWORD}]}" + + # We don't support ~ expansion: too tricky. + if [ "\${TO_COMPLETE:0:1}" != "~" ]; then + # Use ls so as to add the '/' at the end of directories. + RESULT=(\`ls -dp \${TO_COMPLETE}* 2> /dev/null\`) + echo \${RESULT[*]} + + # If there is a single completion and it is a directory, + # we output it a second time to trick tcsh into not adding a space + # after it. + if [ \${#RESULT[*]} -eq 1 ] && [ "\${RESULT[0]: -1}" == "/" ]; then + echo \${RESULT[*]} + fi + fi + fi +fi + +EOF + +# Don't need this variable anymore, so don't pollute the users environment +unset __git_tcsh_completion_original_script + +complete git 'p,*,`bash ${__git_tcsh_completion_script} git "${COMMAND_LINE}"`,' +complete gitk 'p,*,`bash ${__git_tcsh_completion_script} gitk "${COMMAND_LINE}"`,' diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh new file mode 100644 index 000000000..45775021f --- /dev/null +++ b/contrib/completion/git-completion.zsh @@ -0,0 +1,78 @@ +#compdef git gitk + +# zsh completion wrapper for git +# +# You need git's bash completion script installed somewhere, by default on the +# same directory as this script. +# +# If your script is on ~/.git-completion.sh instead, you can configure it on +# your ~/.zshrc: +# +# zstyle ':completion:*:*:git:*' script ~/.git-completion.sh +# +# The recommended way to install this script is to copy to +# '~/.zsh/completion/_git', and then add the following to your ~/.zshrc file: +# +# fpath=(~/.zsh/completion $fpath) + +complete () +{ + # do nothing + return 0 +} + +zstyle -s ":completion:*:*:git:*" script script +test -z "$script" && script="$(dirname ${funcsourcetrace[1]%:*})"/git-completion.bash +ZSH_VERSION='' . "$script" + +__gitcomp () +{ + emulate -L zsh + + local cur_="${3-$cur}" + + case "$cur_" in + --*=) + ;; + *) + local c IFS=$' \t\n' + local -a array + for c in ${=1}; do + c="$c${4-}" + case $c in + --*=*|*.) ;; + *) c="$c " ;; + esac + array+=("$c") + done + compset -P '*[=:]' + compadd -Q -S '' -p "${2-}" -a -- array && _ret=0 + ;; + esac +} + +__gitcomp_nl () +{ + emulate -L zsh + + local IFS=$'\n' + compset -P '*[=:]' + compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0 +} + +_git () +{ + local _ret=1 + () { + emulate -L ksh + local cur cword prev + cur=${words[CURRENT-1]} + prev=${words[CURRENT-2]} + let cword=CURRENT-1 + __${service}_main + } + let _ret && _default -S '' && _ret=0 + return _ret +} + +_git diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh new file mode 100644 index 000000000..9bef0531c --- /dev/null +++ b/contrib/completion/git-prompt.sh @@ -0,0 +1,395 @@ +# bash/zsh git prompt support +# +# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org> +# Distributed under the GNU General Public License, version 2.0. +# +# This script allows you to see the current branch in your prompt. +# +# To enable: +# +# 1) Copy this file to somewhere (e.g. ~/.git-prompt.sh). +# 2) Add the following line to your .bashrc/.zshrc: +# source ~/.git-prompt.sh +# 3a) Change your PS1 to call __git_ps1 as +# command-substitution: +# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ' +# ZSH: PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ ' +# the optional argument will be used as format string. +# 3b) Alternatively, if you are using bash, __git_ps1 can be +# used for PROMPT_COMMAND with two parameters, <pre> and +# <post>, which are strings you would put in $PS1 before +# and after the status string generated by the git-prompt +# machinery. e.g. +# PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "' +# will show username, at-sign, host, colon, cwd, then +# various status string, followed by dollar and SP, as +# your prompt. +# Optionally, you can supply a third argument with a printf +# format string to finetune the output of the branch status +# +# The argument to __git_ps1 will be displayed only if you are currently +# in a git repository. The %s token will be the name of the current +# branch. +# +# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty value, +# unstaged (*) and staged (+) changes will be shown next to the branch +# name. You can configure this per-repository with the +# bash.showDirtyState variable, which defaults to true once +# GIT_PS1_SHOWDIRTYSTATE is enabled. +# +# You can also see if currently something is stashed, by setting +# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed, +# then a '$' will be shown next to the branch name. +# +# If you would like to see if there're untracked files, then you can set +# GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're untracked +# files, then a '%' will be shown next to the branch name. +# +# If you would like to see the difference between HEAD and its upstream, +# set GIT_PS1_SHOWUPSTREAM="auto". A "<" indicates you are behind, ">" +# indicates you are ahead, "<>" indicates you have diverged and "=" +# indicates that there is no difference. You can further control +# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated list +# of values: +# +# verbose show number of commits ahead/behind (+/-) upstream +# legacy don't use the '--count' option available in recent +# versions of git-rev-list +# git always compare HEAD to @{upstream} +# svn always compare HEAD to your SVN upstream +# +# By default, __git_ps1 will compare HEAD to your SVN upstream if it can +# find one, or @{upstream} otherwise. Once you have set +# GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by +# setting the bash.showUpstream config variable. +# +# If you would like to see more information about the identity of +# commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE +# to one of these values: +# +# contains relative to newer annotated tag (v1.6.3.2~35) +# branch relative to newer tag or branch (master~4) +# describe relative to older annotated tag (v1.6.3.1-13-gdd42c2f) +# default exactly matching tag +# +# If you would like a colored hint about the current dirty state, set +# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on +# the colored output of "git status -sb". + +# __gitdir accepts 0 or 1 arguments (i.e., location) +# returns location of .git repo +__gitdir () +{ + # Note: this function is duplicated in git-completion.bash + # When updating it, make sure you update the other one to match. + if [ -z "${1-}" ]; then + if [ -n "${__git_dir-}" ]; then + echo "$__git_dir" + elif [ -n "${GIT_DIR-}" ]; then + test -d "${GIT_DIR-}" || return 1 + echo "$GIT_DIR" + elif [ -d .git ]; then + echo .git + else + git rev-parse --git-dir 2>/dev/null + fi + elif [ -d "$1/.git" ]; then + echo "$1/.git" + else + echo "$1" + fi +} + +# stores the divergence from upstream in $p +# used by GIT_PS1_SHOWUPSTREAM +__git_ps1_show_upstream () +{ + local key value + local svn_remote svn_url_pattern count n + local upstream=git legacy="" verbose="" + + svn_remote=() + # get some config options from git-config + local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')" + while read -r key value; do + case "$key" in + bash.showupstream) + GIT_PS1_SHOWUPSTREAM="$value" + if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then + p="" + return + fi + ;; + svn-remote.*.url) + svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value" + svn_url_pattern+="\\|$value" + upstream=svn+git # default upstream is SVN if available, else git + ;; + esac + done <<< "$output" + + # parse configuration values + for option in ${GIT_PS1_SHOWUPSTREAM}; do + case "$option" in + git|svn) upstream="$option" ;; + verbose) verbose=1 ;; + legacy) legacy=1 ;; + esac + done + + # Find our upstream + case "$upstream" in + git) upstream="@{upstream}" ;; + svn*) + # get the upstream from the "git-svn-id: ..." in a commit message + # (git-svn uses essentially the same procedure internally) + local svn_upstream=($(git log --first-parent -1 \ + --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null)) + if [[ 0 -ne ${#svn_upstream[@]} ]]; then + svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]} + svn_upstream=${svn_upstream%@*} + local n_stop="${#svn_remote[@]}" + for ((n=1; n <= n_stop; n++)); do + svn_upstream=${svn_upstream#${svn_remote[$n]}} + done + + if [[ -z "$svn_upstream" ]]; then + # default branch name for checkouts with no layout: + upstream=${GIT_SVN_ID:-git-svn} + else + upstream=${svn_upstream#/} + fi + elif [[ "svn+git" = "$upstream" ]]; then + upstream="@{upstream}" + fi + ;; + esac + + # Find how many commits we are ahead/behind our upstream + if [[ -z "$legacy" ]]; then + count="$(git rev-list --count --left-right \ + "$upstream"...HEAD 2>/dev/null)" + else + # produce equivalent output to --count for older versions of git + local commits + if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)" + then + local commit behind=0 ahead=0 + for commit in $commits + do + case "$commit" in + "<"*) ((behind++)) ;; + *) ((ahead++)) ;; + esac + done + count="$behind $ahead" + else + count="" + fi + fi + + # calculate the result + if [[ -z "$verbose" ]]; then + case "$count" in + "") # no upstream + p="" ;; + "0 0") # equal to upstream + p="=" ;; + "0 "*) # ahead of upstream + p=">" ;; + *" 0") # behind upstream + p="<" ;; + *) # diverged from upstream + p="<>" ;; + esac + else + case "$count" in + "") # no upstream + p="" ;; + "0 0") # equal to upstream + p=" u=" ;; + "0 "*) # ahead of upstream + p=" u+${count#0 }" ;; + *" 0") # behind upstream + p=" u-${count% 0}" ;; + *) # diverged from upstream + p=" u+${count#* }-${count% *}" ;; + esac + fi + +} + + +# __git_ps1 accepts 0 or 1 arguments (i.e., format string) +# when called from PS1 using command substitution +# in this mode it prints text to add to bash PS1 prompt (includes branch name) +# +# __git_ps1 requires 2 or 3 arguments when called from PROMPT_COMMAND (pc) +# in that case it _sets_ PS1. The arguments are parts of a PS1 string. +# when two arguments are given, the first is prepended and the second appended +# to the state string when assigned to PS1. +# The optional third parameter will be used as printf format string to further +# customize the output of the git-status string. +# In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true +__git_ps1 () +{ + local pcmode=no + local detached=no + local ps1pc_start='\u@\h:\w ' + local ps1pc_end='\$ ' + local printf_format=' (%s)' + + case "$#" in + 2|3) pcmode=yes + ps1pc_start="$1" + ps1pc_end="$2" + printf_format="${3:-$printf_format}" + ;; + 0|1) printf_format="${1:-$printf_format}" + ;; + *) return + ;; + esac + + local g="$(__gitdir)" + if [ -z "$g" ]; then + if [ $pcmode = yes ]; then + #In PC mode PS1 always needs to be set + PS1="$ps1pc_start$ps1pc_end" + fi + else + local r="" + local b="" + if [ -f "$g/rebase-merge/interactive" ]; then + r="|REBASE-i" + b="$(cat "$g/rebase-merge/head-name")" + elif [ -d "$g/rebase-merge" ]; then + r="|REBASE-m" + b="$(cat "$g/rebase-merge/head-name")" + else + if [ -d "$g/rebase-apply" ]; then + if [ -f "$g/rebase-apply/rebasing" ]; then + r="|REBASE" + elif [ -f "$g/rebase-apply/applying" ]; then + r="|AM" + else + r="|AM/REBASE" + fi + elif [ -f "$g/MERGE_HEAD" ]; then + r="|MERGING" + elif [ -f "$g/CHERRY_PICK_HEAD" ]; then + r="|CHERRY-PICKING" + elif [ -f "$g/BISECT_LOG" ]; then + r="|BISECTING" + fi + + b="$(git symbolic-ref HEAD 2>/dev/null)" || { + detached=yes + b="$( + case "${GIT_PS1_DESCRIBE_STYLE-}" in + (contains) + git describe --contains HEAD ;; + (branch) + git describe --contains --all HEAD ;; + (describe) + git describe HEAD ;; + (* | default) + git describe --tags --exact-match HEAD ;; + esac 2>/dev/null)" || + + b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." || + b="unknown" + b="($b)" + } + fi + + local w="" + local i="" + local s="" + local u="" + local c="" + local p="" + + if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then + if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then + c="BARE:" + else + b="GIT_DIR!" + fi + elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then + if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then + if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then + git diff --no-ext-diff --quiet --exit-code || w="*" + if git rev-parse --quiet --verify HEAD >/dev/null; then + git diff-index --cached --quiet HEAD -- || i="+" + else + i="#" + fi + fi + fi + if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then + git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$" + fi + + if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then + if [ -n "$(git ls-files --others --exclude-standard)" ]; then + u="%" + fi + fi + + if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then + __git_ps1_show_upstream + fi + fi + + local f="$w$i$s$u" + if [ $pcmode = yes ]; then + local gitstring= + if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then + local c_red='\e[31m' + local c_green='\e[32m' + local c_lblue='\e[1;34m' + local c_clear='\e[0m' + local bad_color=$c_red + local ok_color=$c_green + local branch_color="$c_clear" + local flags_color="$c_lblue" + local branchstring="$c${b##refs/heads/}" + + if [ $detached = no ]; then + branch_color="$ok_color" + else + branch_color="$bad_color" + fi + + # Setting gitstring directly with \[ and \] around colors + # is necessary to prevent wrapping issues! + gitstring="\[$branch_color\]$branchstring\[$c_clear\]" + + if [ -n "$w$i$s$u$r$p" ]; then + gitstring="$gitstring " + fi + if [ "$w" = "*" ]; then + gitstring="$gitstring\[$bad_color\]$w" + fi + if [ -n "$i" ]; then + gitstring="$gitstring\[$ok_color\]$i" + fi + if [ -n "$s" ]; then + gitstring="$gitstring\[$flags_color\]$s" + fi + if [ -n "$u" ]; then + gitstring="$gitstring\[$bad_color\]$u" + fi + gitstring="$gitstring\[$c_clear\]$r$p" + else + gitstring="$c${b##refs/heads/}${f:+ $f}$r$p" + fi + gitstring=$(printf -- "$printf_format" "$gitstring") + PS1="$ps1pc_start$gitstring$ps1pc_end" + else + # NO color option unless in PROMPT_COMMAND mode + printf -- "$printf_format" "$c${b##refs/heads/}${f:+ $f}$r$p" + fi + fi +} diff --git a/contrib/credential/gnome-keyring/.gitignore b/contrib/credential/gnome-keyring/.gitignore new file mode 100644 index 000000000..88d8fcdbc --- /dev/null +++ b/contrib/credential/gnome-keyring/.gitignore @@ -0,0 +1 @@ +git-credential-gnome-keyring diff --git a/contrib/credential/gnome-keyring/Makefile b/contrib/credential/gnome-keyring/Makefile new file mode 100644 index 000000000..e6561d8db --- /dev/null +++ b/contrib/credential/gnome-keyring/Makefile @@ -0,0 +1,24 @@ +MAIN:=git-credential-gnome-keyring +all:: $(MAIN) + +CC = gcc +RM = rm -f +CFLAGS = -g -O2 -Wall + +-include ../../../config.mak.autogen +-include ../../../config.mak + +INCS:=$(shell pkg-config --cflags gnome-keyring-1) +LIBS:=$(shell pkg-config --libs gnome-keyring-1) + +SRCS:=$(MAIN).c +OBJS:=$(SRCS:.c=.o) + +%.o: %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(INCS) -o $@ -c $< + +$(MAIN): $(OBJS) + $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) + +clean: + @$(RM) $(MAIN) $(OBJS) diff --git a/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c b/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c new file mode 100644 index 000000000..41f61c5db --- /dev/null +++ b/contrib/credential/gnome-keyring/git-credential-gnome-keyring.c @@ -0,0 +1,445 @@ +/* + * Copyright (C) 2011 John Szakmeister <john@szakmeister.net> + * 2012 Philipp A. Hartmann <pah@qo.cx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Credits: + * - GNOME Keyring API handling originally written by John Szakmeister + * - ported to credential helper API by Philipp A. Hartmann + */ + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <errno.h> +#include <gnome-keyring.h> + +/* + * This credential struct and API is simplified from git's credential.{h,c} + */ +struct credential +{ + char *protocol; + char *host; + unsigned short port; + char *path; + char *username; + char *password; +}; + +#define CREDENTIAL_INIT \ + { NULL,NULL,0,NULL,NULL,NULL } + +void credential_init(struct credential *c); +void credential_clear(struct credential *c); +int credential_read(struct credential *c); +void credential_write(const struct credential *c); + +typedef int (*credential_op_cb)(struct credential*); + +struct credential_operation +{ + char *name; + credential_op_cb op; +}; + +#define CREDENTIAL_OP_END \ + { NULL,NULL } + +/* + * Table with operation callbacks is defined in concrete + * credential helper implementation and contains entries + * like { "get", function_to_get_credential } terminated + * by CREDENTIAL_OP_END. + */ +struct credential_operation const credential_helper_ops[]; + +/* ---------------- common helper functions ----------------- */ + +static inline void free_password(char *password) +{ + char *c = password; + if (!password) + return; + + while (*c) *c++ = '\0'; + free(password); +} + +static inline void warning(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "warning: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n" ); + va_end(ap); +} + +static inline void error(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n" ); + va_end(ap); +} + +static inline void die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap,fmt); + error(fmt, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +static inline void die_errno(int err) +{ + error("%s", strerror(err)); + exit(EXIT_FAILURE); +} + +static inline char *xstrdup(const char *str) +{ + char *ret = strdup(str); + if (!ret) + die_errno(errno); + + return ret; +} + +/* ----------------- GNOME Keyring functions ----------------- */ + +/* create a special keyring option string, if path is given */ +static char* keyring_object(struct credential *c) +{ + char* object = NULL; + + if (!c->path) + return object; + + object = (char*) malloc(strlen(c->host)+strlen(c->path)+8); + if(!object) + die_errno(errno); + + if(c->port) + sprintf(object,"%s:%hd/%s",c->host,c->port,c->path); + else + sprintf(object,"%s/%s",c->host,c->path); + + return object; +} + +int keyring_get(struct credential *c) +{ + char* object = NULL; + GList *entries; + GnomeKeyringNetworkPasswordData *password_data; + GnomeKeyringResult result; + + if (!c->protocol || !(c->host || c->path)) + return EXIT_FAILURE; + + object = keyring_object(c); + + result = gnome_keyring_find_network_password_sync( + c->username, + NULL /* domain */, + c->host, + object, + c->protocol, + NULL /* authtype */, + c->port, + &entries); + + free(object); + + if (result == GNOME_KEYRING_RESULT_NO_MATCH) + return EXIT_SUCCESS; + + if (result == GNOME_KEYRING_RESULT_CANCELLED) + return EXIT_SUCCESS; + + if (result != GNOME_KEYRING_RESULT_OK) { + error("%s",gnome_keyring_result_to_message(result)); + return EXIT_FAILURE; + } + + /* pick the first one from the list */ + password_data = (GnomeKeyringNetworkPasswordData *) entries->data; + + free_password(c->password); + c->password = xstrdup(password_data->password); + + if (!c->username) + c->username = xstrdup(password_data->user); + + gnome_keyring_network_password_list_free(entries); + + return EXIT_SUCCESS; +} + + +int keyring_store(struct credential *c) +{ + guint32 item_id; + char *object = NULL; + + /* + * Sanity check that what we are storing is actually sensible. + * In particular, we can't make a URL without a protocol field. + * Without either a host or pathname (depending on the scheme), + * we have no primary key. And without a username and password, + * we are not actually storing a credential. + */ + if (!c->protocol || !(c->host || c->path) || + !c->username || !c->password) + return EXIT_FAILURE; + + object = keyring_object(c); + + gnome_keyring_set_network_password_sync( + GNOME_KEYRING_DEFAULT, + c->username, + NULL /* domain */, + c->host, + object, + c->protocol, + NULL /* authtype */, + c->port, + c->password, + &item_id); + + free(object); + return EXIT_SUCCESS; +} + +int keyring_erase(struct credential *c) +{ + char *object = NULL; + GList *entries; + GnomeKeyringNetworkPasswordData *password_data; + GnomeKeyringResult result; + + /* + * Sanity check that we actually have something to match + * against. The input we get is a restrictive pattern, + * so technically a blank credential means "erase everything". + * But it is too easy to accidentally send this, since it is equivalent + * to empty input. So explicitly disallow it, and require that the + * pattern have some actual content to match. + */ + if (!c->protocol && !c->host && !c->path && !c->username) + return EXIT_FAILURE; + + object = keyring_object(c); + + result = gnome_keyring_find_network_password_sync( + c->username, + NULL /* domain */, + c->host, + object, + c->protocol, + NULL /* authtype */, + c->port, + &entries); + + free(object); + + if (result == GNOME_KEYRING_RESULT_NO_MATCH) + return EXIT_SUCCESS; + + if (result == GNOME_KEYRING_RESULT_CANCELLED) + return EXIT_SUCCESS; + + if (result != GNOME_KEYRING_RESULT_OK) + { + error("%s",gnome_keyring_result_to_message(result)); + return EXIT_FAILURE; + } + + /* pick the first one from the list (delete all matches?) */ + password_data = (GnomeKeyringNetworkPasswordData *) entries->data; + + result = gnome_keyring_item_delete_sync( + password_data->keyring, password_data->item_id); + + gnome_keyring_network_password_list_free(entries); + + if (result != GNOME_KEYRING_RESULT_OK) + { + error("%s",gnome_keyring_result_to_message(result)); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +/* + * Table with helper operation callbacks, used by generic + * credential helper main function. + */ +struct credential_operation const credential_helper_ops[] = +{ + { "get", keyring_get }, + { "store", keyring_store }, + { "erase", keyring_erase }, + CREDENTIAL_OP_END +}; + +/* ------------------ credential functions ------------------ */ + +void credential_init(struct credential *c) +{ + memset(c, 0, sizeof(*c)); +} + +void credential_clear(struct credential *c) +{ + free(c->protocol); + free(c->host); + free(c->path); + free(c->username); + free_password(c->password); + + credential_init(c); +} + +int credential_read(struct credential *c) +{ + char buf[1024]; + ssize_t line_len = 0; + char *key = buf; + char *value; + + while (fgets(buf, sizeof(buf), stdin)) + { + line_len = strlen(buf); + + if(buf[line_len-1]=='\n') + buf[--line_len]='\0'; + + if(!line_len) + break; + + value = strchr(buf,'='); + if(!value) { + warning("invalid credential line: %s", key); + return -1; + } + *value++ = '\0'; + + if (!strcmp(key, "protocol")) { + free(c->protocol); + c->protocol = xstrdup(value); + } else if (!strcmp(key, "host")) { + free(c->host); + c->host = xstrdup(value); + value = strrchr(c->host,':'); + if (value) { + *value++ = '\0'; + c->port = atoi(value); + } + } else if (!strcmp(key, "path")) { + free(c->path); + c->path = xstrdup(value); + } else if (!strcmp(key, "username")) { + free(c->username); + c->username = xstrdup(value); + } else if (!strcmp(key, "password")) { + free_password(c->password); + c->password = xstrdup(value); + while (*value) *value++ = '\0'; + } + /* + * Ignore other lines; we don't know what they mean, but + * this future-proofs us when later versions of git do + * learn new lines, and the helpers are updated to match. + */ + } + return 0; +} + +void credential_write_item(FILE *fp, const char *key, const char *value) +{ + if (!value) + return; + fprintf(fp, "%s=%s\n", key, value); +} + +void credential_write(const struct credential *c) +{ + /* only write username/password, if set */ + credential_write_item(stdout, "username", c->username); + credential_write_item(stdout, "password", c->password); +} + +static void usage(const char *name) +{ + struct credential_operation const *try_op = credential_helper_ops; + const char *basename = strrchr(name,'/'); + + basename = (basename) ? basename + 1 : name; + fprintf(stderr, "Usage: %s <", basename); + while(try_op->name) { + fprintf(stderr,"%s",(try_op++)->name); + if(try_op->name) + fprintf(stderr,"%s","|"); + } + fprintf(stderr,"%s",">\n"); +} + +int main(int argc, char *argv[]) +{ + int ret = EXIT_SUCCESS; + + struct credential_operation const *try_op = credential_helper_ops; + struct credential cred = CREDENTIAL_INIT; + + if (!argv[1]) { + usage(argv[0]); + goto out; + } + + /* lookup operation callback */ + while(try_op->name && strcmp(argv[1], try_op->name)) + try_op++; + + /* unsupported operation given -- ignore silently */ + if(!try_op->name || !try_op->op) + goto out; + + ret = credential_read(&cred); + if(ret) + goto out; + + /* perform credential operation */ + ret = (*try_op->op)(&cred); + + credential_write(&cred); + +out: + credential_clear(&cred); + return ret; +} diff --git a/contrib/credential/wincred/Makefile b/contrib/credential/wincred/Makefile new file mode 100644 index 000000000..bad45ca47 --- /dev/null +++ b/contrib/credential/wincred/Makefile @@ -0,0 +1,14 @@ +all: git-credential-wincred.exe + +CC = gcc +RM = rm -f +CFLAGS = -O2 -Wall + +-include ../../../config.mak.autogen +-include ../../../config.mak + +git-credential-wincred.exe : git-credential-wincred.c + $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +clean: + $(RM) git-credential-wincred.exe diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c new file mode 100644 index 000000000..cbaec5f24 --- /dev/null +++ b/contrib/credential/wincred/git-credential-wincred.c @@ -0,0 +1,357 @@ +/* + * A git credential helper that interface with Windows' Credential Manager + * + */ +#include <windows.h> +#include <stdio.h> +#include <io.h> +#include <fcntl.h> + +/* common helpers */ + +static void die(const char *err, ...) +{ + char msg[4096]; + va_list params; + va_start(params, err); + vsnprintf(msg, sizeof(msg), err, params); + fprintf(stderr, "%s\n", msg); + va_end(params); + exit(1); +} + +static void *xmalloc(size_t size) +{ + void *ret = malloc(size); + if (!ret && !size) + ret = malloc(1); + if (!ret) + die("Out of memory"); + return ret; +} + +static char *xstrdup(const char *str) +{ + char *ret = strdup(str); + if (!ret) + die("Out of memory"); + return ret; +} + +/* MinGW doesn't have wincred.h, so we need to define stuff */ + +typedef struct _CREDENTIAL_ATTRIBUTEW { + LPWSTR Keyword; + DWORD Flags; + DWORD ValueSize; + LPBYTE Value; +} CREDENTIAL_ATTRIBUTEW, *PCREDENTIAL_ATTRIBUTEW; + +typedef struct _CREDENTIALW { + DWORD Flags; + DWORD Type; + LPWSTR TargetName; + LPWSTR Comment; + FILETIME LastWritten; + DWORD CredentialBlobSize; + LPBYTE CredentialBlob; + DWORD Persist; + DWORD AttributeCount; + PCREDENTIAL_ATTRIBUTEW Attributes; + LPWSTR TargetAlias; + LPWSTR UserName; +} CREDENTIALW, *PCREDENTIALW; + +#define CRED_TYPE_GENERIC 1 +#define CRED_PERSIST_LOCAL_MACHINE 2 +#define CRED_MAX_ATTRIBUTES 64 + +typedef BOOL (WINAPI *CredWriteWT)(PCREDENTIALW, DWORD); +typedef BOOL (WINAPI *CredUnPackAuthenticationBufferWT)(DWORD, PVOID, DWORD, + LPWSTR, DWORD *, LPWSTR, DWORD *, LPWSTR, DWORD *); +typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *, + PCREDENTIALW **); +typedef BOOL (WINAPI *CredPackAuthenticationBufferWT)(DWORD, LPWSTR, LPWSTR, + PBYTE, DWORD *); +typedef VOID (WINAPI *CredFreeT)(PVOID); +typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD); + +static HMODULE advapi, credui; +static CredWriteWT CredWriteW; +static CredUnPackAuthenticationBufferWT CredUnPackAuthenticationBufferW; +static CredEnumerateWT CredEnumerateW; +static CredPackAuthenticationBufferWT CredPackAuthenticationBufferW; +static CredFreeT CredFree; +static CredDeleteWT CredDeleteW; + +static void load_cred_funcs(void) +{ + /* load DLLs */ + advapi = LoadLibrary("advapi32.dll"); + credui = LoadLibrary("credui.dll"); + if (!advapi || !credui) + die("failed to load DLLs"); + + /* get function pointers */ + CredWriteW = (CredWriteWT)GetProcAddress(advapi, "CredWriteW"); + CredUnPackAuthenticationBufferW = (CredUnPackAuthenticationBufferWT) + GetProcAddress(credui, "CredUnPackAuthenticationBufferW"); + CredEnumerateW = (CredEnumerateWT)GetProcAddress(advapi, + "CredEnumerateW"); + CredPackAuthenticationBufferW = (CredPackAuthenticationBufferWT) + GetProcAddress(credui, "CredPackAuthenticationBufferW"); + CredFree = (CredFreeT)GetProcAddress(advapi, "CredFree"); + CredDeleteW = (CredDeleteWT)GetProcAddress(advapi, "CredDeleteW"); + if (!CredWriteW || !CredUnPackAuthenticationBufferW || + !CredEnumerateW || !CredPackAuthenticationBufferW || !CredFree || + !CredDeleteW) + die("failed to load functions"); +} + +static char target_buf[1024]; +static char *protocol, *host, *path, *username; +static WCHAR *wusername, *password, *target; + +static void write_item(const char *what, WCHAR *wbuf) +{ + char *buf; + int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL, + FALSE); + buf = xmalloc(len); + + if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, len, NULL, FALSE)) + die("WideCharToMultiByte failed!"); + + printf("%s=", what); + fwrite(buf, 1, len - 1, stdout); + putchar('\n'); + free(buf); +} + +static int match_attr(const CREDENTIALW *cred, const WCHAR *keyword, + const char *want) +{ + int i; + if (!want) + return 1; + + for (i = 0; i < cred->AttributeCount; ++i) + if (!wcscmp(cred->Attributes[i].Keyword, keyword)) + return !strcmp((const char *)cred->Attributes[i].Value, + want); + + return 0; /* not found */ +} + +static int match_cred(const CREDENTIALW *cred) +{ + return (!wusername || !wcscmp(wusername, cred->UserName)) && + match_attr(cred, L"git_protocol", protocol) && + match_attr(cred, L"git_host", host) && + match_attr(cred, L"git_path", path); +} + +static void get_credential(void) +{ + WCHAR *user_buf, *pass_buf; + DWORD user_buf_size = 0, pass_buf_size = 0; + CREDENTIALW **creds, *cred = NULL; + DWORD num_creds; + int i; + + if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds)) + return; + + /* search for the first credential that matches username */ + for (i = 0; i < num_creds; ++i) + if (match_cred(creds[i])) { + cred = creds[i]; + break; + } + if (!cred) + return; + + CredUnPackAuthenticationBufferW(0, cred->CredentialBlob, + cred->CredentialBlobSize, NULL, &user_buf_size, NULL, NULL, + NULL, &pass_buf_size); + + user_buf = xmalloc(user_buf_size * sizeof(WCHAR)); + pass_buf = xmalloc(pass_buf_size * sizeof(WCHAR)); + + if (!CredUnPackAuthenticationBufferW(0, cred->CredentialBlob, + cred->CredentialBlobSize, user_buf, &user_buf_size, NULL, NULL, + pass_buf, &pass_buf_size)) + die("CredUnPackAuthenticationBuffer failed"); + + CredFree(creds); + + /* zero-terminate (sizes include zero-termination) */ + user_buf[user_buf_size - 1] = L'\0'; + pass_buf[pass_buf_size - 1] = L'\0'; + + write_item("username", user_buf); + write_item("password", pass_buf); + + free(user_buf); + free(pass_buf); +} + +static void write_attr(CREDENTIAL_ATTRIBUTEW *attr, const WCHAR *keyword, + const char *value) +{ + attr->Keyword = (LPWSTR)keyword; + attr->Flags = 0; + attr->ValueSize = strlen(value) + 1; /* store zero-termination */ + attr->Value = (LPBYTE)value; +} + +static void store_credential(void) +{ + CREDENTIALW cred; + BYTE *auth_buf; + DWORD auth_buf_size = 0; + CREDENTIAL_ATTRIBUTEW attrs[CRED_MAX_ATTRIBUTES]; + + if (!wusername || !password) + return; + + /* query buffer size */ + CredPackAuthenticationBufferW(0, wusername, password, + NULL, &auth_buf_size); + + auth_buf = xmalloc(auth_buf_size); + + if (!CredPackAuthenticationBufferW(0, wusername, password, + auth_buf, &auth_buf_size)) + die("CredPackAuthenticationBuffer failed"); + + cred.Flags = 0; + cred.Type = CRED_TYPE_GENERIC; + cred.TargetName = target; + cred.Comment = L"saved by git-credential-wincred"; + cred.CredentialBlobSize = auth_buf_size; + cred.CredentialBlob = auth_buf; + cred.Persist = CRED_PERSIST_LOCAL_MACHINE; + cred.AttributeCount = 1; + cred.Attributes = attrs; + cred.TargetAlias = NULL; + cred.UserName = wusername; + + write_attr(attrs, L"git_protocol", protocol); + + if (host) { + write_attr(attrs + cred.AttributeCount, L"git_host", host); + cred.AttributeCount++; + } + + if (path) { + write_attr(attrs + cred.AttributeCount, L"git_path", path); + cred.AttributeCount++; + } + + if (!CredWriteW(&cred, 0)) + die("CredWrite failed"); +} + +static void erase_credential(void) +{ + CREDENTIALW **creds; + DWORD num_creds; + int i; + + if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds)) + return; + + for (i = 0; i < num_creds; ++i) { + if (match_cred(creds[i])) + CredDeleteW(creds[i]->TargetName, creds[i]->Type, 0); + } + + CredFree(creds); +} + +static WCHAR *utf8_to_utf16_dup(const char *str) +{ + int wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + WCHAR *wstr = xmalloc(sizeof(WCHAR) * wlen); + MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, wlen); + return wstr; +} + +static void read_credential(void) +{ + char buf[1024]; + + while (fgets(buf, sizeof(buf), stdin)) { + char *v; + + if (!strcmp(buf, "\n")) + break; + buf[strlen(buf)-1] = '\0'; + + v = strchr(buf, '='); + if (!v) + die("bad input: %s", buf); + *v++ = '\0'; + + if (!strcmp(buf, "protocol")) + protocol = xstrdup(v); + else if (!strcmp(buf, "host")) + host = xstrdup(v); + else if (!strcmp(buf, "path")) + path = xstrdup(v); + else if (!strcmp(buf, "username")) { + username = xstrdup(v); + wusername = utf8_to_utf16_dup(v); + } else if (!strcmp(buf, "password")) + password = utf8_to_utf16_dup(v); + else + die("unrecognized input"); + } +} + +int main(int argc, char *argv[]) +{ + const char *usage = + "Usage: git credential-wincred <get|store|erase>\n"; + + if (!argv[1]) + die(usage); + + /* git use binary pipes to avoid CRLF-issues */ + _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdout), _O_BINARY); + + read_credential(); + + load_cred_funcs(); + + if (!protocol || !(host || path)) + return 0; + + /* prepare 'target', the unique key for the credential */ + strncat(target_buf, "git:", sizeof(target_buf)); + strncat(target_buf, protocol, sizeof(target_buf)); + strncat(target_buf, "://", sizeof(target_buf)); + if (username) { + strncat(target_buf, username, sizeof(target_buf)); + strncat(target_buf, "@", sizeof(target_buf)); + } + if (host) + strncat(target_buf, host, sizeof(target_buf)); + if (path) { + strncat(target_buf, "/", sizeof(target_buf)); + strncat(target_buf, path, sizeof(target_buf)); + } + + target = utf8_to_utf16_dup(target_buf); + + if (!strcmp(argv[1], "get")) + get_credential(); + else if (!strcmp(argv[1], "store")) + store_credential(); + else if (!strcmp(argv[1], "erase")) + erase_credential(); + /* otherwise, ignore unknown action */ + return 0; +} diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index 65c95d9d5..5ffc506f6 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -1671,7 +1671,7 @@ Commands: "Entry point into git-status mode." (interactive "DSelect directory: ") (setq dir (git-get-top-dir dir)) - (if (file-directory-p (concat (file-name-as-directory dir) ".git")) + (if (file-exists-p (concat (file-name-as-directory dir) ".git")) (let ((buffer (or (and git-reuse-status-buffer (git-find-status-buffer dir)) (create-file-buffer (expand-file-name "*git-status*" dir))))) (switch-to-buffer buffer) diff --git a/contrib/examples/builtin-fetch--tool.c b/contrib/examples/builtin-fetch--tool.c index 0d54aa706..8bc8c7533 100644 --- a/contrib/examples/builtin-fetch--tool.c +++ b/contrib/examples/builtin-fetch--tool.c @@ -96,7 +96,7 @@ static int update_local_ref(const char *name, strcpy(oldh, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcpy(newh, find_unique_abbrev(sha1_new, DEFAULT_ABBREV)); - if (in_merge_bases(current, &updated, 1)) { + if (in_merge_bases(current, updated)) { fprintf(stderr, "* %s: fast-forward to %s\n", name, note); fprintf(stderr, " old..new: %s..%s\n", oldh, newh); diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump index a33674e47..dc90cd637 100755 --- a/contrib/git-jump/git-jump +++ b/contrib/git-jump/git-jump @@ -21,9 +21,9 @@ open_editor() { } mode_diff() { - git diff --relative "$@" | + git diff --no-prefix --relative "$@" | perl -ne ' - if (m{^\+\+\+ b/(.*)}) { $file = $1; next } + if (m{^\+\+\+ (.*)}) { $file = $1; next } defined($file) or next; if (m/^@@ .*\+(\d+)/) { $line = $1; next } defined($line) or next; diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email index 01af9df15..b2171a092 100755 --- a/contrib/hooks/post-receive-email +++ b/contrib/hooks/post-receive-email @@ -403,7 +403,7 @@ generate_update_branch_email() echo " \\" echo " O -- O -- O ($oldrev)" echo "" - echo "The removed revisions are not necessarilly gone - if another reference" + echo "The removed revisions are not necessarily gone - if another reference" echo "still refers to them they will stay in the repository." rewind_only=1 else diff --git a/contrib/mw-to-git/Makefile b/contrib/mw-to-git/Makefile new file mode 100644 index 000000000..3ed728b0e --- /dev/null +++ b/contrib/mw-to-git/Makefile @@ -0,0 +1,47 @@ +# +# Copyright (C) 2012 +# Charles Roussel <charles.roussel@ensimag.imag.fr> +# Simon Cathebras <simon.cathebras@ensimag.imag.fr> +# Julien Khayat <julien.khayat@ensimag.imag.fr> +# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr> +# Simon Perrat <simon.perrat@ensimag.imag.fr> +# +## Build git-remote-mediawiki + +-include ../../config.mak.autogen +-include ../../config.mak + +ifndef PERL_PATH + PERL_PATH = /usr/bin/perl +endif +ifndef gitexecdir + gitexecdir = $(shell git --exec-path) +endif + +PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) +gitexecdir_SQ = $(subst ','\'',$(gitexecdir)) +SCRIPT = git-remote-mediawiki + +.PHONY: install help doc test clean + +help: + @echo 'This is the help target of the Makefile. Current configuration:' + @echo ' gitexecdir = $(gitexecdir_SQ)' + @echo ' PERL_PATH = $(PERL_PATH_SQ)' + @echo 'Run "$(MAKE) install" to install $(SCRIPT) in gitexecdir' + @echo 'Run "$(MAKE) test" to run the testsuite' + +install: + sed -e '1s|#!.*/perl|#!$(PERL_PATH_SQ)|' $(SCRIPT) \ + > '$(gitexecdir_SQ)/$(SCRIPT)' + chmod +x '$(gitexecdir)/$(SCRIPT)' + +doc: + @echo 'Sorry, "make doc" is not implemented yet for $(SCRIPT)' + +test: + $(MAKE) -C t/ test + +clean: + $(RM) '$(gitexecdir)/$(SCRIPT)' + $(MAKE) -C t/ clean diff --git a/contrib/mw-to-git/git-remote-mediawiki b/contrib/mw-to-git/git-remote-mediawiki index c18bfa1f1..094129de0 100755 --- a/contrib/mw-to-git/git-remote-mediawiki +++ b/contrib/mw-to-git/git-remote-mediawiki @@ -9,40 +9,19 @@ # License: GPL v2 or later # Gateway between Git and MediaWiki. -# https://github.com/Bibzball/Git-Mediawiki/wiki -# -# Known limitations: -# -# - Only wiki pages are managed, no support for [[File:...]] -# attachments. -# -# - Poor performance in the best case: it takes forever to check -# whether we're up-to-date (on fetch or push) or to fetch a few -# revisions from a large wiki, because we use exclusively a -# page-based synchronization. We could switch to a wiki-wide -# synchronization when the synchronization involves few revisions -# but the wiki is large. -# -# - Git renames could be turned into MediaWiki renames (see TODO -# below) -# -# - login/password support requires the user to write the password -# cleartext in a file (see TODO below). -# -# - No way to import "one page, and all pages included in it" -# -# - Multiple remote MediaWikis have not been very well tested. +# Documentation & bugtracker: https://github.com/moy/Git-Mediawiki/ use strict; use MediaWiki::API; use DateTime::Format::ISO8601; -use encoding 'utf8'; -# use encoding 'utf8' doesn't change STDERROR -# but we're going to output UTF-8 filenames to STDERR +# By default, use UTF-8 to communicate with Git and the user binmode STDERR, ":utf8"; +binmode STDOUT, ":utf8"; use URI::Escape; +use IPC::Open2; + use warnings; # Mediawiki filenames can contain forward slashes. This variable decides by which pattern they should be replaced @@ -59,6 +38,9 @@ use constant EMPTY_CONTENT => "<!-- empty page -->\n"; # used to reflect file creation or deletion in diff. use constant NULL_SHA1 => "0000000000000000000000000000000000000000"; +# Used on Git's side to reflect empty edit messages on the wiki +use constant EMPTY_MESSAGE => '*Empty MediaWiki Message*'; + my $remotename = $ARGV[0]; my $url = $ARGV[1]; @@ -71,10 +53,18 @@ chomp(@tracked_pages); my @tracked_categories = split(/[ \n]/, run_git("config --get-all remote.". $remotename .".categories")); chomp(@tracked_categories); +# Import media files on pull +my $import_media = run_git("config --get --bool remote.". $remotename .".mediaimport"); +chomp($import_media); +$import_media = ($import_media eq "true"); + +# Export media files on push +my $export_media = run_git("config --get --bool remote.". $remotename .".mediaexport"); +chomp($export_media); +$export_media = !($export_media eq "false"); + my $wiki_login = run_git("config --get remote.". $remotename .".mwLogin"); -# TODO: ideally, this should be able to read from keyboard, but we're -# inside a remote helper, so our stdin is connect to git, not to a -# terminal. +# Note: mwPassword is discourraged. Use the credential system instead. my $wiki_passwd = run_git("config --get remote.". $remotename .".mwPassword"); my $wiki_domain = run_git("config --get remote.". $remotename .".mwDomain"); chomp($wiki_login); @@ -86,6 +76,21 @@ my $shallow_import = run_git("config --get --bool remote.". $remotename .".shall chomp($shallow_import); $shallow_import = ($shallow_import eq "true"); +# Fetch (clone and pull) by revisions instead of by pages. This behavior +# is more efficient when we have a wiki with lots of pages and we fetch +# the revisions quite often so that they concern only few pages. +# Possible values: +# - by_rev: perform one query per new revision on the remote wiki +# - by_page: query each tracked page for new revision +my $fetch_strategy = run_git("config --get remote.$remotename.fetchStrategy"); +unless ($fetch_strategy) { + $fetch_strategy = run_git("config --get mediawiki.fetchStrategy"); +} +chomp($fetch_strategy); +unless ($fetch_strategy) { + $fetch_strategy = "by_page"; +} + # Dumb push: don't update notes and mediawiki ref to reflect the last push. # # Configurable with mediawiki.dumbPush, or per-remote with @@ -151,32 +156,152 @@ while (<STDIN>) { ########################## Functions ############################## +## credential API management (generic functions) + +sub credential_read { + my %credential; + my $reader = shift; + my $op = shift; + while (<$reader>) { + my ($key, $value) = /([^=]*)=(.*)/; + if (not defined $key) { + die "ERROR receiving response from git credential $op:\n$_\n"; + } + $credential{$key} = $value; + } + return %credential; +} + +sub credential_write { + my $credential = shift; + my $writer = shift; + # url overwrites other fields, so it must come first + print $writer "url=$credential->{url}\n" if exists $credential->{url}; + while (my ($key, $value) = each(%$credential) ) { + if (length $value && $key ne 'url') { + print $writer "$key=$value\n"; + } + } +} + +sub credential_run { + my $op = shift; + my $credential = shift; + my $pid = open2(my $reader, my $writer, "git credential $op"); + credential_write($credential, $writer); + print $writer "\n"; + close($writer); + + if ($op eq "fill") { + %$credential = credential_read($reader, $op); + } else { + if (<$reader>) { + die "ERROR while running git credential $op:\n$_"; + } + } + close($reader); + waitpid($pid, 0); + my $child_exit_status = $? >> 8; + if ($child_exit_status != 0) { + die "'git credential $op' failed with code $child_exit_status."; + } +} + # MediaWiki API instance, created lazily. my $mediawiki; sub mw_connect_maybe { if ($mediawiki) { - return; + return; } $mediawiki = MediaWiki::API->new; $mediawiki->{config}->{api_url} = "$url/api.php"; if ($wiki_login) { - if (!$mediawiki->login({ - lgname => $wiki_login, - lgpassword => $wiki_passwd, - lgdomain => $wiki_domain, - })) { - print STDERR "Failed to log in mediawiki user \"$wiki_login\" on $url\n"; - print STDERR "(error " . - $mediawiki->{error}->{code} . ': ' . - $mediawiki->{error}->{details} . ")\n"; - exit 1; + my %credential = (url => $url); + $credential{username} = $wiki_login; + $credential{password} = $wiki_passwd; + credential_run("fill", \%credential); + my $request = {lgname => $credential{username}, + lgpassword => $credential{password}, + lgdomain => $wiki_domain}; + if ($mediawiki->login($request)) { + credential_run("approve", \%credential); + print STDERR "Logged in mediawiki user \"$credential{username}\".\n"; } else { - print STDERR "Logged in with user \"$wiki_login\".\n"; + print STDERR "Failed to log in mediawiki user \"$credential{username}\" on $url\n"; + print STDERR " (error " . + $mediawiki->{error}->{code} . ': ' . + $mediawiki->{error}->{details} . ")\n"; + credential_run("reject", \%credential); + exit 1; + } + } +} + +## Functions for listing pages on the remote wiki +sub get_mw_tracked_pages { + my $pages = shift; + get_mw_page_list(\@tracked_pages, $pages); +} + +sub get_mw_page_list { + my $page_list = shift; + my $pages = shift; + my @some_pages = @$page_list; + while (@some_pages) { + my $last = 50; + if ($#some_pages < $last) { + $last = $#some_pages; + } + my @slice = @some_pages[0..$last]; + get_mw_first_pages(\@slice, $pages); + @some_pages = @some_pages[51..$#some_pages]; + } +} + +sub get_mw_tracked_categories { + my $pages = shift; + foreach my $category (@tracked_categories) { + if (index($category, ':') < 0) { + # Mediawiki requires the Category + # prefix, but let's not force the user + # to specify it. + $category = "Category:" . $category; + } + my $mw_pages = $mediawiki->list( { + action => 'query', + list => 'categorymembers', + cmtitle => $category, + cmlimit => 'max' } ) + || die $mediawiki->{error}->{code} . ': ' + . $mediawiki->{error}->{details}; + foreach my $page (@{$mw_pages}) { + $pages->{$page->{title}} = $page; } } } +sub get_mw_all_pages { + my $pages = shift; + # No user-provided list, get the list of pages from the API. + my $mw_pages = $mediawiki->list({ + action => 'query', + list => 'allpages', + aplimit => 'max' + }); + if (!defined($mw_pages)) { + print STDERR "fatal: could not get the list of wiki pages.\n"; + print STDERR "fatal: '$url' does not appear to be a mediawiki\n"; + print STDERR "fatal: make sure '$url/api.php' is a valid page.\n"; + exit 1; + } + foreach my $page (@{$mw_pages}) { + $pages->{$page->{title}} = $page; + } +} + +# queries the wiki for a set of pages. Meant to be used within a loop +# querying the wiki for slices of page list. sub get_mw_first_pages { my $some_pages = shift; my @some_pages = @{$some_pages}; @@ -205,70 +330,45 @@ sub get_mw_first_pages { } } +# Get the list of pages to be fetched according to configuration. sub get_mw_pages { mw_connect_maybe(); + print STDERR "Listing pages on remote wiki...\n"; + my %pages; # hash on page titles to avoid duplicates my $user_defined; if (@tracked_pages) { $user_defined = 1; # The user provided a list of pages titles, but we # still need to query the API to get the page IDs. - - my @some_pages = @tracked_pages; - while (@some_pages) { - my $last = 50; - if ($#some_pages < $last) { - $last = $#some_pages; - } - my @slice = @some_pages[0..$last]; - get_mw_first_pages(\@slice, \%pages); - @some_pages = @some_pages[51..$#some_pages]; - } + get_mw_tracked_pages(\%pages); } if (@tracked_categories) { $user_defined = 1; - foreach my $category (@tracked_categories) { - if (index($category, ':') < 0) { - # Mediawiki requires the Category - # prefix, but let's not force the user - # to specify it. - $category = "Category:" . $category; - } - my $mw_pages = $mediawiki->list( { - action => 'query', - list => 'categorymembers', - cmtitle => $category, - cmlimit => 'max' } ) - || die $mediawiki->{error}->{code} . ': ' . $mediawiki->{error}->{details}; - foreach my $page (@{$mw_pages}) { - $pages{$page->{title}} = $page; - } - } + get_mw_tracked_categories(\%pages); } if (!$user_defined) { - # No user-provided list, get the list of pages from - # the API. - my $mw_pages = $mediawiki->list({ - action => 'query', - list => 'allpages', - aplimit => 500, - }); - if (!defined($mw_pages)) { - print STDERR "fatal: could not get the list of wiki pages.\n"; - print STDERR "fatal: '$url' does not appear to be a mediawiki\n"; - print STDERR "fatal: make sure '$url/api.php' is a valid page.\n"; - exit 1; - } - foreach my $page (@{$mw_pages}) { - $pages{$page->{title}} = $page; + get_mw_all_pages(\%pages); + } + if ($import_media) { + print STDERR "Getting media files for selected pages...\n"; + if ($user_defined) { + get_linked_mediafiles(\%pages); + } else { + get_all_mediafiles(\%pages); } } - return values(%pages); + print STDERR (scalar keys %pages) . " pages found.\n"; + return %pages; } +# usage: $out = run_git("command args"); +# $out = run_git("command args", "raw"); # don't interpret output as UTF-8. sub run_git { - open(my $git, "-|:encoding(UTF-8)", "git " . $_[0]); + my $args = shift; + my $encoding = (shift || "encoding(UTF-8)"); + open(my $git, "-|:$encoding", "git " . $args); my $res = do { local $/; <$git> }; close($git); @@ -276,6 +376,123 @@ sub run_git { } +sub get_all_mediafiles { + my $pages = shift; + # Attach list of all pages for media files from the API, + # they are in a different namespace, only one namespace + # can be queried at the same moment + my $mw_pages = $mediawiki->list({ + action => 'query', + list => 'allpages', + apnamespace => get_mw_namespace_id("File"), + aplimit => 'max' + }); + if (!defined($mw_pages)) { + print STDERR "fatal: could not get the list of pages for media files.\n"; + print STDERR "fatal: '$url' does not appear to be a mediawiki\n"; + print STDERR "fatal: make sure '$url/api.php' is a valid page.\n"; + exit 1; + } + foreach my $page (@{$mw_pages}) { + $pages->{$page->{title}} = $page; + } +} + +sub get_linked_mediafiles { + my $pages = shift; + my @titles = map $_->{title}, values(%{$pages}); + + # The query is split in small batches because of the MW API limit of + # the number of links to be returned (500 links max). + my $batch = 10; + while (@titles) { + if ($#titles < $batch) { + $batch = $#titles; + } + my @slice = @titles[0..$batch]; + + # pattern 'page1|page2|...' required by the API + my $mw_titles = join('|', @slice); + + # Media files could be included or linked from + # a page, get all related + my $query = { + action => 'query', + prop => 'links|images', + titles => $mw_titles, + plnamespace => get_mw_namespace_id("File"), + pllimit => 'max' + }; + my $result = $mediawiki->api($query); + + while (my ($id, $page) = each(%{$result->{query}->{pages}})) { + my @media_titles; + if (defined($page->{links})) { + my @link_titles = map $_->{title}, @{$page->{links}}; + push(@media_titles, @link_titles); + } + if (defined($page->{images})) { + my @image_titles = map $_->{title}, @{$page->{images}}; + push(@media_titles, @image_titles); + } + if (@media_titles) { + get_mw_page_list(\@media_titles, $pages); + } + } + + @titles = @titles[($batch+1)..$#titles]; + } +} + +sub get_mw_mediafile_for_page_revision { + # Name of the file on Wiki, with the prefix. + my $filename = shift; + my $timestamp = shift; + my %mediafile; + + # Search if on a media file with given timestamp exists on + # MediaWiki. In that case download the file. + my $query = { + action => 'query', + prop => 'imageinfo', + titles => "File:" . $filename, + iistart => $timestamp, + iiend => $timestamp, + iiprop => 'timestamp|archivename|url', + iilimit => 1 + }; + my $result = $mediawiki->api($query); + + my ($fileid, $file) = each( %{$result->{query}->{pages}} ); + # If not defined it means there is no revision of the file for + # given timestamp. + if (defined($file->{imageinfo})) { + $mediafile{title} = $filename; + + my $fileinfo = pop(@{$file->{imageinfo}}); + $mediafile{timestamp} = $fileinfo->{timestamp}; + # Mediawiki::API's download function doesn't support https URLs + # and can't download old versions of files. + print STDERR "\tDownloading file $mediafile{title}, version $mediafile{timestamp}\n"; + $mediafile{content} = download_mw_mediafile($fileinfo->{url}); + } + return %mediafile; +} + +sub download_mw_mediafile { + my $url = shift; + + my $response = $mediawiki->{ua}->get($url); + if ($response->code == 200) { + return $response->decoded_content; + } else { + print STDERR "Error downloading mediafile from :\n"; + print STDERR "URL: $url\n"; + print STDERR "Server response: " . $response->code . " " . $response->message . "\n"; + exit 1; + } +} + sub get_last_local_revision { # Get note regarding last mediawiki revision my $note = run_git("notes --ref=$remotename/mediawiki show refs/mediawiki/$remotename/master 2>/dev/null"); @@ -297,13 +514,36 @@ sub get_last_local_revision { # Remember the timestamp corresponding to a revision id. my %basetimestamps; +# Get the last remote revision without taking in account which pages are +# tracked or not. This function makes a single request to the wiki thus +# avoid a loop onto all tracked pages. This is useful for the fetch-by-rev +# option. +sub get_last_global_remote_rev { + mw_connect_maybe(); + + my $query = { + action => 'query', + list => 'recentchanges', + prop => 'revisions', + rclimit => '1', + rcdir => 'older', + }; + my $result = $mediawiki->api($query); + return $result->{query}->{recentchanges}[0]->{revid}; +} + +# Get the last remote revision concerning the tracked pages and the tracked +# categories. sub get_last_remote_revision { mw_connect_maybe(); - my @pages = get_mw_pages(); + my %pages_hash = get_mw_pages(); + my @pages = values(%pages_hash); my $max_rev_num = 0; + print STDERR "Getting last revision id on tracked pages...\n"; + foreach my $page (@pages) { my $id = $page->{pageid}; @@ -379,6 +619,16 @@ sub literal_data { print STDOUT "data ", bytes::length($content), "\n", $content; } +sub literal_data_raw { + # Output possibly binary content. + my ($content) = @_; + # Avoid confusion between size in bytes and in characters + utf8::downgrade($content); + binmode STDOUT, ":raw"; + print STDOUT "data ", bytes::length($content), "\n", $content; + binmode STDOUT, ":utf8"; +} + sub mw_capabilities { # Revisions are imported to the private namespace # refs/mediawiki/$remotename/ by the helper and fetched into @@ -461,11 +711,24 @@ sub fetch_mw_revisions { return ($n, @revisions); } +sub fe_escape_path { + my $path = shift; + $path =~ s/\\/\\\\/g; + $path =~ s/"/\\"/g; + $path =~ s/\n/\\n/g; + return '"' . $path . '"'; +} + sub import_file_revision { my $commit = shift; my %commit = %{$commit}; my $full_import = shift; my $n = shift; + my $mediafile = shift; + my %mediafile; + if ($mediafile) { + %mediafile = %{$mediafile}; + } my $title = $commit{title}; my $comment = $commit{comment}; @@ -483,11 +746,17 @@ sub import_file_revision { print STDOUT "from refs/mediawiki/$remotename/master^0\n"; } if ($content ne DELETED_CONTENT) { - print STDOUT "M 644 inline $title.mw\n"; + print STDOUT "M 644 inline " . + fe_escape_path($title . ".mw") . "\n"; literal_data($content); + if (%mediafile) { + print STDOUT "M 644 inline " + . fe_escape_path($mediafile{title}) . "\n"; + literal_data_raw($mediafile{content}); + } print STDOUT "\n\n"; } else { - print STDOUT "D $title.mw\n"; + print STDOUT "D " . fe_escape_path($title . ".mw") . "\n"; } # mediawiki revision number in the git note @@ -547,8 +816,6 @@ sub mw_import_ref { mw_connect_maybe(); - my @pages = get_mw_pages(); - print STDERR "Searching revisions...\n"; my $last_local = get_last_local_revision(); my $fetch_from = $last_local + 1; @@ -557,36 +824,111 @@ sub mw_import_ref { } else { print STDERR ", fetching from here.\n"; } + + my $n = 0; + if ($fetch_strategy eq "by_rev") { + print STDERR "Fetching & writing export data by revs...\n"; + $n = mw_import_ref_by_revs($fetch_from); + } elsif ($fetch_strategy eq "by_page") { + print STDERR "Fetching & writing export data by pages...\n"; + $n = mw_import_ref_by_pages($fetch_from); + } else { + print STDERR "fatal: invalid fetch strategy \"$fetch_strategy\".\n"; + print STDERR "Check your configuration variables remote.$remotename.fetchStrategy and mediawiki.fetchStrategy\n"; + exit 1; + } + + if ($fetch_from == 1 && $n == 0) { + print STDERR "You appear to have cloned an empty MediaWiki.\n"; + # Something has to be done remote-helper side. If nothing is done, an error is + # thrown saying that HEAD is refering to unknown object 0000000000000000000 + # and the clone fails. + } +} + +sub mw_import_ref_by_pages { + + my $fetch_from = shift; + my %pages_hash = get_mw_pages(); + my @pages = values(%pages_hash); + my ($n, @revisions) = fetch_mw_revisions(\@pages, $fetch_from); - # Creation of the fast-import stream - print STDERR "Fetching & writing export data...\n"; + @revisions = sort {$a->{revid} <=> $b->{revid}} @revisions; + my @revision_ids = map $_->{revid}, @revisions; - $n = 0; + return mw_import_revids($fetch_from, \@revision_ids, \%pages_hash); +} + +sub mw_import_ref_by_revs { + + my $fetch_from = shift; + my %pages_hash = get_mw_pages(); + + my $last_remote = get_last_global_remote_rev(); + my @revision_ids = $fetch_from..$last_remote; + return mw_import_revids($fetch_from, \@revision_ids, \%pages_hash); +} + +# Import revisions given in second argument (array of integers). +# Only pages appearing in the third argument (hash indexed by page titles) +# will be imported. +sub mw_import_revids { + my $fetch_from = shift; + my $revision_ids = shift; + my $pages = shift; + + my $n = 0; + my $n_actual = 0; my $last_timestamp = 0; # Placeholer in case $rev->timestamp is undefined - foreach my $pagerevid (sort {$a->{revid} <=> $b->{revid}} @revisions) { + foreach my $pagerevid (@$revision_ids) { + # Count page even if we skip it, since we display + # $n/$total and $total includes skipped pages. + $n++; + # fetch the content of the pages my $query = { action => 'query', prop => 'revisions', rvprop => 'content|timestamp|comment|user|ids', - revids => $pagerevid->{revid}, + revids => $pagerevid, }; my $result = $mediawiki->api($query); - my $rev = pop(@{$result->{query}->{pages}->{$pagerevid->{pageid}}->{revisions}}); + if (!$result) { + die "Failed to retrieve modified page for revision $pagerevid"; + } - $n++; + if (defined($result->{query}->{badrevids}->{$pagerevid})) { + # The revision id does not exist on the remote wiki. + next; + } + + if (!defined($result->{query}->{pages})) { + die "Invalid revision $pagerevid."; + } + + my @result_pages = values(%{$result->{query}->{pages}}); + my $result_page = $result_pages[0]; + my $rev = $result_pages[0]->{revisions}->[0]; + + my $page_title = $result_page->{title}; + + if (!exists($pages->{$page_title})) { + print STDERR "$n/", scalar(@$revision_ids), + ": Skipping revision #$rev->{revid} of $page_title\n"; + next; + } + + $n_actual++; my %commit; $commit{author} = $rev->{user} || 'Anonymous'; - $commit{comment} = $rev->{comment} || '*Empty MediaWiki Message*'; - $commit{title} = mediawiki_smudge_filename( - $result->{query}->{pages}->{$pagerevid->{pageid}}->{title} - ); - $commit{mw_revision} = $pagerevid->{revid}; + $commit{comment} = $rev->{comment} || EMPTY_MESSAGE; + $commit{title} = mediawiki_smudge_filename($page_title); + $commit{mw_revision} = $rev->{revid}; $commit{content} = mediawiki_smudge($rev->{'*'}); if (!defined($rev->{timestamp})) { @@ -596,17 +938,23 @@ sub mw_import_ref { } $commit{date} = DateTime::Format::ISO8601->parse_datetime($last_timestamp); - print STDERR "$n/", scalar(@revisions), ": Revision #$pagerevid->{revid} of $commit{title}\n"; - - import_file_revision(\%commit, ($fetch_from == 1), $n); + # Differentiates classic pages and media files. + my ($namespace, $filename) = $page_title =~ /^([^:]*):(.*)$/; + my %mediafile; + if ($namespace) { + my $id = get_mw_namespace_id($namespace); + if ($id && $id == get_mw_namespace_id("File")) { + %mediafile = get_mw_mediafile_for_page_revision($filename, $rev->{timestamp}); + } + } + # If this is a revision of the media page for new version + # of a file do one common commit for both file and media page. + # Else do commit only for that page. + print STDERR "$n/", scalar(@$revision_ids), ": Revision #$rev->{revid} of $commit{title}\n"; + import_file_revision(\%commit, ($fetch_from == 1), $n_actual, \%mediafile); } - if ($fetch_from == 1 && $n == 0) { - print STDERR "You appear to have cloned an empty MediaWiki.\n"; - # Something has to be done remote-helper side. If nothing is done, an error is - # thrown saying that HEAD is refering to unknown object 0000000000000000000 - # and the clone fails. - } + return $n_actual; } sub error_non_fast_forward { @@ -624,6 +972,63 @@ sub error_non_fast_forward { return 0; } +sub mw_upload_file { + my $complete_file_name = shift; + my $new_sha1 = shift; + my $extension = shift; + my $file_deleted = shift; + my $summary = shift; + my $newrevid; + my $path = "File:" . $complete_file_name; + my %hashFiles = get_allowed_file_extensions(); + if (!exists($hashFiles{$extension})) { + print STDERR "$complete_file_name is not a permitted file on this wiki.\n"; + print STDERR "Check the configuration of file uploads in your mediawiki.\n"; + return $newrevid; + } + # Deleting and uploading a file requires a priviledged user + if ($file_deleted) { + mw_connect_maybe(); + my $query = { + action => 'delete', + title => $path, + reason => $summary + }; + if (!$mediawiki->edit($query)) { + print STDERR "Failed to delete file on remote wiki\n"; + print STDERR "Check your permissions on the remote site. Error code:\n"; + print STDERR $mediawiki->{error}->{code} . ':' . $mediawiki->{error}->{details}; + exit 1; + } + } else { + # Don't let perl try to interpret file content as UTF-8 => use "raw" + my $content = run_git("cat-file blob $new_sha1", "raw"); + if ($content ne "") { + mw_connect_maybe(); + $mediawiki->{config}->{upload_url} = + "$url/index.php/Special:Upload"; + $mediawiki->edit({ + action => 'upload', + filename => $complete_file_name, + comment => $summary, + file => [undef, + $complete_file_name, + Content => $content], + ignorewarnings => 1, + }, { + skip_encoding => 1 + } ) || die $mediawiki->{error}->{code} . ':' + . $mediawiki->{error}->{details}; + my $last_file_page = $mediawiki->get_page({title => $path}); + $newrevid = $last_file_page->{revid}; + print STDERR "Pushed file: $new_sha1 - $complete_file_name.\n"; + } else { + print STDERR "Empty file $complete_file_name not pushed.\n"; + } + } + return $newrevid; +} + sub mw_push_file { my $diff_info = shift; # $diff_info contains a string in this format: @@ -636,7 +1041,12 @@ sub mw_push_file { my $summary = shift; # MediaWiki revision number. Keep the previous one by default, # in case there's no edit to perform. - my $newrevid = shift; + my $oldrevid = shift; + my $newrevid; + + if ($summary eq EMPTY_MESSAGE) { + $summary = ''; + } my $new_sha1 = $diff_info_split[3]; my $old_sha1 = $diff_info_split[2]; @@ -644,9 +1054,16 @@ sub mw_push_file { my $page_deleted = ($new_sha1 eq NULL_SHA1); $complete_file_name = mediawiki_clean_filename($complete_file_name); - if (substr($complete_file_name,-3) eq ".mw") { - my $title = substr($complete_file_name,0,-3); - + my ($title, $extension) = $complete_file_name =~ /^(.*)\.([^\.]*)$/; + if (!defined($extension)) { + $extension = ""; + } + if ($extension eq "mw") { + my $ns = get_mw_namespace_id_for_page($complete_file_name); + if ($ns && $ns == get_mw_namespace_id("File") && (!$export_media)) { + print STDERR "Ignoring media file related page: $complete_file_name\n"; + return ($oldrevid, "ok"); + } my $file_content; if ($page_deleted) { # Deleting a page usually requires @@ -664,7 +1081,7 @@ sub mw_push_file { action => 'edit', summary => $summary, title => $title, - basetimestamp => $basetimestamps{$newrevid}, + basetimestamp => $basetimestamps{$oldrevid}, text => mediawiki_clean($file_content, $page_created), }, { skip_encoding => 1 # Helps with names with accentuated characters @@ -676,7 +1093,7 @@ sub mw_push_file { $mediawiki->{error}->{code} . ' from mediwiki: ' . $mediawiki->{error}->{details} . ".\n"; - return ($newrevid, "non-fast-forward"); + return ($oldrevid, "non-fast-forward"); } else { # Other errors. Shouldn't happen => just die() die 'Fatal: Error ' . @@ -686,9 +1103,14 @@ sub mw_push_file { } $newrevid = $result->{edit}->{newrevid}; print STDERR "Pushed file: $new_sha1 - $title\n"; + } elsif ($export_media) { + $newrevid = mw_upload_file($complete_file_name, $new_sha1, + $extension, $page_deleted, + $summary); } else { - print STDERR "$complete_file_name not a mediawiki file (Not pushable on this version of git-remote-mediawiki).\n" + print STDERR "Ignoring media file $title\n"; } + $newrevid = ($newrevid or $oldrevid); return ($newrevid, "ok"); } @@ -760,16 +1182,26 @@ sub mw_push_revision { if ($last_local_revid > 0) { my $parsed_sha1 = $remoteorigin_sha1; # Find a path from last MediaWiki commit to pushed commit + print STDERR "Computing path from local to remote ...\n"; + my @local_ancestry = split(/\n/, run_git("rev-list --boundary --parents $local ^$parsed_sha1")); + my %local_ancestry; + foreach my $line (@local_ancestry) { + if (my ($child, $parents) = $line =~ m/^-?([a-f0-9]+) ([a-f0-9 ]+)/) { + foreach my $parent (split(' ', $parents)) { + $local_ancestry{$parent} = $child; + } + } elsif (!$line =~ m/^([a-f0-9]+)/) { + die "Unexpected output from git rev-list: $line"; + } + } while ($parsed_sha1 ne $HEAD_sha1) { - my @commit_info = grep(/^$parsed_sha1/, split(/\n/, run_git("rev-list --children $local"))); - if (!@commit_info) { + my $child = $local_ancestry{$parsed_sha1}; + if (!$child) { + printf STDERR "Cannot find a path in history from remote commit to last commit\n"; return error_non_fast_forward($remote); } - my @commit_info_split = split(/ |\n/, $commit_info[0]); - # $commit_info_split[1] is the sha1 of the commit to export - # $commit_info_split[0] is the sha1 of its direct child - push(@commit_pairs, \@commit_info_split); - $parsed_sha1 = $commit_info_split[1]; + push(@commit_pairs, [$parsed_sha1, $child]); + $parsed_sha1 = $child; } } else { # No remote mediawiki revision. Export the whole @@ -791,8 +1223,8 @@ sub mw_push_revision { # TODO: we could detect rename, and encode them with a #redirect on the wiki. # TODO: for now, it's just a delete+add my @diff_info_list = split(/\0/, $diff_infos); - # Keep the first line of the commit message as mediawiki comment for the revision - my $commit_msg = (split(/\n/, run_git("show --pretty=format:\"%s\" $sha1_commit")))[0]; + # Keep the subject line of the commit message as mediawiki comment for the revision + my $commit_msg = run_git("log --no-walk --format=\"%s\" $sha1_commit"); chomp($commit_msg); # Push every blob while (@diff_info_list) { @@ -817,7 +1249,7 @@ sub mw_push_revision { } } unless ($dumb_push) { - run_git("notes --ref=$remotename/mediawiki add -m \"mediawiki_revision: $mw_revision\" $sha1_commit"); + run_git("notes --ref=$remotename/mediawiki add -f -m \"mediawiki_revision: $mw_revision\" $sha1_commit"); run_git("update-ref -m \"Git-MediaWiki push\" refs/mediawiki/$remotename/master $sha1_commit $sha1_child"); } } @@ -825,3 +1257,104 @@ sub mw_push_revision { print STDOUT "ok $remote\n"; return 1; } + +sub get_allowed_file_extensions { + mw_connect_maybe(); + + my $query = { + action => 'query', + meta => 'siteinfo', + siprop => 'fileextensions' + }; + my $result = $mediawiki->api($query); + my @file_extensions= map $_->{ext},@{$result->{query}->{fileextensions}}; + my %hashFile = map {$_ => 1}@file_extensions; + + return %hashFile; +} + +# In memory cache for MediaWiki namespace ids. +my %namespace_id; + +# Namespaces whose id is cached in the configuration file +# (to avoid duplicates) +my %cached_mw_namespace_id; + +# Return MediaWiki id for a canonical namespace name. +# Ex.: "File", "Project". +sub get_mw_namespace_id { + mw_connect_maybe(); + my $name = shift; + + if (!exists $namespace_id{$name}) { + # Look at configuration file, if the record for that namespace is + # already cached. Namespaces are stored in form: + # "Name_of_namespace:Id_namespace", ex.: "File:6". + my @temp = split(/[\n]/, run_git("config --get-all remote." + . $remotename .".namespaceCache")); + chomp(@temp); + foreach my $ns (@temp) { + my ($n, $id) = split(/:/, $ns); + if ($id eq 'notANameSpace') { + $namespace_id{$n} = {is_namespace => 0}; + } else { + $namespace_id{$n} = {is_namespace => 1, id => $id}; + } + $cached_mw_namespace_id{$n} = 1; + } + } + + if (!exists $namespace_id{$name}) { + print STDERR "Namespace $name not found in cache, querying the wiki ...\n"; + # NS not found => get namespace id from MW and store it in + # configuration file. + my $query = { + action => 'query', + meta => 'siteinfo', + siprop => 'namespaces' + }; + my $result = $mediawiki->api($query); + + while (my ($id, $ns) = each(%{$result->{query}->{namespaces}})) { + if (defined($ns->{id}) && defined($ns->{canonical})) { + $namespace_id{$ns->{canonical}} = {is_namespace => 1, id => $ns->{id}}; + if ($ns->{'*'}) { + # alias (e.g. french Fichier: as alias for canonical File:) + $namespace_id{$ns->{'*'}} = {is_namespace => 1, id => $ns->{id}}; + } + } + } + } + + my $ns = $namespace_id{$name}; + my $id; + + unless (defined $ns) { + print STDERR "No such namespace $name on MediaWiki.\n"; + $ns = {is_namespace => 0}; + $namespace_id{$name} = $ns; + } + + if ($ns->{is_namespace}) { + $id = $ns->{id}; + } + + # Store "notANameSpace" as special value for inexisting namespaces + my $store_id = ($id || 'notANameSpace'); + + # Store explicitely requested namespaces on disk + if (!exists $cached_mw_namespace_id{$name}) { + run_git("config --add remote.". $remotename + .".namespaceCache \"". $name .":". $store_id ."\""); + $cached_mw_namespace_id{$name} = 1; + } + return $id; +} + +sub get_mw_namespace_id_for_page { + if (my ($namespace) = $_[0] =~ /^([^:]*):/) { + return get_mw_namespace_id($namespace); + } else { + return; + } +} diff --git a/contrib/mw-to-git/t/.gitignore b/contrib/mw-to-git/t/.gitignore new file mode 100644 index 000000000..a7a40b496 --- /dev/null +++ b/contrib/mw-to-git/t/.gitignore @@ -0,0 +1,4 @@ +WEB/ +wiki/ +trash directory.t*/ +test-results/ diff --git a/contrib/mw-to-git/t/Makefile b/contrib/mw-to-git/t/Makefile new file mode 100644 index 000000000..f422203fa --- /dev/null +++ b/contrib/mw-to-git/t/Makefile @@ -0,0 +1,31 @@ +# +# Copyright (C) 2012 +# Charles Roussel <charles.roussel@ensimag.imag.fr> +# Simon Cathebras <simon.cathebras@ensimag.imag.fr> +# Julien Khayat <julien.khayat@ensimag.imag.fr> +# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr> +# Simon Perrat <simon.perrat@ensimag.imag.fr> +# +## Test git-remote-mediawiki + +all: test + +-include ../../../config.mak.autogen +-include ../../../config.mak + +T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) + +.PHONY: help test clean all + +help: + @echo 'Run "$(MAKE) test" to launch test scripts' + @echo 'Run "$(MAKE) clean" to remove trash folders' + +test: + @for t in $(T); do \ + echo "$$t"; \ + "./$$t" || exit 1; \ + done + +clean: + $(RM) -r 'trash directory'.* diff --git a/contrib/mw-to-git/t/README b/contrib/mw-to-git/t/README new file mode 100644 index 000000000..96e97390c --- /dev/null +++ b/contrib/mw-to-git/t/README @@ -0,0 +1,124 @@ +Tests for Mediawiki-to-Git +========================== + +Introduction +------------ +This manual describes how to install the git-remote-mediawiki test +environment on a machine with git installed on it. + +Prerequisite +------------ + +In order to run this test environment correctly, you will need to +install the following packages (Debian/Ubuntu names, may need to be +adapted for another distribution): + +* lighttpd +* php5 +* php5-cgi +* php5-cli +* php5-curl +* php5-sqlite + +Principles and Technical Choices +-------------------------------- + +The test environment makes it easy to install and manipulate one or +several MediaWiki instances. To allow developers to run the testsuite +easily, the environment does not require root priviledge (except to +install the required packages if needed). It starts a webserver +instance on the user's account (using lighttpd greatly helps for +that), and does not need a separate database daemon (thanks to the use +of sqlite). + +Run the test environment +------------------------ + +Install a new wiki +~~~~~~~~~~~~~~~~~~ + +Once you have all the prerequisite, you need to install a MediaWiki +instance on your machine. If you already have one, it is still +strongly recommended to install one with the script provided. Here's +how to work it: + +a. change directory to contrib/mw-to-git/t/ +b. if needed, edit test.config to choose your installation parameters +c. run `./install-wiki.sh install` +d. check on your favourite web browser if your wiki is correctly + installed. + +Remove an existing wiki +~~~~~~~~~~~~~~~~~~~~~~~ + +Edit the file test.config to fit the wiki you want to delete, and then +execute the command `./install-wiki.sh delete` from the +contrib/mw-to-git/t directory. + +Run the existing tests +~~~~~~~~~~~~~~~~~~~~~~ + +The provided tests are currently in the `contrib/mw-to-git/t` directory. +The files are all the t936[0-9]-*.sh shell scripts. + +a. Run all tests: +To do so, run "make test" from the contrib/mw-to-git/ directory. + +b. Run a specific test: +To run a given test <test_name>, run ./<test_name> from the +contrib/mw-to-git/t directory. + +How to create new tests +----------------------- + +Available functions +~~~~~~~~~~~~~~~~~~~ + +The test environment of git-remote-mediawiki provides some functions +useful to test its behaviour. for more details about the functions' +parameters, please refer to the `test-gitmw-lib.sh` and +`test-gitmw.pl` files. + +** `test_check_wiki_precond`: +Check if the tests must be skipped or not. Please use this function +at the beggining of each new test file. + +** `wiki_getpage`: +Fetch a given page from the wiki and puts its content in the +directory in parameter. + +** `wiki_delete_page`: +Delete a given page from the wiki. + +** `wiki_edit_page`: +Create or modify a given page in the wiki. You can specify several +parameters like a summary for the page edition, or add the page to a +given category. +See test-gitmw.pl for more details. + +** `wiki_getallpage`: +Fetch all pages from the wiki into a given directory. The directory +is created if it does not exists. + +** `test_diff_directories`: +Compare the content of two directories. The content must be the same. +Use this function to compare the content of a git directory and a wiki +one created by wiki_getallpage. + +** `test_contains_N_files`: +Check if the given directory contains a given number of file. + +** `wiki_page_exists`: +Tests if a given page exists on the wiki. + +** `wiki_reset`: +Reset the wiki, i.e. flush the database. Use this function at the +begining of each new test, except if the test re-uses the same wiki +(and history) as the previous test. + +How to write a new test +~~~~~~~~~~~~~~~~~~~~~~~ + +Please, follow the standards given by git. See git/t/README. +New file should be named as t936[0-9]-*.sh. +Be sure to reset your wiki regulary with the function `wiki_reset`. diff --git a/contrib/mw-to-git/t/install-wiki.sh b/contrib/mw-to-git/t/install-wiki.sh new file mode 100755 index 000000000..c6d6fa3ae --- /dev/null +++ b/contrib/mw-to-git/t/install-wiki.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +# This script installs or deletes a MediaWiki on your computer. +# It requires a web server with PHP and SQLite running. In addition, if you +# do not have MediaWiki sources on your computer, the option 'install' +# downloads them for you. +# Please set the CONFIGURATION VARIABLES in ./test-gitmw-lib.sh + +WIKI_TEST_DIR=$(cd "$(dirname "$0")" && pwd) + +if test -z "$WIKI_TEST_DIR" +then + WIKI_TEST_DIR=. +fi + +. "$WIKI_TEST_DIR"/test-gitmw-lib.sh +usage () { + echo "Usage: " + echo " ./install-wiki.sh <install | delete | --help>" + echo " install | -i : Install a wiki on your computer." + echo " delete | -d : Delete the wiki and all its pages and " + echo " content." +} + + +# Argument: install, delete, --help | -h +case "$1" in + "install" | "-i") + wiki_install + exit 0 + ;; + "delete" | "-d") + wiki_delete + exit 0 + ;; + "--help" | "-h") + usage + exit 0 + ;; + *) + echo "Invalid argument: $1" + usage + exit 1 + ;; +esac diff --git a/contrib/mw-to-git/t/install-wiki/.gitignore b/contrib/mw-to-git/t/install-wiki/.gitignore new file mode 100644 index 000000000..b5a2a4408 --- /dev/null +++ b/contrib/mw-to-git/t/install-wiki/.gitignore @@ -0,0 +1 @@ +wikidb.sqlite diff --git a/contrib/mw-to-git/t/install-wiki/LocalSettings.php b/contrib/mw-to-git/t/install-wiki/LocalSettings.php new file mode 100644 index 000000000..29f125116 --- /dev/null +++ b/contrib/mw-to-git/t/install-wiki/LocalSettings.php @@ -0,0 +1,129 @@ +<?php +# This file was automatically generated by the MediaWiki 1.19.0 +# installer. If you make manual changes, please keep track in case you +# need to recreate them later. +# +# See includes/DefaultSettings.php for all configurable settings +# and their default values, but don't forget to make changes in _this_ +# file, not there. +# +# Further documentation for configuration settings may be found at: +# http://www.mediawiki.org/wiki/Manual:Configuration_settings + +# Protect against web entry +if ( !defined( 'MEDIAWIKI' ) ) { + exit; +} + +## Uncomment this to disable output compression +# $wgDisableOutputCompression = true; + +$wgSitename = "Git-MediaWiki-Test"; +$wgMetaNamespace = "Git-MediaWiki-Test"; + +## The URL base path to the directory containing the wiki; +## defaults for all runtime URL paths are based off of this. +## For more information on customizing the URLs please see: +## http://www.mediawiki.org/wiki/Manual:Short_URL +$wgScriptPath = "@WG_SCRIPT_PATH@"; +$wgScriptExtension = ".php"; + +## The protocol and server name to use in fully-qualified URLs +$wgServer = "@WG_SERVER@"; + +## The relative URL path to the skins directory +$wgStylePath = "$wgScriptPath/skins"; + +## The relative URL path to the logo. Make sure you change this from the default, +## or else you'll overwrite your logo when you upgrade! +$wgLogo = "$wgStylePath/common/images/wiki.png"; + +## UPO means: this is also a user preference option + +$wgEnableEmail = true; +$wgEnableUserEmail = true; # UPO + +$wgEmergencyContact = "apache@localhost"; +$wgPasswordSender = "apache@localhost"; + +$wgEnotifUserTalk = false; # UPO +$wgEnotifWatchlist = false; # UPO +$wgEmailAuthentication = true; + +## Database settings +$wgDBtype = "sqlite"; +$wgDBserver = ""; +$wgDBname = "@WG_SQLITE_DATAFILE@"; +$wgDBuser = ""; +$wgDBpassword = ""; + +# SQLite-specific settings +$wgSQLiteDataDir = "@WG_SQLITE_DATADIR@"; + + +## Shared memory settings +$wgMainCacheType = CACHE_NONE; +$wgMemCachedServers = array(); + +## To enable image uploads, make sure the 'images' directory +## is writable, then set this to true: +$wgEnableUploads = true; +$wgUseImageMagick = true; +$wgImageMagickConvertCommand ="@CONVERT@"; +$wgFileExtensions[] = 'txt'; + +# InstantCommons allows wiki to use images from http://commons.wikimedia.org +$wgUseInstantCommons = false; + +## If you use ImageMagick (or any other shell command) on a +## Linux server, this will need to be set to the name of an +## available UTF-8 locale +$wgShellLocale = "en_US.utf8"; + +## If you want to use image uploads under safe mode, +## create the directories images/archive, images/thumb and +## images/temp, and make them all writable. Then uncomment +## this, if it's not already uncommented: +#$wgHashedUploadDirectory = false; + +## Set $wgCacheDirectory to a writable directory on the web server +## to make your wiki go slightly faster. The directory should not +## be publically accessible from the web. +#$wgCacheDirectory = "$IP/cache"; + +# Site language code, should be one of the list in ./languages/Names.php +$wgLanguageCode = "en"; + +$wgSecretKey = "1c912bfe3519fb70f5dc523ecc698111cd43d81a11c585b3eefb28f29c2699b7"; +#$wgSecretKey = "@SECRETKEY@"; + + +# Site upgrade key. Must be set to a string (default provided) to turn on the +# web installer while LocalSettings.php is in place +$wgUpgradeKey = "ddae7dc87cd0a645"; + +## Default skin: you can change the default skin. Use the internal symbolic +## names, ie 'standard', 'nostalgia', 'cologneblue', 'monobook', 'vector': +$wgDefaultSkin = "vector"; + +## For attaching licensing metadata to pages, and displaying an +## appropriate copyright notice / icon. GNU Free Documentation +## License and Creative Commons licenses are supported so far. +$wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright +$wgRightsUrl = ""; +$wgRightsText = ""; +$wgRightsIcon = ""; + +# Path to the GNU diff3 utility. Used for conflict resolution. +$wgDiff3 = "/usr/bin/diff3"; + +# Query string length limit for ResourceLoader. You should only set this if +# your web server has a query string length limit (then set it to that limit), +# or if you have suhosin.get.max_value_length set in php.ini (then set it to +# that value) +$wgResourceLoaderMaxQueryLength = -1; + + + +# End of automatically generated settings. +# Add more configuration options below. diff --git a/contrib/mw-to-git/t/install-wiki/db_install.php b/contrib/mw-to-git/t/install-wiki/db_install.php new file mode 100644 index 000000000..0f3f4e018 --- /dev/null +++ b/contrib/mw-to-git/t/install-wiki/db_install.php @@ -0,0 +1,120 @@ +<?php +/** + * This script generates a SQLite database for a MediaWiki version 1.19.0 + * You must specify the login of the admin (argument 1) and its + * password (argument 2) and the folder where the database file + * is located (absolute path in argument 3). + * It is used by the script install-wiki.sh in order to make easy the + * installation of a MediaWiki. + * + * In order to generate a SQLite database file, MediaWiki ask the user + * to submit some forms in its web browser. This script simulates this + * behavior though the functions <get> and <submit> + * + */ +$argc = $_SERVER['argc']; +$argv = $_SERVER['argv']; + +$login = $argv[2]; +$pass = $argv[3]; +$tmp = $argv[4]; +$port = $argv[5]; + +$url = 'http://localhost:'.$port.'/wiki/mw-config/index.php'; +$db_dir = urlencode($tmp); +$tmp_cookie = tempnam($tmp, "COOKIE_"); +/* + * Fetchs a page with cURL. + */ +function get($page_name = "") { + $curl = curl_init(); + $page_name_add = ""; + if ($page_name != "") { + $page_name_add = '?page='.$page_name; + } + $url = $GLOBALS['url'].$page_name_add; + $tmp_cookie = $GLOBALS['tmp_cookie']; + curl_setopt($curl, CURLOPT_COOKIEJAR, $tmp_cookie); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_COOKIEFILE, $tmp_cookie); + curl_setopt($curl, CURLOPT_HEADER, true); + curl_setopt($curl, CURLOPT_URL, $url); + + $page = curl_exec($curl); + if (!$page) { + die("Could not get page: $url\n"); + } + curl_close($curl); + return $page; +} + +/* + * Submits a form with cURL. + */ +function submit($page_name, $option = "") { + $curl = curl_init(); + $datapost = 'submit-continue=Continue+%E2%86%92'; + if ($option != "") { + $datapost = $option.'&'.$datapost; + } + $url = $GLOBALS['url'].'?page='.$page_name; + $tmp_cookie = $GLOBALS['tmp_cookie']; + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, $datapost); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_COOKIEJAR, $tmp_cookie); + curl_setopt($curl, CURLOPT_COOKIEFILE, $tmp_cookie); + + $page = curl_exec($curl); + if (!$page) { + die("Could not get page: $url\n"); + } + curl_close($curl); + return "$page"; +} + +/* + * Here starts this script: simulates the behavior of the user + * submitting forms to generates the database file. + * Note this simulation was made for the MediaWiki version 1.19.0, + * we can't assume it works with other versions. + * + */ + +$page = get(); +if (!preg_match('/input type="hidden" value="([0-9]+)" name="LanguageRequestTime"/', + $page, $matches)) { + echo "Unexpected content for page downloaded:\n"; + echo "$page"; + die; +}; +$timestamp = $matches[1]; +$language = "LanguageRequestTime=$timestamp&uselang=en&ContLang=en"; +$page = submit('Language', $language); + +submit('Welcome'); + +$db_config = 'DBType=sqlite'; +$db_config = $db_config.'&sqlite_wgSQLiteDataDir='.$db_dir; +$db_config = $db_config.'&sqlite_wgDBname='.$argv[1]; +submit('DBConnect', $db_config); + +$wiki_config = 'config_wgSitename=TEST'; +$wiki_config = $wiki_config.'&config__NamespaceType=site-name'; +$wiki_config = $wiki_config.'&config_wgMetaNamespace=MyWiki'; +$wiki_config = $wiki_config.'&config__AdminName='.$login; + +$wiki_config = $wiki_config.'&config__AdminPassword='.$pass; +$wiki_config = $wiki_config.'&config__AdminPassword2='.$pass; + +$wiki_config = $wiki_config.'&wiki__configEmail=email%40email.org'; +$wiki_config = $wiki_config.'&config__SkipOptional=skip'; +submit('Name', $wiki_config); +submit('Install'); +submit('Install'); + +unlink($tmp_cookie); +?> diff --git a/contrib/mw-to-git/t/push-pull-tests.sh b/contrib/mw-to-git/t/push-pull-tests.sh new file mode 100644 index 000000000..9da2dc5ff --- /dev/null +++ b/contrib/mw-to-git/t/push-pull-tests.sh @@ -0,0 +1,144 @@ +test_push_pull () { + + test_expect_success 'Git pull works after adding a new wiki page' ' + wiki_reset && + + git clone mediawiki::'"$WIKI_URL"' mw_dir_1 && + wiki_editpage Foo "page created after the git clone" false && + + ( + cd mw_dir_1 && + git pull + ) && + + wiki_getallpage ref_page_1 && + test_diff_directories mw_dir_1 ref_page_1 + ' + + test_expect_success 'Git pull works after editing a wiki page' ' + wiki_reset && + + wiki_editpage Foo "page created before the git clone" false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_2 && + wiki_editpage Foo "new line added on the wiki" true && + + ( + cd mw_dir_2 && + git pull + ) && + + wiki_getallpage ref_page_2 && + test_diff_directories mw_dir_2 ref_page_2 + ' + + test_expect_success 'git pull works on conflict handled by auto-merge' ' + wiki_reset && + + wiki_editpage Foo "1 init +3 +5 + " false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_3 && + + wiki_editpage Foo "1 init +2 content added on wiki after clone +3 +5 + " false && + + ( + cd mw_dir_3 && + echo "1 init +3 +4 content added on git after clone +5 +" >Foo.mw && + git commit -am "conflicting change on foo" && + git pull && + git push + ) + ' + + test_expect_success 'Git push works after adding a file .mw' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir_4 && + wiki_getallpage ref_page_4 && + ( + cd mw_dir_4 && + test_path_is_missing Foo.mw && + touch Foo.mw && + echo "hello world" >>Foo.mw && + git add Foo.mw && + git commit -m "Foo" && + git push + ) && + wiki_getallpage ref_page_4 && + test_diff_directories mw_dir_4 ref_page_4 + ' + + test_expect_success 'Git push works after editing a file .mw' ' + wiki_reset && + wiki_editpage "Foo" "page created before the git clone" false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_5 && + + ( + cd mw_dir_5 && + echo "new line added in the file Foo.mw" >>Foo.mw && + git commit -am "edit file Foo.mw" && + git push + ) && + + wiki_getallpage ref_page_5 && + test_diff_directories mw_dir_5 ref_page_5 + ' + + test_expect_failure 'Git push works after deleting a file' ' + wiki_reset && + wiki_editpage Foo "wiki page added before git clone" false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_6 && + + ( + cd mw_dir_6 && + git rm Foo.mw && + git commit -am "page Foo.mw deleted" && + git push + ) && + + test_must_fail wiki_page_exist Foo + ' + + test_expect_success 'Merge conflict expected and solving it' ' + wiki_reset && + + git clone mediawiki::'"$WIKI_URL"' mw_dir_7 && + wiki_editpage Foo "1 conflict +3 wiki +4" false && + + ( + cd mw_dir_7 && + echo "1 conflict +2 git +4" >Foo.mw && + git add Foo.mw && + git commit -m "conflict created" && + test_must_fail git pull && + "$PERL_PATH" -pi -e "s/[<=>].*//g" Foo.mw && + git commit -am "merge conflict solved" && + git push + ) + ' + + test_expect_failure 'git pull works after deleting a wiki page' ' + wiki_reset && + wiki_editpage Foo "wiki page added before the git clone" false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_8 && + + wiki_delete_page Foo && + ( + cd mw_dir_8 && + git pull && + test_path_is_missing Foo.mw + ) + ' +} diff --git a/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh new file mode 100755 index 000000000..811a90c9a --- /dev/null +++ b/contrib/mw-to-git/t/t9360-mw-to-git-clone.sh @@ -0,0 +1,257 @@ +#!/bin/sh +# +# Copyright (C) 2012 +# Charles Roussel <charles.roussel@ensimag.imag.fr> +# Simon Cathebras <simon.cathebras@ensimag.imag.fr> +# Julien Khayat <julien.khayat@ensimag.imag.fr> +# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr> +# Simon Perrat <simon.perrat@ensimag.imag.fr> +# +# License: GPL v2 or later + + +test_description='Test the Git Mediawiki remote helper: git clone' + +. ./test-gitmw-lib.sh +. $TEST_DIRECTORY/test-lib.sh + + +test_check_precond + + +test_expect_success 'Git clone creates the expected git log with one file' ' + wiki_reset && + wiki_editpage foo "this is not important" false -c cat -s "this must be the same" && + git clone mediawiki::'"$WIKI_URL"' mw_dir_1 && + ( + cd mw_dir_1 && + git log --format=%s HEAD^..HEAD >log.tmp + ) && + echo "this must be the same" >msg.tmp && + diff -b mw_dir_1/log.tmp msg.tmp +' + + +test_expect_success 'Git clone creates the expected git log with multiple files' ' + wiki_reset && + wiki_editpage daddy "this is not important" false -s="this must be the same" && + wiki_editpage daddy "neither is this" true -s="this must also be the same" && + wiki_editpage daddy "neither is this" true -s="same same same" && + wiki_editpage dj "dont care" false -s="identical" && + wiki_editpage dj "dont care either" true -s="identical too" && + git clone mediawiki::'"$WIKI_URL"' mw_dir_2 && + ( + cd mw_dir_2 && + git log --format=%s Daddy.mw >logDaddy.tmp && + git log --format=%s Dj.mw >logDj.tmp + ) && + echo "same same same" >msgDaddy.tmp && + echo "this must also be the same" >>msgDaddy.tmp && + echo "this must be the same" >>msgDaddy.tmp && + echo "identical too" >msgDj.tmp && + echo "identical" >>msgDj.tmp && + diff -b mw_dir_2/logDaddy.tmp msgDaddy.tmp && + diff -b mw_dir_2/logDj.tmp msgDj.tmp +' + + +test_expect_success 'Git clone creates only Main_Page.mw with an empty wiki' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir_3 && + test_contains_N_files mw_dir_3 1 && + test_path_is_file mw_dir_3/Main_Page.mw +' + +test_expect_success 'Git clone does not fetch a deleted page' ' + wiki_reset && + wiki_editpage foo "this page must be deleted before the clone" false && + wiki_delete_page foo && + git clone mediawiki::'"$WIKI_URL"' mw_dir_4 && + test_contains_N_files mw_dir_4 1 && + test_path_is_file mw_dir_4/Main_Page.mw && + test_path_is_missing mw_dir_4/Foo.mw +' + +test_expect_success 'Git clone works with page added' ' + wiki_reset && + wiki_editpage foo " I will be cloned" false && + wiki_editpage bar "I will be cloned" false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_5 && + wiki_getallpage ref_page_5 && + test_diff_directories mw_dir_5 ref_page_5 && + wiki_delete_page foo && + wiki_delete_page bar +' + +test_expect_success 'Git clone works with an edited page ' ' + wiki_reset && + wiki_editpage foo "this page will be edited" \ + false -s "first edition of page foo"&& + wiki_editpage foo "this page has been edited and must be on the clone " true && + git clone mediawiki::'"$WIKI_URL"' mw_dir_6 && + test_path_is_file mw_dir_6/Foo.mw && + test_path_is_file mw_dir_6/Main_Page.mw && + wiki_getallpage mw_dir_6/page_ref_6 && + test_diff_directories mw_dir_6 mw_dir_6/page_ref_6 && + ( + cd mw_dir_6 && + git log --format=%s HEAD^ Foo.mw > ../Foo.log + ) && + echo "first edition of page foo" > FooExpect.log && + diff FooExpect.log Foo.log +' + + +test_expect_success 'Git clone works with several pages and some deleted ' ' + wiki_reset && + wiki_editpage foo "this page will not be deleted" false && + wiki_editpage bar "I must not be erased" false && + wiki_editpage namnam "I will not be there at the end" false && + wiki_editpage nyancat "nyan nyan nyan delete me" false && + wiki_delete_page namnam && + wiki_delete_page nyancat && + git clone mediawiki::'"$WIKI_URL"' mw_dir_7 && + test_path_is_file mw_dir_7/Foo.mw && + test_path_is_file mw_dir_7/Bar.mw && + test_path_is_missing mw_dir_7/Namnam.mw && + test_path_is_missing mw_dir_7/Nyancat.mw && + wiki_getallpage mw_dir_7/page_ref_7 && + test_diff_directories mw_dir_7 mw_dir_7/page_ref_7 +' + + +test_expect_success 'Git clone works with one specific page cloned ' ' + wiki_reset && + wiki_editpage foo "I will not be cloned" false && + wiki_editpage bar "Do not clone me" false && + wiki_editpage namnam "I will be cloned :)" false -s="this log must stay" && + wiki_editpage nyancat "nyan nyan nyan you cant clone me" false && + git clone -c remote.origin.pages=namnam \ + mediawiki::'"$WIKI_URL"' mw_dir_8 && + test_contains_N_files mw_dir_8 1 && + test_path_is_file mw_dir_8/Namnam.mw && + test_path_is_missing mw_dir_8/Main_Page.mw && + ( + cd mw_dir_8 && + echo "this log must stay" >msg.tmp && + git log --format=%s >log.tmp && + diff -b msg.tmp log.tmp + ) && + wiki_check_content mw_dir_8/Namnam.mw Namnam +' + +test_expect_success 'Git clone works with multiple specific page cloned ' ' + wiki_reset && + wiki_editpage foo "I will be there" false && + wiki_editpage bar "I will not disapear" false && + wiki_editpage namnam "I be erased" false && + wiki_editpage nyancat "nyan nyan nyan you will not erase me" false && + wiki_delete_page namnam && + git clone -c remote.origin.pages="foo bar nyancat namnam" \ + mediawiki::'"$WIKI_URL"' mw_dir_9 && + test_contains_N_files mw_dir_9 3 && + test_path_is_missing mw_dir_9/Namnam.mw && + test_path_is_file mw_dir_9/Foo.mw && + test_path_is_file mw_dir_9/Nyancat.mw && + test_path_is_file mw_dir_9/Bar.mw && + wiki_check_content mw_dir_9/Foo.mw Foo && + wiki_check_content mw_dir_9/Bar.mw Bar && + wiki_check_content mw_dir_9/Nyancat.mw Nyancat +' + +test_expect_success 'Mediawiki-clone of several specific pages on wiki' ' + wiki_reset && + wiki_editpage foo "foo 1" false && + wiki_editpage bar "bar 1" false && + wiki_editpage dummy "dummy 1" false && + wiki_editpage cloned_1 "cloned_1 1" false && + wiki_editpage cloned_2 "cloned_2 2" false && + wiki_editpage cloned_3 "cloned_3 3" false && + mkdir -p ref_page_10 && + wiki_getpage cloned_1 ref_page_10 && + wiki_getpage cloned_2 ref_page_10 && + wiki_getpage cloned_3 ref_page_10 && + git clone -c remote.origin.pages="cloned_1 cloned_2 cloned_3" \ + mediawiki::'"$WIKI_URL"' mw_dir_10 && + test_diff_directories mw_dir_10 ref_page_10 +' + +test_expect_success 'Git clone works with the shallow option' ' + wiki_reset && + wiki_editpage foo "1st revision, should be cloned" false && + wiki_editpage bar "1st revision, should be cloned" false && + wiki_editpage nyan "1st revision, should not be cloned" false && + wiki_editpage nyan "2nd revision, should be cloned" false && + git -c remote.origin.shallow=true clone \ + mediawiki::'"$WIKI_URL"' mw_dir_11 && + test_contains_N_files mw_dir_11 4 && + test_path_is_file mw_dir_11/Nyan.mw && + test_path_is_file mw_dir_11/Foo.mw && + test_path_is_file mw_dir_11/Bar.mw && + test_path_is_file mw_dir_11/Main_Page.mw && + ( + cd mw_dir_11 && + test `git log --oneline Nyan.mw | wc -l` -eq 1 && + test `git log --oneline Foo.mw | wc -l` -eq 1 && + test `git log --oneline Bar.mw | wc -l` -eq 1 && + test `git log --oneline Main_Page.mw | wc -l ` -eq 1 + ) && + wiki_check_content mw_dir_11/Nyan.mw Nyan && + wiki_check_content mw_dir_11/Foo.mw Foo && + wiki_check_content mw_dir_11/Bar.mw Bar && + wiki_check_content mw_dir_11/Main_Page.mw Main_Page +' + +test_expect_success 'Git clone works with the shallow option with a delete page' ' + wiki_reset && + wiki_editpage foo "1st revision, will be deleted" false && + wiki_editpage bar "1st revision, should be cloned" false && + wiki_editpage nyan "1st revision, should not be cloned" false && + wiki_editpage nyan "2nd revision, should be cloned" false && + wiki_delete_page foo && + git -c remote.origin.shallow=true clone \ + mediawiki::'"$WIKI_URL"' mw_dir_12 && + test_contains_N_files mw_dir_12 3 && + test_path_is_file mw_dir_12/Nyan.mw && + test_path_is_missing mw_dir_12/Foo.mw && + test_path_is_file mw_dir_12/Bar.mw && + test_path_is_file mw_dir_12/Main_Page.mw && + ( + cd mw_dir_12 && + test `git log --oneline Nyan.mw | wc -l` -eq 1 && + test `git log --oneline Bar.mw | wc -l` -eq 1 && + test `git log --oneline Main_Page.mw | wc -l ` -eq 1 + ) && + wiki_check_content mw_dir_12/Nyan.mw Nyan && + wiki_check_content mw_dir_12/Bar.mw Bar && + wiki_check_content mw_dir_12/Main_Page.mw Main_Page +' + +test_expect_success 'Test of fetching a category' ' + wiki_reset && + wiki_editpage Foo "I will be cloned" false -c=Category && + wiki_editpage Bar "Meet me on the repository" false -c=Category && + wiki_editpage Dummy "I will not come" false && + wiki_editpage BarWrong "I will stay online only" false -c=NotCategory && + git clone -c remote.origin.categories="Category" \ + mediawiki::'"$WIKI_URL"' mw_dir_13 && + wiki_getallpage ref_page_13 Category && + test_diff_directories mw_dir_13 ref_page_13 +' + +test_expect_success 'Test of resistance to modification of category on wiki for clone' ' + wiki_reset && + wiki_editpage Tobedeleted "this page will be deleted" false -c=Catone && + wiki_editpage Tobeedited "this page will be modified" false -c=Catone && + wiki_editpage Normalone "this page wont be modified and will be on git" false -c=Catone && + wiki_editpage Notconsidered "this page will not appear on local" false && + wiki_editpage Othercategory "this page will not appear on local" false -c=Cattwo && + wiki_editpage Tobeedited "this page have been modified" true -c=Catone && + wiki_delete_page Tobedeleted + git clone -c remote.origin.categories="Catone" \ + mediawiki::'"$WIKI_URL"' mw_dir_14 && + wiki_getallpage ref_page_14 Catone && + test_diff_directories mw_dir_14 ref_page_14 +' + +test_done diff --git a/contrib/mw-to-git/t/t9361-mw-to-git-push-pull.sh b/contrib/mw-to-git/t/t9361-mw-to-git-push-pull.sh new file mode 100755 index 000000000..9ea201459 --- /dev/null +++ b/contrib/mw-to-git/t/t9361-mw-to-git-push-pull.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# +# Copyright (C) 2012 +# Charles Roussel <charles.roussel@ensimag.imag.fr> +# Simon Cathebras <simon.cathebras@ensimag.imag.fr> +# Julien Khayat <julien.khayat@ensimag.imag.fr> +# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr> +# Simon Perrat <simon.perrat@ensimag.imag.fr> +# +# License: GPL v2 or later + +# tests for git-remote-mediawiki + +test_description='Test the Git Mediawiki remote helper: git push and git pull simple test cases' + +. ./test-gitmw-lib.sh +. ./push-pull-tests.sh +. $TEST_DIRECTORY/test-lib.sh + +test_check_precond + +test_push_pull + +test_done diff --git a/contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh b/contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh new file mode 100755 index 000000000..b6405ce26 --- /dev/null +++ b/contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh @@ -0,0 +1,347 @@ +#!/bin/sh +# +# Copyright (C) 2012 +# Charles Roussel <charles.roussel@ensimag.imag.fr> +# Simon Cathebras <simon.cathebras@ensimag.imag.fr> +# Julien Khayat <julien.khayat@ensimag.imag.fr> +# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr> +# Simon Perrat <simon.perrat@ensimag.imag.fr> +# +# License: GPL v2 or later + +# tests for git-remote-mediawiki + +test_description='Test git-mediawiki with special characters in filenames' + +. ./test-gitmw-lib.sh +. $TEST_DIRECTORY/test-lib.sh + + +test_check_precond + + +test_expect_success 'Git clone works for a wiki with accents in the page names' ' + wiki_reset && + wiki_editpage féé "This page must be délétéd before clone" false && + wiki_editpage kèè "This page must be deleted before clone" false && + wiki_editpage hà à "This page must be deleted before clone" false && + wiki_editpage kîî "This page must be deleted before clone" false && + wiki_editpage foo "This page must be deleted before clone" false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_1 && + wiki_getallpage ref_page_1 && + test_diff_directories mw_dir_1 ref_page_1 +' + + +test_expect_success 'Git pull works with a wiki with accents in the pages names' ' + wiki_reset && + wiki_editpage kîî "this page must be cloned" false && + wiki_editpage foo "this page must be cloned" false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_2 && + wiki_editpage éà îôû "This page must be pulled" false && + ( + cd mw_dir_2 && + git pull + ) && + wiki_getallpage ref_page_2 && + test_diff_directories mw_dir_2 ref_page_2 +' + + +test_expect_success 'Cloning a chosen page works with accents' ' + wiki_reset && + wiki_editpage kîî "this page must be cloned" false && + git clone -c remote.origin.pages=kîî \ + mediawiki::'"$WIKI_URL"' mw_dir_3 && + wiki_check_content mw_dir_3/Kîî.mw Kîî && + test_path_is_file mw_dir_3/Kîî.mw && + rm -rf mw_dir_3 +' + + +test_expect_success 'The shallow option works with accents' ' + wiki_reset && + wiki_editpage néoà "1st revision, should not be cloned" false && + wiki_editpage néoà "2nd revision, should be cloned" false && + git -c remote.origin.shallow=true clone \ + mediawiki::'"$WIKI_URL"' mw_dir_4 && + test_contains_N_files mw_dir_4 2 && + test_path_is_file mw_dir_4/Néoà .mw && + test_path_is_file mw_dir_4/Main_Page.mw && + ( + cd mw_dir_4 && + test `git log --oneline Néoà .mw | wc -l` -eq 1 && + test `git log --oneline Main_Page.mw | wc -l ` -eq 1 + ) && + wiki_check_content mw_dir_4/Néoà .mw Néoà && + wiki_check_content mw_dir_4/Main_Page.mw Main_Page +' + + +test_expect_success 'Cloning works when page name first letter has an accent' ' + wiki_reset && + wiki_editpage îî "this page must be cloned" false && + git clone -c remote.origin.pages=îî \ + mediawiki::'"$WIKI_URL"' mw_dir_5 && + test_path_is_file mw_dir_5/Îî.mw && + wiki_check_content mw_dir_5/Îî.mw Îî +' + + +test_expect_success 'Git push works with a wiki with accents' ' + wiki_reset && + wiki_editpage féé "lots of accents : éèà Ö" false && + wiki_editpage foo "this page must be cloned" false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_6 && + ( + cd mw_dir_6 && + echo "A wild Pîkächû appears on the wiki" >Pîkächû.mw && + git add Pîkächû.mw && + git commit -m "A new page appears" && + git push + ) && + wiki_getallpage ref_page_6 && + test_diff_directories mw_dir_6 ref_page_6 +' + +test_expect_success 'Git clone works with accentsand spaces' ' + wiki_reset && + wiki_editpage "é à î" "this page must be délété before the clone" false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_7 && + wiki_getallpage ref_page_7 && + test_diff_directories mw_dir_7 ref_page_7 +' + +test_expect_success 'character $ in page name (mw -> git)' ' + wiki_reset && + wiki_editpage file_\$_foo "expect to be called file_$_foo" false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_8 && + test_path_is_file mw_dir_8/File_\$_foo.mw && + wiki_getallpage ref_page_8 && + test_diff_directories mw_dir_8 ref_page_8 +' + + + +test_expect_success 'character $ in file name (git -> mw) ' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir_9 && + ( + cd mw_dir_9 && + echo "this file is called File_\$_foo.mw" >File_\$_foo.mw && + git add . && + git commit -am "file File_\$_foo.mw" && + git pull && + git push + ) && + wiki_getallpage ref_page_9 && + test_diff_directories mw_dir_9 ref_page_9 +' + + +test_expect_failure 'capital at the begining of file names' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir_10 && + ( + cd mw_dir_10 && + echo "my new file foo" >foo.mw && + echo "my new file Foo... Finger crossed" >Foo.mw && + git add . && + git commit -am "file foo.mw" && + git pull && + git push + ) && + wiki_getallpage ref_page_10 && + test_diff_directories mw_dir_10 ref_page_10 +' + + +test_expect_failure 'special character at the begining of file name from mw to git' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir_11 && + wiki_editpage {char_1 "expect to be renamed {char_1" false && + wiki_editpage [char_2 "expect to be renamed [char_2" false && + ( + cd mw_dir_11 && + git pull + ) && + test_path_is_file mw_dir_11/{char_1 && + test_path_is_file mw_dir_11/[char_2 +' + +test_expect_success 'Pull page with title containing ":" other than namespace separator' ' + wiki_editpage Foo:Bar content false && + ( + cd mw_dir_11 && + git pull + ) && + test_path_is_file mw_dir_11/Foo:Bar.mw +' + +test_expect_success 'Push page with title containing ":" other than namespace separator' ' + ( + cd mw_dir_11 && + echo content >NotANameSpace:Page.mw && + git add NotANameSpace:Page.mw && + git commit -m "add page with colon" && + git push + ) && + wiki_page_exist NotANameSpace:Page +' + +test_expect_success 'test of correct formating for file name from mw to git' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir_12 && + wiki_editpage char_%_7b_1 "expect to be renamed char{_1" false && + wiki_editpage char_%_5b_2 "expect to be renamed char{_2" false && + ( + cd mw_dir_12 && + git pull + ) && + test_path_is_file mw_dir_12/Char\{_1.mw && + test_path_is_file mw_dir_12/Char\[_2.mw && + wiki_getallpage ref_page_12 && + mv ref_page_12/Char_%_7b_1.mw ref_page_12/Char\{_1.mw && + mv ref_page_12/Char_%_5b_2.mw ref_page_12/Char\[_2.mw && + test_diff_directories mw_dir_12 ref_page_12 +' + + +test_expect_failure 'test of correct formating for file name begining with special character' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir_13 && + ( + cd mw_dir_13 && + echo "my new file {char_1" >\{char_1.mw && + echo "my new file [char_2" >\[char_2.mw && + git add . && + git commit -am "commiting some exotic file name..." && + git push && + git pull + ) && + wiki_getallpage ref_page_13 && + test_path_is_file ref_page_13/{char_1.mw && + test_path_is_file ref_page_13/[char_2.mw && + test_diff_directories mw_dir_13 ref_page_13 +' + + +test_expect_success 'test of correct formating for file name from git to mw' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir_14 && + ( + cd mw_dir_14 && + echo "my new file char{_1" >Char\{_1.mw && + echo "my new file char[_2" >Char\[_2.mw && + git add . && + git commit -m "commiting some exotic file name..." && + git push + ) && + wiki_getallpage ref_page_14 && + mv mw_dir_14/Char\{_1.mw mw_dir_14/Char_%_7b_1.mw && + mv mw_dir_14/Char\[_2.mw mw_dir_14/Char_%_5b_2.mw && + test_diff_directories mw_dir_14 ref_page_14 +' + + +test_expect_success 'git clone with /' ' + wiki_reset && + wiki_editpage \/fo\/o "this is not important" false -c=Deleted && + git clone mediawiki::'"$WIKI_URL"' mw_dir_15 && + test_path_is_file mw_dir_15/%2Ffo%2Fo.mw && + wiki_check_content mw_dir_15/%2Ffo%2Fo.mw \/fo\/o +' + + +test_expect_success 'git push with /' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir_16 && + echo "I will be on the wiki" >mw_dir_16/%2Ffo%2Fo.mw && + ( + cd mw_dir_16 && + git add %2Ffo%2Fo.mw && + git commit -m " %2Ffo%2Fo added" && + git push + ) && + wiki_page_exist \/fo\/o && + wiki_check_content mw_dir_16/%2Ffo%2Fo.mw \/fo\/o + +' + + +test_expect_success 'git clone with \' ' + wiki_reset && + wiki_editpage \\ko\\o "this is not important" false -c=Deleted && + git clone mediawiki::'"$WIKI_URL"' mw_dir_17 && + test_path_is_file mw_dir_17/\\ko\\o.mw && + wiki_check_content mw_dir_17/\\ko\\o.mw \\ko\\o +' + + +test_expect_success 'git push with \' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir_18 && + echo "I will be on the wiki" >mw_dir_18/\\ko\\o.mw && + ( + cd mw_dir_18 && + git add \\ko\\o.mw && + git commit -m " \\ko\\o added" && + git push + )&& + wiki_page_exist \\ko\\o && + wiki_check_content mw_dir_18/\\ko\\o.mw \\ko\\o + +' + +test_expect_success 'git clone with \ in format control' ' + wiki_reset && + wiki_editpage \\no\\o "this is not important" false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_19 && + test_path_is_file mw_dir_19/\\no\\o.mw && + wiki_check_content mw_dir_19/\\no\\o.mw \\no\\o +' + + +test_expect_success 'git push with \ in format control' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir_20 && + echo "I will be on the wiki" >mw_dir_20/\\fo\\o.mw && + ( + cd mw_dir_20 && + git add \\fo\\o.mw && + git commit -m " \\fo\\o added" && + git push + )&& + wiki_page_exist \\fo\\o && + wiki_check_content mw_dir_20/\\fo\\o.mw \\fo\\o + +' + + +test_expect_success 'fast-import meta-characters in page name (mw -> git)' ' + wiki_reset && + wiki_editpage \"file\"_\\_foo "expect to be called \"file\"_\\_foo" false && + git clone mediawiki::'"$WIKI_URL"' mw_dir_21 && + test_path_is_file mw_dir_21/\"file\"_\\_foo.mw && + wiki_getallpage ref_page_21 && + test_diff_directories mw_dir_21 ref_page_21 +' + + +test_expect_success 'fast-import meta-characters in page name (git -> mw) ' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir_22 && + ( + cd mw_dir_22 && + echo "this file is called \"file\"_\\_foo.mw" >\"file\"_\\_foo && + git add . && + git commit -am "file \"file\"_\\_foo" && + git pull && + git push + ) && + wiki_getallpage ref_page_22 && + test_diff_directories mw_dir_22 ref_page_22 +' + + +test_done diff --git a/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh b/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh new file mode 100755 index 000000000..5a0373935 --- /dev/null +++ b/contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh @@ -0,0 +1,198 @@ +#!/bin/sh +# +# Copyright (C) 2012 +# Charles Roussel <charles.roussel@ensimag.imag.fr> +# Simon Cathebras <simon.cathebras@ensimag.imag.fr> +# Julien Khayat <julien.khayat@ensimag.imag.fr> +# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr> +# Simon Perrat <simon.perrat@ensimag.imag.fr> +# +# License: GPL v2 or later + +# tests for git-remote-mediawiki + +test_description='Test the Git Mediawiki remote helper: git push and git pull simple test cases' + +. ./test-gitmw-lib.sh +. $TEST_DIRECTORY/test-lib.sh + + +test_check_precond + + +test_git_reimport () { + git -c remote.origin.dumbPush=true push && + git -c remote.origin.mediaImport=true pull --rebase +} + +# Don't bother with permissions, be administrator by default +test_expect_success 'setup config' ' + git config --global remote.origin.mwLogin WikiAdmin && + git config --global remote.origin.mwPassword AdminPass && + test_might_fail git config --global --unset remote.origin.mediaImport +' + +test_expect_success 'git push can upload media (File:) files' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir && + ( + cd mw_dir && + echo "hello world" >Foo.txt && + git add Foo.txt && + git commit -m "add a text file" && + git push && + "$PERL_PATH" -e "print STDOUT \"binary content: \".chr(255);" >Foo.txt && + git add Foo.txt && + git commit -m "add a text file with binary content" && + git push + ) +' + +test_expect_success 'git clone works on previously created wiki with media files' ' + test_when_finished "rm -rf mw_dir mw_dir_clone" && + git clone -c remote.origin.mediaimport=true \ + mediawiki::'"$WIKI_URL"' mw_dir_clone && + test_cmp mw_dir_clone/Foo.txt mw_dir/Foo.txt && + (cd mw_dir_clone && git checkout HEAD^) && + (cd mw_dir && git checkout HEAD^) && + test_cmp mw_dir_clone/Foo.txt mw_dir/Foo.txt +' + +test_expect_success 'git push & pull work with locally renamed media files' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir && + test_when_finished "rm -fr mw_dir" && + ( + cd mw_dir && + echo "A File" >Foo.txt && + git add Foo.txt && + git commit -m "add a file" && + git mv Foo.txt Bar.txt && + git commit -m "Rename a file" && + test_git_reimport && + echo "A File" >expect && + test_cmp expect Bar.txt && + test_path_is_missing Foo.txt + ) +' + +test_expect_success 'git push can propagate local page deletion' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir && + test_when_finished "rm -fr mw_dir" && + ( + cd mw_dir && + test_path_is_missing Foo.mw && + echo "hello world" >Foo.mw && + git add Foo.mw && + git commit -m "Add the page Foo" && + git push && + rm -f Foo.mw && + git commit -am "Delete the page Foo" && + test_git_reimport && + test_path_is_missing Foo.mw + ) +' + +test_expect_success 'git push can propagate local media file deletion' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir && + test_when_finished "rm -fr mw_dir" && + ( + cd mw_dir && + echo "hello world" >Foo.txt && + git add Foo.txt && + git commit -m "Add the text file Foo" && + git rm Foo.txt && + git commit -m "Delete the file Foo" && + test_git_reimport && + test_path_is_missing Foo.txt + ) +' + +# test failure: the file is correctly uploaded, and then deleted but +# as no page link to it, the import (which looks at page revisions) +# doesn't notice the file deletion on the wiki. We fetch the list of +# files from the wiki, but as the file is deleted, it doesn't appear. +test_expect_failure 'git pull correctly imports media file deletion when no page link to it' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir && + test_when_finished "rm -fr mw_dir" && + ( + cd mw_dir && + echo "hello world" >Foo.txt && + git add Foo.txt && + git commit -m "Add the text file Foo" && + git push && + git rm Foo.txt && + git commit -m "Delete the file Foo" && + test_git_reimport && + test_path_is_missing Foo.txt + ) +' + +test_expect_success 'git push properly warns about insufficient permissions' ' + wiki_reset && + git clone mediawiki::'"$WIKI_URL"' mw_dir && + test_when_finished "rm -fr mw_dir" && + ( + cd mw_dir && + echo "A File" >foo.forbidden && + git add foo.forbidden && + git commit -m "add a file" && + git push 2>actual && + test_i18ngrep "foo.forbidden is not a permitted file" actual + ) +' + +test_expect_success 'setup a repository with media files' ' + wiki_reset && + wiki_editpage testpage "I am linking a file [[File:File.txt]]" false && + echo "File content" >File.txt && + wiki_upload_file File.txt && + echo "Another file content" >AnotherFile.txt && + wiki_upload_file AnotherFile.txt +' + +test_expect_success 'git clone works with one specific page cloned and mediaimport=true' ' + git clone -c remote.origin.pages=testpage \ + -c remote.origin.mediaimport=true \ + mediawiki::'"$WIKI_URL"' mw_dir_15 && + test_when_finished "rm -rf mw_dir_15" && + test_contains_N_files mw_dir_15 3 && + test_path_is_file mw_dir_15/Testpage.mw && + test_path_is_file mw_dir_15/File:File.txt.mw && + test_path_is_file mw_dir_15/File.txt && + test_path_is_missing mw_dir_15/Main_Page.mw && + test_path_is_missing mw_dir_15/File:AnotherFile.txt.mw && + test_path_is_missing mw_dir_15/AnothetFile.txt && + wiki_check_content mw_dir_15/Testpage.mw Testpage && + test_cmp mw_dir_15/File.txt File.txt +' + +test_expect_success 'git clone works with one specific page cloned and mediaimport=false' ' + test_when_finished "rm -rf mw_dir_16" && + git clone -c remote.origin.pages=testpage \ + mediawiki::'"$WIKI_URL"' mw_dir_16 && + test_contains_N_files mw_dir_16 1 && + test_path_is_file mw_dir_16/Testpage.mw && + test_path_is_missing mw_dir_16/File:File.txt.mw && + test_path_is_missing mw_dir_16/File.txt && + test_path_is_missing mw_dir_16/Main_Page.mw && + wiki_check_content mw_dir_16/Testpage.mw Testpage +' + +# should behave like mediaimport=false +test_expect_success 'git clone works with one specific page cloned and mediaimport unset' ' + test_when_finished "rm -fr mw_dir_17" && + git clone -c remote.origin.pages=testpage \ + mediawiki::'"$WIKI_URL"' mw_dir_17 && + test_contains_N_files mw_dir_17 1 && + test_path_is_file mw_dir_17/Testpage.mw && + test_path_is_missing mw_dir_17/File:File.txt.mw && + test_path_is_missing mw_dir_17/File.txt && + test_path_is_missing mw_dir_17/Main_Page.mw && + wiki_check_content mw_dir_17/Testpage.mw Testpage +' + +test_done diff --git a/contrib/mw-to-git/t/t9364-pull-by-rev.sh b/contrib/mw-to-git/t/t9364-pull-by-rev.sh new file mode 100755 index 000000000..5c22457a0 --- /dev/null +++ b/contrib/mw-to-git/t/t9364-pull-by-rev.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +test_description='Test the Git Mediawiki remote helper: git pull by revision' + +. ./test-gitmw-lib.sh +. ./push-pull-tests.sh +. $TEST_DIRECTORY/test-lib.sh + +test_check_precond + +test_expect_success 'configuration' ' + git config --global mediawiki.fetchStrategy by_rev +' + +test_push_pull + +test_done diff --git a/contrib/mw-to-git/t/test-gitmw-lib.sh b/contrib/mw-to-git/t/test-gitmw-lib.sh new file mode 100755 index 000000000..3b2cfacf5 --- /dev/null +++ b/contrib/mw-to-git/t/test-gitmw-lib.sh @@ -0,0 +1,435 @@ +# Copyright (C) 2012 +# Charles Roussel <charles.roussel@ensimag.imag.fr> +# Simon Cathebras <simon.cathebras@ensimag.imag.fr> +# Julien Khayat <julien.khayat@ensimag.imag.fr> +# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr> +# Simon Perrat <simon.perrat@ensimag.imag.fr> +# License: GPL v2 or later + +# +# CONFIGURATION VARIABLES +# You might want to change these ones +# + +. ./test.config + +WIKI_URL=http://"$SERVER_ADDR:$PORT/$WIKI_DIR_NAME" +CURR_DIR=$(pwd) +TEST_OUTPUT_DIRECTORY=$(pwd) +TEST_DIRECTORY="$CURR_DIR"/../../../t + +export TEST_OUTPUT_DIRECTORY TEST_DIRECTORY CURR_DIR + +if test "$LIGHTTPD" = "false" ; then + PORT=80 +else + WIKI_DIR_INST="$CURR_DIR/$WEB_WWW" +fi + +wiki_upload_file () { + "$CURR_DIR"/test-gitmw.pl upload_file "$@" +} + +wiki_getpage () { + "$CURR_DIR"/test-gitmw.pl get_page "$@" +} + +wiki_delete_page () { + "$CURR_DIR"/test-gitmw.pl delete_page "$@" +} + +wiki_editpage () { + "$CURR_DIR"/test-gitmw.pl edit_page "$@" +} + +die () { + die_with_status 1 "$@" +} + +die_with_status () { + status=$1 + shift + echo >&2 "$*" + exit "$status" +} + + +# Check the preconditions to run git-remote-mediawiki's tests +test_check_precond () { + if ! test_have_prereq PERL + then + skip_all='skipping gateway git-mw tests, perl not available' + test_done + fi + + if [ ! -f "$GIT_BUILD_DIR"/git-remote-mediawiki ]; + then + echo "No remote mediawiki for git found. Copying it in git" + echo "cp $GIT_BUILD_DIR/contrib/mw-to-git/git-remote-mediawiki $GIT_BUILD_DIR/" + ln -s "$GIT_BUILD_DIR"/contrib/mw-to-git/git-remote-mediawiki "$GIT_BUILD_DIR" + fi + + if [ ! -d "$WIKI_DIR_INST/$WIKI_DIR_NAME" ]; + then + skip_all='skipping gateway git-mw tests, no mediawiki found' + test_done + fi +} + +# test_diff_directories <dir_git> <dir_wiki> +# +# Compare the contents of directories <dir_git> and <dir_wiki> with diff +# and errors if they do not match. The program will +# not look into .git in the process. +# Warning: the first argument MUST be the directory containing the git data +test_diff_directories () { + rm -rf "$1_tmp" + mkdir -p "$1_tmp" + cp "$1"/*.mw "$1_tmp" + diff -r -b "$1_tmp" "$2" +} + +# $1=<dir> +# $2=<N> +# +# Check that <dir> contains exactly <N> files +test_contains_N_files () { + if test `ls -- "$1" | wc -l` -ne "$2"; then + echo "directory $1 sould contain $2 files" + echo "it contains these files:" + ls "$1" + false + fi +} + + +# wiki_check_content <file_name> <page_name> +# +# Compares the contents of the file <file_name> and the wiki page +# <page_name> and exits with error 1 if they do not match. +wiki_check_content () { + mkdir -p wiki_tmp + wiki_getpage "$2" wiki_tmp + # replacement of forbidden character in file name + page_name=$(printf "%s\n" "$2" | sed -e "s/\//%2F/g") + + diff -b "$1" wiki_tmp/"$page_name".mw + if test $? -ne 0 + then + rm -rf wiki_tmp + error "ERROR: file $2 not found on wiki" + fi + rm -rf wiki_tmp +} + +# wiki_page_exist <page_name> +# +# Check the existence of the page <page_name> on the wiki and exits +# with error if it is absent from it. +wiki_page_exist () { + mkdir -p wiki_tmp + wiki_getpage "$1" wiki_tmp + page_name=$(printf "%s\n" "$1" | sed "s/\//%2F/g") + if test -f wiki_tmp/"$page_name".mw ; then + rm -rf wiki_tmp + else + rm -rf wiki_tmp + error "test failed: file $1 not found on wiki" + fi +} + +# wiki_getallpagename +# +# Fetch the name of each page on the wiki. +wiki_getallpagename () { + "$CURR_DIR"/test-gitmw.pl getallpagename +} + +# wiki_getallpagecategory <category> +# +# Fetch the name of each page belonging to <category> on the wiki. +wiki_getallpagecategory () { + "$CURR_DIR"/test-gitmw.pl getallpagename "$@" +} + +# wiki_getallpage <dest_dir> [<category>] +# +# Fetch all the pages from the wiki and place them in the directory +# <dest_dir>. +# If <category> is define, then wiki_getallpage fetch the pages included +# in <category>. +wiki_getallpage () { + if test -z "$2"; + then + wiki_getallpagename + else + wiki_getallpagecategory "$2" + fi + mkdir -p "$1" + while read -r line; do + wiki_getpage "$line" $1; + done < all.txt +} + +# ================= Install part ================= + +error () { + echo "$@" >&2 + exit 1 +} + +# config_lighttpd +# +# Create the configuration files and the folders necessary to start lighttpd. +# Overwrite any existing file. +config_lighttpd () { + mkdir -p $WEB + mkdir -p $WEB_TMP + mkdir -p $WEB_WWW + cat > $WEB/lighttpd.conf <<EOF + server.document-root = "$CURR_DIR/$WEB_WWW" + server.port = $PORT + server.pid-file = "$CURR_DIR/$WEB_TMP/pid" + + server.modules = ( + "mod_rewrite", + "mod_redirect", + "mod_access", + "mod_accesslog", + "mod_fastcgi" + ) + + index-file.names = ("index.php" , "index.html") + + mimetype.assign = ( + ".pdf" => "application/pdf", + ".sig" => "application/pgp-signature", + ".spl" => "application/futuresplash", + ".class" => "application/octet-stream", + ".ps" => "application/postscript", + ".torrent" => "application/x-bittorrent", + ".dvi" => "application/x-dvi", + ".gz" => "application/x-gzip", + ".pac" => "application/x-ns-proxy-autoconfig", + ".swf" => "application/x-shockwave-flash", + ".tar.gz" => "application/x-tgz", + ".tgz" => "application/x-tgz", + ".tar" => "application/x-tar", + ".zip" => "application/zip", + ".mp3" => "audio/mpeg", + ".m3u" => "audio/x-mpegurl", + ".wma" => "audio/x-ms-wma", + ".wax" => "audio/x-ms-wax", + ".ogg" => "application/ogg", + ".wav" => "audio/x-wav", + ".gif" => "image/gif", + ".jpg" => "image/jpeg", + ".jpeg" => "image/jpeg", + ".png" => "image/png", + ".xbm" => "image/x-xbitmap", + ".xpm" => "image/x-xpixmap", + ".xwd" => "image/x-xwindowdump", + ".css" => "text/css", + ".html" => "text/html", + ".htm" => "text/html", + ".js" => "text/javascript", + ".asc" => "text/plain", + ".c" => "text/plain", + ".cpp" => "text/plain", + ".log" => "text/plain", + ".conf" => "text/plain", + ".text" => "text/plain", + ".txt" => "text/plain", + ".dtd" => "text/xml", + ".xml" => "text/xml", + ".mpeg" => "video/mpeg", + ".mpg" => "video/mpeg", + ".mov" => "video/quicktime", + ".qt" => "video/quicktime", + ".avi" => "video/x-msvideo", + ".asf" => "video/x-ms-asf", + ".asx" => "video/x-ms-asf", + ".wmv" => "video/x-ms-wmv", + ".bz2" => "application/x-bzip", + ".tbz" => "application/x-bzip-compressed-tar", + ".tar.bz2" => "application/x-bzip-compressed-tar", + "" => "text/plain" + ) + + fastcgi.server = ( ".php" => + ("localhost" => + ( "socket" => "$CURR_DIR/$WEB_TMP/php.socket", + "bin-path" => "$PHP_DIR/php-cgi -c $CURR_DIR/$WEB/php.ini" + + ) + ) + ) +EOF + + cat > $WEB/php.ini <<EOF + session.save_path ='$CURR_DIR/$WEB_TMP' +EOF +} + +# start_lighttpd +# +# Start or restart daemon lighttpd. If restart, rewrite configuration files. +start_lighttpd () { + if test -f "$WEB_TMP/pid"; then + echo "Instance already running. Restarting..." + stop_lighttpd + fi + config_lighttpd + "$LIGHTTPD_DIR"/lighttpd -f "$WEB"/lighttpd.conf + + if test $? -ne 0 ; then + echo "Could not execute http deamon lighttpd" + exit 1 + fi +} + +# stop_lighttpd +# +# Kill daemon lighttpd and removes files and folders associated. +stop_lighttpd () { + test -f "$WEB_TMP/pid" && kill $(cat "$WEB_TMP/pid") + rm -rf "$WEB" +} + +# Create the SQLite database of the MediaWiki. If the database file already +# exists, it will be deleted. +# This script should be runned from the directory where $FILES_FOLDER is +# located. +create_db () { + rm -f "$TMP/$DB_FILE" + + echo "Generating the SQLite database file. It can take some time ..." + # Run the php script to generate the SQLite database file + # with cURL calls. + php "$FILES_FOLDER/$DB_INSTALL_SCRIPT" $(basename "$DB_FILE" .sqlite) \ + "$WIKI_ADMIN" "$WIKI_PASSW" "$TMP" "$PORT" + + if [ ! -f "$TMP/$DB_FILE" ] ; then + error "Can't create database file $TMP/$DB_FILE. Try to run ./install-wiki.sh delete first." + fi + + # Copy the generated database file into the directory the + # user indicated. + cp "$TMP/$DB_FILE" "$FILES_FOLDER" || + error "Unable to copy $TMP/$DB_FILE to $FILES_FOLDER" +} + +# Install a wiki in your web server directory. +wiki_install () { + if test $LIGHTTPD = "true" ; then + start_lighttpd + fi + + SERVER_ADDR=$SERVER_ADDR:$PORT + # In this part, we change directory to $TMP in order to download, + # unpack and copy the files of MediaWiki + ( + mkdir -p "$WIKI_DIR_INST/$WIKI_DIR_NAME" + if [ ! -d "$WIKI_DIR_INST/$WIKI_DIR_NAME" ] ; then + error "Folder $WIKI_DIR_INST/$WIKI_DIR_NAME doesn't exist. + Please create it and launch the script again." + fi + + # Fetch MediaWiki's archive if not already present in the TMP directory + cd "$TMP" + if [ ! -f "$MW_VERSION.tar.gz" ] ; then + echo "Downloading $MW_VERSION sources ..." + wget "http://download.wikimedia.org/mediawiki/1.19/mediawiki-1.19.0.tar.gz" || + error "Unable to download "\ + "http://download.wikimedia.org/mediawiki/1.19/"\ + "mediawiki-1.19.0.tar.gz. "\ + "Please fix your connection and launch the script again." + echo "$MW_VERSION.tar.gz downloaded in `pwd`. "\ + "You can delete it later if you want." + else + echo "Reusing existing $MW_VERSION.tar.gz downloaded in `pwd`." + fi + archive_abs_path=$(pwd)/"$MW_VERSION.tar.gz" + cd "$WIKI_DIR_INST/$WIKI_DIR_NAME/" || + error "can't cd to $WIKI_DIR_INST/$WIKI_DIR_NAME/" + tar xzf "$archive_abs_path" --strip-components=1 || + error "Unable to extract WikiMedia's files from $archive_abs_path to "\ + "$WIKI_DIR_INST/$WIKI_DIR_NAME" + ) || exit 1 + + create_db + + # Copy the generic LocalSettings.php in the web server's directory + # And modify parameters according to the ones set at the top + # of this script. + # Note that LocalSettings.php is never modified. + if [ ! -f "$FILES_FOLDER/LocalSettings.php" ] ; then + error "Can't find $FILES_FOLDER/LocalSettings.php " \ + "in the current folder. "\ + "Please run the script inside its folder." + fi + cp "$FILES_FOLDER/LocalSettings.php" \ + "$FILES_FOLDER/LocalSettings-tmp.php" || + error "Unable to copy $FILES_FOLDER/LocalSettings.php " \ + "to $FILES_FOLDER/LocalSettings-tmp.php" + + # Parse and set the LocalSettings file of the user according to the + # CONFIGURATION VARIABLES section at the beginning of this script + file_swap="$FILES_FOLDER/LocalSettings-swap.php" + sed "s,@WG_SCRIPT_PATH@,/$WIKI_DIR_NAME," \ + "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap" + mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php" + sed "s,@WG_SERVER@,http://$SERVER_ADDR," \ + "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap" + mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php" + sed "s,@WG_SQLITE_DATADIR@,$TMP," \ + "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap" + mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php" + sed "s,@WG_SQLITE_DATAFILE@,$( basename $DB_FILE .sqlite)," \ + "$FILES_FOLDER/LocalSettings-tmp.php" > "$file_swap" + mv "$file_swap" "$FILES_FOLDER/LocalSettings-tmp.php" + + mv "$FILES_FOLDER/LocalSettings-tmp.php" \ + "$WIKI_DIR_INST/$WIKI_DIR_NAME/LocalSettings.php" || + error "Unable to move $FILES_FOLDER/LocalSettings-tmp.php" \ + "in $WIKI_DIR_INST/$WIKI_DIR_NAME" + echo "File $FILES_FOLDER/LocalSettings.php is set in" \ + " $WIKI_DIR_INST/$WIKI_DIR_NAME" + + echo "Your wiki has been installed. You can check it at + http://$SERVER_ADDR/$WIKI_DIR_NAME" +} + +# Reset the database of the wiki and the password of the admin +# +# Warning: This function must be called only in a subdirectory of t/ directory +wiki_reset () { + # Copy initial database of the wiki + if [ ! -f "../$FILES_FOLDER/$DB_FILE" ] ; then + error "Can't find ../$FILES_FOLDER/$DB_FILE in the current folder." + fi + cp "../$FILES_FOLDER/$DB_FILE" "$TMP" || + error "Can't copy ../$FILES_FOLDER/$DB_FILE in $TMP" + echo "File $FILES_FOLDER/$DB_FILE is set in $TMP" +} + +# Delete the wiki created in the web server's directory and all its content +# saved in the database. +wiki_delete () { + if test $LIGHTTPD = "true"; then + stop_lighttpd + else + # Delete the wiki's directory. + rm -rf "$WIKI_DIR_INST/$WIKI_DIR_NAME" || + error "Wiki's directory $WIKI_DIR_INST/" \ + "$WIKI_DIR_NAME could not be deleted" + # Delete the wiki's SQLite database. + rm -f "$TMP/$DB_FILE" || + error "Database $TMP/$DB_FILE could not be deleted." + fi + + # Delete the wiki's SQLite database + rm -f "$TMP/$DB_FILE" || error "Database $TMP/$DB_FILE could not be deleted." + rm -f "$FILES_FOLDER/$DB_FILE" + rm -rf "$TMP/$MW_VERSION" +} diff --git a/contrib/mw-to-git/t/test-gitmw.pl b/contrib/mw-to-git/t/test-gitmw.pl new file mode 100755 index 000000000..0ff76259f --- /dev/null +++ b/contrib/mw-to-git/t/test-gitmw.pl @@ -0,0 +1,225 @@ +#!/usr/bin/perl -w -s +# Copyright (C) 2012 +# Charles Roussel <charles.roussel@ensimag.imag.fr> +# Simon Cathebras <simon.cathebras@ensimag.imag.fr> +# Julien Khayat <julien.khayat@ensimag.imag.fr> +# Guillaume Sasdy <guillaume.sasdy@ensimag.imag.fr> +# Simon Perrat <simon.perrat@ensimag.imag.fr> +# License: GPL v2 or later + +# Usage: +# ./test-gitmw.pl <command> [argument]* +# Execute in terminal using the name of the function to call as first +# parameter, and the function's arguments as following parameters +# +# Example: +# ./test-gitmw.pl "get_page" foo . +# will call <wiki_getpage> with arguments <foo> and <.> +# +# Available functions are: +# "get_page" +# "delete_page" +# "edit_page" +# "getallpagename" + +use MediaWiki::API; +use Getopt::Long; +use encoding 'utf8'; +use DateTime::Format::ISO8601; +use open ':encoding(utf8)'; +use constant SLASH_REPLACEMENT => "%2F"; + +#Parsing of the config file + +my $configfile = "$ENV{'CURR_DIR'}/test.config"; +my %config; +open my $CONFIG, "<", $configfile or die "can't open $configfile: $!"; +while (<$CONFIG>) +{ + chomp; + s/#.*//; + s/^\s+//; + s/\s+$//; + next unless length; + my ($key, $value) = split (/\s*=\s*/,$_, 2); + $config{$key} = $value; + last if ($key eq 'LIGHTTPD' and $value eq 'false'); + last if ($key eq 'PORT'); +} +close $CONFIG or die "can't close $configfile: $!"; + +my $wiki_address = "http://$config{'SERVER_ADDR'}".":"."$config{'PORT'}"; +my $wiki_url = "$wiki_address/$config{'WIKI_DIR_NAME'}/api.php"; +my $wiki_admin = "$config{'WIKI_ADMIN'}"; +my $wiki_admin_pass = "$config{'WIKI_PASSW'}"; +my $mw = MediaWiki::API->new; +$mw->{config}->{api_url} = $wiki_url; + + +# wiki_login <name> <password> +# +# Logs the user with <name> and <password> in the global variable +# of the mediawiki $mw +sub wiki_login { + $mw->login( { lgname => "$_[0]",lgpassword => "$_[1]" } ) + || die "getpage: login failed"; +} + +# wiki_getpage <wiki_page> <dest_path> +# +# fetch a page <wiki_page> from the wiki referenced in the global variable +# $mw and copies its content in directory dest_path +sub wiki_getpage { + my $pagename = $_[0]; + my $destdir = $_[1]; + + my $page = $mw->get_page( { title => $pagename } ); + if (!defined($page)) { + die "getpage: wiki does not exist"; + } + + my $content = $page->{'*'}; + if (!defined($content)) { + die "getpage: page does not exist"; + } + + $pagename=$page->{'title'}; + # Replace spaces by underscore in the page name + $pagename =~ s/ /_/g; + $pagename =~ s/\//%2F/g; + open(my $file, ">$destdir/$pagename.mw"); + print $file "$content"; + close ($file); + +} + +# wiki_delete_page <page_name> +# +# delete the page with name <page_name> from the wiki referenced +# in the global variable $mw +sub wiki_delete_page { + my $pagename = $_[0]; + + my $exist=$mw->get_page({title => $pagename}); + + if (defined($exist->{'*'})){ + $mw->edit({ action => 'delete', + title => $pagename}) + || die $mw->{error}->{code} . ": " . $mw->{error}->{details}; + } else { + die "no page with such name found: $pagename\n"; + } +} + +# wiki_editpage <wiki_page> <wiki_content> <wiki_append> [-c=<category>] [-s=<summary>] +# +# Edit a page named <wiki_page> with content <wiki_content> on the wiki +# referenced with the global variable $mw +# If <wiki_append> == true : append <wiki_content> at the end of the actual +# content of the page <wiki_page> +# If <wik_page> doesn't exist, that page is created with the <wiki_content> +sub wiki_editpage { + my $wiki_page = $_[0]; + my $wiki_content = $_[1]; + my $wiki_append = $_[2]; + my $summary = ""; + my ($summ, $cat) = (); + GetOptions('s=s' => \$summ, 'c=s' => \$cat); + + my $append = 0; + if (defined($wiki_append) && $wiki_append eq 'true') { + $append=1; + } + + my $previous_text =""; + + if ($append) { + my $ref = $mw->get_page( { title => $wiki_page } ); + $previous_text = $ref->{'*'}; + } + + my $text = $wiki_content; + if (defined($previous_text)) { + $text="$previous_text$text"; + } + + # Eventually, add this page to a category. + if (defined($cat)) { + my $category_name="[[Category:$cat]]"; + $text="$text\n $category_name"; + } + if(defined($summ)){ + $summary=$summ; + } + + $mw->edit( { action => 'edit', title => $wiki_page, summary => $summary, text => "$text"} ); +} + +# wiki_getallpagename [<category>] +# +# Fetch all pages of the wiki referenced by the global variable $mw +# and print the names of each one in the file all.txt with a new line +# ("\n") between these. +# If the argument <category> is defined, then this function get only the pages +# belonging to <category>. +sub wiki_getallpagename { + # fetch the pages of the wiki + if (defined($_[0])) { + my $mw_pages = $mw->list ( { action => 'query', + list => 'categorymembers', + cmtitle => "Category:$_[0]", + cmnamespace => 0, + cmlimit => 500 }, + ) + || die $mw->{error}->{code}.": ".$mw->{error}->{details}; + open(my $file, ">all.txt"); + foreach my $page (@{$mw_pages}) { + print $file "$page->{title}\n"; + } + close ($file); + + } else { + my $mw_pages = $mw->list({ + action => 'query', + list => 'allpages', + aplimit => 500, + }) + || die $mw->{error}->{code}.": ".$mw->{error}->{details}; + open(my $file, ">all.txt"); + foreach my $page (@{$mw_pages}) { + print $file "$page->{title}\n"; + } + close ($file); + } +} + +sub wiki_upload_file { + my $file_name = $_[0]; + my $resultat = $mw->edit ( { + action => 'upload', + filename => $file_name, + comment => 'upload a file', + file => [ $file_name ], + ignorewarnings=>1, + }, { + skip_encoding => 1 + } ) || die $mw->{error}->{code} . ' : ' . $mw->{error}->{details}; +} + + + +# Main part of this script: parse the command line arguments +# and select which function to execute +my $fct_to_call = shift; + +wiki_login($wiki_admin, $wiki_admin_pass); + +my %functions_to_call = qw( + upload_file wiki_upload_file + get_page wiki_getpage + delete_page wiki_delete_page + edit_page wiki_editpage + getallpagename wiki_getallpagename +); +die "$0 ERROR: wrong argument" unless exists $functions_to_call{$fct_to_call}; +&{$functions_to_call{$fct_to_call}}(@ARGV); diff --git a/contrib/mw-to-git/t/test.config b/contrib/mw-to-git/t/test.config new file mode 100644 index 000000000..958b37b4a --- /dev/null +++ b/contrib/mw-to-git/t/test.config @@ -0,0 +1,35 @@ +# Name of the web server's directory dedicated to the wiki is WIKI_DIR_NAME +WIKI_DIR_NAME=wiki + +# Login and password of the wiki's admin +WIKI_ADMIN=WikiAdmin +WIKI_PASSW=AdminPass + +# Address of the web server +SERVER_ADDR=localhost + +# SQLite database of the wiki, named DB_FILE, is located in TMP +TMP=/tmp +DB_FILE=wikidb.sqlite + +# If LIGHTTPD is not set to true, the script will use the defaut +# web server running in WIKI_DIR_INST. +WIKI_DIR_INST=/var/www + +# If LIGHTTPD is set to true, the script will use Lighttpd to run +# the wiki. +LIGHTTPD=true + +# The variables below are useful only if LIGHTTPD is set to true. +PORT=1234 +PHP_DIR=/usr/bin +LIGHTTPD_DIR=/usr/sbin +WEB=WEB +WEB_TMP=$WEB/tmp +WEB_WWW=$WEB/www + +# The variables below are used by the script to install a wiki. +# You should not modify these unless you are modifying the script itself. +MW_VERSION=mediawiki-1.19.0 +FILES_FOLDER=install-wiki +DB_INSTALL_SCRIPT=db_install.php diff --git a/contrib/remote-helpers/Makefile b/contrib/remote-helpers/Makefile new file mode 100644 index 000000000..9a76575f7 --- /dev/null +++ b/contrib/remote-helpers/Makefile @@ -0,0 +1,13 @@ +TESTS := $(wildcard test*.sh) + +export T := $(addprefix $(CURDIR)/,$(TESTS)) +export MAKE := $(MAKE) -e +export PATH := $(CURDIR):$(PATH) + +test: + $(MAKE) -C ../../t $@ + +$(TESTS): + $(MAKE) -C ../../t $(CURDIR)/$@ + +.PHONY: $(TESTS) diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg new file mode 100755 index 000000000..c7006000a --- /dev/null +++ b/contrib/remote-helpers/git-remote-hg @@ -0,0 +1,794 @@ +#!/usr/bin/env python +# +# Copyright (c) 2012 Felipe Contreras +# + +# Inspired by Rocco Rutte's hg-fast-export + +# Just copy to your ~/bin, or anywhere in your $PATH. +# Then you can clone with: +# git clone hg::/path/to/mercurial/repo/ + +from mercurial import hg, ui, bookmarks, context, util, encoding + +import re +import sys +import os +import json +import shutil +import subprocess +import urllib + +# +# If you want to switch to hg-git compatibility mode: +# git config --global remote-hg.hg-git-compat true +# +# git: +# Sensible defaults for git. +# hg bookmarks are exported as git branches, hg branches are prefixed +# with 'branches/', HEAD is a special case. +# +# hg: +# Emulate hg-git. +# Only hg bookmarks are exported as git branches. +# Commits are modified to preserve hg information and allow bidirectionality. +# + +NAME_RE = re.compile('^([^<>]+)') +AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$') +AUTHOR_HG_RE = re.compile('^(.*?) ?<(.*?)(?:>(.+)?)?$') +RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)') + +def die(msg, *args): + sys.stderr.write('ERROR: %s\n' % (msg % args)) + sys.exit(1) + +def warn(msg, *args): + sys.stderr.write('WARNING: %s\n' % (msg % args)) + +def gitmode(flags): + return 'l' in flags and '120000' or 'x' in flags and '100755' or '100644' + +def gittz(tz): + return '%+03d%02d' % (-tz / 3600, -tz % 3600 / 60) + +def hgmode(mode): + m = { '0100755': 'x', '0120000': 'l' } + return m.get(mode, '') + +def get_config(config): + cmd = ['git', 'config', '--get', config] + process = subprocess.Popen(cmd, stdout=subprocess.PIPE) + output, _ = process.communicate() + return output + +class Marks: + + def __init__(self, path): + self.path = path + self.tips = {} + self.marks = {} + self.rev_marks = {} + self.last_mark = 0 + + self.load() + + def load(self): + if not os.path.exists(self.path): + return + + tmp = json.load(open(self.path)) + + self.tips = tmp['tips'] + self.marks = tmp['marks'] + self.last_mark = tmp['last-mark'] + + for rev, mark in self.marks.iteritems(): + self.rev_marks[mark] = int(rev) + + def dict(self): + return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark } + + def store(self): + json.dump(self.dict(), open(self.path, 'w')) + + def __str__(self): + return str(self.dict()) + + def from_rev(self, rev): + return self.marks[str(rev)] + + def to_rev(self, mark): + return self.rev_marks[mark] + + def get_mark(self, rev): + self.last_mark += 1 + self.marks[str(rev)] = self.last_mark + return self.last_mark + + def new_mark(self, rev, mark): + self.marks[str(rev)] = mark + self.rev_marks[mark] = rev + self.last_mark = mark + + def is_marked(self, rev): + return self.marks.has_key(str(rev)) + + def get_tip(self, branch): + return self.tips.get(branch, 0) + + def set_tip(self, branch, tip): + self.tips[branch] = tip + +class Parser: + + def __init__(self, repo): + self.repo = repo + self.line = self.get_line() + + def get_line(self): + return sys.stdin.readline().strip() + + def __getitem__(self, i): + return self.line.split()[i] + + def check(self, word): + return self.line.startswith(word) + + def each_block(self, separator): + while self.line != separator: + yield self.line + self.line = self.get_line() + + def __iter__(self): + return self.each_block('') + + def next(self): + self.line = self.get_line() + if self.line == 'done': + self.line = None + + def get_mark(self): + i = self.line.index(':') + 1 + return int(self.line[i:]) + + def get_data(self): + if not self.check('data'): + return None + i = self.line.index(' ') + 1 + size = int(self.line[i:]) + return sys.stdin.read(size) + + def get_author(self): + global bad_mail + + ex = None + m = RAW_AUTHOR_RE.match(self.line) + if not m: + return None + _, name, email, date, tz = m.groups() + if name and 'ext:' in name: + m = re.match('^(.+?) ext:\((.+)\)$', name) + if m: + name = m.group(1) + ex = urllib.unquote(m.group(2)) + + if email != bad_mail: + if name: + user = '%s <%s>' % (name, email) + else: + user = '<%s>' % (email) + else: + user = name + + if ex: + user += ex + + tz = int(tz) + tz = ((tz / 100) * 3600) + ((tz % 100) * 60) + return (user, int(date), -tz) + +def export_file(fc): + d = fc.data() + print "M %s inline %s" % (gitmode(fc.flags()), fc.path()) + print "data %d" % len(d) + print d + +def get_filechanges(repo, ctx, parent): + modified = set() + added = set() + removed = set() + + cur = ctx.manifest() + prev = repo[parent].manifest().copy() + + for fn in cur: + if fn in prev: + if (cur.flags(fn) != prev.flags(fn) or cur[fn] != prev[fn]): + modified.add(fn) + del prev[fn] + else: + added.add(fn) + removed |= set(prev.keys()) + + return added | modified, removed + +def fixup_user_git(user): + name = mail = None + user = user.replace('"', '') + m = AUTHOR_RE.match(user) + if m: + name = m.group(1) + mail = m.group(2).strip() + else: + m = NAME_RE.match(user) + if m: + name = m.group(1).strip() + return (name, mail) + +def fixup_user_hg(user): + def sanitize(name): + # stole this from hg-git + return re.sub('[<>\n]', '?', name.lstrip('< ').rstrip('> ')) + + m = AUTHOR_HG_RE.match(user) + if m: + name = sanitize(m.group(1)) + mail = sanitize(m.group(2)) + ex = m.group(3) + if ex: + name += ' ext:(' + urllib.quote(ex) + ')' + else: + name = sanitize(user) + if '@' in user: + mail = name + else: + mail = None + + return (name, mail) + +def fixup_user(user): + global mode, bad_mail + + if mode == 'git': + name, mail = fixup_user_git(user) + else: + name, mail = fixup_user_hg(user) + + if not name: + name = bad_name + if not mail: + mail = bad_mail + + return '%s <%s>' % (name, mail) + +def get_repo(url, alias): + global dirname, peer + + myui = ui.ui() + myui.setconfig('ui', 'interactive', 'off') + + if hg.islocal(url): + repo = hg.repository(myui, url) + else: + local_path = os.path.join(dirname, 'clone') + if not os.path.exists(local_path): + peer, dstpeer = hg.clone(myui, {}, url, local_path, update=False, pull=True) + repo = dstpeer.local() + else: + repo = hg.repository(myui, local_path) + peer = hg.peer(myui, {}, url) + repo.pull(peer, heads=None, force=True) + + return repo + +def rev_to_mark(rev): + global marks + return marks.from_rev(rev) + +def mark_to_rev(mark): + global marks + return marks.to_rev(mark) + +def export_ref(repo, name, kind, head): + global prefix, marks, mode + + ename = '%s/%s' % (kind, name) + tip = marks.get_tip(ename) + + # mercurial takes too much time checking this + if tip and tip == head.rev(): + # nothing to do + return + revs = xrange(tip, head.rev() + 1) + count = 0 + + revs = [rev for rev in revs if not marks.is_marked(rev)] + + for rev in revs: + + c = repo[rev] + (manifest, user, (time, tz), files, desc, extra) = repo.changelog.read(c.node()) + rev_branch = extra['branch'] + + author = "%s %d %s" % (fixup_user(user), time, gittz(tz)) + if 'committer' in extra: + user, time, tz = extra['committer'].rsplit(' ', 2) + committer = "%s %s %s" % (user, time, gittz(int(tz))) + else: + committer = author + + parents = [p for p in repo.changelog.parentrevs(rev) if p >= 0] + + if len(parents) == 0: + modified = c.manifest().keys() + removed = [] + else: + modified, removed = get_filechanges(repo, c, parents[0]) + + if mode == 'hg': + extra_msg = '' + + if rev_branch != 'default': + extra_msg += 'branch : %s\n' % rev_branch + + renames = [] + for f in c.files(): + if f not in c.manifest(): + continue + rename = c.filectx(f).renamed() + if rename: + renames.append((rename[0], f)) + + for e in renames: + extra_msg += "rename : %s => %s\n" % e + + for key, value in extra.iteritems(): + if key in ('author', 'committer', 'encoding', 'message', 'branch', 'hg-git'): + continue + else: + extra_msg += "extra : %s : %s\n" % (key, urllib.quote(value)) + + desc += '\n' + if extra_msg: + desc += '\n--HG--\n' + extra_msg + + if len(parents) == 0 and rev: + print 'reset %s/%s' % (prefix, ename) + + print "commit %s/%s" % (prefix, ename) + print "mark :%d" % (marks.get_mark(rev)) + print "author %s" % (author) + print "committer %s" % (committer) + print "data %d" % (len(desc)) + print desc + + if len(parents) > 0: + print "from :%s" % (rev_to_mark(parents[0])) + if len(parents) > 1: + print "merge :%s" % (rev_to_mark(parents[1])) + + for f in modified: + export_file(c.filectx(f)) + for f in removed: + print "D %s" % (f) + print + + count += 1 + if (count % 100 == 0): + print "progress revision %d '%s' (%d/%d)" % (rev, name, count, len(revs)) + print "#############################################################" + + # make sure the ref is updated + print "reset %s/%s" % (prefix, ename) + print "from :%u" % rev_to_mark(rev) + print + + marks.set_tip(ename, rev) + +def export_tag(repo, tag): + export_ref(repo, tag, 'tags', repo[tag]) + +def export_bookmark(repo, bmark): + head = bmarks[bmark] + export_ref(repo, bmark, 'bookmarks', head) + +def export_branch(repo, branch): + tip = get_branch_tip(repo, branch) + head = repo[tip] + export_ref(repo, branch, 'branches', head) + +def export_head(repo): + global g_head + export_ref(repo, g_head[0], 'bookmarks', g_head[1]) + +def do_capabilities(parser): + global prefix, dirname + + print "import" + print "export" + print "refspec refs/heads/branches/*:%s/branches/*" % prefix + print "refspec refs/heads/*:%s/bookmarks/*" % prefix + print "refspec refs/tags/*:%s/tags/*" % prefix + + path = os.path.join(dirname, 'marks-git') + + if os.path.exists(path): + print "*import-marks %s" % path + print "*export-marks %s" % path + + print + +def get_branch_tip(repo, branch): + global branches + + heads = branches.get(branch, None) + if not heads: + return None + + # verify there's only one head + if (len(heads) > 1): + warn("Branch '%s' has more than one head, consider merging" % branch) + # older versions of mercurial don't have this + if hasattr(repo, "branchtip"): + return repo.branchtip(branch) + + return heads[0] + +def list_head(repo, cur): + global g_head, bmarks + + head = bookmarks.readcurrent(repo) + if head: + node = repo[head] + else: + # fake bookmark from current branch + head = cur + node = repo['.'] + if not node: + node = repo['tip'] + if not node: + return + if head == 'default': + head = 'master' + bmarks[head] = node + + print "@refs/heads/%s HEAD" % head + g_head = (head, node) + +def do_list(parser): + global branches, bmarks, mode, track_branches + + repo = parser.repo + for bmark, node in bookmarks.listbookmarks(repo).iteritems(): + bmarks[bmark] = repo[node] + + cur = repo.dirstate.branch() + + list_head(repo, cur) + + if track_branches: + for branch in repo.branchmap(): + heads = repo.branchheads(branch) + if len(heads): + branches[branch] = heads + + for branch in branches: + print "? refs/heads/branches/%s" % branch + + for bmark in bmarks: + print "? refs/heads/%s" % bmark + + for tag, node in repo.tagslist(): + if tag == 'tip': + continue + print "? refs/tags/%s" % tag + + print + +def do_import(parser): + repo = parser.repo + + path = os.path.join(dirname, 'marks-git') + + print "feature done" + if os.path.exists(path): + print "feature import-marks=%s" % path + print "feature export-marks=%s" % path + sys.stdout.flush() + + tmp = encoding.encoding + encoding.encoding = 'utf-8' + + # lets get all the import lines + while parser.check('import'): + ref = parser[1] + + if (ref == 'HEAD'): + export_head(repo) + elif ref.startswith('refs/heads/branches/'): + branch = ref[len('refs/heads/branches/'):] + export_branch(repo, branch) + elif ref.startswith('refs/heads/'): + bmark = ref[len('refs/heads/'):] + export_bookmark(repo, bmark) + elif ref.startswith('refs/tags/'): + tag = ref[len('refs/tags/'):] + export_tag(repo, tag) + + parser.next() + + encoding.encoding = tmp + + print 'done' + +def parse_blob(parser): + global blob_marks + + parser.next() + mark = parser.get_mark() + parser.next() + data = parser.get_data() + blob_marks[mark] = data + parser.next() + return + +def get_merge_files(repo, p1, p2, files): + for e in repo[p1].files(): + if e not in files: + if e not in repo[p1].manifest(): + continue + f = { 'ctx' : repo[p1][e] } + files[e] = f + +def parse_commit(parser): + global marks, blob_marks, bmarks, parsed_refs + global mode + + from_mark = merge_mark = None + + ref = parser[1] + parser.next() + + commit_mark = parser.get_mark() + parser.next() + author = parser.get_author() + parser.next() + committer = parser.get_author() + parser.next() + data = parser.get_data() + parser.next() + if parser.check('from'): + from_mark = parser.get_mark() + parser.next() + if parser.check('merge'): + merge_mark = parser.get_mark() + parser.next() + if parser.check('merge'): + die('octopus merges are not supported yet') + + files = {} + + for line in parser: + if parser.check('M'): + t, m, mark_ref, path = line.split(' ', 3) + mark = int(mark_ref[1:]) + f = { 'mode' : hgmode(m), 'data' : blob_marks[mark] } + elif parser.check('D'): + t, path = line.split(' ') + f = { 'deleted' : True } + else: + die('Unknown file command: %s' % line) + files[path] = f + + def getfilectx(repo, memctx, f): + of = files[f] + if 'deleted' in of: + raise IOError + if 'ctx' in of: + return of['ctx'] + is_exec = of['mode'] == 'x' + is_link = of['mode'] == 'l' + rename = of.get('rename', None) + return context.memfilectx(f, of['data'], + is_link, is_exec, rename) + + repo = parser.repo + + user, date, tz = author + extra = {} + + if committer != author: + extra['committer'] = "%s %u %u" % committer + + if from_mark: + p1 = repo.changelog.node(mark_to_rev(from_mark)) + else: + p1 = '\0' * 20 + + if merge_mark: + p2 = repo.changelog.node(mark_to_rev(merge_mark)) + else: + p2 = '\0' * 20 + + # + # If files changed from any of the parents, hg wants to know, but in git if + # nothing changed from the first parent, nothing changed. + # + if merge_mark: + get_merge_files(repo, p1, p2, files) + + if mode == 'hg': + i = data.find('\n--HG--\n') + if i >= 0: + tmp = data[i + len('\n--HG--\n'):].strip() + for k, v in [e.split(' : ') for e in tmp.split('\n')]: + if k == 'rename': + old, new = v.split(' => ', 1) + files[new]['rename'] = old + elif k == 'branch': + extra[k] = v + elif k == 'extra': + ek, ev = v.split(' : ', 1) + extra[ek] = urllib.unquote(ev) + data = data[:i] + + ctx = context.memctx(repo, (p1, p2), data, + files.keys(), getfilectx, + user, (date, tz), extra) + + tmp = encoding.encoding + encoding.encoding = 'utf-8' + + node = repo.commitctx(ctx) + + encoding.encoding = tmp + + rev = repo[node].rev() + + parsed_refs[ref] = node + + marks.new_mark(rev, commit_mark) + +def parse_reset(parser): + ref = parser[1] + parser.next() + # ugh + if parser.check('commit'): + parse_commit(parser) + return + if not parser.check('from'): + return + from_mark = parser.get_mark() + parser.next() + + node = parser.repo.changelog.node(mark_to_rev(from_mark)) + parsed_refs[ref] = node + +def parse_tag(parser): + name = parser[1] + parser.next() + from_mark = parser.get_mark() + parser.next() + tagger = parser.get_author() + parser.next() + data = parser.get_data() + parser.next() + + # nothing to do + +def do_export(parser): + global parsed_refs, bmarks, peer + + parser.next() + + for line in parser.each_block('done'): + if parser.check('blob'): + parse_blob(parser) + elif parser.check('commit'): + parse_commit(parser) + elif parser.check('reset'): + parse_reset(parser) + elif parser.check('tag'): + parse_tag(parser) + elif parser.check('feature'): + pass + else: + die('unhandled export command: %s' % line) + + for ref, node in parsed_refs.iteritems(): + if ref.startswith('refs/heads/branches'): + pass + elif ref.startswith('refs/heads/'): + bmark = ref[len('refs/heads/'):] + if bmark in bmarks: + old = bmarks[bmark].hex() + else: + old = '' + if not bookmarks.pushbookmark(parser.repo, bmark, old, node): + continue + elif ref.startswith('refs/tags/'): + tag = ref[len('refs/tags/'):] + parser.repo.tag([tag], node, None, True, None, {}) + else: + # transport-helper/fast-export bugs + continue + print "ok %s" % ref + + print + + if peer: + parser.repo.push(peer, force=False) + +def main(args): + global prefix, dirname, branches, bmarks + global marks, blob_marks, parsed_refs + global peer, mode, bad_mail, bad_name + global track_branches + + alias = args[1] + url = args[2] + peer = None + + hg_git_compat = False + track_branches = True + try: + if get_config('remote-hg.hg-git-compat') == 'true\n': + hg_git_compat = True + track_branches = False + if get_config('remote-hg.track-branches') == 'false\n': + track_branches = False + except subprocess.CalledProcessError: + pass + + if hg_git_compat: + mode = 'hg' + bad_mail = 'none@none' + bad_name = '' + else: + mode = 'git' + bad_mail = 'unknown' + bad_name = 'Unknown' + + if alias[4:] == url: + is_tmp = True + alias = util.sha1(alias).hexdigest() + else: + is_tmp = False + + gitdir = os.environ['GIT_DIR'] + dirname = os.path.join(gitdir, 'hg', alias) + branches = {} + bmarks = {} + blob_marks = {} + parsed_refs = {} + + repo = get_repo(url, alias) + prefix = 'refs/hg/%s' % alias + + if not os.path.exists(dirname): + os.makedirs(dirname) + + marks_path = os.path.join(dirname, 'marks-hg') + marks = Marks(marks_path) + + parser = Parser(repo) + for line in parser: + if parser.check('capabilities'): + do_capabilities(parser) + elif parser.check('list'): + do_list(parser) + elif parser.check('import'): + do_import(parser) + elif parser.check('export'): + do_export(parser) + else: + die('unhandled command: %s' % line) + sys.stdout.flush() + + if not is_tmp: + marks.store() + else: + shutil.rmtree(dirname) + +sys.exit(main(sys.argv)) diff --git a/contrib/remote-helpers/test-hg-bidi.sh b/contrib/remote-helpers/test-hg-bidi.sh new file mode 100755 index 000000000..1d6198243 --- /dev/null +++ b/contrib/remote-helpers/test-hg-bidi.sh @@ -0,0 +1,243 @@ +#!/bin/sh +# +# Copyright (c) 2012 Felipe Contreras +# +# Base commands from hg-git tests: +# https://bitbucket.org/durin42/hg-git/src +# + +test_description='Test bidirectionality of remote-hg' + +. ./test-lib.sh + +if ! test_have_prereq PYTHON; then + skip_all='skipping remote-hg tests; python not available' + test_done +fi + +if ! "$PYTHON_PATH" -c 'import mercurial'; then + skip_all='skipping remote-hg tests; mercurial not available' + test_done +fi + +# clone to a git repo +git_clone () { + hg -R $1 bookmark -f -r tip master && + git clone -q "hg::$PWD/$1" $2 +} + +# clone to an hg repo +hg_clone () { + ( + hg init $2 && + cd $1 && + git push -q "hg::$PWD/../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' + ) && + + (cd $2 && hg -q update) +} + +# push an hg repo +hg_push () { + ( + cd $2 + old=$(git symbolic-ref --short HEAD) + git checkout -q -b tmp && + git fetch -q "hg::$PWD/../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' && + git checkout -q $old && + git branch -q -D tmp 2> /dev/null || true + ) +} + +hg_log () { + hg -R $1 log --graph --debug | grep -v 'tag: *default/' +} + +setup () { + ( + echo "[ui]" + echo "username = A U Thor <author@example.com>" + echo "[defaults]" + echo "backout = -d \"0 0\"" + echo "commit = -d \"0 0\"" + echo "debugrawcommit = -d \"0 0\"" + echo "tag = -d \"0 0\"" + ) >> "$HOME"/.hgrc && + git config --global remote-hg.hg-git-compat true + + export HGEDITOR=/usr/bin/true + + export GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" + export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" +} + +setup + +test_expect_success 'encoding' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + git init -q gitrepo && + cd gitrepo && + + echo alpha > alpha && + git add alpha && + git commit -m "add älphà " && + + export GIT_AUTHOR_NAME="tést èncödîng" && + echo beta > beta && + git add beta && + git commit -m "add beta" && + + echo gamma > gamma && + git add gamma && + git commit -m "add gämmâ" && + + : TODO git config i18n.commitencoding latin-1 && + echo delta > delta && + git add delta && + git commit -m "add déltà " + ) && + + hg_clone gitrepo hgrepo && + git_clone hgrepo gitrepo2 && + hg_clone gitrepo2 hgrepo2 && + + HGENCODING=utf-8 hg_log hgrepo > expected && + HGENCODING=utf-8 hg_log hgrepo2 > actual && + + test_cmp expected actual +' + +test_expect_success 'file removal' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + git init -q gitrepo && + cd gitrepo && + echo alpha > alpha && + git add alpha && + git commit -m "add alpha" && + echo beta > beta && + git add beta && + git commit -m "add beta" + mkdir foo && + echo blah > foo/bar && + git add foo && + git commit -m "add foo" && + git rm alpha && + git commit -m "remove alpha" && + git rm foo/bar && + git commit -m "remove foo/bar" + ) && + + hg_clone gitrepo hgrepo && + git_clone hgrepo gitrepo2 && + hg_clone gitrepo2 hgrepo2 && + + hg_log hgrepo > expected && + hg_log hgrepo2 > actual && + + test_cmp expected actual +' + +test_expect_success 'git tags' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + git init -q gitrepo && + cd gitrepo && + git config receive.denyCurrentBranch ignore && + echo alpha > alpha && + git add alpha && + git commit -m "add alpha" && + git tag alpha && + + echo beta > beta && + git add beta && + git commit -m "add beta" && + git tag -a -m "added tag beta" beta + ) && + + hg_clone gitrepo hgrepo && + git_clone hgrepo gitrepo2 && + hg_clone gitrepo2 hgrepo2 && + + hg_log hgrepo > expected && + hg_log hgrepo2 > actual && + + test_cmp expected actual +' + +test_expect_success 'hg branch' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + git init -q gitrepo && + cd gitrepo && + + echo alpha > alpha && + git add alpha && + git commit -q -m "add alpha" && + git checkout -q -b not-master + ) && + + ( + hg_clone gitrepo hgrepo && + + cd hgrepo && + hg -q co master && + hg mv alpha beta && + hg -q commit -m "rename alpha to beta" && + hg branch gamma | grep -v "permanent and global" && + hg -q commit -m "started branch gamma" + ) && + + hg_push hgrepo gitrepo && + hg_clone gitrepo hgrepo2 && + + : TODO, avoid "master" bookmark && + (cd hgrepo2 && hg checkout gamma) && + + hg_log hgrepo > expected && + hg_log hgrepo2 > actual && + + test_cmp expected actual +' + +test_expect_success 'hg tags' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + git init -q gitrepo && + cd gitrepo && + + echo alpha > alpha && + git add alpha && + git commit -m "add alpha" && + git checkout -q -b not-master + ) && + + ( + hg_clone gitrepo hgrepo && + + cd hgrepo && + hg co master && + hg tag alpha + ) && + + hg_push hgrepo gitrepo && + hg_clone gitrepo hgrepo2 && + + hg_log hgrepo > expected && + hg_log hgrepo2 > actual && + + test_cmp expected actual +' + +test_done diff --git a/contrib/remote-helpers/test-hg-hg-git.sh b/contrib/remote-helpers/test-hg-hg-git.sh new file mode 100755 index 000000000..3e76d9fb6 --- /dev/null +++ b/contrib/remote-helpers/test-hg-hg-git.sh @@ -0,0 +1,466 @@ +#!/bin/sh +# +# Copyright (c) 2012 Felipe Contreras +# +# Base commands from hg-git tests: +# https://bitbucket.org/durin42/hg-git/src +# + +test_description='Test remote-hg output compared to hg-git' + +. ./test-lib.sh + +if ! test_have_prereq PYTHON; then + skip_all='skipping remote-hg tests; python not available' + test_done +fi + +if ! "$PYTHON_PATH" -c 'import mercurial'; then + skip_all='skipping remote-hg tests; mercurial not available' + test_done +fi + +if ! "$PYTHON_PATH" -c 'import hggit'; then + skip_all='skipping remote-hg tests; hg-git not available' + test_done +fi + +# clone to a git repo with git +git_clone_git () { + hg -R $1 bookmark -f -r tip master && + git clone -q "hg::$PWD/$1" $2 +} + +# clone to an hg repo with git +hg_clone_git () { + ( + hg init $2 && + cd $1 && + git push -q "hg::$PWD/../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' + ) && + + (cd $2 && hg -q update) +} + +# clone to a git repo with hg +git_clone_hg () { + ( + git init -q $2 && + cd $1 && + hg bookmark -f -r tip master && + hg -q push -r master ../$2 || true + ) +} + +# clone to an hg repo with hg +hg_clone_hg () { + hg -q clone $1 $2 +} + +# push an hg repo with git +hg_push_git () { + ( + cd $2 + old=$(git symbolic-ref --short HEAD) + git checkout -q -b tmp && + git fetch -q "hg::$PWD/../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' && + git checkout -q $old && + git branch -q -D tmp 2> /dev/null || true + ) +} + +# push an hg git repo with hg +hg_push_hg () { + ( + cd $1 && + hg -q push ../$2 || true + ) +} + +hg_log () { + hg -R $1 log --graph --debug | grep -v 'tag: *default/' +} + +git_log () { + git --git-dir=$1/.git fast-export --branches +} + +setup () { + ( + echo "[ui]" + echo "username = A U Thor <author@example.com>" + echo "[defaults]" + echo "backout = -d \"0 0\"" + echo "commit = -d \"0 0\"" + echo "debugrawcommit = -d \"0 0\"" + echo "tag = -d \"0 0\"" + echo "[extensions]" + echo "hgext.bookmarks =" + echo "hggit =" + ) >> "$HOME"/.hgrc && + git config --global receive.denycurrentbranch warn + git config --global remote-hg.hg-git-compat true + + export HGEDITOR=/usr/bin/true + + export GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" + export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" +} + +setup + +test_expect_success 'merge conflict 1' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + hg init hgrepo1 && + cd hgrepo1 && + echo A > afile && + hg add afile && + hg ci -m "origin" && + + echo B > afile && + hg ci -m "A->B" && + + hg up -r0 && + echo C > afile && + hg ci -m "A->C" && + + hg merge -r1 || true && + echo C > afile && + hg resolve -m afile && + hg ci -m "merge to C" + ) && + + for x in hg git; do + git_clone_$x hgrepo1 gitrepo-$x && + hg_clone_$x gitrepo-$x hgrepo2-$x && + hg_log hgrepo2-$x > hg-log-$x && + git_log gitrepo-$x > git-log-$x + done && + + test_cmp hg-log-hg hg-log-git && + test_cmp git-log-hg git-log-git +' + +test_expect_success 'merge conflict 2' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + hg init hgrepo1 && + cd hgrepo1 && + echo A > afile && + hg add afile && + hg ci -m "origin" && + + echo B > afile && + hg ci -m "A->B" && + + hg up -r0 && + echo C > afile && + hg ci -m "A->C" && + + hg merge -r1 || true && + echo B > afile && + hg resolve -m afile && + hg ci -m "merge to B" + ) && + + for x in hg git; do + git_clone_$x hgrepo1 gitrepo-$x && + hg_clone_$x gitrepo-$x hgrepo2-$x && + hg_log hgrepo2-$x > hg-log-$x && + git_log gitrepo-$x > git-log-$x + done && + + test_cmp hg-log-hg hg-log-git && + test_cmp git-log-hg git-log-git +' + +test_expect_success 'converged merge' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + hg init hgrepo1 && + cd hgrepo1 && + echo A > afile && + hg add afile && + hg ci -m "origin" && + + echo B > afile && + hg ci -m "A->B" && + + echo C > afile && + hg ci -m "B->C" && + + hg up -r0 && + echo C > afile && + hg ci -m "A->C" && + + hg merge -r2 || true && + hg ci -m "merge" + ) && + + for x in hg git; do + git_clone_$x hgrepo1 gitrepo-$x && + hg_clone_$x gitrepo-$x hgrepo2-$x && + hg_log hgrepo2-$x > hg-log-$x && + git_log gitrepo-$x > git-log-$x + done && + + test_cmp hg-log-hg hg-log-git && + test_cmp git-log-hg git-log-git +' + +test_expect_success 'encoding' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + git init -q gitrepo && + cd gitrepo && + + echo alpha > alpha && + git add alpha && + git commit -m "add älphà " && + + export GIT_AUTHOR_NAME="tést èncödîng" && + echo beta > beta && + git add beta && + git commit -m "add beta" && + + echo gamma > gamma && + git add gamma && + git commit -m "add gämmâ" && + + : TODO git config i18n.commitencoding latin-1 && + echo delta > delta && + git add delta && + git commit -m "add déltà " + ) && + + for x in hg git; do + hg_clone_$x gitrepo hgrepo-$x && + git_clone_$x hgrepo-$x gitrepo2-$x && + + HGENCODING=utf-8 hg_log hgrepo-$x > hg-log-$x && + git_log gitrepo2-$x > git-log-$x + done && + + test_cmp hg-log-hg hg-log-git && + test_cmp git-log-hg git-log-git +' + +test_expect_success 'file removal' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + git init -q gitrepo && + cd gitrepo && + echo alpha > alpha && + git add alpha && + git commit -m "add alpha" && + echo beta > beta && + git add beta && + git commit -m "add beta" + mkdir foo && + echo blah > foo/bar && + git add foo && + git commit -m "add foo" && + git rm alpha && + git commit -m "remove alpha" && + git rm foo/bar && + git commit -m "remove foo/bar" + ) && + + for x in hg git; do + ( + hg_clone_$x gitrepo hgrepo-$x && + cd hgrepo-$x && + hg_log . && + hg manifest -r 3 && + hg manifest + ) > output-$x && + + git_clone_$x hgrepo-$x gitrepo2-$x && + git_log gitrepo2-$x > log-$x + done && + + test_cmp output-hg output-git && + test_cmp log-hg log-git +' + +test_expect_success 'git tags' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + ( + git init -q gitrepo && + cd gitrepo && + git config receive.denyCurrentBranch ignore && + echo alpha > alpha && + git add alpha && + git commit -m "add alpha" && + git tag alpha && + + echo beta > beta && + git add beta && + git commit -m "add beta" && + git tag -a -m "added tag beta" beta + ) && + + for x in hg git; do + hg_clone_$x gitrepo hgrepo-$x && + hg_log hgrepo-$x > log-$x + done && + + test_cmp log-hg log-git +' + +test_expect_success 'hg author' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + for x in hg git; do + ( + git init -q gitrepo-$x && + cd gitrepo-$x && + + echo alpha > alpha && + git add alpha && + git commit -m "add alpha" && + git checkout -q -b not-master + ) && + + ( + hg_clone_$x gitrepo-$x hgrepo-$x && + cd hgrepo-$x && + + hg co master && + echo beta > beta && + hg add beta && + hg commit -u "test" -m "add beta" && + + echo gamma >> beta && + hg commit -u "test <test@example.com> (comment)" -m "modify beta" && + + echo gamma > gamma && + hg add gamma && + hg commit -u "<test@example.com>" -m "add gamma" && + + echo delta > delta && + hg add delta && + hg commit -u "name<test@example.com>" -m "add delta" && + + echo epsilon > epsilon && + hg add epsilon && + hg commit -u "name <test@example.com" -m "add epsilon" && + + echo zeta > zeta && + hg add zeta && + hg commit -u " test " -m "add zeta" && + + echo eta > eta && + hg add eta && + hg commit -u "test < test@example.com >" -m "add eta" && + + echo theta > theta && + hg add theta && + hg commit -u "test >test@example.com>" -m "add theta" && + + echo iota > iota && + hg add iota && + hg commit -u "test <test <at> example <dot> com>" -m "add iota" + ) && + + hg_push_$x hgrepo-$x gitrepo-$x && + hg_clone_$x gitrepo-$x hgrepo2-$x && + + hg_log hgrepo2-$x > hg-log-$x && + git_log gitrepo-$x > git-log-$x + done && + + test_cmp git-log-hg git-log-git && + + test_cmp hg-log-hg hg-log-git && + test_cmp git-log-hg git-log-git +' + +test_expect_success 'hg branch' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + for x in hg git; do + ( + git init -q gitrepo-$x && + cd gitrepo-$x && + + echo alpha > alpha && + git add alpha && + git commit -q -m "add alpha" && + git checkout -q -b not-master + ) && + + ( + hg_clone_$x gitrepo-$x hgrepo-$x && + + cd hgrepo-$x && + hg -q co master && + hg mv alpha beta && + hg -q commit -m "rename alpha to beta" && + hg branch gamma | grep -v "permanent and global" && + hg -q commit -m "started branch gamma" + ) && + + hg_push_$x hgrepo-$x gitrepo-$x && + hg_clone_$x gitrepo-$x hgrepo2-$x && + + hg_log hgrepo2-$x > hg-log-$x && + git_log gitrepo-$x > git-log-$x + done && + + test_cmp hg-log-hg hg-log-git && + test_cmp git-log-hg git-log-git +' + +test_expect_success 'hg tags' ' + mkdir -p tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + for x in hg git; do + ( + git init -q gitrepo-$x && + cd gitrepo-$x && + + echo alpha > alpha && + git add alpha && + git commit -m "add alpha" && + git checkout -q -b not-master + ) && + + ( + hg_clone_$x gitrepo-$x hgrepo-$x && + + cd hgrepo-$x && + hg co master && + hg tag alpha + ) && + + hg_push_$x hgrepo-$x gitrepo-$x && + hg_clone_$x gitrepo-$x hgrepo2-$x && + + ( + git --git-dir=gitrepo-$x/.git tag -l && + hg_log hgrepo2-$x && + cat hgrepo2-$x/.hgtags + ) > output-$x + done && + + test_cmp output-hg output-git +' + +test_done diff --git a/contrib/remote-helpers/test-hg.sh b/contrib/remote-helpers/test-hg.sh new file mode 100755 index 000000000..5f81dfae6 --- /dev/null +++ b/contrib/remote-helpers/test-hg.sh @@ -0,0 +1,121 @@ +#!/bin/sh +# +# Copyright (c) 2012 Felipe Contreras +# +# Base commands from hg-git tests: +# https://bitbucket.org/durin42/hg-git/src +# + +test_description='Test remote-hg' + +. ./test-lib.sh + +if ! test_have_prereq PYTHON; then + skip_all='skipping remote-hg tests; python not available' + test_done +fi + +if ! "$PYTHON_PATH" -c 'import mercurial'; then + skip_all='skipping remote-hg tests; mercurial not available' + test_done +fi + +check () { + (cd $1 && + git log --format='%s' -1 && + git symbolic-ref HEAD) > actual && + (echo $2 && + echo "refs/heads/$3") > expected && + test_cmp expected actual +} + +setup () { + ( + echo "[ui]" + echo "username = H G Wells <wells@example.com>" + ) >> "$HOME"/.hgrc +} + +setup + +test_expect_success 'cloning' ' + test_when_finished "rm -rf gitrepo*" && + + ( + hg init hgrepo && + cd hgrepo && + echo zero > content && + hg add content && + hg commit -m zero + ) && + + git clone "hg::$PWD/hgrepo" gitrepo && + check gitrepo zero master +' + +test_expect_success 'cloning with branches' ' + test_when_finished "rm -rf gitrepo*" && + + ( + cd hgrepo && + hg branch next && + echo next > content && + hg commit -m next + ) && + + git clone "hg::$PWD/hgrepo" gitrepo && + check gitrepo next next && + + (cd hgrepo && hg checkout default) && + + git clone "hg::$PWD/hgrepo" gitrepo2 && + check gitrepo2 zero master +' + +test_expect_success 'cloning with bookmarks' ' + test_when_finished "rm -rf gitrepo*" && + + ( + cd hgrepo && + hg bookmark feature-a && + echo feature-a > content && + hg commit -m feature-a + ) && + + git clone "hg::$PWD/hgrepo" gitrepo && + check gitrepo feature-a feature-a +' + +test_expect_success 'cloning with detached head' ' + test_when_finished "rm -rf gitrepo*" && + + ( + cd hgrepo && + hg update -r 0 + ) && + + git clone "hg::$PWD/hgrepo" gitrepo && + check gitrepo zero master +' + +test_expect_success 'update bookmark' ' + test_when_finished "rm -rf gitrepo*" && + + ( + cd hgrepo && + hg bookmark devel + ) && + + ( + git clone "hg::$PWD/hgrepo" gitrepo && + cd gitrepo && + git checkout devel && + echo devel > content && + git commit -a -m devel && + git push + ) && + + hg -R hgrepo bookmarks | grep "devel\s\+3:" +' + +test_done diff --git a/contrib/stats/mailmap.pl b/contrib/stats/mailmap.pl index 4b852e245..9513f5e35 100755 --- a/contrib/stats/mailmap.pl +++ b/contrib/stats/mailmap.pl @@ -1,38 +1,70 @@ -#!/usr/bin/perl -w -my %mailmap = (); -open I, "<", ".mailmap"; -while (<I>) { - chomp; - next if /^#/; - if (my ($author, $mail) = /^(.*?)\s+<(.+)>$/) { - $mailmap{$mail} = $author; - } +#!/usr/bin/perl + +use warnings 'all'; +use strict; +use Getopt::Long; + +my $match_emails; +my $match_names; +my $order_by = 'count'; +Getopt::Long::Configure(qw(bundling)); +GetOptions( + 'emails|e!' => \$match_emails, + 'names|n!' => \$match_names, + 'count|c' => sub { $order_by = 'count' }, + 'time|t' => sub { $order_by = 'stamp' }, +) or exit 1; +$match_emails = 1 unless $match_names; + +my $email = {}; +my $name = {}; + +open(my $fh, '-|', "git log --format='%at <%aE> %aN'"); +while(<$fh>) { + my ($t, $e, $n) = /(\S+) <(\S+)> (.*)/; + mark($email, $e, $n, $t); + mark($name, $n, $e, $t); } -close I; - -my %mail2author = (); -open I, "git log --pretty='format:%ae %an' |"; -while (<I>) { - chomp; - my ($mail, $author) = split(/\t/, $_); - next if exists $mailmap{$mail}; - $mail2author{$mail} ||= {}; - $mail2author{$mail}{$author} ||= 0; - $mail2author{$mail}{$author}++; +close($fh); + +if ($match_emails) { + foreach my $e (dups($email)) { + foreach my $n (vals($email->{$e})) { + show($n, $e, $email->{$e}->{$n}); + } + print "\n"; + } } -close I; - -while (my ($mail, $authorcount) = each %mail2author) { - # %$authorcount is ($author => $count); - # sort and show the names from the most frequent ones. - my @names = (map { $_->[0] } - sort { $b->[1] <=> $a->[1] } - map { [$_, $authorcount->{$_}] } - keys %$authorcount); - if (1 < @names) { - for (@names) { - print "$_ <$mail>\n"; +if ($match_names) { + foreach my $n (dups($name)) { + foreach my $e (vals($name->{$n})) { + show($n, $e, $name->{$n}->{$e}); } + print "\n"; } } +exit 0; +sub mark { + my ($h, $k, $v, $t) = @_; + my $e = $h->{$k}->{$v} ||= { count => 0, stamp => 0 }; + $e->{count}++; + $e->{stamp} = $t unless $t < $e->{stamp}; +} + +sub dups { + my $h = shift; + return grep { keys($h->{$_}) > 1 } keys($h); +} + +sub vals { + my $h = shift; + return sort { + $h->{$b}->{$order_by} <=> $h->{$a}->{$order_by} + } keys($h); +} + +sub show { + my ($n, $e, $h) = @_; + print "$n <$e> ($h->{$order_by})\n"; +} diff --git a/contrib/subtree/.gitignore b/contrib/subtree/.gitignore index 7e77c9d02..91360a3d7 100644 --- a/contrib/subtree/.gitignore +++ b/contrib/subtree/.gitignore @@ -1,4 +1,5 @@ *~ +git-subtree git-subtree.xml git-subtree.1 mainline diff --git a/contrib/subtree/git-subtree.txt b/contrib/subtree/git-subtree.txt index 0c44fda01..c5bce41ac 100644 --- a/contrib/subtree/git-subtree.txt +++ b/contrib/subtree/git-subtree.txt @@ -93,7 +93,7 @@ pull:: repository. push:: - Does a 'split' (see above) using the <prefix> supplied + Does a 'split' (see below) using the <prefix> supplied and then does a 'git push' to push the result to the repository and refspec. This can be used to push your subtree to different branches of the remote repository. diff --git a/contrib/svn-fe/svn-fe.c b/contrib/svn-fe/svn-fe.c index 35db24f5e..f363505ab 100644 --- a/contrib/svn-fe/svn-fe.c +++ b/contrib/svn-fe/svn-fe.c @@ -10,7 +10,8 @@ int main(int argc, char **argv) { if (svndump_init(NULL)) return 1; - svndump_read((argc > 1) ? argv[1] : NULL); + svndump_read((argc > 1) ? argv[1] : NULL, "refs/heads/master", + "refs/notes/svn/revs"); svndump_deinit(); svndump_reset(); return 0; diff --git a/contrib/svn-fe/svnrdump_sim.py b/contrib/svn-fe/svnrdump_sim.py new file mode 100755 index 000000000..1cfac4a6f --- /dev/null +++ b/contrib/svn-fe/svnrdump_sim.py @@ -0,0 +1,53 @@ +#!/usr/bin/python +""" +Simulates svnrdump by replaying an existing dump from a file, taking care +of the specified revision range. +To simulate incremental imports the environment variable SVNRMAX can be set +to the highest revision that should be available. +""" +import sys, os + + +def getrevlimit(): + var = 'SVNRMAX' + if os.environ.has_key(var): + return os.environ[var] + return None + +def writedump(url, lower, upper): + if url.startswith('sim://'): + filename = url[6:] + if filename[-1] == '/': filename = filename[:-1] #remove terminating slash + else: + raise ValueError('sim:// url required') + f = open(filename, 'r'); + state = 'header' + wroterev = False + while(True): + l = f.readline() + if l == '': break + if state == 'header' and l.startswith('Revision-number: '): + state = 'prefix' + if state == 'prefix' and l == 'Revision-number: %s\n' % lower: + state = 'selection' + if not upper == 'HEAD' and state == 'selection' and l == 'Revision-number: %s\n' % upper: + break; + + if state == 'header' or state == 'selection': + if state == 'selection': wroterev = True + sys.stdout.write(l) + return wroterev + +if __name__ == "__main__": + if not (len(sys.argv) in (3, 4, 5)): + print "usage: %s dump URL -rLOWER:UPPER" + sys.exit(1) + if not sys.argv[1] == 'dump': raise NotImplementedError('only "dump" is suppported.') + url = sys.argv[2] + r = ('0', 'HEAD') + if len(sys.argv) == 4 and sys.argv[3][0:2] == '-r': + r = sys.argv[3][2:].lstrip().split(':') + if not getrevlimit() is None: r[1] = getrevlimit() + if writedump(url, r[0], r[1]): ret = 0 + else: ret = 1 + sys.exit(ret) diff --git a/credential.c b/credential.c index 62d1c5681..e54753c75 100644 --- a/credential.c +++ b/credential.c @@ -172,6 +172,8 @@ int credential_read(struct credential *c, FILE *fp) } else if (!strcmp(key, "path")) { free(c->path); c->path = xstrdup(value); + } else if (!strcmp(key, "url")) { + credential_from_url(c, value); } /* * Ignore other lines; we don't know what they mean, but @@ -191,7 +193,7 @@ static void credential_write_item(FILE *fp, const char *key, const char *value) fprintf(fp, "%s=%s\n", key, value); } -static void credential_write(const struct credential *c, FILE *fp) +void credential_write(const struct credential *c, FILE *fp) { credential_write_item(fp, "protocol", c->protocol); credential_write_item(fp, "host", c->host); diff --git a/credential.h b/credential.h index 96ea41bd1..0c3e85e8e 100644 --- a/credential.h +++ b/credential.h @@ -26,6 +26,7 @@ void credential_approve(struct credential *); void credential_reject(struct credential *); int credential_read(struct credential *, FILE *); +void credential_write(const struct credential *, FILE *); void credential_from_url(struct credential *, const char *url); int credential_match(const struct credential *have, const struct credential *want); @@ -30,6 +30,7 @@ static const char daemon_usage[] = " [--interpolated-path=<path>]\n" " [--reuseaddr] [--pid-file=<file>]\n" " [--(enable|disable|allow-override|forbid-override)=<service>]\n" +" [--access-hook=<path>]\n" " [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n" " [--detach] [--user=<user> [--group=<group>]]\n" " [<directory>...]"; @@ -256,6 +257,71 @@ static int daemon_error(const char *dir, const char *msg) return -1; } +static char *access_hook; + +static int run_access_hook(struct daemon_service *service, const char *dir, const char *path) +{ + struct child_process child; + struct strbuf buf = STRBUF_INIT; + const char *argv[8]; + const char **arg = argv; + char *eol; + int seen_errors = 0; + +#define STRARG(x) ((x) ? (x) : "") + *arg++ = access_hook; + *arg++ = service->name; + *arg++ = path; + *arg++ = STRARG(hostname); + *arg++ = STRARG(canon_hostname); + *arg++ = STRARG(ip_address); + *arg++ = STRARG(tcp_port); + *arg = NULL; +#undef STRARG + + memset(&child, 0, sizeof(child)); + child.use_shell = 1; + child.argv = argv; + child.no_stdin = 1; + child.no_stderr = 1; + child.out = -1; + if (start_command(&child)) { + logerror("daemon access hook '%s' failed to start", + access_hook); + goto error_return; + } + if (strbuf_read(&buf, child.out, 0) < 0) { + logerror("failed to read from pipe to daemon access hook '%s'", + access_hook); + strbuf_reset(&buf); + seen_errors = 1; + } + if (close(child.out) < 0) { + logerror("failed to close pipe to daemon access hook '%s'", + access_hook); + seen_errors = 1; + } + if (finish_command(&child)) + seen_errors = 1; + + if (!seen_errors) { + strbuf_release(&buf); + return 0; + } + +error_return: + strbuf_ltrim(&buf); + if (!buf.len) + strbuf_addstr(&buf, "service rejected"); + eol = strchr(buf.buf, '\n'); + if (eol) + *eol = '\0'; + errno = EACCES; + daemon_error(dir, buf.buf); + strbuf_release(&buf); + return -1; +} + static int run_service(char *dir, struct daemon_service *service) { const char *path; @@ -304,6 +370,13 @@ static int run_service(char *dir, struct daemon_service *service) } /* + * Optionally, a hook can choose to deny access to the + * repository depending on the phase of the moon. + */ + if (access_hook && run_access_hook(service, dir, path)) + return -1; + + /* * We'll ignore SIGTERM from now on, we have a * good client. */ @@ -1142,6 +1215,10 @@ int main(int argc, char **argv) export_all_trees = 1; continue; } + if (!prefixcmp(arg, "--access-hook=")) { + access_hook = arg + 14; + continue; + } if (!prefixcmp(arg, "--timeout=")) { timeout = atoi(arg+10); continue; @@ -15,6 +15,7 @@ #include "sigchain.h" #include "submodule.h" #include "ll-merge.h" +#include "string-list.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -25,7 +26,8 @@ static int diff_detect_rename_default; static int diff_rename_limit_default = 400; static int diff_suppress_blank_empty; -int diff_use_color_default = -1; +static int diff_use_color_default = -1; +static int diff_context_default = 3; static const char *diff_word_regex_cfg; static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; @@ -68,26 +70,30 @@ static int parse_diff_color_slot(const char *var, int ofs) return -1; } -static int parse_dirstat_params(struct diff_options *options, const char *params, +static int parse_dirstat_params(struct diff_options *options, const char *params_string, struct strbuf *errmsg) { - const char *p = params; - int p_len, ret = 0; + char *params_copy = xstrdup(params_string); + struct string_list params = STRING_LIST_INIT_NODUP; + int ret = 0; + int i; - while (*p) { - p_len = strchrnul(p, ',') - p; - if (!memcmp(p, "changes", p_len)) { + if (*params_copy) + string_list_split_in_place(¶ms, params_copy, ',', -1); + for (i = 0; i < params.nr; i++) { + const char *p = params.items[i].string; + if (!strcmp(p, "changes")) { DIFF_OPT_CLR(options, DIRSTAT_BY_LINE); DIFF_OPT_CLR(options, DIRSTAT_BY_FILE); - } else if (!memcmp(p, "lines", p_len)) { + } else if (!strcmp(p, "lines")) { DIFF_OPT_SET(options, DIRSTAT_BY_LINE); DIFF_OPT_CLR(options, DIRSTAT_BY_FILE); - } else if (!memcmp(p, "files", p_len)) { + } else if (!strcmp(p, "files")) { DIFF_OPT_CLR(options, DIRSTAT_BY_LINE); DIFF_OPT_SET(options, DIRSTAT_BY_FILE); - } else if (!memcmp(p, "noncumulative", p_len)) { + } else if (!strcmp(p, "noncumulative")) { DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE); - } else if (!memcmp(p, "cumulative", p_len)) { + } else if (!strcmp(p, "cumulative")) { DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE); } else if (isdigit(*p)) { char *end; @@ -99,27 +105,35 @@ static int parse_dirstat_params(struct diff_options *options, const char *params while (isdigit(*++end)) ; /* nothing */ } - if (end - p == p_len) + if (!*end) options->dirstat_permille = permille; else { - strbuf_addf(errmsg, _(" Failed to parse dirstat cut-off percentage '%.*s'\n"), - p_len, p); + strbuf_addf(errmsg, _(" Failed to parse dirstat cut-off percentage '%s'\n"), + p); ret++; } } else { - strbuf_addf(errmsg, _(" Unknown dirstat parameter '%.*s'\n"), - p_len, p); + strbuf_addf(errmsg, _(" Unknown dirstat parameter '%s'\n"), p); ret++; } - p += p_len; - - if (*p) - p++; /* more parameters, swallow separator */ } + string_list_clear(¶ms, 0); + free(params_copy); return ret; } +static int parse_submodule_params(struct diff_options *options, const char *value) +{ + if (!strcmp(value, "log")) + DIFF_OPT_SET(options, SUBMODULE_LOG); + else if (!strcmp(value, "short")) + DIFF_OPT_CLR(options, SUBMODULE_LOG); + else + return -1; + return 0; +} + static int git_config_rename(const char *var, const char *value) { if (!value) @@ -141,6 +155,12 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) diff_use_color_default = git_config_colorbool(var, value); return 0; } + if (!strcmp(var, "diff.context")) { + diff_context_default = git_config_int(var, value); + if (diff_context_default < 0) + return -1; + return 0; + } if (!strcmp(var, "diff.renames")) { diff_detect_rename_default = git_config_rename(var, value); return 0; @@ -169,6 +189,13 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) if (!strcmp(var, "diff.ignoresubmodules")) handle_ignore_submodules_arg(&default_diff_options, value); + if (!strcmp(var, "diff.submodule")) { + if (parse_submodule_params(&default_diff_options, value)) + warning(_("Unknown value for 'diff.submodule' config variable: '%s'"), + value); + return 0; + } + if (git_color_config(var, value, cb) < 0) return -1; @@ -1300,6 +1327,7 @@ struct diffstat_t { unsigned is_unmerged:1; unsigned is_binary:1; unsigned is_renamed:1; + unsigned is_interesting:1; uintmax_t added, deleted; } **files; }; @@ -1398,11 +1426,11 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions) if (!files) { assert(insertions == 0 && deletions == 0); - return fputs(_(" 0 files changed\n"), fp); + return fprintf(fp, "%s\n", " 0 files changed"); } strbuf_addf(&sb, - Q_(" %d file changed", " %d files changed", files), + (files == 1) ? " %d file changed" : " %d files changed", files); /* @@ -1419,8 +1447,7 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions) * do not translate it. */ strbuf_addf(&sb, - Q_(", %d insertion(+)", ", %d insertions(+)", - insertions), + (insertions == 1) ? ", %d insertion(+)" : ", %d insertions(+)", insertions); } @@ -1430,8 +1457,7 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions) * do not translate it. */ strbuf_addf(&sb, - Q_(", %d deletion(-)", ", %d deletions(-)", - deletions), + (deletions == 1) ? ", %d deletion(-)" : ", %d deletions(-)", deletions); } strbuf_addch(&sb, '\n'); @@ -1471,8 +1497,8 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) for (i = 0; (i < count) && (i < data->nr); i++) { struct diffstat_file *file = data->files[i]; uintmax_t change = file->added + file->deleted; - if (!data->files[i]->is_renamed && - (change == 0)) { + + if (!file->is_interesting && (change == 0)) { count++; /* not shown == room for one more */ continue; } @@ -1499,7 +1525,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) if (max_change < change) max_change = change; } - count = i; /* min(count, data->nr) */ + count = i; /* where we can stop scanning in data->files[] */ /* * We have width = stat_width or term_columns() columns total. @@ -1587,16 +1613,15 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) */ for (i = 0; i < count; i++) { const char *prefix = ""; - char *name = data->files[i]->print_name; - uintmax_t added = data->files[i]->added; - uintmax_t deleted = data->files[i]->deleted; + struct diffstat_file *file = data->files[i]; + char *name = file->print_name; + uintmax_t added = file->added; + uintmax_t deleted = file->deleted; int name_len; - if (!data->files[i]->is_renamed && - (added + deleted == 0)) { - total_files--; + if (!file->is_interesting && (added + deleted == 0)) continue; - } + /* * "scale" the filename */ @@ -1612,7 +1637,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) name = slash; } - if (data->files[i]->is_binary) { + if (file->is_binary) { fprintf(options->file, "%s", line_prefix); show_name(options->file, prefix, name, len); fprintf(options->file, " %*s", number_width, "Bin"); @@ -1629,7 +1654,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) fprintf(options->file, "\n"); continue; } - else if (data->files[i]->is_unmerged) { + else if (file->is_unmerged) { fprintf(options->file, "%s", line_prefix); show_name(options->file, prefix, name, len); fprintf(options->file, " Unmerged\n"); @@ -1641,8 +1666,6 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) */ add = added; del = deleted; - adds += add; - dels += del; if (graph_width <= max_change) { int total = add + del; @@ -1668,16 +1691,24 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) show_graph(options->file, '-', del, del_c, reset); fprintf(options->file, "\n"); } - for (i = count; i < data->nr; i++) { - uintmax_t added = data->files[i]->added; - uintmax_t deleted = data->files[i]->deleted; - if (!data->files[i]->is_renamed && - (added + deleted == 0)) { + + for (i = 0; i < data->nr; i++) { + struct diffstat_file *file = data->files[i]; + uintmax_t added = file->added; + uintmax_t deleted = file->deleted; + + if (file->is_unmerged || + (!file->is_interesting && (added + deleted == 0))) { total_files--; continue; } - adds += added; - dels += deleted; + + if (!file->is_binary) { + adds += added; + dels += deleted; + } + if (i < count) + continue; if (!extra_shown) fprintf(options->file, "%s ...\n", line_prefix); extra_shown = 1; @@ -1697,9 +1728,8 @@ static void show_shortstats(struct diffstat_t *data, struct diff_options *option int added = data->files[i]->added; int deleted= data->files[i]->deleted; - if (data->files[i]->is_unmerged) - continue; - if (!data->files[i]->is_renamed && (added + deleted == 0)) { + if (data->files[i]->is_unmerged || + (!data->files[i]->is_interesting && (added + deleted == 0))) { total_files--; } else if (!data->files[i]->is_binary) { /* don't count bytes */ adds += added; @@ -2215,7 +2245,7 @@ static void builtin_diff(const char *name_a, mmfile_t mf1, mf2; const char *lbl[2]; char *a_one, *b_two; - const char *set = diff_get_color_opt(o, DIFF_METAINFO); + const char *meta = diff_get_color_opt(o, DIFF_METAINFO); const char *reset = diff_get_color_opt(o, DIFF_RESET); const char *a_prefix, *b_prefix; struct userdiff_driver *textconv_one = NULL; @@ -2236,7 +2266,7 @@ static void builtin_diff(const char *name_a, const char *add = diff_get_color_opt(o, DIFF_FILE_NEW); show_submodule_summary(o->file, one ? one->path : two->path, one->sha1, two->sha1, two->dirty_submodule, - del, add, reset); + meta, del, add, reset); return; } @@ -2262,24 +2292,24 @@ static void builtin_diff(const char *name_a, b_two = quote_two(b_prefix, name_b + (*name_b == '/')); lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; - strbuf_addf(&header, "%s%sdiff --git %s %s%s\n", line_prefix, set, a_one, b_two, reset); + strbuf_addf(&header, "%s%sdiff --git %s %s%s\n", line_prefix, meta, a_one, b_two, reset); if (lbl[0][0] == '/') { /* /dev/null */ - strbuf_addf(&header, "%s%snew file mode %06o%s\n", line_prefix, set, two->mode, reset); + strbuf_addf(&header, "%s%snew file mode %06o%s\n", line_prefix, meta, two->mode, reset); if (xfrm_msg) strbuf_addstr(&header, xfrm_msg); must_show_header = 1; } else if (lbl[1][0] == '/') { - strbuf_addf(&header, "%s%sdeleted file mode %06o%s\n", line_prefix, set, one->mode, reset); + strbuf_addf(&header, "%s%sdeleted file mode %06o%s\n", line_prefix, meta, one->mode, reset); if (xfrm_msg) strbuf_addstr(&header, xfrm_msg); must_show_header = 1; } else { if (one->mode != two->mode) { - strbuf_addf(&header, "%s%sold mode %06o%s\n", line_prefix, set, one->mode, reset); - strbuf_addf(&header, "%s%snew mode %06o%s\n", line_prefix, set, two->mode, reset); + strbuf_addf(&header, "%s%sold mode %06o%s\n", line_prefix, meta, one->mode, reset); + strbuf_addf(&header, "%s%snew mode %06o%s\n", line_prefix, meta, two->mode, reset); must_show_header = 1; } if (xfrm_msg) @@ -2399,13 +2429,20 @@ static void builtin_diffstat(const char *name_a, const char *name_b, struct diff_filespec *two, struct diffstat_t *diffstat, struct diff_options *o, - int complete_rewrite) + struct diff_filepair *p) { mmfile_t mf1, mf2; struct diffstat_file *data; int same_contents; + int complete_rewrite = 0; + + if (!DIFF_PAIR_UNMERGED(p)) { + if (p->status == DIFF_STATUS_MODIFIED && p->score) + complete_rewrite = 1; + } data = diffstat_add(diffstat, name_a, name_b); + data->is_interesting = p->status != DIFF_STATUS_UNKNOWN; if (!one || !two) { data->is_unmerged = 1; @@ -3116,11 +3153,10 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o, { const char *name; const char *other; - int complete_rewrite = 0; if (DIFF_PAIR_UNMERGED(p)) { /* unmerged */ - builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, 0); + builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, p); return; } @@ -3133,9 +3169,7 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o, diff_fill_sha1_info(p->one); diff_fill_sha1_info(p->two); - if (p->status == DIFF_STATUS_MODIFIED && p->score) - complete_rewrite = 1; - builtin_diffstat(name, other, p->one, p->two, diffstat, o, complete_rewrite); + builtin_diffstat(name, other, p->one, p->two, diffstat, o, p); } static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) @@ -3172,7 +3206,7 @@ void diff_setup(struct diff_options *options) options->break_opt = -1; options->rename_limit = -1; options->dirstat_permille = diff_dirstat_permille_default; - options->context = 3; + options->context = diff_context_default; DIFF_OPT_SET(options, RENAME_EMPTY); options->change = diff_change; @@ -3468,6 +3502,14 @@ static int parse_dirstat_opt(struct diff_options *options, const char *params) return 1; } +static int parse_submodule_opt(struct diff_options *options, const char *value) +{ + if (parse_submodule_params(options, value)) + die(_("Failed to parse --submodule option parameter: '%s'"), + value); + return 1; +} + int diff_opt_parse(struct diff_options *options, const char **av, int ac) { const char *arg = av[0]; @@ -3648,10 +3690,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) handle_ignore_submodules_arg(options, arg + 20); } else if (!strcmp(arg, "--submodule")) DIFF_OPT_SET(options, SUBMODULE_LOG); - else if (!prefixcmp(arg, "--submodule=")) { - if (!strcmp(arg + 12, "log")) - DIFF_OPT_SET(options, SUBMODULE_LOG); - } + else if (!prefixcmp(arg, "--submodule=")) + return parse_submodule_opt(options, arg + 12); /* misc options */ else if (!strcmp(arg, "-z")) @@ -4873,3 +4913,19 @@ size_t fill_textconv(struct userdiff_driver *driver, return size; } + +void setup_diff_pager(struct diff_options *opt) +{ + /* + * If the user asked for our exit code, then either they want --quiet + * or --exit-code. We should definitely not bother with a pager in the + * former case, as we will generate no output. Since we still properly + * report our exit code even when a pager is run, we _could_ run a + * pager with --exit-code. But since we have not done so historically, + * and because it is easy to find people oneline advising "git diff + * --exit-code" in hooks and other scripts, we do not do so. + */ + if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) && + check_pager_config("diff") != 0) + setup_pager(); +} @@ -243,7 +243,6 @@ extern int parse_long_opt(const char *opt, const char **argv, extern int git_diff_basic_config(const char *var, const char *value, void *cb); extern int git_diff_ui_config(const char *var, const char *value, void *cb); -extern int diff_use_color_default; extern void diff_setup(struct diff_options *); extern int diff_opt_parse(struct diff_options *, const char **, int); extern void diff_setup_done(struct diff_options *); @@ -336,5 +335,6 @@ extern int parse_rename_score(const char **cp_p); extern int print_stat_summary(FILE *fp, int files, int insertions, int deletions); +extern void setup_diff_pager(struct diff_options *); #endif /* DIFF_H */ diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c index ed23eb4bd..b097fa766 100644 --- a/diffcore-pickaxe.c +++ b/diffcore-pickaxe.c @@ -104,10 +104,10 @@ static int diff_grep(struct diff_filepair *p, struct diff_options *o, if (!mf2.ptr) return 0; /* ignore unmerged */ /* created "two" -- does it have what we are looking for? */ - hit = !regexec(regexp, p->two->data, 1, ®match, 0); + hit = !regexec(regexp, mf2.ptr, 1, ®match, 0); } else if (!mf2.ptr) { /* removed "one" -- did it have what we are looking for? */ - hit = !regexec(regexp, p->one->data, 1, ®match, 0); + hit = !regexec(regexp, mf1.ptr, 1, ®match, 0); } else { /* * We have both sides; need to run textual diff and see if @@ -157,19 +157,15 @@ static void diffcore_pickaxe_grep(struct diff_options *o) return; } -static unsigned int contains(struct diff_filespec *one, struct diff_options *o, +static unsigned int contains(mmfile_t *mf, struct diff_options *o, regex_t *regexp, kwset_t kws) { unsigned int cnt; unsigned long sz; const char *data; - if (!o->pickaxe[0]) - return 0; - if (diff_populate_filespec(one, 0)) - return 0; - sz = one->size; - data = one->data; + sz = mf->size; + data = mf->ptr; cnt = 0; if (regexp) { @@ -199,26 +195,53 @@ static unsigned int contains(struct diff_filespec *one, struct diff_options *o, cnt++; } } - diff_free_filespec_data(one); return cnt; } static int has_changes(struct diff_filepair *p, struct diff_options *o, regex_t *regexp, kwset_t kws) { - if (!DIFF_FILE_VALID(p->one)) { - if (!DIFF_FILE_VALID(p->two)) - return 0; /* ignore unmerged */ + struct userdiff_driver *textconv_one = get_textconv(p->one); + struct userdiff_driver *textconv_two = get_textconv(p->two); + mmfile_t mf1, mf2; + int ret; + + if (!o->pickaxe[0]) + return 0; + + /* + * If we have an unmodified pair, we know that the count will be the + * same and don't even have to load the blobs. Unless textconv is in + * play, _and_ we are using two different textconv filters (e.g., + * because a pair is an exact rename with different textconv attributes + * for each side, which might generate different content). + */ + if (textconv_one == textconv_two && diff_unmodified_pair(p)) + return 0; + + fill_one(p->one, &mf1, &textconv_one); + fill_one(p->two, &mf2, &textconv_two); + + if (!mf1.ptr) { + if (!mf2.ptr) + ret = 0; /* ignore unmerged */ /* created */ - return contains(p->two, o, regexp, kws) != 0; - } - if (!DIFF_FILE_VALID(p->two)) - return contains(p->one, o, regexp, kws) != 0; - if (!diff_unmodified_pair(p)) { - return contains(p->one, o, regexp, kws) != - contains(p->two, o, regexp, kws); + ret = contains(&mf2, o, regexp, kws) != 0; } - return 0; + else if (!mf2.ptr) /* removed */ + ret = contains(&mf1, o, regexp, kws) != 0; + else + ret = contains(&mf1, o, regexp, kws) != + contains(&mf2, o, regexp, kws); + + if (textconv_one) + free(mf1.ptr); + if (textconv_two) + free(mf2.ptr); + diff_free_filespec_data(p->one); + diff_free_filespec_data(p->two); + + return ret; } static void diffcore_pickaxe_count(struct diff_options *o) @@ -288,48 +288,89 @@ int match_pathspec_depth(const struct pathspec *ps, return retval; } +/* + * Return the length of the "simple" part of a path match limiter. + */ +static int simple_length(const char *match) +{ + int len = -1; + + for (;;) { + unsigned char c = *match++; + len++; + if (c == '\0' || is_glob_special(c)) + return len; + } +} + static int no_wildcard(const char *string) { - return string[strcspn(string, "*?[{\\")] == '\0'; + return string[simple_length(string)] == '\0'; +} + +void parse_exclude_pattern(const char **pattern, + int *patternlen, + int *flags, + int *nowildcardlen) +{ + const char *p = *pattern; + size_t i, len; + + *flags = 0; + if (*p == '!') { + *flags |= EXC_FLAG_NEGATIVE; + p++; + } + len = strlen(p); + if (len && p[len - 1] == '/') { + len--; + *flags |= EXC_FLAG_MUSTBEDIR; + } + for (i = 0; i < len; i++) { + if (p[i] == '/') + break; + } + if (i == len) + *flags |= EXC_FLAG_NODIR; + *nowildcardlen = simple_length(p); + /* + * we should have excluded the trailing slash from 'p' too, + * but that's one more allocation. Instead just make sure + * nowildcardlen does not exceed real patternlen + */ + if (*nowildcardlen > len) + *nowildcardlen = len; + if (*p == '*' && no_wildcard(p + 1)) + *flags |= EXC_FLAG_ENDSWITH; + *pattern = p; + *patternlen = len; } void add_exclude(const char *string, const char *base, int baselen, struct exclude_list *which) { struct exclude *x; - size_t len; - int to_exclude = 1; - int flags = 0; + int patternlen; + int flags; + int nowildcardlen; - if (*string == '!') { - to_exclude = 0; - string++; - } - len = strlen(string); - if (len && string[len - 1] == '/') { + parse_exclude_pattern(&string, &patternlen, &flags, &nowildcardlen); + if (flags & EXC_FLAG_MUSTBEDIR) { char *s; - x = xmalloc(sizeof(*x) + len); + x = xmalloc(sizeof(*x) + patternlen + 1); s = (char *)(x+1); - memcpy(s, string, len - 1); - s[len - 1] = '\0'; - string = s; + memcpy(s, string, patternlen); + s[patternlen] = '\0'; x->pattern = s; - flags = EXC_FLAG_MUSTBEDIR; } else { x = xmalloc(sizeof(*x)); x->pattern = string; } - x->to_exclude = to_exclude; - x->patternlen = strlen(string); + x->patternlen = patternlen; + x->nowildcardlen = nowildcardlen; x->base = base; x->baselen = baselen; x->flags = flags; - if (!strchr(string, '/')) - x->flags |= EXC_FLAG_NODIR; - if (no_wildcard(string)) - x->flags |= EXC_FLAG_NOWILDCARD; - if (*string == '*' && no_wildcard(string+1)) - x->flags |= EXC_FLAG_ENDSWITH; ALLOC_GROW(which->excludes, which->nr + 1, which->alloc); which->excludes[which->nr++] = x; } @@ -383,6 +424,8 @@ int add_excludes_from_file_to_list(const char *fname, fd = open(fname, O_RDONLY); if (fd < 0 || fstat(fd, &st) < 0) { + if (errno != ENOENT) + warn_on_inaccessible(fname); if (0 <= fd) close(fd); if (!check_index || @@ -489,6 +532,72 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen) dir->basebuf[baselen] = '\0'; } +int match_basename(const char *basename, int basenamelen, + const char *pattern, int prefix, int patternlen, + int flags) +{ + if (prefix == patternlen) { + if (!strcmp_icase(pattern, basename)) + return 1; + } else if (flags & EXC_FLAG_ENDSWITH) { + if (patternlen - 1 <= basenamelen && + !strcmp_icase(pattern + 1, + basename + basenamelen - patternlen + 1)) + return 1; + } else { + if (fnmatch_icase(pattern, basename, 0) == 0) + return 1; + } + return 0; +} + +int match_pathname(const char *pathname, int pathlen, + const char *base, int baselen, + const char *pattern, int prefix, int patternlen, + int flags) +{ + const char *name; + int namelen; + + /* + * match with FNM_PATHNAME; the pattern has base implicitly + * in front of it. + */ + if (*pattern == '/') { + pattern++; + prefix--; + } + + /* + * baselen does not count the trailing slash. base[] may or + * may not end with a trailing slash though. + */ + if (pathlen < baselen + 1 || + (baselen && pathname[baselen] != '/') || + strncmp_icase(pathname, base, baselen)) + return 0; + + namelen = baselen ? pathlen - baselen - 1 : pathlen; + name = pathname + pathlen - namelen; + + if (prefix) { + /* + * if the non-wildcard part is longer than the + * remaining pathname, surely it cannot match. + */ + if (prefix > namelen) + return 0; + + if (strncmp_icase(pattern, name, prefix)) + return 0; + pattern += prefix; + name += prefix; + namelen -= prefix; + } + + return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0; +} + /* Scan the list and let the last match determine the fate. * Return 1 for exclude, 0 for include and -1 for undecided. */ @@ -498,57 +607,36 @@ int excluded_from_list(const char *pathname, { int i; - if (el->nr) { - for (i = el->nr - 1; 0 <= i; i--) { - struct exclude *x = el->excludes[i]; - const char *exclude = x->pattern; - int to_exclude = x->to_exclude; - - if (x->flags & EXC_FLAG_MUSTBEDIR) { - if (*dtype == DT_UNKNOWN) - *dtype = get_dtype(NULL, pathname, pathlen); - if (*dtype != DT_DIR) - continue; - } + if (!el->nr) + return -1; /* undefined */ - if (x->flags & EXC_FLAG_NODIR) { - /* match basename */ - if (x->flags & EXC_FLAG_NOWILDCARD) { - if (!strcmp_icase(exclude, basename)) - return to_exclude; - } else if (x->flags & EXC_FLAG_ENDSWITH) { - if (x->patternlen - 1 <= pathlen && - !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1)) - return to_exclude; - } else { - if (fnmatch_icase(exclude, basename, 0) == 0) - return to_exclude; - } - } - else { - /* match with FNM_PATHNAME: - * exclude has base (baselen long) implicitly - * in front of it. - */ - int baselen = x->baselen; - if (*exclude == '/') - exclude++; - - if (pathlen < baselen || - (baselen && pathname[baselen-1] != '/') || - strncmp_icase(pathname, x->base, baselen)) - continue; - - if (x->flags & EXC_FLAG_NOWILDCARD) { - if (!strcmp_icase(exclude, pathname + baselen)) - return to_exclude; - } else { - if (fnmatch_icase(exclude, pathname+baselen, - FNM_PATHNAME) == 0) - return to_exclude; - } - } + for (i = el->nr - 1; 0 <= i; i--) { + struct exclude *x = el->excludes[i]; + const char *exclude = x->pattern; + int to_exclude = x->flags & EXC_FLAG_NEGATIVE ? 0 : 1; + int prefix = x->nowildcardlen; + + if (x->flags & EXC_FLAG_MUSTBEDIR) { + if (*dtype == DT_UNKNOWN) + *dtype = get_dtype(NULL, pathname, pathlen); + if (*dtype != DT_DIR) + continue; } + + if (x->flags & EXC_FLAG_NODIR) { + if (match_basename(basename, + pathlen - (basename - pathname), + exclude, prefix, x->patternlen, + x->flags)) + return to_exclude; + continue; + } + + assert(x->baselen == 0 || x->base[x->baselen - 1] == '/'); + if (match_pathname(pathname, pathlen, + x->base, x->baselen ? x->baselen - 1 : 0, + exclude, prefix, x->patternlen, x->flags)) + return to_exclude; } return -1; /* undecided */ } @@ -1055,21 +1143,6 @@ static int cmp_name(const void *p1, const void *p2) e2->name, e2->len); } -/* - * Return the length of the "simple" part of a path match limiter. - */ -static int simple_length(const char *match) -{ - int len = -1; - - for (;;) { - unsigned char c = *match++; - len++; - if (c == '\0' || is_glob_special(c)) - return len; - } -} - static struct path_simplify *create_simplify(const char **pathspec) { int nr, alloc = 0; @@ -1292,12 +1365,17 @@ int remove_dir_recursively(struct strbuf *path, int flag) void setup_standard_excludes(struct dir_struct *dir) { const char *path; + char *xdg_path; dir->exclude_per_dir = ".gitignore"; path = git_path("info/exclude"); - if (!access(path, R_OK)) + if (!excludes_file) { + home_config_paths(NULL, &xdg_path, "ignore"); + excludes_file = xdg_path; + } + if (!access_or_warn(path, R_OK)) add_excludes_from_file(dir, path); - if (excludes_file && !access(excludes_file, R_OK)) + if (excludes_file && !access_or_warn(excludes_file, R_OK)) add_excludes_from_file(dir, excludes_file); } @@ -9,9 +9,9 @@ struct dir_entry { }; #define EXC_FLAG_NODIR 1 -#define EXC_FLAG_NOWILDCARD 2 #define EXC_FLAG_ENDSWITH 4 #define EXC_FLAG_MUSTBEDIR 8 +#define EXC_FLAG_NEGATIVE 16 struct exclude_list { int nr; @@ -19,9 +19,9 @@ struct exclude_list { struct exclude { const char *pattern; int patternlen; + int nowildcardlen; const char *base; int baselen; - int to_exclude; int flags; } **excludes; }; @@ -81,6 +81,16 @@ extern int excluded_from_list(const char *pathname, int pathlen, const char *bas struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len); /* + * these implement the matching logic for dir.c:excluded_from_list and + * attr.c:path_matches() + */ +extern int match_basename(const char *, int, + const char *, int, int, int); +extern int match_pathname(const char *, int, + const char *, int, + const char *, int, int, int); + +/* * The excluded() API is meant for callers that check each level of leading * directory hierarchies with excluded() to avoid recursing into excluded * directories. Callers that do not do so should use this API instead. @@ -97,6 +107,7 @@ extern int path_excluded(struct path_exclude_check *, const char *, int namelen, extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, char **buf_p, struct exclude_list *which, int check_index); extern void add_excludes_from_file(struct dir_struct *, const char *fname); +extern void parse_exclude_pattern(const char **string, int *patternlen, int *flags, int *nowildcardlen); extern void add_exclude(const char *string, const char *base, int baselen, struct exclude_list *which); extern void free_excludes(struct exclude_list *el); @@ -1,6 +1,7 @@ #include "cache.h" #include "strbuf.h" #include "run-command.h" +#include "sigchain.h" #ifndef DEFAULT_EDITOR #define DEFAULT_EDITOR "vi" @@ -37,8 +38,25 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en if (strcmp(editor, ":")) { const char *args[] = { editor, path, NULL }; + struct child_process p; + int ret, sig; - if (run_command_v_opt_cd_env(args, RUN_USING_SHELL, NULL, env)) + memset(&p, 0, sizeof(p)); + p.argv = args; + p.env = env; + p.use_shell = 1; + if (start_command(&p) < 0) + return error("unable to start editor '%s'", editor); + + sigchain_push(SIGINT, SIG_IGN); + sigchain_push(SIGQUIT, SIG_IGN); + ret = finish_command(&p); + sig = ret + 128; + sigchain_pop(SIGINT); + sigchain_pop(SIGQUIT); + if (sig == SIGINT || sig == SIGQUIT) + raise(sig); + if (ret) return error("There was a problem with the editor '%s'.", editor); } diff --git a/environment.c b/environment.c index 669e498f5..85edd7f95 100644 --- a/environment.c +++ b/environment.c @@ -58,6 +58,7 @@ char *notes_ref_name; int grafts_replace_parents = 1; int core_apply_sparse_checkout; int merge_log_config = -1; +int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */ struct startup_info *startup_info; unsigned long pack_size_limit_cfg; diff --git a/fast-import.c b/fast-import.c index eed97c8fa..c2a814ec6 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1691,7 +1691,7 @@ static int update_branch(struct branch *b) return error("Branch %s is missing commits.", b->name); } - if (!in_merge_bases(old_cmit, &new_cmit, 1)) { + if (!in_merge_bases(old_cmit, new_cmit)) { unlock_ref(lock); warning("Not updating %s" " (new tip %s does not contain %s)", diff --git a/fetch-pack.c b/fetch-pack.c new file mode 100644 index 000000000..099ff4ddf --- /dev/null +++ b/fetch-pack.c @@ -0,0 +1,951 @@ +#include "cache.h" +#include "refs.h" +#include "pkt-line.h" +#include "commit.h" +#include "tag.h" +#include "exec_cmd.h" +#include "pack.h" +#include "sideband.h" +#include "fetch-pack.h" +#include "remote.h" +#include "run-command.h" +#include "transport.h" +#include "version.h" + +static int transfer_unpack_limit = -1; +static int fetch_unpack_limit = -1; +static int unpack_limit = 100; +static int prefer_ofs_delta = 1; +static int no_done; +static int fetch_fsck_objects = -1; +static int transfer_fsck_objects = -1; +static int agent_supported; + +#define COMPLETE (1U << 0) +#define COMMON (1U << 1) +#define COMMON_REF (1U << 2) +#define SEEN (1U << 3) +#define POPPED (1U << 4) + +static int marked; + +/* + * After sending this many "have"s if we do not get any new ACK , we + * give up traversing our history. + */ +#define MAX_IN_VAIN 256 + +static struct commit_list *rev_list; +static int non_common_revs, multi_ack, use_sideband; + +static void rev_list_push(struct commit *commit, int mark) +{ + if (!(commit->object.flags & mark)) { + commit->object.flags |= mark; + + if (!(commit->object.parsed)) + if (parse_commit(commit)) + return; + + commit_list_insert_by_date(commit, &rev_list); + + if (!(commit->object.flags & COMMON)) + non_common_revs++; + } +} + +static int rev_list_insert_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) +{ + struct object *o = deref_tag(parse_object(sha1), refname, 0); + + if (o && o->type == OBJ_COMMIT) + rev_list_push((struct commit *)o, SEEN); + + return 0; +} + +static int clear_marks(const char *refname, const unsigned char *sha1, int flag, void *cb_data) +{ + struct object *o = deref_tag(parse_object(sha1), refname, 0); + + if (o && o->type == OBJ_COMMIT) + clear_commit_marks((struct commit *)o, + COMMON | COMMON_REF | SEEN | POPPED); + return 0; +} + +/* + This function marks a rev and its ancestors as common. + In some cases, it is desirable to mark only the ancestors (for example + when only the server does not yet know that they are common). +*/ + +static void mark_common(struct commit *commit, + int ancestors_only, int dont_parse) +{ + if (commit != NULL && !(commit->object.flags & COMMON)) { + struct object *o = (struct object *)commit; + + if (!ancestors_only) + o->flags |= COMMON; + + if (!(o->flags & SEEN)) + rev_list_push(commit, SEEN); + else { + struct commit_list *parents; + + if (!ancestors_only && !(o->flags & POPPED)) + non_common_revs--; + if (!o->parsed && !dont_parse) + if (parse_commit(commit)) + return; + + for (parents = commit->parents; + parents; + parents = parents->next) + mark_common(parents->item, 0, dont_parse); + } + } +} + +/* + Get the next rev to send, ignoring the common. +*/ + +static const unsigned char *get_rev(void) +{ + struct commit *commit = NULL; + + while (commit == NULL) { + unsigned int mark; + struct commit_list *parents; + + if (rev_list == NULL || non_common_revs == 0) + return NULL; + + commit = rev_list->item; + if (!commit->object.parsed) + parse_commit(commit); + parents = commit->parents; + + commit->object.flags |= POPPED; + if (!(commit->object.flags & COMMON)) + non_common_revs--; + + if (commit->object.flags & COMMON) { + /* do not send "have", and ignore ancestors */ + commit = NULL; + mark = COMMON | SEEN; + } else if (commit->object.flags & COMMON_REF) + /* send "have", and ignore ancestors */ + mark = COMMON | SEEN; + else + /* send "have", also for its ancestors */ + mark = SEEN; + + while (parents) { + if (!(parents->item->object.flags & SEEN)) + rev_list_push(parents->item, mark); + if (mark & COMMON) + mark_common(parents->item, 1, 0); + parents = parents->next; + } + + rev_list = rev_list->next; + } + + return commit->object.sha1; +} + +enum ack_type { + NAK = 0, + ACK, + ACK_continue, + ACK_common, + ACK_ready +}; + +static void consume_shallow_list(struct fetch_pack_args *args, int fd) +{ + if (args->stateless_rpc && args->depth > 0) { + /* If we sent a depth we will get back "duplicate" + * shallow and unshallow commands every time there + * is a block of have lines exchanged. + */ + char line[1000]; + while (packet_read_line(fd, line, sizeof(line))) { + if (!prefixcmp(line, "shallow ")) + continue; + if (!prefixcmp(line, "unshallow ")) + continue; + die("git fetch-pack: expected shallow list"); + } + } +} + +struct write_shallow_data { + struct strbuf *out; + int use_pack_protocol; + int count; +}; + +static int write_one_shallow(const struct commit_graft *graft, void *cb_data) +{ + struct write_shallow_data *data = cb_data; + const char *hex = sha1_to_hex(graft->sha1); + data->count++; + if (data->use_pack_protocol) + packet_buf_write(data->out, "shallow %s", hex); + else { + strbuf_addstr(data->out, hex); + strbuf_addch(data->out, '\n'); + } + return 0; +} + +static int write_shallow_commits(struct strbuf *out, int use_pack_protocol) +{ + struct write_shallow_data data; + data.out = out; + data.use_pack_protocol = use_pack_protocol; + data.count = 0; + for_each_commit_graft(write_one_shallow, &data); + return data.count; +} + +static enum ack_type get_ack(int fd, unsigned char *result_sha1) +{ + static char line[1000]; + int len = packet_read_line(fd, line, sizeof(line)); + + if (!len) + die("git fetch-pack: expected ACK/NAK, got EOF"); + if (line[len-1] == '\n') + line[--len] = 0; + if (!strcmp(line, "NAK")) + return NAK; + if (!prefixcmp(line, "ACK ")) { + if (!get_sha1_hex(line+4, result_sha1)) { + if (strstr(line+45, "continue")) + return ACK_continue; + if (strstr(line+45, "common")) + return ACK_common; + if (strstr(line+45, "ready")) + return ACK_ready; + return ACK; + } + } + die("git fetch_pack: expected ACK/NAK, got '%s'", line); +} + +static void send_request(struct fetch_pack_args *args, + int fd, struct strbuf *buf) +{ + if (args->stateless_rpc) { + send_sideband(fd, -1, buf->buf, buf->len, LARGE_PACKET_MAX); + packet_flush(fd); + } else + safe_write(fd, buf->buf, buf->len); +} + +static void insert_one_alternate_ref(const struct ref *ref, void *unused) +{ + rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL); +} + +#define INITIAL_FLUSH 16 +#define PIPESAFE_FLUSH 32 +#define LARGE_FLUSH 1024 + +static int next_flush(struct fetch_pack_args *args, int count) +{ + int flush_limit = args->stateless_rpc ? LARGE_FLUSH : PIPESAFE_FLUSH; + + if (count < flush_limit) + count <<= 1; + else + count += flush_limit; + return count; +} + +static int find_common(struct fetch_pack_args *args, + int fd[2], unsigned char *result_sha1, + struct ref *refs) +{ + int fetching; + int count = 0, flushes = 0, flush_at = INITIAL_FLUSH, retval; + const unsigned char *sha1; + unsigned in_vain = 0; + int got_continue = 0; + int got_ready = 0; + struct strbuf req_buf = STRBUF_INIT; + size_t state_len = 0; + + if (args->stateless_rpc && multi_ack == 1) + die("--stateless-rpc requires multi_ack_detailed"); + if (marked) + for_each_ref(clear_marks, NULL); + marked = 1; + + for_each_ref(rev_list_insert_ref, NULL); + for_each_alternate_ref(insert_one_alternate_ref, NULL); + + fetching = 0; + for ( ; refs ; refs = refs->next) { + unsigned char *remote = refs->old_sha1; + const char *remote_hex; + struct object *o; + + /* + * If that object is complete (i.e. it is an ancestor of a + * local ref), we tell them we have it but do not have to + * tell them about its ancestors, which they already know + * about. + * + * We use lookup_object here because we are only + * interested in the case we *know* the object is + * reachable and we have already scanned it. + */ + if (((o = lookup_object(remote)) != NULL) && + (o->flags & COMPLETE)) { + continue; + } + + remote_hex = sha1_to_hex(remote); + if (!fetching) { + struct strbuf c = STRBUF_INIT; + if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed"); + if (multi_ack == 1) strbuf_addstr(&c, " multi_ack"); + if (no_done) strbuf_addstr(&c, " no-done"); + if (use_sideband == 2) strbuf_addstr(&c, " side-band-64k"); + if (use_sideband == 1) strbuf_addstr(&c, " side-band"); + if (args->use_thin_pack) strbuf_addstr(&c, " thin-pack"); + if (args->no_progress) strbuf_addstr(&c, " no-progress"); + if (args->include_tag) strbuf_addstr(&c, " include-tag"); + if (prefer_ofs_delta) strbuf_addstr(&c, " ofs-delta"); + if (agent_supported) strbuf_addf(&c, " agent=%s", + git_user_agent_sanitized()); + packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf); + strbuf_release(&c); + } else + packet_buf_write(&req_buf, "want %s\n", remote_hex); + fetching++; + } + + if (!fetching) { + strbuf_release(&req_buf); + packet_flush(fd[1]); + return 1; + } + + if (is_repository_shallow()) + write_shallow_commits(&req_buf, 1); + if (args->depth > 0) + packet_buf_write(&req_buf, "deepen %d", args->depth); + packet_buf_flush(&req_buf); + state_len = req_buf.len; + + if (args->depth > 0) { + char line[1024]; + unsigned char sha1[20]; + + send_request(args, fd[1], &req_buf); + while (packet_read_line(fd[0], line, sizeof(line))) { + if (!prefixcmp(line, "shallow ")) { + if (get_sha1_hex(line + 8, sha1)) + die("invalid shallow line: %s", line); + register_shallow(sha1); + continue; + } + if (!prefixcmp(line, "unshallow ")) { + if (get_sha1_hex(line + 10, sha1)) + die("invalid unshallow line: %s", line); + if (!lookup_object(sha1)) + die("object not found: %s", line); + /* make sure that it is parsed as shallow */ + if (!parse_object(sha1)) + die("error in object: %s", line); + if (unregister_shallow(sha1)) + die("no shallow found: %s", line); + continue; + } + die("expected shallow/unshallow, got %s", line); + } + } else if (!args->stateless_rpc) + send_request(args, fd[1], &req_buf); + + if (!args->stateless_rpc) { + /* If we aren't using the stateless-rpc interface + * we don't need to retain the headers. + */ + strbuf_setlen(&req_buf, 0); + state_len = 0; + } + + flushes = 0; + retval = -1; + while ((sha1 = get_rev())) { + packet_buf_write(&req_buf, "have %s\n", sha1_to_hex(sha1)); + if (args->verbose) + fprintf(stderr, "have %s\n", sha1_to_hex(sha1)); + in_vain++; + if (flush_at <= ++count) { + int ack; + + packet_buf_flush(&req_buf); + send_request(args, fd[1], &req_buf); + strbuf_setlen(&req_buf, state_len); + flushes++; + flush_at = next_flush(args, count); + + /* + * We keep one window "ahead" of the other side, and + * will wait for an ACK only on the next one + */ + if (!args->stateless_rpc && count == INITIAL_FLUSH) + continue; + + consume_shallow_list(args, fd[0]); + do { + ack = get_ack(fd[0], result_sha1); + if (args->verbose && ack) + fprintf(stderr, "got ack %d %s\n", ack, + sha1_to_hex(result_sha1)); + switch (ack) { + case ACK: + flushes = 0; + multi_ack = 0; + retval = 0; + goto done; + case ACK_common: + case ACK_ready: + case ACK_continue: { + struct commit *commit = + lookup_commit(result_sha1); + if (!commit) + die("invalid commit %s", sha1_to_hex(result_sha1)); + if (args->stateless_rpc + && ack == ACK_common + && !(commit->object.flags & COMMON)) { + /* We need to replay the have for this object + * on the next RPC request so the peer knows + * it is in common with us. + */ + const char *hex = sha1_to_hex(result_sha1); + packet_buf_write(&req_buf, "have %s\n", hex); + state_len = req_buf.len; + } + mark_common(commit, 0, 1); + retval = 0; + in_vain = 0; + got_continue = 1; + if (ack == ACK_ready) { + rev_list = NULL; + got_ready = 1; + } + break; + } + } + } while (ack); + flushes--; + if (got_continue && MAX_IN_VAIN < in_vain) { + if (args->verbose) + fprintf(stderr, "giving up\n"); + break; /* give up */ + } + } + } +done: + if (!got_ready || !no_done) { + packet_buf_write(&req_buf, "done\n"); + send_request(args, fd[1], &req_buf); + } + if (args->verbose) + fprintf(stderr, "done\n"); + if (retval != 0) { + multi_ack = 0; + flushes++; + } + strbuf_release(&req_buf); + + consume_shallow_list(args, fd[0]); + while (flushes || multi_ack) { + int ack = get_ack(fd[0], result_sha1); + if (ack) { + if (args->verbose) + fprintf(stderr, "got ack (%d) %s\n", ack, + sha1_to_hex(result_sha1)); + if (ack == ACK) + return 0; + multi_ack = 1; + continue; + } + flushes--; + } + /* it is no error to fetch into a completely empty repo */ + return count ? retval : 0; +} + +static struct commit_list *complete; + +static int mark_complete(const char *refname, const unsigned char *sha1, int flag, void *cb_data) +{ + struct object *o = parse_object(sha1); + + while (o && o->type == OBJ_TAG) { + struct tag *t = (struct tag *) o; + if (!t->tagged) + break; /* broken repository */ + o->flags |= COMPLETE; + o = parse_object(t->tagged->sha1); + } + if (o && o->type == OBJ_COMMIT) { + struct commit *commit = (struct commit *)o; + if (!(commit->object.flags & COMPLETE)) { + commit->object.flags |= COMPLETE; + commit_list_insert_by_date(commit, &complete); + } + } + return 0; +} + +static void mark_recent_complete_commits(struct fetch_pack_args *args, + unsigned long cutoff) +{ + while (complete && cutoff <= complete->item->date) { + if (args->verbose) + fprintf(stderr, "Marking %s as complete\n", + sha1_to_hex(complete->item->object.sha1)); + pop_most_recent_commit(&complete, COMPLETE); + } +} + +static int non_matching_ref(struct string_list_item *item, void *unused) +{ + if (item->util) { + item->util = NULL; + return 0; + } + else + return 1; +} + +static void filter_refs(struct fetch_pack_args *args, + struct ref **refs, struct string_list *sought) +{ + struct ref *newlist = NULL; + struct ref **newtail = &newlist; + struct ref *ref, *next; + int sought_pos; + + sought_pos = 0; + for (ref = *refs; ref; ref = next) { + int keep = 0; + next = ref->next; + if (!memcmp(ref->name, "refs/", 5) && + check_refname_format(ref->name + 5, 0)) + ; /* trash */ + else { + while (sought_pos < sought->nr) { + int cmp = strcmp(ref->name, sought->items[sought_pos].string); + if (cmp < 0) + break; /* definitely do not have it */ + else if (cmp == 0) { + keep = 1; /* definitely have it */ + sought->items[sought_pos++].util = "matched"; + break; + } + else + sought_pos++; /* might have it; keep looking */ + } + } + + if (! keep && args->fetch_all && + (!args->depth || prefixcmp(ref->name, "refs/tags/"))) + keep = 1; + + if (keep) { + *newtail = ref; + ref->next = NULL; + newtail = &ref->next; + } else { + free(ref); + } + } + + filter_string_list(sought, 0, non_matching_ref, NULL); + *refs = newlist; +} + +static void mark_alternate_complete(const struct ref *ref, void *unused) +{ + mark_complete(NULL, ref->old_sha1, 0, NULL); +} + +static int everything_local(struct fetch_pack_args *args, + struct ref **refs, struct string_list *sought) +{ + struct ref *ref; + int retval; + unsigned long cutoff = 0; + + save_commit_buffer = 0; + + for (ref = *refs; ref; ref = ref->next) { + struct object *o; + + o = parse_object(ref->old_sha1); + if (!o) + continue; + + /* We already have it -- which may mean that we were + * in sync with the other side at some time after + * that (it is OK if we guess wrong here). + */ + if (o->type == OBJ_COMMIT) { + struct commit *commit = (struct commit *)o; + if (!cutoff || cutoff < commit->date) + cutoff = commit->date; + } + } + + if (!args->depth) { + for_each_ref(mark_complete, NULL); + for_each_alternate_ref(mark_alternate_complete, NULL); + if (cutoff) + mark_recent_complete_commits(args, cutoff); + } + + /* + * Mark all complete remote refs as common refs. + * Don't mark them common yet; the server has to be told so first. + */ + for (ref = *refs; ref; ref = ref->next) { + struct object *o = deref_tag(lookup_object(ref->old_sha1), + NULL, 0); + + if (!o || o->type != OBJ_COMMIT || !(o->flags & COMPLETE)) + continue; + + if (!(o->flags & SEEN)) { + rev_list_push((struct commit *)o, COMMON_REF | SEEN); + + mark_common((struct commit *)o, 1, 1); + } + } + + filter_refs(args, refs, sought); + + for (retval = 1, ref = *refs; ref ; ref = ref->next) { + const unsigned char *remote = ref->old_sha1; + unsigned char local[20]; + struct object *o; + + o = lookup_object(remote); + if (!o || !(o->flags & COMPLETE)) { + retval = 0; + if (!args->verbose) + continue; + fprintf(stderr, + "want %s (%s)\n", sha1_to_hex(remote), + ref->name); + continue; + } + + hashcpy(ref->new_sha1, local); + if (!args->verbose) + continue; + fprintf(stderr, + "already have %s (%s)\n", sha1_to_hex(remote), + ref->name); + } + return retval; +} + +static int sideband_demux(int in, int out, void *data) +{ + int *xd = data; + + int ret = recv_sideband("fetch-pack", xd[0], out); + close(out); + return ret; +} + +static int get_pack(struct fetch_pack_args *args, + int xd[2], char **pack_lockfile) +{ + struct async demux; + const char *argv[20]; + char keep_arg[256]; + char hdr_arg[256]; + const char **av; + int do_keep = args->keep_pack; + struct child_process cmd; + + memset(&demux, 0, sizeof(demux)); + if (use_sideband) { + /* xd[] is talking with upload-pack; subprocess reads from + * xd[0], spits out band#2 to stderr, and feeds us band#1 + * through demux->out. + */ + demux.proc = sideband_demux; + demux.data = xd; + demux.out = -1; + if (start_async(&demux)) + die("fetch-pack: unable to fork off sideband" + " demultiplexer"); + } + else + demux.out = xd[0]; + + memset(&cmd, 0, sizeof(cmd)); + cmd.argv = argv; + av = argv; + *hdr_arg = 0; + if (!args->keep_pack && unpack_limit) { + struct pack_header header; + + if (read_pack_header(demux.out, &header)) + die("protocol error: bad pack header"); + snprintf(hdr_arg, sizeof(hdr_arg), + "--pack_header=%"PRIu32",%"PRIu32, + ntohl(header.hdr_version), ntohl(header.hdr_entries)); + if (ntohl(header.hdr_entries) < unpack_limit) + do_keep = 0; + else + do_keep = 1; + } + + if (do_keep) { + if (pack_lockfile) + cmd.out = -1; + *av++ = "index-pack"; + *av++ = "--stdin"; + if (!args->quiet && !args->no_progress) + *av++ = "-v"; + if (args->use_thin_pack) + *av++ = "--fix-thin"; + if (args->lock_pack || unpack_limit) { + int s = sprintf(keep_arg, + "--keep=fetch-pack %"PRIuMAX " on ", (uintmax_t) getpid()); + if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) + strcpy(keep_arg + s, "localhost"); + *av++ = keep_arg; + } + } + else { + *av++ = "unpack-objects"; + if (args->quiet || args->no_progress) + *av++ = "-q"; + } + if (*hdr_arg) + *av++ = hdr_arg; + if (fetch_fsck_objects >= 0 + ? fetch_fsck_objects + : transfer_fsck_objects >= 0 + ? transfer_fsck_objects + : 0) + *av++ = "--strict"; + *av++ = NULL; + + cmd.in = demux.out; + cmd.git_cmd = 1; + if (start_command(&cmd)) + die("fetch-pack: unable to fork off %s", argv[0]); + if (do_keep && pack_lockfile) { + *pack_lockfile = index_pack_lockfile(cmd.out); + close(cmd.out); + } + + if (finish_command(&cmd)) + die("%s failed", argv[0]); + if (use_sideband && finish_async(&demux)) + die("error in sideband demultiplexer"); + return 0; +} + +static struct ref *do_fetch_pack(struct fetch_pack_args *args, + int fd[2], + const struct ref *orig_ref, + struct string_list *sought, + char **pack_lockfile) +{ + struct ref *ref = copy_ref_list(orig_ref); + unsigned char sha1[20]; + const char *agent_feature; + int agent_len; + + sort_ref_list(&ref, ref_compare_name); + + if (is_repository_shallow() && !server_supports("shallow")) + die("Server does not support shallow clients"); + if (server_supports("multi_ack_detailed")) { + if (args->verbose) + fprintf(stderr, "Server supports multi_ack_detailed\n"); + multi_ack = 2; + if (server_supports("no-done")) { + if (args->verbose) + fprintf(stderr, "Server supports no-done\n"); + if (args->stateless_rpc) + no_done = 1; + } + } + else if (server_supports("multi_ack")) { + if (args->verbose) + fprintf(stderr, "Server supports multi_ack\n"); + multi_ack = 1; + } + if (server_supports("side-band-64k")) { + if (args->verbose) + fprintf(stderr, "Server supports side-band-64k\n"); + use_sideband = 2; + } + else if (server_supports("side-band")) { + if (args->verbose) + fprintf(stderr, "Server supports side-band\n"); + use_sideband = 1; + } + if (!server_supports("thin-pack")) + args->use_thin_pack = 0; + if (!server_supports("no-progress")) + args->no_progress = 0; + if (!server_supports("include-tag")) + args->include_tag = 0; + if (server_supports("ofs-delta")) { + if (args->verbose) + fprintf(stderr, "Server supports ofs-delta\n"); + } else + prefer_ofs_delta = 0; + + if ((agent_feature = server_feature_value("agent", &agent_len))) { + agent_supported = 1; + if (args->verbose && agent_len) + fprintf(stderr, "Server version is %.*s\n", + agent_len, agent_feature); + } + + if (everything_local(args, &ref, sought)) { + packet_flush(fd[1]); + goto all_done; + } + if (find_common(args, fd, sha1, ref) < 0) + if (!args->keep_pack) + /* When cloning, it is not unusual to have + * no common commit. + */ + warning("no common commits"); + + if (args->stateless_rpc) + packet_flush(fd[1]); + if (get_pack(args, fd, pack_lockfile)) + die("git fetch-pack: fetch failed."); + + all_done: + return ref; +} + +static int fetch_pack_config(const char *var, const char *value, void *cb) +{ + if (strcmp(var, "fetch.unpacklimit") == 0) { + fetch_unpack_limit = git_config_int(var, value); + return 0; + } + + if (strcmp(var, "transfer.unpacklimit") == 0) { + transfer_unpack_limit = git_config_int(var, value); + return 0; + } + + if (strcmp(var, "repack.usedeltabaseoffset") == 0) { + prefer_ofs_delta = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "fetch.fsckobjects")) { + fetch_fsck_objects = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "transfer.fsckobjects")) { + transfer_fsck_objects = git_config_bool(var, value); + return 0; + } + + return git_default_config(var, value, cb); +} + +static struct lock_file lock; + +static void fetch_pack_setup(void) +{ + static int did_setup; + if (did_setup) + return; + git_config(fetch_pack_config, NULL); + if (0 <= transfer_unpack_limit) + unpack_limit = transfer_unpack_limit; + else if (0 <= fetch_unpack_limit) + unpack_limit = fetch_unpack_limit; + did_setup = 1; +} + +struct ref *fetch_pack(struct fetch_pack_args *args, + int fd[], struct child_process *conn, + const struct ref *ref, + const char *dest, + struct string_list *sought, + char **pack_lockfile) +{ + struct stat st; + struct ref *ref_cpy; + + fetch_pack_setup(); + if (args->depth > 0) { + if (stat(git_path("shallow"), &st)) + st.st_mtime = 0; + } + + if (sought->nr) { + sort_string_list(sought); + string_list_remove_duplicates(sought, 0); + } + + if (!ref) { + packet_flush(fd[1]); + die("no matching remote head"); + } + ref_cpy = do_fetch_pack(args, fd, ref, sought, pack_lockfile); + + if (args->depth > 0) { + struct cache_time mtime; + struct strbuf sb = STRBUF_INIT; + char *shallow = git_path("shallow"); + int fd; + + mtime.sec = st.st_mtime; + mtime.nsec = ST_MTIME_NSEC(st); + if (stat(shallow, &st)) { + if (mtime.sec) + die("shallow file was removed during fetch"); + } else if (st.st_mtime != mtime.sec +#ifdef USE_NSEC + || ST_MTIME_NSEC(st) != mtime.nsec +#endif + ) + die("shallow file was changed during fetch"); + + fd = hold_lock_file_for_update(&lock, shallow, + LOCK_DIE_ON_ERROR); + if (!write_shallow_commits(&sb, 0) + || write_in_full(fd, sb.buf, sb.len) != sb.len) { + unlink_or_warn(shallow); + rollback_lock_file(&lock); + } else { + commit_lock_file(&lock); + } + strbuf_release(&sb); + } + + reprepare_packed_git(); + return ref_cpy; +} diff --git a/fetch-pack.h b/fetch-pack.h index 7c2069c97..cb148719b 100644 --- a/fetch-pack.h +++ b/fetch-pack.h @@ -1,6 +1,8 @@ #ifndef FETCH_PACK_H #define FETCH_PACK_H +#include "string-list.h" + struct fetch_pack_args { const char *uploadpack; int unpacklimit; @@ -17,12 +19,18 @@ struct fetch_pack_args { stateless_rpc:1; }; +/* + * sought contains the full names of remote references that should be + * updated from. On return, the names that were found on the remote + * will have been removed from the list. The util members of the + * string_list_items are used internally; they must be NULL on entry + * (and will be NULL on exit). + */ struct ref *fetch_pack(struct fetch_pack_args *args, - int fd[], struct child_process *conn, - const struct ref *ref, - const char *dest, - int nr_heads, - char **heads, - char **pack_lockfile); + int fd[], struct child_process *conn, + const struct ref *ref, + const char *dest, + struct string_list *sought, + char **pack_lockfile); #endif @@ -4,6 +4,8 @@ #include "git-compat-util.h" #include "gettext.h" +#include "strbuf.h" +#include "utf8.h" #ifndef NO_GETTEXT # include <locale.h> @@ -27,10 +29,9 @@ int use_gettext_poison(void) #endif #ifndef NO_GETTEXT +static const char *charset; static void init_gettext_charset(const char *domain) { - const char *charset; - /* This trick arranges for messages to be emitted in the user's requested encoding, but avoids setting LC_CTYPE from the @@ -128,4 +129,14 @@ void git_setup_gettext(void) init_gettext_charset("git"); textdomain("git"); } + +/* return the number of columns of string 's' in current locale */ +int gettext_width(const char *s) +{ + static int is_utf8 = -1; + if (is_utf8 == -1) + is_utf8 = !strcmp(charset, "UTF-8"); + + return is_utf8 ? utf8_strwidth(s) : strlen(s); +} #endif @@ -30,10 +30,15 @@ #ifndef NO_GETTEXT extern void git_setup_gettext(void); +extern int gettext_width(const char *s); #else static inline void git_setup_gettext(void) { } +static inline int gettext_width(const char *s) +{ + return strlen(s); +} #endif #ifdef GETTEXT_POISON @@ -44,6 +49,8 @@ extern int use_gettext_poison(void); static inline FORMAT_PRESERVING(1) const char *_(const char *msgid) { + if (!*msgid) + return ""; return use_gettext_poison() ? "# GETTEXT POISON #" : gettext(msgid); } @@ -92,7 +92,7 @@ safe_to_abort () { then return 0 fi - gettextln "You seem to have moved HEAD since the last 'am' failure. + gettextln "You seem to have moved HEAD since the last 'am' failure. Not rewinding to ORIG_HEAD" >&2 return 1 } @@ -102,9 +102,9 @@ stop_here_user_resolve () { printf '%s\n' "$resolvemsg" stop_here $1 fi - eval_gettextln "When you have resolved this problem run \"\$cmdline --resolved\". -If you would prefer to skip this patch, instead run \"\$cmdline --skip\". -To restore the original branch and stop patching run \"\$cmdline --abort\"." + eval_gettextln "When you have resolved this problem, run \"\$cmdline --resolved\". +If you prefer to skip this patch, run \"\$cmdline --skip\" instead. +To restore the original branch and stop patching, run \"\$cmdline --abort\"." stop_here $1 } @@ -136,7 +136,7 @@ fall_back_3way () { git write-tree >"$dotest/patch-merge-base+" || cannot_fallback "$(gettext "Repository lacks necessary blobs to fall back on 3-way merge.")" - say Using index info to reconstruct a base tree... + say "$(gettext "Using index info to reconstruct a base tree...")" cmd='GIT_INDEX_FILE="$dotest/patch-merge-tmp-index"' @@ -176,8 +176,7 @@ It does not apply to blobs recorded in its index.")" fi git-merge-recursive $orig_tree -- HEAD $his_tree || { git rerere $allow_rerere_autoupdate - echo Failed to merge in the changes. - exit 1 + die "$(gettext "Failed to merge in the changes.")" } unset GITHEAD_$his_tree } @@ -260,7 +259,7 @@ check_patch_format () { split_patches () { case "$patch_format" in mbox) - if test -n "$rebasing" || test t = "$keepcr" + if test t = "$keepcr" then keep_cr=--keep-cr else @@ -387,8 +386,8 @@ do -i|--interactive) interactive=t ;; -b|--binary) - echo >&2 "The $1 option has been a no-op for long time, and" - echo >&2 "it will be removed. Please do not use it anymore." + gettextln >&2 "The -b/--binary option has been a no-op for long time, and +it will be removed. Please do not use it anymore." ;; -3|--3way) threeway=t ;; @@ -413,10 +412,7 @@ do --abort) abort=t ;; --rebasing) - rebasing=t threeway=t keep=t scissors=f no_inbody_headers=t ;; - -d|--dotest) - die "$(gettext "-d option is no longer supported. Do not use.")" - ;; + rebasing=t threeway=t ;; --resolvemsg) shift; resolvemsg=$1 ;; --whitespace|--directory|--exclude|--include) @@ -658,32 +654,34 @@ do # by the user, or the user can tell us to do so by --resolved flag. case "$resume" in '') - git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \ - <"$dotest/$msgnum" >"$dotest/info" || - stop_here $this - - # skip pine's internal folder data - sane_grep '^Author: Mail System Internal Data$' \ - <"$dotest"/info >/dev/null && - go_next && continue - - test -s "$dotest/patch" || { - eval_gettextln "Patch is empty. Was it split wrong? -If you would prefer to skip this patch, instead run \"\$cmdline --skip\". -To restore the original branch and stop patching run \"\$cmdline --abort\"." - stop_here $this - } - rm -f "$dotest/original-commit" "$dotest/author-script" - if test -f "$dotest/rebasing" && + if test -f "$dotest/rebasing" + then commit=$(sed -e 's/^From \([0-9a-f]*\) .*/\1/' \ -e q "$dotest/$msgnum") && - test "$(git cat-file -t "$commit")" = commit - then + test "$(git cat-file -t "$commit")" = commit || + stop_here $this git cat-file commit "$commit" | sed -e '1,/^$/d' >"$dotest/msg-clean" - echo "$commit" > "$dotest/original-commit" - get_author_ident_from_commit "$commit" > "$dotest/author-script" + echo "$commit" >"$dotest/original-commit" + get_author_ident_from_commit "$commit" >"$dotest/author-script" + git diff-tree --root --binary "$commit" >"$dotest/patch" else + git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \ + <"$dotest/$msgnum" >"$dotest/info" || + stop_here $this + + # skip pine's internal folder data + sane_grep '^Author: Mail System Internal Data$' \ + <"$dotest"/info >/dev/null && + go_next && continue + + test -s "$dotest/patch" || { + eval_gettextln "Patch is empty. Was it split wrong? +If you would prefer to skip this patch, instead run \"\$cmdline --skip\". +To restore the original branch and stop patching run \"\$cmdline --abort\"." + stop_here $this + } + rm -f "$dotest/original-commit" "$dotest/author-script" { sed -n '/^Subject/ s/Subject: //p' "$dotest/info" echo @@ -857,8 +855,8 @@ did you forget to use 'git add'?" eval_gettextln 'Patch failed at $msgnum $FIRSTLINE' if test "$(git config --bool advice.amworkdir)" != false then - eval_gettextln "The copy of the patch that failed is found in: - $dotest/patch" + eval_gettextln 'The copy of the patch that failed is found in: + $dotest/patch' fi stop_here_user_resolve $this fi diff --git a/git-compat-util.h b/git-compat-util.h index 5bd9ad7d2..590d5d318 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -74,7 +74,8 @@ # define _XOPEN_SOURCE 500 # endif #elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \ - !defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__) + !defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__) && \ + !defined(__TANDEM) #define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */ #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */ #endif @@ -98,6 +99,9 @@ #include <stdlib.h> #include <stdarg.h> #include <string.h> +#ifdef __TANDEM /* or HAVE_STRINGS_H or !NO_STRINGS_H? */ +#include <strings.h> /* for strcasecmp() */ +#endif #include <errno.h> #include <limits.h> #include <sys/param.h> @@ -141,6 +145,17 @@ #else #include <stdint.h> #endif +#ifdef NO_INTPTR_T +/* + * On I16LP32, ILP32 and LP64 "long" is the save bet, however + * on LLP86, IL33LLP64 and P64 it needs to be "long long", + * while on IP16 and IP16L32 it is "int" (resp. "short") + * Size needs to match (or exceed) 'sizeof(void *)'. + * We can't take "long long" here as not everybody has it. + */ +typedef long intptr_t; +typedef unsigned long uintptr_t; +#endif #if defined(__CYGWIN__) #undef _XOPEN_SOURCE #include <grp.h> @@ -153,6 +168,31 @@ #endif #endif +/* used on Mac OS X */ +#ifdef PRECOMPOSE_UNICODE +#include "compat/precompose_utf8.h" +#else +#define precompose_str(in,i_nfd2nfc) +#define precompose_argv(c,v) +#define probe_utf8_pathname_composition(a,b) +#endif + +#ifdef MKDIR_WO_TRAILING_SLASH +#define mkdir(a,b) compat_mkdir_wo_trailing_slash((a),(b)) +extern int compat_mkdir_wo_trailing_slash(const char*, mode_t); +#endif + +#ifdef NO_STRUCT_ITIMERVAL +struct itimerval { + struct timeval it_interval; + struct timeval it_value; +} +#endif + +#ifdef NO_SETITIMER +#define setitimer(which,value,ovalue) +#endif + #ifndef NO_LIBGEN_H #include <libgen.h> #else @@ -466,6 +506,7 @@ extern const char tolower_trans_tbl[256]; #undef isdigit #undef isalpha #undef isalnum +#undef isprint #undef islower #undef isupper #undef tolower @@ -483,6 +524,7 @@ extern unsigned char sane_ctype[256]; #define isdigit(x) sane_istest(x,GIT_DIGIT) #define isalpha(x) sane_istest(x,GIT_ALPHA) #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) +#define isprint(x) ((x) >= 0x20 && (x) <= 0x7e) #define islower(x) sane_iscase(x, 1) #define isupper(x) sane_iscase(x, 0) #define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL) @@ -595,6 +637,16 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +/* + * Call access(2), but warn for any error except "missing file" + * (ENOENT or ENOTDIR). + */ +int access_or_warn(const char *path, int mode); +int access_or_die(const char *path, int mode); + +/* Warn on an inaccessible file that ought to be accessible */ +void warn_on_inaccessible(const char *path); + /* Get the passwd entry for the UID of the current process. */ struct passwd *xgetpwuid_self(void); diff --git a/git-cvsimport.perl b/git-cvsimport.perl index 8d41610bc..0a31ebd82 100755 --- a/git-cvsimport.perl +++ b/git-cvsimport.perl @@ -24,14 +24,14 @@ use File::Basename qw(basename dirname); use Time::Local; use IO::Socket; use IO::Pipe; -use POSIX qw(strftime dup2 ENOENT); +use POSIX qw(strftime tzset dup2 ENOENT); use IPC::Open2; $SIG{'PIPE'}="IGNORE"; -$ENV{'TZ'}="UTC"; +set_timezone('UTC'); our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,@opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r, $opt_R); -my (%conv_author_name, %conv_author_email); +my (%conv_author_name, %conv_author_email, %conv_author_tz); sub usage(;$) { my $msg = shift; @@ -59,6 +59,14 @@ sub read_author_info($) { $conv_author_name{$user} = $2; $conv_author_email{$user} = $3; } + # or with an optional timezone: + # spawn=Simon Pawn <spawn@frog-pond.org> America/Chicago + elsif (m/^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*(\S+?)\s*$/) { + $user = $1; + $conv_author_name{$user} = $2; + $conv_author_email{$user} = $3; + $conv_author_tz{$user} = $4; + } # However, we also read from CVSROOT/users format # to ease migration. elsif (/^(\w+):(['"]?)(.+?)\2\s*$/) { @@ -84,11 +92,22 @@ sub write_author_info($) { die("Failed to open $file for writing: $!"); foreach (keys %conv_author_name) { - print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>\n"; + print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>"; + print $f " $conv_author_tz{$_}" if ($conv_author_tz{$_}); + print $f "\n"; } close ($f); } +# Versions of perl before 5.10.0 may not automatically check $TZ each +# time localtime is run (most platforms will do so only the first time). +# We can work around this by using tzset() to update the internal +# variable whenever we change the environment. +sub set_timezone { + $ENV{TZ} = shift; + tzset(); +} + # convert getopts specs for use by git config my %longmap = ( 'A:' => 'authors-file', @@ -795,7 +814,7 @@ sub write_tree () { return $tree; } -my ($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg); +my ($patchset,$date,$author_name,$author_email,$author_tz,$branch,$ancestor,$tag,$logmsg); my (@old,@new,@skipped,%ignorebranch,@commit_revisions); # commits that cvsps cannot place anywhere... @@ -844,7 +863,9 @@ sub commit { } } - my $commit_date = strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)); + set_timezone($author_tz); + my $commit_date = strftime("%s %z", localtime($date)); + set_timezone('UTC'); $ENV{GIT_AUTHOR_NAME} = $author_name; $ENV{GIT_AUTHOR_EMAIL} = $author_email; $ENV{GIT_AUTHOR_DATE} = $commit_date; @@ -889,10 +910,37 @@ sub commit { $xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY ** $xtag =~ tr/_/\./ if ( $opt_u ); $xtag =~ s/[\/]/$opt_s/g; - $xtag =~ s/\[//g; - system('git' , 'tag', '-f', $xtag, $cid) == 0 - or die "Cannot create tag $xtag: $!\n"; + # See refs.c for these rules. + # Tag cannot contain bad chars. (See bad_ref_char in refs.c.) + $xtag =~ s/[ ~\^:\\\*\?\[]//g; + # Other bad strings for tags: + # (See check_refname_component in refs.c.) + 1 while $xtag =~ s/ + (?: \.\. # Tag cannot contain '..'. + | \@{ # Tag cannot contain '@{'. + | ^ - # Tag cannot begin with '-'. + | \.lock $ # Tag cannot end with '.lock'. + | ^ \. # Tag cannot begin... + | \. $ # ...or end with '.' + )//xg; + # Tag cannot be empty. + if ($xtag eq '') { + warn("warning: ignoring tag '$tag'", + " with invalid tagname\n"); + return; + } + + if (system('git' , 'tag', '-f', $xtag, $cid) != 0) { + # We did our best to sanitize the tag, but still failed + # for whatever reason. Bail out, and give the user + # enough information to understand if/how we should + # improve the translation in the future. + if ($tag ne $xtag) { + print "Translated '$tag' tag to '$xtag'\n"; + } + die "Cannot create tag $xtag: $!\n"; + } print "Created tag '$xtag' on '$branch'\n" if $opt_v; } @@ -918,12 +966,14 @@ while (<CVS>) { } $state=3; } elsif ($state == 3 and s/^Author:\s+//) { + $author_tz = "UTC"; s/\s+$//; if (/^(.*?)\s+<(.*)>/) { ($author_name, $author_email) = ($1, $2); } elsif ($conv_author_name{$_}) { $author_name = $conv_author_name{$_}; $author_email = $conv_author_email{$_}; + $author_tz = $conv_author_tz{$_} if ($conv_author_tz{$_}); } else { $author_name = $author_email = $_; } diff --git a/git-cvsserver.perl b/git-cvsserver.perl index b8eddabc9..c5ebfa063 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -51,6 +51,10 @@ $| = 1; #### Definition and mappings of functions #### +# NOTE: Despite the existence of req_CATCHALL and req_EMPTY unimplemented +# requests, this list is incomplete. It is missing many rarer/optional +# requests. Perhaps some clients require a claim of support for +# these specific requests for main functionality to work? my $methods = { 'Root' => \&req_Root, 'Valid-responses' => \&req_Validresponses, @@ -80,7 +84,6 @@ my $methods = { 'noop' => \&req_EMPTY, 'annotate' => \&req_annotate, 'Global_option' => \&req_Globaloption, - #'annotate' => \&req_CATCHALL, }; ############################################## @@ -499,7 +502,7 @@ sub req_Entry #$log->debug("req_Entry : $data"); - my @data = split(/\//, $data); + my @data = split(/\//, $data, -1); $state->{entries}{$state->{directory}.$data[1]} = { revision => $data[2], @@ -540,8 +543,6 @@ sub req_add my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log); $updater->update(); - argsfromdir($updater); - my $addcount = 0; foreach my $filename ( @{$state->{args}} ) @@ -551,10 +552,10 @@ sub req_add my $meta = $updater->getmeta($filename); my $wrev = revparse($filename); - if ($wrev && $meta && ($wrev < 0)) + if ($wrev && $meta && ($wrev=~/^-/)) { # previously removed file, add back - $log->info("added file $filename was previously removed, send 1.$meta->{revision}"); + $log->info("added file $filename was previously removed, send $meta->{revision}"); print "MT +updated\n"; print "MT text U \n"; @@ -571,8 +572,8 @@ sub req_add # this is an "entries" line my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash}); - $log->debug("/$filepart/1.$meta->{revision}//$kopts/"); - print "/$filepart/1.$meta->{revision}//$kopts/\n"; + $log->debug("/$filepart/$meta->{revision}//$kopts/"); + print "/$filepart/$meta->{revision}//$kopts/\n"; # permissions $log->debug("SEND : u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}"); print "u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}\n"; @@ -680,13 +681,13 @@ sub req_remove next; } - if ( defined($wrev) and $wrev < 0 ) + if ( defined($wrev) and ($wrev=~/^-/) ) { print "E cvs remove: file `$filename' already scheduled for removal\n"; next; } - unless ( $wrev == $meta->{revision} ) + unless ( $wrev eq $meta->{revision} ) { # TODO : not sure if the format of this message is quite correct. print "E cvs remove: Up to date check failed for `$filename'\n"; @@ -701,7 +702,7 @@ sub req_remove print "Checked-in $dirpart\n"; print "$filename\n"; my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash}); - print "/$filepart/-1.$wrev//$kopts/\n"; + print "/$filepart/-$wrev//$kopts/\n"; $rmcount++; } @@ -992,7 +993,7 @@ sub req_co # this is an "entries" line my $kopts = kopts_from_path($fullName,"sha1",$git->{filehash}); - print "/$git->{name}/1.$git->{revision}//$kopts/\n"; + print "/$git->{name}/$git->{revision}//$kopts/\n"; # permissions print "u=$git->{mode},g=$git->{mode},o=$git->{mode}\n"; @@ -1080,7 +1081,7 @@ sub req_update } my $meta; - if ( defined($state->{opt}{r}) and $state->{opt}{r} =~ /^1\.(\d+)/ ) + if ( defined($state->{opt}{r}) and $state->{opt}{r} =~ /^(1\.\d+)$/ ) { $meta = $updater->getmeta($filename, $1); } else { @@ -1102,7 +1103,7 @@ sub req_update { $meta = { name => $filename, - revision => 0, + revision => '0', filehash => 'added' }; } @@ -1112,7 +1113,7 @@ sub req_update my $wrev = revparse($filename); # If the working copy is an old revision, lets get that version too for comparison. - if ( defined($wrev) and $wrev != $meta->{revision} ) + if ( defined($wrev) and $wrev ne $meta->{revision} ) { $oldmeta = $updater->getmeta($filename, $wrev); } @@ -1123,7 +1124,7 @@ sub req_update # and the working copy is unmodified _and_ the user hasn't specified -C next if ( defined ( $wrev ) and defined($meta->{revision}) - and $wrev == $meta->{revision} + and $wrev eq $meta->{revision} and $state->{entries}{$filename}{unchanged} and not exists ( $state->{opt}{C} ) ); @@ -1131,7 +1132,7 @@ sub req_update # but the working copy is modified, tell the client it's modified if ( defined ( $wrev ) and defined($meta->{revision}) - and $wrev == $meta->{revision} + and $wrev eq $meta->{revision} and defined($state->{entries}{$filename}{modified_hash}) and not exists ( $state->{opt}{C} ) ) { @@ -1144,6 +1145,10 @@ sub req_update if ( $meta->{filehash} eq "deleted" ) { + # TODO: If it has been modified in the sandbox, error out + # with the appropriate message, rather than deleting a modified + # file. + my ( $filepart, $dirpart ) = filenamesplit($filename,1); $log->info("Removing '$filename' from working copy (no longer in the repo)"); @@ -1161,7 +1166,7 @@ sub req_update { # normal update, just send the new revision (either U=Update, # or A=Add, or R=Remove) - if ( defined($wrev) && $wrev < 0 ) + if ( defined($wrev) && ($wrev=~/^-/) ) { $log->info("Tell the client the file is scheduled for removal"); print "MT text R \n"; @@ -1169,7 +1174,8 @@ sub req_update print "MT newline\n"; next; } - elsif ( (!defined($wrev) || $wrev == 0) && (!defined($meta->{revision}) || $meta->{revision} == 0) ) + elsif ( (!defined($wrev) || $wrev eq '0') && + (!defined($meta->{revision}) || $meta->{revision} eq '0') ) { $log->info("Tell the client the file is scheduled for addition"); print "MT text A \n"; @@ -1179,7 +1185,7 @@ sub req_update } else { - $log->info("Updating '$filename' to ".$meta->{revision}); + $log->info("UpdatingX3 '$filename' to ".$meta->{revision}); print "MT +updated\n"; print "MT text U \n"; print "MT fname $filename\n"; @@ -1211,8 +1217,8 @@ sub req_update # this is an "entries" line my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash}); - $log->debug("/$filepart/1.$meta->{revision}//$kopts/"); - print "/$filepart/1.$meta->{revision}//$kopts/\n"; + $log->debug("/$filepart/$meta->{revision}//$kopts/"); + print "/$filepart/$meta->{revision}//$kopts/\n"; # permissions $log->debug("SEND : u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}"); @@ -1222,7 +1228,6 @@ sub req_update transmitfile($meta->{filehash}); } } else { - $log->info("Updating '$filename'"); my ( $filepart, $dirpart ) = filenamesplit($meta->{name},1); my $mergeDir = setupTmpDir(); @@ -1237,7 +1242,7 @@ sub req_update # we need to merge with the local changes ( M=successful merge, C=conflict merge ) $log->info("Merging $file_local, $file_old, $file_new"); - print "M Merging differences between 1.$oldmeta->{revision} and 1.$meta->{revision} into $filename\n"; + print "M Merging differences between $oldmeta->{revision} and $meta->{revision} into $filename\n"; $log->debug("Temporary directory for merge is $mergeDir"); @@ -1260,8 +1265,8 @@ sub req_update print $state->{CVSROOT} . "/$state->{module}/$filename\n"; my $kopts = kopts_from_path("$dirpart/$filepart", "file",$mergedFile); - $log->debug("/$filepart/1.$meta->{revision}//$kopts/"); - print "/$filepart/1.$meta->{revision}//$kopts/\n"; + $log->debug("/$filepart/$meta->{revision}//$kopts/"); + print "/$filepart/$meta->{revision}//$kopts/\n"; } } elsif ( $return == 1 ) @@ -1277,7 +1282,7 @@ sub req_update print $state->{CVSROOT} . "/$state->{module}/$filename\n"; my $kopts = kopts_from_path("$dirpart/$filepart", "file",$mergedFile); - print "/$filepart/1.$meta->{revision}/+/$kopts/\n"; + print "/$filepart/$meta->{revision}/+/$kopts/\n"; } } else @@ -1380,11 +1385,12 @@ sub req_ci my $addflag = 0; my $rmflag = 0; - $rmflag = 1 if ( defined($wrev) and $wrev < 0 ); + $rmflag = 1 if ( defined($wrev) and ($wrev=~/^-/) ); $addflag = 1 unless ( -e $filename ); # Do up to date checking - unless ( $addflag or $wrev == $meta->{revision} or ( $rmflag and -$wrev == $meta->{revision} ) ) + unless ( $addflag or $wrev eq $meta->{revision} or + ( $rmflag and $wrev eq "-$meta->{revision}" ) ) { # fail everything if an up to date check fails print "error 1 Up to date check failed for $filename\n"; @@ -1421,7 +1427,7 @@ sub req_ci $log->info("Adding file '$filename'"); system("git", "update-index", "--add", $filename); } else { - $log->info("Updating file '$filename'"); + $log->info("UpdatingX2 file '$filename'"); system("git", "update-index", $filename); } } @@ -1512,7 +1518,7 @@ sub req_ci my $meta = $updater->getmeta($filename); unless (defined $meta->{revision}) { - $meta->{revision} = 1; + $meta->{revision} = "1.1"; } my ( $filepart, $dirpart ) = filenamesplit($filename, 1); @@ -1522,19 +1528,19 @@ sub req_ci print "M $state->{CVSROOT}/$state->{module}/$filename,v <-- $dirpart$filepart\n"; if ( defined $meta->{filehash} && $meta->{filehash} eq "deleted" ) { - print "M new revision: delete; previous revision: 1.$oldmeta{$filename}{revision}\n"; + print "M new revision: delete; previous revision: $oldmeta{$filename}{revision}\n"; print "Remove-entry $dirpart\n"; print "$filename\n"; } else { - if ($meta->{revision} == 1) { + if ($meta->{revision} eq "1.1") { print "M initial revision: 1.1\n"; } else { - print "M new revision: 1.$meta->{revision}; previous revision: 1.$oldmeta{$filename}{revision}\n"; + print "M new revision: $meta->{revision}; previous revision: $oldmeta{$filename}{revision}\n"; } print "Checked-in $dirpart\n"; print "$filename\n"; my $kopts = kopts_from_path($filename,"sha1",$meta->{filehash}); - print "/$filepart/1.$meta->{revision}//$kopts/\n"; + print "/$filepart/$meta->{revision}//$kopts/\n"; } } @@ -1552,10 +1558,12 @@ sub req_status #$log->debug("status state : " . Dumper($state)); # Grab a handle to the SQLite db and do any necessary updates - my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log); + my $updater; + $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log); $updater->update(); - # if no files were specified, we need to work out what files we should be providing status on ... + # if no files were specified, we need to work out what files we should + # be providing status on ... argsfromdir($updater); # foreach file specified on the command line ... @@ -1563,67 +1571,135 @@ sub req_status { $filename = filecleanup($filename); - next if exists($state->{opt}{l}) && index($filename, '/', length($state->{prependdir})) >= 0; + if ( exists($state->{opt}{l}) && + index($filename, '/', length($state->{prependdir})) >= 0 ) + { + next; + } my $meta = $updater->getmeta($filename); my $oldmeta = $meta; my $wrev = revparse($filename); - # If the working copy is an old revision, lets get that version too for comparison. - if ( defined($wrev) and $wrev != $meta->{revision} ) + # If the working copy is an old revision, lets get that + # version too for comparison. + if ( defined($wrev) and $wrev ne $meta->{revision} ) { $oldmeta = $updater->getmeta($filename, $wrev); } # TODO : All possible statuses aren't yet implemented my $status; - # Files are up to date if the working copy and repo copy have the same revision, and the working copy is unmodified - $status = "Up-to-date" if ( defined ( $wrev ) and defined($meta->{revision}) and $wrev == $meta->{revision} - and - ( ( $state->{entries}{$filename}{unchanged} and ( not defined ( $state->{entries}{$filename}{conflict} ) or $state->{entries}{$filename}{conflict} !~ /^\+=/ ) ) - or ( defined($state->{entries}{$filename}{modified_hash}) and $state->{entries}{$filename}{modified_hash} eq $meta->{filehash} ) ) - ); - - # Need checkout if the working copy has an older revision than the repo copy, and the working copy is unmodified - $status ||= "Needs Checkout" if ( defined ( $wrev ) and defined ( $meta->{revision} ) and $meta->{revision} > $wrev - and - ( $state->{entries}{$filename}{unchanged} - or ( defined($state->{entries}{$filename}{modified_hash}) and $state->{entries}{$filename}{modified_hash} eq $oldmeta->{filehash} ) ) - ); - - # Need checkout if it exists in the repo but doesn't have a working copy - $status ||= "Needs Checkout" if ( not defined ( $wrev ) and defined ( $meta->{revision} ) ); - - # Locally modified if working copy and repo copy have the same revision but there are local changes - $status ||= "Locally Modified" if ( defined ( $wrev ) and defined($meta->{revision}) and $wrev == $meta->{revision} and $state->{entries}{$filename}{modified_filename} ); - - # Needs Merge if working copy revision is less than repo copy and there are local changes - $status ||= "Needs Merge" if ( defined ( $wrev ) and defined ( $meta->{revision} ) and $meta->{revision} > $wrev and $state->{entries}{$filename}{modified_filename} ); - - $status ||= "Locally Added" if ( defined ( $state->{entries}{$filename}{revision} ) and not defined ( $meta->{revision} ) ); - $status ||= "Locally Removed" if ( defined ( $wrev ) and defined ( $meta->{revision} ) and -$wrev == $meta->{revision} ); - $status ||= "Unresolved Conflict" if ( defined ( $state->{entries}{$filename}{conflict} ) and $state->{entries}{$filename}{conflict} =~ /^\+=/ ); - $status ||= "File had conflicts on merge" if ( 0 ); + # Files are up to date if the working copy and repo copy have + # the same revision, and the working copy is unmodified + if ( defined ( $wrev ) and defined($meta->{revision}) and + $wrev eq $meta->{revision} and + ( ( $state->{entries}{$filename}{unchanged} and + ( not defined ( $state->{entries}{$filename}{conflict} ) or + $state->{entries}{$filename}{conflict} !~ /^\+=/ ) ) or + ( defined($state->{entries}{$filename}{modified_hash}) and + $state->{entries}{$filename}{modified_hash} eq + $meta->{filehash} ) ) ) + { + $status = "Up-to-date" + } + + # Need checkout if the working copy has a different (usually + # older) revision than the repo copy, and the working copy is + # unmodified + if ( defined ( $wrev ) and defined ( $meta->{revision} ) and + $meta->{revision} ne $wrev and + ( $state->{entries}{$filename}{unchanged} or + ( defined($state->{entries}{$filename}{modified_hash}) and + $state->{entries}{$filename}{modified_hash} eq + $oldmeta->{filehash} ) ) ) + { + $status ||= "Needs Checkout"; + } + + # Need checkout if it exists in the repo but doesn't have a working + # copy + if ( not defined ( $wrev ) and defined ( $meta->{revision} ) ) + { + $status ||= "Needs Checkout"; + } + + # Locally modified if working copy and repo copy have the + # same revision but there are local changes + if ( defined ( $wrev ) and defined($meta->{revision}) and + $wrev eq $meta->{revision} and + $state->{entries}{$filename}{modified_filename} ) + { + $status ||= "Locally Modified"; + } + + # Needs Merge if working copy revision is different + # (usually older) than repo copy and there are local changes + if ( defined ( $wrev ) and defined ( $meta->{revision} ) and + $meta->{revision} ne $wrev and + $state->{entries}{$filename}{modified_filename} ) + { + $status ||= "Needs Merge"; + } + + if ( defined ( $state->{entries}{$filename}{revision} ) and + not defined ( $meta->{revision} ) ) + { + $status ||= "Locally Added"; + } + if ( defined ( $wrev ) and defined ( $meta->{revision} ) and + $wrev eq "-$meta->{revision}" ) + { + $status ||= "Locally Removed"; + } + if ( defined ( $state->{entries}{$filename}{conflict} ) and + $state->{entries}{$filename}{conflict} =~ /^\+=/ ) + { + $status ||= "Unresolved Conflict"; + } + if ( 0 ) + { + $status ||= "File had conflicts on merge"; + } $status ||= "Unknown"; my ($filepart) = filenamesplit($filename); - print "M ===================================================================\n"; + print "M =======" . ( "=" x 60 ) . "\n"; print "M File: $filepart\tStatus: $status\n"; if ( defined($state->{entries}{$filename}{revision}) ) { - print "M Working revision:\t" . $state->{entries}{$filename}{revision} . "\n"; + print "M Working revision:\t" . + $state->{entries}{$filename}{revision} . "\n"; } else { print "M Working revision:\tNo entry for $filename\n"; } if ( defined($meta->{revision}) ) { - print "M Repository revision:\t1." . $meta->{revision} . "\t$state->{CVSROOT}/$state->{module}/$filename,v\n"; - print "M Sticky Tag:\t\t(none)\n"; - print "M Sticky Date:\t\t(none)\n"; - print "M Sticky Options:\t\t(none)\n"; + print "M Repository revision:\t" . + $meta->{revision} . + "\t$state->{CVSROOT}/$state->{module}/$filename,v\n"; + my($tagOrDate)=$state->{entries}{$filename}{tag_or_date}; + my($tag)=($tagOrDate=~m/^T(.+)$/); + if( !defined($tag) ) + { + $tag="(none)"; + } + print "M Sticky Tag:\t\t$tag\n"; + my($date)=($tagOrDate=~m/^D(.+)$/); + if( !defined($date) ) + { + $date="(none)"; + } + print "M Sticky Date:\t\t$date\n"; + my($options)=$state->{entries}{$filename}{options}; + if( $options eq "" ) + { + $options="(none)"; + } + print "M Sticky Options:\t\t$options\n"; } else { print "M Repository revision:\tNo revision control file\n"; } @@ -1651,16 +1727,17 @@ sub req_diff $revision1 = $state->{opt}{r}; } - $revision1 =~ s/^1\.// if ( defined ( $revision1 ) ); - $revision2 =~ s/^1\.// if ( defined ( $revision2 ) ); - - $log->debug("Diffing revisions " . ( defined($revision1) ? $revision1 : "[NULL]" ) . " and " . ( defined($revision2) ? $revision2 : "[NULL]" ) ); + $log->debug("Diffing revisions " . + ( defined($revision1) ? $revision1 : "[NULL]" ) . + " and " . ( defined($revision2) ? $revision2 : "[NULL]" ) ); # Grab a handle to the SQLite db and do any necessary updates - my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log); + my $updater; + $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log); $updater->update(); - # if no files were specified, we need to work out what files we should be providing status on ... + # if no files were specified, we need to work out what files we should + # be providing status on ... argsfromdir($updater); # foreach file specified on the command line ... @@ -1682,7 +1759,7 @@ sub req_diff $meta1 = $updater->getmeta($filename, $revision1); unless ( defined ( $meta1 ) and $meta1->{filehash} ne "deleted" ) { - print "E File $filename at revision 1.$revision1 doesn't exist\n"; + print "E File $filename at revision $revision1 doesn't exist\n"; next; } transmitfile($meta1->{filehash}, { targetfile => $file1 }); @@ -1703,7 +1780,7 @@ sub req_diff unless ( defined ( $meta2 ) and $meta2->{filehash} ne "deleted" ) { - print "E File $filename at revision 1.$revision2 doesn't exist\n"; + print "E File $filename at revision $revision2 doesn't exist\n"; next; } @@ -1715,7 +1792,8 @@ sub req_diff $file2 = $state->{entries}{$filename}{modified_filename}; } - # if we have been given -r, and we don't have a $file2 yet, lets get one + # if we have been given -r, and we don't have a $file2 yet, lets + # get one if ( defined ( $revision1 ) and not defined ( $file2 ) ) { ( undef, $file2 ) = tempfile( DIR => $TEMP_DIR, OPEN => 0 ); @@ -1726,21 +1804,37 @@ sub req_diff # We need to have retrieved something useful next unless ( defined ( $meta1 ) ); - # Files to date if the working copy and repo copy have the same revision, and the working copy is unmodified - next if ( not defined ( $meta2 ) and $wrev == $meta1->{revision} - and - ( ( $state->{entries}{$filename}{unchanged} and ( not defined ( $state->{entries}{$filename}{conflict} ) or $state->{entries}{$filename}{conflict} !~ /^\+=/ ) ) - or ( defined($state->{entries}{$filename}{modified_hash}) and $state->{entries}{$filename}{modified_hash} eq $meta1->{filehash} ) ) - ); + # Files to date if the working copy and repo copy have the same + # revision, and the working copy is unmodified + if ( not defined ( $meta2 ) and $wrev eq $meta1->{revision} and + ( ( $state->{entries}{$filename}{unchanged} and + ( not defined ( $state->{entries}{$filename}{conflict} ) or + $state->{entries}{$filename}{conflict} !~ /^\+=/ ) ) or + ( defined($state->{entries}{$filename}{modified_hash}) and + $state->{entries}{$filename}{modified_hash} eq + $meta1->{filehash} ) ) ) + { + next; + } # Apparently we only show diffs for locally modified files - next unless ( defined($meta2) or defined ( $state->{entries}{$filename}{modified_filename} ) ); + unless ( defined($meta2) or + defined ( $state->{entries}{$filename}{modified_filename} ) ) + { + next; + } print "M Index: $filename\n"; - print "M ===================================================================\n"; + print "M =======" . ( "=" x 60 ) . "\n"; print "M RCS file: $state->{CVSROOT}/$state->{module}/$filename,v\n"; - print "M retrieving revision 1.$meta1->{revision}\n" if ( defined ( $meta1 ) ); - print "M retrieving revision 1.$meta2->{revision}\n" if ( defined ( $meta2 ) ); + if ( defined ( $meta1 ) ) + { + print "M retrieving revision $meta1->{revision}\n" + } + if ( defined ( $meta2 ) ) + { + print "M retrieving revision $meta2->{revision}\n" + } print "M diff "; foreach my $opt ( keys %{$state->{opt}} ) { @@ -1752,18 +1846,27 @@ sub req_diff } } else { print "-$opt "; - print "$state->{opt}{$opt} " if ( defined ( $state->{opt}{$opt} ) ); + if ( defined ( $state->{opt}{$opt} ) ) + { + print "$state->{opt}{$opt} " + } } } print "$filename\n"; - $log->info("Diffing $filename -r $meta1->{revision} -r " . ( $meta2->{revision} or "workingcopy" )); + $log->info("Diffing $filename -r $meta1->{revision} -r " . + ( $meta2->{revision} or "workingcopy" )); ( $fh, $filediff ) = tempfile ( DIR => $TEMP_DIR ); if ( exists $state->{opt}{u} ) { - system("diff -u -L '$filename revision 1.$meta1->{revision}' -L '$filename " . ( defined($meta2->{revision}) ? "revision 1.$meta2->{revision}" : "working copy" ) . "' $file1 $file2 > $filediff"); + system("diff -u -L '$filename revision $meta1->{revision}'" . + " -L '$filename " . + ( defined($meta2->{revision}) ? + "revision $meta2->{revision}" : + "working copy" ) . + "' $file1 $file2 > $filediff" ); } else { system("diff $file1 $file2 > $filediff"); } @@ -1787,22 +1890,19 @@ sub req_log $log->debug("req_log : " . ( defined($data) ? $data : "[NULL]" )); #$log->debug("log state : " . Dumper($state)); - my ( $minrev, $maxrev ); - if ( defined ( $state->{opt}{r} ) and $state->{opt}{r} =~ /([\d.]+)?(::?)([\d.]+)?/ ) + my ( $revFilter ); + if ( defined ( $state->{opt}{r} ) ) { - my $control = $2; - $minrev = $1; - $maxrev = $3; - $minrev =~ s/^1\.// if ( defined ( $minrev ) ); - $maxrev =~ s/^1\.// if ( defined ( $maxrev ) ); - $minrev++ if ( defined($minrev) and $control eq "::" ); + $revFilter = $state->{opt}{r}; } # Grab a handle to the SQLite db and do any necessary updates - my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log); + my $updater; + $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log); $updater->update(); - # if no files were specified, we need to work out what files we should be providing status on ... + # if no files were specified, we need to work out what files we + # should be providing status on ... argsfromdir($updater); # foreach file specified on the command line ... @@ -1812,53 +1912,46 @@ sub req_log my $headmeta = $updater->getmeta($filename); - my $revisions = $updater->getlog($filename); - my $totalrevisions = scalar(@$revisions); - - if ( defined ( $minrev ) ) - { - $log->debug("Removing revisions less than $minrev"); - while ( scalar(@$revisions) > 0 and $revisions->[-1]{revision} < $minrev ) - { - pop @$revisions; - } - } - if ( defined ( $maxrev ) ) - { - $log->debug("Removing revisions greater than $maxrev"); - while ( scalar(@$revisions) > 0 and $revisions->[0]{revision} > $maxrev ) - { - shift @$revisions; - } - } + my ($revisions,$totalrevisions) = $updater->getlog($filename, + $revFilter); next unless ( scalar(@$revisions) ); print "M \n"; print "M RCS file: $state->{CVSROOT}/$state->{module}/$filename,v\n"; print "M Working file: $filename\n"; - print "M head: 1.$headmeta->{revision}\n"; + print "M head: $headmeta->{revision}\n"; print "M branch:\n"; print "M locks: strict\n"; print "M access list:\n"; print "M symbolic names:\n"; print "M keyword substitution: kv\n"; - print "M total revisions: $totalrevisions;\tselected revisions: " . scalar(@$revisions) . "\n"; + print "M total revisions: $totalrevisions;\tselected revisions: " . + scalar(@$revisions) . "\n"; print "M description:\n"; foreach my $revision ( @$revisions ) { print "M ----------------------------\n"; - print "M revision 1.$revision->{revision}\n"; + print "M revision $revision->{revision}\n"; # reformat the date for log output - $revision->{modified} = sprintf('%04d/%02d/%02d %s', $3, $DATE_LIST->{$2}, $1, $4 ) if ( $revision->{modified} =~ /(\d+)\s+(\w+)\s+(\d+)\s+(\S+)/ and defined($DATE_LIST->{$2}) ); + if ( $revision->{modified} =~ /(\d+)\s+(\w+)\s+(\d+)\s+(\S+)/ and + defined($DATE_LIST->{$2}) ) + { + $revision->{modified} = sprintf('%04d/%02d/%02d %s', + $3, $DATE_LIST->{$2}, $1, $4 ); + } $revision->{author} = cvs_author($revision->{author}); - print "M date: $revision->{modified}; author: $revision->{author}; state: " . ( $revision->{filehash} eq "deleted" ? "dead" : "Exp" ) . "; lines: +2 -3\n"; - my $commitmessage = $updater->commitmessage($revision->{commithash}); + print "M date: $revision->{modified};" . + " author: $revision->{author}; state: " . + ( $revision->{filehash} eq "deleted" ? "dead" : "Exp" ) . + "; lines: +2 -3\n"; + my $commitmessage; + $commitmessage = $updater->commitmessage($revision->{commithash}); $commitmessage =~ s/^/M /mg; print $commitmessage . "\n"; } - print "M =============================================================================\n"; + print "M =======" . ( "=" x 70 ) . "\n"; } print "ok\n"; @@ -1964,7 +2057,7 @@ sub req_annotate $metadata->{$commithash}{author} = cvs_author($metadata->{$commithash}{author}); $metadata->{$commithash}{modified} = sprintf("%02d-%s-%02d", $1, $2, $3) if ( $metadata->{$commithash}{modified} =~ /^(\d+)\s(\w+)\s\d\d(\d\d)/ ); } - printf("M 1.%-5d (%-8s %10s): %s\n", + printf("M %-7s (%-8s %10s): %s\n", $metadata->{$commithash}{revision}, $metadata->{$commithash}{author}, $metadata->{$commithash}{modified}, @@ -2085,7 +2178,7 @@ sub argsfromdir # push added files foreach my $file (keys %{$state->{entries}}) { if ( exists $state->{entries}{$file}{revision} && - $state->{entries}{$file}{revision} == 0 ) + $state->{entries}{$file}{revision} eq '0' ) { push @gethead, { name => $file, filehash => 'added' }; } @@ -2129,16 +2222,15 @@ sub statecleanup $state->{entries} = {}; } +# Return working directory CVS revision "1.X" out +# of the the working directory "entries" state, for the given filename. +# This is prefixed with a dash if the file is scheduled for removal +# when it is committed. sub revparse { my $filename = shift; - return undef unless ( defined ( $state->{entries}{$filename}{revision} ) ); - - return $1 if ( $state->{entries}{$filename}{revision} =~ /^1\.(\d+)/ ); - return -$1 if ( $state->{entries}{$filename}{revision} =~ /^-1\.(\d+)/ ); - - return undef; + return $state->{entries}{$filename}{revision}; } # This method takes a file hash and does a CVS "file transfer". Its @@ -2444,42 +2536,14 @@ sub kopts_from_path } elsif( ($cfg->{gitcvs}{allbinary} =~ /^\s*guess\s*$/i) ) { - if( $srcType eq "sha1Or-k" && - !defined($name) ) + if( is_binary($srcType,$name) ) { - my ($ret)=$state->{entries}{$path}{options}; - if( !defined($ret) ) - { - $ret=$state->{opt}{k}; - if(defined($ret)) - { - $ret="-k$ret"; - } - else - { - $ret=""; - } - } - if( ! ($ret=~/^(|-kb|-kkv|-kkvl|-kk|-ko|-kv)$/) ) - { - print "E Bad -k option\n"; - $log->warn("Bad -k option: $ret"); - die "Error: Bad -k option: $ret\n"; - } - - return $ret; + $log->debug("... as binary"); + return "-kb"; } else { - if( is_binary($srcType,$name) ) - { - $log->debug("... as binary"); - return "-kb"; - } - else - { - $log->debug("... as text"); - } + $log->debug("... as text"); } } } @@ -2586,7 +2650,7 @@ sub open_blob_or_die die "Unable to open file $name: $!\n"; } } - elsif( $srcType eq "sha1" || $srcType eq "sha1Or-k" ) + elsif( $srcType eq "sha1" ) { unless ( defined ( $name ) and $name =~ /^[a-zA-Z0-9]{40}$/ ) { @@ -2929,6 +2993,16 @@ sub new } # Construct the revision table if required + # The revision table stores an entry for each file, each time that file + # changes. + # numberOfRecords = O( numCommits * averageNumChangedFilesPerCommit ) + # This is not sufficient to support "-r {commithash}" for any + # files except files that were modified by that commit (also, + # some places in the code ignore/effectively strip out -r in + # some cases, before it gets passed to getmeta()). + # The "filehash" field typically has a git blob hash, but can also + # be set to "dead" to indicate that the given version of the file + # should not exist in the sandbox. unless ( $self->{tables}{$self->tablename("revision")} ) { my $tablename = $self->tablename("revision"); @@ -2956,6 +3030,15 @@ sub new } # Construct the head table if required + # The head table (along with the "last_commit" entry in the property + # table) is the persisted working state of the "sub update" subroutine. + # All of it's data is read entirely first, and completely recreated + # last, every time "sub update" runs. + # This is also used by "sub getmeta" when it is asked for the latest + # version of a file (as opposed to some specific version). + # Another way of thinking about it is as a single slice out of + # "revisions", giving just the most recent revision information for + # each file. unless ( $self->{tables}{$self->tablename("head")} ) { my $tablename = $self->tablename("head"); @@ -2978,6 +3061,7 @@ sub new } # Construct the properties table if required + # - "last_commit" - Used by "sub update". unless ( $self->{tables}{$self->tablename("properties")} ) { my $tablename = $self->tablename("properties"); @@ -2990,6 +3074,11 @@ sub new } # Construct the commitmsgs table if required + # The commitmsgs table is only used for merge commits, since + # "sub update" will only keep one branch of parents. Shortlogs + # for ignored commits (i.e. not on the chosen branch) will be used + # to construct a replacement "collapsed" merge commit message, + # which will be stored in this table. See also "sub commitmessage". unless ( $self->{tables}{$self->tablename("commitmsgs")} ) { my $tablename = $self->tablename("commitmsgs"); @@ -3021,6 +3110,14 @@ sub tablename =head2 update +Bring the database up to date with the latest changes from +the git repository. + +Internal working state is read out of the "head" table and the +"last_commit" property, then it updates "revisions" based on that, and +finally it writes the new internal state back to the "head" table +so it can be used as a starting point the next time update is called. + =cut sub update { @@ -3116,7 +3213,7 @@ sub update my $commitcount = 0; # Load the head table into $head (for cached lookups during the update process) - foreach my $file ( @{$self->gethead()} ) + foreach my $file ( @{$self->gethead(1)} ) { $head->{$file->{name}} = $file; } @@ -3134,17 +3231,18 @@ sub update next; } elsif (@{$commit->{parents}} > 1) { # it is a merge commit, for each parent that is - # not $lastpicked, see if we can get a log + # not $lastpicked (not given a CVS revision number), + # see if we can get a log # from the merge-base to that parent to put it # in the message as a merge summary. my @parents = @{$commit->{parents}}; foreach my $parent (@parents) { - # git-merge-base can potentially (but rarely) throw - # several candidate merge bases. let's assume - # that the first one is the best one. if ($parent eq $lastpicked) { next; } + # git-merge-base can potentially (but rarely) throw + # several candidate merge bases. let's assume + # that the first one is the best one. my $base = eval { safe_pipe_capture('git', 'merge-base', $lastpicked, $parent); @@ -3426,19 +3524,6 @@ sub insert_head $insert_head->execute($name, $revision, $filehash, $commithash, $modified, $author, $mode); } -sub _headrev -{ - my $self = shift; - my $filename = shift; - my $tablename = $self->tablename("head"); - - my $db_query = $self->{dbh}->prepare_cached("SELECT filehash, revision, mode FROM $tablename WHERE name=?",{},1); - $db_query->execute($filename); - my ( $hash, $revision, $mode ) = $db_query->fetchrow_array; - - return ( $hash, $revision, $mode ); -} - sub _get_prop { my $self = shift; @@ -3478,6 +3563,7 @@ sub _set_prop sub gethead { my $self = shift; + my $intRev = shift; my $tablename = $self->tablename("head"); return $self->{gethead_cache} if ( defined ( $self->{gethead_cache} ) ); @@ -3488,6 +3574,10 @@ sub gethead my $tree = []; while ( my $file = $db_query->fetchrow_hashref ) { + if(!$intRev) + { + $file->{revision} = "1.$file->{revision}" + } push @$tree, $file; } @@ -3498,24 +3588,57 @@ sub gethead =head2 getlog +See also gethistorydense(). + =cut sub getlog { my $self = shift; my $filename = shift; + my $revFilter = shift; + my $tablename = $self->tablename("revision"); + # Filters: + # TODO: date, state, or by specific logins filters? + # TODO: Handle comma-separated list of revFilter items, each item + # can be a range [only case currently handled] or individual + # rev or branch or "branch.". + # TODO: Adjust $db_query WHERE clause based on revFilter, instead of + # manually filtering the results of the query? + my ( $minrev, $maxrev ); + if( defined($revFilter) and + $state->{opt}{r} =~ /^(1.(\d+))?(::?)(1.(\d.+))?$/ ) + { + my $control = $3; + $minrev = $2; + $maxrev = $5; + $minrev++ if ( defined($minrev) and $control eq "::" ); + } + my $db_query = $self->{dbh}->prepare_cached("SELECT name, filehash, author, mode, revision, modified, commithash FROM $tablename WHERE name=? ORDER BY revision DESC",{},1); $db_query->execute($filename); + my $totalRevs=0; my $tree = []; while ( my $file = $db_query->fetchrow_hashref ) { + $totalRevs++; + if( defined($minrev) and $file->{revision} < $minrev ) + { + next; + } + if( defined($maxrev) and $file->{revision} > $maxrev ) + { + next; + } + + $file->{revision} = "1." . $file->{revision}; push @$tree, $file; } - return $tree; + return ($tree,$totalRevs); } =head2 getmeta @@ -3534,10 +3657,11 @@ sub getmeta my $tablename_head = $self->tablename("head"); my $db_query; - if ( defined($revision) and $revision =~ /^\d+$/ ) + if ( defined($revision) and $revision =~ /^1\.(\d+)$/ ) { + my ($intRev) = $1; $db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_rev WHERE name=? AND revision=?",{},1); - $db_query->execute($filename, $revision); + $db_query->execute($filename, $intRev); } elsif ( defined($revision) and $revision =~ /^[a-zA-Z0-9]{40}$/ ) { @@ -3548,7 +3672,12 @@ sub getmeta $db_query->execute($filename); } - return $db_query->fetchrow_hashref; + my $meta = $db_query->fetchrow_hashref; + if($meta) + { + $meta->{revision} = "1.$meta->{revision}"; + } + return $meta; } =head2 commitmessage @@ -3583,25 +3712,6 @@ sub commitmessage return $message; } -=head2 gethistory - -This function takes a filename (with path) argument and returns an arrayofarrays -containing revision,filehash,commithash ordered by revision descending - -=cut -sub gethistory -{ - my $self = shift; - my $filename = shift; - my $tablename = $self->tablename("revision"); - - my $db_query; - $db_query = $self->{dbh}->prepare_cached("SELECT revision, filehash, commithash FROM $tablename WHERE name=? ORDER BY revision DESC",{},1); - $db_query->execute($filename); - - return $db_query->fetchall_arrayref; -} - =head2 gethistorydense This function takes a filename (with path) argument and returns an arrayofarrays @@ -3611,6 +3721,8 @@ This version of gethistory skips deleted entries -- so it is useful for annotate The 'dense' part is a reference to a '--dense' option available for git-rev-list and other git tools that depend on it. +See also getlog(). + =cut sub gethistorydense { @@ -3622,7 +3734,15 @@ sub gethistorydense $db_query = $self->{dbh}->prepare_cached("SELECT revision, filehash, commithash FROM $tablename WHERE name=? AND filehash!='deleted' ORDER BY revision DESC",{},1); $db_query->execute($filename); - return $db_query->fetchall_arrayref; + my $result = $db_query->fetchall_arrayref; + + my $i; + for($i=0 ; $i<scalar(@$result) ; $i++) + { + $result->[$i][0]="1." . $result->[$i][0]; + } + + return $result; } =head2 in_array() diff --git a/git-difftool.perl b/git-difftool.perl index ae1e0525d..edd0493a0 100755 --- a/git-difftool.perl +++ b/git-difftool.perl @@ -15,19 +15,14 @@ use strict; use warnings; use File::Basename qw(dirname); use File::Copy; +use File::Compare; use File::Find; use File::stat; -use File::Path qw(mkpath); +use File::Path qw(mkpath rmtree); use File::Temp qw(tempdir); use Getopt::Long qw(:config pass_through); use Git; -my @tools; -my @working_tree; -my $rc; -my $repo = Git->repository(); -my $repo_path = $repo->repo_path(); - sub usage { my $exitcode = shift; @@ -44,6 +39,8 @@ USAGE sub find_worktree { + my ($repo) = @_; + # Git->repository->wc_path() does not honor changes to the working # tree location made by $ENV{GIT_WORK_TREE} or the 'core.worktree' # config variable. @@ -62,10 +59,9 @@ sub find_worktree return $worktree; } -my $workdir = find_worktree(); - sub filter_tool_scripts { + my ($tools) = @_; if (-d $_) { if ($_ ne ".") { # Ignore files in subdirectories @@ -73,17 +69,17 @@ sub filter_tool_scripts } } else { if ((-f $_) && ($_ ne "defaults")) { - push(@tools, $_); + push(@$tools, $_); } } } sub print_tool_help { - my ($cmd, @found, @notfound); + my ($cmd, @found, @notfound, @tools); my $gitpath = Git::exec_path(); - find(\&filter_tool_scripts, "$gitpath/mergetools"); + find(sub { filter_tool_scripts(\@tools) }, "$gitpath/mergetools"); foreach my $tool (@tools) { $cmd = "TOOL_MODE=diff"; @@ -97,34 +93,52 @@ sub print_tool_help } } - print "'git difftool --tool=<tool>' may be set to one of the following:\n"; + print << 'EOF'; +'git difftool --tool=<tool>' may be set to one of the following: +EOF print "\t$_\n" for (sort(@found)); - print "\nThe following tools are valid, but not currently available:\n"; + print << 'EOF'; + +The following tools are valid, but not currently available: +EOF print "\t$_\n" for (sort(@notfound)); - print "\nNOTE: Some of the tools listed above only work in a windowed\n"; - print "environment. If run in a terminal-only session, they will fail.\n"; + print << 'EOF'; +NOTE: Some of the tools listed above only work in a windowed +environment. If run in a terminal-only session, they will fail. +EOF exit(0); } +sub exit_cleanup +{ + my ($tmpdir, $status) = @_; + my $errno = $!; + rmtree($tmpdir); + if ($status and $errno) { + my ($package, $file, $line) = caller(); + warn "$file line $line: $errno\n"; + } + exit($status | ($status >> 8)); +} + sub setup_dir_diff { + my ($repo, $workdir, $symlinks) = @_; + # Run the diff; exit immediately if no diff found # 'Repository' and 'WorkingCopy' must be explicitly set to insure that # if $GIT_DIR and $GIT_WORK_TREE are set in ENV, they are actually used # by Git->repository->command*. - my $diffrepo = Git->repository(Repository => $repo_path, WorkingCopy => $workdir); - my $diffrtn = $diffrepo->command_oneline('diff', '--raw', '--no-abbrev', '-z', @ARGV); - exit(0) if (length($diffrtn) == 0); + my $repo_path = $repo->repo_path(); + my %repo_args = (Repository => $repo_path, WorkingCopy => $workdir); + my $diffrepo = Git->repository(%repo_args); - # Setup temp directories - my $tmpdir = tempdir('git-diffall.XXXXX', CLEANUP => 1, TMPDIR => 1); - my $ldir = "$tmpdir/left"; - my $rdir = "$tmpdir/right"; - mkpath($ldir) or die $!; - mkpath($rdir) or die $!; + my @gitargs = ('diff', '--raw', '--no-abbrev', '-z', @ARGV); + my $diffrtn = $diffrepo->command_oneline(@gitargs); + exit(0) unless defined($diffrtn); # Build index info for left and right sides of the diff my $submodule_mode = '160000'; @@ -135,16 +149,21 @@ sub setup_dir_diff my $rindex = ''; my %submodule; my %symlink; + my @working_tree = (); my @rawdiff = split('\0', $diffrtn); my $i = 0; while ($i < $#rawdiff) { if ($rawdiff[$i] =~ /^::/) { - print "Combined diff formats ('-c' and '--cc') are not supported in directory diff mode.\n"; + warn << 'EOF'; +Combined diff formats ('-c' and '--cc') are not supported in +directory diff mode ('-d' and '--dir-diff'). +EOF exit(1); } - my ($lmode, $rmode, $lsha1, $rsha1, $status) = split(' ', substr($rawdiff[$i], 1)); + my ($lmode, $rmode, $lsha1, $rsha1, $status) = + split(' ', substr($rawdiff[$i], 1)); my $src_path = $rawdiff[$i + 1]; my $dst_path; @@ -156,7 +175,7 @@ sub setup_dir_diff $i += 2; } - if (($lmode eq $submodule_mode) or ($rmode eq $submodule_mode)) { + if ($lmode eq $submodule_mode or $rmode eq $submodule_mode) { $submodule{$src_path}{left} = $lsha1; if ($lsha1 ne $rsha1) { $submodule{$dst_path}{right} = $rsha1; @@ -167,14 +186,16 @@ sub setup_dir_diff } if ($lmode eq $symlink_mode) { - $symlink{$src_path}{left} = $diffrepo->command_oneline('show', "$lsha1"); + $symlink{$src_path}{left} = + $diffrepo->command_oneline('show', "$lsha1"); } if ($rmode eq $symlink_mode) { - $symlink{$dst_path}{right} = $diffrepo->command_oneline('show', "$rsha1"); + $symlink{$dst_path}{right} = + $diffrepo->command_oneline('show', "$rsha1"); } - if (($lmode ne $null_mode) and ($status !~ /^C/)) { + if ($lmode ne $null_mode and $status !~ /^C/) { $lindex .= "$lmode $lsha1\t$src_path\0"; } @@ -187,6 +208,13 @@ sub setup_dir_diff } } + # Setup temp directories + my $tmpdir = tempdir('git-difftool.XXXXX', CLEANUP => 0, TMPDIR => 1); + my $ldir = "$tmpdir/left"; + my $rdir = "$tmpdir/right"; + mkpath($ldir) or exit_cleanup($tmpdir, 1); + mkpath($rdir) or exit_cleanup($tmpdir, 1); + # If $GIT_DIR is not set prior to calling 'git update-index' and # 'git checkout-index', then those commands will fail if difftool # is called from a directory other than the repo root. @@ -199,18 +227,22 @@ sub setup_dir_diff # Populate the left and right directories based on each index file my ($inpipe, $ctx); $ENV{GIT_INDEX_FILE} = "$tmpdir/lindex"; - ($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/); + ($inpipe, $ctx) = + $repo->command_input_pipe(qw(update-index -z --index-info)); print($inpipe $lindex); $repo->command_close_pipe($inpipe, $ctx); - $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/"); - exit($rc | ($rc >> 8)) if ($rc != 0); + + my $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/"); + exit_cleanup($tmpdir, $rc) if $rc != 0; $ENV{GIT_INDEX_FILE} = "$tmpdir/rindex"; - ($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/); + ($inpipe, $ctx) = + $repo->command_input_pipe(qw(update-index -z --index-info)); print($inpipe $rindex); $repo->command_close_pipe($inpipe, $ctx); + $rc = system('git', 'checkout-index', '--all', "--prefix=$rdir/"); - exit($rc | ($rc >> 8)) if ($rc != 0); + exit_cleanup($tmpdir, $rc) if $rc != 0; # If $GIT_DIR was explicitly set just for the update/checkout # commands, then it should be unset before continuing. @@ -222,37 +254,55 @@ sub setup_dir_diff for my $file (@working_tree) { my $dir = dirname($file); unless (-d "$rdir/$dir") { - mkpath("$rdir/$dir") or die $!; + mkpath("$rdir/$dir") or + exit_cleanup($tmpdir, 1); + } + if ($symlinks) { + symlink("$workdir/$file", "$rdir/$file") or + exit_cleanup($tmpdir, 1); + } else { + copy("$workdir/$file", "$rdir/$file") or + exit_cleanup($tmpdir, 1); + + my $mode = stat("$workdir/$file")->mode; + chmod($mode, "$rdir/$file") or + exit_cleanup($tmpdir, 1); } - copy("$workdir/$file", "$rdir/$file") or die $!; - chmod(stat("$workdir/$file")->mode, "$rdir/$file") or die $!; } # 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. for my $path (keys %submodule) { + my $ok; if (defined($submodule{$path}{left})) { - write_to_file("$ldir/$path", "Subproject commit $submodule{$path}{left}"); + $ok = write_to_file("$ldir/$path", + "Subproject commit $submodule{$path}{left}"); } if (defined($submodule{$path}{right})) { - write_to_file("$rdir/$path", "Subproject commit $submodule{$path}{right}"); + $ok = write_to_file("$rdir/$path", + "Subproject commit $submodule{$path}{right}"); } + exit_cleanup($tmpdir, 1) if not $ok; } # 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. for my $path (keys %symlink) { + my $ok; if (defined($symlink{$path}{left})) { - write_to_file("$ldir/$path", $symlink{$path}{left}); + $ok = write_to_file("$ldir/$path", + $symlink{$path}{left}); } if (defined($symlink{$path}{right})) { - write_to_file("$rdir/$path", $symlink{$path}{right}); + $ok = write_to_file("$rdir/$path", + $symlink{$path}{right}); } + exit_cleanup($tmpdir, 1) if not $ok; } - return ($ldir, $rdir); + return ($ldir, $rdir, $tmpdir, @working_tree); } sub write_to_file @@ -263,83 +313,141 @@ sub write_to_file # Make sure the path to the file exists my $dir = dirname($path); unless (-d "$dir") { - mkpath("$dir") or die $!; + mkpath("$dir") or return 0; } # If the file already exists in that location, delete it. This # is required in the case of symbolic links. - unlink("$path"); + unlink($path); - open(my $fh, '>', "$path") or die $!; + open(my $fh, '>', $path) or return 0; print($fh $value); close($fh); -} -# parse command-line options. all unrecognized options and arguments -# are passed through to the 'git diff' command. -my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help); -GetOptions('g|gui!' => \$gui, - 'd|dir-diff' => \$dirdiff, - 'h' => \$help, - 'prompt!' => \$prompt, - 'y' => sub { $prompt = 0; }, - 't|tool:s' => \$difftool_cmd, - 'tool-help' => \$tool_help, - 'x|extcmd:s' => \$extcmd); - -if (defined($help)) { - usage(0); -} -if (defined($tool_help)) { - print_tool_help(); + return 1; } -if (defined($difftool_cmd)) { - if (length($difftool_cmd) > 0) { - $ENV{GIT_DIFF_TOOL} = $difftool_cmd; - } else { - print "No <tool> given for --tool=<tool>\n"; - usage(1); + +sub main +{ + # parse command-line options. all unrecognized options and arguments + # are passed through to the 'git diff' command. + my %opts = ( + difftool_cmd => undef, + dirdiff => undef, + extcmd => undef, + gui => undef, + help => undef, + prompt => undef, + symlinks => $^O ne 'cygwin' && + $^O ne 'MSWin32' && $^O ne 'msys', + tool_help => undef, + ); + GetOptions('g|gui!' => \$opts{gui}, + 'd|dir-diff' => \$opts{dirdiff}, + 'h' => \$opts{help}, + 'prompt!' => \$opts{prompt}, + 'y' => sub { $opts{prompt} = 0; }, + 'symlinks' => \$opts{symlinks}, + 'no-symlinks' => sub { $opts{symlinks} = 0; }, + 't|tool:s' => \$opts{difftool_cmd}, + 'tool-help' => \$opts{tool_help}, + 'x|extcmd:s' => \$opts{extcmd}); + + if (defined($opts{help})) { + usage(0); } -} -if (defined($extcmd)) { - if (length($extcmd) > 0) { - $ENV{GIT_DIFFTOOL_EXTCMD} = $extcmd; - } else { - print "No <cmd> given for --extcmd=<cmd>\n"; - usage(1); + if (defined($opts{tool_help})) { + print_tool_help(); } -} -if ($gui) { - my $guitool = ''; - $guitool = Git::config('diff.guitool'); - if (length($guitool) > 0) { - $ENV{GIT_DIFF_TOOL} = $guitool; + if (defined($opts{difftool_cmd})) { + if (length($opts{difftool_cmd}) > 0) { + $ENV{GIT_DIFF_TOOL} = $opts{difftool_cmd}; + } else { + print "No <tool> given for --tool=<tool>\n"; + usage(1); + } + } + if (defined($opts{extcmd})) { + if (length($opts{extcmd}) > 0) { + $ENV{GIT_DIFFTOOL_EXTCMD} = $opts{extcmd}; + } else { + print "No <cmd> given for --extcmd=<cmd>\n"; + usage(1); + } + } + if ($opts{gui}) { + my $guitool = Git::config('diff.guitool'); + if (length($guitool) > 0) { + $ENV{GIT_DIFF_TOOL} = $guitool; + } + } + + # 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 (defined($opts{dirdiff})) { + dir_diff($opts{extcmd}, $opts{symlinks}); + } else { + file_diff($opts{prompt}); } } -# 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 (defined($dirdiff)) { - my ($a, $b) = setup_dir_diff(); +sub dir_diff +{ + my ($extcmd, $symlinks) = @_; + my $rc; + my $error = 0; + my $repo = Git->repository(); + my $workdir = find_worktree($repo); + my ($a, $b, $tmpdir, @worktree) = + setup_dir_diff($repo, $workdir, $symlinks); + if (defined($extcmd)) { $rc = system($extcmd, $a, $b); } else { $ENV{GIT_DIFFTOOL_DIRDIFF} = 'true'; $rc = system('git', 'difftool--helper', $a, $b); } - - exit($rc | ($rc >> 8)) if ($rc != 0); - # If the diff including working copy files and those # files were modified during the diff, then the changes - # should be copied back to the working tree - for my $file (@working_tree) { - copy("$b/$file", "$workdir/$file") or die $!; - chmod(stat("$b/$file")->mode, "$workdir/$file") or die $!; + # 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. + for my $file (@worktree) { + next if $symlinks && -l "$b/$file"; + next if ! -f "$b/$file"; + + my $diff = compare("$b/$file", "$workdir/$file"); + if ($diff == 0) { + next; + } elsif ($diff == -1) { + my $errmsg = "warning: Could not compare "; + $errmsg += "'$b/$file' with '$workdir/$file'\n"; + warn $errmsg; + $error = 1; + } elsif ($diff == 1) { + my $mode = stat("$b/$file")->mode; + copy("$b/$file", "$workdir/$file") or + exit_cleanup($tmpdir, 1); + + chmod($mode, "$workdir/$file") or + exit_cleanup($tmpdir, 1); + } } -} else { + if ($error) { + warn "warning: Temporary files exist in '$tmpdir'.\n"; + warn "warning: You may want to cleanup or recover these.\n"; + exit(1); + } else { + exit_cleanup($tmpdir, $rc); + } +} + +sub file_diff +{ + my ($prompt) = @_; + if (defined($prompt)) { if ($prompt) { $ENV{GIT_DIFFTOOL_PROMPT} = 'true'; @@ -359,3 +467,5 @@ if (defined($dirdiff)) { my $rc = system('git', 'diff', @ARGV); exit($rc | ($rc >> 8)); } + +main(); diff --git a/git-filter-branch.sh b/git-filter-branch.sh index 178e45305..53142492a 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -64,37 +64,19 @@ EOF eval "$functions" -# When piped a commit, output a script to set the ident of either -# "author" or "committer +finish_ident() { + # Ensure non-empty id name. + echo "case \"\$GIT_$1_NAME\" in \"\") GIT_$1_NAME=\"\${GIT_$1_EMAIL%%@*}\" && export GIT_$1_NAME;; esac" + # And make sure everything is exported. + echo "export GIT_$1_NAME" + echo "export GIT_$1_EMAIL" + echo "export GIT_$1_DATE" +} set_ident () { - lid="$(echo "$1" | tr "[A-Z]" "[a-z]")" - uid="$(echo "$1" | tr "[a-z]" "[A-Z]")" - pick_id_script=' - /^'$lid' /{ - s/'\''/'\''\\'\'\''/g - h - s/^'$lid' \([^<]*\) <[^>]*> .*$/\1/ - s/'\''/'\''\'\'\''/g - s/.*/GIT_'$uid'_NAME='\''&'\''; export GIT_'$uid'_NAME/p - - g - s/^'$lid' [^<]* <\([^>]*\)> .*$/\1/ - s/'\''/'\''\'\'\''/g - s/.*/GIT_'$uid'_EMAIL='\''&'\''; export GIT_'$uid'_EMAIL/p - - g - s/^'$lid' [^<]* <[^>]*> \(.*\)$/@\1/ - s/'\''/'\''\'\'\''/g - s/.*/GIT_'$uid'_DATE='\''&'\''; export GIT_'$uid'_DATE/p - - q - } - ' - - LANG=C LC_ALL=C sed -ne "$pick_id_script" - # Ensure non-empty id name. - echo "case \"\$GIT_${uid}_NAME\" in \"\") GIT_${uid}_NAME=\"\${GIT_${uid}_EMAIL%%@*}\" && export GIT_${uid}_NAME;; esac" + parse_ident_from_commit author AUTHOR committer COMMITTER + finish_ident AUTHOR + finish_ident COMMITTER } USAGE="[--env-filter <command>] [--tree-filter <command>] @@ -320,10 +302,8 @@ while read commit parents; do git cat-file commit "$commit" >../commit || die "Cannot read commit $commit" - eval "$(set_ident AUTHOR <../commit)" || - die "setting author failed for commit $commit" - eval "$(set_ident COMMITTER <../commit)" || - die "setting committer failed for commit $commit" + eval "$(set_ident <../commit)" || + die "setting author/committer failed for commit $commit" eval "$filter_env" < /dev/null || die "env filter failed: $filter_env" diff --git a/git-gui/GIT-VERSION-GEN b/git-gui/GIT-VERSION-GEN index 65709437f..49b62ea6e 100755 --- a/git-gui/GIT-VERSION-GEN +++ b/git-gui/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=0.16.GITGUI +DEF_VER=0.17.GITGUI LF=' ' diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ba4e5c133..89f636f49 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -154,6 +154,7 @@ set _trace [lsearch -exact $argv --trace] if {$_trace >= 0} { set argv [lreplace $argv $_trace $_trace] set _trace 1 + if {[tk windowingsystem] eq "win32"} { console show } } else { set _trace 0 } @@ -1463,7 +1464,7 @@ proc rescan {after {honor_trustmtime 1}} { (![$ui_comm edit modified] || [string trim [$ui_comm get 0.0 end]] eq {})} { if {[string match amend* $commit_type]} { - } elseif {[load_message GITGUI_MSG]} { + } elseif {[load_message GITGUI_MSG utf-8]} { } elseif {[run_prepare_commit_msg_hook]} { } elseif {[load_message MERGE_MSG]} { } elseif {[load_message SQUASH_MSG]} { @@ -1549,7 +1550,7 @@ proc rescan_stage2 {fd after} { fileevent $fd_lo readable [list read_ls_others $fd_lo $after] } -proc load_message {file} { +proc load_message {file {encoding {}}} { global ui_comm set f [gitdir $file] @@ -1558,6 +1559,9 @@ proc load_message {file} { return 0 } fconfigure $fd -eofchar {} + if {$encoding ne {}} { + fconfigure $fd -encoding $encoding + } set content [string trim [read $fd]] close $fd regsub -all -line {[ \r\t]+$} $content {} content @@ -2266,6 +2270,7 @@ proc do_quit {{rc {1}}} { && $msg ne {}} { catch { set fd [open $save w] + fconfigure $fd -encoding utf-8 puts -nonewline $fd $msg close $fd } @@ -2998,10 +3003,19 @@ blame { set jump_spec {} set is_path 0 foreach a $argv { - if {$is_path || [file exists $_prefix$a]} { + if {[file exists $a]} { + if {$path ne {}} usage + set path [normalize_relpath $a] + break + } elseif {[file exists $_prefix$a]} { if {$path ne {}} usage set path [normalize_relpath $_prefix$a] break + } + + if {$is_path} { + if {$path ne {}} usage + break } elseif {$a eq {--}} { if {$path ne {}} { if {$head ne {}} usage @@ -3023,8 +3037,13 @@ blame { unset is_path if {$head ne {} && $path eq {}} { - set path [normalize_relpath $_prefix$head] - set head {} + if {[string index $head 0] eq {/}} { + set path [normalize_relpath $head] + set head {} + } else { + set path [normalize_relpath $_prefix$head] + set head {} + } } if {$head eq {}} { @@ -3710,6 +3729,8 @@ bind $ui_diff <$M1B-Key-v> {break} bind $ui_diff <$M1B-Key-V> {break} bind $ui_diff <$M1B-Key-a> {%W tag add sel 0.0 end;break} bind $ui_diff <$M1B-Key-A> {%W tag add sel 0.0 end;break} +bind $ui_diff <$M1B-Key-j> {do_revert_selection;break} +bind $ui_diff <$M1B-Key-J> {do_revert_selection;break} bind $ui_diff <Key-Up> {catch {%W yview scroll -1 units};break} bind $ui_diff <Key-Down> {catch {%W yview scroll 1 units};break} bind $ui_diff <Key-Left> {catch {%W xview scroll -1 units};break} @@ -3742,6 +3763,8 @@ bind . <$M1B-Key-s> do_signoff bind . <$M1B-Key-S> do_signoff bind . <$M1B-Key-t> do_add_selection bind . <$M1B-Key-T> do_add_selection +bind . <$M1B-Key-u> do_unstage_selection +bind . <$M1B-Key-U> do_unstage_selection bind . <$M1B-Key-j> do_revert_selection bind . <$M1B-Key-J> do_revert_selection bind . <$M1B-Key-i> do_add_all @@ -3835,7 +3858,7 @@ if {[is_enabled transport]} { } if {[winfo exists $ui_comm]} { - set GITGUI_BCK_exists [load_message GITGUI_BCK] + set GITGUI_BCK_exists [load_message GITGUI_BCK utf-8] # -- If both our backup and message files exist use the # newer of the two files to initialize the buffer. @@ -3872,6 +3895,7 @@ if {[winfo exists $ui_comm]} { } elseif {$m} { catch { set fd [open [gitdir GITGUI_BCK] w] + fconfigure $fd -encoding utf-8 puts -nonewline $fd $msg close $fd set GITGUI_BCK_exists 1 diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl index 0d81432af..864b68705 100644 --- a/git-gui/lib/commit.tcl +++ b/git-gui/lib/commit.tcl @@ -268,7 +268,7 @@ proc commit_commitmsg {curHEAD msg_p} { && [is_config_true gui.warndetachedcommit]} { set msg [mc "You are about to commit on a detached head.\ This is a potentially dangerous thing to do because if you switch\ -to another branch you will loose your changes and it can be difficult\ +to another branch you will lose your changes and it can be difficult\ to retrieve them later from the reflog. You should probably cancel this\ commit and create a new branch to continue.\n\ \n\ @@ -409,6 +409,7 @@ A rescan will be automatically started now. catch {file delete [gitdir MERGE_MSG]} catch {file delete [gitdir SQUASH_MSG]} catch {file delete [gitdir GITGUI_MSG]} + catch {file delete [gitdir CHERRY_PICK_HEAD]} # -- Let rerere do its thing. # diff --git a/git-gui/lib/status_bar.tcl b/git-gui/lib/status_bar.tcl index 95cb44991..02111a174 100644 --- a/git-gui/lib/status_bar.tcl +++ b/git-gui/lib/status_bar.tcl @@ -77,6 +77,7 @@ method start {msg uds} { method update {have total} { set pdone 0 + set cdone 0 if {$total > 0} { set pdone [expr {100 * $have / $total}] set cdone [expr {[winfo width $w_c] * $have / $total}] diff --git a/git-gui/macosx/AppMain.tcl b/git-gui/macosx/AppMain.tcl index ddbe6334a..738bdd03e 100644 --- a/git-gui/macosx/AppMain.tcl +++ b/git-gui/macosx/AppMain.tcl @@ -12,7 +12,9 @@ if {[file tail [lindex $argv 0]] eq {gitk}} { } else { set argv0 [file join $gitexecdir [file tail [lindex $argv 0]]] set AppMain_source [file join $gitguilib git-gui.tcl] - if {[pwd] eq {/}} { + if {[info exists env(PWD)]} { + cd $env(PWD) + } elseif {[pwd] eq {/}} { cd $env(HOME) } } diff --git a/git-gui/po/de.po b/git-gui/po/de.po index 44c5ddc8b..baebff2ff 100644 --- a/git-gui/po/de.po +++ b/git-gui/po/de.po @@ -72,7 +72,7 @@ msgstr "" #: git-gui.sh:1154 msgid "Cannot use bare repository:" -msgstr "Leeres Projektarchiv kann nicht benutzt werden:" +msgstr "Bloßes Projektarchiv kann nicht benutzt werden:" #: git-gui.sh:1162 msgid "No working directory" @@ -88,7 +88,7 @@ msgstr "Nach geänderten Dateien suchen..." #: git-gui.sh:1454 msgid "Calling prepare-commit-msg hook..." -msgstr "Aufrufen der Eintragen-Vorbereiten-Kontrolle..." +msgstr "Aufrufen der Eintragen-Vorbereiten-Kontrolle (»prepare-commit hook«)..." #: git-gui.sh:1471 msgid "Commit declined by prepare-commit-msg hook." @@ -188,7 +188,7 @@ msgstr "Zusammenführen" #: git-gui.sh:2465 lib/choose_rev.tcl:557 msgid "Remote" -msgstr "Andere Archive" +msgstr "Externe Archive" #: git-gui.sh:2468 msgid "Tools" @@ -478,7 +478,7 @@ msgstr "Zusammenführungswerkzeug" #: git-gui.sh:3328 msgid "Use Remote Version" -msgstr "Entfernte Version benutzen" +msgstr "Externe Version benutzen" #: git-gui.sh:3332 msgid "Use Local Version" @@ -771,7 +771,7 @@ msgstr "Bitte wählen Sie einen Übernahmezweig." #: lib/branch_create.tcl:140 #, tcl-format msgid "Tracking branch %s is not a branch in the remote repository." -msgstr "Übernahmezweig »%s« ist kein Zweig im anderen Projektarchiv." +msgstr "Übernahmezweig »%s« ist kein Zweig im externen Projektarchiv." #: lib/branch_create.tcl:153 lib/branch_rename.tcl:86 msgid "Please supply a branch name." @@ -1446,7 +1446,7 @@ msgstr "" #: lib/commit.tcl:234 msgid "Calling pre-commit hook..." -msgstr "Aufrufen der Vor-Eintragen-Kontrolle..." +msgstr "Aufrufen der Vor-Eintragen-Kontrolle (»pre-commit hook«)..." #: lib/commit.tcl:249 msgid "Commit declined by pre-commit hook." @@ -1454,7 +1454,7 @@ msgstr "Eintragen abgelehnt durch Vor-Eintragen-Kontrolle (»pre-commit hook«). #: lib/commit.tcl:272 msgid "Calling commit-msg hook..." -msgstr "Aufrufen der Versionsbeschreibungs-Kontrolle..." +msgstr "Aufrufen der Versionsbeschreibungs-Kontrolle (»commit-message hook«)..." #: lib/commit.tcl:287 msgid "Commit declined by commit-msg hook." @@ -2134,11 +2134,11 @@ msgstr "Optionen konnten nicht gespeichert werden:" #: lib/remote_add.tcl:19 msgid "Add Remote" -msgstr "Anderes Archiv hinzufügen" +msgstr "Externes Archiv hinzufügen" #: lib/remote_add.tcl:24 msgid "Add New Remote" -msgstr "Neues anderes Archiv hinzufügen" +msgstr "Neues externes Archiv hinzufügen" #: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36 msgid "Add" @@ -2146,7 +2146,7 @@ msgstr "Hinzufügen" #: lib/remote_add.tcl:37 msgid "Remote Details" -msgstr "Einzelheiten des anderen Archivs" +msgstr "Einzelheiten des externen Archivs" #: lib/remote_add.tcl:50 msgid "Location:" @@ -2162,7 +2162,7 @@ msgstr "Gleich anfordern" #: lib/remote_add.tcl:71 msgid "Initialize Remote Repository and Push" -msgstr "Anderes Archiv initialisieren und dahin versenden" +msgstr "Externes Archiv initialisieren und dahin versenden" #: lib/remote_add.tcl:77 msgid "Do Nothing Else Now" @@ -2170,17 +2170,17 @@ msgstr "Nichts tun" #: lib/remote_add.tcl:101 msgid "Please supply a remote name." -msgstr "Bitte geben Sie einen Namen des anderen Archivs an." +msgstr "Bitte geben Sie einen Namen des externen Archivs an." #: lib/remote_add.tcl:114 #, tcl-format msgid "'%s' is not an acceptable remote name." -msgstr "»%s« ist kein zulässiger Name eines anderen Archivs." +msgstr "»%s« ist kein zulässiger Name eines externen Archivs." #: lib/remote_add.tcl:125 #, tcl-format msgid "Failed to add remote '%s' of location '%s'." -msgstr "Fehler beim Hinzufügen des anderen Archivs »%s« aus Herkunftsort »%s«." +msgstr "Fehler beim Hinzufügen des externen Archivs »%s« aus Herkunftsort »%s«." #: lib/remote_add.tcl:133 lib/transport.tcl:6 #, tcl-format @@ -2195,7 +2195,7 @@ msgstr "»%s« anfordern" #: lib/remote_add.tcl:157 #, tcl-format msgid "Do not know how to initialize repository at location '%s'." -msgstr "Initialisieren eines anderen Archivs an Adresse »%s« ist nicht möglich." +msgstr "Initialisieren eines externen Archivs an Adresse »%s« ist nicht möglich." #: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63 #: lib/transport.tcl:81 @@ -2210,7 +2210,7 @@ msgstr "Einrichten von »%s« an »%s«" #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 msgid "Delete Branch Remotely" -msgstr "Zweig in anderem Archiv löschen" +msgstr "Zweig in externem Archiv löschen" #: lib/remote_branch_delete.tcl:47 msgid "From Repository" @@ -2218,7 +2218,7 @@ msgstr "In Projektarchiv" #: lib/remote_branch_delete.tcl:50 lib/transport.tcl:134 msgid "Remote:" -msgstr "Anderes Archiv:" +msgstr "Externes Archiv:" #: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149 msgid "Arbitrary Location:" @@ -2281,7 +2281,7 @@ msgstr "»%s« laden..." #: lib/remote.tcl:163 msgid "Remove Remote" -msgstr "Anderes Archiv entfernen" +msgstr "Externes Archiv entfernen" #: lib/remote.tcl:168 msgid "Prune from" @@ -2397,7 +2397,7 @@ msgid "Generation failed." msgstr "Schlüsselerzeugung fehlgeschlagen." #: lib/sshkey.tcl:118 -msgid "Generation succeded, but no keys found." +msgid "Generation succeeded, but no keys found." msgstr "Schlüsselerzeugung erfolgreich, aber keine Schlüssel gefunden." #: lib/sshkey.tcl:121 diff --git a/git-gui/po/fr.po b/git-gui/po/fr.po index 81706965f..40441dbb0 100644 --- a/git-gui/po/fr.po +++ b/git-gui/po/fr.po @@ -2399,7 +2399,7 @@ msgid "Generation failed." msgstr "La génération a échoué." #: lib/sshkey.tcl:118 -msgid "Generation succeded, but no keys found." +msgid "Generation succeeded, but no keys found." msgstr "La génération a réussi, mais aucune clé n'a été trouvée." #: lib/sshkey.tcl:121 diff --git a/git-gui/po/git-gui.pot b/git-gui/po/git-gui.pot index 1ae2aaa0b..0c94f9c2c 100644 --- a/git-gui/po/git-gui.pot +++ b/git-gui/po/git-gui.pot @@ -2203,7 +2203,7 @@ msgid "Generation failed." msgstr "" #: lib/sshkey.tcl:118 -msgid "Generation succeded, but no keys found." +msgid "Generation succeeded, but no keys found." msgstr "" #: lib/sshkey.tcl:121 diff --git a/git-gui/po/hu.po b/git-gui/po/hu.po index 0f87bc1cb..d106dadac 100644 --- a/git-gui/po/hu.po +++ b/git-gui/po/hu.po @@ -2354,7 +2354,7 @@ msgid "Generation failed." msgstr "A generálás nem sikerült." #: lib/sshkey.tcl:118 -msgid "Generation succeded, but no keys found." +msgid "Generation succeeded, but no keys found." msgstr "A generálás sikeres, de egy kulcs se található." #: lib/sshkey.tcl:121 diff --git a/git-gui/po/it.po b/git-gui/po/it.po index aa15a204d..1bd8b8e04 100644 --- a/git-gui/po/it.po +++ b/git-gui/po/it.po @@ -2397,7 +2397,7 @@ msgid "Generation failed." msgstr "Errore durante la creazione della chiave." #: lib/sshkey.tcl:118 -msgid "Generation succeded, but no keys found." +msgid "Generation succeeded, but no keys found." msgstr "La chiave è stata creata con successo, ma non è stata trovata." #: lib/sshkey.tcl:121 diff --git a/git-gui/po/ja.po b/git-gui/po/ja.po index 15017985e..9aff249d5 100644 --- a/git-gui/po/ja.po +++ b/git-gui/po/ja.po @@ -2362,7 +2362,7 @@ msgid "Generation failed." msgstr "生æˆã«å¤±æ•—ã—ã¾ã—ãŸã€‚" #: lib/sshkey.tcl:118 -msgid "Generation succeded, but no keys found." +msgid "Generation succeeded, but no keys found." msgstr "生æˆã«ã¯æˆåŠŸã—ã¾ã—ãŸãŒã€éµãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。" #: lib/sshkey.tcl:121 diff --git a/git-gui/po/nb.po b/git-gui/po/nb.po index 6de93c28c..d66aa5026 100644 --- a/git-gui/po/nb.po +++ b/git-gui/po/nb.po @@ -2286,7 +2286,7 @@ msgid "Generation failed." msgstr "Generering feilet." #: lib/sshkey.tcl:118 -msgid "Generation succeded, but no keys found." +msgid "Generation succeeded, but no keys found." msgstr "Generering vellykket, men ingen nøkler er funnet." #: lib/sshkey.tcl:121 diff --git a/git-gui/po/pt_br.po b/git-gui/po/pt_br.po index b175b9791..bad116c78 100644 --- a/git-gui/po/pt_br.po +++ b/git-gui/po/pt_br.po @@ -2375,7 +2375,7 @@ msgid "Generation failed." msgstr "A geração da chave falhou." #: lib/sshkey.tcl:118 -msgid "Generation succeded, but no keys found." +msgid "Generation succeeded, but no keys found." msgstr "A geração da chave foi bem-sucedida, mas nenhuma chave foi encontrada." #: lib/sshkey.tcl:121 diff --git a/git-gui/po/ru.po b/git-gui/po/ru.po index 30f4b77da..ca4343b40 100644 --- a/git-gui/po/ru.po +++ b/git-gui/po/ru.po @@ -2370,7 +2370,7 @@ msgid "Generation failed." msgstr "Ключ не Ñоздан." #: lib/sshkey.tcl:118 -msgid "Generation succeded, but no keys found." +msgid "Generation succeeded, but no keys found." msgstr "Создание ключа завершилоÑÑŒ, но результат не был найден" #: lib/sshkey.tcl:121 diff --git a/git-gui/po/sv.po b/git-gui/po/sv.po index 24cc4e367..fcb063ffa 100644 --- a/git-gui/po/sv.po +++ b/git-gui/po/sv.po @@ -2382,7 +2382,7 @@ msgid "Generation failed." msgstr "Misslyckades med att skapa." #: lib/sshkey.tcl:120 -msgid "Generation succeded, but no keys found." +msgid "Generation succeeded, but no keys found." msgstr "Lyckades skapa nyckeln, men hittar inte nÃ¥gon nyckel." #: lib/sshkey.tcl:123 diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index f730253c0..f013a0350 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -104,13 +104,49 @@ run_merge_tool () { if merge_mode then - merge_cmd "$1" + run_merge_cmd "$1" else - diff_cmd "$1" + run_diff_cmd "$1" fi return $status } +# Run a either a configured or built-in diff tool +run_diff_cmd () { + merge_tool_cmd="$(get_merge_tool_cmd "$1")" + if test -n "$merge_tool_cmd" + then + ( eval $merge_tool_cmd ) + status=$? + return $status + else + diff_cmd "$1" + fi +} + +# Run a either a configured or built-in merge tool +run_merge_cmd () { + merge_tool_cmd="$(get_merge_tool_cmd "$1")" + if test -n "$merge_tool_cmd" + then + trust_exit_code="$(git config --bool \ + mergetool."$1".trustExitCode || echo false)" + if test "$trust_exit_code" = "false" + then + touch "$BACKUP" + ( eval $merge_tool_cmd ) + status=$? + check_unchanged + else + ( eval $merge_tool_cmd ) + status=$? + fi + return $status + else + merge_cmd "$1" + fi +} + list_merge_tool_candidates () { if merge_mode then @@ -126,7 +162,7 @@ list_merge_tool_candidates () { else tools="opendiff kdiff3 tkdiff xxdiff meld $tools" fi - tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3" + tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3 codecompare" fi case "${VISUAL:-$EDITOR}" in *vim*) @@ -120,6 +120,34 @@ def p4_read_pipe_lines(c): real_cmd = p4_build_cmd(c) return read_pipe_lines(real_cmd) +def p4_has_command(cmd): + """Ask p4 for help on this command. If it returns an error, the + command does not exist in this version of p4.""" + real_cmd = p4_build_cmd(["help", cmd]) + p = subprocess.Popen(real_cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + p.communicate() + return p.returncode == 0 + +def p4_has_move_command(): + """See if the move command exists, that it supports -k, and that + it has not been administratively disabled. The arguments + must be correct, but the filenames do not have to exist. Use + ones with wildcards so even if they exist, it will fail.""" + + if not p4_has_command("move"): + return False + cmd = p4_build_cmd(["move", "-k", "@from", "@to"]) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (out, err) = p.communicate() + # return code will be 1 in either case + if err.find("Invalid option") >= 0: + return False + if err.find("disabled") >= 0: + return False + # assume it failed because @... was invalid changelist + return True + def system(cmd): expand = isinstance(cmd,basestring) if verbose: @@ -157,6 +185,32 @@ def p4_revert(f): def p4_reopen(type, f): p4_system(["reopen", "-t", type, wildcard_encode(f)]) +def p4_move(src, dest): + p4_system(["move", "-k", wildcard_encode(src), wildcard_encode(dest)]) + +def p4_describe(change): + """Make sure it returns a valid result by checking for + the presence of field "time". Return a dict of the + results.""" + + ds = p4CmdList(["describe", "-s", str(change)]) + if len(ds) != 1: + die("p4 describe -s %d did not return 1 result: %s" % (change, str(ds))) + + d = ds[0] + + if "p4ExitCode" in d: + die("p4 describe -s %d exited with %d: %s" % (change, d["p4ExitCode"], + str(d))) + if "code" in d: + if d["code"] == "error": + die("p4 describe -s %d returned error code: %s" % (change, str(d))) + + if "time" not in d: + die("p4 describe -s %d returned no \"time\": %s" % (change, str(d))) + + return d + # # Canonicalize the p4 type and return a tuple of the # base type, plus any modifiers. See "p4 help filetypes" @@ -215,7 +269,7 @@ def p4_keywords_regexp_for_type(base, type_mods): pattern = r""" \$ # Starts with a dollar, followed by... (%s) # one of the keywords, followed by... - (:[^$]+)? # possibly an old expansion, followed by... + (:[^$\n]+)? # possibly an old expansion, followed by... \$ # another dollar """ % kwords return pattern @@ -832,6 +886,9 @@ class P4RollBack(Command): return True class P4Submit(Command, P4UserMap): + + conflict_behavior_choices = ("ask", "skip", "quit") + def __init__(self): Command.__init__(self) P4UserMap.__init__(self) @@ -841,23 +898,55 @@ class P4Submit(Command, P4UserMap): # preserve the user, requires relevant p4 permissions optparse.make_option("--preserve-user", dest="preserveUser", action="store_true"), optparse.make_option("--export-labels", dest="exportLabels", action="store_true"), + optparse.make_option("--dry-run", "-n", dest="dry_run", action="store_true"), + optparse.make_option("--prepare-p4-only", dest="prepare_p4_only", action="store_true"), + optparse.make_option("--conflict", dest="conflict_behavior", + choices=self.conflict_behavior_choices) ] self.description = "Submit changes from git to the perforce depot." self.usage += " [name of git branch to submit into perforce depot]" - self.interactive = True self.origin = "" self.detectRenames = False self.preserveUser = gitConfig("git-p4.preserveUser").lower() == "true" + self.dry_run = False + self.prepare_p4_only = False + self.conflict_behavior = None self.isWindows = (platform.system() == "Windows") self.exportLabels = False + self.p4HasMoveCommand = p4_has_move_command() def check(self): if len(p4CmdList("opened ...")) > 0: die("You have files opened with perforce! Close them before starting the sync.") - # replaces everything between 'Description:' and the next P4 submit template field with the - # commit message - def prepareLogMessage(self, template, message): + def separate_jobs_from_description(self, message): + """Extract and return a possible Jobs field in the commit + message. It goes into a separate section in the p4 change + specification. + + A jobs line starts with "Jobs:" and looks like a new field + in a form. Values are white-space separated on the same + line or on following lines that start with a tab. + + This does not parse and extract the full git commit message + like a p4 form. It just sees the Jobs: line as a marker + to pass everything from then on directly into the p4 form, + but outside the description section. + + Return a tuple (stripped log message, jobs string).""" + + m = re.search(r'^Jobs:', message, re.MULTILINE) + if m is None: + return (message, None) + + jobtext = message[m.start():] + stripped_message = message[:m.start()].rstrip() + return (stripped_message, jobtext) + + def prepareLogMessage(self, template, message, jobs): + """Edits the template returned from "p4 change -o" to insert + the message in the Description field, and the jobs text in + the Jobs field.""" result = "" inDescriptionSection = False @@ -870,6 +959,9 @@ class P4Submit(Command, P4UserMap): if inDescriptionSection: if line.startswith("Files:") or line.startswith("Jobs:"): inDescriptionSection = False + # insert Jobs section + if jobs: + result += jobs + "\n" else: continue else: @@ -981,7 +1073,13 @@ class P4Submit(Command, P4UserMap): return 0 def prepareSubmitTemplate(self): - # remove lines in the Files section that show changes to files outside the depot path we're committing into + """Run "p4 change -o" to grab a change specification template. + This does not use "p4 -G", as it is nice to keep the submission + template in original order, since a human might edit it. + + Remove lines in the Files section that show changes to files + outside the depot path we're committing into.""" + template = "" inFilesSection = False for line in p4_read_pipe_lines(['change', '-o']): @@ -1042,31 +1140,14 @@ class P4Submit(Command, P4UserMap): return False def applyCommit(self, id): - print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id)) + """Apply one commit, return True if it succeeded.""" - (p4User, gitEmail) = self.p4UserForCommit(id) + print "Applying", read_pipe(["git", "show", "-s", + "--format=format:%h %s", id]) - if not self.detectRenames: - # If not explicitly set check the config variable - self.detectRenames = gitConfig("git-p4.detectRenames") - - if self.detectRenames.lower() == "false" or self.detectRenames == "": - diffOpts = "" - elif self.detectRenames.lower() == "true": - diffOpts = "-M" - else: - diffOpts = "-M%s" % self.detectRenames - - detectCopies = gitConfig("git-p4.detectCopies") - if detectCopies.lower() == "true": - diffOpts += " -C" - elif detectCopies != "" and detectCopies.lower() != "false": - diffOpts += " -C%s" % detectCopies - - if gitConfig("git-p4.detectCopiesHarder", "--bool") == "true": - diffOpts += " --find-copies-harder" + (p4User, gitEmail) = self.p4UserForCommit(id) - diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id)) + diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (self.diffOpts, id, id)) filesToAdd = set() filesToDelete = set() editedFiles = set() @@ -1106,17 +1187,23 @@ class P4Submit(Command, P4UserMap): editedFiles.add(dest) elif modifier == "R": src, dest = diff['src'], diff['dst'] - p4_integrate(src, dest) - if diff['src_sha1'] != diff['dst_sha1']: - p4_edit(dest) + if self.p4HasMoveCommand: + p4_edit(src) # src must be open before move + p4_move(src, dest) # opens for (move/delete, move/add) else: - pureRenameCopy.add(dest) + p4_integrate(src, dest) + if diff['src_sha1'] != diff['dst_sha1']: + p4_edit(dest) + else: + pureRenameCopy.add(dest) if isModeExecChanged(diff['src_mode'], diff['dst_mode']): - p4_edit(dest) + if not self.p4HasMoveCommand: + p4_edit(dest) # with move: already open, writable filesToChangeExecBit[dest] = diff['dst_mode'] - os.unlink(dest) + if not self.p4HasMoveCommand: + os.unlink(dest) + filesToDelete.add(src) editedFiles.add(dest) - filesToDelete.add(src) else: die("unknown modifier %s for %s" % (modifier, path)) @@ -1163,34 +1250,13 @@ class P4Submit(Command, P4UserMap): patch_succeeded = True if not patch_succeeded: - print "What do you want to do?" - response = "x" - while response != "s" and response != "a" and response != "w": - response = raw_input("[s]kip this patch / [a]pply the patch forcibly " - "and with .rej files / [w]rite the patch to a file (patch.txt) ") - if response == "s": - print "Skipping! Good luck with the next patches..." - for f in editedFiles: - p4_revert(f) - for f in filesToAdd: - os.remove(f) - return - elif response == "a": - os.system(applyPatchCmd) - if len(filesToAdd) > 0: - print "You may also want to call p4 add on the following files:" - print " ".join(filesToAdd) - if len(filesToDelete): - print "The following files should be scheduled for deletion with p4 delete:" - print " ".join(filesToDelete) - die("Please resolve and submit the conflict manually and " - + "continue afterwards with git p4 submit --continue") - elif response == "w": - system(diffcmd + " > patch.txt") - print "Patch saved to patch.txt in %s !" % self.clientPath - die("Please resolve and submit the conflict manually and " - "continue afterwards with git p4 submit --continue") + for f in editedFiles: + p4_revert(f) + return False + # + # Apply the patch for real, and do add/delete/+x handling. + # system(applyPatchCmd) for f in filesToAdd: @@ -1204,91 +1270,132 @@ class P4Submit(Command, P4UserMap): mode = filesToChangeExecBit[f] setP4ExecBit(f, mode) + # + # Build p4 change description, starting with the contents + # of the git commit message. + # logMessage = extractLogMessageFromGitCommit(id) logMessage = logMessage.strip() + (logMessage, jobs) = self.separate_jobs_from_description(logMessage) template = self.prepareSubmitTemplate() + submitTemplate = self.prepareLogMessage(template, logMessage, jobs) - if self.interactive: - submitTemplate = self.prepareLogMessage(template, logMessage) - - if self.preserveUser: - submitTemplate = submitTemplate + ("\n######## Actual user %s, modified after commit\n" % p4User) - - if os.environ.has_key("P4DIFF"): - del(os.environ["P4DIFF"]) - diff = "" - for editedFile in editedFiles: - diff += p4_read_pipe(['diff', '-du', - wildcard_encode(editedFile)]) - - newdiff = "" - for newFile in filesToAdd: - newdiff += "==== new file ====\n" - newdiff += "--- /dev/null\n" - newdiff += "+++ %s\n" % newFile - f = open(newFile, "r") - for line in f.readlines(): - newdiff += "+" + line - f.close() - - if self.checkAuthorship and not self.p4UserIsMe(p4User): - submitTemplate += "######## git author %s does not match your p4 account.\n" % gitEmail - submitTemplate += "######## Use option --preserve-user to modify authorship.\n" - submitTemplate += "######## Variable git-p4.skipUserNameCheck hides this message.\n" - - separatorLine = "######## everything below this line is just the diff #######\n" - - (handle, fileName) = tempfile.mkstemp() - tmpFile = os.fdopen(handle, "w+") - if self.isWindows: - submitTemplate = submitTemplate.replace("\n", "\r\n") - separatorLine = separatorLine.replace("\n", "\r\n") - newdiff = newdiff.replace("\n", "\r\n") - tmpFile.write(submitTemplate + separatorLine + diff + newdiff) - tmpFile.close() - - if self.edit_template(fileName): - # read the edited message and submit - tmpFile = open(fileName, "rb") - message = tmpFile.read() - tmpFile.close() - submitTemplate = message[:message.index(separatorLine)] - if self.isWindows: - submitTemplate = submitTemplate.replace("\r\n", "\n") - p4_write_pipe(['submit', '-i'], submitTemplate) - - if self.preserveUser: - if p4User: - # Get last changelist number. Cannot easily get it from - # the submit command output as the output is - # unmarshalled. - changelist = self.lastP4Changelist() - self.modifyChangelistUser(changelist, p4User) - - # The rename/copy happened by applying a patch that created a - # new file. This leaves it writable, which confuses p4. + if self.preserveUser: + submitTemplate += "\n######## Actual user %s, modified after commit\n" % p4User + + if self.checkAuthorship and not self.p4UserIsMe(p4User): + submitTemplate += "######## git author %s does not match your p4 account.\n" % gitEmail + submitTemplate += "######## Use option --preserve-user to modify authorship.\n" + submitTemplate += "######## Variable git-p4.skipUserNameCheck hides this message.\n" + + separatorLine = "######## everything below this line is just the diff #######\n" + + # diff + if os.environ.has_key("P4DIFF"): + del(os.environ["P4DIFF"]) + diff = "" + for editedFile in editedFiles: + diff += p4_read_pipe(['diff', '-du', + wildcard_encode(editedFile)]) + + # new file diff + newdiff = "" + for newFile in filesToAdd: + newdiff += "==== new file ====\n" + newdiff += "--- /dev/null\n" + newdiff += "+++ %s\n" % newFile + f = open(newFile, "r") + for line in f.readlines(): + newdiff += "+" + line + f.close() + + # change description file: submitTemplate, separatorLine, diff, newdiff + (handle, fileName) = tempfile.mkstemp() + tmpFile = os.fdopen(handle, "w+") + if self.isWindows: + submitTemplate = submitTemplate.replace("\n", "\r\n") + separatorLine = separatorLine.replace("\n", "\r\n") + newdiff = newdiff.replace("\n", "\r\n") + tmpFile.write(submitTemplate + separatorLine + diff + newdiff) + tmpFile.close() + + if self.prepare_p4_only: + # + # Leave the p4 tree prepared, and the submit template around + # and let the user decide what to do next + # + print + print "P4 workspace prepared for submission." + print "To submit or revert, go to client workspace" + print " " + self.clientPath + print + print "To submit, use \"p4 submit\" to write a new description," + print "or \"p4 submit -i %s\" to use the one prepared by" \ + " \"git p4\"." % fileName + print "You can delete the file \"%s\" when finished." % fileName + + if self.preserveUser and p4User and not self.p4UserIsMe(p4User): + print "To preserve change ownership by user %s, you must\n" \ + "do \"p4 change -f <change>\" after submitting and\n" \ + "edit the User field." + if pureRenameCopy: + print "After submitting, renamed files must be re-synced." + print "Invoke \"p4 sync -f\" on each of these files:" for f in pureRenameCopy: - p4_sync(f, "-f") + print " " + f - else: - # skip this patch - print "Submission cancelled, undoing p4 changes." - for f in editedFiles: - p4_revert(f) + print + print "To revert the changes, use \"p4 revert ...\", and delete" + print "the submit template file \"%s\"" % fileName + if filesToAdd: + print "Since the commit adds new files, they must be deleted:" for f in filesToAdd: - p4_revert(f) - os.remove(f) + print " " + f + print + return True + + # + # Let the user edit the change description, then submit it. + # + if self.edit_template(fileName): + # read the edited message and submit + ret = True + tmpFile = open(fileName, "rb") + message = tmpFile.read() + tmpFile.close() + submitTemplate = message[:message.index(separatorLine)] + if self.isWindows: + submitTemplate = submitTemplate.replace("\r\n", "\n") + p4_write_pipe(['submit', '-i'], submitTemplate) + + if self.preserveUser: + if p4User: + # Get last changelist number. Cannot easily get it from + # the submit command output as the output is + # unmarshalled. + changelist = self.lastP4Changelist() + self.modifyChangelistUser(changelist, p4User) + + # The rename/copy happened by applying a patch that created a + # new file. This leaves it writable, which confuses p4. + for f in pureRenameCopy: + p4_sync(f, "-f") - os.remove(fileName) else: - fileName = "submit.txt" - file = open(fileName, "w+") - file.write(self.prepareLogMessage(template, logMessage)) - file.close() - print ("Perforce submit template written as %s. " - + "Please review/edit and then use p4 submit -i < %s to submit directly!" - % (fileName, fileName)) + # skip this patch + ret = False + print "Submission cancelled, undoing p4 changes." + for f in editedFiles: + p4_revert(f) + for f in filesToAdd: + p4_revert(f) + os.remove(f) + for f in filesToDelete: + p4_revert(f) + + os.remove(fileName) + return ret # Export git tags as p4 labels. Create a p4 label and then tag # with that. @@ -1346,14 +1453,20 @@ class P4Submit(Command, P4UserMap): for mapping in clientSpec.mappings: labelTemplate += "\t%s\n" % mapping.depot_side.path - p4_write_pipe(["label", "-i"], labelTemplate) + if self.dry_run: + print "Would create p4 label %s for tag" % name + elif self.prepare_p4_only: + print "Not creating p4 label %s for tag due to option" \ + " --prepare-p4-only" % name + else: + p4_write_pipe(["label", "-i"], labelTemplate) - # Use the label - p4_system(["tag", "-l", name] + - ["%s@%s" % (mapping.depot_side.path, changelist) for mapping in clientSpec.mappings]) + # Use the label + p4_system(["tag", "-l", name] + + ["%s@%s" % (mapping.depot_side.path, changelist) for mapping in clientSpec.mappings]) - if verbose: - print "created p4 label for tag %s" % name + if verbose: + print "created p4 label for tag %s" % name def run(self, args): if len(args) == 0: @@ -1380,6 +1493,16 @@ class P4Submit(Command, P4UserMap): if not self.canChangeChangelists(): die("Cannot preserve user names without p4 super-user or admin permissions") + # if not set from the command line, try the config file + if self.conflict_behavior is None: + val = gitConfig("git-p4.conflict") + if val: + if val not in self.conflict_behavior_choices: + die("Invalid value '%s' for config git-p4.conflict" % val) + else: + val = "ask" + self.conflict_behavior = val + if self.verbose: print "Origin branch is " + self.origin @@ -1412,12 +1535,15 @@ class P4Submit(Command, P4UserMap): os.makedirs(self.clientPath) chdir(self.clientPath) - print "Synchronizing p4 checkout..." - if new_client_dir: - # old one was destroyed, and maybe nobody told p4 - p4_sync("...", "-f") + if self.dry_run: + print "Would synchronize p4 checkout in %s" % self.clientPath else: - p4_sync("...") + print "Synchronizing p4 checkout..." + if new_client_dir: + # old one was destroyed, and maybe nobody told p4 + p4_sync("...", "-f") + else: + p4_sync("...") self.check() commits = [] @@ -1433,16 +1559,95 @@ class P4Submit(Command, P4UserMap): if self.preserveUser: self.checkValidP4Users(commits) - while len(commits) > 0: - commit = commits[0] - commits = commits[1:] - self.applyCommit(commit) - if not self.interactive: - break + # + # Build up a set of options to be passed to diff when + # submitting each commit to p4. + # + if self.detectRenames: + # command-line -M arg + self.diffOpts = "-M" + else: + # If not explicitly set check the config variable + detectRenames = gitConfig("git-p4.detectRenames") + + if detectRenames.lower() == "false" or detectRenames == "": + self.diffOpts = "" + elif detectRenames.lower() == "true": + self.diffOpts = "-M" + else: + self.diffOpts = "-M%s" % detectRenames + + # no command-line arg for -C or --find-copies-harder, just + # config variables + detectCopies = gitConfig("git-p4.detectCopies") + if detectCopies.lower() == "false" or detectCopies == "": + pass + elif detectCopies.lower() == "true": + self.diffOpts += " -C" + else: + self.diffOpts += " -C%s" % detectCopies + + if gitConfig("git-p4.detectCopiesHarder", "--bool") == "true": + self.diffOpts += " --find-copies-harder" + + # + # Apply the commits, one at a time. On failure, ask if should + # continue to try the rest of the patches, or quit. + # + if self.dry_run: + print "Would apply" + applied = [] + last = len(commits) - 1 + for i, commit in enumerate(commits): + if self.dry_run: + print " ", read_pipe(["git", "show", "-s", + "--format=format:%h %s", commit]) + ok = True + else: + ok = self.applyCommit(commit) + if ok: + applied.append(commit) + else: + if self.prepare_p4_only and i < last: + print "Processing only the first commit due to option" \ + " --prepare-p4-only" + break + if i < last: + quit = False + while True: + # prompt for what to do, or use the option/variable + if self.conflict_behavior == "ask": + print "What do you want to do?" + response = raw_input("[s]kip this commit but apply" + " the rest, or [q]uit? ") + if not response: + continue + elif self.conflict_behavior == "skip": + response = "s" + elif self.conflict_behavior == "quit": + response = "q" + else: + die("Unknown conflict_behavior '%s'" % + self.conflict_behavior) + + if response[0] == "s": + print "Skipping this commit, but applying the rest" + break + if response[0] == "q": + print "Quitting" + quit = True + break + if quit: + break - if len(commits) == 0: - print "All changes applied!" - chdir(self.oldWorkingDirectory) + chdir(self.oldWorkingDirectory) + + if self.dry_run: + pass + elif self.prepare_p4_only: + pass + elif len(commits) == len(applied): + print "All commits applied!" sync = P4Sync() sync.run([]) @@ -1450,6 +1655,20 @@ class P4Submit(Command, P4UserMap): rebase = P4Rebase() rebase.rebase() + else: + if len(applied) == 0: + print "No commits applied." + else: + print "Applied only the commits marked with '*':" + for c in commits: + if c in applied: + star = "*" + else: + star = " " + print star, read_pipe(["git", "show", "-s", + "--format=format:%h %s", c]) + print "You will have to do 'git p4 sync' and rebase." + if gitConfig("git-p4.exportLabels", "--bool") == "true": self.exportLabels = True @@ -1460,6 +1679,10 @@ class P4Submit(Command, P4UserMap): missingGitTags = gitTags - p4Labels self.exportGitTags(missingGitTags) + # exit with error unless everything applied perfecly + if len(commits) != len(applied): + sys.exit(1) + return True class View(object): @@ -1766,19 +1989,41 @@ class P4Sync(Command, P4UserMap): return files def stripRepoPath(self, path, prefixes): - if self.useClientSpec: - return self.clientSpecDirs.map_in_client(path) + """When streaming files, this is called to map a p4 depot path + to where it should go in git. The prefixes are either + self.depotPaths, or self.branchPrefixes in the case of + branch detection.""" - if self.keepRepoPath: - prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])] + if self.useClientSpec: + # branch detection moves files up a level (the branch name) + # from what client spec interpretation gives + path = self.clientSpecDirs.map_in_client(path) + if self.detectBranches: + for b in self.knownBranches: + if path.startswith(b + "/"): + path = path[len(b)+1:] + + elif self.keepRepoPath: + # Preserve everything in relative path name except leading + # //depot/; just look at first prefix as they all should + # be in the same depot. + depot = re.sub("^(//[^/]+/).*", r'\1', prefixes[0]) + if p4PathStartsWith(path, depot): + path = path[len(depot):] - for p in prefixes: - if p4PathStartsWith(path, p): - path = path[len(p):] + else: + for p in prefixes: + if p4PathStartsWith(path, p): + path = path[len(p):] + break + path = wildcard_decode(path) return path def splitFilesIntoBranches(self, commit): + """Look at each depotFile in the commit to figure out to what + branch it belongs.""" + branches = {} fnum = 0 while commit.has_key("depotFile%s" % fnum): @@ -1796,12 +2041,16 @@ class P4Sync(Command, P4UserMap): file["type"] = commit["type%s" % fnum] fnum = fnum + 1 - relPath = self.stripRepoPath(path, self.depotPaths) - relPath = wildcard_decode(relPath) + # start with the full relative path where this file would + # go in a p4 client + if self.useClientSpec: + relPath = self.clientSpecDirs.map_in_client(path) + else: + relPath = self.stripRepoPath(path, self.depotPaths) for branch in self.knownBranches.keys(): - - # add a trailing slash so that a commit into qt/4.2foo doesn't end up in qt/4.2 + # add a trailing slash so that a commit into qt/4.2foo + # doesn't end up in qt/4.2, e.g. if relPath.startswith(branch + "/"): if branch not in branches: branches[branch] = [] @@ -1815,7 +2064,6 @@ class P4Sync(Command, P4UserMap): def streamOneP4File(self, file, contents): relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes) - relPath = wildcard_decode(relPath) if verbose: sys.stderr.write("%s\n" % relPath) @@ -1884,7 +2132,6 @@ class P4Sync(Command, P4UserMap): def streamOneP4Deletion(self, file): relPath = self.stripRepoPath(file['path'], self.branchPrefixes) - relPath = wildcard_decode(relPath) if verbose: sys.stderr.write("delete %s\n" % relPath) self.gitStream.write("D %s\n" % relPath) @@ -1892,6 +2139,29 @@ class P4Sync(Command, P4UserMap): # handle another chunk of streaming data def streamP4FilesCb(self, marshalled): + # catch p4 errors and complain + err = None + if "code" in marshalled: + if marshalled["code"] == "error": + if "data" in marshalled: + err = marshalled["data"].rstrip() + if err: + f = None + if self.stream_have_file_info: + if "depotFile" in self.stream_file: + f = self.stream_file["depotFile"] + # force a failure in fast-import, else an empty + # commit will be made + self.gitStream.write("\n") + self.gitStream.write("die-now\n") + self.gitStream.close() + # ignore errors, but make sure it exits first + self.importProcess.wait() + if f: + die("Error from p4 print for %s: %s" % (f, err)) + else: + die("Error from p4 print: %s" % err) + if marshalled.has_key('depotFile') and self.stream_have_file_info: # start of a new file - output the old one first self.streamOneP4File(self.stream_file, self.stream_contents) @@ -1989,10 +2259,9 @@ class P4Sync(Command, P4UserMap): gitStream.write(description) gitStream.write("\n") - def commit(self, details, files, branch, branchPrefixes, parent = ""): + def commit(self, details, files, branch, parent = ""): epoch = details["time"] author = details["user"] - self.branchPrefixes = branchPrefixes if self.verbose: print "commit into %s" % branch @@ -2001,7 +2270,7 @@ class P4Sync(Command, P4UserMap): # create a commit. new_files = [] for f in files: - if [p for p in branchPrefixes if p4PathStartsWith(f['path'], p)]: + if [p for p in self.branchPrefixes if p4PathStartsWith(f['path'], p)]: new_files.append (f) else: sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path']) @@ -2018,8 +2287,8 @@ class P4Sync(Command, P4UserMap): self.gitStream.write("data <<EOT\n") self.gitStream.write(details["desc"]) - self.gitStream.write("\n[git-p4: depot-paths = \"%s\": change = %s" - % (','.join (branchPrefixes), details["change"])) + self.gitStream.write("\n[git-p4: depot-paths = \"%s\": change = %s" % + (','.join(self.branchPrefixes), details["change"])) if len(details['options']) > 0: self.gitStream.write(": options = %s" % details['options']) self.gitStream.write("]\nEOT\n\n") @@ -2042,7 +2311,7 @@ class P4Sync(Command, P4UserMap): print "Change %s is labelled %s" % (change, labelDetails) files = p4CmdList(["files"] + ["%s...@%s" % (p, change) - for p in branchPrefixes]) + for p in self.branchPrefixes]) if len(files) == len(labelRevisions): @@ -2137,7 +2406,7 @@ class P4Sync(Command, P4UserMap): try: tmwhen = time.strptime(labelDetails['Update'], "%Y/%m/%d %H:%M:%S") except ValueError: - print "Could not convert label time %s" % labelDetail['Update'] + print "Could not convert label time %s" % labelDetails['Update'] tmwhen = 1 when = int(time.mktime(tmwhen)) @@ -2339,7 +2608,7 @@ class P4Sync(Command, P4UserMap): def importChanges(self, changes): cnt = 1 for change in changes: - description = p4Cmd(["describe", str(change)]) + description = p4_describe(change) self.updateOptionDict(description) if not self.silent: @@ -2353,6 +2622,7 @@ class P4Sync(Command, P4UserMap): for branch in branches.keys(): ## HACK --hwn branchPrefix = self.depotPaths[0] + branch + "/" + self.branchPrefixes = [ branchPrefix ] parent = "" @@ -2397,19 +2667,19 @@ class P4Sync(Command, P4UserMap): tempBranch = os.path.join(self.tempBranchLocation, "%d" % (change)) if self.verbose: print "Creating temporary branch: " + tempBranch - self.commit(description, filesForCommit, tempBranch, [branchPrefix]) + self.commit(description, filesForCommit, tempBranch) self.tempBranches.append(tempBranch) self.checkpoint() blob = self.searchParent(parent, branch, tempBranch) if blob: - self.commit(description, filesForCommit, branch, [branchPrefix], blob) + self.commit(description, filesForCommit, branch, blob) else: if self.verbose: print "Parent of %s not found. Committing into head of %s" % (branch, parent) - self.commit(description, filesForCommit, branch, [branchPrefix], parent) + self.commit(description, filesForCommit, branch, parent) else: files = self.extractFilesFromCommit(description) - self.commit(description, files, self.branch, self.depotPaths, + self.commit(description, files, self.branch, self.initialParent) self.initialParent = "" except IOError: @@ -2462,18 +2732,12 @@ class P4Sync(Command, P4UserMap): # Use time from top-most change so that all git p4 clones of # the same p4 repo have the same commit SHA1s. - res = p4CmdList("describe -s %d" % newestRevision) - newestTime = None - for r in res: - if r.has_key('time'): - newestTime = int(r['time']) - if newestTime is None: - die("\"describe -s\" on newest change %d did not give a time") - details["time"] = newestTime + res = p4_describe(newestRevision) + details["time"] = res["time"] self.updateOptionDict(details) try: - self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPaths) + self.commit(details, self.extractFilesFromCommit(details), self.branch) except IOError: print "IO error with git fast-import. Is your git version recent enough?" print self.gitError.read() @@ -2631,6 +2895,9 @@ class P4Sync(Command, P4UserMap): self.depotPaths = newPaths + # --detect-branches may change this for each branch + self.branchPrefixes = self.depotPaths + self.loadUserMapFromCache() self.labels = {} if self.detectLabels: @@ -2656,12 +2923,13 @@ class P4Sync(Command, P4UserMap): self.tz = "%+03d%02d" % (- time.timezone / 3600, ((- time.timezone % 3600) / 60)) - importProcess = subprocess.Popen(["git", "fast-import"], - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE); - self.gitOutput = importProcess.stdout - self.gitStream = importProcess.stdin - self.gitError = importProcess.stderr + self.importProcess = subprocess.Popen(["git", "fast-import"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE); + self.gitOutput = self.importProcess.stdout + self.gitStream = self.importProcess.stdin + self.gitError = self.importProcess.stderr if revision: self.importHeadRevision(revision) @@ -2721,7 +2989,7 @@ class P4Sync(Command, P4UserMap): self.importP4Labels(self.gitStream, missingP4Labels) self.gitStream.close() - if importProcess.wait() != 0: + if self.importProcess.wait() != 0: die("fast-import failed: %s" % self.gitError.read()) self.gitOutput.close() self.gitError.close() @@ -2920,7 +3188,6 @@ def main(): printUsage(commands.keys()) sys.exit(2) - cmd = "" cmdName = sys.argv[1] try: klass = commands[cmdName] @@ -2936,7 +3203,7 @@ def main(): args = sys.argv[2:] - options.append(optparse.make_option("--verbose", dest="verbose", action="store_true")) + options.append(optparse.make_option("--verbose", "-v", dest="verbose", action="store_true")) if cmd.needsGit: options.append(optparse.make_option("--git-dir", dest="gitdir")) diff --git a/git-parse-remote.sh b/git-parse-remote.sh index 484b2e61c..0e87e0915 100644 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -80,7 +80,7 @@ See git-${cmd}(1) for details If you wish to set tracking information for this branch you can do so with: - git branch --set-upstream ${branch_name#refs/heads/} $remote/<branch> + git branch --set-upstream-to=$remote/<branch> ${branch_name#refs/heads/} " fi exit 1 diff --git a/git-pull.sh b/git-pull.sh index 2a10047eb..266e682f6 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -200,6 +200,7 @@ test true = "$rebase" && { require_clean_work_tree "pull with rebase" "Please commit or stash them." fi oldremoteref= && + test -n "$curr_branch" && . git-parse-remote && remoteref="$(get_remote_merge_branch "$@" 2>/dev/null)" && oldremoteref="$(git rev-parse -q --verify "$remoteref")" && diff --git a/git-rebase--am.sh b/git-rebase--am.sh index 04d89415f..392ebc979 100644 --- a/git-rebase--am.sh +++ b/git-rebase--am.sh @@ -3,8 +3,6 @@ # Copyright (c) 2010 Junio C Hamano. # -. git-sh-setup - case "$action" in continue) git am --resolved --resolvemsg="$resolvemsg" && diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 84926783d..44901d53c 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -9,9 +9,7 @@ # # The original idea comes from Eric W. Biederman, in # http://article.gmane.org/gmane.comp.version-control.git/22407 - -. git-sh-setup - +# # The file containing rebase commands, comments, and empty lines. # This file is created by "git rebase -i" then edited by the user. As # the lines are processed, they are removed from the front of this @@ -117,6 +115,23 @@ mark_action_done () { fi } +append_todo_help () { + cat >> "$todo" << EOF +# +# Commands: +# p, pick = use commit +# r, reword = use commit, but edit the commit message +# e, edit = use commit, but stop for amending +# s, squash = use commit, but meld into previous commit +# f, fixup = like "squash", but discard this commit's log message +# x, exec = run command (the rest of the line) using shell +# +# These lines can be re-ordered; they are executed from top to bottom. +# +# If you remove a line here THAT COMMIT WILL BE LOST. +EOF +} + make_patch () { sha1_and_parents="$(git rev-list --parents -1 "$1")" case "$sha1_and_parents" in @@ -417,6 +432,29 @@ record_in_rewritten() { esac } +do_pick () { + if test "$(git rev-parse HEAD)" = "$squash_onto" + then + # Set the correct commit message and author info on the + # sentinel root before cherry-picking the original changes + # without committing (-n). Finally, update the sentinel again + # to include these changes. If the cherry-pick results in a + # conflict, this means our behaviour is similar to a standard + # failed cherry-pick during rebase, with a dirty index to + # resolve before manually running git commit --amend then git + # rebase --continue. + git commit --allow-empty --allow-empty-message --amend \ + --no-post-rewrite -n -q -C $1 && + pick_one -n $1 && + git commit --allow-empty --allow-empty-message \ + --amend --no-post-rewrite -n -q -C $1 || + die_with_patch $1 "Could not apply $1... $2" + else + pick_one $1 || + die_with_patch $1 "Could not apply $1... $2" + fi +} + do_next () { rm -f "$msg" "$author_script" "$amend" || exit read -r command sha1 rest < "$todo" @@ -428,16 +466,14 @@ do_next () { comment_for_reflog pick mark_action_done - pick_one $sha1 || - die_with_patch $sha1 "Could not apply $sha1... $rest" + do_pick $sha1 "$rest" record_in_rewritten $sha1 ;; reword|r) comment_for_reflog reword mark_action_done - pick_one $sha1 || - die_with_patch $sha1 "Could not apply $sha1... $rest" + do_pick $sha1 "$rest" git commit --amend --no-post-rewrite || { warn "Could not amend commit after successfully picking $sha1... $rest" warn "This is most likely due to an empty commit message, or the pre-commit hook" @@ -451,8 +487,7 @@ do_next () { comment_for_reflog edit mark_action_done - pick_one $sha1 || - die_with_patch $sha1 "Could not apply $sha1... $rest" + do_pick $sha1 "$rest" warn "Stopped at $sha1... $rest" exit_with_patch $sha1 0 ;; @@ -475,25 +510,28 @@ do_next () { author_script_content=$(get_author_ident_from_commit HEAD) echo "$author_script_content" > "$author_script" eval "$author_script_content" - output git reset --soft HEAD^ - pick_one -n $sha1 || die_failed_squash $sha1 "$rest" + if ! pick_one -n $sha1 + then + git rev-parse --verify HEAD >"$amend" + die_failed_squash $sha1 "$rest" + fi case "$(peek_next_command)" in squash|s|fixup|f) # This is an intermediate commit; its message will only be # used in case of trouble. So use the long version: - do_with_author output git commit --no-verify -F "$squash_msg" || + do_with_author output git commit --amend --no-verify -F "$squash_msg" || die_failed_squash $sha1 "$rest" ;; *) # This is the final command of this squash/fixup group if test -f "$fixup_msg" then - do_with_author git commit --no-verify -F "$fixup_msg" || + do_with_author git commit --amend --no-verify -F "$fixup_msg" || die_failed_squash $sha1 "$rest" else cp "$squash_msg" "$GIT_DIR"/SQUASH_MSG || exit rm -f "$GIT_DIR"/MERGE_MSG - do_with_author git commit --no-verify -e || + do_with_author git commit --amend --no-verify -F "$GIT_DIR"/SQUASH_MSG -e || die_failed_squash $sha1 "$rest" fi rm -f "$squash_msg" "$fixup_msg" @@ -523,6 +561,10 @@ do_next () { warn warn " git rebase --continue" warn + if test $status -eq 127 # command not found + then + status=1 + fi exit "$status" elif test "$dirty" = t then @@ -537,11 +579,12 @@ do_next () { ;; *) warn "Unknown command: $command $sha1 $rest" + fixtodo="Please fix this using 'git rebase --edit-todo'." if git rev-parse --verify -q "$sha1" >/dev/null then - die_with_patch $sha1 "Please fix this in the file $todo." + die_with_patch $sha1 "$fixtodo" else - die "Please fix this in the file $todo." + die "$fixtodo" fi ;; esac @@ -683,6 +726,27 @@ rearrange_squash () { rm -f "$1.sq" "$1.rearranged" } +# Add commands after a pick or after a squash/fixup serie +# in the todo list. +add_exec_commands () { + { + first=t + while read -r insn rest + do + case $insn in + pick) + test -n "$first" || + printf "%s" "$cmd" + ;; + esac + printf "%s %s\n" "$insn" "$rest" + first= + done + printf "%s" "$cmd" + } <"$1" >"$1.new" && + mv "$1.new" "$1" +} + case "$action" in continue) # do we have anything to commit? @@ -708,7 +772,6 @@ In both case, once you're done, continue with: fi . "$author_script" || die "Error trying to find the author identity to amend commit" - current_head= if test -f "$amend" then current_head=$(git rev-parse --verify HEAD) @@ -716,13 +779,12 @@ In both case, once you're done, continue with: die "\ You have uncommitted changes in your working tree. Please, commit them first and then run 'git rebase --continue' again." - git reset --soft HEAD^ || - die "Cannot rewind the HEAD" + do_with_author git commit --amend --no-verify -F "$msg" -e || + die "Could not commit staged changes." + else + do_with_author git commit --no-verify -F "$msg" -e || + die "Could not commit staged changes." fi - do_with_author git commit --no-verify -F "$msg" -e || { - test -n "$current_head" && git reset --soft $current_head - die "Could not commit staged changes." - } fi record_in_rewritten "$(cat "$state_dir"/stopped-sha)" @@ -735,6 +797,23 @@ skip) do_rest ;; +edit-todo) + sed -e '/^#/d' < "$todo" > "$todo".new + mv -f "$todo".new "$todo" + append_todo_help + cat >> "$todo" << EOF +# +# You are editing the todo file of an ongoing interactive rebase. +# To continue rebase after editing, run: +# git rebase --continue +# +EOF + + git_sequence_editor "$todo" || + die "Could not execute editor" + + exit + ;; esac git var GIT_COMMITTER_IDENT >/dev/null || @@ -856,21 +935,15 @@ fi test -s "$todo" || echo noop >> "$todo" test -n "$autosquash" && rearrange_squash "$todo" +test -n "$cmd" && add_exec_commands "$todo" + cat >> "$todo" << EOF # Rebase $shortrevisions onto $shortonto +EOF +append_todo_help +cat >> "$todo" << EOF # -# Commands: -# p, pick = use commit -# r, reword = use commit, but edit the commit message -# e, edit = use commit, but stop for amending -# s, squash = use commit, but meld into previous commit -# f, fixup = like "squash", but discard this commit's log message -# x, exec = run command (the rest of the line) using shell -# -# These lines can be re-ordered; they are executed from top to bottom. -# -# If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. # EOF diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh index dc599077f..b10f2cf21 100644 --- a/git-rebase--merge.sh +++ b/git-rebase--merge.sh @@ -3,8 +3,6 @@ # Copyright (c) 2010 Junio C Hamano. # -. git-sh-setup - prec=4 read_state () { diff --git a/git-rebase.sh b/git-rebase.sh index e61673744..b2f1c76dc 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -3,36 +3,12 @@ # Copyright (c) 2005 Junio C Hamano. # -USAGE='[--interactive | -i] [-v] [--force-rebase | -f] [--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]' -LONG_USAGE='git-rebase replaces <branch> with a new branch of the -same name. When the --onto option is provided the new branch starts -out with a HEAD equal to <newbase>, otherwise it is equal to <upstream> -It then attempts to create a new commit for each commit from the original -<branch> that does not exist in the <upstream> branch. - -It is possible that a merge failure will prevent this process from being -completely automatic. You will have to resolve any such merge failure -and run git rebase --continue. Another option is to bypass the commit -that caused the merge failure with git rebase --skip. To check out the -original <branch> and remove the .git/rebase-apply working files, use the -command git rebase --abort instead. - -Note that if <branch> is not specified on the command line, the -currently checked out branch is used. - -Example: git-rebase master~1 topic - - A---B---C topic A'\''--B'\''--C'\'' topic - / --> / - D---E---F---G master D---E---F---G master -' - SUBDIRECTORY_OK=Yes OPTIONS_KEEPDASHDASH= OPTIONS_SPEC="\ -git rebase [-i] [options] [--onto <newbase>] [<upstream>] [<branch>] -git rebase [-i] [options] --onto <newbase> --root [<branch>] -git-rebase [-i] --continue | --abort | --skip +git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>] +git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>] +git-rebase --continue | --abort | --skip | --edit-todo -- Available options are v,verbose! display a diffstat of what changed upstream @@ -43,6 +19,7 @@ s,strategy=! use the given merge strategy no-ff! cherry-pick all commits, even if unchanged m,merge! use merging strategies to rebase i,interactive! let the user edit the list of commits to rebase +x,exec=! add exec lines after each commit of the editable list k,keep-empty preserve empty commits during rebase f,force-rebase! force rebase even if branch is up to date X,strategy-option=! pass the argument through to the merge strategy @@ -61,8 +38,10 @@ C=! passed to 'git apply' continue! continue abort! abort and check out the original branch skip! skip current patch and continue +edit-todo! edit the todo list during an interactive rebase " . git-sh-setup +. git-sh-i18n set_reflog_action rebase require_work_tree_exists cd_to_toplevel @@ -71,11 +50,12 @@ LF=' ' ok_to_skip_pre_rebase= resolvemsg=" -When you have resolved this problem run \"git rebase --continue\". -If you would prefer to skip this patch, instead run \"git rebase --skip\". -To check out the original branch and stop rebasing run \"git rebase --abort\". +$(gettext 'When you have resolved this problem, run "git rebase --continue". +If you prefer to skip this patch, run "git rebase --skip" instead. +To check out the original branch and stop rebasing, run "git rebase --abort".') " unset onto +cmd= strategy= strategy_opts= do_merge= @@ -158,7 +138,7 @@ move_to_original_branch () { git symbolic-ref \ -m "rebase finished: returning to $head_name" \ HEAD $head_name || - die "Could not move back to $head_name" + die "$(gettext "Could not move back to $head_name")" ;; esac } @@ -177,12 +157,12 @@ run_pre_rebase_hook () { test -x "$GIT_DIR/hooks/pre-rebase" then "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || - die "The pre-rebase hook refused to rebase." + die "$(gettext "The pre-rebase hook refused to rebase.")" fi } test -f "$apply_dir"/applying && - die 'It looks like git-am is in progress. Cannot rebase.' + die "$(gettext "It looks like git-am is in progress. Cannot rebase.")" if test -d "$apply_dir" then @@ -211,7 +191,7 @@ do --verify) ok_to_skip_pre_rebase= ;; - --continue|--skip|--abort) + --continue|--skip|--abort|--edit-todo) test $total_argc -eq 2 || usage action=${1##--} ;; @@ -220,6 +200,11 @@ do onto="$2" shift ;; + -x) + test 2 -le "$#" || usage + cmd="${cmd}exec $2${LF}" + shift + ;; -i) interactive_rebase=explicit ;; @@ -305,9 +290,15 @@ do done test $# -gt 2 && usage +if test -n "$cmd" && + test "$interactive_rebase" != explicit +then + die "$(gettext "The --exec option must be used with the --interactive option")" +fi + if test -n "$action" then - test -z "$in_progress" && die "No rebase in progress?" + test -z "$in_progress" && die "$(gettext "No rebase in progress?")" # Only interactive rebase uses detailed reflog messages if test "$type" = interactive && test "$GIT_REFLOG_ACTION" = rebase then @@ -316,15 +307,20 @@ then fi fi +if test "$action" = "edit-todo" && test "$type" != "interactive" +then + die "$(gettext "The --edit-todo action can only be used during interactive rebase.")" +fi + case "$action" in continue) # Sanity check git rev-parse --verify HEAD >/dev/null || - die "Cannot read HEAD" + die "$(gettext "Cannot read HEAD")" git update-index --ignore-submodules --refresh && git diff-files --quiet --ignore-submodules || { - echo "You must edit all merge conflicts and then" - echo "mark them as resolved using git add" + echo "$(gettext "You must edit all merge conflicts and then +mark them as resolved using git add")" exit 1 } read_basic_state @@ -341,27 +337,38 @@ abort) case "$head_name" in refs/*) git symbolic-ref -m "rebase: aborting" HEAD $head_name || - die "Could not move back to $head_name" + die "$(eval_gettext "Could not move back to \$head_name")" ;; esac output git reset --hard $orig_head rm -r "$state_dir" exit ;; +edit-todo) + run_specific_rebase + ;; esac # Make sure no rebase is in progress if test -n "$in_progress" then - die ' -It seems that there is already a '"${state_dir##*/}"' directory, and + state_dir_base=${state_dir##*/} + cmd_live_rebase="git rebase (--continue | --abort | --skip)" + cmd_clear_stale_rebase="rm -fr \"$state_dir\"" + die " +$(eval_gettext 'It seems that there is already a $state_dir_base directory, and I wonder if you are in the middle of another rebase. If that is the case, please try - git rebase (--continue | --abort | --skip) + $cmd_live_rebase If that is not the case, please - rm -fr '"$state_dir"' + $cmd_clear_stale_rebase and run me again. I am stopping in case you still have something -valuable there.' +valuable there.')" +fi + +if test -n "$rebase_root" && test -z "$onto" +then + test -z "$interactive_rebase" && interactive_rebase=implied fi if test -n "$interactive_rebase" @@ -394,12 +401,18 @@ then ;; esac upstream=`git rev-parse --verify "${upstream_name}^0"` || - die "invalid upstream $upstream_name" + die "$(eval_gettext "invalid upstream \$upstream_name")" upstream_arg="$upstream_name" else - test -z "$onto" && die "You must specify --onto when using --root" + if test -z "$onto" + then + empty_tree=`git hash-object -t tree /dev/null` + onto=`git commit-tree $empty_tree </dev/null` + squash_onto="$onto" + fi unset upstream_name unset upstream + test $# -gt 1 && usage upstream_arg=--root fi @@ -412,19 +425,19 @@ case "$onto_name" in then case "$onto" in ?*"$LF"?*) - die "$onto_name: there are more than one merge bases" + die "$(eval_gettext "\$onto_name: there are more than one merge bases")" ;; '') - die "$onto_name: there is no merge base" + die "$(eval_gettext "\$onto_name: there is no merge base")" ;; esac else - die "$onto_name: there is no merge base" + die "$(eval_gettext "\$onto_name: there is no merge base")" fi ;; *) onto=$(git rev-parse --verify "${onto_name}^0") || - die "Does not point to a valid commit: $onto_name" + die "$(eval_gettext "Does not point to a valid commit: \$onto_name")" ;; esac @@ -447,10 +460,10 @@ case "$#" in then head_name="detached HEAD" else - die "fatal: no such branch: $1" + die "$(eval_gettext "fatal: no such branch: \$branch_name")" fi ;; -*) +0) # Do not need to switch branches, we are already on it. if branch_name=`git symbolic-ref -q HEAD` then @@ -462,9 +475,12 @@ case "$#" in fi orig_head=$(git rev-parse --verify "${branch_name}^0") || exit ;; +*) + die "BUG: unexpected number of arguments left to parse" + ;; esac -require_clean_work_tree "rebase" "Please commit or stash them." +require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")" # Now we are rebasing commits $upstream..$orig_head (or with --root, # everything leading up to $orig_head) on top of $onto @@ -482,10 +498,10 @@ then then # Lazily switch to the target branch if needed... test -z "$switch_to" || git checkout "$switch_to" -- - say "Current branch $branch_name is up to date." + say "$(eval_gettext "Current branch \$branch_name is up to date.")" exit 0 else - say "Current branch $branch_name is up to date, rebase forced." + say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")" fi fi @@ -496,7 +512,7 @@ if test -n "$diffstat" then if test -n "$verbose" then - echo "Changes from $mb to $onto:" + echo "$(eval_gettext "Changes from \$mb to \$onto:")" fi # We want color (if set), but no pager GIT_PAGER='' git diff --stat --summary "$mb" "$onto" @@ -505,7 +521,7 @@ fi test "$type" = interactive && run_specific_rebase # Detach HEAD and reset the tree -say "First, rewinding head to replay your work on top of it..." +say "$(gettext "First, rewinding head to replay your work on top of it...")" git checkout -q "$onto^0" || die "could not detach HEAD" git update-ref ORIG_HEAD $orig_head @@ -513,7 +529,7 @@ git update-ref ORIG_HEAD $orig_head # we just fast-forwarded. if test "$mb" = "$orig_head" then - say "Fast-forwarded $branch_name to $onto_name." + say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")" move_to_original_branch exit 0 fi diff --git a/git-send-email.perl b/git-send-email.perl index 664713709..94c7f76a1 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -56,6 +56,7 @@ git send-email [options] <file | directory | rev-list options > --in-reply-to <str> * Email "In-Reply-To:" --annotate * Review each patch that will be sent in an editor. --compose * Open an editor for introduction. + --compose-encoding <str> * Encoding to assume for introduction. --8bit-encoding <str> * Encoding to assume 8bit mails if undeclared Sending: @@ -198,6 +199,7 @@ my ($identity, $aliasfiletype, @alias_files, $smtp_domain); my ($validate, $confirm); my (@suppress_cc); my ($auto_8bit_encoding); +my ($compose_encoding); my ($debug_net_smtp) = 0; # Net::SMTP, see send_message() @@ -231,6 +233,7 @@ my %config_settings = ( "confirm" => \$confirm, "from" => \$sender, "assume8bitencoding" => \$auto_8bit_encoding, + "composeencoding" => \$compose_encoding, ); my %config_path_settings = ( @@ -315,6 +318,7 @@ my $rc = GetOptions("h" => \$help, "validate!" => \$validate, "format-patch!" => \$format_patch, "8bit-encoding=s" => \$auto_8bit_encoding, + "compose-encoding=s" => \$compose_encoding, "force" => \$force, ); @@ -632,6 +636,9 @@ EOT my $need_8bit_cte = file_has_nonascii($compose_filename); my $in_body = 0; my $summary_empty = 1; + if (!defined $compose_encoding) { + $compose_encoding = "UTF-8"; + } while(<$c>) { next if m/^GIT:/; if ($in_body) { @@ -641,7 +648,7 @@ EOT if ($need_8bit_cte) { print $c2 "MIME-Version: 1.0\n", "Content-Type: text/plain; ", - "charset=UTF-8\n", + "charset=$compose_encoding\n", "Content-Transfer-Encoding: 8bit\n"; } } elsif (/^MIME-Version:/i) { @@ -650,9 +657,7 @@ EOT $initial_subject = $1; my $subject = $initial_subject; $_ = "Subject: " . - ($subject =~ /[^[:ascii:]]/ ? - quote_rfc2047($subject) : - $subject) . + quote_subject($subject, $compose_encoding) . "\n"; } elsif (/^In-Reply-To:\s*(.+)\s*$/i) { $initial_reply_to = $1; @@ -681,6 +686,7 @@ sub ask { my ($prompt, %arg) = @_; my $valid_re = $arg{valid_re}; my $default = $arg{default}; + my $confirm_only = $arg{confirm_only}; my $resp; my $i = 0; return defined $default ? $default : undef @@ -698,6 +704,12 @@ sub ask { if (!defined $valid_re or $resp =~ /$valid_re/) { return $resp; } + if ($confirm_only) { + my $yesno = $term->readline("Are you sure you want to use <$resp> [y/N]? "); + if (defined $yesno && $yesno =~ /y/i) { + return $resp; + } + } } return undef; } @@ -741,17 +753,15 @@ if (!$force) { } } -my $prompting = 0; if (!defined $sender) { $sender = $repoauthor || $repocommitter || ''; - $sender = ask("Who should the emails appear to be from? [$sender] ", - default => $sender); - print "Emails will be sent from: ", $sender, "\n"; - $prompting++; } +my $prompting = 0; if (!@initial_to && !defined $to_cmd) { - my $to = ask("Who should the emails be sent to? "); + my $to = ask("Who should the emails be sent to (if any)? ", + default => "", + valid_re => qr/\@.*\./, confirm_only => 1); push @initial_to, parse_address_line($to) if defined $to; # sanitized/validated later $prompting++; } @@ -771,13 +781,17 @@ sub expand_one_alias { } @initial_to = expand_aliases(@initial_to); -@initial_to = (map { sanitize_address($_) } @initial_to); +@initial_to = validate_address_list(sanitize_address_list(@initial_to)); @initial_cc = expand_aliases(@initial_cc); +@initial_cc = validate_address_list(sanitize_address_list(@initial_cc)); @bcclist = expand_aliases(@bcclist); +@bcclist = validate_address_list(sanitize_address_list(@bcclist)); if ($thread && !defined $initial_reply_to && $prompting) { $initial_reply_to = ask( - "Message-ID to be used as In-Reply-To for the first email? "); + "Message-ID to be used as In-Reply-To for the first email (if any)? ", + default => "", + valid_re => qr/\@.*\./, confirm_only => 1); } if (defined $initial_reply_to) { $initial_reply_to =~ s/^\s*<?//; @@ -814,12 +828,45 @@ sub extract_valid_address { $address =~ s/^\s*<(.*)>\s*$/$1/; if ($have_email_valid) { return scalar Email::Valid->address($address); - } else { - # less robust/correct than the monster regexp in Email::Valid, - # but still does a 99% job, and one less dependency - $address =~ /($local_part_regexp\@$domain_regexp)/; - return $1; } + + # less robust/correct than the monster regexp in Email::Valid, + # but still does a 99% job, and one less dependency + return $1 if $address =~ /($local_part_regexp\@$domain_regexp)/; + return undef; +} + +sub extract_valid_address_or_die { + my $address = shift; + $address = extract_valid_address($address); + die "error: unable to extract a valid address from: $address\n" + if !$address; + return $address; +} + +sub validate_address { + my $address = shift; + while (!extract_valid_address($address)) { + print STDERR "error: unable to extract a valid address from: $address\n"; + $_ = ask("What to do with this address? ([q]uit|[d]rop|[e]dit): ", + valid_re => qr/^(?:quit|q|drop|d|edit|e)/i, + default => 'q'); + if (/^d/i) { + return undef; + } elsif (/^q/i) { + cleanup_compose_files(); + exit(0); + } + $address = ask("Who should the email be sent to (if any)? ", + default => "", + valid_re => qr/\@.*\./, confirm_only => 1); + } + return $address; +} + +sub validate_address_list { + return (grep { defined $_ } + map { validate_address($_) } @_); } # Usually don't need to change anything below here. @@ -888,9 +935,29 @@ sub is_rfc2047_quoted { $s =~ m/^(?:"[[:ascii:]]*"|=\?$token\?$token\?$encoded_text\?=)$/o; } +sub subject_needs_rfc2047_quoting { + my $s = shift; + + return ($s =~ /[^[:ascii:]]/) || ($s =~ /=\?/); +} + +sub quote_subject { + local $subject = shift; + my $encoding = shift || 'UTF-8'; + + if (subject_needs_rfc2047_quoting($subject)) { + return quote_rfc2047($subject, $encoding); + } + return $subject; +} + # use the simplest quoting being able to handle the recipient sub sanitize_address { my ($recipient) = @_; + + # remove garbage after email address + $recipient =~ s/(.*>).*$/$1/; + my ($recipient_name, $recipient_addr) = ($recipient =~ /^(.*?)\s*(<.*)/); if (not $recipient_name) { @@ -918,6 +985,10 @@ sub sanitize_address { } +sub sanitize_address_list { + return (map { sanitize_address($_) } @_); +} + # Returns the local Fully Qualified Domain Name (FQDN) if available. # # Tightly configured MTAa require that a caller sends a real DNS @@ -980,14 +1051,13 @@ sub maildomain { sub send_message { my @recipients = unique_email_list(@to); - @cc = (grep { my $cc = extract_valid_address($_); + @cc = (grep { my $cc = extract_valid_address_or_die($_); not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients } - map { sanitize_address($_) } @cc); my $to = join (",\n\t", @recipients); @recipients = unique_email_list(@recipients,@cc,@bcclist); - @recipients = (map { extract_valid_address($_) } @recipients); + @recipients = (map { extract_valid_address_or_die($_) } @recipients); my $date = format_2822_time($time++); my $gitversion = '@@GIT_VERSION@@'; if ($gitversion =~ m/..GIT_VERSION../) { @@ -1230,7 +1300,7 @@ foreach my $t (@files) { foreach my $addr (parse_address_line($1)) { printf("(mbox) Adding to: %s from line '%s'\n", $addr, $_) unless $quiet; - push @to, sanitize_address($addr); + push @to, $addr; } } elsif (/^Cc:\s+(.*)$/) { @@ -1309,7 +1379,7 @@ foreach my $t (@files) { } if ($broken_encoding{$t} && !is_rfc2047_quoted($subject)) { - $subject = quote_rfc2047($subject, $auto_8bit_encoding); + $subject = quote_subject($subject, $auto_8bit_encoding); } if (defined $author and $author ne $sender) { @@ -1339,6 +1409,9 @@ foreach my $t (@files) { ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1)); $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc); + @to = validate_address_list(sanitize_address_list(@to)); + @cc = validate_address_list(sanitize_address_list(@cc)); + @to = (@initial_to, @to); @cc = (@initial_cc, @cc); @@ -1394,14 +1467,10 @@ sub unique_email_list { my @emails; foreach my $entry (@_) { - if (my $clean = extract_valid_address($entry)) { - $seen{$clean} ||= 0; - next if $seen{$clean}++; - push @emails, $entry; - } else { - print STDERR "W: unable to extract a valid address", - " from: $entry\n"; - } + my $clean = extract_valid_address_or_die($entry); + $seen{$clean} ||= 0; + next if $seen{$clean}++; + push @emails, $entry; } return @emails; } diff --git a/git-sh-setup.sh b/git-sh-setup.sh index ee0e0bc04..795edd285 100644 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -12,8 +12,11 @@ # But we protect ourselves from such a user mistake nevertheless. unset CDPATH -# Similarly for IFS -unset IFS +# Similarly for IFS, but some shells (e.g. FreeBSD 7.2) are buggy and +# do not equate an unset IFS with IFS with the default, so here is +# an explicit SP HT LF. +IFS=' +' git_broken_path_fix () { case ":$PATH:" in @@ -191,28 +194,52 @@ require_clean_work_tree () { fi } +# Generate a sed script to parse identities from a commit. +# +# Reads the commit from stdin, which should be in raw format (e.g., from +# cat-file or "--pretty=raw"). +# +# The first argument specifies the ident line to parse (e.g., "author"), and +# the second specifies the environment variable to put it in (e.g., "AUTHOR" +# for "GIT_AUTHOR_*"). Multiple pairs can be given to parse author and +# committer. +pick_ident_script () { + while test $# -gt 0 + do + lid=$1; shift + uid=$1; shift + printf '%s' " + /^$lid /{ + s/'/'\\\\''/g + h + s/^$lid "'\([^<]*\) <[^>]*> .*$/\1/'" + s/.*/GIT_${uid}_NAME='&'/p + + g + s/^$lid "'[^<]* <\([^>]*\)> .*$/\1/'" + s/.*/GIT_${uid}_EMAIL='&'/p + + g + s/^$lid "'[^<]* <[^>]*> \(.*\)$/@\1/'" + s/.*/GIT_${uid}_DATE='&'/p + } + " + done + echo '/^$/q' +} + +# Create a pick-script as above and feed it to sed. Stdout is suitable for +# feeding to eval. +parse_ident_from_commit () { + LANG=C LC_ALL=C sed -ne "$(pick_ident_script "$@")" +} + +# Parse the author from a commit given as an argument. Stdout is suitable for +# feeding to eval to set the usual GIT_* ident variables. get_author_ident_from_commit () { - pick_author_script=' - /^author /{ - s/'\''/'\''\\'\'\''/g - h - s/^author \([^<]*\) <[^>]*> .*$/\1/ - s/.*/GIT_AUTHOR_NAME='\''&'\''/p - - g - s/^author [^<]* <\([^>]*\)> .*$/\1/ - s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p - - g - s/^author [^<]* <[^>]*> \(.*\)$/@\1/ - s/.*/GIT_AUTHOR_DATE='\''&'\''/p - - q - } - ' encoding=$(git config i18n.commitencoding || echo UTF-8) git show -s --pretty=raw --encoding="$encoding" "$1" -- | - LANG=C LC_ALL=C sed -ne "$pick_author_script" + parse_ident_from_commit author AUTHOR } # Clear repo-local GIT_* environment variables. Useful when switching to diff --git a/git-submodule.sh b/git-submodule.sh index e89b51603..2365149d0 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -5,13 +5,13 @@ # Copyright (c) 2007 Lars Hjemli dashless=$(basename "$0" | sed -e 's/-/ /') -USAGE="[--quiet] add [-b branch] [-f|--force] [--reference <repository>] [--] <repository> [<path>] +USAGE="[--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>] or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...] or: $dashless [--quiet] init [--] [<path>...] or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...] or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...] or: $dashless [--quiet] foreach [--recursive] <command> - or: $dashless [--quiet] sync [--] [<path>...]" + or: $dashless [--quiet] sync [--recursive] [--] [<path>...]" OPTIONS_SPEC= . git-sh-setup . git-sh-i18n @@ -29,8 +29,24 @@ files= nofetch= update= prefix= +custom_name= -# Resolve relative url by appending to parent's url +# The function takes at most 2 arguments. The first argument is the +# URL that navigates to the submodule origin repo. When relative, this URL +# is relative to the superproject origin URL repo. The second up_path +# argument, if specified, is the relative path that navigates +# from the submodule working tree to the superproject working tree. +# +# The output of the function is the origin URL of the submodule. +# +# The output will either be an absolute URL or filesystem path (if the +# superproject origin URL is an absolute URL or filesystem path, +# respectively) or a relative file system path (if the superproject +# origin URL is a relative file system path). +# +# When the output is a relative file system path, the path is either +# relative to the submodule working tree, if up_path is specified, or to +# the superproject working tree otherwise. resolve_relative_url () { remote=$(get_default_remote) @@ -39,6 +55,21 @@ resolve_relative_url () url="$1" remoteurl=${remoteurl%/} sep=/ + up_path="$2" + + case "$remoteurl" in + *:*|/*) + is_relative= + ;; + ./*|../*) + is_relative=t + ;; + *) + is_relative=t + remoteurl="./$remoteurl" + ;; + esac + while test -n "$url" do case "$url" in @@ -53,7 +84,12 @@ resolve_relative_url () sep=: ;; *) - die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")" + if test -z "$is_relative" || test "." = "$remoteurl" + then + die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")" + else + remoteurl=. + fi ;; esac ;; @@ -64,7 +100,8 @@ resolve_relative_url () break;; esac done - echo "$remoteurl$sep${url%/}" + remoteurl="$remoteurl$sep${url%/}" + echo "${is_relative:+${up_path}}${remoteurl#./}" } # @@ -143,8 +180,9 @@ module_name() module_clone() { sm_path=$1 - url=$2 - reference="$3" + name=$2 + url=$3 + reference="$4" quiet= if test -n "$GIT_QUIET" then @@ -153,8 +191,6 @@ module_clone() gitdir= gitdir_base= - name=$(module_name "$sm_path" 2>/dev/null) - test -n "$name" || name="$sm_path" base_name=$(dirname "$name") gitdir=$(git rev-parse --git-dir) @@ -167,8 +203,11 @@ module_clone() rm -f "$gitdir/index" else mkdir -p "$gitdir_base" - git clone $quiet -n ${reference:+"$reference"} \ - --separate-git-dir "$gitdir" "$url" "$sm_path" || + ( + clear_local_git_env + git clone $quiet -n ${reference:+"$reference"} \ + --separate-git-dir "$gitdir" "$url" "$sm_path" + ) || die "$(eval_gettext "Clone of '\$url' into submodule path '\$sm_path' failed")" fi @@ -231,6 +270,10 @@ cmd_add() ;; --reference=*) reference="$1" + ;; + --name) + case "$2" in '') usage ;; esac + custom_name=$2 shift ;; --) @@ -297,6 +340,13 @@ Use -f if you really want to add it." >&2 exit 1 fi + if test -n "$custom_name" + then + sm_name="$custom_name" + else + sm_name="$sm_path" + fi + # perhaps the path exists and is already a git repo, else clone it if test -e "$sm_path" then @@ -308,8 +358,21 @@ Use -f if you really want to add it." >&2 fi else - - module_clone "$sm_path" "$realrepo" "$reference" || exit + if test -d ".git/modules/$sm_name" + then + if test -z "$force" + then + echo >&2 "$(eval_gettext "A git directory for '\$sm_name' is found locally with remote(s):")" + GIT_DIR=".git/modules/$sm_name" GIT_WORK_TREE=. git remote -v | grep '(fetch)' | sed -e s,^," ", -e s,' (fetch)',, >&2 + echo >&2 "$(eval_gettext "If you want to reuse this local git directory instead of cloning again from")" + echo >&2 " $realrepo" + echo >&2 "$(eval_gettext "use the '--force' option. If the local git directory is not the correct repo")" + die "$(eval_gettext "or you are unsure what this means choose another name with the '--name' option.")" + else + echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")" + fi + fi + module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" || exit ( clear_local_git_env cd "$sm_path" && @@ -320,13 +383,13 @@ Use -f if you really want to add it." >&2 esac ) || die "$(eval_gettext "Unable to checkout submodule '\$sm_path'")" fi - git config submodule."$sm_path".url "$realrepo" + git config submodule."$sm_name".url "$realrepo" git add $force "$sm_path" || die "$(eval_gettext "Failed to add submodule '\$sm_path'")" - git config -f .gitmodules submodule."$sm_path".path "$sm_path" && - git config -f .gitmodules submodule."$sm_path".url "$repo" && + git config -f .gitmodules submodule."$sm_name".path "$sm_path" && + git config -f .gitmodules submodule."$sm_name".url "$repo" && git add --force .gitmodules || die "$(eval_gettext "Failed to register submodule '\$sm_path'")" } @@ -555,7 +618,7 @@ Maybe you want to use 'update --init'?")" if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git then - module_clone "$sm_path" "$url" "$reference"|| exit + module_clone "$sm_path" "$name" "$url" "$reference" || exit cloned_modules="$cloned_modules;$name" subsha1= else @@ -737,7 +800,7 @@ cmd_summary() { if [ -n "$files" ] then test -n "$cached" && - die "$(gettext -- "--cached cannot be used with --files")" + die "$(gettext "The --cached option cannot be used with the --files option")" diff_cmd=diff-files head= fi @@ -887,7 +950,6 @@ cmd_summary() { cmd_status() { # parse $args after "submodule ... status". - orig_flags= while test $# -ne 0 do case "$1" in @@ -911,7 +973,6 @@ cmd_status() break ;; esac - orig_flags="$orig_flags $(git rev-parse --sq-quote "$1")" shift done @@ -951,7 +1012,7 @@ cmd_status() prefix="$displaypath/" clear_local_git_env cd "$sm_path" && - eval cmd_status "$orig_args" + eval cmd_status ) || die "$(eval_gettext "Failed to recurse into submodule path '\$sm_path'")" fi @@ -971,6 +1032,10 @@ cmd_sync() GIT_QUIET=1 shift ;; + --recursive) + recursive=1 + shift + ;; --) shift break @@ -994,14 +1059,26 @@ cmd_sync() # Possibly a url relative to parent case "$url" in ./*|../*) - url=$(resolve_relative_url "$url") || exit + # rewrite foo/bar as ../.. to find path from + # submodule work tree to superproject work tree + up_path="$(echo "$sm_path" | sed "s/[^/][^/]*/../g")" && + # guarantee a trailing / + up_path=${up_path%/}/ && + # path from submodule work tree to submodule origin repo + sub_origin_url=$(resolve_relative_url "$url" "$up_path") && + # path from superproject work tree to submodule origin repo + super_config_url=$(resolve_relative_url "$url") || exit + ;; + *) + sub_origin_url="$url" + super_config_url="$url" ;; esac if git config "submodule.$name.url" >/dev/null 2>/dev/null then - say "$(eval_gettext "Synchronizing submodule url for '\$name'")" - git config submodule."$name".url "$url" + say "$(eval_gettext "Synchronizing submodule url for '\$prefix\$sm_path'")" + git config submodule."$name".url "$super_config_url" if test -e "$sm_path"/.git then @@ -1009,7 +1086,13 @@ cmd_sync() clear_local_git_env cd "$sm_path" remote=$(get_default_remote) - git config remote."$remote".url "$url" + git config remote."$remote".url "$sub_origin_url" + + if test -n "$recursive" + then + prefix="$prefix$sm_path/" + eval cmd_sync + fi ) fi fi @@ -1056,7 +1139,15 @@ do done # No command word defaults to "status" -test -n "$command" || command=status +if test -z "$command" +then + if test $# = 0 + then + command=status + else + usage + fi +fi # "-b branch" is accepted only by "add" if test -n "$branch" && test "$command" != add diff --git a/git-svn.perl b/git-svn.perl index 0b074c4c6..bd5266c86 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -10,6 +10,52 @@ use vars qw/ $AUTHOR $VERSION $AUTHOR = 'Eric Wong <normalperson@yhbt.net>'; $VERSION = '@@GIT_VERSION@@'; +use Carp qw/croak/; +use Digest::MD5; +use IO::File qw//; +use File::Basename qw/dirname basename/; +use File::Path qw/mkpath/; +use File::Spec; +use File::Find; +use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/; +use IPC::Open3; +use Memoize; + +use Git::SVN; +use Git::SVN::Editor; +use Git::SVN::Fetcher; +use Git::SVN::Ra; +use Git::SVN::Prompt; +use Git::SVN::Log; +use Git::SVN::Migration; + +use Git::SVN::Utils qw( + fatal + can_compress + canonicalize_path + canonicalize_url + join_paths + add_path_to_url + join_paths +); + +use Git qw( + git_cmd_try + command + command_oneline + command_noisy + command_output_pipe + command_close_pipe + command_bidi_pipe + command_close_bidi_pipe +); + +BEGIN { + Memoize::memoize 'Git::config'; + Memoize::memoize 'Git::config_bool'; +} + + # From which subdir have we been invoked? my $cmd_dir_prefix = eval { command_oneline([qw/rev-parse --show-prefix/], STDERR => 0) @@ -17,10 +63,7 @@ my $cmd_dir_prefix = eval { my $git_dir_user_set = 1 if defined $ENV{GIT_DIR}; $ENV{GIT_DIR} ||= '.git'; -$Git::SVN::default_repo_id = 'svn'; -$Git::SVN::default_ref_id = $ENV{GIT_SVN_ID} || 'git-svn'; $Git::SVN::Ra::_log_window_size = 100; -$Git::SVN::_minimize_url = 'unset'; if (! exists $ENV{SVN_SSH} && exists $ENV{GIT_SSH}) { $ENV{SVN_SSH} = $ENV{GIT_SSH}; @@ -35,8 +78,6 @@ $Git::SVN::Log::TZ = $ENV{TZ}; $ENV{TZ} = 'UTC'; $| = 1; # unbuffer STDOUT -sub fatal (@) { print STDERR "@_\n"; exit 1 } - # All SVN commands do it. Otherwise we may die on SIGPIPE when the remote # repository decides to close the connection which we expect to be kept alive. $SIG{PIPE} = 'IGNORE'; @@ -66,39 +107,6 @@ sub _req_svn { fatal "Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)"; } } -my $can_compress = eval { require Compress::Zlib; 1}; -use Carp qw/croak/; -use Digest::MD5; -use IO::File qw//; -use File::Basename qw/dirname basename/; -use File::Path qw/mkpath/; -use File::Spec; -use File::Find; -use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/; -use IPC::Open3; -use Git; -use Git::SVN::Editor qw//; -use Git::SVN::Fetcher qw//; -use Git::SVN::Ra qw//; -use Git::SVN::Prompt qw//; -use Memoize; # core since 5.8.0, Jul 2002 - -BEGIN { - # import functions from Git into our packages, en masse - no strict 'refs'; - foreach (qw/command command_oneline command_noisy command_output_pipe - command_input_pipe command_close_pipe - command_bidi_pipe command_close_bidi_pipe/) { - for my $package ( qw(Git::SVN::Migration Git::SVN::Log Git::SVN), - __PACKAGE__) { - *{"${package}::$_"} = \&{"Git::$_"}; - } - } - Memoize::memoize 'Git::config'; - Memoize::memoize 'Git::config_bool'; -} - -my ($SVN); $sha1 = qr/[a-f\d]{40}/; $sha1_short = qr/[a-f\d]{4,40}/; @@ -108,8 +116,11 @@ my ($_stdin, $_help, $_edit, $_version, $_fetch_all, $_no_rebase, $_fetch_parent, $_merge, $_strategy, $_preserve_merges, $_dry_run, $_local, $_prefix, $_no_checkout, $_url, $_verbose, - $_git_format, $_commit_url, $_tag, $_merge_info, $_interactive); -$Git::SVN::_follow_parent = 1; + $_commit_url, $_tag, $_merge_info, $_interactive); + +# This is a refactoring artifact so Git::SVN can get at this git-svn switch. +sub opt_prefix { return $_prefix || '' } + $Git::SVN::Fetcher::_placeholder_filename = ".gitignore"; $_q ||= 0; my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username, @@ -269,7 +280,7 @@ my %cmd = ( { 'url' => \$_url, } ], 'blame' => [ \&Git::SVN::Log::cmd_blame, "Show what revision and author last modified each line of a file", - { 'git-format' => \$_git_format } ], + { 'git-format' => \$Git::SVN::Log::_git_format } ], 'reset' => [ \&cmd_reset, "Undo fetches back to the specified SVN revision", { 'revision|r=s' => \$_revision, @@ -367,9 +378,9 @@ Git::SVN::init_vars(); eval { Git::SVN::verify_remotes_sanity(); $cmd{$cmd}->[0]->(@ARGV); + post_fetch_checkout(); }; fatal $@ if $@; -post_fetch_checkout(); exit 0; ####################### primary functions ###################### @@ -775,6 +786,44 @@ sub populate_merge_info { return undef; } +sub dcommit_rebase { + my ($is_last, $current, $fetched_ref, $svn_error) = @_; + my @diff; + + if ($svn_error) { + print STDERR "\nERROR from SVN:\n", + $svn_error->expanded_message, "\n"; + } + unless ($_no_rebase) { + # we always want to rebase against the current HEAD, + # not any head that was passed to us + @diff = command('diff-tree', $current, + $fetched_ref, '--'); + my @finish; + if (@diff) { + @finish = rebase_cmd(); + print STDERR "W: $current and ", $fetched_ref, + " differ, using @finish:\n", + join("\n", @diff), "\n"; + } elsif ($is_last) { + print "No changes between ", $current, " and ", + $fetched_ref, + "\nResetting to the latest ", + $fetched_ref, "\n"; + @finish = qw/reset --mixed/; + } + command_noisy(@finish, $fetched_ref) if @finish; + } + if ($svn_error) { + die "ERROR: Not all changes have been committed into SVN" + .($_no_rebase ? ".\n" : ", however the committed\n" + ."ones (if any) seem to be successfully integrated " + ."into the working tree.\n") + ."Please see the above messages for details.\n"; + } + return @diff; +} + sub cmd_dcommit { my $head = shift; command_noisy(qw/update-index --refresh/); @@ -902,6 +951,7 @@ sub cmd_dcommit { } my $rewritten_parent; + my $current_head = command_oneline(qw/rev-parse HEAD/); Git::SVN::remove_username($expect_url); if (defined($_merge_info)) { $_merge_info =~ tr{ }{\n}; @@ -941,6 +991,14 @@ sub cmd_dcommit { }, mergeinfo => $_merge_info, svn_path => ''); + + my $err_handler = $SVN::Error::handler; + $SVN::Error::handler = sub { + my $err = shift; + dcommit_rebase(1, $current_head, $gs->refname, + $err); + }; + if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) { print "No changes\n$d~1 == $d\n"; } elsif ($parents->{$d} && @{$parents->{$d}}) { @@ -948,31 +1006,19 @@ sub cmd_dcommit { $parents->{$d}; } $_fetch_all ? $gs->fetch_all : $gs->fetch; + $SVN::Error::handler = $err_handler; $last_rev = $cmt_rev; next if $_no_rebase; - # we always want to rebase against the current HEAD, - # not any head that was passed to us - my @diff = command('diff-tree', $d, - $gs->refname, '--'); - my @finish; - if (@diff) { - @finish = rebase_cmd(); - print STDERR "W: $d and ", $gs->refname, - " differ, using @finish:\n", - join("\n", @diff), "\n"; - } else { - print "No changes between current HEAD and ", - $gs->refname, - "\nResetting to the latest ", - $gs->refname, "\n"; - @finish = qw/reset --mixed/; - } - command_noisy(@finish, $gs->refname); + my @diff = dcommit_rebase(@$linear_refs == 0, $d, + $gs->refname, undef); - $rewritten_parent = command_oneline(qw/rev-parse HEAD/); + $rewritten_parent = command_oneline(qw/rev-parse/, + $gs->refname); if (@diff) { + $current_head = command_oneline(qw/rev-parse + HEAD/); @refs = (); my ($url_, $rev_, $uuid_, $gs_) = working_head_info('HEAD', \@refs); @@ -1017,6 +1063,7 @@ sub cmd_dcommit { } $parents = \%p; $linear_refs = \@l; + undef $last_rev; } } } @@ -1193,7 +1240,7 @@ sub cmd_show_ignore { my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); $gs ||= Git::SVN->new; my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum); - $gs->prop_walk($gs->{path}, $r, sub { + $gs->prop_walk($gs->path, $r, sub { my ($gs, $path, $props) = @_; print STDOUT "\n# $path\n"; my $s = $props->{'svn:ignore'} or return; @@ -1209,7 +1256,7 @@ sub cmd_show_externals { my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); $gs ||= Git::SVN->new; my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum); - $gs->prop_walk($gs->{path}, $r, sub { + $gs->prop_walk($gs->path, $r, sub { my ($gs, $path, $props) = @_; print STDOUT "\n# $path\n"; my $s = $props->{'svn:externals'} or return; @@ -1224,7 +1271,7 @@ sub cmd_create_ignore { my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); $gs ||= Git::SVN->new; my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum); - $gs->prop_walk($gs->{path}, $r, sub { + $gs->prop_walk($gs->path, $r, sub { my ($gs, $path, $props) = @_; # $path is of the form /path/to/dir/ $path = '.' . $path; @@ -1254,31 +1301,6 @@ sub cmd_mkdirs { $gs->mkemptydirs($_revision); } -sub canonicalize_path { - my ($path) = @_; - my $dot_slash_added = 0; - if (substr($path, 0, 1) ne "/") { - $path = "./" . $path; - $dot_slash_added = 1; - } - # File::Spec->canonpath doesn't collapse x/../y into y (for a - # good reason), so let's do this manually. - $path =~ s#/+#/#g; - $path =~ s#/\.(?:/|$)#/#g; - $path =~ s#/[^/]+/\.\.##g; - $path =~ s#/$##g; - $path =~ s#^\./## if $dot_slash_added; - $path =~ s#^/##; - $path =~ s#^\.$##; - return $path; -} - -sub canonicalize_url { - my ($url) = @_; - $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e; - return $url; -} - # get_svnprops(PATH) # ------------------ # Helper for cmd_propget and cmd_proplist below. @@ -1292,7 +1314,7 @@ sub get_svnprops { $path = $cmd_dir_prefix . $path; fatal("No such file or directory: $path") unless -e $path; my $is_dir = -d $path ? 1 : 0; - $path = $gs->{path} . '/' . $path; + $path = join_paths($gs->path, $path); # canonicalize the path (otherwise libsvn will abort or fail to # find the file) @@ -1393,8 +1415,8 @@ sub cmd_commit_diff { fatal("Needed URL or usable git-svn --id in ", "the command-line\n", $usage); } - $url = $gs->{url}; - $svn_path = $gs->{path}; + $url = $gs->url; + $svn_path = $gs->path; } unless (defined $_revision) { fatal("-r|--revision is a required argument\n", $usage); @@ -1428,24 +1450,6 @@ sub cmd_commit_diff { } } -sub escape_uri_only { - my ($uri) = @_; - my @tmp; - foreach (split m{/}, $uri) { - s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg; - push @tmp, $_; - } - join('/', @tmp); -} - -sub escape_url { - my ($url) = @_; - if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) { - my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3)); - $url = "$scheme://$domain$uri"; - } - $url; -} sub cmd_info { my $path = canonicalize_path(defined($_[0]) ? $_[0] : "."); @@ -1470,21 +1474,21 @@ sub cmd_info { # canonicalize_path() will return "" to make libsvn 1.5.x happy, $path = "." if $path eq ""; - my $full_url = $url . ($fullpath eq "" ? "" : "/$fullpath"); + my $full_url = canonicalize_url( add_path_to_url( $url, $fullpath ) ); if ($_url) { - print escape_url($full_url), "\n"; + print "$full_url\n"; return; } my $result = "Path: $path\n"; $result .= "Name: " . basename($path) . "\n" if $file_type ne "dir"; - $result .= "URL: " . escape_url($full_url) . "\n"; + $result .= "URL: $full_url\n"; eval { my $repos_root = $gs->repos_root; Git::SVN::remove_username($repos_root); - $result .= "Repository Root: " . escape_url($repos_root) . "\n"; + $result .= "Repository Root: " . canonicalize_url($repos_root) . "\n"; }; if ($@) { $result .= "Repository Root: (offline)\n"; @@ -1578,7 +1582,7 @@ sub cmd_reset { } sub cmd_gc { - if (!$can_compress) { + if (!can_compress()) { warn "Compress::Zlib could not be found; unhandled.log " . "files will not be compressed.\n"; } @@ -1598,8 +1602,8 @@ sub rebase_cmd { sub post_fetch_checkout { return if $_no_checkout; + return if verify_ref('HEAD^0'); my $gs = $Git::SVN::_head or return; - return if verify_ref('refs/heads/master^0'); # look for "trunk" ref if it exists my $remote = Git::SVN::read_all_remotes()->{$gs->{repo_id}}; @@ -1612,9 +1616,8 @@ sub post_fetch_checkout { } } - my $valid_head = verify_ref('HEAD^0'); - command_noisy(qw(update-ref refs/heads/master), $gs->refname); - return if ($valid_head || !verify_ref('HEAD^0')); + command_noisy(qw(update-ref HEAD), $gs->refname); + return unless verify_ref('HEAD^0'); return if $ENV{GIT_DIR} !~ m#^(?:.*/)?\.git$#; my $index = $ENV{GIT_INDEX_FILE} || "$ENV{GIT_DIR}/index"; @@ -1632,7 +1635,9 @@ sub post_fetch_checkout { sub complete_svn_url { my ($url, $path) = @_; - $path =~ s#/+$##; + $path = canonicalize_path($path); + + # If the path is not a URL... if ($path !~ m#^[a-z\+]+://#) { if (!defined $url || $url !~ m#^[a-z\+]+://#) { fatal("E: '$path' is not a complete URL ", @@ -1649,7 +1654,7 @@ sub complete_url_ls_init { print STDERR "W: $switch not specified\n"; return; } - $repo_path =~ s#/+$##; + $repo_path = canonicalize_path($repo_path); if ($repo_path =~ m#^[a-z\+]+://#) { $ra = Git::SVN::Ra->new($repo_path); $repo_path = ''; @@ -1660,18 +1665,18 @@ sub complete_url_ls_init { "and a separate URL is not specified"); } } - my $url = $ra->{url}; + my $url = $ra->url; my $gs = Git::SVN->init($url, undef, undef, undef, 1); my $k = "svn-remote.$gs->{repo_id}.url"; my $orig_url = eval { command_oneline(qw/config --get/, $k) }; - if ($orig_url && ($orig_url ne $gs->{url})) { + if ($orig_url && ($orig_url ne $gs->url)) { die "$k already set: $orig_url\n", - "wanted to set to: $gs->{url}\n"; + "wanted to set to: $gs->url\n"; } - command_oneline('config', $k, $gs->{url}) unless $orig_url; - my $remote_path = "$gs->{path}/$repo_path"; + command_oneline('config', $k, $gs->url) unless $orig_url; + + my $remote_path = join_paths( $gs->path, $repo_path ); $remote_path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg; - $remote_path =~ s#/+#/#g; $remote_path =~ s#^/##g; $remote_path .= "/*" if $remote_path !~ /\*/; my ($n) = ($switch =~ /^--(\w+)/); @@ -2014,13 +2019,13 @@ sub md5sum { } elsif (!$ref) { $md5->add($arg) or croak $!; } else { - ::fatal "Can't provide MD5 hash for unknown ref type: '", $ref, "'"; + fatal "Can't provide MD5 hash for unknown ref type: '", $ref, "'"; } return $md5->hexdigest(); } sub gc_directory { - if ($can_compress && -f $_ && basename($_) eq "unhandled.log") { + if (can_compress() && -f $_ && basename($_) eq "unhandled.log") { my $out_filename = $_ . ".gz"; open my $in_fh, "<", $_ or die "Unable to open $_: $!\n"; binmode $in_fh; @@ -2038,3035 +2043,6 @@ sub gc_directory { } } -package Git::SVN; -use strict; -use warnings; -use Fcntl qw/:DEFAULT :seek/; -use constant rev_map_fmt => 'NH40'; -use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent - $_repack $_repack_flags $_use_svm_props $_head - $_use_svnsync_props $no_reuse_existing $_minimize_url - $_use_log_author $_add_author_from $_localtime/; -use Carp qw/croak/; -use File::Path qw/mkpath/; -use File::Copy qw/copy/; -use IPC::Open3; -use Time::Local; -use Memoize; # core since 5.8.0, Jul 2002 -use Memoize::Storable; -use POSIX qw(:signal_h); -my $can_use_yaml; -BEGIN { - $can_use_yaml = eval { require Git::SVN::Memoize::YAML; 1}; -} - -my ($_gc_nr, $_gc_period); - -# properties that we do not log: -my %SKIP_PROP; -BEGIN { - %SKIP_PROP = map { $_ => 1 } qw/svn:wc:ra_dav:version-url - svn:special svn:executable - svn:entry:committed-rev - svn:entry:last-author - svn:entry:uuid - svn:entry:committed-date/; - - # some options are read globally, but can be overridden locally - # per [svn-remote "..."] section. Command-line options will *NOT* - # override options set in an [svn-remote "..."] section - no strict 'refs'; - for my $option (qw/follow_parent no_metadata use_svm_props - use_svnsync_props/) { - my $key = $option; - $key =~ tr/_//d; - my $prop = "-$option"; - *$option = sub { - my ($self) = @_; - return $self->{$prop} if exists $self->{$prop}; - my $k = "svn-remote.$self->{repo_id}.$key"; - eval { command_oneline(qw/config --get/, $k) }; - if ($@) { - $self->{$prop} = ${"Git::SVN::_$option"}; - } else { - my $v = command_oneline(qw/config --bool/,$k); - $self->{$prop} = $v eq 'false' ? 0 : 1; - } - return $self->{$prop}; - } - } -} - - -my (%LOCKFILES, %INDEX_FILES); -END { - unlink keys %LOCKFILES if %LOCKFILES; - unlink keys %INDEX_FILES if %INDEX_FILES; -} - -sub resolve_local_globs { - my ($url, $fetch, $glob_spec) = @_; - return unless defined $glob_spec; - my $ref = $glob_spec->{ref}; - my $path = $glob_spec->{path}; - foreach (command(qw#for-each-ref --format=%(refname) refs/#)) { - next unless m#^$ref->{regex}$#; - my $p = $1; - my $pathname = desanitize_refname($path->full_path($p)); - my $refname = desanitize_refname($ref->full_path($p)); - if (my $existing = $fetch->{$pathname}) { - if ($existing ne $refname) { - die "Refspec conflict:\n", - "existing: $existing\n", - " globbed: $refname\n"; - } - my $u = (::cmt_metadata("$refname"))[0]; - $u =~ s!^\Q$url\E(/|$)!! or die - "$refname: '$url' not found in '$u'\n"; - if ($pathname ne $u) { - warn "W: Refspec glob conflict ", - "(ref: $refname):\n", - "expected path: $pathname\n", - " real path: $u\n", - "Continuing ahead with $u\n"; - next; - } - } else { - $fetch->{$pathname} = $refname; - } - } -} - -sub parse_revision_argument { - my ($base, $head) = @_; - if (!defined $::_revision || $::_revision eq 'BASE:HEAD') { - return ($base, $head); - } - return ($1, $2) if ($::_revision =~ /^(\d+):(\d+)$/); - return ($::_revision, $::_revision) if ($::_revision =~ /^\d+$/); - return ($head, $head) if ($::_revision eq 'HEAD'); - return ($base, $1) if ($::_revision =~ /^BASE:(\d+)$/); - return ($1, $head) if ($::_revision =~ /^(\d+):HEAD$/); - die "revision argument: $::_revision not understood by git-svn\n"; -} - -sub fetch_all { - my ($repo_id, $remotes) = @_; - if (ref $repo_id) { - my $gs = $repo_id; - $repo_id = undef; - $repo_id = $gs->{repo_id}; - } - $remotes ||= read_all_remotes(); - my $remote = $remotes->{$repo_id} or - die "[svn-remote \"$repo_id\"] unknown\n"; - my $fetch = $remote->{fetch}; - my $url = $remote->{url} or die "svn-remote.$repo_id.url not defined\n"; - my (@gs, @globs); - my $ra = Git::SVN::Ra->new($url); - my $uuid = $ra->get_uuid; - my $head = $ra->get_latest_revnum; - - # ignore errors, $head revision may not even exist anymore - eval { $ra->get_log("", $head, 0, 1, 0, 1, sub { $head = $_[1] }) }; - warn "W: $@\n" if $@; - - my $base = defined $fetch ? $head : 0; - - # read the max revs for wildcard expansion (branches/*, tags/*) - foreach my $t (qw/branches tags/) { - defined $remote->{$t} or next; - push @globs, @{$remote->{$t}}; - - my $max_rev = eval { tmp_config(qw/--int --get/, - "svn-remote.$repo_id.${t}-maxRev") }; - if (defined $max_rev && ($max_rev < $base)) { - $base = $max_rev; - } elsif (!defined $max_rev) { - $base = 0; - } - } - - if ($fetch) { - foreach my $p (sort keys %$fetch) { - my $gs = Git::SVN->new($fetch->{$p}, $repo_id, $p); - my $lr = $gs->rev_map_max; - if (defined $lr) { - $base = $lr if ($lr < $base); - } - push @gs, $gs; - } - } - - ($base, $head) = parse_revision_argument($base, $head); - $ra->gs_fetch_loop_common($base, $head, \@gs, \@globs); -} - -sub read_all_remotes { - my $r = {}; - my $use_svm_props = eval { command_oneline(qw/config --bool - svn.useSvmProps/) }; - $use_svm_props = $use_svm_props eq 'true' if $use_svm_props; - my $svn_refspec = qr{\s*(.*?)\s*:\s*(.+?)\s*}; - foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) { - if (m!^(.+)\.fetch=$svn_refspec$!) { - my ($remote, $local_ref, $remote_ref) = ($1, $2, $3); - die("svn-remote.$remote: remote ref '$remote_ref' " - . "must start with 'refs/'\n") - unless $remote_ref =~ m{^refs/}; - $local_ref = uri_decode($local_ref); - $r->{$remote}->{fetch}->{$local_ref} = $remote_ref; - $r->{$remote}->{svm} = {} if $use_svm_props; - } elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) { - $r->{$1}->{svm} = {}; - } elsif (m!^(.+)\.url=\s*(.*)\s*$!) { - $r->{$1}->{url} = $2; - } elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) { - $r->{$1}->{pushurl} = $2; - } elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) { - $r->{$1}->{ignore_refs_regex} = $2; - } elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) { - my ($remote, $t, $local_ref, $remote_ref) = - ($1, $2, $3, $4); - die("svn-remote.$remote: remote ref '$remote_ref' ($t) " - . "must start with 'refs/'\n") - unless $remote_ref =~ m{^refs/}; - $local_ref = uri_decode($local_ref); - my $rs = { - t => $t, - remote => $remote, - path => Git::SVN::GlobSpec->new($local_ref, 1), - ref => Git::SVN::GlobSpec->new($remote_ref, 0) }; - if (length($rs->{ref}->{right}) != 0) { - die "The '*' glob character must be the last ", - "character of '$remote_ref'\n"; - } - push @{ $r->{$remote}->{$t} }, $rs; - } - } - - map { - if (defined $r->{$_}->{svm}) { - my $svm; - eval { - my $section = "svn-remote.$_"; - $svm = { - source => tmp_config('--get', - "$section.svm-source"), - replace => tmp_config('--get', - "$section.svm-replace"), - } - }; - $r->{$_}->{svm} = $svm; - } - } keys %$r; - - foreach my $remote (keys %$r) { - foreach ( grep { defined $_ } - map { $r->{$remote}->{$_} } qw(branches tags) ) { - foreach my $rs ( @$_ ) { - $rs->{ignore_refs_regex} = - $r->{$remote}->{ignore_refs_regex}; - } - } - } - - $r; -} - -sub init_vars { - $_gc_nr = $_gc_period = 1000; - if (defined $_repack || defined $_repack_flags) { - warn "Repack options are obsolete; they have no effect.\n"; - } -} - -sub verify_remotes_sanity { - return unless -d $ENV{GIT_DIR}; - my %seen; - foreach (command(qw/config -l/)) { - if (m!^svn-remote\.(?:.+)\.fetch=.*:refs/remotes/(\S+)\s*$!) { - if ($seen{$1}) { - die "Remote ref refs/remote/$1 is tracked by", - "\n \"$_\"\nand\n \"$seen{$1}\"\n", - "Please resolve this ambiguity in ", - "your git configuration file before ", - "continuing\n"; - } - $seen{$1} = $_; - } - } -} - -sub find_existing_remote { - my ($url, $remotes) = @_; - return undef if $no_reuse_existing; - my $existing; - foreach my $repo_id (keys %$remotes) { - my $u = $remotes->{$repo_id}->{url} or next; - next if $u ne $url; - $existing = $repo_id; - last; - } - $existing; -} - -sub init_remote_config { - my ($self, $url, $no_write) = @_; - $url =~ s!/+$!!; # strip trailing slash - my $r = read_all_remotes(); - my $existing = find_existing_remote($url, $r); - if ($existing) { - unless ($no_write) { - print STDERR "Using existing ", - "[svn-remote \"$existing\"]\n"; - } - $self->{repo_id} = $existing; - } elsif ($_minimize_url) { - my $min_url = Git::SVN::Ra->new($url)->minimize_url; - $existing = find_existing_remote($min_url, $r); - if ($existing) { - unless ($no_write) { - print STDERR "Using existing ", - "[svn-remote \"$existing\"]\n"; - } - $self->{repo_id} = $existing; - } - if ($min_url ne $url) { - unless ($no_write) { - print STDERR "Using higher level of URL: ", - "$url => $min_url\n"; - } - my $old_path = $self->{path}; - $self->{path} = $url; - $self->{path} =~ s!^\Q$min_url\E(/|$)!!; - if (length $old_path) { - $self->{path} .= "/$old_path"; - } - $url = $min_url; - } - } - my $orig_url; - if (!$existing) { - # verify that we aren't overwriting anything: - $orig_url = eval { - command_oneline('config', '--get', - "svn-remote.$self->{repo_id}.url") - }; - if ($orig_url && ($orig_url ne $url)) { - die "svn-remote.$self->{repo_id}.url already set: ", - "$orig_url\nwanted to set to: $url\n"; - } - } - my ($xrepo_id, $xpath) = find_ref($self->refname); - if (!$no_write && defined $xpath) { - die "svn-remote.$xrepo_id.fetch already set to track ", - "$xpath:", $self->refname, "\n"; - } - unless ($no_write) { - command_noisy('config', - "svn-remote.$self->{repo_id}.url", $url); - $self->{path} =~ s{^/}{}; - $self->{path} =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg; - command_noisy('config', '--add', - "svn-remote.$self->{repo_id}.fetch", - "$self->{path}:".$self->refname); - } - $self->{url} = $url; -} - -sub find_by_url { # repos_root and, path are optional - my ($class, $full_url, $repos_root, $path) = @_; - - return undef unless defined $full_url; - remove_username($full_url); - remove_username($repos_root) if defined $repos_root; - my $remotes = read_all_remotes(); - if (defined $full_url && defined $repos_root && !defined $path) { - $path = $full_url; - $path =~ s#^\Q$repos_root\E(?:/|$)##; - } - foreach my $repo_id (keys %$remotes) { - my $u = $remotes->{$repo_id}->{url} or next; - remove_username($u); - next if defined $repos_root && $repos_root ne $u; - - my $fetch = $remotes->{$repo_id}->{fetch} || {}; - foreach my $t (qw/branches tags/) { - foreach my $globspec (@{$remotes->{$repo_id}->{$t}}) { - resolve_local_globs($u, $fetch, $globspec); - } - } - my $p = $path; - my $rwr = rewrite_root({repo_id => $repo_id}); - my $svm = $remotes->{$repo_id}->{svm} - if defined $remotes->{$repo_id}->{svm}; - unless (defined $p) { - $p = $full_url; - my $z = $u; - my $prefix = ''; - if ($rwr) { - $z = $rwr; - remove_username($z); - } elsif (defined $svm) { - $z = $svm->{source}; - $prefix = $svm->{replace}; - $prefix =~ s#^\Q$u\E(?:/|$)##; - $prefix =~ s#/$##; - } - $p =~ s#^\Q$z\E(?:/|$)#$prefix# or next; - } - foreach my $f (keys %$fetch) { - next if $f ne $p; - return Git::SVN->new($fetch->{$f}, $repo_id, $f); - } - } - undef; -} - -sub init { - my ($class, $url, $path, $repo_id, $ref_id, $no_write) = @_; - my $self = _new($class, $repo_id, $ref_id, $path); - if (defined $url) { - $self->init_remote_config($url, $no_write); - } - $self; -} - -sub find_ref { - my ($ref_id) = @_; - foreach (command(qw/config -l/)) { - next unless m!^svn-remote\.(.+)\.fetch= - \s*(.*?)\s*:\s*(.+?)\s*$!x; - my ($repo_id, $path, $ref) = ($1, $2, $3); - if ($ref eq $ref_id) { - $path = '' if ($path =~ m#^\./?#); - return ($repo_id, $path); - } - } - (undef, undef, undef); -} - -sub new { - my ($class, $ref_id, $repo_id, $path) = @_; - if (defined $ref_id && !defined $repo_id && !defined $path) { - ($repo_id, $path) = find_ref($ref_id); - if (!defined $repo_id) { - die "Could not find a \"svn-remote.*.fetch\" key ", - "in the repository configuration matching: ", - "$ref_id\n"; - } - } - my $self = _new($class, $repo_id, $ref_id, $path); - if (!defined $self->{path} || !length $self->{path}) { - my $fetch = command_oneline('config', '--get', - "svn-remote.$repo_id.fetch", - ":$ref_id\$") or - die "Failed to read \"svn-remote.$repo_id.fetch\" ", - "\":$ref_id\$\" in config\n"; - ($self->{path}, undef) = split(/\s*:\s*/, $fetch); - } - $self->{path} =~ s{/+}{/}g; - $self->{path} =~ s{\A/}{}; - $self->{path} =~ s{/\z}{}; - $self->{url} = command_oneline('config', '--get', - "svn-remote.$repo_id.url") or - die "Failed to read \"svn-remote.$repo_id.url\" in config\n"; - $self->{pushurl} = eval { command_oneline('config', '--get', - "svn-remote.$repo_id.pushurl") }; - $self->rebuild; - $self; -} - -sub refname { - my ($refname) = $_[0]->{ref_id} ; - - # It cannot end with a slash /, we'll throw up on this because - # SVN can't have directories with a slash in their name, either: - if ($refname =~ m{/$}) { - die "ref: '$refname' ends with a trailing slash, this is ", - "not permitted by git nor Subversion\n"; - } - - # It cannot have ASCII control character space, tilde ~, caret ^, - # colon :, question-mark ?, asterisk *, space, or open bracket [ - # anywhere. - # - # Additionally, % must be escaped because it is used for escaping - # and we want our escaped refname to be reversible - $refname =~ s{([ \%~\^:\?\*\[\t])}{uc sprintf('%%%02x',ord($1))}eg; - - # no slash-separated component can begin with a dot . - # /.* becomes /%2E* - $refname =~ s{/\.}{/%2E}g; - - # It cannot have two consecutive dots .. anywhere - # .. becomes %2E%2E - $refname =~ s{\.\.}{%2E%2E}g; - - # trailing dots and .lock are not allowed - # .$ becomes %2E and .lock becomes %2Elock - $refname =~ s{\.(?=$|lock$)}{%2E}; - - # the sequence @{ is used to access the reflog - # @{ becomes %40{ - $refname =~ s{\@\{}{%40\{}g; - - return $refname; -} - -sub desanitize_refname { - my ($refname) = @_; - $refname =~ s{%(?:([0-9A-F]{2}))}{chr hex($1)}eg; - return $refname; -} - -sub svm_uuid { - my ($self) = @_; - return $self->{svm}->{uuid} if $self->svm; - $self->ra; - unless ($self->{svm}) { - die "SVM UUID not cached, and reading remotely failed\n"; - } - $self->{svm}->{uuid}; -} - -sub svm { - my ($self) = @_; - return $self->{svm} if $self->{svm}; - my $svm; - # see if we have it in our config, first: - eval { - my $section = "svn-remote.$self->{repo_id}"; - $svm = { - source => tmp_config('--get', "$section.svm-source"), - uuid => tmp_config('--get', "$section.svm-uuid"), - replace => tmp_config('--get', "$section.svm-replace"), - } - }; - if ($svm && $svm->{source} && $svm->{uuid} && $svm->{replace}) { - $self->{svm} = $svm; - } - $self->{svm}; -} - -sub _set_svm_vars { - my ($self, $ra) = @_; - return $ra if $self->svm; - - my @err = ( "useSvmProps set, but failed to read SVM properties\n", - "(svm:source, svm:uuid) ", - "from the following URLs:\n" ); - sub read_svm_props { - my ($self, $ra, $path, $r) = @_; - my $props = ($ra->get_dir($path, $r))[2]; - my $src = $props->{'svm:source'}; - my $uuid = $props->{'svm:uuid'}; - return undef if (!$src || !$uuid); - - chomp($src, $uuid); - - $uuid =~ m{^[0-9a-f\-]{30,}$}i - or die "doesn't look right - svm:uuid is '$uuid'\n"; - - # the '!' is used to mark the repos_root!/relative/path - $src =~ s{/?!/?}{/}; - $src =~ s{/+$}{}; # no trailing slashes please - # username is of no interest - $src =~ s{(^[a-z\+]*://)[^/@]*@}{$1}; - - my $replace = $ra->{url}; - $replace .= "/$path" if length $path; - - my $section = "svn-remote.$self->{repo_id}"; - tmp_config("$section.svm-source", $src); - tmp_config("$section.svm-replace", $replace); - tmp_config("$section.svm-uuid", $uuid); - $self->{svm} = { - source => $src, - uuid => $uuid, - replace => $replace - }; - } - - my $r = $ra->get_latest_revnum; - my $path = $self->{path}; - my %tried; - while (length $path) { - unless ($tried{"$self->{url}/$path"}) { - return $ra if $self->read_svm_props($ra, $path, $r); - $tried{"$self->{url}/$path"} = 1; - } - $path =~ s#/?[^/]+$##; - } - die "Path: '$path' should be ''\n" if $path ne ''; - return $ra if $self->read_svm_props($ra, $path, $r); - $tried{"$self->{url}/$path"} = 1; - - if ($ra->{repos_root} eq $self->{url}) { - die @err, (map { " $_\n" } keys %tried), "\n"; - } - - # nope, make sure we're connected to the repository root: - my $ok; - my @tried_b; - $path = $ra->{svn_path}; - $ra = Git::SVN::Ra->new($ra->{repos_root}); - while (length $path) { - unless ($tried{"$ra->{url}/$path"}) { - $ok = $self->read_svm_props($ra, $path, $r); - last if $ok; - $tried{"$ra->{url}/$path"} = 1; - } - $path =~ s#/?[^/]+$##; - } - die "Path: '$path' should be ''\n" if $path ne ''; - $ok ||= $self->read_svm_props($ra, $path, $r); - $tried{"$ra->{url}/$path"} = 1; - if (!$ok) { - die @err, (map { " $_\n" } keys %tried), "\n"; - } - Git::SVN::Ra->new($self->{url}); -} - -sub svnsync { - my ($self) = @_; - return $self->{svnsync} if $self->{svnsync}; - - if ($self->no_metadata) { - die "Can't have both 'noMetadata' and ", - "'useSvnsyncProps' options set!\n"; - } - if ($self->rewrite_root) { - die "Can't have both 'useSvnsyncProps' and 'rewriteRoot' ", - "options set!\n"; - } - if ($self->rewrite_uuid) { - die "Can't have both 'useSvnsyncProps' and 'rewriteUUID' ", - "options set!\n"; - } - - my $svnsync; - # see if we have it in our config, first: - eval { - my $section = "svn-remote.$self->{repo_id}"; - - my $url = tmp_config('--get', "$section.svnsync-url"); - ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or - die "doesn't look right - svn:sync-from-url is '$url'\n"; - - my $uuid = tmp_config('--get', "$section.svnsync-uuid"); - ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or - die "doesn't look right - svn:sync-from-uuid is '$uuid'\n"; - - $svnsync = { url => $url, uuid => $uuid } - }; - if ($svnsync && $svnsync->{url} && $svnsync->{uuid}) { - return $self->{svnsync} = $svnsync; - } - - my $err = "useSvnsyncProps set, but failed to read " . - "svnsync property: svn:sync-from-"; - my $rp = $self->ra->rev_proplist(0); - - my $url = $rp->{'svn:sync-from-url'} or die $err . "url\n"; - ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or - die "doesn't look right - svn:sync-from-url is '$url'\n"; - - my $uuid = $rp->{'svn:sync-from-uuid'} or die $err . "uuid\n"; - ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or - die "doesn't look right - svn:sync-from-uuid is '$uuid'\n"; - - my $section = "svn-remote.$self->{repo_id}"; - tmp_config('--add', "$section.svnsync-uuid", $uuid); - tmp_config('--add', "$section.svnsync-url", $url); - return $self->{svnsync} = { url => $url, uuid => $uuid }; -} - -# this allows us to memoize our SVN::Ra UUID locally and avoid a -# remote lookup (useful for 'git svn log'). -sub ra_uuid { - my ($self) = @_; - unless ($self->{ra_uuid}) { - my $key = "svn-remote.$self->{repo_id}.uuid"; - my $uuid = eval { tmp_config('--get', $key) }; - if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) { - $self->{ra_uuid} = $uuid; - } else { - die "ra_uuid called without URL\n" unless $self->{url}; - $self->{ra_uuid} = $self->ra->get_uuid; - tmp_config('--add', $key, $self->{ra_uuid}); - } - } - $self->{ra_uuid}; -} - -sub _set_repos_root { - my ($self, $repos_root) = @_; - my $k = "svn-remote.$self->{repo_id}.reposRoot"; - $repos_root ||= $self->ra->{repos_root}; - tmp_config($k, $repos_root); - $repos_root; -} - -sub repos_root { - my ($self) = @_; - my $k = "svn-remote.$self->{repo_id}.reposRoot"; - eval { tmp_config('--get', $k) } || $self->_set_repos_root; -} - -sub ra { - my ($self) = shift; - my $ra = Git::SVN::Ra->new($self->{url}); - $self->_set_repos_root($ra->{repos_root}); - if ($self->use_svm_props && !$self->{svm}) { - if ($self->no_metadata) { - die "Can't have both 'noMetadata' and ", - "'useSvmProps' options set!\n"; - } elsif ($self->use_svnsync_props) { - die "Can't have both 'useSvnsyncProps' and ", - "'useSvmProps' options set!\n"; - } - $ra = $self->_set_svm_vars($ra); - $self->{-want_revprops} = 1; - } - $ra; -} - -# prop_walk(PATH, REV, SUB) -# ------------------------- -# Recursively traverse PATH at revision REV and invoke SUB for each -# directory that contains a SVN property. SUB will be invoked as -# follows: &SUB(gs, path, props); where `gs' is this instance of -# Git::SVN, `path' the path to the directory where the properties -# `props' were found. The `path' will be relative to point of checkout, -# that is, if url://repo/trunk is the current Git branch, and that -# directory contains a sub-directory `d', SUB will be invoked with `/d/' -# as `path' (note the trailing `/'). -sub prop_walk { - my ($self, $path, $rev, $sub) = @_; - - $path =~ s#^/##; - my ($dirent, undef, $props) = $self->ra->get_dir($path, $rev); - $path =~ s#^/*#/#g; - my $p = $path; - # Strip the irrelevant part of the path. - $p =~ s#^/+\Q$self->{path}\E(/|$)#/#; - # Ensure the path is terminated by a `/'. - $p =~ s#/*$#/#; - - # The properties contain all the internal SVN stuff nobody - # (usually) cares about. - my $interesting_props = 0; - foreach (keys %{$props}) { - # If it doesn't start with `svn:', it must be a - # user-defined property. - ++$interesting_props and next if $_ !~ /^svn:/; - # FIXME: Fragile, if SVN adds new public properties, - # this needs to be updated. - ++$interesting_props if /^svn:(?:ignore|keywords|executable - |eol-style|mime-type - |externals|needs-lock)$/x; - } - &$sub($self, $p, $props) if $interesting_props; - - foreach (sort keys %$dirent) { - next if $dirent->{$_}->{kind} != $SVN::Node::dir; - $self->prop_walk($self->{path} . $p . $_, $rev, $sub); - } -} - -sub last_rev { ($_[0]->last_rev_commit)[0] } -sub last_commit { ($_[0]->last_rev_commit)[1] } - -# returns the newest SVN revision number and newest commit SHA1 -sub last_rev_commit { - my ($self) = @_; - if (defined $self->{last_rev} && defined $self->{last_commit}) { - return ($self->{last_rev}, $self->{last_commit}); - } - my $c = ::verify_ref($self->refname.'^0'); - if ($c && !$self->use_svm_props && !$self->no_metadata) { - my $rev = (::cmt_metadata($c))[1]; - if (defined $rev) { - ($self->{last_rev}, $self->{last_commit}) = ($rev, $c); - return ($rev, $c); - } - } - my $map_path = $self->map_path; - unless (-e $map_path) { - ($self->{last_rev}, $self->{last_commit}) = (undef, undef); - return (undef, undef); - } - my ($rev, $commit) = $self->rev_map_max(1); - ($self->{last_rev}, $self->{last_commit}) = ($rev, $commit); - return ($rev, $commit); -} - -sub get_fetch_range { - my ($self, $min, $max) = @_; - $max ||= $self->ra->get_latest_revnum; - $min ||= $self->rev_map_max; - (++$min, $max); -} - -sub tmp_config { - my (@args) = @_; - my $old_def_config = "$ENV{GIT_DIR}/svn/config"; - my $config = "$ENV{GIT_DIR}/svn/.metadata"; - if (! -f $config && -f $old_def_config) { - rename $old_def_config, $config or - die "Failed rename $old_def_config => $config: $!\n"; - } - my $old_config = $ENV{GIT_CONFIG}; - $ENV{GIT_CONFIG} = $config; - $@ = undef; - my @ret = eval { - unless (-f $config) { - mkfile($config); - open my $fh, '>', $config or - die "Can't open $config: $!\n"; - print $fh "; This file is used internally by ", - "git-svn\n" or die - "Couldn't write to $config: $!\n"; - print $fh "; You should not have to edit it\n" or - die "Couldn't write to $config: $!\n"; - close $fh or die "Couldn't close $config: $!\n"; - } - command('config', @args); - }; - my $err = $@; - if (defined $old_config) { - $ENV{GIT_CONFIG} = $old_config; - } else { - delete $ENV{GIT_CONFIG}; - } - die $err if $err; - wantarray ? @ret : $ret[0]; -} - -sub tmp_index_do { - my ($self, $sub) = @_; - my $old_index = $ENV{GIT_INDEX_FILE}; - $ENV{GIT_INDEX_FILE} = $self->{index}; - $@ = undef; - my @ret = eval { - my ($dir, $base) = ($self->{index} =~ m#^(.*?)/?([^/]+)$#); - mkpath([$dir]) unless -d $dir; - &$sub; - }; - my $err = $@; - if (defined $old_index) { - $ENV{GIT_INDEX_FILE} = $old_index; - } else { - delete $ENV{GIT_INDEX_FILE}; - } - die $err if $err; - wantarray ? @ret : $ret[0]; -} - -sub assert_index_clean { - my ($self, $treeish) = @_; - - $self->tmp_index_do(sub { - command_noisy('read-tree', $treeish) unless -e $self->{index}; - my $x = command_oneline('write-tree'); - my ($y) = (command(qw/cat-file commit/, $treeish) =~ - /^tree ($::sha1)/mo); - return if $y eq $x; - - warn "Index mismatch: $y != $x\nrereading $treeish\n"; - unlink $self->{index} or die "unlink $self->{index}: $!\n"; - command_noisy('read-tree', $treeish); - $x = command_oneline('write-tree'); - if ($y ne $x) { - ::fatal "trees ($treeish) $y != $x\n", - "Something is seriously wrong..."; - } - }); -} - -sub get_commit_parents { - my ($self, $log_entry) = @_; - my (%seen, @ret, @tmp); - # legacy support for 'set-tree'; this is only used by set_tree_cb: - if (my $ip = $self->{inject_parents}) { - if (my $commit = delete $ip->{$log_entry->{revision}}) { - push @tmp, $commit; - } - } - if (my $cur = ::verify_ref($self->refname.'^0')) { - push @tmp, $cur; - } - if (my $ipd = $self->{inject_parents_dcommit}) { - if (my $commit = delete $ipd->{$log_entry->{revision}}) { - push @tmp, @$commit; - } - } - push @tmp, $_ foreach (@{$log_entry->{parents}}, @tmp); - while (my $p = shift @tmp) { - next if $seen{$p}; - $seen{$p} = 1; - push @ret, $p; - } - @ret; -} - -sub rewrite_root { - my ($self) = @_; - return $self->{-rewrite_root} if exists $self->{-rewrite_root}; - my $k = "svn-remote.$self->{repo_id}.rewriteRoot"; - my $rwr = eval { command_oneline(qw/config --get/, $k) }; - if ($rwr) { - $rwr =~ s#/+$##; - if ($rwr !~ m#^[a-z\+]+://#) { - die "$rwr is not a valid URL (key: $k)\n"; - } - } - $self->{-rewrite_root} = $rwr; -} - -sub rewrite_uuid { - my ($self) = @_; - return $self->{-rewrite_uuid} if exists $self->{-rewrite_uuid}; - my $k = "svn-remote.$self->{repo_id}.rewriteUUID"; - my $rwid = eval { command_oneline(qw/config --get/, $k) }; - if ($rwid) { - $rwid =~ s#/+$##; - if ($rwid !~ m#^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$#) { - die "$rwid is not a valid UUID (key: $k)\n"; - } - } - $self->{-rewrite_uuid} = $rwid; -} - -sub metadata_url { - my ($self) = @_; - ($self->rewrite_root || $self->{url}) . - (length $self->{path} ? '/' . $self->{path} : ''); -} - -sub full_url { - my ($self) = @_; - $self->{url} . (length $self->{path} ? '/' . $self->{path} : ''); -} - -sub full_pushurl { - my ($self) = @_; - if ($self->{pushurl}) { - return $self->{pushurl} . (length $self->{path} ? '/' . - $self->{path} : ''); - } else { - return $self->full_url; - } -} - -sub set_commit_header_env { - my ($log_entry) = @_; - my %env; - foreach my $ned (qw/NAME EMAIL DATE/) { - foreach my $ac (qw/AUTHOR COMMITTER/) { - $env{"GIT_${ac}_${ned}"} = $ENV{"GIT_${ac}_${ned}"}; - } - } - - $ENV{GIT_AUTHOR_NAME} = $log_entry->{name}; - $ENV{GIT_AUTHOR_EMAIL} = $log_entry->{email}; - $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_entry->{date}; - - $ENV{GIT_COMMITTER_NAME} = (defined $log_entry->{commit_name}) - ? $log_entry->{commit_name} - : $log_entry->{name}; - $ENV{GIT_COMMITTER_EMAIL} = (defined $log_entry->{commit_email}) - ? $log_entry->{commit_email} - : $log_entry->{email}; - \%env; -} - -sub restore_commit_header_env { - my ($env) = @_; - foreach my $ned (qw/NAME EMAIL DATE/) { - foreach my $ac (qw/AUTHOR COMMITTER/) { - my $k = "GIT_${ac}_${ned}"; - if (defined $env->{$k}) { - $ENV{$k} = $env->{$k}; - } else { - delete $ENV{$k}; - } - } - } -} - -sub gc { - command_noisy('gc', '--auto'); -}; - -sub do_git_commit { - my ($self, $log_entry) = @_; - my $lr = $self->last_rev; - if (defined $lr && $lr >= $log_entry->{revision}) { - die "Last fetched revision of ", $self->refname, - " was r$lr, but we are about to fetch: ", - "r$log_entry->{revision}!\n"; - } - if (my $c = $self->rev_map_get($log_entry->{revision})) { - croak "$log_entry->{revision} = $c already exists! ", - "Why are we refetching it?\n"; - } - my $old_env = set_commit_header_env($log_entry); - my $tree = $log_entry->{tree}; - if (!defined $tree) { - $tree = $self->tmp_index_do(sub { - command_oneline('write-tree') }); - } - die "Tree is not a valid sha1: $tree\n" if $tree !~ /^$::sha1$/o; - - my @exec = ('git', 'commit-tree', $tree); - foreach ($self->get_commit_parents($log_entry)) { - push @exec, '-p', $_; - } - defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec)) - or croak $!; - binmode $msg_fh; - - # we always get UTF-8 from SVN, but we may want our commits in - # a different encoding. - if (my $enc = Git::config('i18n.commitencoding')) { - require Encode; - Encode::from_to($log_entry->{log}, 'UTF-8', $enc); - } - print $msg_fh $log_entry->{log} or croak $!; - restore_commit_header_env($old_env); - unless ($self->no_metadata) { - print $msg_fh "\ngit-svn-id: $log_entry->{metadata}\n" - or croak $!; - } - $msg_fh->flush == 0 or croak $!; - close $msg_fh or croak $!; - chomp(my $commit = do { local $/; <$out_fh> }); - close $out_fh or croak $!; - waitpid $pid, 0; - croak $? if $?; - if ($commit !~ /^$::sha1$/o) { - die "Failed to commit, invalid sha1: $commit\n"; - } - - $self->rev_map_set($log_entry->{revision}, $commit, 1); - - $self->{last_rev} = $log_entry->{revision}; - $self->{last_commit} = $commit; - print "r$log_entry->{revision}" unless $::_q > 1; - if (defined $log_entry->{svm_revision}) { - print " (\@$log_entry->{svm_revision})" unless $::_q > 1; - $self->rev_map_set($log_entry->{svm_revision}, $commit, - 0, $self->svm_uuid); - } - print " = $commit ($self->{ref_id})\n" unless $::_q > 1; - if (--$_gc_nr == 0) { - $_gc_nr = $_gc_period; - gc(); - } - return $commit; -} - -sub match_paths { - my ($self, $paths, $r) = @_; - return 1 if $self->{path} eq ''; - if (my $path = $paths->{"/$self->{path}"}) { - return ($path->{action} eq 'D') ? 0 : 1; - } - $self->{path_regex} ||= qr/^\/\Q$self->{path}\E\//; - if (grep /$self->{path_regex}/, keys %$paths) { - return 1; - } - my $c = ''; - foreach (split m#/#, $self->{path}) { - $c .= "/$_"; - next unless ($paths->{$c} && - ($paths->{$c}->{action} =~ /^[AR]$/)); - if ($self->ra->check_path($self->{path}, $r) == - $SVN::Node::dir) { - return 1; - } - } - return 0; -} - -sub find_parent_branch { - my ($self, $paths, $rev) = @_; - return undef unless $self->follow_parent; - unless (defined $paths) { - my $err_handler = $SVN::Error::handler; - $SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs; - $self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1, - sub { $paths = $_[0] }); - $SVN::Error::handler = $err_handler; - } - return undef unless defined $paths; - - # look for a parent from another branch: - my @b_path_components = split m#/#, $self->{path}; - my @a_path_components; - my $i; - while (@b_path_components) { - $i = $paths->{'/'.join('/', @b_path_components)}; - last if $i && defined $i->{copyfrom_path}; - unshift(@a_path_components, pop(@b_path_components)); - } - return undef unless defined $i && defined $i->{copyfrom_path}; - my $branch_from = $i->{copyfrom_path}; - if (@a_path_components) { - print STDERR "branch_from: $branch_from => "; - $branch_from .= '/'.join('/', @a_path_components); - print STDERR $branch_from, "\n"; - } - my $r = $i->{copyfrom_rev}; - my $repos_root = $self->ra->{repos_root}; - my $url = $self->ra->{url}; - my $new_url = $url . $branch_from; - print STDERR "Found possible branch point: ", - "$new_url => ", $self->full_url, ", $r\n" - unless $::_q > 1; - $branch_from =~ s#^/##; - my $gs = $self->other_gs($new_url, $url, - $branch_from, $r, $self->{ref_id}); - my ($r0, $parent) = $gs->find_rev_before($r, 1); - { - my ($base, $head); - if (!defined $r0 || !defined $parent) { - ($base, $head) = parse_revision_argument(0, $r); - } else { - if ($r0 < $r) { - $gs->ra->get_log([$gs->{path}], $r0 + 1, $r, 1, - 0, 1, sub { $base = $_[1] - 1 }); - } - } - if (defined $base && $base <= $r) { - $gs->fetch($base, $r); - } - ($r0, $parent) = $gs->find_rev_before($r, 1); - } - if (defined $r0 && defined $parent) { - print STDERR "Found branch parent: ($self->{ref_id}) $parent\n" - unless $::_q > 1; - my $ed; - if ($self->ra->can_do_switch) { - $self->assert_index_clean($parent); - print STDERR "Following parent with do_switch\n" - unless $::_q > 1; - # do_switch works with svn/trunk >= r22312, but that - # is not included with SVN 1.4.3 (the latest version - # at the moment), so we can't rely on it - $self->{last_rev} = $r0; - $self->{last_commit} = $parent; - $ed = Git::SVN::Fetcher->new($self, $gs->{path}); - $gs->ra->gs_do_switch($r0, $rev, $gs, - $self->full_url, $ed) - or die "SVN connection failed somewhere...\n"; - } elsif ($self->ra->trees_match($new_url, $r0, - $self->full_url, $rev)) { - print STDERR "Trees match:\n", - " $new_url\@$r0\n", - " ${\$self->full_url}\@$rev\n", - "Following parent with no changes\n" - unless $::_q > 1; - $self->tmp_index_do(sub { - command_noisy('read-tree', $parent); - }); - $self->{last_commit} = $parent; - } else { - print STDERR "Following parent with do_update\n" - unless $::_q > 1; - $ed = Git::SVN::Fetcher->new($self); - $self->ra->gs_do_update($rev, $rev, $self, $ed) - or die "SVN connection failed somewhere...\n"; - } - print STDERR "Successfully followed parent\n" unless $::_q > 1; - return $self->make_log_entry($rev, [$parent], $ed); - } - return undef; -} - -sub do_fetch { - my ($self, $paths, $rev) = @_; - my $ed; - my ($last_rev, @parents); - if (my $lc = $self->last_commit) { - # we can have a branch that was deleted, then re-added - # under the same name but copied from another path, in - # which case we'll have multiple parents (we don't - # want to break the original ref, nor lose copypath info): - if (my $log_entry = $self->find_parent_branch($paths, $rev)) { - push @{$log_entry->{parents}}, $lc; - return $log_entry; - } - $ed = Git::SVN::Fetcher->new($self); - $last_rev = $self->{last_rev}; - $ed->{c} = $lc; - @parents = ($lc); - } else { - $last_rev = $rev; - if (my $log_entry = $self->find_parent_branch($paths, $rev)) { - return $log_entry; - } - $ed = Git::SVN::Fetcher->new($self); - } - unless ($self->ra->gs_do_update($last_rev, $rev, $self, $ed)) { - die "SVN connection failed somewhere...\n"; - } - $self->make_log_entry($rev, \@parents, $ed); -} - -sub mkemptydirs { - my ($self, $r) = @_; - - sub scan { - my ($r, $empty_dirs, $line) = @_; - if (defined $r && $line =~ /^r(\d+)$/) { - return 0 if $1 > $r; - } elsif ($line =~ /^ \+empty_dir: (.+)$/) { - $empty_dirs->{$1} = 1; - } elsif ($line =~ /^ \-empty_dir: (.+)$/) { - my @d = grep {m[^\Q$1\E(/|$)]} (keys %$empty_dirs); - delete @$empty_dirs{@d}; - } - 1; # continue - }; - - my %empty_dirs = (); - my $gz_file = "$self->{dir}/unhandled.log.gz"; - if (-f $gz_file) { - if (!$can_compress) { - warn "Compress::Zlib could not be found; ", - "empty directories in $gz_file will not be read\n"; - } else { - my $gz = Compress::Zlib::gzopen($gz_file, "rb") or - die "Unable to open $gz_file: $!\n"; - my $line; - while ($gz->gzreadline($line) > 0) { - scan($r, \%empty_dirs, $line) or last; - } - $gz->gzclose; - } - } - - if (open my $fh, '<', "$self->{dir}/unhandled.log") { - binmode $fh or croak "binmode: $!"; - while (<$fh>) { - scan($r, \%empty_dirs, $_) or last; - } - close $fh; - } - - my $strip = qr/\A\Q$self->{path}\E(?:\/|$)/; - foreach my $d (sort keys %empty_dirs) { - $d = uri_decode($d); - $d =~ s/$strip//; - next unless length($d); - next if -d $d; - if (-e $d) { - warn "$d exists but is not a directory\n"; - } else { - print "creating empty directory: $d\n"; - mkpath([$d]); - } - } -} - -sub get_untracked { - my ($self, $ed) = @_; - my @out; - my $h = $ed->{empty}; - foreach (sort keys %$h) { - my $act = $h->{$_} ? '+empty_dir' : '-empty_dir'; - push @out, " $act: " . uri_encode($_); - warn "W: $act: $_\n"; - } - foreach my $t (qw/dir_prop file_prop/) { - $h = $ed->{$t} or next; - foreach my $path (sort keys %$h) { - my $ppath = $path eq '' ? '.' : $path; - foreach my $prop (sort keys %{$h->{$path}}) { - next if $SKIP_PROP{$prop}; - my $v = $h->{$path}->{$prop}; - my $t_ppath_prop = "$t: " . - uri_encode($ppath) . ' ' . - uri_encode($prop); - if (defined $v) { - push @out, " +$t_ppath_prop " . - uri_encode($v); - } else { - push @out, " -$t_ppath_prop"; - } - } - } - } - foreach my $t (qw/absent_file absent_directory/) { - $h = $ed->{$t} or next; - foreach my $parent (sort keys %$h) { - foreach my $path (sort @{$h->{$parent}}) { - push @out, " $t: " . - uri_encode("$parent/$path"); - warn "W: $t: $parent/$path ", - "Insufficient permissions?\n"; - } - } - } - \@out; -} - -sub get_tz { - # some systmes don't handle or mishandle %z, so be creative. - my $t = shift || time; - my $gm = timelocal(gmtime($t)); - my $sign = qw( + + - )[ $t <=> $gm ]; - return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]); -} - -# parse_svn_date(DATE) -# -------------------- -# Given a date (in UTC) from Subversion, return a string in the format -# "<TZ Offset> <local date/time>" that Git will use. -# -# By default the parsed date will be in UTC; if $Git::SVN::_localtime -# is true we'll convert it to the local timezone instead. -sub parse_svn_date { - my $date = shift || return '+0000 1970-01-01 00:00:00'; - my ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\d{4})\-(\d\d)\-(\d\d)T - (\d\d)\:(\d\d)\:(\d\d)\.\d*Z$/x) or - croak "Unable to parse date: $date\n"; - my $parsed_date; # Set next. - - if ($Git::SVN::_localtime) { - # Translate the Subversion datetime to an epoch time. - # Begin by switching ourselves to $date's timezone, UTC. - my $old_env_TZ = $ENV{TZ}; - $ENV{TZ} = 'UTC'; - - my $epoch_in_UTC = - POSIX::strftime('%s', $S, $M, $H, $d, $m - 1, $Y - 1900); - - # Determine our local timezone (including DST) at the - # time of $epoch_in_UTC. $Git::SVN::Log::TZ stored the - # value of TZ, if any, at the time we were run. - if (defined $Git::SVN::Log::TZ) { - $ENV{TZ} = $Git::SVN::Log::TZ; - } else { - delete $ENV{TZ}; - } - - my $our_TZ = get_tz(); - - # This converts $epoch_in_UTC into our local timezone. - my ($sec, $min, $hour, $mday, $mon, $year, - $wday, $yday, $isdst) = localtime($epoch_in_UTC); - - $parsed_date = sprintf('%s %04d-%02d-%02d %02d:%02d:%02d', - $our_TZ, $year + 1900, $mon + 1, - $mday, $hour, $min, $sec); - - # Reset us to the timezone in effect when we entered - # this routine. - if (defined $old_env_TZ) { - $ENV{TZ} = $old_env_TZ; - } else { - delete $ENV{TZ}; - } - } else { - $parsed_date = "+0000 $Y-$m-$d $H:$M:$S"; - } - - return $parsed_date; -} - -sub other_gs { - my ($self, $new_url, $url, - $branch_from, $r, $old_ref_id) = @_; - my $gs = Git::SVN->find_by_url($new_url, $url, $branch_from); - unless ($gs) { - my $ref_id = $old_ref_id; - $ref_id =~ s/\@\d+-*$//; - $ref_id .= "\@$r"; - # just grow a tail if we're not unique enough :x - $ref_id .= '-' while find_ref($ref_id); - my ($u, $p, $repo_id) = ($new_url, '', $ref_id); - if ($u =~ s#^\Q$url\E(/|$)##) { - $p = $u; - $u = $url; - $repo_id = $self->{repo_id}; - } - while (1) { - # It is possible to tag two different subdirectories at - # the same revision. If the url for an existing ref - # does not match, we must either find a ref with a - # matching url or create a new ref by growing a tail. - $gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1); - my (undef, $max_commit) = $gs->rev_map_max(1); - last if (!$max_commit); - my ($url) = ::cmt_metadata($max_commit); - last if ($url eq $gs->metadata_url); - $ref_id .= '-'; - } - print STDERR "Initializing parent: $ref_id\n" unless $::_q > 1; - } - $gs -} - -sub call_authors_prog { - my ($orig_author) = @_; - $orig_author = command_oneline('rev-parse', '--sq-quote', $orig_author); - my $author = `$::_authors_prog $orig_author`; - if ($? != 0) { - die "$::_authors_prog failed with exit code $?\n" - } - if ($author =~ /^\s*(.+?)\s*<(.*)>\s*$/) { - my ($name, $email) = ($1, $2); - $email = undef if length $2 == 0; - return [$name, $email]; - } else { - die "Author: $orig_author: $::_authors_prog returned " - . "invalid author format: $author\n"; - } -} - -sub check_author { - my ($author) = @_; - if (!defined $author || length $author == 0) { - $author = '(no author)'; - } - if (!defined $::users{$author}) { - if (defined $::_authors_prog) { - $::users{$author} = call_authors_prog($author); - } elsif (defined $::_authors) { - die "Author: $author not defined in $::_authors file\n"; - } - } - $author; -} - -sub find_extra_svk_parents { - my ($self, $ed, $tickets, $parents) = @_; - # aha! svk:merge property changed... - my @tickets = split "\n", $tickets; - my @known_parents; - for my $ticket ( @tickets ) { - my ($uuid, $path, $rev) = split /:/, $ticket; - if ( $uuid eq $self->ra_uuid ) { - my $url = $self->{url}; - my $repos_root = $url; - my $branch_from = $path; - $branch_from =~ s{^/}{}; - my $gs = $self->other_gs($repos_root."/".$branch_from, - $url, - $branch_from, - $rev, - $self->{ref_id}); - if ( my $commit = $gs->rev_map_get($rev, $uuid) ) { - # wahey! we found it, but it might be - # an old one (!) - push @known_parents, [ $rev, $commit ]; - } - } - } - # Ordering matters; highest-numbered commit merge tickets - # first, as they may account for later merge ticket additions - # or changes. - @known_parents = map {$_->[1]} sort {$b->[0] <=> $a->[0]} @known_parents; - for my $parent ( @known_parents ) { - my @cmd = ('rev-list', $parent, map { "^$_" } @$parents ); - my ($msg_fh, $ctx) = command_output_pipe(@cmd); - my $new; - while ( <$msg_fh> ) { - $new=1;last; - } - command_close_pipe($msg_fh, $ctx); - if ( $new ) { - print STDERR - "Found merge parent (svk:merge ticket): $parent\n"; - push @$parents, $parent; - } - } -} - -sub lookup_svn_merge { - my $uuid = shift; - my $url = shift; - my $merge = shift; - - my ($source, $revs) = split ":", $merge; - my $path = $source; - $path =~ s{^/}{}; - my $gs = Git::SVN->find_by_url($url.$source, $url, $path); - if ( !$gs ) { - warn "Couldn't find revmap for $url$source\n"; - return; - } - my @ranges = split ",", $revs; - my ($tip, $tip_commit); - my @merged_commit_ranges; - # find the tip - for my $range ( @ranges ) { - my ($bottom, $top) = split "-", $range; - $top ||= $bottom; - my $bottom_commit = $gs->find_rev_after( $bottom, 1, $top ); - my $top_commit = $gs->find_rev_before( $top, 1, $bottom ); - - unless ($top_commit and $bottom_commit) { - warn "W:unknown path/rev in svn:mergeinfo " - ."dirprop: $source:$range\n"; - next; - } - - if (scalar(command('rev-parse', "$bottom_commit^@"))) { - push @merged_commit_ranges, - "$bottom_commit^..$top_commit"; - } else { - push @merged_commit_ranges, "$top_commit"; - } - - if ( !defined $tip or $top > $tip ) { - $tip = $top; - $tip_commit = $top_commit; - } - } - return ($tip_commit, @merged_commit_ranges); -} - -sub _rev_list { - my ($msg_fh, $ctx) = command_output_pipe( - "rev-list", @_, - ); - my @rv; - while ( <$msg_fh> ) { - chomp; - push @rv, $_; - } - command_close_pipe($msg_fh, $ctx); - @rv; -} - -sub check_cherry_pick { - my $base = shift; - my $tip = shift; - my $parents = shift; - my @ranges = @_; - my %commits = map { $_ => 1 } - _rev_list("--no-merges", $tip, "--not", $base, @$parents, "--"); - for my $range ( @ranges ) { - delete @commits{_rev_list($range, "--")}; - } - for my $commit (keys %commits) { - if (has_no_changes($commit)) { - delete $commits{$commit}; - } - } - return (keys %commits); -} - -sub has_no_changes { - my $commit = shift; - - my @revs = split / /, command_oneline( - qw(rev-list --parents -1 -m), $commit); - - # Commits with no parents, e.g. the start of a partial branch, - # have changes by definition. - return 1 if (@revs < 2); - - # Commits with multiple parents, e.g a merge, have no changes - # by definition. - return 0 if (@revs > 2); - - return (command_oneline("rev-parse", "$commit^{tree}") eq - command_oneline("rev-parse", "$commit~1^{tree}")); -} - -sub tie_for_persistent_memoization { - my $hash = shift; - my $path = shift; - - if ($can_use_yaml) { - tie %$hash => 'Git::SVN::Memoize::YAML', "$path.yaml"; - } else { - tie %$hash => 'Memoize::Storable', "$path.db", 'nstore'; - } -} - -# The GIT_DIR environment variable is not always set until after the command -# line arguments are processed, so we can't memoize in a BEGIN block. -{ - my $memoized = 0; - - sub memoize_svn_mergeinfo_functions { - return if $memoized; - $memoized = 1; - - my $cache_path = "$ENV{GIT_DIR}/svn/.caches/"; - mkpath([$cache_path]) unless -d $cache_path; - - my %lookup_svn_merge_cache; - my %check_cherry_pick_cache; - my %has_no_changes_cache; - - tie_for_persistent_memoization(\%lookup_svn_merge_cache, - "$cache_path/lookup_svn_merge"); - memoize 'lookup_svn_merge', - SCALAR_CACHE => 'FAULT', - LIST_CACHE => ['HASH' => \%lookup_svn_merge_cache], - ; - - tie_for_persistent_memoization(\%check_cherry_pick_cache, - "$cache_path/check_cherry_pick"); - memoize 'check_cherry_pick', - SCALAR_CACHE => 'FAULT', - LIST_CACHE => ['HASH' => \%check_cherry_pick_cache], - ; - - tie_for_persistent_memoization(\%has_no_changes_cache, - "$cache_path/has_no_changes"); - memoize 'has_no_changes', - SCALAR_CACHE => ['HASH' => \%has_no_changes_cache], - LIST_CACHE => 'FAULT', - ; - } - - sub unmemoize_svn_mergeinfo_functions { - return if not $memoized; - $memoized = 0; - - Memoize::unmemoize 'lookup_svn_merge'; - Memoize::unmemoize 'check_cherry_pick'; - Memoize::unmemoize 'has_no_changes'; - } - - Memoize::memoize 'Git::SVN::repos_root'; -} - -END { - # Force cache writeout explicitly instead of waiting for - # global destruction to avoid segfault in Storable: - # http://rt.cpan.org/Public/Bug/Display.html?id=36087 - unmemoize_svn_mergeinfo_functions(); -} - -sub parents_exclude { - my $parents = shift; - my @commits = @_; - return unless @commits; - - my @excluded; - my $excluded; - do { - my @cmd = ('rev-list', "-1", @commits, "--not", @$parents ); - $excluded = command_oneline(@cmd); - if ( $excluded ) { - my @new; - my $found; - for my $commit ( @commits ) { - if ( $commit eq $excluded ) { - push @excluded, $commit; - $found++; - last; - } - else { - push @new, $commit; - } - } - die "saw commit '$excluded' in rev-list output, " - ."but we didn't ask for that commit (wanted: @commits --not @$parents)" - unless $found; - @commits = @new; - } - } - while ($excluded and @commits); - - return @excluded; -} - - -# note: this function should only be called if the various dirprops -# have actually changed -sub find_extra_svn_parents { - my ($self, $ed, $mergeinfo, $parents) = @_; - # aha! svk:merge property changed... - - memoize_svn_mergeinfo_functions(); - - # We first search for merged tips which are not in our - # history. Then, we figure out which git revisions are in - # that tip, but not this revision. If all of those revisions - # are now marked as merge, we can add the tip as a parent. - my @merges = split "\n", $mergeinfo; - my @merge_tips; - my $url = $self->{url}; - my $uuid = $self->ra_uuid; - my %ranges; - for my $merge ( @merges ) { - my ($tip_commit, @ranges) = - lookup_svn_merge( $uuid, $url, $merge ); - unless (!$tip_commit or - grep { $_ eq $tip_commit } @$parents ) { - push @merge_tips, $tip_commit; - $ranges{$tip_commit} = \@ranges; - } else { - push @merge_tips, undef; - } - } - - my %excluded = map { $_ => 1 } - parents_exclude($parents, grep { defined } @merge_tips); - - # check merge tips for new parents - my @new_parents; - for my $merge_tip ( @merge_tips ) { - my $spec = shift @merges; - next unless $merge_tip and $excluded{$merge_tip}; - - my $ranges = $ranges{$merge_tip}; - - # check out 'new' tips - my $merge_base; - eval { - $merge_base = command_oneline( - "merge-base", - @$parents, $merge_tip, - ); - }; - if ($@) { - die "An error occurred during merge-base" - unless $@->isa("Git::Error::Command"); - - warn "W: Cannot find common ancestor between ". - "@$parents and $merge_tip. Ignoring merge info.\n"; - next; - } - - # double check that there are no missing non-merge commits - my (@incomplete) = check_cherry_pick( - $merge_base, $merge_tip, - $parents, - @$ranges, - ); - - if ( @incomplete ) { - warn "W:svn cherry-pick ignored ($spec) - missing " - .@incomplete." commit(s) (eg $incomplete[0])\n"; - } else { - warn - "Found merge parent (svn:mergeinfo prop): ", - $merge_tip, "\n"; - push @new_parents, $merge_tip; - } - } - - # cater for merges which merge commits from multiple branches - if ( @new_parents > 1 ) { - for ( my $i = 0; $i <= $#new_parents; $i++ ) { - for ( my $j = 0; $j <= $#new_parents; $j++ ) { - next if $i == $j; - next unless $new_parents[$i]; - next unless $new_parents[$j]; - my $revs = command_oneline( - "rev-list", "-1", - "$new_parents[$i]..$new_parents[$j]", - ); - if ( !$revs ) { - undef($new_parents[$j]); - } - } - } - } - push @$parents, grep { defined } @new_parents; -} - -sub make_log_entry { - my ($self, $rev, $parents, $ed) = @_; - my $untracked = $self->get_untracked($ed); - - my @parents = @$parents; - my $ps = $ed->{path_strip} || ""; - for my $path ( grep { m/$ps/ } %{$ed->{dir_prop}} ) { - my $props = $ed->{dir_prop}{$path}; - if ( $props->{"svk:merge"} ) { - $self->find_extra_svk_parents - ($ed, $props->{"svk:merge"}, \@parents); - } - if ( $props->{"svn:mergeinfo"} ) { - $self->find_extra_svn_parents - ($ed, - $props->{"svn:mergeinfo"}, - \@parents); - } - } - - open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!; - print $un "r$rev\n" or croak $!; - print $un $_, "\n" foreach @$untracked; - my %log_entry = ( parents => \@parents, revision => $rev, - log => ''); - - my $headrev; - my $logged = delete $self->{logged_rev_props}; - if (!$logged || $self->{-want_revprops}) { - my $rp = $self->ra->rev_proplist($rev); - foreach (sort keys %$rp) { - my $v = $rp->{$_}; - if (/^svn:(author|date|log)$/) { - $log_entry{$1} = $v; - } elsif ($_ eq 'svm:headrev') { - $headrev = $v; - } else { - print $un " rev_prop: ", uri_encode($_), ' ', - uri_encode($v), "\n"; - } - } - } else { - map { $log_entry{$_} = $logged->{$_} } keys %$logged; - } - close $un or croak $!; - - $log_entry{date} = parse_svn_date($log_entry{date}); - $log_entry{log} .= "\n"; - my $author = $log_entry{author} = check_author($log_entry{author}); - my ($name, $email) = defined $::users{$author} ? @{$::users{$author}} - : ($author, undef); - - my ($commit_name, $commit_email) = ($name, $email); - if ($_use_log_author) { - my $name_field; - if ($log_entry{log} =~ /From:\s+(.*\S)\s*\n/i) { - $name_field = $1; - } elsif ($log_entry{log} =~ /Signed-off-by:\s+(.*\S)\s*\n/i) { - $name_field = $1; - } - if (!defined $name_field) { - if (!defined $email) { - $email = $name; - } - } elsif ($name_field =~ /(.*?)\s+<(.*)>/) { - ($name, $email) = ($1, $2); - } elsif ($name_field =~ /(.*)@/) { - ($name, $email) = ($1, $name_field); - } else { - ($name, $email) = ($name_field, $name_field); - } - } - if (defined $headrev && $self->use_svm_props) { - if ($self->rewrite_root) { - die "Can't have both 'useSvmProps' and 'rewriteRoot' ", - "options set!\n"; - } - if ($self->rewrite_uuid) { - die "Can't have both 'useSvmProps' and 'rewriteUUID' ", - "options set!\n"; - } - my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}i; - # we don't want "SVM: initializing mirror for junk" ... - return undef if $r == 0; - my $svm = $self->svm; - if ($uuid ne $svm->{uuid}) { - die "UUID mismatch on SVM path:\n", - "expected: $svm->{uuid}\n", - " got: $uuid\n"; - } - my $full_url = $self->full_url; - $full_url =~ s#^\Q$svm->{replace}\E(/|$)#$svm->{source}$1# or - die "Failed to replace '$svm->{replace}' with ", - "'$svm->{source}' in $full_url\n"; - # throw away username for storing in records - remove_username($full_url); - $log_entry{metadata} = "$full_url\@$r $uuid"; - $log_entry{svm_revision} = $r; - $email ||= "$author\@$uuid"; - $commit_email ||= "$author\@$uuid"; - } elsif ($self->use_svnsync_props) { - my $full_url = $self->svnsync->{url}; - $full_url .= "/$self->{path}" if length $self->{path}; - remove_username($full_url); - my $uuid = $self->svnsync->{uuid}; - $log_entry{metadata} = "$full_url\@$rev $uuid"; - $email ||= "$author\@$uuid"; - $commit_email ||= "$author\@$uuid"; - } else { - my $url = $self->metadata_url; - remove_username($url); - my $uuid = $self->rewrite_uuid || $self->ra->get_uuid; - $log_entry{metadata} = "$url\@$rev " . $uuid; - $email ||= "$author\@" . $uuid; - $commit_email ||= "$author\@" . $uuid; - } - $log_entry{name} = $name; - $log_entry{email} = $email; - $log_entry{commit_name} = $commit_name; - $log_entry{commit_email} = $commit_email; - \%log_entry; -} - -sub fetch { - my ($self, $min_rev, $max_rev, @parents) = @_; - my ($last_rev, $last_commit) = $self->last_rev_commit; - my ($base, $head) = $self->get_fetch_range($min_rev, $max_rev); - $self->ra->gs_fetch_loop_common($base, $head, [$self]); -} - -sub set_tree_cb { - my ($self, $log_entry, $tree, $rev, $date, $author) = @_; - $self->{inject_parents} = { $rev => $tree }; - $self->fetch(undef, undef); -} - -sub set_tree { - my ($self, $tree) = (shift, shift); - my $log_entry = ::get_commit_entry($tree); - unless ($self->{last_rev}) { - ::fatal("Must have an existing revision to commit"); - } - my %ed_opts = ( r => $self->{last_rev}, - log => $log_entry->{log}, - ra => $self->ra, - tree_a => $self->{last_commit}, - tree_b => $tree, - editor_cb => sub { - $self->set_tree_cb($log_entry, $tree, @_) }, - svn_path => $self->{path} ); - if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) { - print "No changes\nr$self->{last_rev} = $tree\n"; - } -} - -sub rebuild_from_rev_db { - my ($self, $path) = @_; - my $r = -1; - open my $fh, '<', $path or croak "open: $!"; - binmode $fh or croak "binmode: $!"; - while (<$fh>) { - length($_) == 41 or croak "inconsistent size in ($_) != 41"; - chomp($_); - ++$r; - next if $_ eq ('0' x 40); - $self->rev_map_set($r, $_); - print "r$r = $_\n"; - } - close $fh or croak "close: $!"; - unlink $path or croak "unlink: $!"; -} - -sub rebuild { - my ($self) = @_; - my $map_path = $self->map_path; - my $partial = (-e $map_path && ! -z $map_path); - return unless ::verify_ref($self->refname.'^0'); - if (!$partial && ($self->use_svm_props || $self->no_metadata)) { - my $rev_db = $self->rev_db_path; - $self->rebuild_from_rev_db($rev_db); - if ($self->use_svm_props) { - my $svm_rev_db = $self->rev_db_path($self->svm_uuid); - $self->rebuild_from_rev_db($svm_rev_db); - } - $self->unlink_rev_db_symlink; - return; - } - print "Rebuilding $map_path ...\n" if (!$partial); - my ($base_rev, $head) = ($partial ? $self->rev_map_max_norebuild(1) : - (undef, undef)); - my ($log, $ctx) = - command_output_pipe(qw/rev-list --pretty=raw --reverse/, - ($head ? "$head.." : "") . $self->refname, - '--'); - my $metadata_url = $self->metadata_url; - remove_username($metadata_url); - my $svn_uuid = $self->rewrite_uuid || $self->ra_uuid; - my $c; - while (<$log>) { - if ( m{^commit ($::sha1)$} ) { - $c = $1; - next; - } - next unless s{^\s*(git-svn-id:)}{$1}; - my ($url, $rev, $uuid) = ::extract_metadata($_); - remove_username($url); - - # ignore merges (from set-tree) - next if (!defined $rev || !$uuid); - - # if we merged or otherwise started elsewhere, this is - # how we break out of it - if (($uuid ne $svn_uuid) || - ($metadata_url && $url && ($url ne $metadata_url))) { - next; - } - if ($partial && $head) { - print "Partial-rebuilding $map_path ...\n"; - print "Currently at $base_rev = $head\n"; - $head = undef; - } - - $self->rev_map_set($rev, $c); - print "r$rev = $c\n"; - } - command_close_pipe($log, $ctx); - print "Done rebuilding $map_path\n" if (!$partial || !$head); - my $rev_db_path = $self->rev_db_path; - if (-f $self->rev_db_path) { - unlink $self->rev_db_path or croak "unlink: $!"; - } - $self->unlink_rev_db_symlink; -} - -# rev_map: -# Tie::File seems to be prone to offset errors if revisions get sparse, -# it's not that fast, either. Tie::File is also not in Perl 5.6. So -# one of my favorite modules is out :< Next up would be one of the DBM -# modules, but I'm not sure which is most portable... -# -# This is the replacement for the rev_db format, which was too big -# and inefficient for large repositories with a lot of sparse history -# (mainly tags) -# -# The format is this: -# - 24 bytes for every record, -# * 4 bytes for the integer representing an SVN revision number -# * 20 bytes representing the sha1 of a git commit -# - No empty padding records like the old format -# (except the last record, which can be overwritten) -# - new records are written append-only since SVN revision numbers -# increase monotonically -# - lookups on SVN revision number are done via a binary search -# - Piping the file to xxd -c24 is a good way of dumping it for -# viewing or editing (piped back through xxd -r), should the need -# ever arise. -# - The last record can be padding revision with an all-zero sha1 -# This is used to optimize fetch performance when using multiple -# "fetch" directives in .git/config -# -# These files are disposable unless noMetadata or useSvmProps is set - -sub _rev_map_set { - my ($fh, $rev, $commit) = @_; - - binmode $fh or croak "binmode: $!"; - my $size = (stat($fh))[7]; - ($size % 24) == 0 or croak "inconsistent size: $size"; - - my $wr_offset = 0; - if ($size > 0) { - sysseek($fh, -24, SEEK_END) or croak "seek: $!"; - my $read = sysread($fh, my $buf, 24) or croak "read: $!"; - $read == 24 or croak "read only $read bytes (!= 24)"; - my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf); - if ($last_commit eq ('0' x40)) { - if ($size >= 48) { - sysseek($fh, -48, SEEK_END) or croak "seek: $!"; - $read = sysread($fh, $buf, 24) or - croak "read: $!"; - $read == 24 or - croak "read only $read bytes (!= 24)"; - ($last_rev, $last_commit) = - unpack(rev_map_fmt, $buf); - if ($last_commit eq ('0' x40)) { - croak "inconsistent .rev_map\n"; - } - } - if ($last_rev >= $rev) { - croak "last_rev is higher!: $last_rev >= $rev"; - } - $wr_offset = -24; - } - } - sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!"; - syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or - croak "write: $!"; -} - -sub _rev_map_reset { - my ($fh, $rev, $commit) = @_; - my $c = _rev_map_get($fh, $rev); - $c eq $commit or die "_rev_map_reset(@_) commit $c does not match!\n"; - my $offset = sysseek($fh, 0, SEEK_CUR) or croak "seek: $!"; - truncate $fh, $offset or croak "truncate: $!"; -} - -sub mkfile { - my ($path) = @_; - unless (-e $path) { - my ($dir, $base) = ($path =~ m#^(.*?)/?([^/]+)$#); - mkpath([$dir]) unless -d $dir; - open my $fh, '>>', $path or die "Couldn't create $path: $!\n"; - close $fh or die "Couldn't close (create) $path: $!\n"; - } -} - -sub rev_map_set { - my ($self, $rev, $commit, $update_ref, $uuid) = @_; - defined $commit or die "missing arg3\n"; - length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n"; - my $db = $self->map_path($uuid); - my $db_lock = "$db.lock"; - my $sigmask; - $update_ref ||= 0; - if ($update_ref) { - $sigmask = POSIX::SigSet->new(); - my $signew = POSIX::SigSet->new(SIGINT, SIGHUP, SIGTERM, - SIGALRM, SIGUSR1, SIGUSR2); - sigprocmask(SIG_BLOCK, $signew, $sigmask) or - croak "Can't block signals: $!"; - } - mkfile($db); - - $LOCKFILES{$db_lock} = 1; - my $sync; - # both of these options make our .rev_db file very, very important - # and we can't afford to lose it because rebuild() won't work - if ($self->use_svm_props || $self->no_metadata) { - $sync = 1; - copy($db, $db_lock) or die "rev_map_set(@_): ", - "Failed to copy: ", - "$db => $db_lock ($!)\n"; - } else { - rename $db, $db_lock or die "rev_map_set(@_): ", - "Failed to rename: ", - "$db => $db_lock ($!)\n"; - } - - sysopen(my $fh, $db_lock, O_RDWR | O_CREAT) - or croak "Couldn't open $db_lock: $!\n"; - $update_ref eq 'reset' ? _rev_map_reset($fh, $rev, $commit) : - _rev_map_set($fh, $rev, $commit); - if ($sync) { - $fh->flush or die "Couldn't flush $db_lock: $!\n"; - $fh->sync or die "Couldn't sync $db_lock: $!\n"; - } - close $fh or croak $!; - if ($update_ref) { - $_head = $self; - my $note = ""; - $note = " ($update_ref)" if ($update_ref !~ /^\d*$/); - command_noisy('update-ref', '-m', "r$rev$note", - $self->refname, $commit); - } - rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ", - "$db_lock => $db ($!)\n"; - delete $LOCKFILES{$db_lock}; - if ($update_ref) { - sigprocmask(SIG_SETMASK, $sigmask) or - croak "Can't restore signal mask: $!"; - } -} - -# If want_commit, this will return an array of (rev, commit) where -# commit _must_ be a valid commit in the archive. -# Otherwise, it'll return the max revision (whether or not the -# commit is valid or just a 0x40 placeholder). -sub rev_map_max { - my ($self, $want_commit) = @_; - $self->rebuild; - my ($r, $c) = $self->rev_map_max_norebuild($want_commit); - $want_commit ? ($r, $c) : $r; -} - -sub rev_map_max_norebuild { - my ($self, $want_commit) = @_; - my $map_path = $self->map_path; - stat $map_path or return $want_commit ? (0, undef) : 0; - sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!"; - binmode $fh or croak "binmode: $!"; - my $size = (stat($fh))[7]; - ($size % 24) == 0 or croak "inconsistent size: $size"; - - if ($size == 0) { - close $fh or croak "close: $!"; - return $want_commit ? (0, undef) : 0; - } - - sysseek($fh, -24, SEEK_END) or croak "seek: $!"; - sysread($fh, my $buf, 24) == 24 or croak "read: $!"; - my ($r, $c) = unpack(rev_map_fmt, $buf); - if ($want_commit && $c eq ('0' x40)) { - if ($size < 48) { - return $want_commit ? (0, undef) : 0; - } - sysseek($fh, -48, SEEK_END) or croak "seek: $!"; - sysread($fh, $buf, 24) == 24 or croak "read: $!"; - ($r, $c) = unpack(rev_map_fmt, $buf); - if ($c eq ('0'x40)) { - croak "Penultimate record is all-zeroes in $map_path"; - } - } - close $fh or croak "close: $!"; - $want_commit ? ($r, $c) : $r; -} - -sub rev_map_get { - my ($self, $rev, $uuid) = @_; - my $map_path = $self->map_path($uuid); - return undef unless -e $map_path; - - sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!"; - my $c = _rev_map_get($fh, $rev); - close($fh) or croak "close: $!"; - $c -} - -sub _rev_map_get { - my ($fh, $rev) = @_; - - binmode $fh or croak "binmode: $!"; - my $size = (stat($fh))[7]; - ($size % 24) == 0 or croak "inconsistent size: $size"; - - if ($size == 0) { - return undef; - } - - my ($l, $u) = (0, $size - 24); - my ($r, $c, $buf); - - while ($l <= $u) { - my $i = int(($l/24 + $u/24) / 2) * 24; - sysseek($fh, $i, SEEK_SET) or croak "seek: $!"; - sysread($fh, my $buf, 24) == 24 or croak "read: $!"; - my ($r, $c) = unpack(rev_map_fmt, $buf); - - if ($r < $rev) { - $l = $i + 24; - } elsif ($r > $rev) { - $u = $i - 24; - } else { # $r == $rev - return $c eq ('0' x 40) ? undef : $c; - } - } - undef; -} - -# Finds the first svn revision that exists on (if $eq_ok is true) or -# before $rev for the current branch. It will not search any lower -# than $min_rev. Returns the git commit hash and svn revision number -# if found, else (undef, undef). -sub find_rev_before { - my ($self, $rev, $eq_ok, $min_rev) = @_; - --$rev unless $eq_ok; - $min_rev ||= 1; - my $max_rev = $self->rev_map_max; - $rev = $max_rev if ($rev > $max_rev); - while ($rev >= $min_rev) { - if (my $c = $self->rev_map_get($rev)) { - return ($rev, $c); - } - --$rev; - } - return (undef, undef); -} - -# Finds the first svn revision that exists on (if $eq_ok is true) or -# after $rev for the current branch. It will not search any higher -# than $max_rev. Returns the git commit hash and svn revision number -# if found, else (undef, undef). -sub find_rev_after { - my ($self, $rev, $eq_ok, $max_rev) = @_; - ++$rev unless $eq_ok; - $max_rev ||= $self->rev_map_max; - while ($rev <= $max_rev) { - if (my $c = $self->rev_map_get($rev)) { - return ($rev, $c); - } - ++$rev; - } - return (undef, undef); -} - -sub _new { - my ($class, $repo_id, $ref_id, $path) = @_; - unless (defined $repo_id && length $repo_id) { - $repo_id = $Git::SVN::default_repo_id; - } - unless (defined $ref_id && length $ref_id) { - $_prefix = '' unless defined($_prefix); - $_[2] = $ref_id = - "refs/remotes/$_prefix$Git::SVN::default_ref_id"; - } - $_[1] = $repo_id; - my $dir = "$ENV{GIT_DIR}/svn/$ref_id"; - - # Older repos imported by us used $GIT_DIR/svn/foo instead of - # $GIT_DIR/svn/refs/remotes/foo when tracking refs/remotes/foo - if ($ref_id =~ m{^refs/remotes/(.*)}) { - my $old_dir = "$ENV{GIT_DIR}/svn/$1"; - if (-d $old_dir && ! -d $dir) { - $dir = $old_dir; - } - } - - $_[3] = $path = '' unless (defined $path); - mkpath([$dir]); - bless { - ref_id => $ref_id, dir => $dir, index => "$dir/index", - path => $path, config => "$ENV{GIT_DIR}/svn/config", - map_root => "$dir/.rev_map", repo_id => $repo_id }, $class; -} - -# for read-only access of old .rev_db formats -sub unlink_rev_db_symlink { - my ($self) = @_; - my $link = $self->rev_db_path; - $link =~ s/\.[\w-]+$// or croak "missing UUID at the end of $link"; - if (-l $link) { - unlink $link or croak "unlink: $link failed!"; - } -} - -sub rev_db_path { - my ($self, $uuid) = @_; - my $db_path = $self->map_path($uuid); - $db_path =~ s{/\.rev_map\.}{/\.rev_db\.} - or croak "map_path: $db_path does not contain '/.rev_map.' !"; - $db_path; -} - -# the new replacement for .rev_db -sub map_path { - my ($self, $uuid) = @_; - $uuid ||= $self->ra_uuid; - "$self->{map_root}.$uuid"; -} - -sub uri_encode { - my ($f) = @_; - $f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg; - $f -} - -sub uri_decode { - my ($f) = @_; - $f =~ s#%([0-9a-fA-F]{2})#chr(hex($1))#eg; - $f -} - -sub remove_username { - $_[0] =~ s{^([^:]*://)[^@]+@}{$1}; -} - -package Git::SVN::Log; -use strict; -use warnings; -use POSIX qw/strftime/; -use constant commit_log_separator => ('-' x 72) . "\n"; -use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline - %rusers $show_commit $incremental/; -my $l_fmt; - -sub cmt_showable { - my ($c) = @_; - return 1 if defined $c->{r}; - - # big commit message got truncated by the 16k pretty buffer in rev-list - if ($c->{l} && $c->{l}->[-1] eq "...\n" && - $c->{a_raw} =~ /\@([a-f\d\-]+)>$/) { - @{$c->{l}} = (); - my @log = command(qw/cat-file commit/, $c->{c}); - - # shift off the headers - shift @log while ($log[0] ne ''); - shift @log; - - # TODO: make $c->{l} not have a trailing newline in the future - @{$c->{l}} = map { "$_\n" } grep !/^git-svn-id: /, @log; - - (undef, $c->{r}, undef) = ::extract_metadata( - (grep(/^git-svn-id: /, @log))[-1]); - } - return defined $c->{r}; -} - -sub log_use_color { - return $color || Git->repository->get_colorbool('color.diff'); -} - -sub git_svn_log_cmd { - my ($r_min, $r_max, @args) = @_; - my $head = 'HEAD'; - my (@files, @log_opts); - foreach my $x (@args) { - if ($x eq '--' || @files) { - push @files, $x; - } else { - if (::verify_ref("$x^0")) { - $head = $x; - } else { - push @log_opts, $x; - } - } - } - - my ($url, $rev, $uuid, $gs) = ::working_head_info($head); - $gs ||= Git::SVN->_new; - my @cmd = (qw/log --abbrev-commit --pretty=raw --default/, - $gs->refname); - push @cmd, '-r' unless $non_recursive; - push @cmd, qw/--raw --name-status/ if $verbose; - push @cmd, '--color' if log_use_color(); - push @cmd, @log_opts; - if (defined $r_max && $r_max == $r_min) { - push @cmd, '--max-count=1'; - if (my $c = $gs->rev_map_get($r_max)) { - push @cmd, $c; - } - } elsif (defined $r_max) { - if ($r_max < $r_min) { - ($r_min, $r_max) = ($r_max, $r_min); - } - my (undef, $c_max) = $gs->find_rev_before($r_max, 1, $r_min); - my (undef, $c_min) = $gs->find_rev_after($r_min, 1, $r_max); - # If there are no commits in the range, both $c_max and $c_min - # will be undefined. If there is at least 1 commit in the - # range, both will be defined. - return () if !defined $c_min || !defined $c_max; - if ($c_min eq $c_max) { - push @cmd, '--max-count=1', $c_min; - } else { - push @cmd, '--boundary', "$c_min..$c_max"; - } - } - return (@cmd, @files); -} - -# adapted from pager.c -sub config_pager { - if (! -t *STDOUT) { - $ENV{GIT_PAGER_IN_USE} = 'false'; - $pager = undef; - return; - } - chomp($pager = command_oneline(qw(var GIT_PAGER))); - if ($pager eq 'cat') { - $pager = undef; - } - $ENV{GIT_PAGER_IN_USE} = defined($pager); -} - -sub run_pager { - return unless defined $pager; - pipe my ($rfd, $wfd) or return; - defined(my $pid = fork) or ::fatal "Can't fork: $!"; - if (!$pid) { - open STDOUT, '>&', $wfd or - ::fatal "Can't redirect to stdout: $!"; - return; - } - open STDIN, '<&', $rfd or ::fatal "Can't redirect stdin: $!"; - $ENV{LESS} ||= 'FRSX'; - exec $pager or ::fatal "Can't run pager: $! ($pager)"; -} - -sub format_svn_date { - my $t = shift || time; - my $gmoff = Git::SVN::get_tz($t); - return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t)); -} - -sub parse_git_date { - my ($t, $tz) = @_; - # Date::Parse isn't in the standard Perl distro :( - if ($tz =~ s/^\+//) { - $t += tz_to_s_offset($tz); - } elsif ($tz =~ s/^\-//) { - $t -= tz_to_s_offset($tz); - } - return $t; -} - -sub set_local_timezone { - if (defined $TZ) { - $ENV{TZ} = $TZ; - } else { - delete $ENV{TZ}; - } -} - -sub tz_to_s_offset { - my ($tz) = @_; - $tz =~ s/(\d\d)$//; - return ($1 * 60) + ($tz * 3600); -} - -sub get_author_info { - my ($dest, $author, $t, $tz) = @_; - $author =~ s/(?:^\s*|\s*$)//g; - $dest->{a_raw} = $author; - my $au; - if ($::_authors) { - $au = $rusers{$author} || undef; - } - if (!$au) { - ($au) = ($author =~ /<([^>]+)\@[^>]+>$/); - } - $dest->{t} = $t; - $dest->{tz} = $tz; - $dest->{a} = $au; - $dest->{t_utc} = parse_git_date($t, $tz); -} - -sub process_commit { - my ($c, $r_min, $r_max, $defer) = @_; - if (defined $r_min && defined $r_max) { - if ($r_min == $c->{r} && $r_min == $r_max) { - show_commit($c); - return 0; - } - return 1 if $r_min == $r_max; - if ($r_min < $r_max) { - # we need to reverse the print order - return 0 if (defined $limit && --$limit < 0); - push @$defer, $c; - return 1; - } - if ($r_min != $r_max) { - return 1 if ($r_min < $c->{r}); - return 1 if ($r_max > $c->{r}); - } - } - return 0 if (defined $limit && --$limit < 0); - show_commit($c); - return 1; -} - -sub show_commit { - my $c = shift; - if ($oneline) { - my $x = "\n"; - if (my $l = $c->{l}) { - while ($l->[0] =~ /^\s*$/) { shift @$l } - $x = $l->[0]; - } - $l_fmt ||= 'A' . length($c->{r}); - print 'r',pack($l_fmt, $c->{r}),' | '; - print "$c->{c} | " if $show_commit; - print $x; - } else { - show_commit_normal($c); - } -} - -sub show_commit_changed_paths { - my ($c) = @_; - return unless $c->{changed}; - print "Changed paths:\n", @{$c->{changed}}; -} - -sub show_commit_normal { - my ($c) = @_; - print commit_log_separator, "r$c->{r} | "; - print "$c->{c} | " if $show_commit; - print "$c->{a} | ", format_svn_date($c->{t_utc}), ' | '; - my $nr_line = 0; - - if (my $l = $c->{l}) { - while ($l->[$#$l] eq "\n" && $#$l > 0 - && $l->[($#$l - 1)] eq "\n") { - pop @$l; - } - $nr_line = scalar @$l; - if (!$nr_line) { - print "1 line\n\n\n"; - } else { - if ($nr_line == 1) { - $nr_line = '1 line'; - } else { - $nr_line .= ' lines'; - } - print $nr_line, "\n"; - show_commit_changed_paths($c); - print "\n"; - print $_ foreach @$l; - } - } else { - print "1 line\n"; - show_commit_changed_paths($c); - print "\n"; - - } - foreach my $x (qw/raw stat diff/) { - if ($c->{$x}) { - print "\n"; - print $_ foreach @{$c->{$x}} - } - } -} - -sub cmd_show_log { - my (@args) = @_; - my ($r_min, $r_max); - my $r_last = -1; # prevent dupes - set_local_timezone(); - if (defined $::_revision) { - if ($::_revision =~ /^(\d+):(\d+)$/) { - ($r_min, $r_max) = ($1, $2); - } elsif ($::_revision =~ /^\d+$/) { - $r_min = $r_max = $::_revision; - } else { - ::fatal "-r$::_revision is not supported, use ", - "standard 'git log' arguments instead"; - } - } - - config_pager(); - @args = git_svn_log_cmd($r_min, $r_max, @args); - if (!@args) { - print commit_log_separator unless $incremental || $oneline; - return; - } - my $log = command_output_pipe(@args); - run_pager(); - my (@k, $c, $d, $stat); - my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/; - while (<$log>) { - if (/^${esc_color}commit (?:- )?($::sha1_short)/o) { - my $cmt = $1; - if ($c && cmt_showable($c) && $c->{r} != $r_last) { - $r_last = $c->{r}; - process_commit($c, $r_min, $r_max, \@k) or - goto out; - } - $d = undef; - $c = { c => $cmt }; - } elsif (/^${esc_color}author (.+) (\d+) ([\-\+]?\d+)$/o) { - get_author_info($c, $1, $2, $3); - } elsif (/^${esc_color}(?:tree|parent|committer) /o) { - # ignore - } elsif (/^${esc_color}:\d{6} \d{6} $::sha1_short/o) { - push @{$c->{raw}}, $_; - } elsif (/^${esc_color}[ACRMDT]\t/) { - # we could add $SVN->{svn_path} here, but that requires - # remote access at the moment (repo_path_split)... - s#^(${esc_color})([ACRMDT])\t#$1 $2 #o; - push @{$c->{changed}}, $_; - } elsif (/^${esc_color}diff /o) { - $d = 1; - push @{$c->{diff}}, $_; - } elsif ($d) { - push @{$c->{diff}}, $_; - } elsif (/^\ .+\ \|\s*\d+\ $esc_color[\+\-]* - $esc_color*[\+\-]*$esc_color$/x) { - $stat = 1; - push @{$c->{stat}}, $_; - } elsif ($stat && /^ \d+ files changed, \d+ insertions/) { - push @{$c->{stat}}, $_; - $stat = undef; - } elsif (/^${esc_color} (git-svn-id:.+)$/o) { - ($c->{url}, $c->{r}, undef) = ::extract_metadata($1); - } elsif (s/^${esc_color} //o) { - push @{$c->{l}}, $_; - } - } - if ($c && defined $c->{r} && $c->{r} != $r_last) { - $r_last = $c->{r}; - process_commit($c, $r_min, $r_max, \@k); - } - if (@k) { - ($r_min, $r_max) = ($r_max, $r_min); - process_commit($_, $r_min, $r_max) foreach reverse @k; - } -out: - close $log; - print commit_log_separator unless $incremental || $oneline; -} - -sub cmd_blame { - my $path = pop; - - config_pager(); - run_pager(); - - my ($fh, $ctx, $rev); - - if ($_git_format) { - ($fh, $ctx) = command_output_pipe('blame', @_, $path); - while (my $line = <$fh>) { - if ($line =~ /^\^?([[:xdigit:]]+)\s/) { - # Uncommitted edits show up as a rev ID of - # all zeros, which we can't look up with - # cmt_metadata - if ($1 !~ /^0+$/) { - (undef, $rev, undef) = - ::cmt_metadata($1); - $rev = '0' if (!$rev); - } else { - $rev = '0'; - } - $rev = sprintf('%-10s', $rev); - $line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/; - } - print $line; - } - } else { - ($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD', - '--', $path); - my ($sha1); - my %authors; - my @buffer; - my %dsha; #distinct sha keys - - while (my $line = <$fh>) { - push @buffer, $line; - if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) { - $dsha{$1} = 1; - } - } - - my $s2r = ::cmt_sha2rev_batch([keys %dsha]); - - foreach my $line (@buffer) { - if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) { - $rev = $s2r->{$1}; - $rev = '0' if (!$rev) - } - elsif ($line =~ /^author (.*)/) { - $authors{$rev} = $1; - $authors{$rev} =~ s/\s/_/g; - } - elsif ($line =~ /^\t(.*)$/) { - printf("%6s %10s %s\n", $rev, $authors{$rev}, $1); - } - } - } - command_close_pipe($fh, $ctx); -} - -package Git::SVN::Migration; -# these version numbers do NOT correspond to actual version numbers -# of git nor git-svn. They are just relative. -# -# v0 layout: .git/$id/info/url, refs/heads/$id-HEAD -# -# v1 layout: .git/$id/info/url, refs/remotes/$id -# -# v2 layout: .git/svn/$id/info/url, refs/remotes/$id -# -# v3 layout: .git/svn/$id, refs/remotes/$id -# - info/url may remain for backwards compatibility -# - this is what we migrate up to this layout automatically, -# - this will be used by git svn init on single branches -# v3.1 layout (auto migrated): -# - .rev_db => .rev_db.$UUID, .rev_db will remain as a symlink -# for backwards compatibility -# -# v4 layout: .git/svn/$repo_id/$id, refs/remotes/$repo_id/$id -# - this is only created for newly multi-init-ed -# repositories. Similar in spirit to the -# --use-separate-remotes option in git-clone (now default) -# - we do not automatically migrate to this (following -# the example set by core git) -# -# v5 layout: .rev_db.$UUID => .rev_map.$UUID -# - newer, more-efficient format that uses 24-bytes per record -# with no filler space. -# - use xxd -c24 < .rev_map.$UUID to view and debug -# - This is a one-way migration, repositories updated to the -# new format will not be able to use old git-svn without -# rebuilding the .rev_db. Rebuilding the rev_db is not -# possible if noMetadata or useSvmProps are set; but should -# be no problem for users that use the (sensible) defaults. -use strict; -use warnings; -use Carp qw/croak/; -use File::Path qw/mkpath/; -use File::Basename qw/dirname basename/; -use vars qw/$_minimize/; - -sub migrate_from_v0 { - my $git_dir = $ENV{GIT_DIR}; - return undef unless -d $git_dir; - my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/); - my $migrated = 0; - while (<$fh>) { - chomp; - my ($id, $orig_ref) = ($_, $_); - next unless $id =~ s#^refs/heads/(.+)-HEAD$#$1#; - next unless -f "$git_dir/$id/info/url"; - my $new_ref = "refs/remotes/$id"; - if (::verify_ref("$new_ref^0")) { - print STDERR "W: $orig_ref is probably an old ", - "branch used by an ancient version of ", - "git-svn.\n", - "However, $new_ref also exists.\n", - "We will not be able ", - "to use this branch until this ", - "ambiguity is resolved.\n"; - next; - } - print STDERR "Migrating from v0 layout...\n" if !$migrated; - print STDERR "Renaming ref: $orig_ref => $new_ref\n"; - command_noisy('update-ref', $new_ref, $orig_ref); - command_noisy('update-ref', '-d', $orig_ref, $orig_ref); - $migrated++; - } - command_close_pipe($fh, $ctx); - print STDERR "Done migrating from v0 layout...\n" if $migrated; - $migrated; -} - -sub migrate_from_v1 { - my $git_dir = $ENV{GIT_DIR}; - my $migrated = 0; - return $migrated unless -d $git_dir; - my $svn_dir = "$git_dir/svn"; - - # just in case somebody used 'svn' as their $id at some point... - return $migrated if -d $svn_dir && ! -f "$svn_dir/info/url"; - - print STDERR "Migrating from a git-svn v1 layout...\n"; - mkpath([$svn_dir]); - print STDERR "Data from a previous version of git-svn exists, but\n\t", - "$svn_dir\n\t(required for this version ", - "($::VERSION) of git-svn) does not exist.\n"; - my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/); - while (<$fh>) { - my $x = $_; - next unless $x =~ s#^refs/remotes/##; - chomp $x; - next unless -f "$git_dir/$x/info/url"; - my $u = eval { ::file_to_s("$git_dir/$x/info/url") }; - next unless $u; - my $dn = dirname("$git_dir/svn/$x"); - mkpath([$dn]) unless -d $dn; - if ($x eq 'svn') { # they used 'svn' as GIT_SVN_ID: - mkpath(["$git_dir/svn/svn"]); - print STDERR " - $git_dir/$x/info => ", - "$git_dir/svn/$x/info\n"; - rename "$git_dir/$x/info", "$git_dir/svn/$x/info" or - croak "$!: $x"; - # don't worry too much about these, they probably - # don't exist with repos this old (save for index, - # and we can easily regenerate that) - foreach my $f (qw/unhandled.log index .rev_db/) { - rename "$git_dir/$x/$f", "$git_dir/svn/$x/$f"; - } - } else { - print STDERR " - $git_dir/$x => $git_dir/svn/$x\n"; - rename "$git_dir/$x", "$git_dir/svn/$x" or - croak "$!: $x"; - } - $migrated++; - } - command_close_pipe($fh, $ctx); - print STDERR "Done migrating from a git-svn v1 layout\n"; - $migrated; -} - -sub read_old_urls { - my ($l_map, $pfx, $path) = @_; - my @dir; - foreach (<$path/*>) { - if (-r "$_/info/url") { - $pfx .= '/' if $pfx && $pfx !~ m!/$!; - my $ref_id = $pfx . basename $_; - my $url = ::file_to_s("$_/info/url"); - $l_map->{$ref_id} = $url; - } elsif (-d $_) { - push @dir, $_; - } - } - foreach (@dir) { - my $x = $_; - $x =~ s!^\Q$ENV{GIT_DIR}\E/svn/!!o; - read_old_urls($l_map, $x, $_); - } -} - -sub migrate_from_v2 { - my @cfg = command(qw/config -l/); - return if grep /^svn-remote\..+\.url=/, @cfg; - my %l_map; - read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn"); - my $migrated = 0; - - foreach my $ref_id (sort keys %l_map) { - eval { Git::SVN->init($l_map{$ref_id}, '', undef, $ref_id) }; - if ($@) { - Git::SVN->init($l_map{$ref_id}, '', $ref_id, $ref_id); - } - $migrated++; - } - $migrated; -} - -sub minimize_connections { - my $r = Git::SVN::read_all_remotes(); - my $new_urls = {}; - my $root_repos = {}; - foreach my $repo_id (keys %$r) { - my $url = $r->{$repo_id}->{url} or next; - my $fetch = $r->{$repo_id}->{fetch} or next; - my $ra = Git::SVN::Ra->new($url); - - # skip existing cases where we already connect to the root - if (($ra->{url} eq $ra->{repos_root}) || - ($ra->{repos_root} eq $repo_id)) { - $root_repos->{$ra->{url}} = $repo_id; - next; - } - - my $root_ra = Git::SVN::Ra->new($ra->{repos_root}); - my $root_path = $ra->{url}; - $root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##; - foreach my $path (keys %$fetch) { - my $ref_id = $fetch->{$path}; - my $gs = Git::SVN->new($ref_id, $repo_id, $path); - - # make sure we can read when connecting to - # a higher level of a repository - my ($last_rev, undef) = $gs->last_rev_commit; - if (!defined $last_rev) { - $last_rev = eval { - $root_ra->get_latest_revnum; - }; - next if $@; - } - my $new = $root_path; - $new .= length $path ? "/$path" : ''; - eval { - $root_ra->get_log([$new], $last_rev, $last_rev, - 0, 0, 1, sub { }); - }; - next if $@; - $new_urls->{$ra->{repos_root}}->{$new} = - { ref_id => $ref_id, - old_repo_id => $repo_id, - old_path => $path }; - } - } - - my @emptied; - foreach my $url (keys %$new_urls) { - # see if we can re-use an existing [svn-remote "repo_id"] - # instead of creating a(n ugly) new section: - my $repo_id = $root_repos->{$url} || $url; - - my $fetch = $new_urls->{$url}; - foreach my $path (keys %$fetch) { - my $x = $fetch->{$path}; - Git::SVN->init($url, $path, $repo_id, $x->{ref_id}); - my $pfx = "svn-remote.$x->{old_repo_id}"; - - my $old_fetch = quotemeta("$x->{old_path}:". - "$x->{ref_id}"); - command_noisy(qw/config --unset/, - "$pfx.fetch", '^'. $old_fetch . '$'); - delete $r->{$x->{old_repo_id}}-> - {fetch}->{$x->{old_path}}; - if (!keys %{$r->{$x->{old_repo_id}}->{fetch}}) { - command_noisy(qw/config --unset/, - "$pfx.url"); - push @emptied, $x->{old_repo_id} - } - } - } - if (@emptied) { - my $file = $ENV{GIT_CONFIG} || "$ENV{GIT_DIR}/config"; - print STDERR <<EOF; -The following [svn-remote] sections in your config file ($file) are empty -and can be safely removed: -EOF - print STDERR "[svn-remote \"$_\"]\n" foreach @emptied; - } -} - -sub migration_check { - migrate_from_v0(); - migrate_from_v1(); - migrate_from_v2(); - minimize_connections() if $_minimize; -} - -package Git::IndexInfo; -use strict; -use warnings; -use Git qw/command_input_pipe command_close_pipe/; - -sub new { - my ($class) = @_; - my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/); - bless { gui => $gui, ctx => $ctx, nr => 0}, $class; -} - -sub remove { - my ($self, $path) = @_; - if (print { $self->{gui} } '0 ', 0 x 40, "\t", $path, "\0") { - return ++$self->{nr}; - } - undef; -} - -sub update { - my ($self, $mode, $hash, $path) = @_; - if (print { $self->{gui} } $mode, ' ', $hash, "\t", $path, "\0") { - return ++$self->{nr}; - } - undef; -} - -sub DESTROY { - my ($self) = @_; - command_close_pipe($self->{gui}, $self->{ctx}); -} - -package Git::SVN::GlobSpec; -use strict; -use warnings; - -sub new { - my ($class, $glob, $pattern_ok) = @_; - my $re = $glob; - $re =~ s!/+$!!g; # no need for trailing slashes - my (@left, @right, @patterns); - my $state = "left"; - my $die_msg = "Only one set of wildcard directories " . - "(e.g. '*' or '*/*/*') is supported: '$glob'\n"; - for my $part (split(m|/|, $glob)) { - if ($part =~ /\*/ && $part ne "*") { - die "Invalid pattern in '$glob': $part\n"; - } elsif ($pattern_ok && $part =~ /[{}]/ && - $part !~ /^\{[^{}]+\}/) { - die "Invalid pattern in '$glob': $part\n"; - } - if ($part eq "*") { - die $die_msg if $state eq "right"; - $state = "pattern"; - push(@patterns, "[^/]*"); - } elsif ($pattern_ok && $part =~ /^\{(.*)\}$/) { - die $die_msg if $state eq "right"; - $state = "pattern"; - my $p = quotemeta($1); - $p =~ s/\\,/|/g; - push(@patterns, "(?:$p)"); - } else { - if ($state eq "left") { - push(@left, $part); - } else { - push(@right, $part); - $state = "right"; - } - } - } - my $depth = @patterns; - if ($depth == 0) { - die "One '*' is needed in glob: '$glob'\n"; - } - my $left = join('/', @left); - my $right = join('/', @right); - $re = join('/', @patterns); - $re = join('\/', - grep(length, quotemeta($left), "($re)", quotemeta($right))); - my $left_re = qr/^\/\Q$left\E(\/|$)/; - bless { left => $left, right => $right, left_regex => $left_re, - regex => qr/$re/, glob => $glob, depth => $depth }, $class; -} - -sub full_path { - my ($self, $path) = @_; - return (length $self->{left} ? "$self->{left}/" : '') . - $path . (length $self->{right} ? "/$self->{right}" : ''); -} - __END__ Data structures: @@ -17,39 +17,6 @@ const char git_more_info_string[] = static struct startup_info git_startup_info; static int use_pager = -1; -struct pager_config { - const char *cmd; - int want; - char *value; -}; - -static int pager_command_config(const char *var, const char *value, void *data) -{ - struct pager_config *c = data; - if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd)) { - int b = git_config_maybe_bool(var, value); - if (b >= 0) - c->want = b; - else { - c->want = 1; - c->value = xstrdup(value); - } - } - return 0; -} - -/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */ -int check_pager_config(const char *cmd) -{ - struct pager_config c; - c.cmd = cmd; - c.want = -1; - c.value = NULL; - git_config(pager_command_config, &c); - if (c.value) - pager_program = c.value; - return c.want; -} static void commit_pager_choice(void) { switch (use_pager) { @@ -256,8 +223,6 @@ static int handle_alias(int *argcp, const char ***argv) return ret; } -const char git_version_string[] = GIT_VERSION; - #define RUN_SETUP (1<<0) #define RUN_SETUP_GENTLY (1<<1) #define USE_PAGER (1<<2) @@ -353,6 +318,7 @@ static void handle_internal_command(int argc, const char **argv) { "commit-tree", cmd_commit_tree, RUN_SETUP }, { "config", cmd_config, RUN_SETUP_GENTLY }, { "count-objects", cmd_count_objects, RUN_SETUP }, + { "credential", cmd_credential, RUN_SETUP_GENTLY }, { "describe", cmd_describe, RUN_SETUP }, { "diff", cmd_diff }, { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE }, diff --git a/gitk-git/gitk b/gitk-git/gitk index 6f24f53d2..d93bd990a 100755 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -11533,6 +11533,11 @@ if {[catch {package require Tk 8.4} err]} { exit 1 } +# Unset GIT_TRACE var if set +if { [info exists ::env(GIT_TRACE)] } { + unset ::env(GIT_TRACE) +} + # defaults... set wrcomcmd "git diff-tree --stdin -p --pretty" diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index a40ed0ceb..c6bafe6ea 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -270,16 +270,15 @@ our %highlight_basename = ( our %highlight_ext = ( # main extensions, defining name of syntax; # see files in /usr/share/highlight/langDefs/ directory - map { $_ => $_ } - qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl sql make), + (map { $_ => $_ } qw(py rb java css js tex bib xml awk bat ini spec tcl sql)), # alternate extensions, see /etc/highlight/filetypes.conf - 'h' => 'c', - map { $_ => 'sh' } qw(bash zsh ksh), - map { $_ => 'cpp' } qw(cxx c++ cc), - map { $_ => 'php' } qw(php3 php4 php5 phps), - map { $_ => 'pl' } qw(perl pm), # perhaps also 'cgi' - map { $_ => 'make'} qw(mak mk), - map { $_ => 'xml' } qw(xhtml html htm), + (map { $_ => 'c' } qw(c h)), + (map { $_ => 'sh' } qw(sh bash zsh ksh)), + (map { $_ => 'cpp' } qw(cpp cxx c++ cc)), + (map { $_ => 'php' } qw(php php3 php4 php5 phps)), + (map { $_ => 'pl' } qw(pl perl pm)), # perhaps also 'cgi' + (map { $_ => 'make'} qw(make mak mk)), + (map { $_ => 'xml' } qw(xml xhtml html htm)), ); # You define site-wide feature defaults here; override them with @@ -541,7 +540,7 @@ our %feature = ( # $feature{'remote_heads'}{'default'} = [1]; # To have project specific config enable override in $GITWEB_CONFIG # $feature{'remote_heads'}{'override'} = 1; - # and in project config gitweb.remote_heads = 0|1; + # and in project config gitweb.remoteheads = 0|1; 'remote_heads' => { 'sub' => sub { feature_bool('remote_heads', @_) }, 'override' => 0, @@ -1557,7 +1556,7 @@ sub sanitize { return undef unless defined $str; $str = to_utf8($str); - $str =~ s|([[:cntrl:]])|($1 =~ /[\t\n\r]/ ? $1 : quot_cec($1))|eg; + $str =~ s|([[:cntrl:]])|(index("\t\n\r", $1) != -1 ? $1 : quot_cec($1))|eg; return $str; } @@ -2697,12 +2696,15 @@ sub git_get_project_config { # only subsection, if exists, is case sensitive, # and not lowercased by 'git config -z -l' if (my ($hi, $mi, $lo) = ($key =~ /^([^.]*)\.(.*)\.([^.]*)$/)) { + $lo =~ s/_//g; $key = join(".", lc($hi), $mi, lc($lo)); + return if ($lo =~ /\W/ || $hi =~ /\W/); } else { $key = lc($key); + $key =~ s/_//g; + return if ($key =~ /\W/); } $key =~ s/^gitweb\.//; - return if ($key =~ m/\W/); # type sanity check if (defined $type) { @@ -4489,30 +4491,33 @@ sub git_print_log { } # print log - my $signoff = 0; - my $empty = 0; + my $skip_blank_line = 0; foreach my $line (@$log) { - if ($line =~ m/^ *(signed[ \-]off[ \-]by[ :]|acked[ \-]by[ :]|cc[ :])/i) { - $signoff = 1; - $empty = 0; + if ($line =~ m/^\s*([A-Z][-A-Za-z]*-[Bb]y|C[Cc]): /) { if (! $opts{'-remove_signoff'}) { print "<span class=\"signoff\">" . esc_html($line) . "</span><br/>\n"; - next; - } else { - # remove signoff lines - next; + $skip_blank_line = 1; } - } else { - $signoff = 0; + next; + } + + if ($line =~ m,\s*([a-z]*link): (https?://\S+),i) { + if (! $opts{'-remove_signoff'}) { + print "<span class=\"signoff\">" . esc_html($1) . ": " . + "<a href=\"" . esc_html($2) . "\">" . esc_html($2) . "</a>" . + "</span><br/>\n"; + $skip_blank_line = 1; + } + next; } # print only one empty line # do not print empty line after signoff if ($line eq "") { - next if ($empty || $signoff); - $empty = 1; + next if ($skip_blank_line); + $skip_blank_line = 1; } else { - $empty = 0; + $skip_blank_line = 0; } print format_log_line_html($line) . "<br/>\n"; @@ -4520,7 +4525,7 @@ sub git_print_log { if ($opts{'-final_empty_line'}) { # end with single empty line - print "<br/>\n" unless $empty; + print "<br/>\n" unless $skip_blank_line; } } @@ -5523,23 +5528,30 @@ sub fill_project_list_info { sub sort_projects_list { my ($projlist, $order) = @_; - my @projects; - my %order_info = ( - project => { key => 'path', type => 'str' }, - descr => { key => 'descr_long', type => 'str' }, - owner => { key => 'owner', type => 'str' }, - age => { key => 'age', type => 'num' } - ); - my $oi = $order_info{$order}; - return @$projlist unless defined $oi; - if ($oi->{'type'} eq 'str') { - @projects = sort {$a->{$oi->{'key'}} cmp $b->{$oi->{'key'}}} @$projlist; - } else { - @projects = sort {$a->{$oi->{'key'}} <=> $b->{$oi->{'key'}}} @$projlist; + sub order_str { + my $key = shift; + return sub { $a->{$key} cmp $b->{$key} }; } - return @projects; + sub order_num_then_undef { + my $key = shift; + return sub { + defined $a->{$key} ? + (defined $b->{$key} ? $a->{$key} <=> $b->{$key} : -1) : + (defined $b->{$key} ? 1 : 0) + }; + } + + my %orderings = ( + project => order_str('path'), + descr => order_str('descr_long'), + owner => order_str('owner'), + age => order_num_then_undef('age'), + ); + + my $ordering = $orderings{$order}; + return defined $ordering ? sort $ordering @$projlist : @$projlist; } # returns a hash of categories, containing the list of project @@ -8025,7 +8037,7 @@ sub git_feed { %latest_commit = %{$commitlist[0]}; my $latest_epoch = $latest_commit{'committer_epoch'}; exit_if_unmodified_since($latest_epoch); - %latest_date = parse_date($latest_epoch, $latest_commit{'comitter_tz'}); + %latest_date = parse_date($latest_epoch, $latest_commit{'committer_tz'}); } print $cgi->header( -type => $content_type, @@ -8052,6 +8064,7 @@ sub git_feed { $feed_type = 'history'; } $title .= " $feed_type"; + $title = esc_html($title); my $descr = git_get_project_description($project); if (defined $descr) { $descr = esc_html($descr); @@ -8,6 +8,34 @@ /* Internal API */ /* + * Output the next line for a graph. + * This formats the next graph line into the specified strbuf. It is not + * terminated with a newline. + * + * Returns 1 if the line includes the current commit, and 0 otherwise. + * graph_next_line() will return 1 exactly once for each time + * graph_update() is called. + */ +static int graph_next_line(struct git_graph *graph, struct strbuf *sb); + +/* + * Set up a custom scheme for column colors. + * + * The default column color scheme inserts ANSI color escapes to colorize + * the graph. The various color escapes are stored in an array of strings + * where each entry corresponds to a color, except for the last entry, + * which denotes the escape for resetting the color back to the default. + * When generating the graph, strings from this array are inserted before + * and after the various column characters. + * + * This function allows you to enable a custom array of color escapes. + * The 'colors_max' argument is the index of the last "reset" entry. + * + * This functions must be called BEFORE graph_init() is called. + */ +static void graph_set_column_colors(const char **colors, unsigned short colors_max); + +/* * Output a padding line in the graph. * This is similar to graph_next_line(). However, it is guaranteed to * never print the current commit line. Instead, if the commit line is @@ -62,7 +90,7 @@ enum graph_state { static const char **column_colors; static unsigned short column_colors_max; -void graph_set_column_colors(const char **colors, unsigned short colors_max) +static void graph_set_column_colors(const char **colors, unsigned short colors_max) { column_colors = colors; column_colors_max = colors_max; @@ -1116,7 +1144,7 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct strbuf graph_update_state(graph, GRAPH_PADDING); } -int graph_next_line(struct git_graph *graph, struct strbuf *sb) +static int graph_next_line(struct git_graph *graph, struct strbuf *sb) { switch (graph->state) { case GRAPH_PADDING: @@ -1199,7 +1227,7 @@ void graph_show_commit(struct git_graph *graph) if (!graph) return; - while (!shown_commit_line) { + while (!shown_commit_line && !graph_is_commit_finished(graph)) { shown_commit_line = graph_next_line(graph, &msgbuf); fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); if (!shown_commit_line) @@ -4,22 +4,6 @@ /* A graph is a pointer to this opaque structure */ struct git_graph; -/* - * Set up a custom scheme for column colors. - * - * The default column color scheme inserts ANSI color escapes to colorize - * the graph. The various color escapes are stored in an array of strings - * where each entry corresponds to a color, except for the last entry, - * which denotes the escape for resetting the color back to the default. - * When generating the graph, strings from this array are inserted before - * and after the various column characters. - * - * This function allows you to enable a custom array of color escapes. - * The 'colors_max' argument is the index of the last "reset" entry. - * - * This functions must be called BEFORE graph_init() is called. - */ -void graph_set_column_colors(const char **colors, unsigned short colors_max); /* * Create a new struct git_graph. @@ -49,17 +33,6 @@ void graph_update(struct git_graph *graph, struct commit *commit); */ int graph_is_commit_finished(struct git_graph const *graph); -/* - * Output the next line for a graph. - * This formats the next graph line into the specified strbuf. It is not - * terminated with a newline. - * - * Returns 1 if the line includes the current commit, and 0 otherwise. - * graph_next_line() will return 1 exactly once for each time - * graph_update() is called. - */ -int graph_next_line(struct git_graph *graph, struct strbuf *sb); - /* * graph_show_*: helper functions for printing to stdout @@ -3,6 +3,187 @@ #include "userdiff.h" #include "xdiff-interface.h" +static int grep_source_load(struct grep_source *gs); +static int grep_source_is_binary(struct grep_source *gs); + +static struct grep_opt grep_defaults; + +/* + * Initialize the grep_defaults template with hardcoded defaults. + * We could let the compiler do this, but without C99 initializers + * the code gets unwieldy and unreadable, so... + */ +void init_grep_defaults(void) +{ + struct grep_opt *opt = &grep_defaults; + static int run_once; + + if (run_once) + return; + run_once++; + + memset(opt, 0, sizeof(*opt)); + opt->relative = 1; + opt->pathname = 1; + opt->regflags = REG_NEWLINE; + opt->max_depth = -1; + opt->pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED; + opt->extended_regexp_option = 0; + strcpy(opt->color_context, ""); + strcpy(opt->color_filename, ""); + strcpy(opt->color_function, ""); + strcpy(opt->color_lineno, ""); + strcpy(opt->color_match, GIT_COLOR_BOLD_RED); + strcpy(opt->color_selected, ""); + strcpy(opt->color_sep, GIT_COLOR_CYAN); + opt->color = -1; +} + +static int parse_pattern_type_arg(const char *opt, const char *arg) +{ + if (!strcmp(arg, "default")) + return GREP_PATTERN_TYPE_UNSPECIFIED; + else if (!strcmp(arg, "basic")) + return GREP_PATTERN_TYPE_BRE; + else if (!strcmp(arg, "extended")) + return GREP_PATTERN_TYPE_ERE; + else if (!strcmp(arg, "fixed")) + return GREP_PATTERN_TYPE_FIXED; + else if (!strcmp(arg, "perl")) + return GREP_PATTERN_TYPE_PCRE; + die("bad %s argument: %s", opt, arg); +} + +/* + * Read the configuration file once and store it in + * the grep_defaults template. + */ +int grep_config(const char *var, const char *value, void *cb) +{ + struct grep_opt *opt = &grep_defaults; + char *color = NULL; + + if (userdiff_config(var, value) < 0) + return -1; + + if (!strcmp(var, "grep.extendedregexp")) { + if (git_config_bool(var, value)) + opt->extended_regexp_option = 1; + else + opt->extended_regexp_option = 0; + return 0; + } + + if (!strcmp(var, "grep.patterntype")) { + opt->pattern_type_option = parse_pattern_type_arg(var, value); + return 0; + } + + if (!strcmp(var, "grep.linenumber")) { + opt->linenum = git_config_bool(var, value); + return 0; + } + + if (!strcmp(var, "color.grep")) + opt->color = git_config_colorbool(var, value); + else if (!strcmp(var, "color.grep.context")) + color = opt->color_context; + else if (!strcmp(var, "color.grep.filename")) + color = opt->color_filename; + else if (!strcmp(var, "color.grep.function")) + color = opt->color_function; + else if (!strcmp(var, "color.grep.linenumber")) + color = opt->color_lineno; + else if (!strcmp(var, "color.grep.match")) + color = opt->color_match; + else if (!strcmp(var, "color.grep.selected")) + color = opt->color_selected; + else if (!strcmp(var, "color.grep.separator")) + color = opt->color_sep; + + if (color) { + if (!value) + return config_error_nonbool(var); + color_parse(value, var, color); + } + return 0; +} + +/* + * Initialize one instance of grep_opt and copy the + * default values from the template we read the configuration + * information in an earlier call to git_config(grep_config). + */ +void grep_init(struct grep_opt *opt, const char *prefix) +{ + struct grep_opt *def = &grep_defaults; + + memset(opt, 0, sizeof(*opt)); + opt->prefix = prefix; + opt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0; + opt->pattern_tail = &opt->pattern_list; + opt->header_tail = &opt->header_list; + + opt->color = def->color; + opt->extended_regexp_option = def->extended_regexp_option; + opt->pattern_type_option = def->pattern_type_option; + opt->linenum = def->linenum; + opt->max_depth = def->max_depth; + opt->pathname = def->pathname; + opt->regflags = def->regflags; + opt->relative = def->relative; + + strcpy(opt->color_context, def->color_context); + strcpy(opt->color_filename, def->color_filename); + strcpy(opt->color_function, def->color_function); + strcpy(opt->color_lineno, def->color_lineno); + strcpy(opt->color_match, def->color_match); + strcpy(opt->color_selected, def->color_selected); + strcpy(opt->color_sep, def->color_sep); +} + +void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt) +{ + if (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED) + grep_set_pattern_type_option(pattern_type, opt); + else if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED) + grep_set_pattern_type_option(opt->pattern_type_option, opt); + else if (opt->extended_regexp_option) + grep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt); +} + +void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt) +{ + switch (pattern_type) { + case GREP_PATTERN_TYPE_UNSPECIFIED: + /* fall through */ + + case GREP_PATTERN_TYPE_BRE: + opt->fixed = 0; + opt->pcre = 0; + opt->regflags &= ~REG_EXTENDED; + break; + + case GREP_PATTERN_TYPE_ERE: + opt->fixed = 0; + opt->pcre = 0; + opt->regflags |= REG_EXTENDED; + break; + + case GREP_PATTERN_TYPE_FIXED: + opt->fixed = 1; + opt->pcre = 0; + opt->regflags &= ~REG_EXTENDED; + break; + + case GREP_PATTERN_TYPE_PCRE: + opt->fixed = 0; + opt->pcre = 1; + opt->regflags &= ~REG_EXTENDED; + break; + } +} + static struct grep_pat *create_grep_pat(const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t, @@ -60,6 +241,8 @@ void append_header_grep_pattern(struct grep_opt *opt, { struct grep_pat *p = create_grep_pat(pat, strlen(pat), "header", 0, GREP_PATTERN_HEAD, field); + if (field == GREP_HEADER_REFLOG) + opt->use_reflog_filter = 1; do_append_grep_pat(&opt->header_tail, p); } @@ -332,6 +515,87 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list) return compile_pattern_or(list); } +static void indent(int in) +{ + while (in-- > 0) + fputc(' ', stderr); +} + +static void dump_grep_pat(struct grep_pat *p) +{ + switch (p->token) { + case GREP_AND: fprintf(stderr, "*and*"); break; + case GREP_OPEN_PAREN: fprintf(stderr, "*(*"); break; + case GREP_CLOSE_PAREN: fprintf(stderr, "*)*"); break; + case GREP_NOT: fprintf(stderr, "*not*"); break; + case GREP_OR: fprintf(stderr, "*or*"); break; + + case GREP_PATTERN: fprintf(stderr, "pattern"); break; + case GREP_PATTERN_HEAD: fprintf(stderr, "pattern_head"); break; + case GREP_PATTERN_BODY: fprintf(stderr, "pattern_body"); break; + } + + switch (p->token) { + default: break; + case GREP_PATTERN_HEAD: + fprintf(stderr, "<head %d>", p->field); break; + case GREP_PATTERN_BODY: + fprintf(stderr, "<body>"); break; + } + switch (p->token) { + default: break; + case GREP_PATTERN_HEAD: + case GREP_PATTERN_BODY: + case GREP_PATTERN: + fprintf(stderr, "%.*s", (int)p->patternlen, p->pattern); + break; + } + fputc('\n', stderr); +} + +static void dump_grep_expression_1(struct grep_expr *x, int in) +{ + indent(in); + switch (x->node) { + case GREP_NODE_TRUE: + fprintf(stderr, "true\n"); + break; + case GREP_NODE_ATOM: + dump_grep_pat(x->u.atom); + break; + case GREP_NODE_NOT: + fprintf(stderr, "(not\n"); + dump_grep_expression_1(x->u.unary, in+1); + indent(in); + fprintf(stderr, ")\n"); + break; + case GREP_NODE_AND: + fprintf(stderr, "(and\n"); + dump_grep_expression_1(x->u.binary.left, in+1); + dump_grep_expression_1(x->u.binary.right, in+1); + indent(in); + fprintf(stderr, ")\n"); + break; + case GREP_NODE_OR: + fprintf(stderr, "(or\n"); + dump_grep_expression_1(x->u.binary.left, in+1); + dump_grep_expression_1(x->u.binary.right, in+1); + indent(in); + fprintf(stderr, ")\n"); + break; + } +} + +static void dump_grep_expression(struct grep_opt *opt) +{ + struct grep_expr *x = opt->pattern_expression; + + if (opt->all_match) + fprintf(stderr, "[all-match]\n"); + dump_grep_expression_1(x, 0); + fflush(NULL); +} + static struct grep_expr *grep_true_expr(void) { struct grep_expr *z = xcalloc(1, sizeof(*z)); @@ -395,7 +659,23 @@ static struct grep_expr *prep_header_patterns(struct grep_opt *opt) return header_expr; } -void compile_grep_patterns(struct grep_opt *opt) +static struct grep_expr *grep_splice_or(struct grep_expr *x, struct grep_expr *y) +{ + struct grep_expr *z = x; + + while (x) { + assert(x->node == GREP_NODE_OR); + if (x->u.binary.right && + x->u.binary.right->node == GREP_NODE_TRUE) { + x->u.binary.right = y; + break; + } + x = x->u.binary.right; + } + return z; +} + +static void compile_grep_patterns_real(struct grep_opt *opt) { struct grep_pat *p; struct grep_expr *header_expr = prep_header_patterns(opt); @@ -415,7 +695,7 @@ void compile_grep_patterns(struct grep_opt *opt) if (opt->all_match || header_expr) opt->extended = 1; - else if (!opt->extended) + else if (!opt->extended && !opt->debug) return; p = opt->pattern_list; @@ -429,12 +709,22 @@ void compile_grep_patterns(struct grep_opt *opt) if (!opt->pattern_expression) opt->pattern_expression = header_expr; + else if (opt->all_match) + opt->pattern_expression = grep_splice_or(header_expr, + opt->pattern_expression); else opt->pattern_expression = grep_or_expr(opt->pattern_expression, header_expr); opt->all_match = 1; } +void compile_grep_patterns(struct grep_opt *opt) +{ + compile_grep_patterns_real(opt); + if (opt->debug) + dump_grep_expression(opt); +} + static void free_pattern_expr(struct grep_expr *x) { switch (x->node) { @@ -586,6 +876,7 @@ static struct { } header_field[] = { { "author ", 7 }, { "committer ", 10 }, + { "reflog ", 7 }, }; static int match_one_pattern(struct grep_pat *p, char *bol, char *eol, @@ -609,7 +900,14 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol, if (strncmp(bol, field, len)) return 0; bol += len; - saved_ch = strip_timestamp(bol, &eol); + switch (p->field) { + case GREP_HEADER_AUTHOR: + case GREP_HEADER_COMMITTER: + saved_ch = strip_timestamp(bol, &eol); + break; + default: + break; + } } again: @@ -1252,7 +1550,7 @@ int grep_buffer(struct grep_opt *opt, char *buf, unsigned long size) struct grep_source gs; int r; - grep_source_init(&gs, GREP_SOURCE_BUF, NULL, NULL); + grep_source_init(&gs, GREP_SOURCE_BUF, NULL, NULL, NULL); gs.buf = buf; gs.size = size; @@ -1263,10 +1561,12 @@ int grep_buffer(struct grep_opt *opt, char *buf, unsigned long size) } void grep_source_init(struct grep_source *gs, enum grep_source_type type, - const char *name, const void *identifier) + const char *name, const char *path, + const void *identifier) { gs->type = type; gs->name = name ? xstrdup(name) : NULL; + gs->path = path ? xstrdup(path) : NULL; gs->buf = NULL; gs->size = 0; gs->driver = NULL; @@ -1288,6 +1588,8 @@ void grep_source_clear(struct grep_source *gs) { free(gs->name); gs->name = NULL; + free(gs->path); + gs->path = NULL; free(gs->identifier); gs->identifier = NULL; grep_source_clear_data(gs); @@ -1358,7 +1660,7 @@ static int grep_source_load_file(struct grep_source *gs) return 0; } -int grep_source_load(struct grep_source *gs) +static int grep_source_load(struct grep_source *gs) { if (gs->buf) return 0; @@ -1380,13 +1682,14 @@ void grep_source_load_driver(struct grep_source *gs) return; grep_attr_lock(); - gs->driver = userdiff_find_by_path(gs->name); + if (gs->path) + gs->driver = userdiff_find_by_path(gs->path); if (!gs->driver) gs->driver = userdiff_find_by_name("default"); grep_attr_unlock(); } -int grep_source_is_binary(struct grep_source *gs) +static int grep_source_is_binary(struct grep_source *gs) { grep_source_load_driver(gs); if (gs->driver->binary != -1) @@ -29,9 +29,12 @@ enum grep_context { enum grep_header_field { GREP_HEADER_AUTHOR = 0, - GREP_HEADER_COMMITTER + GREP_HEADER_COMMITTER, + GREP_HEADER_REFLOG, + + /* Must be at the end of the enum */ + GREP_HEADER_FIELD_MAX }; -#define GREP_HEADER_FIELD_MAX (GREP_HEADER_COMMITTER + 1) struct grep_pat { struct grep_pat *next; @@ -58,6 +61,14 @@ enum grep_expr_node { GREP_NODE_OR }; +enum grep_pattern_type { + GREP_PATTERN_TYPE_UNSPECIFIED = 0, + GREP_PATTERN_TYPE_BRE, + GREP_PATTERN_TYPE_ERE, + GREP_PATTERN_TYPE_FIXED, + GREP_PATTERN_TYPE_PCRE +}; + struct grep_expr { enum grep_expr_node node; unsigned hit; @@ -90,11 +101,13 @@ struct grep_opt { int word_regexp; int fixed; int all_match; + int debug; #define GREP_BINARY_DEFAULT 0 #define GREP_BINARY_NOMATCH 1 #define GREP_BINARY_TEXT 2 int binary; int extended; + int use_reflog_filter; int pcre; int relative; int pathname; @@ -103,6 +116,8 @@ struct grep_opt { int max_depth; int funcname; int funcbody; + int extended_regexp_option; + int pattern_type_option; char color_context[COLOR_MAXLEN]; char color_filename[COLOR_MAXLEN]; char color_function[COLOR_MAXLEN]; @@ -123,6 +138,12 @@ struct grep_opt { void *output_priv; }; +extern void init_grep_defaults(void); +extern int grep_config(const char *var, const char *value, void *); +extern void grep_init(struct grep_opt *, const char *prefix); +void grep_set_pattern_type_option(enum grep_pattern_type, struct grep_opt *opt); +void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt); + extern void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t); extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t); extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *); @@ -143,16 +164,17 @@ struct grep_source { char *buf; unsigned long size; + char *path; /* for attribute lookups */ struct userdiff_driver *driver; }; void grep_source_init(struct grep_source *gs, enum grep_source_type type, - const char *name, const void *identifier); -int grep_source_load(struct grep_source *gs); + const char *name, const char *path, + const void *identifier); void grep_source_clear_data(struct grep_source *gs); void grep_source_clear(struct grep_source *gs); void grep_source_load_driver(struct grep_source *gs); -int grep_source_is_binary(struct grep_source *gs); + int grep_source(struct grep_opt *opt, struct grep_source *gs); @@ -6,6 +6,7 @@ #include "common-cmds.h" #include "string-list.h" #include "column.h" +#include "version.h" void add_cmdname(struct cmdnames *cmds, const char *name, int len) { @@ -43,9 +44,12 @@ static void uniq(struct cmdnames *cmds) if (!cmds->cnt) return; - for (i = j = 1; i < cmds->cnt; i++) - if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name)) + for (i = j = 1; i < cmds->cnt; i++) { + if (!strcmp(cmds->names[i]->name, cmds->names[j-1]->name)) + free(cmds->names[i]); + else cmds->names[j++] = cmds->names[i]; + } cmds->cnt = j; } @@ -60,9 +64,10 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name); if (cmp < 0) cmds->names[cj++] = cmds->names[ci++]; - else if (cmp == 0) - ci++, ei++; - else if (cmp > 0) + else if (cmp == 0) { + ei++; + free(cmds->names[ci++]); + } else if (cmp > 0) ei++; } diff --git a/http-push.c b/http-push.c index a832ca77a..8701c1215 100644 --- a/http-push.c +++ b/http-push.c @@ -1610,9 +1610,8 @@ static int verify_merge_base(unsigned char *head_sha1, struct ref *remote) { struct commit *head = lookup_commit_or_die(head_sha1, "HEAD"); struct commit *branch = lookup_commit_or_die(remote->old_sha1, remote->name); - struct commit_list *merge_bases = get_merge_bases(head, branch, 1); - return (merge_bases && !merge_bases->next && merge_bases->item == branch); + return in_merge_bases(branch, head); } static int delete_remote_branch(const char *pattern, int force) diff --git a/http-walker.c b/http-walker.c index 51a906e9e..1516c5eb2 100644 --- a/http-walker.c +++ b/http-walker.c @@ -396,7 +396,7 @@ static int fetch_indices(struct walker *walker, struct alt_base *repo) return ret; } -static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1) +static int http_fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1) { struct packed_git *target; int ret; @@ -524,7 +524,7 @@ static int fetch(struct walker *walker, unsigned char *sha1) if (!fetch_object(walker, altbase, sha1)) return 0; while (altbase) { - if (!fetch_pack(walker, altbase, sha1)) + if (!http_fetch_pack(walker, altbase, sha1)) return 0; fetch_alternates(walker, data->alt->base); altbase = altbase->next; @@ -4,6 +4,7 @@ #include "run-command.h" #include "url.h" #include "credential.h" +#include "version.h" int active_requests; int http_is_verbose; @@ -235,6 +236,7 @@ static int has_cert_password(void) return 0; if (!cert_auth.password) { cert_auth.protocol = xstrdup("cert"); + cert_auth.username = xstrdup(""); cert_auth.path = xstrdup(ssl_cert); credential_fill(&cert_auth); } @@ -299,7 +301,7 @@ static CURL *get_curl_handle(void) curl_easy_setopt(result, CURLOPT_VERBOSE, 1); curl_easy_setopt(result, CURLOPT_USERAGENT, - user_agent ? user_agent : GIT_HTTP_USER_AGENT); + user_agent ? user_agent : git_user_agent()); if (curl_ftp_no_epsv) curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0); @@ -630,6 +632,18 @@ void run_active_slot(struct active_request_slot *slot) FD_ZERO(&excfds); curl_multi_fdset(curlm, &readfds, &writefds, &excfds, &max_fd); + /* + * It can happen that curl_multi_timeout returns a pathologically + * long timeout when curl_multi_fdset returns no file descriptors + * to read. See commit message for more details. + */ + if (max_fd < 0 && + (select_timeout.tv_sec > 0 || + select_timeout.tv_usec > 50000)) { + select_timeout.tv_sec = 0; + select_timeout.tv_usec = 50000; + } + select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout); } } @@ -744,10 +758,8 @@ char *get_remote_object_url(const char *url, const char *hex, return strbuf_detach(&buf, NULL); } -int handle_curl_result(struct active_request_slot *slot) +int handle_curl_result(struct slot_results *results) { - struct slot_results *results = slot->results; - if (results->curl_result == CURLE_OK) { credential_approve(&http_auth); return HTTP_OK; @@ -759,14 +771,15 @@ int handle_curl_result(struct active_request_slot *slot) return HTTP_NOAUTH; } else { credential_fill(&http_auth); - init_curl_http_auth(slot->curl); return HTTP_REAUTH; } } else { +#if LIBCURL_VERSION_NUM >= 0x070c00 if (!curl_errorstr[0]) strlcpy(curl_errorstr, curl_easy_strerror(results->curl_result), sizeof(curl_errorstr)); +#endif return HTTP_ERROR; } } @@ -815,10 +828,11 @@ static int http_request(const char *url, void *result, int target, int options) curl_easy_setopt(slot->curl, CURLOPT_URL, url); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "gzip"); if (start_active_slot(slot)) { run_active_slot(slot); - ret = handle_curl_result(slot); + ret = handle_curl_result(&results); } else { error("Unable to start HTTP request for %s", url); ret = HTTP_START_FAILED; @@ -78,7 +78,7 @@ extern int start_active_slot(struct active_request_slot *slot); extern void run_active_slot(struct active_request_slot *slot); extern void finish_active_slot(struct active_request_slot *slot); extern void finish_all_active_slots(void); -extern int handle_curl_result(struct active_request_slot *slot); +extern int handle_curl_result(struct slot_results *results); #ifdef USE_CURL_MULTI extern void fill_active_slots(void); @@ -10,7 +10,12 @@ static struct strbuf git_default_name = STRBUF_INIT; static struct strbuf git_default_email = STRBUF_INIT; static char git_default_date[50]; -int user_ident_explicitly_given; + +#define IDENT_NAME_GIVEN 01 +#define IDENT_MAIL_GIVEN 02 +#define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN) +static int committer_ident_explicitly_given; +static int author_ident_explicitly_given; #ifdef NO_GECOS_IN_PWENT #define get_gecos(ignored) "&" @@ -93,7 +98,7 @@ static void copy_email(const struct passwd *pw, struct strbuf *email) add_domainname(email); } -const char *ident_default_name(void) +static const char *ident_default_name(void) { if (!git_default_name.len) { copy_gecos(xgetpwuid_self(), &git_default_name); @@ -109,7 +114,8 @@ const char *ident_default_email(void) if (email && email[0]) { strbuf_addstr(&git_default_email, email); - user_ident_explicitly_given |= IDENT_MAIL_GIVEN; + committer_ident_explicitly_given |= IDENT_MAIL_GIVEN; + author_ident_explicitly_given |= IDENT_MAIL_GIVEN; } else copy_email(xgetpwuid_self(), &git_default_email); strbuf_trim(&git_default_email); @@ -117,7 +123,7 @@ const char *ident_default_email(void) return git_default_email.buf; } -const char *ident_default_date(void) +static const char *ident_default_date(void) { if (!git_default_date[0]) datestamp(git_default_date, sizeof(git_default_date)); @@ -327,6 +333,10 @@ const char *fmt_name(const char *name, const char *email) const char *git_author_info(int flag) { + if (getenv("GIT_AUTHOR_NAME")) + author_ident_explicitly_given |= IDENT_NAME_GIVEN; + if (getenv("GIT_AUTHOR_EMAIL")) + author_ident_explicitly_given |= IDENT_MAIL_GIVEN; return fmt_ident(getenv("GIT_AUTHOR_NAME"), getenv("GIT_AUTHOR_EMAIL"), getenv("GIT_AUTHOR_DATE"), @@ -336,16 +346,16 @@ const char *git_author_info(int flag) const char *git_committer_info(int flag) { if (getenv("GIT_COMMITTER_NAME")) - user_ident_explicitly_given |= IDENT_NAME_GIVEN; + committer_ident_explicitly_given |= IDENT_NAME_GIVEN; if (getenv("GIT_COMMITTER_EMAIL")) - user_ident_explicitly_given |= IDENT_MAIL_GIVEN; + committer_ident_explicitly_given |= IDENT_MAIL_GIVEN; return fmt_ident(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"), getenv("GIT_COMMITTER_DATE"), flag); } -int user_ident_sufficiently_given(void) +static int ident_is_sufficient(int user_ident_explicitly_given) { #ifndef WINDOWS return (user_ident_explicitly_given & IDENT_MAIL_GIVEN); @@ -354,6 +364,16 @@ int user_ident_sufficiently_given(void) #endif } +int committer_ident_sufficiently_given(void) +{ + return ident_is_sufficient(committer_ident_explicitly_given); +} + +int author_ident_sufficiently_given(void) +{ + return ident_is_sufficient(author_ident_explicitly_given); +} + int git_ident_config(const char *var, const char *value, void *data) { if (!strcmp(var, "user.name")) { @@ -361,7 +381,8 @@ int git_ident_config(const char *var, const char *value, void *data) return config_error_nonbool(var); strbuf_reset(&git_default_name); strbuf_addstr(&git_default_name, value); - user_ident_explicitly_given |= IDENT_NAME_GIVEN; + committer_ident_explicitly_given |= IDENT_NAME_GIVEN; + author_ident_explicitly_given |= IDENT_NAME_GIVEN; return 0; } @@ -370,7 +391,8 @@ int git_ident_config(const char *var, const char *value, void *data) return config_error_nonbool(var); strbuf_reset(&git_default_email); strbuf_addstr(&git_default_email, value); - user_ident_explicitly_given |= IDENT_MAIL_GIVEN; + committer_ident_explicitly_given |= IDENT_MAIL_GIVEN; + author_ident_explicitly_given |= IDENT_MAIL_GIVEN; return 0; } diff --git a/ll-merge.c b/ll-merge.c index f3f769215..acea33bf1 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -35,7 +35,7 @@ struct ll_merge_driver { */ static int ll_binary_merge(const struct ll_merge_driver *drv_unused, mmbuffer_t *result, - const char *path_unused, + const char *path, mmfile_t *orig, const char *orig_name, mmfile_t *src1, const char *name1, mmfile_t *src2, const char *name2, @@ -46,16 +46,34 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused, assert(opts); /* - * The tentative merge result is "ours" for the final round, - * or common ancestor for an internal merge. Still return - * "conflicted merge" status. + * The tentative merge result is the or common ancestor for an internal merge. */ - stolen = opts->virtual_ancestor ? orig : src1; + if (opts->virtual_ancestor) { + stolen = orig; + } else { + switch (opts->variant) { + default: + warning("Cannot merge binary files: %s (%s vs. %s)", + path, name1, name2); + /* fallthru */ + case XDL_MERGE_FAVOR_OURS: + stolen = src1; + break; + case XDL_MERGE_FAVOR_THEIRS: + stolen = src2; + break; + } + } result->ptr = stolen->ptr; result->size = stolen->size; stolen->ptr = NULL; - return 1; + + /* + * With -Xtheirs or -Xours, we have cleanly merged; + * otherwise we got a conflict. + */ + return (opts->variant ? 0 : 1); } static int ll_xdl_merge(const struct ll_merge_driver *drv_unused, @@ -73,8 +91,6 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused, if (buffer_is_binary(orig->ptr, orig->size) || buffer_is_binary(src1->ptr, src1->size) || buffer_is_binary(src2->ptr, src2->size)) { - warning("Cannot merge binary files: %s (%s vs. %s)", - path, name1, name2); return ll_binary_merge(drv_unused, result, path, orig, orig_name, diff --git a/log-tree.c b/log-tree.c index c894930c1..4f86defe3 100644 --- a/log-tree.c +++ b/log-tree.c @@ -540,7 +540,6 @@ void show_log(struct rev_info *opt) struct pretty_print_context ctx = {0}; opt->loginfo = NULL; - ctx.show_notes = opt->show_notes; if (!opt->verbose_header) { graph_show_commit(opt->graph); @@ -648,6 +647,18 @@ void show_log(struct rev_info *opt) if (!commit->buffer) return; + if (opt->show_notes) { + int raw; + struct strbuf notebuf = STRBUF_INIT; + + raw = (opt->commit_format == CMIT_FMT_USERFORMAT); + format_display_notes(commit->object.sha1, ¬ebuf, + get_log_output_encoding(), raw); + ctx.notes_message = notebuf.len + ? strbuf_detach(¬ebuf, NULL) + : xcalloc(1, 1); + } + /* * And then the pretty-printed message itself */ @@ -664,6 +675,16 @@ void show_log(struct rev_info *opt) if (opt->add_signoff) append_signoff(&msgbuf, opt->add_signoff); + + if ((ctx.fmt != CMIT_FMT_USERFORMAT) && + ctx.notes_message && *ctx.notes_message) { + if (ctx.fmt == CMIT_FMT_EMAIL) { + strbuf_addstr(&msgbuf, "---\n"); + opt->shown_dashes = 1; + } + strbuf_addstr(&msgbuf, ctx.notes_message); + } + if (opt->show_log_size) { printf("log size %i\n", (int)msgbuf.len); graph_show_oneline(opt->graph); @@ -689,10 +710,12 @@ void show_log(struct rev_info *opt) } strbuf_release(&msgbuf); + free(ctx.notes_message); } int log_tree_diff_flush(struct rev_info *opt) { + opt->shown_dashes = 0; diffcore_std(&opt->diffopt); if (diff_queue_is_empty()) { @@ -704,15 +727,16 @@ int log_tree_diff_flush(struct rev_info *opt) } if (opt->loginfo && !opt->no_commit_id) { - /* When showing a verbose header (i.e. log message), - * and not in --pretty=oneline format, we would want - * an extra newline between the end of log and the - * output for readability. - */ show_log(opt); if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) && opt->verbose_header && opt->commit_format != CMIT_FMT_ONELINE) { + /* + * When showing a verbose header (i.e. log message), + * and not in --pretty=oneline format, we would want + * an extra newline between the end of log and the + * diff/diffstat output for readability. + */ int pch = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH; if (opt->diffopt.output_prefix) { struct strbuf *msg = NULL; @@ -720,9 +744,20 @@ int log_tree_diff_flush(struct rev_info *opt) opt->diffopt.output_prefix_data); fwrite(msg->buf, msg->len, 1, stdout); } - if ((pch & opt->diffopt.output_format) == pch) { + + /* + * We may have shown three-dashes line early + * between notes and the log message, in which + * case we only want a blank line after the + * notes without (an extra) three-dashes line. + * Otherwise, we show the three-dashes line if + * we are showing the patch with diffstat, but + * in that case, there is no extra blank line + * after the three-dashes line. + */ + if (!opt->shown_dashes && + (pch & opt->diffopt.output_format) == pch) printf("---"); - } putchar('\n'); } } @@ -118,7 +118,7 @@ static char *parse_name_and_email(char *buffer, char **name, while (isspace(*nstart) && nstart < left) ++nstart; nend = left-1; - while (isspace(*nend) && nend > nstart) + while (nend > nstart && isspace(*nend)) --nend; *name = (nstart < nend ? nstart : NULL); diff --git a/merge-recursive.c b/merge-recursive.c index e02da3556..d8820604c 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -187,7 +187,7 @@ static void output_commit_title(struct merge_options *o, struct commit *commit) else { printf("%s ", find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV)); if (parse_commit(commit) != 0) - printf("(bad commit)\n"); + printf(_("(bad commit)\n")); else { const char *title; int len = find_commit_subject(commit->buffer, &title); @@ -203,7 +203,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, struct cache_entry *ce; ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh); if (!ce) - return error("addinfo_cache failed for path '%s'", path); + return error(_("addinfo_cache failed for path '%s'"), path); return add_cache_entry(ce, options); } @@ -265,7 +265,7 @@ struct tree *write_tree_from_memory(struct merge_options *o) if (!cache_tree_fully_valid(active_cache_tree) && cache_tree_update(active_cache_tree, active_cache, active_nr, 0) < 0) - die("error building trees"); + die(_("error building trees")); result = lookup_tree(active_cache_tree->sha1); @@ -669,7 +669,7 @@ static int would_lose_untracked(const char *path) static int make_room_for_path(struct merge_options *o, const char *path) { int status, i; - const char *msg = "failed to create path '%s'%s"; + const char *msg = _("failed to create path '%s'%s"); /* Unlink any D/F conflict files that are in the way */ for (i = 0; i < o->df_conflict_file_set.nr; i++) { @@ -680,7 +680,7 @@ static int make_room_for_path(struct merge_options *o, const char *path) path[df_pathlen] == '/' && strncmp(path, df_path, df_pathlen) == 0) { output(o, 3, - "Removing %s to make room for subdirectory\n", + _("Removing %s to make room for subdirectory\n"), df_path); unlink(df_path); unsorted_string_list_delete_item(&o->df_conflict_file_set, @@ -694,7 +694,7 @@ static int make_room_for_path(struct merge_options *o, const char *path) if (status) { if (status == -3) { /* something else exists */ - error(msg, path, ": perhaps a D/F conflict?"); + error(msg, path, _(": perhaps a D/F conflict?")); return -1; } die(msg, path, ""); @@ -705,7 +705,7 @@ static int make_room_for_path(struct merge_options *o, const char *path) * tracking it. */ if (would_lose_untracked(path)) - return error("refusing to lose untracked file at '%s'", + return error(_("refusing to lose untracked file at '%s'"), path); /* Successful unlink is good.. */ @@ -715,7 +715,7 @@ static int make_room_for_path(struct merge_options *o, const char *path) if (errno == ENOENT) return 0; /* .. but not some other error (who really cares what?) */ - return error(msg, path, ": perhaps a D/F conflict?"); + return error(msg, path, _(": perhaps a D/F conflict?")); } static void update_file_flags(struct merge_options *o, @@ -745,9 +745,9 @@ static void update_file_flags(struct merge_options *o, buf = read_sha1_file(sha, &type, &size); if (!buf) - die("cannot read object %s '%s'", sha1_to_hex(sha), path); + die(_("cannot read object %s '%s'"), sha1_to_hex(sha), path); if (type != OBJ_BLOB) - die("blob expected for %s '%s'", sha1_to_hex(sha), path); + die(_("blob expected for %s '%s'"), sha1_to_hex(sha), path); if (S_ISREG(mode)) { struct strbuf strbuf = STRBUF_INIT; if (convert_to_working_tree(path, buf, size, &strbuf)) { @@ -770,7 +770,7 @@ static void update_file_flags(struct merge_options *o, mode = 0666; fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode); if (fd < 0) - die_errno("failed to open '%s'", path); + die_errno(_("failed to open '%s'"), path); write_in_full(fd, buf, size); close(fd); } else if (S_ISLNK(mode)) { @@ -778,10 +778,10 @@ static void update_file_flags(struct merge_options *o, safe_create_leading_directories_const(path); unlink(path); if (symlink(lnk, path)) - die_errno("failed to symlink '%s'", path); + die_errno(_("failed to symlink '%s'"), path); free(lnk); } else - die("do not know what to do with %06o %s '%s'", + die(_("do not know what to do with %06o %s '%s'"), mode, sha1_to_hex(sha), path); free(buf); } @@ -844,14 +844,14 @@ static int merge_3way(struct merge_options *o, if (strcmp(a->path, b->path) || (o->ancestor != NULL && strcmp(a->path, one->path) != 0)) { base_name = o->ancestor == NULL ? NULL : - xstrdup(mkpath("%s:%s", o->ancestor, one->path)); - name1 = xstrdup(mkpath("%s:%s", branch1, a->path)); - name2 = xstrdup(mkpath("%s:%s", branch2, b->path)); + mkpathdup("%s:%s", o->ancestor, one->path); + name1 = mkpathdup("%s:%s", branch1, a->path); + name2 = mkpathdup("%s:%s", branch2, b->path); } else { base_name = o->ancestor == NULL ? NULL : - xstrdup(mkpath("%s", o->ancestor)); - name1 = xstrdup(mkpath("%s", branch1)); - name2 = xstrdup(mkpath("%s", branch2)); + mkpathdup("%s", o->ancestor); + name1 = mkpathdup("%s", branch1); + name2 = mkpathdup("%s", branch2); } read_mmblob(&orig, one->sha1); @@ -861,6 +861,7 @@ static int merge_3way(struct merge_options *o, merge_status = ll_merge(result_buf, a->path, &orig, base_name, &src1, name1, &src2, name2, &ll_opts); + free(base_name); free(name1); free(name2); free(orig.ptr); @@ -918,11 +919,11 @@ static struct merge_file_info merge_file_1(struct merge_options *o, branch1, branch2); if ((merge_status < 0) || !result_buf.ptr) - die("Failed to execute internal merge"); + die(_("Failed to execute internal merge")); if (write_sha1_file(result_buf.ptr, result_buf.size, blob_type, result.sha)) - die("Unable to add %s to database", + die(_("Unable to add %s to database"), a->path); free(result_buf.ptr); @@ -938,7 +939,7 @@ static struct merge_file_info merge_file_1(struct merge_options *o, if (!sha_eq(a->sha1, b->sha1)) result.clean = 0; } else { - die("unsupported object type in the tree"); + die(_("unsupported object type in the tree")); } } @@ -1016,22 +1017,32 @@ static void handle_change_delete(struct merge_options *o, remove_file_from_cache(path); update_file(o, 0, o_sha, o_mode, renamed ? renamed : path); } else if (!a_sha) { - output(o, 1, "CONFLICT (%s/delete): %s deleted in %s " - "and %s in %s. Version %s of %s left in tree%s%s.", - change, path, o->branch1, - change_past, o->branch2, o->branch2, path, - NULL == renamed ? "" : " at ", - NULL == renamed ? "" : renamed); - update_file(o, 0, b_sha, b_mode, renamed ? renamed : path); + if (!renamed) { + output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s " + "and %s in %s. Version %s of %s left in tree."), + change, path, o->branch1, change_past, + o->branch2, o->branch2, path); + update_file(o, 0, b_sha, b_mode, path); + } else { + output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s " + "and %s in %s. Version %s of %s left in tree at %s."), + change, path, o->branch1, change_past, + o->branch2, o->branch2, path, renamed); + update_file(o, 0, b_sha, b_mode, renamed); + } } else { - output(o, 1, "CONFLICT (%s/delete): %s deleted in %s " - "and %s in %s. Version %s of %s left in tree%s%s.", - change, path, o->branch2, - change_past, o->branch1, o->branch1, path, - NULL == renamed ? "" : " at ", - NULL == renamed ? "" : renamed); - if (renamed) + if (!renamed) { + output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s " + "and %s in %s. Version %s of %s left in tree."), + change, path, o->branch2, change_past, + o->branch1, o->branch1, path); + } else { + output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s " + "and %s in %s. Version %s of %s left in tree at %s."), + change, path, o->branch2, change_past, + o->branch1, o->branch1, path, renamed); update_file(o, 0, a_sha, a_mode, renamed); + } /* * No need to call update_file() on path when !renamed, since * that would needlessly touch path. We could call @@ -1067,7 +1078,7 @@ static void conflict_rename_delete(struct merge_options *o, orig->sha1, orig->mode, a_sha, a_mode, b_sha, b_mode, - "rename", "renamed"); + _("rename"), _("renamed")); if (o->call_depth) { remove_file_from_cache(dest->path); @@ -1123,7 +1134,7 @@ static void handle_file(struct merge_options *o, } else { if (dir_in_way(rename->path, !o->call_depth)) { dst_name = unique_path(o, rename->path, cur_branch); - output(o, 1, "%s is a directory in %s adding as %s instead", + output(o, 1, _("%s is a directory in %s adding as %s instead"), rename->path, other_branch, dst_name); } } @@ -1145,12 +1156,12 @@ static void conflict_rename_rename_1to2(struct merge_options *o, struct diff_filespec *a = ci->pair1->two; struct diff_filespec *b = ci->pair2->two; - output(o, 1, "CONFLICT (rename/rename): " + output(o, 1, _("CONFLICT (rename/rename): " "Rename \"%s\"->\"%s\" in branch \"%s\" " - "rename \"%s\"->\"%s\" in \"%s\"%s", + "rename \"%s\"->\"%s\" in \"%s\"%s"), one->path, a->path, ci->branch1, one->path, b->path, ci->branch2, - o->call_depth ? " (left unresolved)" : ""); + o->call_depth ? _(" (left unresolved)") : ""); if (o->call_depth) { struct merge_file_info mfi; struct diff_filespec other; @@ -1204,9 +1215,9 @@ static void conflict_rename_rename_2to1(struct merge_options *o, struct merge_file_info mfi_c1; struct merge_file_info mfi_c2; - output(o, 1, "CONFLICT (rename/rename): " + output(o, 1, _("CONFLICT (rename/rename): " "Rename %s->%s in %s. " - "Rename %s->%s in %s", + "Rename %s->%s in %s"), a->path, c1->path, ci->branch1, b->path, c2->path, ci->branch2); @@ -1234,7 +1245,7 @@ static void conflict_rename_rename_2to1(struct merge_options *o, } else { char *new_path1 = unique_path(o, path, ci->branch1); char *new_path2 = unique_path(o, path, ci->branch2); - output(o, 1, "Renaming %s to %s and %s to %s instead", + output(o, 1, _("Renaming %s to %s and %s to %s instead"), a->path, new_path1, b->path, new_path2); remove_file(o, 0, path, 0); update_file(o, 0, mfi_c1.sha, mfi_c1.mode, new_path1); @@ -1433,8 +1444,8 @@ static int process_renames(struct merge_options *o, } else if (!sha_eq(dst_other.sha1, null_sha1)) { clean_merge = 0; try_merge = 1; - output(o, 1, "CONFLICT (rename/add): Rename %s->%s in %s. " - "%s added in %s", + output(o, 1, _("CONFLICT (rename/add): Rename %s->%s in %s. " + "%s added in %s"), ren1_src, ren1_dst, branch1, ren1_dst, branch2); if (o->call_depth) { @@ -1443,12 +1454,12 @@ static int process_renames(struct merge_options *o, ren1->pair->two->sha1, ren1->pair->two->mode, dst_other.sha1, dst_other.mode, branch1, branch2); - output(o, 1, "Adding merged %s", ren1_dst); + output(o, 1, _("Adding merged %s"), ren1_dst); update_file(o, 0, mfi.sha, mfi.mode, ren1_dst); try_merge = 0; } else { char *new_path = unique_path(o, ren1_dst, branch2); - output(o, 1, "Adding as %s instead", new_path); + output(o, 1, _("Adding as %s instead"), new_path); update_file(o, 0, dst_other.sha1, dst_other.mode, new_path); free(new_path); } @@ -1499,10 +1510,10 @@ static int read_sha1_strbuf(const unsigned char *sha1, struct strbuf *dst) unsigned long size; buf = read_sha1_file(sha1, &type, &size); if (!buf) - return error("cannot read object %s", sha1_to_hex(sha1)); + return error(_("cannot read object %s"), sha1_to_hex(sha1)); if (type != OBJ_BLOB) { free(buf); - return error("object %s is not a blob", sha1_to_hex(sha1)); + return error(_("object %s is not a blob"), sha1_to_hex(sha1)); } strbuf_attach(dst, buf, size, size + 1); return 0; @@ -1550,7 +1561,7 @@ static void handle_modify_delete(struct merge_options *o, o_sha, o_mode, a_sha, a_mode, b_sha, b_mode, - "modify", "modified"); + _("modify"), _("modified")); } static int merge_content(struct merge_options *o, @@ -1560,14 +1571,14 @@ static int merge_content(struct merge_options *o, unsigned char *b_sha, int b_mode, struct rename_conflict_info *rename_conflict_info) { - const char *reason = "content"; + const char *reason = _("content"); const char *path1 = NULL, *path2 = NULL; struct merge_file_info mfi; struct diff_filespec one, a, b; unsigned df_conflict_remains = 0; if (!o_sha) { - reason = "add/add"; + reason = _("add/add"); o_sha = (unsigned char *)null_sha1; } one.path = a.path = b.path = (char *)path; @@ -1601,7 +1612,7 @@ static int merge_content(struct merge_options *o, if (mfi.clean && !df_conflict_remains && sha_eq(mfi.sha, a_sha) && mfi.mode == a_mode) { int path_renamed_outside_HEAD; - output(o, 3, "Skipped %s (merged same as existing)", path); + output(o, 3, _("Skipped %s (merged same as existing)"), path); /* * The content merge resulted in the same file contents we * already had. We can return early if those file contents @@ -1615,12 +1626,12 @@ static int merge_content(struct merge_options *o, return mfi.clean; } } else - output(o, 2, "Auto-merging %s", path); + output(o, 2, _("Auto-merging %s"), path); if (!mfi.clean) { if (S_ISGITLINK(mfi.mode)) - reason = "submodule"; - output(o, 1, "CONFLICT (%s): Merge conflict in %s", + reason = _("submodule"); + output(o, 1, _("CONFLICT (%s): Merge conflict in %s"), reason, path); if (rename_conflict_info && !df_conflict_remains) update_stages(path, &one, &a, &b); @@ -1646,7 +1657,7 @@ static int merge_content(struct merge_options *o, } new_path = unique_path(o, path, rename_conflict_info->branch1); - output(o, 1, "Adding as %s instead", new_path); + output(o, 1, _("Adding as %s instead"), new_path); update_file(o, 0, mfi.sha, mfi.mode, new_path); free(new_path); mfi.clean = 0; @@ -1710,7 +1721,7 @@ static int process_entry(struct merge_options *o, /* Deleted in both or deleted in one and * unchanged in the other */ if (a_sha) - output(o, 2, "Removing %s", path); + output(o, 2, _("Removing %s"), path); /* do not touch working file if it did not exist */ remove_file(o, 1, path, !a_sha); } else { @@ -1735,19 +1746,19 @@ static int process_entry(struct merge_options *o, other_branch = o->branch2; mode = a_mode; sha = a_sha; - conf = "file/directory"; + conf = _("file/directory"); } else { add_branch = o->branch2; other_branch = o->branch1; mode = b_mode; sha = b_sha; - conf = "directory/file"; + conf = _("directory/file"); } if (dir_in_way(path, !o->call_depth)) { char *new_path = unique_path(o, path, add_branch); clean_merge = 0; - output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. " - "Adding %s as %s", + output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. " + "Adding %s as %s"), conf, path, other_branch, path, new_path); if (o->call_depth) remove_file_from_cache(path); @@ -1756,7 +1767,7 @@ static int process_entry(struct merge_options *o, remove_file_from_cache(path); free(new_path); } else { - output(o, 2, "Adding %s", path); + output(o, 2, _("Adding %s"), path); /* do not overwrite file if already present */ update_file_flags(o, sha, mode, path, 1, !a_sha); } @@ -1773,7 +1784,7 @@ static int process_entry(struct merge_options *o, */ remove_file(o, 1, path, !a_mode); } else - die("Fatal merge failure, shouldn't happen."); + die(_("Fatal merge failure, shouldn't happen.")); return clean_merge; } @@ -1792,7 +1803,7 @@ int merge_trees(struct merge_options *o, } if (sha_eq(common->object.sha1, merge->object.sha1)) { - output(o, 0, "Already up-to-date!"); + output(o, 0, _("Already up-to-date!")); *result = head; return 1; } @@ -1801,7 +1812,7 @@ int merge_trees(struct merge_options *o, if (code != 0) { if (show(o, 4) || o->call_depth) - die("merging of trees %s and %s failed", + die(_("merging of trees %s and %s failed"), sha1_to_hex(head->object.sha1), sha1_to_hex(merge->object.sha1)); else @@ -1831,7 +1842,7 @@ int merge_trees(struct merge_options *o, for (i = 0; i < entries->nr; i++) { struct stage_data *e = entries->items[i].util; if (!e->processed) - die("Unprocessed path??? %s", + die(_("Unprocessed path??? %s"), entries->items[i].string); } @@ -1876,7 +1887,7 @@ int merge_recursive(struct merge_options *o, int clean; if (show(o, 4)) { - output(o, 4, "Merging:"); + output(o, 4, _("Merging:")); output_commit_title(o, h1); output_commit_title(o, h2); } @@ -1887,7 +1898,10 @@ int merge_recursive(struct merge_options *o, } if (show(o, 5)) { - output(o, 5, "found %u common ancestor(s):", commit_list_count(ca)); + unsigned cnt = commit_list_count(ca); + + output(o, 5, Q_("found %u common ancestor:", + "found %u common ancestors:", cnt), cnt); for (iter = ca; iter; iter = iter->next) output_commit_title(o, iter->item); } @@ -1923,7 +1937,7 @@ int merge_recursive(struct merge_options *o, o->call_depth--; if (!merged_common_ancestors) - die("merge returned no commit"); + die(_("merge returned no commit")); } discard_cache(); @@ -1980,7 +1994,7 @@ int merge_recursive_generic(struct merge_options *o, for (i = 0; i < num_base_list; ++i) { struct commit *base; if (!(base = get_ref(base_list[i], sha1_to_hex(base_list[i])))) - return error("Could not parse object '%s'", + return error(_("Could not parse object '%s'"), sha1_to_hex(base_list[i])); commit_list_insert(base, &ca); } @@ -1992,7 +2006,7 @@ int merge_recursive_generic(struct merge_options *o, if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) - return error("Unable to write index."); + return error(_("Unable to write index.")); return clean ? 0 : 1; } diff --git a/merge-recursive.h b/merge-recursive.h index 58f3435e9..9e090a347 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -59,9 +59,4 @@ struct tree *write_tree_from_memory(struct merge_options *o); int parse_merge_opt(struct merge_options *out, const char *s); -/* builtin/merge.c */ -int try_merge_command(const char *strategy, size_t xopts_nr, - const char **xopts, struct commit_list *common, - const char *head_arg, struct commit_list *remotes); - #endif diff --git a/merge.c b/merge.c new file mode 100644 index 000000000..70f1000fc --- /dev/null +++ b/merge.c @@ -0,0 +1,112 @@ +#include "cache.h" +#include "commit.h" +#include "run-command.h" +#include "resolve-undo.h" +#include "tree-walk.h" +#include "unpack-trees.h" +#include "dir.h" + +static const char *merge_argument(struct commit *commit) +{ + if (commit) + return sha1_to_hex(commit->object.sha1); + else + return EMPTY_TREE_SHA1_HEX; +} + +int try_merge_command(const char *strategy, size_t xopts_nr, + const char **xopts, struct commit_list *common, + const char *head_arg, struct commit_list *remotes) +{ + const char **args; + int i = 0, x = 0, ret; + struct commit_list *j; + struct strbuf buf = STRBUF_INIT; + + args = xmalloc((4 + xopts_nr + commit_list_count(common) + + commit_list_count(remotes)) * sizeof(char *)); + strbuf_addf(&buf, "merge-%s", strategy); + args[i++] = buf.buf; + for (x = 0; x < xopts_nr; x++) { + char *s = xmalloc(strlen(xopts[x])+2+1); + strcpy(s, "--"); + strcpy(s+2, xopts[x]); + args[i++] = s; + } + for (j = common; j; j = j->next) + args[i++] = xstrdup(merge_argument(j->item)); + args[i++] = "--"; + args[i++] = head_arg; + for (j = remotes; j; j = j->next) + args[i++] = xstrdup(merge_argument(j->item)); + args[i] = NULL; + ret = run_command_v_opt(args, RUN_GIT_CMD); + strbuf_release(&buf); + i = 1; + for (x = 0; x < xopts_nr; x++) + free((void *)args[i++]); + for (j = common; j; j = j->next) + free((void *)args[i++]); + i += 2; + for (j = remotes; j; j = j->next) + free((void *)args[i++]); + free(args); + discard_cache(); + if (read_cache() < 0) + die(_("failed to read the cache")); + resolve_undo_clear(); + + return ret; +} + +int checkout_fast_forward(const unsigned char *head, + const unsigned char *remote, + int overwrite_ignore) +{ + struct tree *trees[MAX_UNPACK_TREES]; + struct unpack_trees_options opts; + struct tree_desc t[MAX_UNPACK_TREES]; + int i, fd, nr_trees = 0; + struct dir_struct dir; + struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); + + refresh_cache(REFRESH_QUIET); + + fd = hold_locked_index(lock_file, 1); + + memset(&trees, 0, sizeof(trees)); + memset(&opts, 0, sizeof(opts)); + memset(&t, 0, sizeof(t)); + if (overwrite_ignore) { + memset(&dir, 0, sizeof(dir)); + dir.flags |= DIR_SHOW_IGNORED; + setup_standard_excludes(&dir); + opts.dir = &dir; + } + + opts.head_idx = 1; + opts.src_index = &the_index; + opts.dst_index = &the_index; + opts.update = 1; + opts.verbose_update = 1; + opts.merge = 1; + opts.fn = twoway_merge; + setup_unpack_trees_porcelain(&opts, "merge"); + + trees[nr_trees] = parse_tree_indirect(head); + if (!trees[nr_trees++]) + return -1; + trees[nr_trees] = parse_tree_indirect(remote); + if (!trees[nr_trees++]) + return -1; + for (i = 0; i < nr_trees; i++) { + parse_tree(trees[i]); + init_tree_desc(t+i, trees[i]->buffer, trees[i]->size); + } + if (unpack_trees(nr_trees, t, &opts)) + return -1; + if (write_cache(fd, active_cache, active_nr) || + commit_locked_index(lock_file)) + die(_("unable to write new index file")); + return 0; +} diff --git a/mergetools/codecompare b/mergetools/codecompare new file mode 100644 index 000000000..3f0486bc8 --- /dev/null +++ b/mergetools/codecompare @@ -0,0 +1,25 @@ +diff_cmd () { + "$merge_tool_path" "$LOCAL" "$REMOTE" +} + +merge_cmd () { + touch "$BACKUP" + if $base_present + then + "$merge_tool_path" -MF="$LOCAL" -TF="$REMOTE" -BF="$BASE" \ + -RF="$MERGED" + else + "$merge_tool_path" -MF="$LOCAL" -TF="$REMOTE" \ + -RF="$MERGED" + fi + check_unchanged +} + +translate_merge_tool_path() { + if merge_mode + then + echo CodeMerge + else + echo CodeCompare + fi +} diff --git a/mergetools/defaults b/mergetools/defaults index 1d8f2a3dd..21e63ecc3 100644 --- a/mergetools/defaults +++ b/mergetools/defaults @@ -8,36 +8,12 @@ can_diff () { } diff_cmd () { - merge_tool_cmd="$(get_merge_tool_cmd "$1")" - if test -z "$merge_tool_cmd" - then - status=1 - break - fi - ( eval $merge_tool_cmd ) - status=$? + status=1 return $status } merge_cmd () { - merge_tool_cmd="$(get_merge_tool_cmd "$1")" - if test -z "$merge_tool_cmd" - then - status=1 - break - fi - trust_exit_code="$(git config --bool \ - mergetool."$1".trustExitCode || echo false)" - if test "$trust_exit_code" = "false" - then - touch "$BACKUP" - ( eval $merge_tool_cmd ) - status=$? - check_unchanged - else - ( eval $merge_tool_cmd ) - status=$? - fi + status=1 return $status } diff --git a/mergetools/p4merge b/mergetools/p4merge index 1a45c1b0c..295361a8a 100644 --- a/mergetools/p4merge +++ b/mergetools/p4merge @@ -1,5 +1,30 @@ diff_cmd () { + # p4merge does not like /dev/null + rm_local= + rm_remote= + if test "/dev/null" = "$LOCAL" + then + LOCAL="./p4merge-dev-null.LOCAL.$$" + >"$LOCAL" + rm_local=true + fi + if test "/dev/null" = "$REMOTE" + then + REMOTE="./p4merge-dev-null.REMOTE.$$" + >"$REMOTE" + rm_remote=true + fi + "$merge_tool_path" "$LOCAL" "$REMOTE" + + if test -n "$rm_local" + then + rm -f "$LOCAL" + fi + if test -n "$rm_remote" + then + rm -f "$REMOTE" + fi } merge_cmd () { diff --git a/notes-merge.c b/notes-merge.c index 7d62904f6..0f67bd3f9 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -522,8 +522,10 @@ static int merge_from_diffs(struct notes_merge_options *o, free(changes); if (o->verbosity >= 4) - printf("Merge result: %i unmerged notes and a %s notes tree\n", - conflicts, t->dirty ? "dirty" : "clean"); + printf(t->dirty ? + "Merge result: %i unmerged notes and a dirty notes tree\n" : + "Merge result: %i unmerged notes and a clean notes tree\n", + conflicts); return conflicts ? -1 : 1; } @@ -848,15 +848,16 @@ int combine_notes_ignore(unsigned char *cur_sha1, return 0; } -static int string_list_add_note_lines(struct string_list *sort_uniq_list, +/* + * Add the lines from the named object to list, with trailing + * newlines removed. + */ +static int string_list_add_note_lines(struct string_list *list, const unsigned char *sha1) { char *data; unsigned long len; enum object_type t; - struct strbuf buf = STRBUF_INIT; - struct strbuf **lines = NULL; - int i, list_index; if (is_null_sha1(sha1)) return 0; @@ -868,24 +869,14 @@ static int string_list_add_note_lines(struct string_list *sort_uniq_list, return t != OBJ_BLOB || !data; } - strbuf_attach(&buf, data, len, len + 1); - lines = strbuf_split(&buf, '\n'); - - for (i = 0; lines[i]; i++) { - if (lines[i]->buf[lines[i]->len - 1] == '\n') - strbuf_setlen(lines[i], lines[i]->len - 1); - if (!lines[i]->len) - continue; /* skip empty lines */ - list_index = string_list_find_insert_index(sort_uniq_list, - lines[i]->buf, 0); - if (list_index < 0) - continue; /* skip duplicate lines */ - string_list_insert_at_index(sort_uniq_list, list_index, - lines[i]->buf); - } - - strbuf_list_free(lines); - strbuf_release(&buf); + /* + * If the last line of the file is EOL-terminated, this will + * add an empty string to the list. But it will be removed + * later, along with any empty strings that came from empty + * lines within the file. + */ + string_list_split(list, data, '\n', -1); + free(data); return 0; } @@ -901,7 +892,7 @@ static int string_list_join_lines_helper(struct string_list_item *item, int combine_notes_cat_sort_uniq(unsigned char *cur_sha1, const unsigned char *new_sha1) { - struct string_list sort_uniq_list = { NULL, 0, 0, 1 }; + struct string_list sort_uniq_list = STRING_LIST_INIT_DUP; struct strbuf buf = STRBUF_INIT; int ret = 1; @@ -910,6 +901,9 @@ int combine_notes_cat_sort_uniq(unsigned char *cur_sha1, goto out; if (string_list_add_note_lines(&sort_uniq_list, new_sha1)) goto out; + string_list_remove_empty_items(&sort_uniq_list, 0); + sort_string_list(&sort_uniq_list); + string_list_remove_duplicates(&sort_uniq_list, 0); /* create a new blob object from sort_uniq_list */ if (for_each_string_list(&sort_uniq_list, @@ -949,23 +943,18 @@ void string_list_add_refs_by_glob(struct string_list *list, const char *glob) void string_list_add_refs_from_colon_sep(struct string_list *list, const char *globs) { - struct strbuf globbuf = STRBUF_INIT; - struct strbuf **split; + struct string_list split = STRING_LIST_INIT_NODUP; + char *globs_copy = xstrdup(globs); int i; - strbuf_addstr(&globbuf, globs); - split = strbuf_split(&globbuf, ':'); + string_list_split_in_place(&split, globs_copy, ':', -1); + string_list_remove_empty_items(&split, 0); - for (i = 0; split[i]; i++) { - if (!split[i]->len) - continue; - if (split[i]->buf[split[i]->len-1] == ':') - strbuf_setlen(split[i], split[i]->len-1); - string_list_add_refs_by_glob(list, split[i]->buf); - } + for (i = 0; i < split.nr; i++) + string_list_add_refs_by_glob(list, split.items[i].string); - strbuf_list_free(split); - strbuf_release(&globbuf); + string_list_clear(&split, 0); + free(globs_copy); } static int notes_display_config(const char *k, const char *v, void *cb) @@ -1196,8 +1185,19 @@ void free_notes(struct notes_tree *t) memset(t, 0, sizeof(struct notes_tree)); } -void format_note(struct notes_tree *t, const unsigned char *object_sha1, - struct strbuf *sb, const char *output_encoding, int flags) +/* + * Fill the given strbuf with the notes associated with the given object. + * + * If the given notes_tree structure is not initialized, it will be auto- + * initialized to the default value (see documentation for init_notes() above). + * If the given notes_tree is NULL, the internal/default notes_tree will be + * used instead. + * + * (raw != 0) gives the %N userformat; otherwise, the note message is given + * for human consumption. + */ +static void format_note(struct notes_tree *t, const unsigned char *object_sha1, + struct strbuf *sb, const char *output_encoding, int raw) { static const char utf8[] = "utf-8"; const unsigned char *sha1; @@ -1221,7 +1221,7 @@ void format_note(struct notes_tree *t, const unsigned char *object_sha1, } if (output_encoding && *output_encoding && - strcmp(utf8, output_encoding)) { + !is_encoding_utf8(output_encoding)) { char *reencoded = reencode_string(msg, output_encoding, utf8); if (reencoded) { free(msg); @@ -1234,7 +1234,7 @@ void format_note(struct notes_tree *t, const unsigned char *object_sha1, if (msglen && msg[msglen - 1] == '\n') msglen--; - if (flags & NOTES_SHOW_HEADER) { + if (!raw) { const char *ref = t->ref; if (!ref || !strcmp(ref, GIT_NOTES_DEFAULT_REF)) { strbuf_addstr(sb, "\nNotes:\n"); @@ -1250,7 +1250,7 @@ void format_note(struct notes_tree *t, const unsigned char *object_sha1, for (msg_p = msg; msg_p < msg + msglen; msg_p += linelen + 1) { linelen = strchrnul(msg_p, '\n') - msg_p; - if (flags & NOTES_INDENT) + if (!raw) strbuf_addstr(sb, " "); strbuf_add(sb, msg_p, linelen); strbuf_addch(sb, '\n'); @@ -1260,13 +1260,13 @@ void format_note(struct notes_tree *t, const unsigned char *object_sha1, } void format_display_notes(const unsigned char *object_sha1, - struct strbuf *sb, const char *output_encoding, int flags) + struct strbuf *sb, const char *output_encoding, int raw) { int i; assert(display_notes_trees); for (i = 0; display_notes_trees[i]; i++) format_note(display_notes_trees[i], object_sha1, sb, - output_encoding, flags); + output_encoding, raw); } int copy_note(struct notes_tree *t, @@ -237,24 +237,6 @@ void prune_notes(struct notes_tree *t, int flags); */ void free_notes(struct notes_tree *t); -/* Flags controlling how notes are formatted */ -#define NOTES_SHOW_HEADER 1 -#define NOTES_INDENT 2 - -/* - * Fill the given strbuf with the notes associated with the given object. - * - * If the given notes_tree structure is not initialized, it will be auto- - * initialized to the default value (see documentation for init_notes() above). - * If the given notes_tree is NULL, the internal/default notes_tree will be - * used instead. - * - * 'flags' is a bitwise combination of the above formatting flags. - */ -void format_note(struct notes_tree *t, const unsigned char *object_sha1, - struct strbuf *sb, const char *output_encoding, int flags); - - struct string_list; struct display_notes_opt { @@ -288,7 +270,7 @@ void init_display_notes(struct display_notes_opt *opt); * You *must* call init_display_notes() before using this function. */ void format_display_notes(const unsigned char *object_sha1, - struct strbuf *sb, const char *output_encoding, int flags); + struct strbuf *sb, const char *output_encoding, int raw); /* * Load the notes tree from each ref listed in 'refs'. The output is @@ -6,26 +6,17 @@ #define DEFAULT_PAGER "less" #endif +struct pager_config { + const char *cmd; + int want; + char *value; +}; + /* * This is split up from the rest of git so that we can do * something different on Windows. */ -#ifndef WIN32 -static void pager_preexec(void) -{ - /* - * Work around bug in "less" by not starting it until we - * have real input - */ - fd_set in; - - FD_ZERO(&in); - FD_SET(0, &in); - select(1, &in, NULL, &in, NULL); -} -#endif - static const char *pager_argv[] = { NULL, NULL }; static struct child_process pager_process; @@ -93,9 +84,6 @@ void setup_pager(void) static const char *env[] = { "LESS=FRSX", NULL }; pager_process.env = env; } -#ifndef WIN32 - pager_process.preexec_cb = pager_preexec; -#endif if (start_command(&pager_process)) return; @@ -159,3 +147,31 @@ int decimal_width(int number) i *= 10; return width; } + +static int pager_command_config(const char *var, const char *value, void *data) +{ + struct pager_config *c = data; + if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd)) { + int b = git_config_maybe_bool(var, value); + if (b >= 0) + c->want = b; + else { + c->want = 1; + c->value = xstrdup(value); + } + } + return 0; +} + +/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */ +int check_pager_config(const char *cmd) +{ + struct pager_config c; + c.cmd = cmd; + c.want = -1; + c.value = NULL; + git_config(pager_command_config, &c); + if (c.value) + pager_program = c.value; + return c.want; +} diff --git a/parse-options.c b/parse-options.c index ab70c29c4..c1c66bd40 100644 --- a/parse-options.c +++ b/parse-options.c @@ -476,6 +476,7 @@ int parse_options(int argc, const char **argv, const char *prefix, usage_with_options(usagestr, options); } + precompose_argv(argc, argv); return parse_options_end(&ctx); } diff --git a/parse-options.h b/parse-options.h index 77a4a8b2e..71a39c60d 100644 --- a/parse-options.h +++ b/parse-options.h @@ -238,6 +238,6 @@ extern int parse_opt_noop_cb(const struct option *, const char *, int); #define OPT__COLOR(var, h) \ OPT_COLOR_FLAG(0, "color", (var), (h)) #define OPT_COLUMN(s, l, v, h) \ - { OPTION_CALLBACK, (s), (l), (v), "style", (h), PARSE_OPT_OPTARG, parseopt_column_callback } + { OPTION_CALLBACK, (s), (l), (v), N_("style"), (h), PARSE_OPT_OPTARG, parseopt_column_callback } #endif @@ -48,7 +48,7 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...) return cleanup_path(buf); } -static char *git_vsnpath(char *buf, size_t n, const char *fmt, va_list args) +static char *vsnpath(char *buf, size_t n, const char *fmt, va_list args) { const char *git_dir = get_git_dir(); size_t len; @@ -70,21 +70,37 @@ bad: char *git_snpath(char *buf, size_t n, const char *fmt, ...) { + char *ret; va_list args; va_start(args, fmt); - (void)git_vsnpath(buf, n, fmt, args); + ret = vsnpath(buf, n, fmt, args); va_end(args); - return buf; + return ret; } char *git_pathdup(const char *fmt, ...) { - char path[PATH_MAX]; + char path[PATH_MAX], *ret; + va_list args; + va_start(args, fmt); + ret = vsnpath(path, sizeof(path), fmt, args); + va_end(args); + return xstrdup(ret); +} + +char *mkpathdup(const char *fmt, ...) +{ + char *path; + struct strbuf sb = STRBUF_INIT; va_list args; + va_start(args, fmt); - (void)git_vsnpath(path, sizeof(path), fmt, args); + strbuf_vaddf(&sb, fmt, args); va_end(args); - return xstrdup(path); + path = xstrdup(cleanup_path(sb.buf)); + + strbuf_release(&sb); + return path; } char *mkpath(const char *fmt, ...) @@ -103,23 +119,40 @@ char *mkpath(const char *fmt, ...) char *git_path(const char *fmt, ...) { - const char *git_dir = get_git_dir(); char *pathname = get_pathname(); va_list args; - unsigned len; + char *ret; - len = strlen(git_dir); - if (len > PATH_MAX-100) - return bad_path; - memcpy(pathname, git_dir, len); - if (len && git_dir[len-1] != '/') - pathname[len++] = '/'; va_start(args, fmt); - len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args); + ret = vsnpath(pathname, PATH_MAX, fmt, args); va_end(args); - if (len >= PATH_MAX) - return bad_path; - return cleanup_path(pathname); + return ret; +} + +void home_config_paths(char **global, char **xdg, char *file) +{ + char *xdg_home = getenv("XDG_CONFIG_HOME"); + char *home = getenv("HOME"); + char *to_free = NULL; + + if (!home) { + if (global) + *global = NULL; + } else { + if (!xdg_home) { + to_free = mkpathdup("%s/.config", home); + xdg_home = to_free; + } + if (global) + *global = mkpathdup("%s/.gitconfig", home); + } + + if (!xdg_home) + *xdg = NULL; + else + *xdg = mkpathdup("%s/git/%s", xdg_home, file); + + free(to_free); } char *git_path_submodule(const char *path, const char *fmt, ...) diff --git a/perl/.gitignore b/perl/.gitignore index d5c6e22d0..0f1fc27f8 100644 --- a/perl/.gitignore +++ b/perl/.gitignore @@ -5,3 +5,4 @@ MYMETA.yml blib blibdirs pm_to_blib +PM.stamp diff --git a/perl/Git.pm b/perl/Git.pm index 497f42017..931047c51 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -58,7 +58,7 @@ require Exporter; command_output_pipe command_input_pipe command_close_pipe command_bidi_pipe command_close_bidi_pipe version exec_path html_path hash_object git_cmd_try - remote_refs + remote_refs prompt temp_acquire temp_release temp_reset temp_path); @@ -511,6 +511,58 @@ C<git --html-path>). Useful mostly only internally. sub html_path { command_oneline('--html-path') } +=item prompt ( PROMPT , ISPASSWORD ) + +Query user C<PROMPT> and return answer from user. + +Honours GIT_ASKPASS and SSH_ASKPASS environment variables for querying +the user. If no *_ASKPASS variable is set or an error occoured, +the terminal is tried as a fallback. +If C<ISPASSWORD> is set and true, the terminal disables echo. + +=cut + +sub prompt { + my ($prompt, $isPassword) = @_; + my $ret; + if (exists $ENV{'GIT_ASKPASS'}) { + $ret = _prompt($ENV{'GIT_ASKPASS'}, $prompt); + } + if (!defined $ret && exists $ENV{'SSH_ASKPASS'}) { + $ret = _prompt($ENV{'SSH_ASKPASS'}, $prompt); + } + if (!defined $ret) { + print STDERR $prompt; + STDERR->flush; + if (defined $isPassword && $isPassword) { + require Term::ReadKey; + Term::ReadKey::ReadMode('noecho'); + $ret = ''; + while (defined(my $key = Term::ReadKey::ReadKey(0))) { + last if $key =~ /[\012\015]/; # \n\r + $ret .= $key; + } + Term::ReadKey::ReadMode('restore'); + print STDERR "\n"; + STDERR->flush; + } else { + chomp($ret = <STDIN>); + } + } + return $ret; +} + +sub _prompt { + my ($askpass, $prompt) = @_; + return unless length $askpass; + $prompt =~ s/\n/ /g; + my $ret; + open my $fh, "-|", $askpass, $prompt or return; + $ret = <$fh>; + $ret =~ s/[\015\012]//g; # strip \r\n, chomp does not work on all systems (i.e. windows) as expected + close ($fh); + return $ret; +} =item repo_path () diff --git a/perl/Git/IndexInfo.pm b/perl/Git/IndexInfo.pm new file mode 100644 index 000000000..a43108c98 --- /dev/null +++ b/perl/Git/IndexInfo.pm @@ -0,0 +1,33 @@ +package Git::IndexInfo; +use strict; +use warnings; +use Git qw/command_input_pipe command_close_pipe/; + +sub new { + my ($class) = @_; + my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/); + bless { gui => $gui, ctx => $ctx, nr => 0}, $class; +} + +sub remove { + my ($self, $path) = @_; + if (print { $self->{gui} } '0 ', 0 x 40, "\t", $path, "\0") { + return ++$self->{nr}; + } + undef; +} + +sub update { + my ($self, $mode, $hash, $path) = @_; + if (print { $self->{gui} } $mode, ' ', $hash, "\t", $path, "\0") { + return ++$self->{nr}; + } + undef; +} + +sub DESTROY { + my ($self) = @_; + command_close_pipe($self->{gui}, $self->{ctx}); +} + +1; diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm new file mode 100644 index 000000000..59215fa86 --- /dev/null +++ b/perl/Git/SVN.pm @@ -0,0 +1,2394 @@ +package Git::SVN; +use strict; +use warnings; +use Fcntl qw/:DEFAULT :seek/; +use constant rev_map_fmt => 'NH40'; +use vars qw/$_no_metadata + $_repack $_repack_flags $_use_svm_props $_head + $_use_svnsync_props $no_reuse_existing + $_use_log_author $_add_author_from $_localtime/; +use Carp qw/croak/; +use File::Path qw/mkpath/; +use File::Copy qw/copy/; +use IPC::Open3; +use Time::Local; +use Memoize; # core since 5.8.0, Jul 2002 +use Memoize::Storable; +use POSIX qw(:signal_h); + +use Git qw( + command + command_oneline + command_noisy + command_output_pipe + command_close_pipe +); +use Git::SVN::Utils qw( + fatal + can_compress + join_paths + canonicalize_path + canonicalize_url + add_path_to_url +); + +my $can_use_yaml; +BEGIN { + $can_use_yaml = eval { require Git::SVN::Memoize::YAML; 1}; +} + +our $_follow_parent = 1; +our $_minimize_url = 'unset'; +our $default_repo_id = 'svn'; +our $default_ref_id = $ENV{GIT_SVN_ID} || 'git-svn'; + +my ($_gc_nr, $_gc_period); + +# properties that we do not log: +my %SKIP_PROP; +BEGIN { + %SKIP_PROP = map { $_ => 1 } qw/svn:wc:ra_dav:version-url + svn:special svn:executable + svn:entry:committed-rev + svn:entry:last-author + svn:entry:uuid + svn:entry:committed-date/; + + # some options are read globally, but can be overridden locally + # per [svn-remote "..."] section. Command-line options will *NOT* + # override options set in an [svn-remote "..."] section + no strict 'refs'; + for my $option (qw/follow_parent no_metadata use_svm_props + use_svnsync_props/) { + my $key = $option; + $key =~ tr/_//d; + my $prop = "-$option"; + *$option = sub { + my ($self) = @_; + return $self->{$prop} if exists $self->{$prop}; + my $k = "svn-remote.$self->{repo_id}.$key"; + eval { command_oneline(qw/config --get/, $k) }; + if ($@) { + $self->{$prop} = ${"Git::SVN::_$option"}; + } else { + my $v = command_oneline(qw/config --bool/,$k); + $self->{$prop} = $v eq 'false' ? 0 : 1; + } + return $self->{$prop}; + } + } +} + + +my (%LOCKFILES, %INDEX_FILES); +END { + unlink keys %LOCKFILES if %LOCKFILES; + unlink keys %INDEX_FILES if %INDEX_FILES; +} + +sub resolve_local_globs { + my ($url, $fetch, $glob_spec) = @_; + return unless defined $glob_spec; + my $ref = $glob_spec->{ref}; + my $path = $glob_spec->{path}; + foreach (command(qw#for-each-ref --format=%(refname) refs/#)) { + next unless m#^$ref->{regex}$#; + my $p = $1; + my $pathname = desanitize_refname($path->full_path($p)); + my $refname = desanitize_refname($ref->full_path($p)); + if (my $existing = $fetch->{$pathname}) { + if ($existing ne $refname) { + die "Refspec conflict:\n", + "existing: $existing\n", + " globbed: $refname\n"; + } + my $u = (::cmt_metadata("$refname"))[0]; + $u =~ s!^\Q$url\E(/|$)!! or die + "$refname: '$url' not found in '$u'\n"; + if ($pathname ne $u) { + warn "W: Refspec glob conflict ", + "(ref: $refname):\n", + "expected path: $pathname\n", + " real path: $u\n", + "Continuing ahead with $u\n"; + next; + } + } else { + $fetch->{$pathname} = $refname; + } + } +} + +sub parse_revision_argument { + my ($base, $head) = @_; + if (!defined $::_revision || $::_revision eq 'BASE:HEAD') { + return ($base, $head); + } + return ($1, $2) if ($::_revision =~ /^(\d+):(\d+)$/); + return ($::_revision, $::_revision) if ($::_revision =~ /^\d+$/); + return ($head, $head) if ($::_revision eq 'HEAD'); + return ($base, $1) if ($::_revision =~ /^BASE:(\d+)$/); + return ($1, $head) if ($::_revision =~ /^(\d+):HEAD$/); + die "revision argument: $::_revision not understood by git-svn\n"; +} + +sub fetch_all { + my ($repo_id, $remotes) = @_; + if (ref $repo_id) { + my $gs = $repo_id; + $repo_id = undef; + $repo_id = $gs->{repo_id}; + } + $remotes ||= read_all_remotes(); + my $remote = $remotes->{$repo_id} or + die "[svn-remote \"$repo_id\"] unknown\n"; + my $fetch = $remote->{fetch}; + my $url = $remote->{url} or die "svn-remote.$repo_id.url not defined\n"; + my (@gs, @globs); + my $ra = Git::SVN::Ra->new($url); + my $uuid = $ra->get_uuid; + my $head = $ra->get_latest_revnum; + + # ignore errors, $head revision may not even exist anymore + eval { $ra->get_log("", $head, 0, 1, 0, 1, sub { $head = $_[1] }) }; + warn "W: $@\n" if $@; + + my $base = defined $fetch ? $head : 0; + + # read the max revs for wildcard expansion (branches/*, tags/*) + foreach my $t (qw/branches tags/) { + defined $remote->{$t} or next; + push @globs, @{$remote->{$t}}; + + my $max_rev = eval { tmp_config(qw/--int --get/, + "svn-remote.$repo_id.${t}-maxRev") }; + if (defined $max_rev && ($max_rev < $base)) { + $base = $max_rev; + } elsif (!defined $max_rev) { + $base = 0; + } + } + + if ($fetch) { + foreach my $p (sort keys %$fetch) { + my $gs = Git::SVN->new($fetch->{$p}, $repo_id, $p); + my $lr = $gs->rev_map_max; + if (defined $lr) { + $base = $lr if ($lr < $base); + } + push @gs, $gs; + } + } + + ($base, $head) = parse_revision_argument($base, $head); + $ra->gs_fetch_loop_common($base, $head, \@gs, \@globs); +} + +sub read_all_remotes { + my $r = {}; + my $use_svm_props = eval { command_oneline(qw/config --bool + svn.useSvmProps/) }; + $use_svm_props = $use_svm_props eq 'true' if $use_svm_props; + my $svn_refspec = qr{\s*(.*?)\s*:\s*(.+?)\s*}; + foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) { + if (m!^(.+)\.fetch=$svn_refspec$!) { + my ($remote, $local_ref, $remote_ref) = ($1, $2, $3); + die("svn-remote.$remote: remote ref '$remote_ref' " + . "must start with 'refs/'\n") + unless $remote_ref =~ m{^refs/}; + $local_ref = uri_decode($local_ref); + $r->{$remote}->{fetch}->{$local_ref} = $remote_ref; + $r->{$remote}->{svm} = {} if $use_svm_props; + } elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) { + $r->{$1}->{svm} = {}; + } elsif (m!^(.+)\.url=\s*(.*)\s*$!) { + $r->{$1}->{url} = canonicalize_url($2); + } elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) { + $r->{$1}->{pushurl} = canonicalize_url($2); + } elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) { + $r->{$1}->{ignore_refs_regex} = $2; + } elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) { + my ($remote, $t, $local_ref, $remote_ref) = + ($1, $2, $3, $4); + die("svn-remote.$remote: remote ref '$remote_ref' ($t) " + . "must start with 'refs/'\n") + unless $remote_ref =~ m{^refs/}; + $local_ref = uri_decode($local_ref); + + require Git::SVN::GlobSpec; + my $rs = { + t => $t, + remote => $remote, + path => Git::SVN::GlobSpec->new($local_ref, 1), + ref => Git::SVN::GlobSpec->new($remote_ref, 0) }; + if (length($rs->{ref}->{right}) != 0) { + die "The '*' glob character must be the last ", + "character of '$remote_ref'\n"; + } + push @{ $r->{$remote}->{$t} }, $rs; + } + } + + map { + if (defined $r->{$_}->{svm}) { + my $svm; + eval { + my $section = "svn-remote.$_"; + $svm = { + source => tmp_config('--get', + "$section.svm-source"), + replace => tmp_config('--get', + "$section.svm-replace"), + } + }; + $r->{$_}->{svm} = $svm; + } + } keys %$r; + + foreach my $remote (keys %$r) { + foreach ( grep { defined $_ } + map { $r->{$remote}->{$_} } qw(branches tags) ) { + foreach my $rs ( @$_ ) { + $rs->{ignore_refs_regex} = + $r->{$remote}->{ignore_refs_regex}; + } + } + } + + $r; +} + +sub init_vars { + $_gc_nr = $_gc_period = 1000; + if (defined $_repack || defined $_repack_flags) { + warn "Repack options are obsolete; they have no effect.\n"; + } +} + +sub verify_remotes_sanity { + return unless -d $ENV{GIT_DIR}; + my %seen; + foreach (command(qw/config -l/)) { + if (m!^svn-remote\.(?:.+)\.fetch=.*:refs/remotes/(\S+)\s*$!) { + if ($seen{$1}) { + die "Remote ref refs/remote/$1 is tracked by", + "\n \"$_\"\nand\n \"$seen{$1}\"\n", + "Please resolve this ambiguity in ", + "your git configuration file before ", + "continuing\n"; + } + $seen{$1} = $_; + } + } +} + +sub find_existing_remote { + my ($url, $remotes) = @_; + return undef if $no_reuse_existing; + my $existing; + foreach my $repo_id (keys %$remotes) { + my $u = $remotes->{$repo_id}->{url} or next; + next if $u ne $url; + $existing = $repo_id; + last; + } + $existing; +} + +sub init_remote_config { + my ($self, $url, $no_write) = @_; + $url = canonicalize_url($url); + my $r = read_all_remotes(); + my $existing = find_existing_remote($url, $r); + if ($existing) { + unless ($no_write) { + print STDERR "Using existing ", + "[svn-remote \"$existing\"]\n"; + } + $self->{repo_id} = $existing; + } elsif ($_minimize_url) { + my $min_url = Git::SVN::Ra->new($url)->minimize_url; + $existing = find_existing_remote($min_url, $r); + if ($existing) { + unless ($no_write) { + print STDERR "Using existing ", + "[svn-remote \"$existing\"]\n"; + } + $self->{repo_id} = $existing; + } + if ($min_url ne $url) { + unless ($no_write) { + print STDERR "Using higher level of URL: ", + "$url => $min_url\n"; + } + my $old_path = $self->path; + $url =~ s!^\Q$min_url\E(/|$)!!; + $url = join_paths($url, $old_path); + $self->path($url); + $url = $min_url; + } + } + my $orig_url; + if (!$existing) { + # verify that we aren't overwriting anything: + $orig_url = eval { + command_oneline('config', '--get', + "svn-remote.$self->{repo_id}.url") + }; + if ($orig_url && ($orig_url ne $url)) { + die "svn-remote.$self->{repo_id}.url already set: ", + "$orig_url\nwanted to set to: $url\n"; + } + } + my ($xrepo_id, $xpath) = find_ref($self->refname); + if (!$no_write && defined $xpath) { + die "svn-remote.$xrepo_id.fetch already set to track ", + "$xpath:", $self->refname, "\n"; + } + unless ($no_write) { + command_noisy('config', + "svn-remote.$self->{repo_id}.url", $url); + my $path = $self->path; + $path =~ s{^/}{}; + $path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg; + $self->path($path); + command_noisy('config', '--add', + "svn-remote.$self->{repo_id}.fetch", + $self->path.":".$self->refname); + } + $self->url($url); +} + +sub find_by_url { # repos_root and, path are optional + my ($class, $full_url, $repos_root, $path) = @_; + + $full_url = canonicalize_url($full_url); + + return undef unless defined $full_url; + remove_username($full_url); + remove_username($repos_root) if defined $repos_root; + my $remotes = read_all_remotes(); + if (defined $full_url && defined $repos_root && !defined $path) { + $path = $full_url; + $path =~ s#^\Q$repos_root\E(?:/|$)##; + } + foreach my $repo_id (keys %$remotes) { + my $u = $remotes->{$repo_id}->{url} or next; + remove_username($u); + next if defined $repos_root && $repos_root ne $u; + + my $fetch = $remotes->{$repo_id}->{fetch} || {}; + foreach my $t (qw/branches tags/) { + foreach my $globspec (@{$remotes->{$repo_id}->{$t}}) { + resolve_local_globs($u, $fetch, $globspec); + } + } + my $p = $path; + my $rwr = rewrite_root({repo_id => $repo_id}); + my $svm = $remotes->{$repo_id}->{svm} + if defined $remotes->{$repo_id}->{svm}; + unless (defined $p) { + $p = $full_url; + my $z = $u; + my $prefix = ''; + if ($rwr) { + $z = $rwr; + remove_username($z); + } elsif (defined $svm) { + $z = $svm->{source}; + $prefix = $svm->{replace}; + $prefix =~ s#^\Q$u\E(?:/|$)##; + $prefix =~ s#/$##; + } + $p =~ s#^\Q$z\E(?:/|$)#$prefix# or next; + } + + # remote fetch paths are not URI escaped. Decode ours + # so they match + $p = uri_decode($p); + + foreach my $f (keys %$fetch) { + next if $f ne $p; + return Git::SVN->new($fetch->{$f}, $repo_id, $f); + } + } + undef; +} + +sub init { + my ($class, $url, $path, $repo_id, $ref_id, $no_write) = @_; + my $self = _new($class, $repo_id, $ref_id, $path); + if (defined $url) { + $self->init_remote_config($url, $no_write); + } + $self; +} + +sub find_ref { + my ($ref_id) = @_; + foreach (command(qw/config -l/)) { + next unless m!^svn-remote\.(.+)\.fetch= + \s*(.*?)\s*:\s*(.+?)\s*$!x; + my ($repo_id, $path, $ref) = ($1, $2, $3); + if ($ref eq $ref_id) { + $path = '' if ($path =~ m#^\./?#); + return ($repo_id, $path); + } + } + (undef, undef, undef); +} + +sub new { + my ($class, $ref_id, $repo_id, $path) = @_; + if (defined $ref_id && !defined $repo_id && !defined $path) { + ($repo_id, $path) = find_ref($ref_id); + if (!defined $repo_id) { + die "Could not find a \"svn-remote.*.fetch\" key ", + "in the repository configuration matching: ", + "$ref_id\n"; + } + } + my $self = _new($class, $repo_id, $ref_id, $path); + if (!defined $self->path || !length $self->path) { + my $fetch = command_oneline('config', '--get', + "svn-remote.$repo_id.fetch", + ":$ref_id\$") or + die "Failed to read \"svn-remote.$repo_id.fetch\" ", + "\":$ref_id\$\" in config\n"; + my($path) = split(/\s*:\s*/, $fetch); + $self->path($path); + } + { + my $path = $self->path; + $path =~ s{\A/}{}; + $path =~ s{/\z}{}; + $self->path($path); + } + my $url = command_oneline('config', '--get', + "svn-remote.$repo_id.url") or + die "Failed to read \"svn-remote.$repo_id.url\" in config\n"; + $self->url($url); + $self->{pushurl} = eval { command_oneline('config', '--get', + "svn-remote.$repo_id.pushurl") }; + $self->rebuild; + $self; +} + +sub refname { + my ($refname) = $_[0]->{ref_id} ; + + # It cannot end with a slash /, we'll throw up on this because + # SVN can't have directories with a slash in their name, either: + if ($refname =~ m{/$}) { + die "ref: '$refname' ends with a trailing slash, this is ", + "not permitted by git nor Subversion\n"; + } + + # It cannot have ASCII control character space, tilde ~, caret ^, + # colon :, question-mark ?, asterisk *, space, or open bracket [ + # anywhere. + # + # Additionally, % must be escaped because it is used for escaping + # and we want our escaped refname to be reversible + $refname =~ s{([ \%~\^:\?\*\[\t])}{uc sprintf('%%%02x',ord($1))}eg; + + # no slash-separated component can begin with a dot . + # /.* becomes /%2E* + $refname =~ s{/\.}{/%2E}g; + + # It cannot have two consecutive dots .. anywhere + # .. becomes %2E%2E + $refname =~ s{\.\.}{%2E%2E}g; + + # trailing dots and .lock are not allowed + # .$ becomes %2E and .lock becomes %2Elock + $refname =~ s{\.(?=$|lock$)}{%2E}; + + # the sequence @{ is used to access the reflog + # @{ becomes %40{ + $refname =~ s{\@\{}{%40\{}g; + + return $refname; +} + +sub desanitize_refname { + my ($refname) = @_; + $refname =~ s{%(?:([0-9A-F]{2}))}{chr hex($1)}eg; + return $refname; +} + +sub svm_uuid { + my ($self) = @_; + return $self->{svm}->{uuid} if $self->svm; + $self->ra; + unless ($self->{svm}) { + die "SVM UUID not cached, and reading remotely failed\n"; + } + $self->{svm}->{uuid}; +} + +sub svm { + my ($self) = @_; + return $self->{svm} if $self->{svm}; + my $svm; + # see if we have it in our config, first: + eval { + my $section = "svn-remote.$self->{repo_id}"; + $svm = { + source => tmp_config('--get', "$section.svm-source"), + uuid => tmp_config('--get', "$section.svm-uuid"), + replace => tmp_config('--get', "$section.svm-replace"), + } + }; + if ($svm && $svm->{source} && $svm->{uuid} && $svm->{replace}) { + $self->{svm} = $svm; + } + $self->{svm}; +} + +sub _set_svm_vars { + my ($self, $ra) = @_; + return $ra if $self->svm; + + my @err = ( "useSvmProps set, but failed to read SVM properties\n", + "(svm:source, svm:uuid) ", + "from the following URLs:\n" ); + sub read_svm_props { + my ($self, $ra, $path, $r) = @_; + my $props = ($ra->get_dir($path, $r))[2]; + my $src = $props->{'svm:source'}; + my $uuid = $props->{'svm:uuid'}; + return undef if (!$src || !$uuid); + + chomp($src, $uuid); + + $uuid =~ m{^[0-9a-f\-]{30,}$}i + or die "doesn't look right - svm:uuid is '$uuid'\n"; + + # the '!' is used to mark the repos_root!/relative/path + $src =~ s{/?!/?}{/}; + $src =~ s{/+$}{}; # no trailing slashes please + # username is of no interest + $src =~ s{(^[a-z\+]*://)[^/@]*@}{$1}; + + my $replace = add_path_to_url($ra->url, $path); + + my $section = "svn-remote.$self->{repo_id}"; + tmp_config("$section.svm-source", $src); + tmp_config("$section.svm-replace", $replace); + tmp_config("$section.svm-uuid", $uuid); + $self->{svm} = { + source => $src, + uuid => $uuid, + replace => $replace + }; + } + + my $r = $ra->get_latest_revnum; + my $path = $self->path; + my %tried; + while (length $path) { + my $try = add_path_to_url($self->url, $path); + unless ($tried{$try}) { + return $ra if $self->read_svm_props($ra, $path, $r); + $tried{$try} = 1; + } + $path =~ s#/?[^/]+$##; + } + die "Path: '$path' should be ''\n" if $path ne ''; + return $ra if $self->read_svm_props($ra, $path, $r); + $tried{ add_path_to_url($self->url, $path) } = 1; + + if ($ra->{repos_root} eq $self->url) { + die @err, (map { " $_\n" } keys %tried), "\n"; + } + + # nope, make sure we're connected to the repository root: + my $ok; + my @tried_b; + $path = $ra->{svn_path}; + $ra = Git::SVN::Ra->new($ra->{repos_root}); + while (length $path) { + my $try = add_path_to_url($ra->url, $path); + unless ($tried{$try}) { + $ok = $self->read_svm_props($ra, $path, $r); + last if $ok; + $tried{$try} = 1; + } + $path =~ s#/?[^/]+$##; + } + die "Path: '$path' should be ''\n" if $path ne ''; + $ok ||= $self->read_svm_props($ra, $path, $r); + $tried{ add_path_to_url($ra->url, $path) } = 1; + if (!$ok) { + die @err, (map { " $_\n" } keys %tried), "\n"; + } + Git::SVN::Ra->new($self->url); +} + +sub svnsync { + my ($self) = @_; + return $self->{svnsync} if $self->{svnsync}; + + if ($self->no_metadata) { + die "Can't have both 'noMetadata' and ", + "'useSvnsyncProps' options set!\n"; + } + if ($self->rewrite_root) { + die "Can't have both 'useSvnsyncProps' and 'rewriteRoot' ", + "options set!\n"; + } + if ($self->rewrite_uuid) { + die "Can't have both 'useSvnsyncProps' and 'rewriteUUID' ", + "options set!\n"; + } + + my $svnsync; + # see if we have it in our config, first: + eval { + my $section = "svn-remote.$self->{repo_id}"; + + my $url = tmp_config('--get', "$section.svnsync-url"); + ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or + die "doesn't look right - svn:sync-from-url is '$url'\n"; + + my $uuid = tmp_config('--get', "$section.svnsync-uuid"); + ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or + die "doesn't look right - svn:sync-from-uuid is '$uuid'\n"; + + $svnsync = { url => $url, uuid => $uuid } + }; + if ($svnsync && $svnsync->{url} && $svnsync->{uuid}) { + return $self->{svnsync} = $svnsync; + } + + my $err = "useSvnsyncProps set, but failed to read " . + "svnsync property: svn:sync-from-"; + my $rp = $self->ra->rev_proplist(0); + + my $url = $rp->{'svn:sync-from-url'} or die $err . "url\n"; + ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or + die "doesn't look right - svn:sync-from-url is '$url'\n"; + + my $uuid = $rp->{'svn:sync-from-uuid'} or die $err . "uuid\n"; + ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or + die "doesn't look right - svn:sync-from-uuid is '$uuid'\n"; + + my $section = "svn-remote.$self->{repo_id}"; + tmp_config('--add', "$section.svnsync-uuid", $uuid); + tmp_config('--add', "$section.svnsync-url", $url); + return $self->{svnsync} = { url => $url, uuid => $uuid }; +} + +# this allows us to memoize our SVN::Ra UUID locally and avoid a +# remote lookup (useful for 'git svn log'). +sub ra_uuid { + my ($self) = @_; + unless ($self->{ra_uuid}) { + my $key = "svn-remote.$self->{repo_id}.uuid"; + my $uuid = eval { tmp_config('--get', $key) }; + if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) { + $self->{ra_uuid} = $uuid; + } else { + die "ra_uuid called without URL\n" unless $self->url; + $self->{ra_uuid} = $self->ra->get_uuid; + tmp_config('--add', $key, $self->{ra_uuid}); + } + } + $self->{ra_uuid}; +} + +sub _set_repos_root { + my ($self, $repos_root) = @_; + my $k = "svn-remote.$self->{repo_id}.reposRoot"; + $repos_root ||= $self->ra->{repos_root}; + tmp_config($k, $repos_root); + $repos_root; +} + +sub repos_root { + my ($self) = @_; + my $k = "svn-remote.$self->{repo_id}.reposRoot"; + eval { tmp_config('--get', $k) } || $self->_set_repos_root; +} + +sub ra { + my ($self) = shift; + my $ra = Git::SVN::Ra->new($self->url); + $self->_set_repos_root($ra->{repos_root}); + if ($self->use_svm_props && !$self->{svm}) { + if ($self->no_metadata) { + die "Can't have both 'noMetadata' and ", + "'useSvmProps' options set!\n"; + } elsif ($self->use_svnsync_props) { + die "Can't have both 'useSvnsyncProps' and ", + "'useSvmProps' options set!\n"; + } + $ra = $self->_set_svm_vars($ra); + $self->{-want_revprops} = 1; + } + $ra; +} + +# prop_walk(PATH, REV, SUB) +# ------------------------- +# Recursively traverse PATH at revision REV and invoke SUB for each +# directory that contains a SVN property. SUB will be invoked as +# follows: &SUB(gs, path, props); where `gs' is this instance of +# Git::SVN, `path' the path to the directory where the properties +# `props' were found. The `path' will be relative to point of checkout, +# that is, if url://repo/trunk is the current Git branch, and that +# directory contains a sub-directory `d', SUB will be invoked with `/d/' +# as `path' (note the trailing `/'). +sub prop_walk { + my ($self, $path, $rev, $sub) = @_; + + $path =~ s#^/##; + my ($dirent, undef, $props) = $self->ra->get_dir($path, $rev); + $path =~ s#^/*#/#g; + my $p = $path; + # Strip the irrelevant part of the path. + $p =~ s#^/+\Q@{[$self->path]}\E(/|$)#/#; + # Ensure the path is terminated by a `/'. + $p =~ s#/*$#/#; + + # The properties contain all the internal SVN stuff nobody + # (usually) cares about. + my $interesting_props = 0; + foreach (keys %{$props}) { + # If it doesn't start with `svn:', it must be a + # user-defined property. + ++$interesting_props and next if $_ !~ /^svn:/; + # FIXME: Fragile, if SVN adds new public properties, + # this needs to be updated. + ++$interesting_props if /^svn:(?:ignore|keywords|executable + |eol-style|mime-type + |externals|needs-lock)$/x; + } + &$sub($self, $p, $props) if $interesting_props; + + foreach (sort keys %$dirent) { + next if $dirent->{$_}->{kind} != $SVN::Node::dir; + $self->prop_walk($self->path . $p . $_, $rev, $sub); + } +} + +sub last_rev { ($_[0]->last_rev_commit)[0] } +sub last_commit { ($_[0]->last_rev_commit)[1] } + +# returns the newest SVN revision number and newest commit SHA1 +sub last_rev_commit { + my ($self) = @_; + if (defined $self->{last_rev} && defined $self->{last_commit}) { + return ($self->{last_rev}, $self->{last_commit}); + } + my $c = ::verify_ref($self->refname.'^0'); + if ($c && !$self->use_svm_props && !$self->no_metadata) { + my $rev = (::cmt_metadata($c))[1]; + if (defined $rev) { + ($self->{last_rev}, $self->{last_commit}) = ($rev, $c); + return ($rev, $c); + } + } + my $map_path = $self->map_path; + unless (-e $map_path) { + ($self->{last_rev}, $self->{last_commit}) = (undef, undef); + return (undef, undef); + } + my ($rev, $commit) = $self->rev_map_max(1); + ($self->{last_rev}, $self->{last_commit}) = ($rev, $commit); + return ($rev, $commit); +} + +sub get_fetch_range { + my ($self, $min, $max) = @_; + $max ||= $self->ra->get_latest_revnum; + $min ||= $self->rev_map_max; + (++$min, $max); +} + +sub tmp_config { + my (@args) = @_; + my $old_def_config = "$ENV{GIT_DIR}/svn/config"; + my $config = "$ENV{GIT_DIR}/svn/.metadata"; + if (! -f $config && -f $old_def_config) { + rename $old_def_config, $config or + die "Failed rename $old_def_config => $config: $!\n"; + } + my $old_config = $ENV{GIT_CONFIG}; + $ENV{GIT_CONFIG} = $config; + $@ = undef; + my @ret = eval { + unless (-f $config) { + mkfile($config); + open my $fh, '>', $config or + die "Can't open $config: $!\n"; + print $fh "; This file is used internally by ", + "git-svn\n" or die + "Couldn't write to $config: $!\n"; + print $fh "; You should not have to edit it\n" or + die "Couldn't write to $config: $!\n"; + close $fh or die "Couldn't close $config: $!\n"; + } + command('config', @args); + }; + my $err = $@; + if (defined $old_config) { + $ENV{GIT_CONFIG} = $old_config; + } else { + delete $ENV{GIT_CONFIG}; + } + die $err if $err; + wantarray ? @ret : $ret[0]; +} + +sub tmp_index_do { + my ($self, $sub) = @_; + my $old_index = $ENV{GIT_INDEX_FILE}; + $ENV{GIT_INDEX_FILE} = $self->{index}; + $@ = undef; + my @ret = eval { + my ($dir, $base) = ($self->{index} =~ m#^(.*?)/?([^/]+)$#); + mkpath([$dir]) unless -d $dir; + &$sub; + }; + my $err = $@; + if (defined $old_index) { + $ENV{GIT_INDEX_FILE} = $old_index; + } else { + delete $ENV{GIT_INDEX_FILE}; + } + die $err if $err; + wantarray ? @ret : $ret[0]; +} + +sub assert_index_clean { + my ($self, $treeish) = @_; + + $self->tmp_index_do(sub { + command_noisy('read-tree', $treeish) unless -e $self->{index}; + my $x = command_oneline('write-tree'); + my ($y) = (command(qw/cat-file commit/, $treeish) =~ + /^tree ($::sha1)/mo); + return if $y eq $x; + + warn "Index mismatch: $y != $x\nrereading $treeish\n"; + unlink $self->{index} or die "unlink $self->{index}: $!\n"; + command_noisy('read-tree', $treeish); + $x = command_oneline('write-tree'); + if ($y ne $x) { + fatal "trees ($treeish) $y != $x\n", + "Something is seriously wrong..."; + } + }); +} + +sub get_commit_parents { + my ($self, $log_entry) = @_; + my (%seen, @ret, @tmp); + # legacy support for 'set-tree'; this is only used by set_tree_cb: + if (my $ip = $self->{inject_parents}) { + if (my $commit = delete $ip->{$log_entry->{revision}}) { + push @tmp, $commit; + } + } + if (my $cur = ::verify_ref($self->refname.'^0')) { + push @tmp, $cur; + } + if (my $ipd = $self->{inject_parents_dcommit}) { + if (my $commit = delete $ipd->{$log_entry->{revision}}) { + push @tmp, @$commit; + } + } + push @tmp, $_ foreach (@{$log_entry->{parents}}, @tmp); + while (my $p = shift @tmp) { + next if $seen{$p}; + $seen{$p} = 1; + push @ret, $p; + } + @ret; +} + +sub rewrite_root { + my ($self) = @_; + return $self->{-rewrite_root} if exists $self->{-rewrite_root}; + my $k = "svn-remote.$self->{repo_id}.rewriteRoot"; + my $rwr = eval { command_oneline(qw/config --get/, $k) }; + if ($rwr) { + $rwr =~ s#/+$##; + if ($rwr !~ m#^[a-z\+]+://#) { + die "$rwr is not a valid URL (key: $k)\n"; + } + } + $self->{-rewrite_root} = $rwr; +} + +sub rewrite_uuid { + my ($self) = @_; + return $self->{-rewrite_uuid} if exists $self->{-rewrite_uuid}; + my $k = "svn-remote.$self->{repo_id}.rewriteUUID"; + my $rwid = eval { command_oneline(qw/config --get/, $k) }; + if ($rwid) { + $rwid =~ s#/+$##; + if ($rwid !~ m#^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$#) { + die "$rwid is not a valid UUID (key: $k)\n"; + } + } + $self->{-rewrite_uuid} = $rwid; +} + +sub metadata_url { + my ($self) = @_; + my $url = $self->rewrite_root || $self->url; + return canonicalize_url( add_path_to_url( $url, $self->path ) ); +} + +sub full_url { + my ($self) = @_; + return canonicalize_url( add_path_to_url( $self->url, $self->path ) ); +} + +sub full_pushurl { + my ($self) = @_; + if ($self->{pushurl}) { + return canonicalize_url( add_path_to_url( $self->{pushurl}, $self->path ) ); + } else { + return $self->full_url; + } +} + +sub set_commit_header_env { + my ($log_entry) = @_; + my %env; + foreach my $ned (qw/NAME EMAIL DATE/) { + foreach my $ac (qw/AUTHOR COMMITTER/) { + $env{"GIT_${ac}_${ned}"} = $ENV{"GIT_${ac}_${ned}"}; + } + } + + $ENV{GIT_AUTHOR_NAME} = $log_entry->{name}; + $ENV{GIT_AUTHOR_EMAIL} = $log_entry->{email}; + $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_entry->{date}; + + $ENV{GIT_COMMITTER_NAME} = (defined $log_entry->{commit_name}) + ? $log_entry->{commit_name} + : $log_entry->{name}; + $ENV{GIT_COMMITTER_EMAIL} = (defined $log_entry->{commit_email}) + ? $log_entry->{commit_email} + : $log_entry->{email}; + \%env; +} + +sub restore_commit_header_env { + my ($env) = @_; + foreach my $ned (qw/NAME EMAIL DATE/) { + foreach my $ac (qw/AUTHOR COMMITTER/) { + my $k = "GIT_${ac}_${ned}"; + if (defined $env->{$k}) { + $ENV{$k} = $env->{$k}; + } else { + delete $ENV{$k}; + } + } + } +} + +sub gc { + command_noisy('gc', '--auto'); +}; + +sub do_git_commit { + my ($self, $log_entry) = @_; + my $lr = $self->last_rev; + if (defined $lr && $lr >= $log_entry->{revision}) { + die "Last fetched revision of ", $self->refname, + " was r$lr, but we are about to fetch: ", + "r$log_entry->{revision}!\n"; + } + if (my $c = $self->rev_map_get($log_entry->{revision})) { + croak "$log_entry->{revision} = $c already exists! ", + "Why are we refetching it?\n"; + } + my $old_env = set_commit_header_env($log_entry); + my $tree = $log_entry->{tree}; + if (!defined $tree) { + $tree = $self->tmp_index_do(sub { + command_oneline('write-tree') }); + } + die "Tree is not a valid sha1: $tree\n" if $tree !~ /^$::sha1$/o; + + my @exec = ('git', 'commit-tree', $tree); + foreach ($self->get_commit_parents($log_entry)) { + push @exec, '-p', $_; + } + defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec)) + or croak $!; + binmode $msg_fh; + + # we always get UTF-8 from SVN, but we may want our commits in + # a different encoding. + if (my $enc = Git::config('i18n.commitencoding')) { + require Encode; + Encode::from_to($log_entry->{log}, 'UTF-8', $enc); + } + print $msg_fh $log_entry->{log} or croak $!; + restore_commit_header_env($old_env); + unless ($self->no_metadata) { + print $msg_fh "\ngit-svn-id: $log_entry->{metadata}\n" + or croak $!; + } + $msg_fh->flush == 0 or croak $!; + close $msg_fh or croak $!; + chomp(my $commit = do { local $/; <$out_fh> }); + close $out_fh or croak $!; + waitpid $pid, 0; + croak $? if $?; + if ($commit !~ /^$::sha1$/o) { + die "Failed to commit, invalid sha1: $commit\n"; + } + + $self->rev_map_set($log_entry->{revision}, $commit, 1); + + $self->{last_rev} = $log_entry->{revision}; + $self->{last_commit} = $commit; + print "r$log_entry->{revision}" unless $::_q > 1; + if (defined $log_entry->{svm_revision}) { + print " (\@$log_entry->{svm_revision})" unless $::_q > 1; + $self->rev_map_set($log_entry->{svm_revision}, $commit, + 0, $self->svm_uuid); + } + print " = $commit ($self->{ref_id})\n" unless $::_q > 1; + if (--$_gc_nr == 0) { + $_gc_nr = $_gc_period; + gc(); + } + return $commit; +} + +sub match_paths { + my ($self, $paths, $r) = @_; + return 1 if $self->path eq ''; + if (my $path = $paths->{"/".$self->path}) { + return ($path->{action} eq 'D') ? 0 : 1; + } + $self->{path_regex} ||= qr{^/\Q@{[$self->path]}\E/}; + if (grep /$self->{path_regex}/, keys %$paths) { + return 1; + } + my $c = ''; + foreach (split m#/#, $self->path) { + $c .= "/$_"; + next unless ($paths->{$c} && + ($paths->{$c}->{action} =~ /^[AR]$/)); + if ($self->ra->check_path($self->path, $r) == + $SVN::Node::dir) { + return 1; + } + } + return 0; +} + +sub find_parent_branch { + my ($self, $paths, $rev) = @_; + return undef unless $self->follow_parent; + unless (defined $paths) { + my $err_handler = $SVN::Error::handler; + $SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs; + $self->ra->get_log([$self->path], $rev, $rev, 0, 1, 1, + sub { $paths = $_[0] }); + $SVN::Error::handler = $err_handler; + } + return undef unless defined $paths; + + # look for a parent from another branch: + my @b_path_components = split m#/#, $self->path; + my @a_path_components; + my $i; + while (@b_path_components) { + $i = $paths->{'/'.join('/', @b_path_components)}; + last if $i && defined $i->{copyfrom_path}; + unshift(@a_path_components, pop(@b_path_components)); + } + return undef unless defined $i && defined $i->{copyfrom_path}; + my $branch_from = $i->{copyfrom_path}; + if (@a_path_components) { + print STDERR "branch_from: $branch_from => "; + $branch_from .= '/'.join('/', @a_path_components); + print STDERR $branch_from, "\n"; + } + my $r = $i->{copyfrom_rev}; + my $repos_root = $self->ra->{repos_root}; + my $url = $self->ra->url; + my $new_url = canonicalize_url( add_path_to_url( $url, $branch_from ) ); + print STDERR "Found possible branch point: ", + "$new_url => ", $self->full_url, ", $r\n" + unless $::_q > 1; + $branch_from =~ s#^/##; + my $gs = $self->other_gs($new_url, $url, + $branch_from, $r, $self->{ref_id}); + my ($r0, $parent) = $gs->find_rev_before($r, 1); + { + my ($base, $head); + if (!defined $r0 || !defined $parent) { + ($base, $head) = parse_revision_argument(0, $r); + } else { + if ($r0 < $r) { + $gs->ra->get_log([$gs->path], $r0 + 1, $r, 1, + 0, 1, sub { $base = $_[1] - 1 }); + } + } + if (defined $base && $base <= $r) { + $gs->fetch($base, $r); + } + ($r0, $parent) = $gs->find_rev_before($r, 1); + } + if (defined $r0 && defined $parent) { + print STDERR "Found branch parent: ($self->{ref_id}) $parent\n" + unless $::_q > 1; + my $ed; + if ($self->ra->can_do_switch) { + $self->assert_index_clean($parent); + print STDERR "Following parent with do_switch\n" + unless $::_q > 1; + # do_switch works with svn/trunk >= r22312, but that + # is not included with SVN 1.4.3 (the latest version + # at the moment), so we can't rely on it + $self->{last_rev} = $r0; + $self->{last_commit} = $parent; + $ed = Git::SVN::Fetcher->new($self, $gs->path); + $gs->ra->gs_do_switch($r0, $rev, $gs, + $self->full_url, $ed) + or die "SVN connection failed somewhere...\n"; + } elsif ($self->ra->trees_match($new_url, $r0, + $self->full_url, $rev)) { + print STDERR "Trees match:\n", + " $new_url\@$r0\n", + " ${\$self->full_url}\@$rev\n", + "Following parent with no changes\n" + unless $::_q > 1; + $self->tmp_index_do(sub { + command_noisy('read-tree', $parent); + }); + $self->{last_commit} = $parent; + } else { + print STDERR "Following parent with do_update\n" + unless $::_q > 1; + $ed = Git::SVN::Fetcher->new($self); + $self->ra->gs_do_update($rev, $rev, $self, $ed) + or die "SVN connection failed somewhere...\n"; + } + print STDERR "Successfully followed parent\n" unless $::_q > 1; + return $self->make_log_entry($rev, [$parent], $ed); + } + return undef; +} + +sub do_fetch { + my ($self, $paths, $rev) = @_; + my $ed; + my ($last_rev, @parents); + if (my $lc = $self->last_commit) { + # we can have a branch that was deleted, then re-added + # under the same name but copied from another path, in + # which case we'll have multiple parents (we don't + # want to break the original ref, nor lose copypath info): + if (my $log_entry = $self->find_parent_branch($paths, $rev)) { + push @{$log_entry->{parents}}, $lc; + return $log_entry; + } + $ed = Git::SVN::Fetcher->new($self); + $last_rev = $self->{last_rev}; + $ed->{c} = $lc; + @parents = ($lc); + } else { + $last_rev = $rev; + if (my $log_entry = $self->find_parent_branch($paths, $rev)) { + return $log_entry; + } + $ed = Git::SVN::Fetcher->new($self); + } + unless ($self->ra->gs_do_update($last_rev, $rev, $self, $ed)) { + die "SVN connection failed somewhere...\n"; + } + $self->make_log_entry($rev, \@parents, $ed); +} + +sub mkemptydirs { + my ($self, $r) = @_; + + sub scan { + my ($r, $empty_dirs, $line) = @_; + if (defined $r && $line =~ /^r(\d+)$/) { + return 0 if $1 > $r; + } elsif ($line =~ /^ \+empty_dir: (.+)$/) { + $empty_dirs->{$1} = 1; + } elsif ($line =~ /^ \-empty_dir: (.+)$/) { + my @d = grep {m[^\Q$1\E(/|$)]} (keys %$empty_dirs); + delete @$empty_dirs{@d}; + } + 1; # continue + }; + + my %empty_dirs = (); + my $gz_file = "$self->{dir}/unhandled.log.gz"; + if (-f $gz_file) { + if (!can_compress()) { + warn "Compress::Zlib could not be found; ", + "empty directories in $gz_file will not be read\n"; + } else { + my $gz = Compress::Zlib::gzopen($gz_file, "rb") or + die "Unable to open $gz_file: $!\n"; + my $line; + while ($gz->gzreadline($line) > 0) { + scan($r, \%empty_dirs, $line) or last; + } + $gz->gzclose; + } + } + + if (open my $fh, '<', "$self->{dir}/unhandled.log") { + binmode $fh or croak "binmode: $!"; + while (<$fh>) { + scan($r, \%empty_dirs, $_) or last; + } + close $fh; + } + + my $strip = qr/\A\Q@{[$self->path]}\E(?:\/|$)/; + foreach my $d (sort keys %empty_dirs) { + $d = uri_decode($d); + $d =~ s/$strip//; + next unless length($d); + next if -d $d; + if (-e $d) { + warn "$d exists but is not a directory\n"; + } else { + print "creating empty directory: $d\n"; + mkpath([$d]); + } + } +} + +sub get_untracked { + my ($self, $ed) = @_; + my @out; + my $h = $ed->{empty}; + foreach (sort keys %$h) { + my $act = $h->{$_} ? '+empty_dir' : '-empty_dir'; + push @out, " $act: " . uri_encode($_); + warn "W: $act: $_\n"; + } + foreach my $t (qw/dir_prop file_prop/) { + $h = $ed->{$t} or next; + foreach my $path (sort keys %$h) { + my $ppath = $path eq '' ? '.' : $path; + foreach my $prop (sort keys %{$h->{$path}}) { + next if $SKIP_PROP{$prop}; + my $v = $h->{$path}->{$prop}; + my $t_ppath_prop = "$t: " . + uri_encode($ppath) . ' ' . + uri_encode($prop); + if (defined $v) { + push @out, " +$t_ppath_prop " . + uri_encode($v); + } else { + push @out, " -$t_ppath_prop"; + } + } + } + } + foreach my $t (qw/absent_file absent_directory/) { + $h = $ed->{$t} or next; + foreach my $parent (sort keys %$h) { + foreach my $path (sort @{$h->{$parent}}) { + push @out, " $t: " . + uri_encode("$parent/$path"); + warn "W: $t: $parent/$path ", + "Insufficient permissions?\n"; + } + } + } + \@out; +} + +sub get_tz { + # some systmes don't handle or mishandle %z, so be creative. + my $t = shift || time; + my $gm = timelocal(gmtime($t)); + my $sign = qw( + + - )[ $t <=> $gm ]; + return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]); +} + +# parse_svn_date(DATE) +# -------------------- +# Given a date (in UTC) from Subversion, return a string in the format +# "<TZ Offset> <local date/time>" that Git will use. +# +# By default the parsed date will be in UTC; if $Git::SVN::_localtime +# is true we'll convert it to the local timezone instead. +sub parse_svn_date { + my $date = shift || return '+0000 1970-01-01 00:00:00'; + my ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\d{4})\-(\d\d)\-(\d\d)T + (\d\d)\:(\d\d)\:(\d\d)\.\d*Z$/x) or + croak "Unable to parse date: $date\n"; + my $parsed_date; # Set next. + + if ($Git::SVN::_localtime) { + # Translate the Subversion datetime to an epoch time. + # Begin by switching ourselves to $date's timezone, UTC. + my $old_env_TZ = $ENV{TZ}; + $ENV{TZ} = 'UTC'; + + my $epoch_in_UTC = + POSIX::strftime('%s', $S, $M, $H, $d, $m - 1, $Y - 1900); + + # Determine our local timezone (including DST) at the + # time of $epoch_in_UTC. $Git::SVN::Log::TZ stored the + # value of TZ, if any, at the time we were run. + if (defined $Git::SVN::Log::TZ) { + $ENV{TZ} = $Git::SVN::Log::TZ; + } else { + delete $ENV{TZ}; + } + + my $our_TZ = get_tz(); + + # This converts $epoch_in_UTC into our local timezone. + my ($sec, $min, $hour, $mday, $mon, $year, + $wday, $yday, $isdst) = localtime($epoch_in_UTC); + + $parsed_date = sprintf('%s %04d-%02d-%02d %02d:%02d:%02d', + $our_TZ, $year + 1900, $mon + 1, + $mday, $hour, $min, $sec); + + # Reset us to the timezone in effect when we entered + # this routine. + if (defined $old_env_TZ) { + $ENV{TZ} = $old_env_TZ; + } else { + delete $ENV{TZ}; + } + } else { + $parsed_date = "+0000 $Y-$m-$d $H:$M:$S"; + } + + return $parsed_date; +} + +sub other_gs { + my ($self, $new_url, $url, + $branch_from, $r, $old_ref_id) = @_; + my $gs = Git::SVN->find_by_url($new_url, $url, $branch_from); + unless ($gs) { + my $ref_id = $old_ref_id; + $ref_id =~ s/\@\d+-*$//; + $ref_id .= "\@$r"; + # just grow a tail if we're not unique enough :x + $ref_id .= '-' while find_ref($ref_id); + my ($u, $p, $repo_id) = ($new_url, '', $ref_id); + if ($u =~ s#^\Q$url\E(/|$)##) { + $p = $u; + $u = $url; + $repo_id = $self->{repo_id}; + } + while (1) { + # It is possible to tag two different subdirectories at + # the same revision. If the url for an existing ref + # does not match, we must either find a ref with a + # matching url or create a new ref by growing a tail. + $gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1); + my (undef, $max_commit) = $gs->rev_map_max(1); + last if (!$max_commit); + my ($url) = ::cmt_metadata($max_commit); + last if ($url eq $gs->metadata_url); + $ref_id .= '-'; + } + print STDERR "Initializing parent: $ref_id\n" unless $::_q > 1; + } + $gs +} + +sub call_authors_prog { + my ($orig_author) = @_; + $orig_author = command_oneline('rev-parse', '--sq-quote', $orig_author); + my $author = `$::_authors_prog $orig_author`; + if ($? != 0) { + die "$::_authors_prog failed with exit code $?\n" + } + if ($author =~ /^\s*(.+?)\s*<(.*)>\s*$/) { + my ($name, $email) = ($1, $2); + $email = undef if length $2 == 0; + return [$name, $email]; + } else { + die "Author: $orig_author: $::_authors_prog returned " + . "invalid author format: $author\n"; + } +} + +sub check_author { + my ($author) = @_; + if (!defined $author || length $author == 0) { + $author = '(no author)'; + } + if (!defined $::users{$author}) { + if (defined $::_authors_prog) { + $::users{$author} = call_authors_prog($author); + } elsif (defined $::_authors) { + die "Author: $author not defined in $::_authors file\n"; + } + } + $author; +} + +sub find_extra_svk_parents { + my ($self, $ed, $tickets, $parents) = @_; + # aha! svk:merge property changed... + my @tickets = split "\n", $tickets; + my @known_parents; + for my $ticket ( @tickets ) { + my ($uuid, $path, $rev) = split /:/, $ticket; + if ( $uuid eq $self->ra_uuid ) { + my $repos_root = $self->url; + my $branch_from = $path; + $branch_from =~ s{^/}{}; + my $gs = $self->other_gs(add_path_to_url( $repos_root, $branch_from ), + $repos_root, + $branch_from, + $rev, + $self->{ref_id}); + if ( my $commit = $gs->rev_map_get($rev, $uuid) ) { + # wahey! we found it, but it might be + # an old one (!) + push @known_parents, [ $rev, $commit ]; + } + } + } + # Ordering matters; highest-numbered commit merge tickets + # first, as they may account for later merge ticket additions + # or changes. + @known_parents = map {$_->[1]} sort {$b->[0] <=> $a->[0]} @known_parents; + for my $parent ( @known_parents ) { + my @cmd = ('rev-list', $parent, map { "^$_" } @$parents ); + my ($msg_fh, $ctx) = command_output_pipe(@cmd); + my $new; + while ( <$msg_fh> ) { + $new=1;last; + } + command_close_pipe($msg_fh, $ctx); + if ( $new ) { + print STDERR + "Found merge parent (svk:merge ticket): $parent\n"; + push @$parents, $parent; + } + } +} + +sub lookup_svn_merge { + my $uuid = shift; + my $url = shift; + my $merge = shift; + + my ($source, $revs) = split ":", $merge; + my $path = $source; + $path =~ s{^/}{}; + my $gs = Git::SVN->find_by_url($url.$source, $url, $path); + if ( !$gs ) { + warn "Couldn't find revmap for $url$source\n"; + return; + } + my @ranges = split ",", $revs; + my ($tip, $tip_commit); + my @merged_commit_ranges; + # find the tip + for my $range ( @ranges ) { + my ($bottom, $top) = split "-", $range; + $top ||= $bottom; + my $bottom_commit = $gs->find_rev_after( $bottom, 1, $top ); + my $top_commit = $gs->find_rev_before( $top, 1, $bottom ); + + unless ($top_commit and $bottom_commit) { + warn "W:unknown path/rev in svn:mergeinfo " + ."dirprop: $source:$range\n"; + next; + } + + if (scalar(command('rev-parse', "$bottom_commit^@"))) { + push @merged_commit_ranges, + "$bottom_commit^..$top_commit"; + } else { + push @merged_commit_ranges, "$top_commit"; + } + + if ( !defined $tip or $top > $tip ) { + $tip = $top; + $tip_commit = $top_commit; + } + } + return ($tip_commit, @merged_commit_ranges); +} + +sub _rev_list { + my ($msg_fh, $ctx) = command_output_pipe( + "rev-list", @_, + ); + my @rv; + while ( <$msg_fh> ) { + chomp; + push @rv, $_; + } + command_close_pipe($msg_fh, $ctx); + @rv; +} + +sub check_cherry_pick { + my $base = shift; + my $tip = shift; + my $parents = shift; + my @ranges = @_; + my %commits = map { $_ => 1 } + _rev_list("--no-merges", $tip, "--not", $base, @$parents, "--"); + for my $range ( @ranges ) { + delete @commits{_rev_list($range, "--")}; + } + for my $commit (keys %commits) { + if (has_no_changes($commit)) { + delete $commits{$commit}; + } + } + return (keys %commits); +} + +sub has_no_changes { + my $commit = shift; + + my @revs = split / /, command_oneline( + qw(rev-list --parents -1 -m), $commit); + + # Commits with no parents, e.g. the start of a partial branch, + # have changes by definition. + return 1 if (@revs < 2); + + # Commits with multiple parents, e.g a merge, have no changes + # by definition. + return 0 if (@revs > 2); + + return (command_oneline("rev-parse", "$commit^{tree}") eq + command_oneline("rev-parse", "$commit~1^{tree}")); +} + +sub tie_for_persistent_memoization { + my $hash = shift; + my $path = shift; + + if ($can_use_yaml) { + tie %$hash => 'Git::SVN::Memoize::YAML', "$path.yaml"; + } else { + tie %$hash => 'Memoize::Storable', "$path.db", 'nstore'; + } +} + +# The GIT_DIR environment variable is not always set until after the command +# line arguments are processed, so we can't memoize in a BEGIN block. +{ + my $memoized = 0; + + sub memoize_svn_mergeinfo_functions { + return if $memoized; + $memoized = 1; + + my $cache_path = "$ENV{GIT_DIR}/svn/.caches/"; + mkpath([$cache_path]) unless -d $cache_path; + + my %lookup_svn_merge_cache; + my %check_cherry_pick_cache; + my %has_no_changes_cache; + + tie_for_persistent_memoization(\%lookup_svn_merge_cache, + "$cache_path/lookup_svn_merge"); + memoize 'lookup_svn_merge', + SCALAR_CACHE => 'FAULT', + LIST_CACHE => ['HASH' => \%lookup_svn_merge_cache], + ; + + tie_for_persistent_memoization(\%check_cherry_pick_cache, + "$cache_path/check_cherry_pick"); + memoize 'check_cherry_pick', + SCALAR_CACHE => 'FAULT', + LIST_CACHE => ['HASH' => \%check_cherry_pick_cache], + ; + + tie_for_persistent_memoization(\%has_no_changes_cache, + "$cache_path/has_no_changes"); + memoize 'has_no_changes', + SCALAR_CACHE => ['HASH' => \%has_no_changes_cache], + LIST_CACHE => 'FAULT', + ; + } + + sub unmemoize_svn_mergeinfo_functions { + return if not $memoized; + $memoized = 0; + + Memoize::unmemoize 'lookup_svn_merge'; + Memoize::unmemoize 'check_cherry_pick'; + Memoize::unmemoize 'has_no_changes'; + } + + sub clear_memoized_mergeinfo_caches { + die "Only call this method in non-memoized context" if ($memoized); + + my $cache_path = "$ENV{GIT_DIR}/svn/.caches/"; + return unless -d $cache_path; + + for my $cache_file (("$cache_path/lookup_svn_merge", + "$cache_path/check_cherry_pick", + "$cache_path/has_no_changes")) { + for my $suffix (qw(yaml db)) { + my $file = "$cache_file.$suffix"; + next unless -e $file; + unlink($file) or die "unlink($file) failed: $!\n"; + } + } + } + + + Memoize::memoize 'Git::SVN::repos_root'; +} + +END { + # Force cache writeout explicitly instead of waiting for + # global destruction to avoid segfault in Storable: + # http://rt.cpan.org/Public/Bug/Display.html?id=36087 + unmemoize_svn_mergeinfo_functions(); +} + +sub parents_exclude { + my $parents = shift; + my @commits = @_; + return unless @commits; + + my @excluded; + my $excluded; + do { + my @cmd = ('rev-list', "-1", @commits, "--not", @$parents ); + $excluded = command_oneline(@cmd); + if ( $excluded ) { + my @new; + my $found; + for my $commit ( @commits ) { + if ( $commit eq $excluded ) { + push @excluded, $commit; + $found++; + } + else { + push @new, $commit; + } + } + die "saw commit '$excluded' in rev-list output, " + ."but we didn't ask for that commit (wanted: @commits --not @$parents)" + unless $found; + @commits = @new; + } + } + while ($excluded and @commits); + + return @excluded; +} + + +# note: this function should only be called if the various dirprops +# have actually changed +sub find_extra_svn_parents { + my ($self, $ed, $mergeinfo, $parents) = @_; + # aha! svk:merge property changed... + + memoize_svn_mergeinfo_functions(); + + # We first search for merged tips which are not in our + # history. Then, we figure out which git revisions are in + # that tip, but not this revision. If all of those revisions + # are now marked as merge, we can add the tip as a parent. + my @merges = split "\n", $mergeinfo; + my @merge_tips; + my $url = $self->url; + my $uuid = $self->ra_uuid; + my @all_ranges; + for my $merge ( @merges ) { + my ($tip_commit, @ranges) = + lookup_svn_merge( $uuid, $url, $merge ); + unless (!$tip_commit or + grep { $_ eq $tip_commit } @$parents ) { + push @merge_tips, $tip_commit; + push @all_ranges, @ranges; + } else { + push @merge_tips, undef; + } + } + + my %excluded = map { $_ => 1 } + parents_exclude($parents, grep { defined } @merge_tips); + + # check merge tips for new parents + my @new_parents; + for my $merge_tip ( @merge_tips ) { + my $spec = shift @merges; + next unless $merge_tip and $excluded{$merge_tip}; + + # check out 'new' tips + my $merge_base; + eval { + $merge_base = command_oneline( + "merge-base", + @$parents, $merge_tip, + ); + }; + if ($@) { + die "An error occurred during merge-base" + unless $@->isa("Git::Error::Command"); + + warn "W: Cannot find common ancestor between ". + "@$parents and $merge_tip. Ignoring merge info.\n"; + next; + } + + # double check that there are no missing non-merge commits + my (@incomplete) = check_cherry_pick( + $merge_base, $merge_tip, + $parents, + @all_ranges, + ); + + if ( @incomplete ) { + warn "W:svn cherry-pick ignored ($spec) - missing " + .@incomplete." commit(s) (eg $incomplete[0])\n"; + } else { + warn + "Found merge parent (svn:mergeinfo prop): ", + $merge_tip, "\n"; + push @new_parents, $merge_tip; + } + } + + # cater for merges which merge commits from multiple branches + if ( @new_parents > 1 ) { + for ( my $i = 0; $i <= $#new_parents; $i++ ) { + for ( my $j = 0; $j <= $#new_parents; $j++ ) { + next if $i == $j; + next unless $new_parents[$i]; + next unless $new_parents[$j]; + my $revs = command_oneline( + "rev-list", "-1", + "$new_parents[$i]..$new_parents[$j]", + ); + if ( !$revs ) { + undef($new_parents[$j]); + } + } + } + } + push @$parents, grep { defined } @new_parents; +} + +sub make_log_entry { + my ($self, $rev, $parents, $ed) = @_; + my $untracked = $self->get_untracked($ed); + + my @parents = @$parents; + my $ps = $ed->{path_strip} || ""; + for my $path ( grep { m/$ps/ } %{$ed->{dir_prop}} ) { + my $props = $ed->{dir_prop}{$path}; + if ( $props->{"svk:merge"} ) { + $self->find_extra_svk_parents + ($ed, $props->{"svk:merge"}, \@parents); + } + if ( $props->{"svn:mergeinfo"} ) { + $self->find_extra_svn_parents + ($ed, + $props->{"svn:mergeinfo"}, + \@parents); + } + } + + open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!; + print $un "r$rev\n" or croak $!; + print $un $_, "\n" foreach @$untracked; + my %log_entry = ( parents => \@parents, revision => $rev, + log => ''); + + my $headrev; + my $logged = delete $self->{logged_rev_props}; + if (!$logged || $self->{-want_revprops}) { + my $rp = $self->ra->rev_proplist($rev); + foreach (sort keys %$rp) { + my $v = $rp->{$_}; + if (/^svn:(author|date|log)$/) { + $log_entry{$1} = $v; + } elsif ($_ eq 'svm:headrev') { + $headrev = $v; + } else { + print $un " rev_prop: ", uri_encode($_), ' ', + uri_encode($v), "\n"; + } + } + } else { + map { $log_entry{$_} = $logged->{$_} } keys %$logged; + } + close $un or croak $!; + + $log_entry{date} = parse_svn_date($log_entry{date}); + $log_entry{log} .= "\n"; + my $author = $log_entry{author} = check_author($log_entry{author}); + my ($name, $email) = defined $::users{$author} ? @{$::users{$author}} + : ($author, undef); + + my ($commit_name, $commit_email) = ($name, $email); + if ($_use_log_author) { + my $name_field; + if ($log_entry{log} =~ /From:\s+(.*\S)\s*\n/i) { + $name_field = $1; + } elsif ($log_entry{log} =~ /Signed-off-by:\s+(.*\S)\s*\n/i) { + $name_field = $1; + } + if (!defined $name_field) { + if (!defined $email) { + $email = $name; + } + } elsif ($name_field =~ /(.*?)\s+<(.*)>/) { + ($name, $email) = ($1, $2); + } elsif ($name_field =~ /(.*)@/) { + ($name, $email) = ($1, $name_field); + } else { + ($name, $email) = ($name_field, $name_field); + } + } + if (defined $headrev && $self->use_svm_props) { + if ($self->rewrite_root) { + die "Can't have both 'useSvmProps' and 'rewriteRoot' ", + "options set!\n"; + } + if ($self->rewrite_uuid) { + die "Can't have both 'useSvmProps' and 'rewriteUUID' ", + "options set!\n"; + } + my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}i; + # we don't want "SVM: initializing mirror for junk" ... + return undef if $r == 0; + my $svm = $self->svm; + if ($uuid ne $svm->{uuid}) { + die "UUID mismatch on SVM path:\n", + "expected: $svm->{uuid}\n", + " got: $uuid\n"; + } + my $full_url = $self->full_url; + $full_url =~ s#^\Q$svm->{replace}\E(/|$)#$svm->{source}$1# or + die "Failed to replace '$svm->{replace}' with ", + "'$svm->{source}' in $full_url\n"; + # throw away username for storing in records + remove_username($full_url); + $log_entry{metadata} = "$full_url\@$r $uuid"; + $log_entry{svm_revision} = $r; + $email ||= "$author\@$uuid"; + $commit_email ||= "$author\@$uuid"; + } elsif ($self->use_svnsync_props) { + my $full_url = canonicalize_url( + add_path_to_url( $self->svnsync->{url}, $self->path ) + ); + remove_username($full_url); + my $uuid = $self->svnsync->{uuid}; + $log_entry{metadata} = "$full_url\@$rev $uuid"; + $email ||= "$author\@$uuid"; + $commit_email ||= "$author\@$uuid"; + } else { + my $url = $self->metadata_url; + remove_username($url); + my $uuid = $self->rewrite_uuid || $self->ra->get_uuid; + $log_entry{metadata} = "$url\@$rev " . $uuid; + $email ||= "$author\@" . $uuid; + $commit_email ||= "$author\@" . $uuid; + } + $log_entry{name} = $name; + $log_entry{email} = $email; + $log_entry{commit_name} = $commit_name; + $log_entry{commit_email} = $commit_email; + \%log_entry; +} + +sub fetch { + my ($self, $min_rev, $max_rev, @parents) = @_; + my ($last_rev, $last_commit) = $self->last_rev_commit; + my ($base, $head) = $self->get_fetch_range($min_rev, $max_rev); + $self->ra->gs_fetch_loop_common($base, $head, [$self]); +} + +sub set_tree_cb { + my ($self, $log_entry, $tree, $rev, $date, $author) = @_; + $self->{inject_parents} = { $rev => $tree }; + $self->fetch(undef, undef); +} + +sub set_tree { + my ($self, $tree) = (shift, shift); + my $log_entry = ::get_commit_entry($tree); + unless ($self->{last_rev}) { + fatal("Must have an existing revision to commit"); + } + my %ed_opts = ( r => $self->{last_rev}, + log => $log_entry->{log}, + ra => $self->ra, + tree_a => $self->{last_commit}, + tree_b => $tree, + editor_cb => sub { + $self->set_tree_cb($log_entry, $tree, @_) }, + svn_path => $self->path ); + if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) { + print "No changes\nr$self->{last_rev} = $tree\n"; + } +} + +sub rebuild_from_rev_db { + my ($self, $path) = @_; + my $r = -1; + open my $fh, '<', $path or croak "open: $!"; + binmode $fh or croak "binmode: $!"; + while (<$fh>) { + length($_) == 41 or croak "inconsistent size in ($_) != 41"; + chomp($_); + ++$r; + next if $_ eq ('0' x 40); + $self->rev_map_set($r, $_); + print "r$r = $_\n"; + } + close $fh or croak "close: $!"; + unlink $path or croak "unlink: $!"; +} + +sub rebuild { + my ($self) = @_; + my $map_path = $self->map_path; + my $partial = (-e $map_path && ! -z $map_path); + return unless ::verify_ref($self->refname.'^0'); + if (!$partial && ($self->use_svm_props || $self->no_metadata)) { + my $rev_db = $self->rev_db_path; + $self->rebuild_from_rev_db($rev_db); + if ($self->use_svm_props) { + my $svm_rev_db = $self->rev_db_path($self->svm_uuid); + $self->rebuild_from_rev_db($svm_rev_db); + } + $self->unlink_rev_db_symlink; + return; + } + print "Rebuilding $map_path ...\n" if (!$partial); + my ($base_rev, $head) = ($partial ? $self->rev_map_max_norebuild(1) : + (undef, undef)); + my ($log, $ctx) = + command_output_pipe(qw/rev-list --pretty=raw --reverse/, + ($head ? "$head.." : "") . $self->refname, + '--'); + my $metadata_url = $self->metadata_url; + remove_username($metadata_url); + my $svn_uuid = $self->rewrite_uuid || $self->ra_uuid; + my $c; + while (<$log>) { + if ( m{^commit ($::sha1)$} ) { + $c = $1; + next; + } + next unless s{^\s*(git-svn-id:)}{$1}; + my ($url, $rev, $uuid) = ::extract_metadata($_); + remove_username($url); + + # ignore merges (from set-tree) + next if (!defined $rev || !$uuid); + + # if we merged or otherwise started elsewhere, this is + # how we break out of it + if (($uuid ne $svn_uuid) || + ($metadata_url && $url && ($url ne $metadata_url))) { + next; + } + if ($partial && $head) { + print "Partial-rebuilding $map_path ...\n"; + print "Currently at $base_rev = $head\n"; + $head = undef; + } + + $self->rev_map_set($rev, $c); + print "r$rev = $c\n"; + } + command_close_pipe($log, $ctx); + print "Done rebuilding $map_path\n" if (!$partial || !$head); + my $rev_db_path = $self->rev_db_path; + if (-f $self->rev_db_path) { + unlink $self->rev_db_path or croak "unlink: $!"; + } + $self->unlink_rev_db_symlink; +} + +# rev_map: +# Tie::File seems to be prone to offset errors if revisions get sparse, +# it's not that fast, either. Tie::File is also not in Perl 5.6. So +# one of my favorite modules is out :< Next up would be one of the DBM +# modules, but I'm not sure which is most portable... +# +# This is the replacement for the rev_db format, which was too big +# and inefficient for large repositories with a lot of sparse history +# (mainly tags) +# +# The format is this: +# - 24 bytes for every record, +# * 4 bytes for the integer representing an SVN revision number +# * 20 bytes representing the sha1 of a git commit +# - No empty padding records like the old format +# (except the last record, which can be overwritten) +# - new records are written append-only since SVN revision numbers +# increase monotonically +# - lookups on SVN revision number are done via a binary search +# - Piping the file to xxd -c24 is a good way of dumping it for +# viewing or editing (piped back through xxd -r), should the need +# ever arise. +# - The last record can be padding revision with an all-zero sha1 +# This is used to optimize fetch performance when using multiple +# "fetch" directives in .git/config +# +# These files are disposable unless noMetadata or useSvmProps is set + +sub _rev_map_set { + my ($fh, $rev, $commit) = @_; + + binmode $fh or croak "binmode: $!"; + my $size = (stat($fh))[7]; + ($size % 24) == 0 or croak "inconsistent size: $size"; + + my $wr_offset = 0; + if ($size > 0) { + sysseek($fh, -24, SEEK_END) or croak "seek: $!"; + my $read = sysread($fh, my $buf, 24) or croak "read: $!"; + $read == 24 or croak "read only $read bytes (!= 24)"; + my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf); + if ($last_commit eq ('0' x40)) { + if ($size >= 48) { + sysseek($fh, -48, SEEK_END) or croak "seek: $!"; + $read = sysread($fh, $buf, 24) or + croak "read: $!"; + $read == 24 or + croak "read only $read bytes (!= 24)"; + ($last_rev, $last_commit) = + unpack(rev_map_fmt, $buf); + if ($last_commit eq ('0' x40)) { + croak "inconsistent .rev_map\n"; + } + } + if ($last_rev >= $rev) { + croak "last_rev is higher!: $last_rev >= $rev"; + } + $wr_offset = -24; + } + } + sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!"; + syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or + croak "write: $!"; +} + +sub _rev_map_reset { + my ($fh, $rev, $commit) = @_; + my $c = _rev_map_get($fh, $rev); + $c eq $commit or die "_rev_map_reset(@_) commit $c does not match!\n"; + my $offset = sysseek($fh, 0, SEEK_CUR) or croak "seek: $!"; + truncate $fh, $offset or croak "truncate: $!"; +} + +sub mkfile { + my ($path) = @_; + unless (-e $path) { + my ($dir, $base) = ($path =~ m#^(.*?)/?([^/]+)$#); + mkpath([$dir]) unless -d $dir; + open my $fh, '>>', $path or die "Couldn't create $path: $!\n"; + close $fh or die "Couldn't close (create) $path: $!\n"; + } +} + +sub rev_map_set { + my ($self, $rev, $commit, $update_ref, $uuid) = @_; + defined $commit or die "missing arg3\n"; + length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n"; + my $db = $self->map_path($uuid); + my $db_lock = "$db.lock"; + my $sigmask; + $update_ref ||= 0; + if ($update_ref) { + $sigmask = POSIX::SigSet->new(); + my $signew = POSIX::SigSet->new(SIGINT, SIGHUP, SIGTERM, + SIGALRM, SIGUSR1, SIGUSR2); + sigprocmask(SIG_BLOCK, $signew, $sigmask) or + croak "Can't block signals: $!"; + } + mkfile($db); + + $LOCKFILES{$db_lock} = 1; + my $sync; + # both of these options make our .rev_db file very, very important + # and we can't afford to lose it because rebuild() won't work + if ($self->use_svm_props || $self->no_metadata) { + $sync = 1; + copy($db, $db_lock) or die "rev_map_set(@_): ", + "Failed to copy: ", + "$db => $db_lock ($!)\n"; + } else { + rename $db, $db_lock or die "rev_map_set(@_): ", + "Failed to rename: ", + "$db => $db_lock ($!)\n"; + } + + sysopen(my $fh, $db_lock, O_RDWR | O_CREAT) + or croak "Couldn't open $db_lock: $!\n"; + if ($update_ref eq 'reset') { + clear_memoized_mergeinfo_caches(); + _rev_map_reset($fh, $rev, $commit); + } else { + _rev_map_set($fh, $rev, $commit); + } + + if ($sync) { + $fh->flush or die "Couldn't flush $db_lock: $!\n"; + $fh->sync or die "Couldn't sync $db_lock: $!\n"; + } + close $fh or croak $!; + if ($update_ref) { + $_head = $self; + my $note = ""; + $note = " ($update_ref)" if ($update_ref !~ /^\d*$/); + command_noisy('update-ref', '-m', "r$rev$note", + $self->refname, $commit); + } + rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ", + "$db_lock => $db ($!)\n"; + delete $LOCKFILES{$db_lock}; + if ($update_ref) { + sigprocmask(SIG_SETMASK, $sigmask) or + croak "Can't restore signal mask: $!"; + } +} + +# If want_commit, this will return an array of (rev, commit) where +# commit _must_ be a valid commit in the archive. +# Otherwise, it'll return the max revision (whether or not the +# commit is valid or just a 0x40 placeholder). +sub rev_map_max { + my ($self, $want_commit) = @_; + $self->rebuild; + my ($r, $c) = $self->rev_map_max_norebuild($want_commit); + $want_commit ? ($r, $c) : $r; +} + +sub rev_map_max_norebuild { + my ($self, $want_commit) = @_; + my $map_path = $self->map_path; + stat $map_path or return $want_commit ? (0, undef) : 0; + sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!"; + binmode $fh or croak "binmode: $!"; + my $size = (stat($fh))[7]; + ($size % 24) == 0 or croak "inconsistent size: $size"; + + if ($size == 0) { + close $fh or croak "close: $!"; + return $want_commit ? (0, undef) : 0; + } + + sysseek($fh, -24, SEEK_END) or croak "seek: $!"; + sysread($fh, my $buf, 24) == 24 or croak "read: $!"; + my ($r, $c) = unpack(rev_map_fmt, $buf); + if ($want_commit && $c eq ('0' x40)) { + if ($size < 48) { + return $want_commit ? (0, undef) : 0; + } + sysseek($fh, -48, SEEK_END) or croak "seek: $!"; + sysread($fh, $buf, 24) == 24 or croak "read: $!"; + ($r, $c) = unpack(rev_map_fmt, $buf); + if ($c eq ('0'x40)) { + croak "Penultimate record is all-zeroes in $map_path"; + } + } + close $fh or croak "close: $!"; + $want_commit ? ($r, $c) : $r; +} + +sub rev_map_get { + my ($self, $rev, $uuid) = @_; + my $map_path = $self->map_path($uuid); + return undef unless -e $map_path; + + sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!"; + my $c = _rev_map_get($fh, $rev); + close($fh) or croak "close: $!"; + $c +} + +sub _rev_map_get { + my ($fh, $rev) = @_; + + binmode $fh or croak "binmode: $!"; + my $size = (stat($fh))[7]; + ($size % 24) == 0 or croak "inconsistent size: $size"; + + if ($size == 0) { + return undef; + } + + my ($l, $u) = (0, $size - 24); + my ($r, $c, $buf); + + while ($l <= $u) { + my $i = int(($l/24 + $u/24) / 2) * 24; + sysseek($fh, $i, SEEK_SET) or croak "seek: $!"; + sysread($fh, my $buf, 24) == 24 or croak "read: $!"; + my ($r, $c) = unpack(rev_map_fmt, $buf); + + if ($r < $rev) { + $l = $i + 24; + } elsif ($r > $rev) { + $u = $i - 24; + } else { # $r == $rev + return $c eq ('0' x 40) ? undef : $c; + } + } + undef; +} + +# Finds the first svn revision that exists on (if $eq_ok is true) or +# before $rev for the current branch. It will not search any lower +# than $min_rev. Returns the git commit hash and svn revision number +# if found, else (undef, undef). +sub find_rev_before { + my ($self, $rev, $eq_ok, $min_rev) = @_; + --$rev unless $eq_ok; + $min_rev ||= 1; + my $max_rev = $self->rev_map_max; + $rev = $max_rev if ($rev > $max_rev); + while ($rev >= $min_rev) { + if (my $c = $self->rev_map_get($rev)) { + return ($rev, $c); + } + --$rev; + } + return (undef, undef); +} + +# Finds the first svn revision that exists on (if $eq_ok is true) or +# after $rev for the current branch. It will not search any higher +# than $max_rev. Returns the git commit hash and svn revision number +# if found, else (undef, undef). +sub find_rev_after { + my ($self, $rev, $eq_ok, $max_rev) = @_; + ++$rev unless $eq_ok; + $max_rev ||= $self->rev_map_max; + while ($rev <= $max_rev) { + if (my $c = $self->rev_map_get($rev)) { + return ($rev, $c); + } + ++$rev; + } + return (undef, undef); +} + +sub _new { + my ($class, $repo_id, $ref_id, $path) = @_; + unless (defined $repo_id && length $repo_id) { + $repo_id = $default_repo_id; + } + unless (defined $ref_id && length $ref_id) { + # Access the prefix option from the git-svn main program if it's loaded. + my $prefix = defined &::opt_prefix ? ::opt_prefix() : ""; + $_[2] = $ref_id = + "refs/remotes/$prefix$default_ref_id"; + } + $_[1] = $repo_id; + my $dir = "$ENV{GIT_DIR}/svn/$ref_id"; + + # Older repos imported by us used $GIT_DIR/svn/foo instead of + # $GIT_DIR/svn/refs/remotes/foo when tracking refs/remotes/foo + if ($ref_id =~ m{^refs/remotes/(.*)}) { + my $old_dir = "$ENV{GIT_DIR}/svn/$1"; + if (-d $old_dir && ! -d $dir) { + $dir = $old_dir; + } + } + + $_[3] = $path = '' unless (defined $path); + mkpath([$dir]); + my $obj = bless { + ref_id => $ref_id, dir => $dir, index => "$dir/index", + config => "$ENV{GIT_DIR}/svn/config", + map_root => "$dir/.rev_map", repo_id => $repo_id }, $class; + + # Ensure it gets canonicalized + $obj->path($path); + + return $obj; +} + +sub path { + my $self = shift; + + if (@_) { + my $path = shift; + $self->{_path} = canonicalize_path($path); + return; + } + + return $self->{_path}; +} + +sub url { + my $self = shift; + + if (@_) { + my $url = shift; + $self->{url} = canonicalize_url($url); + return; + } + + return $self->{url}; +} + +# for read-only access of old .rev_db formats +sub unlink_rev_db_symlink { + my ($self) = @_; + my $link = $self->rev_db_path; + $link =~ s/\.[\w-]+$// or croak "missing UUID at the end of $link"; + if (-l $link) { + unlink $link or croak "unlink: $link failed!"; + } +} + +sub rev_db_path { + my ($self, $uuid) = @_; + my $db_path = $self->map_path($uuid); + $db_path =~ s{/\.rev_map\.}{/\.rev_db\.} + or croak "map_path: $db_path does not contain '/.rev_map.' !"; + $db_path; +} + +# the new replacement for .rev_db +sub map_path { + my ($self, $uuid) = @_; + $uuid ||= $self->ra_uuid; + "$self->{map_root}.$uuid"; +} + +sub uri_encode { + my ($f) = @_; + $f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg; + $f +} + +sub uri_decode { + my ($f) = @_; + $f =~ s#%([0-9a-fA-F]{2})#chr(hex($1))#eg; + $f +} + +sub remove_username { + $_[0] =~ s{^([^:]*://)[^@]+@}{$1}; +} + +1; diff --git a/perl/Git/SVN/Editor.pm b/perl/Git/SVN/Editor.pm index 755092fdf..3bbc20a05 100644 --- a/perl/Git/SVN/Editor.pm +++ b/perl/Git/SVN/Editor.pm @@ -345,7 +345,30 @@ sub M { $self->close_file($fbat,undef,$self->{pool}); } -sub T { shift->M(@_) } +sub T { + my ($self, $m, $deletions) = @_; + + # Work around subversion issue 4091: toggling the "is a + # symlink" property requires removing and re-adding a + # file or else "svn up" on affected clients trips an + # assertion and aborts. + if (($m->{mode_b} =~ /^120/ && $m->{mode_a} !~ /^120/) || + ($m->{mode_b} !~ /^120/ && $m->{mode_a} =~ /^120/)) { + $self->D({ + mode_a => $m->{mode_a}, mode_b => '000000', + sha1_a => $m->{sha1_a}, sha1_b => '0' x 40, + chg => 'D', file_b => $m->{file_b} + }); + $self->A({ + mode_a => '000000', mode_b => $m->{mode_b}, + sha1_a => '0' x 40, sha1_b => $m->{sha1_b}, + chg => 'A', file_b => $m->{file_b} + }); + return; + } + + $self->M($m, $deletions); +} sub change_file_prop { my ($self, $fbat, $pname, $pval) = @_; diff --git a/perl/Git/SVN/Fetcher.pm b/perl/Git/SVN/Fetcher.pm index ef8e9ed2a..046a7a2f3 100644 --- a/perl/Git/SVN/Fetcher.pm +++ b/perl/Git/SVN/Fetcher.pm @@ -57,6 +57,7 @@ sub new { $self->{file_prop} = {}; $self->{absent_dir} = {}; $self->{absent_file} = {}; + require Git::IndexInfo; $self->{gii} = $git_svn->tmp_index_do(sub { Git::IndexInfo->new }); $self->{pathnameencoding} = Git::config('svn.pathnameencoding'); $self; @@ -82,7 +83,7 @@ sub _mark_empty_symlinks { chomp(my $empty_blob = `git hash-object -t blob --stdin < /dev/null`); my ($ls, $ctx) = command_output_pipe(qw/ls-tree -r -z/, $cmt); local $/ = "\0"; - my $pfx = defined($switch_path) ? $switch_path : $git_svn->{path}; + my $pfx = defined($switch_path) ? $switch_path : $git_svn->path; $pfx .= '/' if length($pfx); while (<$ls>) { chomp; diff --git a/perl/Git/SVN/GlobSpec.pm b/perl/Git/SVN/GlobSpec.pm new file mode 100644 index 000000000..c95f5d76c --- /dev/null +++ b/perl/Git/SVN/GlobSpec.pm @@ -0,0 +1,61 @@ +package Git::SVN::GlobSpec; +use strict; +use warnings; + +sub new { + my ($class, $glob, $pattern_ok) = @_; + my $re = $glob; + $re =~ s!/+$!!g; # no need for trailing slashes + my (@left, @right, @patterns); + my $state = "left"; + my $die_msg = "Only one set of wildcard directories " . + "(e.g. '*' or '*/*/*') is supported: '$glob'\n"; + for my $part (split(m|/|, $glob)) { + if ($part =~ /\*/ && $part ne "*") { + die "Invalid pattern in '$glob': $part\n"; + } elsif ($pattern_ok && $part =~ /[{}]/ && + $part !~ /^\{[^{}]+\}/) { + die "Invalid pattern in '$glob': $part\n"; + } + if ($part eq "*") { + die $die_msg if $state eq "right"; + $state = "pattern"; + push(@patterns, "[^/]*"); + } elsif ($pattern_ok && $part =~ /^\{(.*)\}$/) { + die $die_msg if $state eq "right"; + $state = "pattern"; + my $p = quotemeta($1); + $p =~ s/\\,/|/g; + push(@patterns, "(?:$p)"); + } else { + if ($state eq "left") { + push(@left, $part); + } else { + push(@right, $part); + $state = "right"; + } + } + } + my $depth = @patterns; + if ($depth == 0) { + die "One '*' is needed in glob: '$glob'\n"; + } + my $left = join('/', @left); + my $right = join('/', @right); + $re = join('/', @patterns); + $re = join('\/', + grep(length, quotemeta($left), + "($re)(?=/|\$)", + quotemeta($right))); + my $left_re = qr/^\/\Q$left\E(\/|$)/; + bless { left => $left, right => $right, left_regex => $left_re, + regex => qr/$re/, glob => $glob, depth => $depth }, $class; +} + +sub full_path { + my ($self, $path) = @_; + return (length $self->{left} ? "$self->{left}/" : '') . + $path . (length $self->{right} ? "/$self->{right}" : ''); +} + +1; diff --git a/perl/Git/SVN/Log.pm b/perl/Git/SVN/Log.pm new file mode 100644 index 000000000..3cc1c6f08 --- /dev/null +++ b/perl/Git/SVN/Log.pm @@ -0,0 +1,395 @@ +package Git::SVN::Log; +use strict; +use warnings; +use Git::SVN::Utils qw(fatal); +use Git qw(command command_oneline command_output_pipe command_close_pipe); +use POSIX qw/strftime/; +use constant commit_log_separator => ('-' x 72) . "\n"; +use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline + %rusers $show_commit $incremental/; + +# Option set in git-svn +our $_git_format; + +sub cmt_showable { + my ($c) = @_; + return 1 if defined $c->{r}; + + # big commit message got truncated by the 16k pretty buffer in rev-list + if ($c->{l} && $c->{l}->[-1] eq "...\n" && + $c->{a_raw} =~ /\@([a-f\d\-]+)>$/) { + @{$c->{l}} = (); + my @log = command(qw/cat-file commit/, $c->{c}); + + # shift off the headers + shift @log while ($log[0] ne ''); + shift @log; + + # TODO: make $c->{l} not have a trailing newline in the future + @{$c->{l}} = map { "$_\n" } grep !/^git-svn-id: /, @log; + + (undef, $c->{r}, undef) = ::extract_metadata( + (grep(/^git-svn-id: /, @log))[-1]); + } + return defined $c->{r}; +} + +sub log_use_color { + return $color || Git->repository->get_colorbool('color.diff'); +} + +sub git_svn_log_cmd { + my ($r_min, $r_max, @args) = @_; + my $head = 'HEAD'; + my (@files, @log_opts); + foreach my $x (@args) { + if ($x eq '--' || @files) { + push @files, $x; + } else { + if (::verify_ref("$x^0")) { + $head = $x; + } else { + push @log_opts, $x; + } + } + } + + my ($url, $rev, $uuid, $gs) = ::working_head_info($head); + + require Git::SVN; + $gs ||= Git::SVN->_new; + my @cmd = (qw/log --abbrev-commit --pretty=raw --default/, + $gs->refname); + push @cmd, '-r' unless $non_recursive; + push @cmd, qw/--raw --name-status/ if $verbose; + push @cmd, '--color' if log_use_color(); + push @cmd, @log_opts; + if (defined $r_max && $r_max == $r_min) { + push @cmd, '--max-count=1'; + if (my $c = $gs->rev_map_get($r_max)) { + push @cmd, $c; + } + } elsif (defined $r_max) { + if ($r_max < $r_min) { + ($r_min, $r_max) = ($r_max, $r_min); + } + my (undef, $c_max) = $gs->find_rev_before($r_max, 1, $r_min); + my (undef, $c_min) = $gs->find_rev_after($r_min, 1, $r_max); + # If there are no commits in the range, both $c_max and $c_min + # will be undefined. If there is at least 1 commit in the + # range, both will be defined. + return () if !defined $c_min || !defined $c_max; + if ($c_min eq $c_max) { + push @cmd, '--max-count=1', $c_min; + } else { + push @cmd, '--boundary', "$c_min..$c_max"; + } + } + return (@cmd, @files); +} + +# adapted from pager.c +sub config_pager { + if (! -t *STDOUT) { + $ENV{GIT_PAGER_IN_USE} = 'false'; + $pager = undef; + return; + } + chomp($pager = command_oneline(qw(var GIT_PAGER))); + if ($pager eq 'cat') { + $pager = undef; + } + $ENV{GIT_PAGER_IN_USE} = defined($pager); +} + +sub run_pager { + return unless defined $pager; + pipe my ($rfd, $wfd) or return; + defined(my $pid = fork) or fatal "Can't fork: $!"; + if (!$pid) { + open STDOUT, '>&', $wfd or + fatal "Can't redirect to stdout: $!"; + return; + } + open STDIN, '<&', $rfd or fatal "Can't redirect stdin: $!"; + $ENV{LESS} ||= 'FRSX'; + exec $pager or fatal "Can't run pager: $! ($pager)"; +} + +sub format_svn_date { + my $t = shift || time; + require Git::SVN; + my $gmoff = Git::SVN::get_tz($t); + return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t)); +} + +sub parse_git_date { + my ($t, $tz) = @_; + # Date::Parse isn't in the standard Perl distro :( + if ($tz =~ s/^\+//) { + $t += tz_to_s_offset($tz); + } elsif ($tz =~ s/^\-//) { + $t -= tz_to_s_offset($tz); + } + return $t; +} + +sub set_local_timezone { + if (defined $TZ) { + $ENV{TZ} = $TZ; + } else { + delete $ENV{TZ}; + } +} + +sub tz_to_s_offset { + my ($tz) = @_; + $tz =~ s/(\d\d)$//; + return ($1 * 60) + ($tz * 3600); +} + +sub get_author_info { + my ($dest, $author, $t, $tz) = @_; + $author =~ s/(?:^\s*|\s*$)//g; + $dest->{a_raw} = $author; + my $au; + if ($::_authors) { + $au = $rusers{$author} || undef; + } + if (!$au) { + ($au) = ($author =~ /<([^>]+)\@[^>]+>$/); + } + $dest->{t} = $t; + $dest->{tz} = $tz; + $dest->{a} = $au; + $dest->{t_utc} = parse_git_date($t, $tz); +} + +sub process_commit { + my ($c, $r_min, $r_max, $defer) = @_; + if (defined $r_min && defined $r_max) { + if ($r_min == $c->{r} && $r_min == $r_max) { + show_commit($c); + return 0; + } + return 1 if $r_min == $r_max; + if ($r_min < $r_max) { + # we need to reverse the print order + return 0 if (defined $limit && --$limit < 0); + push @$defer, $c; + return 1; + } + if ($r_min != $r_max) { + return 1 if ($r_min < $c->{r}); + return 1 if ($r_max > $c->{r}); + } + } + return 0 if (defined $limit && --$limit < 0); + show_commit($c); + return 1; +} + +my $l_fmt; +sub show_commit { + my $c = shift; + if ($oneline) { + my $x = "\n"; + if (my $l = $c->{l}) { + while ($l->[0] =~ /^\s*$/) { shift @$l } + $x = $l->[0]; + } + $l_fmt ||= 'A' . length($c->{r}); + print 'r',pack($l_fmt, $c->{r}),' | '; + print "$c->{c} | " if $show_commit; + print $x; + } else { + show_commit_normal($c); + } +} + +sub show_commit_changed_paths { + my ($c) = @_; + return unless $c->{changed}; + print "Changed paths:\n", @{$c->{changed}}; +} + +sub show_commit_normal { + my ($c) = @_; + print commit_log_separator, "r$c->{r} | "; + print "$c->{c} | " if $show_commit; + print "$c->{a} | ", format_svn_date($c->{t_utc}), ' | '; + my $nr_line = 0; + + if (my $l = $c->{l}) { + while ($l->[$#$l] eq "\n" && $#$l > 0 + && $l->[($#$l - 1)] eq "\n") { + pop @$l; + } + $nr_line = scalar @$l; + if (!$nr_line) { + print "1 line\n\n\n"; + } else { + if ($nr_line == 1) { + $nr_line = '1 line'; + } else { + $nr_line .= ' lines'; + } + print $nr_line, "\n"; + show_commit_changed_paths($c); + print "\n"; + print $_ foreach @$l; + } + } else { + print "1 line\n"; + show_commit_changed_paths($c); + print "\n"; + + } + foreach my $x (qw/raw stat diff/) { + if ($c->{$x}) { + print "\n"; + print $_ foreach @{$c->{$x}} + } + } +} + +sub cmd_show_log { + my (@args) = @_; + my ($r_min, $r_max); + my $r_last = -1; # prevent dupes + set_local_timezone(); + if (defined $::_revision) { + if ($::_revision =~ /^(\d+):(\d+)$/) { + ($r_min, $r_max) = ($1, $2); + } elsif ($::_revision =~ /^\d+$/) { + $r_min = $r_max = $::_revision; + } else { + fatal "-r$::_revision is not supported, use ", + "standard 'git log' arguments instead"; + } + } + + config_pager(); + @args = git_svn_log_cmd($r_min, $r_max, @args); + if (!@args) { + print commit_log_separator unless $incremental || $oneline; + return; + } + my $log = command_output_pipe(@args); + run_pager(); + my (@k, $c, $d, $stat); + my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/; + while (<$log>) { + if (/^${esc_color}commit (?:- )?($::sha1_short)/o) { + my $cmt = $1; + if ($c && cmt_showable($c) && $c->{r} != $r_last) { + $r_last = $c->{r}; + process_commit($c, $r_min, $r_max, \@k) or + goto out; + } + $d = undef; + $c = { c => $cmt }; + } elsif (/^${esc_color}author (.+) (\d+) ([\-\+]?\d+)$/o) { + get_author_info($c, $1, $2, $3); + } elsif (/^${esc_color}(?:tree|parent|committer) /o) { + # ignore + } elsif (/^${esc_color}:\d{6} \d{6} $::sha1_short/o) { + push @{$c->{raw}}, $_; + } elsif (/^${esc_color}[ACRMDT]\t/) { + # we could add $SVN->{svn_path} here, but that requires + # remote access at the moment (repo_path_split)... + s#^(${esc_color})([ACRMDT])\t#$1 $2 #o; + push @{$c->{changed}}, $_; + } elsif (/^${esc_color}diff /o) { + $d = 1; + push @{$c->{diff}}, $_; + } elsif ($d) { + push @{$c->{diff}}, $_; + } elsif (/^\ .+\ \|\s*\d+\ $esc_color[\+\-]* + $esc_color*[\+\-]*$esc_color$/x) { + $stat = 1; + push @{$c->{stat}}, $_; + } elsif ($stat && /^ \d+ files changed, \d+ insertions/) { + push @{$c->{stat}}, $_; + $stat = undef; + } elsif (/^${esc_color} (git-svn-id:.+)$/o) { + ($c->{url}, $c->{r}, undef) = ::extract_metadata($1); + } elsif (s/^${esc_color} //o) { + push @{$c->{l}}, $_; + } + } + if ($c && defined $c->{r} && $c->{r} != $r_last) { + $r_last = $c->{r}; + process_commit($c, $r_min, $r_max, \@k); + } + if (@k) { + ($r_min, $r_max) = ($r_max, $r_min); + process_commit($_, $r_min, $r_max) foreach reverse @k; + } +out: + close $log; + print commit_log_separator unless $incremental || $oneline; +} + +sub cmd_blame { + my $path = pop; + + config_pager(); + run_pager(); + + my ($fh, $ctx, $rev); + + if ($_git_format) { + ($fh, $ctx) = command_output_pipe('blame', @_, $path); + while (my $line = <$fh>) { + if ($line =~ /^\^?([[:xdigit:]]+)\s/) { + # Uncommitted edits show up as a rev ID of + # all zeros, which we can't look up with + # cmt_metadata + if ($1 !~ /^0+$/) { + (undef, $rev, undef) = + ::cmt_metadata($1); + $rev = '0' if (!$rev); + } else { + $rev = '0'; + } + $rev = sprintf('%-10s', $rev); + $line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/; + } + print $line; + } + } else { + ($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD', + '--', $path); + my ($sha1); + my %authors; + my @buffer; + my %dsha; #distinct sha keys + + while (my $line = <$fh>) { + push @buffer, $line; + if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) { + $dsha{$1} = 1; + } + } + + my $s2r = ::cmt_sha2rev_batch([keys %dsha]); + + foreach my $line (@buffer) { + if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) { + $rev = $s2r->{$1}; + $rev = '0' if (!$rev) + } + elsif ($line =~ /^author (.*)/) { + $authors{$rev} = $1; + $authors{$rev} =~ s/\s/_/g; + } + elsif ($line =~ /^\t(.*)$/) { + printf("%6s %10s %s\n", $rev, $authors{$rev}, $1); + } + } + } + command_close_pipe($fh, $ctx); +} + +1; diff --git a/perl/Git/SVN/Migration.pm b/perl/Git/SVN/Migration.pm new file mode 100644 index 000000000..30daf3546 --- /dev/null +++ b/perl/Git/SVN/Migration.pm @@ -0,0 +1,258 @@ +package Git::SVN::Migration; +# these version numbers do NOT correspond to actual version numbers +# of git nor git-svn. They are just relative. +# +# v0 layout: .git/$id/info/url, refs/heads/$id-HEAD +# +# v1 layout: .git/$id/info/url, refs/remotes/$id +# +# v2 layout: .git/svn/$id/info/url, refs/remotes/$id +# +# v3 layout: .git/svn/$id, refs/remotes/$id +# - info/url may remain for backwards compatibility +# - this is what we migrate up to this layout automatically, +# - this will be used by git svn init on single branches +# v3.1 layout (auto migrated): +# - .rev_db => .rev_db.$UUID, .rev_db will remain as a symlink +# for backwards compatibility +# +# v4 layout: .git/svn/$repo_id/$id, refs/remotes/$repo_id/$id +# - this is only created for newly multi-init-ed +# repositories. Similar in spirit to the +# --use-separate-remotes option in git-clone (now default) +# - we do not automatically migrate to this (following +# the example set by core git) +# +# v5 layout: .rev_db.$UUID => .rev_map.$UUID +# - newer, more-efficient format that uses 24-bytes per record +# with no filler space. +# - use xxd -c24 < .rev_map.$UUID to view and debug +# - This is a one-way migration, repositories updated to the +# new format will not be able to use old git-svn without +# rebuilding the .rev_db. Rebuilding the rev_db is not +# possible if noMetadata or useSvmProps are set; but should +# be no problem for users that use the (sensible) defaults. +use strict; +use warnings; +use Carp qw/croak/; +use File::Path qw/mkpath/; +use File::Basename qw/dirname basename/; + +our $_minimize; +use Git qw( + command + command_noisy + command_output_pipe + command_close_pipe +); + +sub migrate_from_v0 { + my $git_dir = $ENV{GIT_DIR}; + return undef unless -d $git_dir; + my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/); + my $migrated = 0; + while (<$fh>) { + chomp; + my ($id, $orig_ref) = ($_, $_); + next unless $id =~ s#^refs/heads/(.+)-HEAD$#$1#; + next unless -f "$git_dir/$id/info/url"; + my $new_ref = "refs/remotes/$id"; + if (::verify_ref("$new_ref^0")) { + print STDERR "W: $orig_ref is probably an old ", + "branch used by an ancient version of ", + "git-svn.\n", + "However, $new_ref also exists.\n", + "We will not be able ", + "to use this branch until this ", + "ambiguity is resolved.\n"; + next; + } + print STDERR "Migrating from v0 layout...\n" if !$migrated; + print STDERR "Renaming ref: $orig_ref => $new_ref\n"; + command_noisy('update-ref', $new_ref, $orig_ref); + command_noisy('update-ref', '-d', $orig_ref, $orig_ref); + $migrated++; + } + command_close_pipe($fh, $ctx); + print STDERR "Done migrating from v0 layout...\n" if $migrated; + $migrated; +} + +sub migrate_from_v1 { + my $git_dir = $ENV{GIT_DIR}; + my $migrated = 0; + return $migrated unless -d $git_dir; + my $svn_dir = "$git_dir/svn"; + + # just in case somebody used 'svn' as their $id at some point... + return $migrated if -d $svn_dir && ! -f "$svn_dir/info/url"; + + print STDERR "Migrating from a git-svn v1 layout...\n"; + mkpath([$svn_dir]); + print STDERR "Data from a previous version of git-svn exists, but\n\t", + "$svn_dir\n\t(required for this version ", + "($::VERSION) of git-svn) does not exist.\n"; + my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/); + while (<$fh>) { + my $x = $_; + next unless $x =~ s#^refs/remotes/##; + chomp $x; + next unless -f "$git_dir/$x/info/url"; + my $u = eval { ::file_to_s("$git_dir/$x/info/url") }; + next unless $u; + my $dn = dirname("$git_dir/svn/$x"); + mkpath([$dn]) unless -d $dn; + if ($x eq 'svn') { # they used 'svn' as GIT_SVN_ID: + mkpath(["$git_dir/svn/svn"]); + print STDERR " - $git_dir/$x/info => ", + "$git_dir/svn/$x/info\n"; + rename "$git_dir/$x/info", "$git_dir/svn/$x/info" or + croak "$!: $x"; + # don't worry too much about these, they probably + # don't exist with repos this old (save for index, + # and we can easily regenerate that) + foreach my $f (qw/unhandled.log index .rev_db/) { + rename "$git_dir/$x/$f", "$git_dir/svn/$x/$f"; + } + } else { + print STDERR " - $git_dir/$x => $git_dir/svn/$x\n"; + rename "$git_dir/$x", "$git_dir/svn/$x" or + croak "$!: $x"; + } + $migrated++; + } + command_close_pipe($fh, $ctx); + print STDERR "Done migrating from a git-svn v1 layout\n"; + $migrated; +} + +sub read_old_urls { + my ($l_map, $pfx, $path) = @_; + my @dir; + foreach (<$path/*>) { + if (-r "$_/info/url") { + $pfx .= '/' if $pfx && $pfx !~ m!/$!; + my $ref_id = $pfx . basename $_; + my $url = ::file_to_s("$_/info/url"); + $l_map->{$ref_id} = $url; + } elsif (-d $_) { + push @dir, $_; + } + } + foreach (@dir) { + my $x = $_; + $x =~ s!^\Q$ENV{GIT_DIR}\E/svn/!!o; + read_old_urls($l_map, $x, $_); + } +} + +sub migrate_from_v2 { + my @cfg = command(qw/config -l/); + return if grep /^svn-remote\..+\.url=/, @cfg; + my %l_map; + read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn"); + my $migrated = 0; + + require Git::SVN; + foreach my $ref_id (sort keys %l_map) { + eval { Git::SVN->init($l_map{$ref_id}, '', undef, $ref_id) }; + if ($@) { + Git::SVN->init($l_map{$ref_id}, '', $ref_id, $ref_id); + } + $migrated++; + } + $migrated; +} + +sub minimize_connections { + require Git::SVN; + require Git::SVN::Ra; + + my $r = Git::SVN::read_all_remotes(); + my $new_urls = {}; + my $root_repos = {}; + foreach my $repo_id (keys %$r) { + my $url = $r->{$repo_id}->{url} or next; + my $fetch = $r->{$repo_id}->{fetch} or next; + my $ra = Git::SVN::Ra->new($url); + + # skip existing cases where we already connect to the root + if (($ra->url eq $ra->{repos_root}) || + ($ra->{repos_root} eq $repo_id)) { + $root_repos->{$ra->url} = $repo_id; + next; + } + + my $root_ra = Git::SVN::Ra->new($ra->{repos_root}); + my $root_path = $ra->url; + $root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##; + foreach my $path (keys %$fetch) { + my $ref_id = $fetch->{$path}; + my $gs = Git::SVN->new($ref_id, $repo_id, $path); + + # make sure we can read when connecting to + # a higher level of a repository + my ($last_rev, undef) = $gs->last_rev_commit; + if (!defined $last_rev) { + $last_rev = eval { + $root_ra->get_latest_revnum; + }; + next if $@; + } + my $new = $root_path; + $new .= length $path ? "/$path" : ''; + eval { + $root_ra->get_log([$new], $last_rev, $last_rev, + 0, 0, 1, sub { }); + }; + next if $@; + $new_urls->{$ra->{repos_root}}->{$new} = + { ref_id => $ref_id, + old_repo_id => $repo_id, + old_path => $path }; + } + } + + my @emptied; + foreach my $url (keys %$new_urls) { + # see if we can re-use an existing [svn-remote "repo_id"] + # instead of creating a(n ugly) new section: + my $repo_id = $root_repos->{$url} || $url; + + my $fetch = $new_urls->{$url}; + foreach my $path (keys %$fetch) { + my $x = $fetch->{$path}; + Git::SVN->init($url, $path, $repo_id, $x->{ref_id}); + my $pfx = "svn-remote.$x->{old_repo_id}"; + + my $old_fetch = quotemeta("$x->{old_path}:". + "$x->{ref_id}"); + command_noisy(qw/config --unset/, + "$pfx.fetch", '^'. $old_fetch . '$'); + delete $r->{$x->{old_repo_id}}-> + {fetch}->{$x->{old_path}}; + if (!keys %{$r->{$x->{old_repo_id}}->{fetch}}) { + command_noisy(qw/config --unset/, + "$pfx.url"); + push @emptied, $x->{old_repo_id} + } + } + } + if (@emptied) { + my $file = $ENV{GIT_CONFIG} || "$ENV{GIT_DIR}/config"; + print STDERR <<EOF; +The following [svn-remote] sections in your config file ($file) are empty +and can be safely removed: +EOF + print STDERR "[svn-remote \"$_\"]\n" foreach @emptied; + } +} + +sub migration_check { + migrate_from_v0(); + migrate_from_v1(); + migrate_from_v2(); + minimize_connections() if $_minimize; +} + +1; diff --git a/perl/Git/SVN/Prompt.pm b/perl/Git/SVN/Prompt.pm index 3a6f8af0d..74daa7a59 100644 --- a/perl/Git/SVN/Prompt.pm +++ b/perl/Git/SVN/Prompt.pm @@ -62,16 +62,16 @@ sub ssl_server_trust { issuer_dname fingerprint); my $choice; prompt: - print STDERR $may_save ? + my $options = $may_save ? "(R)eject, accept (t)emporarily or accept (p)ermanently? " : "(R)eject or accept (t)emporarily? "; STDERR->flush; - $choice = lc(substr(<STDIN> || 'R', 0, 1)); - if ($choice =~ /^t$/i) { + $choice = lc(substr(Git::prompt("Certificate problem.\n" . $options) || 'R', 0, 1)); + if ($choice eq 't') { $cred->may_save(undef); - } elsif ($choice =~ /^r$/i) { + } elsif ($choice eq 'r') { return -1; - } elsif ($may_save && $choice =~ /^p$/i) { + } elsif ($may_save && $choice eq 'p') { $cred->may_save($may_save); } else { goto prompt; @@ -109,9 +109,7 @@ sub username { if (defined $_username) { $username = $_username; } else { - print STDERR "Username: "; - STDERR->flush; - chomp($username = <STDIN>); + $username = Git::prompt("Username: "); } $cred->username($username); $cred->may_save($may_save); @@ -120,25 +118,7 @@ sub username { sub _read_password { my ($prompt, $realm) = @_; - my $password = ''; - if (exists $ENV{GIT_ASKPASS}) { - open(PH, "-|", $ENV{GIT_ASKPASS}, $prompt); - $password = <PH>; - $password =~ s/[\012\015]//; # \n\r - close(PH); - } else { - print STDERR $prompt; - STDERR->flush; - require Term::ReadKey; - Term::ReadKey::ReadMode('noecho'); - while (defined(my $key = Term::ReadKey::ReadKey(0))) { - last if $key =~ /[\012\015]/; # \n\r - $password .= $key; - } - Term::ReadKey::ReadMode('restore'); - print STDERR "\n"; - STDERR->flush; - } + my $password = Git::prompt($prompt, 1); $password; } diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm index 23ff43e86..049c97bfa 100644 --- a/perl/Git/SVN/Ra.pm +++ b/perl/Git/SVN/Ra.pm @@ -3,6 +3,12 @@ use vars qw/@ISA $config_dir $_ignore_refs_regex $_log_window_size/; use strict; use warnings; use SVN::Client; +use Git::SVN::Utils qw( + canonicalize_url + canonicalize_path + add_path_to_url +); + use SVN::Ra; BEGIN { @ISA = qw(SVN::Ra); @@ -62,29 +68,11 @@ sub _auth_providers () { \@rv; } -sub escape_uri_only { - my ($uri) = @_; - my @tmp; - foreach (split m{/}, $uri) { - s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg; - push @tmp, $_; - } - join('/', @tmp); -} - -sub escape_url { - my ($url) = @_; - if ($url =~ m#^(https?)://([^/]+)(.*)$#) { - my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3)); - $url = "$scheme://$domain$uri"; - } - $url; -} sub new { my ($class, $url) = @_; - $url =~ s!/+$!!; - return $RA if ($RA && $RA->{url} eq $url); + $url = canonicalize_url($url); + return $RA if ($RA && $RA->url eq $url); ::_req_svn(); @@ -115,17 +103,34 @@ sub new { $Git::SVN::Prompt::_no_auth_cache = 1; } } # no warnings 'once' - my $self = SVN::Ra->new(url => escape_url($url), auth => $baton, + + my $self = SVN::Ra->new(url => $url, auth => $baton, config => $config, pool => SVN::Pool->new, auth_provider_callbacks => $callbacks); - $self->{url} = $url; + $RA = bless $self, $class; + + # Make sure its canonicalized + $self->url($url); $self->{svn_path} = $url; $self->{repos_root} = $self->get_repos_root; $self->{svn_path} =~ s#^\Q$self->{repos_root}\E(/|$)##; $self->{cache} = { check_path => { r => 0, data => {} }, get_dir => { r => 0, data => {} } }; - $RA = bless $self, $class; + + return $RA; +} + +sub url { + my $self = shift; + + if (@_) { + my $url = shift; + $self->{url} = canonicalize_url($url); + return; + } + + return $self->{url}; } sub check_path { @@ -195,6 +200,7 @@ sub get_log { qw/copyfrom_path copyfrom_rev action/; if ($s{'copyfrom_path'}) { $s{'copyfrom_path'} =~ s/$prefix_regex//; + $s{'copyfrom_path'} = canonicalize_path($s{'copyfrom_path'}); } $_[0]{$p} = \%s; } @@ -246,7 +252,7 @@ sub get_commit_editor { sub gs_do_update { my ($self, $rev_a, $rev_b, $gs, $editor) = @_; my $new = ($rev_a == $rev_b); - my $path = $gs->{path}; + my $path = $gs->path; if ($new && -e $gs->{index}) { unlink $gs->{index} or die @@ -282,30 +288,33 @@ sub gs_do_update { # svn_ra_reparent didn't work before 1.4) sub gs_do_switch { my ($self, $rev_a, $rev_b, $gs, $url_b, $editor) = @_; - my $path = $gs->{path}; + my $path = $gs->path; my $pool = SVN::Pool->new; - my $full_url = $self->{url}; - my $old_url = $full_url; - $full_url .= '/' . $path if length $path; + my $old_url = $self->url; + my $full_url = add_path_to_url( $self->url, $path ); my ($ra, $reparented); if ($old_url =~ m#^svn(\+ssh)?://# || ($full_url =~ m#^https?://# && - escape_url($full_url) ne $full_url)) { + canonicalize_url($full_url) ne $full_url)) { $_[0] = undef; $self = undef; $RA = undef; $ra = Git::SVN::Ra->new($full_url); $ra_invalid = 1; } elsif ($old_url ne $full_url) { - SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, $pool); - $self->{url} = $full_url; + SVN::_Ra::svn_ra_reparent( + $self->{session}, + canonicalize_url($full_url), + $pool + ); + $self->url($full_url); $reparented = 1; } $ra ||= $self; - $url_b = escape_url($url_b); + $url_b = canonicalize_url($url_b); my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool); my @lock = (::compare_svn_version('1.2.0') >= 0) ? (undef) : (); $reporter->set_path('', $rev_a, 0, @lock, $pool); @@ -313,7 +322,7 @@ sub gs_do_switch { if ($reparented) { SVN::_Ra::svn_ra_reparent($self->{session}, $old_url, $pool); - $self->{url} = $old_url; + $self->url($old_url); } $pool->clear; @@ -326,7 +335,7 @@ sub longest_common_path { my $common_max = scalar @$gsv; foreach my $gs (@$gsv) { - my @tmp = split m#/#, $gs->{path}; + my @tmp = split m#/#, $gs->path; my $p = ''; foreach (@tmp) { $p .= length($p) ? "/$_" : $_; @@ -362,7 +371,7 @@ sub gs_fetch_loop_common { my $inc = $_log_window_size; my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc); my $longest_path = longest_common_path($gsv, $globs); - my $ra_url = $self->{url}; + my $ra_url = $self->url; my $find_trailing_edge; while (1) { my %revs; @@ -407,7 +416,7 @@ sub gs_fetch_loop_common { } $SVN::Error::handler = $err_handler; - my %exists = map { $_->{path} => $_ } @$gsv; + my %exists = map { $_->path => $_ } @$gsv; foreach my $r (sort {$a <=> $b} keys %revs) { my ($paths, $logged) = @{$revs{$r}}; @@ -508,7 +517,7 @@ sub match_globs { ($self->check_path($p, $r) != $SVN::Node::dir)); next unless $p =~ /$g->{path}->{regex}/; - $exists->{$p} = Git::SVN->init($self->{url}, $p, undef, + $exists->{$p} = Git::SVN->init($self->url, $p, undef, $g->{ref}->full_path($de), 1); } } @@ -532,7 +541,7 @@ sub match_globs { next if ($self->check_path($pathname, $r) != $SVN::Node::dir); $exists->{$pathname} = Git::SVN->init( - $self->{url}, $pathname, undef, + $self->url, $pathname, undef, $g->{ref}->full_path($p), 1); } my $c = ''; @@ -548,19 +557,20 @@ sub match_globs { sub minimize_url { my ($self) = @_; - return $self->{url} if ($self->{url} eq $self->{repos_root}); + return $self->url if ($self->url eq $self->{repos_root}); my $url = $self->{repos_root}; my @components = split(m!/!, $self->{svn_path}); my $c = ''; do { - $url .= "/$c" if length $c; + $url = add_path_to_url($url, $c); eval { my $ra = (ref $self)->new($url); my $latest = $ra->get_latest_revnum; $ra->get_log("", $latest, 0, 1, 0, 1, sub {}); }; } while ($@ && ($c = shift @components)); - $url; + + return canonicalize_url($url); } sub can_do_switch { @@ -568,7 +578,7 @@ sub can_do_switch { unless (defined $can_do_switch) { my $pool = SVN::Pool->new; my $rep = eval { - $self->do_switch(1, '', 0, $self->{url}, + $self->do_switch(1, '', 0, $self->url, SVN::Delta::Editor->new, $pool); }; if ($@) { diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm new file mode 100644 index 000000000..8b8cf3755 --- /dev/null +++ b/perl/Git/SVN/Utils.pm @@ -0,0 +1,232 @@ +package Git::SVN::Utils; + +use strict; +use warnings; + +use SVN::Core; + +use base qw(Exporter); + +our @EXPORT_OK = qw( + fatal + can_compress + canonicalize_path + canonicalize_url + join_paths + add_path_to_url +); + + +=head1 NAME + +Git::SVN::Utils - utility functions used across Git::SVN + +=head1 SYNOPSIS + + use Git::SVN::Utils qw(functions to import); + +=head1 DESCRIPTION + +This module contains functions which are useful across many different +parts of Git::SVN. Mostly it's a place to put utility functions +rather than duplicate the code or have classes grabbing at other +classes. + +=head1 FUNCTIONS + +All functions can be imported only on request. + +=head3 fatal + + fatal(@message); + +Display a message and exit with a fatal error code. + +=cut + +# Note: not certain why this is in use instead of die. Probably because +# the exit code of die is 255? Doesn't appear to be used consistently. +sub fatal (@) { print STDERR "@_\n"; exit 1 } + + +=head3 can_compress + + my $can_compress = can_compress; + +Returns true if Compress::Zlib is available, false otherwise. + +=cut + +my $can_compress; +sub can_compress { + return $can_compress if defined $can_compress; + + return $can_compress = eval { require Compress::Zlib; }; +} + + +=head3 canonicalize_path + + my $canoncalized_path = canonicalize_path($path); + +Converts $path into a canonical form which is safe to pass to the SVN +API as a file path. + +=cut + +# Turn foo/../bar into bar +sub _collapse_dotdot { + my $path = shift; + + 1 while $path =~ s{/[^/]+/+\.\.}{}; + 1 while $path =~ s{[^/]+/+\.\./}{}; + 1 while $path =~ s{[^/]+/+\.\.}{}; + + return $path; +} + + +sub canonicalize_path { + my $path = shift; + my $rv; + + # The 1.7 way to do it + if ( defined &SVN::_Core::svn_dirent_canonicalize ) { + $path = _collapse_dotdot($path); + $rv = SVN::_Core::svn_dirent_canonicalize($path); + } + # The 1.6 way to do it + # This can return undef on subversion-perl-1.4.2-2.el5 (CentOS 5.2) + elsif ( defined &SVN::_Core::svn_path_canonicalize ) { + $path = _collapse_dotdot($path); + $rv = SVN::_Core::svn_path_canonicalize($path); + } + + return $rv if defined $rv; + + # No SVN API canonicalization is available, or the SVN API + # didn't return a successful result, do it ourselves + return _canonicalize_path_ourselves($path); +} + + +sub _canonicalize_path_ourselves { + my ($path) = @_; + my $dot_slash_added = 0; + if (substr($path, 0, 1) ne "/") { + $path = "./" . $path; + $dot_slash_added = 1; + } + $path =~ s#/+#/#g; + $path =~ s#/\.(?:/|$)#/#g; + $path = _collapse_dotdot($path); + $path =~ s#/$##g; + $path =~ s#^\./## if $dot_slash_added; + $path =~ s#^\.$##; + return $path; +} + + +=head3 canonicalize_url + + my $canonicalized_url = canonicalize_url($url); + +Converts $url into a canonical form which is safe to pass to the SVN +API as a URL. + +=cut + +sub canonicalize_url { + my $url = shift; + + # The 1.7 way to do it + if ( defined &SVN::_Core::svn_uri_canonicalize ) { + return SVN::_Core::svn_uri_canonicalize($url); + } + # There wasn't a 1.6 way to do it, so we do it ourself. + else { + return _canonicalize_url_ourselves($url); + } +} + + +sub _canonicalize_url_path { + my ($uri_path) = @_; + + my @parts; + foreach my $part (split m{/+}, $uri_path) { + $part =~ s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg; + push @parts, $part; + } + + return join('/', @parts); +} + +sub _canonicalize_url_ourselves { + my ($url) = @_; + if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) { + my ($scheme, $domain, $uri) = ($1, $2, _canonicalize_url_path(canonicalize_path($3))); + $url = "$scheme://$domain$uri"; + } + $url; +} + + +=head3 join_paths + + my $new_path = join_paths(@paths); + +Appends @paths together into a single path. Any empty paths are ignored. + +=cut + +sub join_paths { + my @paths = @_; + + @paths = grep { defined $_ && length $_ } @paths; + + return '' unless @paths; + return $paths[0] if @paths == 1; + + my $new_path = shift @paths; + $new_path =~ s{/+$}{}; + + my $last_path = pop @paths; + $last_path =~ s{^/+}{}; + + for my $path (@paths) { + $path =~ s{^/+}{}; + $path =~ s{/+$}{}; + $new_path .= "/$path"; + } + + return $new_path .= "/$last_path"; +} + + +=head3 add_path_to_url + + my $new_url = add_path_to_url($url, $path); + +Appends $path onto the $url. If $path is empty, $url is returned unchanged. + +=cut + +sub add_path_to_url { + my($url, $path) = @_; + + return $url if !defined $path or !length $path; + + # Strip trailing and leading slashes so we don't + # wind up with http://x.com///path + $url =~ s{/+$}{}; + $path =~ s{^/+}{}; + + # If a path has a % in it, URI escape it so it's not + # mistaken for a URI escape later. + $path =~ s{%}{%25}g; + + return join '/', $url, $path; +} + +1; diff --git a/perl/Makefile b/perl/Makefile index fe7a48646..15d96fcc7 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -20,36 +20,57 @@ clean: $(RM) ppport.h $(RM) $(makfile) $(RM) $(makfile).old + $(RM) PM.stamp + +$(makfile): PM.stamp ifdef NO_PERL_MAKEMAKER instdir_SQ = $(subst ','\'',$(prefix)/lib) modules += Git modules += Git/I18N +modules += Git/IndexInfo +modules += Git/SVN modules += Git/SVN/Memoize/YAML modules += Git/SVN/Fetcher modules += Git/SVN/Editor +modules += Git/SVN/GlobSpec +modules += Git/SVN/Log +modules += Git/SVN/Migration modules += Git/SVN/Prompt modules += Git/SVN/Ra +modules += Git/SVN/Utils $(makfile): ../GIT-CFLAGS Makefile echo all: private-Error.pm Git.pm Git/I18N.pm > $@ - echo ' mkdir -p blib/lib/Git/SVN/Memoize' >> $@ set -e; \ for i in $(modules); \ do \ + if test $$i = $${i%/*}; \ + then \ + subdir=; \ + else \ + subdir=/$${i%/*}; \ + fi; \ echo ' $(RM) blib/lib/'$$i'.pm' >> $@; \ + echo ' mkdir -p blib/lib'$$subdir >> $@; \ echo ' cp '$$i'.pm blib/lib/'$$i'.pm' >> $@; \ done echo ' $(RM) blib/lib/Error.pm' >> $@ '$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \ echo ' cp private-Error.pm blib/lib/Error.pm' >> $@ echo install: >> $@ - echo ' mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git/SVN/Memoize"' >> $@ set -e; \ for i in $(modules); \ do \ + if test $$i = $${i%/*}; \ + then \ + subdir=; \ + else \ + subdir=/$${i%/*}; \ + fi; \ echo ' $(RM) "$$(DESTDIR)$(instdir_SQ)/'$$i'.pm"' >> $@; \ + echo ' mkdir -p "$$(DESTDIR)$(instdir_SQ)'$$subdir'"' >> $@; \ echo ' cp '$$i'.pm "$$(DESTDIR)$(instdir_SQ)/'$$i'.pm"' >> $@; \ done echo ' $(RM) "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@ diff --git a/perl/Makefile.PL b/perl/Makefile.PL index b54b04a61..3f29ba98a 100644 --- a/perl/Makefile.PL +++ b/perl/Makefile.PL @@ -2,11 +2,16 @@ use strict; use warnings; use ExtUtils::MakeMaker; use Getopt::Long; +use File::Find; + +# Don't forget to update the perl/Makefile, too. +# Don't forget to test with NO_PERL_MAKEMAKER=YesPlease # Sanity: die at first unknown option Getopt::Long::Configure qw/ pass_through /; -GetOptions("localedir=s" => \my $localedir); +my $localedir = ''; +GetOptions("localedir=s" => \$localedir); sub MY::postamble { return <<'MAKE_FRAG'; @@ -24,24 +29,22 @@ endif MAKE_FRAG } -# XXX. When editing this list: -# -# * Please update perl/Makefile, too. -# * Don't forget to test with NO_PERL_MAKEMAKER=YesPlease -my %pm = ( - 'Git.pm' => '$(INST_LIBDIR)/Git.pm', - 'Git/I18N.pm' => '$(INST_LIBDIR)/Git/I18N.pm', - 'Git/SVN/Memoize/YAML.pm' => '$(INST_LIBDIR)/Git/SVN/Memoize/YAML.pm', - 'Git/SVN/Fetcher.pm' => '$(INST_LIBDIR)/Git/SVN/Fetcher.pm', - 'Git/SVN/Editor.pm' => '$(INST_LIBDIR)/Git/SVN/Editor.pm', - 'Git/SVN/Prompt.pm' => '$(INST_LIBDIR)/Git/SVN/Prompt.pm', - 'Git/SVN/Ra.pm' => '$(INST_LIBDIR)/Git/SVN/Ra.pm', -); +# Find all the .pm files in "Git/" and Git.pm +my %pm; +find sub { + return unless /\.pm$/; + + # sometimes File::Find prepends a ./ Strip it. + my $pm_path = $File::Find::name; + $pm_path =~ s{^\./}{}; + + $pm{$pm_path} = '$(INST_LIBDIR)/'.$pm_path; +}, "Git", "Git.pm"; + # We come with our own bundled Error.pm. It's not in the set of default # Perl modules so install it if it's not available on the system yet. -eval { require Error }; -if ($@ || $Error::VERSION < 0.15009) { +if ( !eval { require Error } || $Error::VERSION < 0.15009) { $pm{'private-Error.pm'} = '$(INST_LIBDIR)/Error.pm'; } diff --git a/pkt-line.c b/pkt-line.c index 5a04984ea..eaba15f12 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -135,13 +135,19 @@ void packet_buf_write(struct strbuf *buf, const char *fmt, ...) strbuf_add(buf, buffer, n); } -static void safe_read(int fd, void *buffer, unsigned size) +static int safe_read(int fd, void *buffer, unsigned size, int return_line_fail) { ssize_t ret = read_in_full(fd, buffer, size); if (ret < 0) die_errno("read error"); - else if (ret < size) + else if (ret < size) { + if (return_line_fail) + return -1; + die("The remote end hung up unexpectedly"); + } + + return ret; } static int packet_length(const char *linelen) @@ -169,12 +175,14 @@ static int packet_length(const char *linelen) return len; } -int packet_read_line(int fd, char *buffer, unsigned size) +static int packet_read_internal(int fd, char *buffer, unsigned size, int return_line_fail) { - int len; + int len, ret; char linelen[4]; - safe_read(fd, linelen, 4); + ret = safe_read(fd, linelen, 4, return_line_fail); + if (return_line_fail && ret < 0) + return ret; len = packet_length(linelen); if (len < 0) die("protocol error: bad line length character: %.4s", linelen); @@ -185,12 +193,24 @@ int packet_read_line(int fd, char *buffer, unsigned size) len -= 4; if (len >= size) die("protocol error: bad line length %d", len); - safe_read(fd, buffer, len); + ret = safe_read(fd, buffer, len, return_line_fail); + if (return_line_fail && ret < 0) + return ret; buffer[len] = 0; packet_trace(buffer, len, 0); return len; } +int packet_read(int fd, char *buffer, unsigned size) +{ + return packet_read_internal(fd, buffer, size, 1); +} + +int packet_read_line(int fd, char *buffer, unsigned size) +{ + return packet_read_internal(fd, buffer, size, 0); +} + int packet_get_line(struct strbuf *out, char **src_buf, size_t *src_len) { diff --git a/pkt-line.h b/pkt-line.h index 1e5dcfe87..8cfeb0c31 100644 --- a/pkt-line.h +++ b/pkt-line.h @@ -13,6 +13,7 @@ void packet_buf_flush(struct strbuf *buf); void packet_buf_write(struct strbuf *buf, const char *fmt, ...) __attribute__((format (printf, 2, 3))); int packet_read_line(int fd, char *buffer, unsigned size); +int packet_read(int fd, char *buffer, unsigned size); int packet_get_line(struct strbuf *out, char **src_buf, size_t *src_len); ssize_t safe_write(int, const void *, ssize_t); @@ -33,8 +33,9 @@ Repository: https://github.com/nafmo/git-l10n-sv/ Leader: Peter Krefting <peter@softwolves.pp.se> Language: vi (Vietnamese) -Repository: https://github.com/vnwildman/git.git +Repository: https://github.com/vnwildman/git/ Leader: Trần Ngá»c Quân <vnwildman AT gmail.com> +Members: Nguyá»…n Thái Ngá»c Duy <pclouds AT gmail.com> Language: zh_CN (Simplified Chinese) Repository: https://github.com/gotgit/git-po-zh_CN/ @@ -1,21 +1,21 @@ # German translations for Git. -# Copyright (C) 2010-2012 Ralf Thielow <ralf.thielow@googlemail.com> +# Copyright (C) 2010-2012 Ralf Thielow <ralf.thielow@gmail.com> # This file is distributed under the same license as the Git package. -# Ralf Thielow <ralf.thielow@googlemail.com>, 2010, 2011, 2012. +# Ralf Thielow <ralf.thielow@gmail.com>, 2010, 2011, 2012. # msgid "" msgstr "" -"Project-Id-Version: git 1.7.11\n" +"Project-Id-Version: git 1.8.1\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2012-06-08 10:20+0800\n" -"PO-Revision-Date: 2012-03-28 18:46+0200\n" -"Last-Translator: Ralf Thielow <ralf.thielow@googlemail.com>\n" -"Language-Team: German\n" +"POT-Creation-Date: 2012-11-30 12:40+0800\n" +"PO-Revision-Date: 2012-10-02 19:35+0200\n" +"Last-Translator: Ralf Thielow <ralf.thielow@gmail.com>\n" +"Language-Team: German <>\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" #: advice.c:40 #, c-format @@ -38,6 +38,101 @@ msgstr "" "um die Auflösung entsprechend zu markieren und einzutragen,\n" "oder benutze 'git commit -a'." +#: archive.c:10 +msgid "git archive [options] <tree-ish> [<path>...]" +msgstr "git archive [Optionen] <Versionsreferenz> [<Pfad>...]" + +#: archive.c:11 +msgid "git archive --list" +msgstr "git archive --list" + +#: archive.c:12 +msgid "" +"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]" +msgstr "" +"git archive --remote <Projektarchiv> [--exec <Programm>] [Optionen] " +"<Versionsreferenz> [Pfad...]" + +#: archive.c:13 +msgid "git archive --remote <repo> [--exec <cmd>] --list" +msgstr "git archive --remote <Projektarchiv> [--exec <Programm>] --list" + +#: archive.c:322 +msgid "fmt" +msgstr "Format" + +#: archive.c:322 +msgid "archive format" +msgstr "Ausgabeformat" + +#: archive.c:323 builtin/log.c:1084 +msgid "prefix" +msgstr "Prefix" + +#: archive.c:324 +msgid "prepend prefix to each pathname in the archive" +msgstr "stellt einen Präfix vor jeden Pfadnamen in der Ausgabe" + +#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2390 +#: builtin/blame.c:2391 builtin/config.c:55 builtin/fast-export.c:642 +#: builtin/fast-export.c:644 builtin/grep.c:715 builtin/hash-object.c:77 +#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:540 +#: builtin/notes.c:697 builtin/read-tree.c:107 parse-options.h:149 +msgid "file" +msgstr "Datei" + +#: archive.c:326 builtin/archive.c:92 +msgid "write the archive to this file" +msgstr "schreibt die Ausgabe in diese Datei" + +#: archive.c:328 +msgid "read .gitattributes in working directory" +msgstr "liest .gitattributes aus dem Arbeitsverzeichnis" + +#: archive.c:329 +msgid "report archived files on stderr" +msgstr "gibt archivierte Dateien in der Standard-Fehlerausgabe aus" + +#: archive.c:330 +msgid "store only" +msgstr "nur speichern" + +#: archive.c:331 +msgid "compress faster" +msgstr "schneller komprimieren" + +#: archive.c:339 +msgid "compress better" +msgstr "besser komprimieren" + +#: archive.c:342 +msgid "list supported archive formats" +msgstr "listet unterstützte Ausgabeformate auf" + +#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85 +msgid "repo" +msgstr "Projektarchiv" + +#: archive.c:345 builtin/archive.c:94 +msgid "retrieve the archive from remote repository <repo>" +msgstr "ruft das Archiv von externem Projektarchiv <Projektarchiv> ab" + +#: archive.c:346 builtin/archive.c:95 builtin/notes.c:619 +msgid "command" +msgstr "Programm" + +#: archive.c:347 builtin/archive.c:96 +msgid "path to the remote git-upload-archive command" +msgstr "Pfad zum externen \"git-upload-archive\"-Programm" + +#: attr.c:259 +msgid "" +"Negative patterns are forbidden in git attributes\n" +"Use '\\!' for literal leading exclamation." +msgstr "" +"Verneinende Muster sind in Git-Attributen verboten.\n" +"Benutze '\\!' für führende Ausrufezeichen." + #: bundle.c:36 #, c-format msgid "'%s' does not look like a v2 bundle file" @@ -48,17 +143,17 @@ msgstr "'%s' sieht nicht wie eine v2 Paketdatei aus" msgid "unrecognized header: %s%s (%d)" msgstr "nicht erkannter Kopfbereich: %s%s (%d)" -#: bundle.c:89 builtin/commit.c:696 +#: bundle.c:89 builtin/commit.c:674 #, c-format msgid "could not open '%s'" msgstr "Konnte '%s' nicht öffnen" #: bundle.c:140 msgid "Repository lacks these prerequisite commits:" -msgstr "Dem Projektarchiv fehlen folgende vorrausgesetzte Versionen:" +msgstr "Dem Projektarchiv fehlen folgende vorausgesetzte Versionen:" -#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:289 -#: builtin/log.c:720 builtin/log.c:1309 builtin/log.c:1528 builtin/merge.c:347 +#: bundle.c:164 sequencer.c:562 sequencer.c:994 builtin/log.c:290 +#: builtin/log.c:732 builtin/log.c:1319 builtin/log.c:1535 builtin/merge.c:347 #: builtin/shortlog.c:181 msgid "revision walk setup failed" msgstr "Einrichtung des Revisionsgangs fehlgeschlagen" @@ -71,53 +166,57 @@ msgstr[0] "Das Paket enthält %d Referenz" msgstr[1] "Das Paket enthält %d Referenzen" #: bundle.c:192 +msgid "The bundle records a complete history." +msgstr "Das Paket speichert eine komplette Historie." + +#: bundle.c:195 #, c-format msgid "The bundle requires this ref" msgid_plural "The bundle requires these %d refs" msgstr[0] "Das Paket benötigt diese Referenz" msgstr[1] "Das Paket benötigt diese %d Referenzen" -#: bundle.c:290 +#: bundle.c:294 msgid "rev-list died" msgstr "\"rev-list\" abgebrochen" -#: bundle.c:296 builtin/log.c:1205 builtin/shortlog.c:284 +#: bundle.c:300 builtin/log.c:1215 builtin/shortlog.c:284 #, c-format msgid "unrecognized argument: %s" msgstr "nicht erkanntes Argument: %s" -#: bundle.c:331 +#: bundle.c:335 #, c-format msgid "ref '%s' is excluded by the rev-list options" msgstr "Referenz '%s' wird durch \"rev-list\" Optionen ausgeschlossen" -#: bundle.c:376 +#: bundle.c:380 msgid "Refusing to create empty bundle." msgstr "Erstellung eines leeren Pakets zurückgewiesen." -#: bundle.c:394 +#: bundle.c:398 msgid "Could not spawn pack-objects" msgstr "Konnte Paketobjekte nicht erstellen" -#: bundle.c:412 +#: bundle.c:416 msgid "pack-objects died" msgstr "Erstellung der Paketobjekte abgebrochen" -#: bundle.c:415 +#: bundle.c:419 #, c-format msgid "cannot create '%s'" msgstr "kann '%s' nicht erstellen" -#: bundle.c:437 +#: bundle.c:441 msgid "index-pack died" msgstr "Erstellung der Paketindexdatei abgebrochen" -#: commit.c:48 +#: commit.c:50 #, c-format msgid "could not parse %s" msgstr "konnte %s nicht parsen" -#: commit.c:50 +#: commit.c:52 #, c-format msgid "%s %s is not a commit!" msgstr "%s %s ist keine Version!" @@ -207,18 +306,24 @@ msgid_plural "%lu years ago" msgstr[0] "vor %lu Jahr" msgstr[1] "vor %lu Jahren" -#: diff.c:105 +#: diff.c:111 #, c-format -msgid " Failed to parse dirstat cut-off percentage '%.*s'\n" +msgid " Failed to parse dirstat cut-off percentage '%s'\n" msgstr "" -" Fehler beim Parsen des abgeschnittenen \"dirstat\" Prozentsatzes '%.*s'\n" +" Fehler beim Parsen des abgeschnittenen \"dirstat\" Prozentsatzes '%s'\n" -#: diff.c:110 +#: diff.c:116 #, c-format -msgid " Unknown dirstat parameter '%.*s'\n" -msgstr " Unbekannter \"dirstat\" Parameter '%.*s'\n" +msgid " Unknown dirstat parameter '%s'\n" +msgstr " Unbekannter \"dirstat\" Parameter '%s'\n" -#: diff.c:210 +#: diff.c:194 +#, c-format +msgid "Unknown value for 'diff.submodule' config variable: '%s'" +msgstr "" +"Unbekannter Wert in Konfigurationsvariable 'diff.dirstat': '%s'" + +#: diff.c:237 #, c-format msgid "" "Found errors in 'diff.dirstat' config variable:\n" @@ -227,32 +332,7 @@ msgstr "" "Fehler in 'diff.dirstat' Konfigurationsvariable gefunden:\n" "%s" -#: diff.c:1400 -msgid " 0 files changed\n" -msgstr " 0 Dateien geändert\n" - -#: diff.c:1404 -#, c-format -msgid " %d file changed" -msgid_plural " %d files changed" -msgstr[0] " %d Datei geändert" -msgstr[1] " %d Dateien geändert" - -#: diff.c:1421 -#, c-format -msgid ", %d insertion(+)" -msgid_plural ", %d insertions(+)" -msgstr[0] ", %d Zeile hinzugefügt(+)" -msgstr[1] ", %d Zeilen hinzugefügt(+)" - -#: diff.c:1432 -#, c-format -msgid ", %d deletion(-)" -msgid_plural ", %d deletions(-)" -msgstr[0] ", %d Zeile entfernt(-)" -msgstr[1] ", %d Zeilen entfernt(-)" - -#: diff.c:3478 +#: diff.c:3494 #, c-format msgid "" "Failed to parse --dirstat/-X option parameter:\n" @@ -261,6 +341,12 @@ msgstr "" "Fehler beim Parsen des --dirstat/-X Optionsparameters:\n" "%s" +#: diff.c:3508 +#, c-format +msgid "Failed to parse --submodule option parameter: '%s'" +msgstr "" +"Fehler beim Parsen des --submodule Optionsparameters: '%s'" + #: gpg-interface.c:59 msgid "could not run gpg." msgstr "konnte gpg nicht ausführen" @@ -273,31 +359,31 @@ msgstr "gpg hat die Daten nicht akzeptiert" msgid "gpg failed to sign the data" msgstr "gpg beim Signieren der Daten fehlgeschlagen" -#: grep.c:1320 +#: grep.c:1622 #, c-format msgid "'%s': unable to read %s" msgstr "'%s': konnte nicht lesen %s" -#: grep.c:1337 +#: grep.c:1639 #, c-format msgid "'%s': %s" msgstr "'%s': %s" -#: grep.c:1348 +#: grep.c:1650 #, c-format msgid "'%s': short read %s" msgstr "'%s': read() zu kurz %s" -#: help.c:207 +#: help.c:212 #, c-format msgid "available git commands in '%s'" msgstr "Vorhandene Git-Kommandos in '%s'" -#: help.c:214 +#: help.c:219 msgid "git commands available from elsewhere on your $PATH" msgstr "Vorhandene Git-Kommandos irgendwo in deinem $PATH" -#: help.c:270 +#: help.c:275 #, c-format msgid "" "'%s' appears to be a git command, but we were not\n" @@ -306,11 +392,11 @@ msgstr "" "'%s' scheint ein git-Kommando zu sein, konnte aber\n" "nicht ausgeführt werden. Vielleicht ist git-%s fehlerhaft?" -#: help.c:327 +#: help.c:332 msgid "Uh oh. Your system reports no Git commands at all." msgstr "Uh oh. Keine Git-Kommandos auf deinem System vorhanden." -#: help.c:349 +#: help.c:354 #, c-format msgid "" "WARNING: You called a Git command named '%s', which does not exist.\n" @@ -319,17 +405,17 @@ msgstr "" "Warnung: Du hast das nicht existierende Git-Kommando '%s' ausgeführt.\n" "Setze fort unter der Annahme das du '%s' gemeint hast" -#: help.c:354 +#: help.c:359 #, c-format msgid "in %0.1f seconds automatically..." msgstr "automatisch in %0.1f Sekunden..." -#: help.c:361 +#: help.c:366 #, c-format msgid "git: '%s' is not a git command. See 'git --help'." msgstr "git: '%s' ist kein Git-Kommando. Siehe 'git --help'." -#: help.c:365 +#: help.c:370 msgid "" "\n" "Did you mean this?" @@ -343,35 +429,306 @@ msgstr[1] "" "\n" "Hast du eines von diesen gemeint?" -#: parse-options.c:493 +#: merge.c:56 +msgid "failed to read the cache" +msgstr "Lesen des Zwischenspeichers fehlgeschlagen" + +#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534 +#: builtin/clone.c:586 +msgid "unable to write new index file" +msgstr "Konnte neue Bereitstellungsdatei nicht schreiben." + +#: merge-recursive.c:190 +#, c-format +msgid "(bad commit)\n" +msgstr "(ungültige Version)\n" + +#: merge-recursive.c:206 +#, c-format +msgid "addinfo_cache failed for path '%s'" +msgstr "addinfo_cache für Pfad '%s' fehlgeschlagen" + +#: merge-recursive.c:268 +msgid "error building trees" +msgstr "Fehler beim Erstellen der Bäume" + +#: merge-recursive.c:672 +#, c-format +msgid "failed to create path '%s'%s" +msgstr "Fehler beim Erstellen des Pfades '%s'%s" + +#: merge-recursive.c:683 +#, c-format +msgid "Removing %s to make room for subdirectory\n" +msgstr "Entferne %s um Platz für Unterverzeichnis zu schaffen\n" + +#. something else exists +#. .. but not some other error (who really cares what?) +#: merge-recursive.c:697 merge-recursive.c:718 +msgid ": perhaps a D/F conflict?" +msgstr ": vielleicht ein Verzeichnis/Datei-Konflikt?" + +#: merge-recursive.c:708 +#, c-format +msgid "refusing to lose untracked file at '%s'" +msgstr "verweigere, da unbeobachtete Dateien in '%s' verloren gehen würden" + +#: merge-recursive.c:748 +#, c-format +msgid "cannot read object %s '%s'" +msgstr "kann Objekt %s '%s' nicht lesen" + +#: merge-recursive.c:750 +#, c-format +msgid "blob expected for %s '%s'" +msgstr "Blob erwartet für %s '%s'" + +#: merge-recursive.c:773 builtin/clone.c:302 +#, c-format +msgid "failed to open '%s'" +msgstr "Fehler beim Öffnen von '%s'" + +#: merge-recursive.c:781 +#, c-format +msgid "failed to symlink '%s'" +msgstr "Fehler beim Erstellen einer symbolischen Verknüpfung für '%s'" + +#: merge-recursive.c:784 +#, c-format +msgid "do not know what to do with %06o %s '%s'" +msgstr "weiß nicht was mit %06o %s '%s' zu machen ist" + +#: merge-recursive.c:922 +msgid "Failed to execute internal merge" +msgstr "Fehler bei Ausführung der internen Zusammenführung" + +#: merge-recursive.c:926 +#, c-format +msgid "Unable to add %s to database" +msgstr "Konnte %s nicht zur Datenbank hinzufügen" + +#: merge-recursive.c:942 +msgid "unsupported object type in the tree" +msgstr "nicht unterstützter Objekttyp im Baum" + +#: merge-recursive.c:1021 merge-recursive.c:1035 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree." +msgstr "" +"KONFLIKT (%s/löschen): %s gelöscht in %s und %s in %s. Stand %s von %s wurde " +"im Arbeitsbereich gelassen." + +#: merge-recursive.c:1027 merge-recursive.c:1040 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree at %s." +msgstr "" +"KONFLIKT (%s/löschen): %s gelöscht in %s und %s in %s. Stand %s von %s wurde " +"im Arbeitsbereich bei %s gelassen." + +#: merge-recursive.c:1081 +msgid "rename" +msgstr "umbenennen" + +#: merge-recursive.c:1081 +msgid "renamed" +msgstr "umbenannt" + +#: merge-recursive.c:1137 +#, c-format +msgid "%s is a directory in %s adding as %s instead" +msgstr "%s ist ein Verzeichnis in %s, füge es stattdessen als %s hinzu" + +#: merge-recursive.c:1159 +#, c-format +msgid "" +"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s" +"\"->\"%s\" in \"%s\"%s" +msgstr "" +"KONFLIKT (umbenennen/umbenennen): Benenne um \"%s\"->\"%s\" in Zweig \"%s\" " +"und \"%s\"->\"%s\" in Zweig \"%s\"%s" + +#: merge-recursive.c:1164 +msgid " (left unresolved)" +msgstr " (bleibt unaufgelöst)" + +#: merge-recursive.c:1218 +#, c-format +msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s" +msgstr "" +"KONFLIKT (umbenennen/umbenennen): Benenne um %s->%s in %s. Benenne um %s->%s " +"in %s" + +#: merge-recursive.c:1248 +#, c-format +msgid "Renaming %s to %s and %s to %s instead" +msgstr "Benenne stattdessen %s nach %s und %s nach %s um" + +#: merge-recursive.c:1447 +#, c-format +msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s" +msgstr "" +"KONFLIKT (umbenennen/hinzufügen): Benenne um %s->%s in %s. %s hinzugefügt in " +"%s" + +#: merge-recursive.c:1457 +#, c-format +msgid "Adding merged %s" +msgstr "Füge zusammengeführte Datei %s hinzu" + +#: merge-recursive.c:1462 merge-recursive.c:1660 +#, c-format +msgid "Adding as %s instead" +msgstr "Füge stattdessen als %s hinzu" + +#: merge-recursive.c:1513 +#, c-format +msgid "cannot read object %s" +msgstr "kann Objekt %s nicht lesen" + +#: merge-recursive.c:1516 +#, c-format +msgid "object %s is not a blob" +msgstr "Objekt %s ist kein Blob" + +#: merge-recursive.c:1564 +msgid "modify" +msgstr "ändern" + +#: merge-recursive.c:1564 +msgid "modified" +msgstr "geändert" + +#: merge-recursive.c:1574 +msgid "content" +msgstr "Inhalt" + +#: merge-recursive.c:1581 +msgid "add/add" +msgstr "hinzufügen/hinzufügen" + +#: merge-recursive.c:1615 +#, c-format +msgid "Skipped %s (merged same as existing)" +msgstr "%s ausgelassen (Ergebnis der Zusammenführung existiert bereits)" + +#: merge-recursive.c:1629 +#, c-format +msgid "Auto-merging %s" +msgstr "automatische Zusammenführung von %s" + +#: merge-recursive.c:1633 git-submodule.sh:893 +msgid "submodule" +msgstr "Unterprojekt" + +#: merge-recursive.c:1634 +#, c-format +msgid "CONFLICT (%s): Merge conflict in %s" +msgstr "KONFLIKT (%s): Zusammenführungskonflikt in %s" + +#: merge-recursive.c:1724 +#, c-format +msgid "Removing %s" +msgstr "Entferne %s" + +#: merge-recursive.c:1749 +msgid "file/directory" +msgstr "Datei/Verzeichnis" + +#: merge-recursive.c:1755 +msgid "directory/file" +msgstr "Verzeichnis/Datei" + +#: merge-recursive.c:1760 +#, c-format +msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s" +msgstr "" +"KONFLIKT (%s): Es existiert bereits ein Verzeichnis %s in %s. Füge %s als %s " +"hinzu." + +#: merge-recursive.c:1770 +#, c-format +msgid "Adding %s" +msgstr "Füge %s hinzu" + +#: merge-recursive.c:1787 +msgid "Fatal merge failure, shouldn't happen." +msgstr "Fataler Fehler bei der Zusammenführung. Sollte nicht passieren." + +#: merge-recursive.c:1806 +msgid "Already up-to-date!" +msgstr "Bereits aktuell!" + +#: merge-recursive.c:1815 +#, c-format +msgid "merging of trees %s and %s failed" +msgstr "Zusammenführen der Bäume %s und %s fehlgeschlagen" + +#: merge-recursive.c:1845 +#, c-format +msgid "Unprocessed path??? %s" +msgstr "unverarbeiteter Pfad??? %s" + +#: merge-recursive.c:1890 +msgid "Merging:" +msgstr "Zusammenführung:" + +#: merge-recursive.c:1903 +#, c-format +msgid "found %u common ancestor:" +msgid_plural "found %u common ancestors:" +msgstr[0] "%u gemeinsamen Vorfahren gefunden" +msgstr[1] "%u gemeinsame Vorfahren gefunden" + +#: merge-recursive.c:1940 +msgid "merge returned no commit" +msgstr "Zusammenführung hat keine Version zurückgegeben" + +#: merge-recursive.c:1997 +#, c-format +msgid "Could not parse object '%s'" +msgstr "Konnte Objekt '%s' nicht parsen." + +#: merge-recursive.c:2009 builtin/merge.c:643 +msgid "Unable to write index." +msgstr "Konnte Bereitstellung nicht schreiben." + +#: parse-options.c:494 msgid "..." msgstr "..." -#: parse-options.c:511 +#: parse-options.c:512 #, c-format msgid "usage: %s" msgstr "Verwendung: %s" #. TRANSLATORS: the colon here should align with the #. one in "usage: %s" translation -#: parse-options.c:515 +#: parse-options.c:516 #, c-format msgid " or: %s" msgstr " oder: %s" -#: parse-options.c:518 +#: parse-options.c:519 #, c-format msgid " %s" msgstr " %s" -#: remote.c:1629 +#: remote.c:1632 #, c-format msgid "Your branch is ahead of '%s' by %d commit.\n" msgid_plural "Your branch is ahead of '%s' by %d commits.\n" msgstr[0] "Dein Zweig ist vor '%s' um %d Version.\n" msgstr[1] "Dein Zweig ist vor '%s' um %d Versionen.\n" -#: remote.c:1635 +#: remote.c:1637 +msgid " (use \"git push\" to publish your local commits)\n" +msgstr " (benutze \"git push\" um deine lokalen Versionen herauszubringen)\n" + +#: remote.c:1640 #, c-format msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n" msgid_plural "" @@ -382,7 +739,12 @@ msgstr[1] "" "Dein Zweig ist zu '%s' um %d Versionen hinterher, und kann vorgespult " "werden.\n" -#: remote.c:1643 +#: remote.c:1647 +msgid " (use \"git pull\" to update your local branch)\n" +msgstr "" +" (benutze \"git pull\" um deinen lokalen Zweig zu aktualisieren)\n" + +#: remote.c:1650 #, c-format msgid "" "Your branch and '%s' have diverged,\n" @@ -397,19 +759,24 @@ msgstr[1] "" "Dein Zweig und '%s' sind divergiert,\n" "und haben jeweils %d und %d unterschiedliche Versionen.\n" -#: sequencer.c:121 builtin/merge.c:865 builtin/merge.c:978 -#: builtin/merge.c:1088 builtin/merge.c:1098 +#: remote.c:1659 +msgid " (use \"git pull\" to merge the remote branch into yours)\n" +msgstr "" +" (benutze \"git pull\" um deinen Zweig mit dem externen zusammenzuführen)\n" + +#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984 +#: builtin/merge.c:994 #, c-format msgid "Could not open '%s' for writing" msgstr "Konnte '%s' nicht zum Schreiben öffnen." -#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:868 -#: builtin/merge.c:1090 builtin/merge.c:1103 +#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986 +#: builtin/merge.c:999 #, c-format msgid "Could not write to '%s'" msgstr "Konnte nicht nach '%s' schreiben." -#: sequencer.c:144 +#: sequencer.c:146 msgid "" "after resolving the conflicts, mark the corrected paths\n" "with 'git add <paths>' or 'git rm <paths>'" @@ -417,7 +784,7 @@ msgstr "" "nach Auflösung der Konflikte, markiere die korrigierten Pfade\n" "mit 'git add <Pfade>' oder 'git rm <Pfade>'" -#: sequencer.c:147 +#: sequencer.c:149 msgid "" "after resolving the conflicts, mark the corrected paths\n" "with 'git add <paths>' or 'git rm <paths>'\n" @@ -427,74 +794,74 @@ msgstr "" "mit 'git add <Pfade>' oder 'git rm <Pfade>'und trage das Ergebnis ein mit " "'git commit'" -#: sequencer.c:160 sequencer.c:758 sequencer.c:841 +#: sequencer.c:162 sequencer.c:770 sequencer.c:853 #, c-format msgid "Could not write to %s" msgstr "Konnte nicht nach %s schreiben" -#: sequencer.c:163 +#: sequencer.c:165 #, c-format msgid "Error wrapping up %s" msgstr "Fehler bei Nachbereitung von %s" -#: sequencer.c:178 +#: sequencer.c:180 msgid "Your local changes would be overwritten by cherry-pick." msgstr "" "Deine lokalen Änderungen würden von \"cherry-pick\" überschrieben werden." -#: sequencer.c:180 +#: sequencer.c:182 msgid "Your local changes would be overwritten by revert." msgstr "Deine lokalen Änderungen würden von \"revert\" überschrieben werden." -#: sequencer.c:183 +#: sequencer.c:185 msgid "Commit your changes or stash them to proceed." msgstr "Trage deine Änderungen ein oder benutze \"stash\" um fortzufahren." #. TRANSLATORS: %s will be "revert" or "cherry-pick" -#: sequencer.c:233 +#: sequencer.c:235 #, c-format msgid "%s: Unable to write new index file" msgstr "%s: Konnte neue Bereitstellungsdatei nicht schreiben" -#: sequencer.c:261 +#: sequencer.c:266 msgid "Could not resolve HEAD commit\n" msgstr "Konnte Version der Zweigspitze (HEAD) nicht auflösen\n" -#: sequencer.c:282 +#: sequencer.c:287 msgid "Unable to update cache tree\n" msgstr "Konnte zwischengespeicherten Baum nicht aktualisieren\n" -#: sequencer.c:324 +#: sequencer.c:332 #, c-format msgid "Could not parse commit %s\n" msgstr "Konnte Version %s nicht parsen\n" -#: sequencer.c:329 +#: sequencer.c:337 #, c-format msgid "Could not parse parent commit %s\n" msgstr "Konnte Elternversion %s nicht parsen\n" -#: sequencer.c:395 +#: sequencer.c:403 msgid "Your index file is unmerged." msgstr "Deine Bereitstellungsdatei ist nicht zusammengeführt." -#: sequencer.c:398 +#: sequencer.c:406 msgid "You do not have a valid HEAD" msgstr "Du hast keine gültige Zweigspitze (HEAD)" -#: sequencer.c:413 +#: sequencer.c:421 #, c-format msgid "Commit %s is a merge but no -m option was given." msgstr "" "Version %s ist eine Zusammenführung, aber die Option -m wurde nicht " "angegeben." -#: sequencer.c:421 +#: sequencer.c:429 #, c-format msgid "Commit %s does not have parent %d" msgstr "Version %s hat keinen Elternteil %d" -#: sequencer.c:425 +#: sequencer.c:433 #, c-format msgid "Mainline was specified but commit %s is not a merge." msgstr "" @@ -502,430 +869,563 @@ msgstr "" #. TRANSLATORS: The first %s will be "revert" or #. "cherry-pick", the second %s a SHA1 -#: sequencer.c:436 +#: sequencer.c:444 #, c-format msgid "%s: cannot parse parent commit %s" msgstr "%s: kann Elternversion %s nicht parsen" -#: sequencer.c:440 +#: sequencer.c:448 #, c-format msgid "Cannot get commit message for %s" msgstr "Kann keine Versionsbeschreibung für %s bekommen" -#: sequencer.c:524 +#: sequencer.c:532 #, c-format msgid "could not revert %s... %s" msgstr "Konnte %s nicht zurücksetzen... %s" -#: sequencer.c:525 +#: sequencer.c:533 #, c-format msgid "could not apply %s... %s" msgstr "Konnte %s nicht anwenden... %s" -#: sequencer.c:553 +#: sequencer.c:565 msgid "empty commit set passed" msgstr "leere Menge von Versionen übergeben" -#: sequencer.c:561 +#: sequencer.c:573 #, c-format msgid "git %s: failed to read the index" msgstr "git %s: Fehler beim Lesen der Bereitstellung" -#: sequencer.c:566 +#: sequencer.c:578 #, c-format msgid "git %s: failed to refresh the index" msgstr "git %s: Fehler beim Aktualisieren der Bereitstellung" -#: sequencer.c:624 +#: sequencer.c:636 #, c-format msgid "Cannot %s during a %s" msgstr "Kann %s nicht während eines %s durchführen" -#: sequencer.c:646 +#: sequencer.c:658 #, c-format msgid "Could not parse line %d." msgstr "Konnte Zeile %d nicht parsen." -#: sequencer.c:651 +#: sequencer.c:663 msgid "No commits parsed." msgstr "Keine Versionen geparst." -#: sequencer.c:664 +#: sequencer.c:676 #, c-format msgid "Could not open %s" msgstr "Konnte %s nicht öffnen" -#: sequencer.c:668 +#: sequencer.c:680 #, c-format msgid "Could not read %s." msgstr "Konnte %s nicht lesen." -#: sequencer.c:675 +#: sequencer.c:687 #, c-format msgid "Unusable instruction sheet: %s" msgstr "Unbenutzbares Instruktionsblatt: %s" -#: sequencer.c:703 +#: sequencer.c:715 #, c-format msgid "Invalid key: %s" msgstr "Ungültiger Schlüssel: %s" -#: sequencer.c:706 +#: sequencer.c:718 #, c-format msgid "Invalid value for %s: %s" msgstr "Ungültiger Wert für %s: %s" -#: sequencer.c:718 +#: sequencer.c:730 #, c-format msgid "Malformed options sheet: %s" msgstr "Fehlerhaftes Optionsblatt: %s" -#: sequencer.c:739 +#: sequencer.c:751 msgid "a cherry-pick or revert is already in progress" msgstr "\"cherry-pick\" oder \"revert\" ist bereits im Gang" -#: sequencer.c:740 +#: sequencer.c:752 msgid "try \"git cherry-pick (--continue | --quit | --abort)\"" msgstr "versuche \"git cherry-pick (--continue | --quit | --abort)\"" -#: sequencer.c:744 +#: sequencer.c:756 #, c-format msgid "Could not create sequencer directory %s" msgstr "Konnte \"sequencer\"-Verzeichnis %s nicht erstellen" -#: sequencer.c:760 sequencer.c:845 +#: sequencer.c:772 sequencer.c:857 #, c-format msgid "Error wrapping up %s." msgstr "Fehler beim Einpacken von %s." -#: sequencer.c:779 sequencer.c:913 +#: sequencer.c:791 sequencer.c:925 msgid "no cherry-pick or revert in progress" msgstr "kein \"cherry-pick\" oder \"revert\" im Gang" -#: sequencer.c:781 +#: sequencer.c:793 msgid "cannot resolve HEAD" msgstr "kann Zweigspitze (HEAD) nicht auflösen" -#: sequencer.c:783 +#: sequencer.c:795 msgid "cannot abort from a branch yet to be born" msgstr "kann nicht abbrechen: bin auf einem Zweig, der noch geboren wird" -#: sequencer.c:805 builtin/apply.c:3697 +#: sequencer.c:817 builtin/apply.c:4005 #, c-format msgid "cannot open %s: %s" msgstr "Kann %s nicht öffnen: %s" -#: sequencer.c:808 +#: sequencer.c:820 #, c-format msgid "cannot read %s: %s" msgstr "Kann %s nicht lesen: %s" -#: sequencer.c:809 +#: sequencer.c:821 msgid "unexpected end of file" msgstr "Unerwartetes Dateiende" -#: sequencer.c:815 +#: sequencer.c:827 #, c-format msgid "stored pre-cherry-pick HEAD file '%s' is corrupt" msgstr "" "gespeicherte \"pre-cherry-pick\" Datei der Zweigspitze (HEAD) '%s' ist " "beschädigt" -#: sequencer.c:838 +#: sequencer.c:850 #, c-format msgid "Could not format %s." msgstr "Konnte %s nicht formatieren." -#: sequencer.c:1000 +#: sequencer.c:1012 msgid "Can't revert as initial commit" msgstr "Kann nicht zu initialer Version zurücksetzen." -#: sequencer.c:1001 +#: sequencer.c:1013 msgid "Can't cherry-pick into empty head" msgstr "Kann \"cherry-pick\" nicht in einem leerem Kopf ausführen." -#: sha1_name.c:864 +#: sha1_name.c:1044 msgid "HEAD does not point to a branch" msgstr "Zweigspitze (HEAD) zeigt auf keinen Zweig" -#: sha1_name.c:867 +#: sha1_name.c:1047 #, c-format msgid "No such branch: '%s'" msgstr "Kein solcher Zweig '%s'" -#: sha1_name.c:869 +#: sha1_name.c:1049 #, c-format msgid "No upstream configured for branch '%s'" msgstr "Kein entferntes Projektarchiv für Zweig '%s' konfiguriert." -#: sha1_name.c:872 +#: sha1_name.c:1052 #, c-format msgid "Upstream branch '%s' not stored as a remote-tracking branch" msgstr "" "Zweig '%s' des entfernten Projektarchivs ist kein gefolgter Übernahmezweig" -#: wrapper.c:413 +#: wrapper.c:408 +#, c-format +msgid "unable to access '%s': %s" +msgstr "konnte nicht auf '%s' zugreifen: %s" + +#: wrapper.c:426 #, c-format msgid "unable to look up current user in the passwd file: %s" msgstr "konnte aktuellen Benutzer nicht in Passwort-Datei finden: %s" -#: wrapper.c:414 +#: wrapper.c:427 msgid "no such user" msgstr "kein solcher Benutzer" -#: wt-status.c:135 +#: wt-status.c:140 msgid "Unmerged paths:" msgstr "Nicht zusammengeführte Pfade:" -#: wt-status.c:141 wt-status.c:158 +#: wt-status.c:167 wt-status.c:194 #, c-format msgid " (use \"git reset %s <file>...\" to unstage)" msgstr "" " (benutze \"git reset %s <Datei>...\" zum Herausnehmen aus der " "Bereitstellung)" -#: wt-status.c:143 wt-status.c:160 +#: wt-status.c:169 wt-status.c:196 msgid " (use \"git rm --cached <file>...\" to unstage)" msgstr "" " (benutze \"git rm --cached <Datei>...\" zum Herausnehmen aus der " "Bereitstellung)" -#: wt-status.c:144 +#: wt-status.c:173 +msgid " (use \"git add <file>...\" to mark resolution)" +msgstr " (benutze \"git add/rm <Datei>...\" um die Auflösung zu markieren)" + +#: wt-status.c:175 wt-status.c:179 msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" msgstr "" " (benutze \"git add/rm <Datei>...\" um die Auflösung entsprechend zu " "markieren)" -#: wt-status.c:152 +#: wt-status.c:177 +msgid " (use \"git rm <file>...\" to mark resolution)" +msgstr " (benutze \"git add/rm <Datei>...\" um die Auflösung zu markieren)" + +#: wt-status.c:188 msgid "Changes to be committed:" msgstr "zum Eintragen bereitgestellte Änderungen:" -#: wt-status.c:170 +#: wt-status.c:206 msgid "Changes not staged for commit:" msgstr "Änderungen, die nicht zum Eintragen bereitgestellt sind:" -#: wt-status.c:174 +#: wt-status.c:210 msgid " (use \"git add <file>...\" to update what will be committed)" msgstr " (benutze \"git add <Datei>...\" zum Bereitstellen)" -#: wt-status.c:176 +#: wt-status.c:212 msgid " (use \"git add/rm <file>...\" to update what will be committed)" msgstr " (benutze \"git add/rm <Datei>...\" zum Bereitstellen)" -#: wt-status.c:177 +#: wt-status.c:213 msgid "" " (use \"git checkout -- <file>...\" to discard changes in working directory)" msgstr "" " (benutze \"git checkout -- <Datei>...\" um die Änderungen im " "Arbeitsverzeichnis zu verwerfen)" -#: wt-status.c:179 +#: wt-status.c:215 msgid " (commit or discard the untracked or modified content in submodules)" msgstr "" " (trage ein oder verwerfe den unbeobachteten oder geänderten Inhalt in den " "Unterprojekten)" -#: wt-status.c:188 -#, c-format -msgid "%s files:" -msgstr "%s Dateien:" - -#: wt-status.c:191 +#: wt-status.c:227 #, c-format msgid " (use \"git %s <file>...\" to include in what will be committed)" msgstr " (benutze \"git %s <Datei>...\" zum Einfügen in die Eintragung)" -#: wt-status.c:208 +#: wt-status.c:244 msgid "bug" msgstr "Fehler" -#: wt-status.c:213 +#: wt-status.c:249 msgid "both deleted:" msgstr "beide gelöscht:" -#: wt-status.c:214 +#: wt-status.c:250 msgid "added by us:" msgstr "von uns hinzugefügt:" -#: wt-status.c:215 +#: wt-status.c:251 msgid "deleted by them:" msgstr "von denen gelöscht:" -#: wt-status.c:216 +#: wt-status.c:252 msgid "added by them:" msgstr "von denen hinzugefügt:" -#: wt-status.c:217 +#: wt-status.c:253 msgid "deleted by us:" msgstr "von uns gelöscht:" -#: wt-status.c:218 +#: wt-status.c:254 msgid "both added:" msgstr "von beiden hinzugefügt:" -#: wt-status.c:219 +#: wt-status.c:255 msgid "both modified:" msgstr "von beiden geändert:" -#: wt-status.c:249 +#: wt-status.c:285 msgid "new commits, " msgstr "neue Versionen, " -#: wt-status.c:251 +#: wt-status.c:287 msgid "modified content, " msgstr "geänderter Inhalt, " -#: wt-status.c:253 +#: wt-status.c:289 msgid "untracked content, " msgstr "unbeobachteter Inhalt, " -#: wt-status.c:267 +#: wt-status.c:303 #, c-format msgid "new file: %s" msgstr "neue Datei: %s" -#: wt-status.c:270 +#: wt-status.c:306 #, c-format msgid "copied: %s -> %s" msgstr "kopiert: %s -> %s" -#: wt-status.c:273 +#: wt-status.c:309 #, c-format msgid "deleted: %s" msgstr "gelöscht: %s" -#: wt-status.c:276 +#: wt-status.c:312 #, c-format msgid "modified: %s" msgstr "geändert: %s" -#: wt-status.c:279 +#: wt-status.c:315 #, c-format msgid "renamed: %s -> %s" msgstr "umbenannt: %s -> %s" -#: wt-status.c:282 +#: wt-status.c:318 #, c-format msgid "typechange: %s" msgstr "Typänderung: %s" -#: wt-status.c:285 +#: wt-status.c:321 #, c-format msgid "unknown: %s" msgstr "unbekannt: %s" -#: wt-status.c:288 +#: wt-status.c:324 #, c-format msgid "unmerged: %s" msgstr "nicht zusammengeführt: %s" -#: wt-status.c:291 +#: wt-status.c:327 #, c-format msgid "bug: unhandled diff status %c" msgstr "Fehler: unbehandelter Differenz-Status %c" -#: wt-status.c:737 +#: wt-status.c:785 +msgid "You have unmerged paths." +msgstr "Du hast nicht zusammengeführte Pfade." + +#: wt-status.c:788 wt-status.c:912 +msgid " (fix conflicts and run \"git commit\")" +msgstr " (behebe die Konflikte und führe \"git commit\" aus)" + +#: wt-status.c:791 +msgid "All conflicts fixed but you are still merging." +msgstr "" +"Alle Konflikte sind behoben, aber du bist immer noch beim Zusammenführen." + +#: wt-status.c:794 +msgid " (use \"git commit\" to conclude merge)" +msgstr " (benutze \"git commit\" um die Zusammenführung abzuschließen)" + +#: wt-status.c:804 +msgid "You are in the middle of an am session." +msgstr "Eine \"am\"-Sitzung ist im Gange." + +#: wt-status.c:807 +msgid "The current patch is empty." +msgstr "Der aktuelle Patch ist leer." + +#: wt-status.c:811 +msgid " (fix conflicts and then run \"git am --resolved\")" +msgstr " (behebe die Konflikte und führe dann \"git am --resolved\" aus)" + +#: wt-status.c:813 +msgid " (use \"git am --skip\" to skip this patch)" +msgstr " (benutze \"git am --skip\" um diesen Patch auszulassen)" + +#: wt-status.c:815 +msgid " (use \"git am --abort\" to restore the original branch)" +msgstr "" +" (benutze \"git am --abort\" um den ursprünglichen Zweig wiederherzustellen)" + +#: wt-status.c:873 wt-status.c:883 +msgid "You are currently rebasing." +msgstr "Du bist gerade beim Neuaufbau." + +#: wt-status.c:876 +msgid " (fix conflicts and then run \"git rebase --continue\")" +msgstr " (behebe die Konflikte und führe dann \"git rebase --continue\" aus)" + +#: wt-status.c:878 +msgid " (use \"git rebase --skip\" to skip this patch)" +msgstr " (benutze \"git rebase --skip\" um diesen Patch auszulassen)" + +#: wt-status.c:880 +msgid " (use \"git rebase --abort\" to check out the original branch)" +msgstr "" +" (benutze \"git rebase --abort\" um den ursprünglichen Zweig auszuchecken)" + +#: wt-status.c:886 +msgid " (all conflicts fixed: run \"git rebase --continue\")" +msgstr " (alle Konflikte behoben: führe \"git rebase --continue\" aus)" + +#: wt-status.c:888 +msgid "You are currently splitting a commit during a rebase." +msgstr "Du teilst gerade eine Version während eines Neuaufbaus auf." + +#: wt-status.c:891 +msgid " (Once your working directory is clean, run \"git rebase --continue\")" +msgstr "" +" (Sobald dein Arbeitsverzeichnis sauber ist, führe \"git rebase --continue" +"\" aus)" + +#: wt-status.c:893 +msgid "You are currently editing a commit during a rebase." +msgstr "Du editierst gerade eine Version während eines Neuaufbaus." + +#: wt-status.c:896 +msgid " (use \"git commit --amend\" to amend the current commit)" +msgstr "" +" (benutze \"git commit --amend\" um die aktuelle Version nachzubessern)" + +#: wt-status.c:898 +msgid "" +" (use \"git rebase --continue\" once you are satisfied with your changes)" +msgstr "" +" (benutze \"git rebase --continue\" sobald deine Änderungen abgeschlossen " +"sind)" + +#: wt-status.c:908 +msgid "You are currently cherry-picking." +msgstr "Du führst gerade \"cherry-pick\" aus." + +#: wt-status.c:915 +msgid " (all conflicts fixed: run \"git commit\")" +msgstr " (alle Konflikte behoben: führe \"git commit\" aus)" + +#: wt-status.c:924 +msgid "You are currently bisecting." +msgstr "Du bist gerade beim Halbieren." + +#: wt-status.c:927 +msgid " (use \"git bisect reset\" to get back to the original branch)" +msgstr "" +" (benutze \"git bisect reset\" um zum ursprünglichen Zweig zurückzukehren)" + +#: wt-status.c:978 msgid "On branch " msgstr "Auf Zweig " -#: wt-status.c:744 +#: wt-status.c:985 msgid "Not currently on any branch." msgstr "Im Moment auf keinem Zweig." -#: wt-status.c:755 +#: wt-status.c:997 msgid "Initial commit" msgstr "Initiale Version" -#: wt-status.c:769 -msgid "Untracked" -msgstr "Unbeobachtete" +#: wt-status.c:1011 +msgid "Untracked files" +msgstr "Unbeobachtete Dateien" -#: wt-status.c:771 -msgid "Ignored" -msgstr "Ignorierte" +#: wt-status.c:1013 +msgid "Ignored files" +msgstr "Ignorierte Dateien" -#: wt-status.c:773 +#: wt-status.c:1015 #, c-format msgid "Untracked files not listed%s" msgstr "Unbeobachtete Dateien nicht aufgelistet%s" -#: wt-status.c:775 +#: wt-status.c:1017 msgid " (use -u option to show untracked files)" msgstr " (benutze die Option -u um unbeobachteten Dateien anzuzeigen)" -#: wt-status.c:781 +#: wt-status.c:1023 msgid "No changes" msgstr "Keine Änderungen" -#: wt-status.c:785 +#: wt-status.c:1028 #, c-format -msgid "no changes added to commit%s\n" -msgstr "keine Änderungen zum Eintragen hinzugefügt%s\n" +msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n" +msgstr "" +"keine Änderungen zum Eintragen hinzugefügt (benutze \"git add\" und/oder " +"\"git commit -a\")\n" -#: wt-status.c:787 -msgid " (use \"git add\" and/or \"git commit -a\")" -msgstr " (benutze \"git add\" und/oder \"git commit -a\")" +#: wt-status.c:1031 +#, c-format +msgid "no changes added to commit\n" +msgstr "keine Änderungen zum Eintragen hinzugefügt\n" -#: wt-status.c:789 +#: wt-status.c:1034 #, c-format -msgid "nothing added to commit but untracked files present%s\n" +msgid "" +"nothing added to commit but untracked files present (use \"git add\" to " +"track)\n" msgstr "" -"nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien%s\n" +"nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien " +"(benutze \"git add\" zum Beobachten)\n" -#: wt-status.c:791 -msgid " (use \"git add\" to track)" -msgstr " (benutze \"git add\" zum Beobachten)" +#: wt-status.c:1037 +#, c-format +msgid "nothing added to commit but untracked files present\n" +msgstr "nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien\n" -#: wt-status.c:793 wt-status.c:796 wt-status.c:799 +#: wt-status.c:1040 #, c-format -msgid "nothing to commit%s\n" -msgstr "nichts zum Eintragen%s\n" +msgid "nothing to commit (create/copy files and use \"git add\" to track)\n" +msgstr "" +"nichts einzutragen (Erstelle/Kopiere Dateien und benutze \"git add\" zum " +"Beobachten)\n" -#: wt-status.c:794 -msgid " (create/copy files and use \"git add\" to track)" -msgstr " (Erstelle/Kopiere Dateien und benutze \"git add\" zum Beobachten)" +#: wt-status.c:1043 wt-status.c:1048 +#, c-format +msgid "nothing to commit\n" +msgstr "nichts einzutragen\n" -#: wt-status.c:797 -msgid " (use -u to show untracked files)" -msgstr " (benutze die Option -u um unbeobachtete Dateien anzuzeigen)" +#: wt-status.c:1046 +#, c-format +msgid "nothing to commit (use -u to show untracked files)\n" +msgstr "" +"nichts einzutragen (benutze die Option -u, um unbeobachtete Dateien " +"anzuzeigen)\n" -#: wt-status.c:800 -msgid " (working directory clean)" -msgstr " (Arbeitsverzeichnis sauber)" +#: wt-status.c:1050 +#, c-format +msgid "nothing to commit, working directory clean\n" +msgstr "nichts einzutragen, Arbeitsverzeichnis sauber\n" -#: wt-status.c:908 +#: wt-status.c:1158 msgid "HEAD (no branch)" msgstr "HEAD (kein Zweig)" -#: wt-status.c:914 +#: wt-status.c:1164 msgid "Initial commit on " msgstr "Initiale Version auf " -#: wt-status.c:929 +#: wt-status.c:1179 msgid "behind " msgstr "hinterher " -#: wt-status.c:932 wt-status.c:935 +#: wt-status.c:1182 wt-status.c:1185 msgid "ahead " msgstr "voraus " -#: wt-status.c:937 +#: wt-status.c:1187 msgid ", behind " msgstr ", hinterher " +#: compat/precompose_utf8.c:58 builtin/clone.c:341 +#, c-format +msgid "failed to unlink '%s'" +msgstr "Konnte '%s' nicht entfernen" + +#: builtin/add.c:19 +msgid "git add [options] [--] <filepattern>..." +msgstr "git add [Optionen] [--] [<Dateimuster>...]" + #: builtin/add.c:62 #, c-format msgid "unexpected diff status %c" msgstr "unerwarteter Differenz-Status %c" -#: builtin/add.c:67 builtin/commit.c:226 +#: builtin/add.c:67 builtin/commit.c:231 msgid "updating files failed" msgstr "Aktualisierung der Dateien fehlgeschlagen" #: builtin/add.c:77 #, c-format msgid "remove '%s'\n" -msgstr "entferne '%s'\n" +msgstr "lösche '%s'\n" #: builtin/add.c:176 #, c-format @@ -937,7 +1437,7 @@ msgid "Unstaged changes after refreshing the index:" msgstr "" "Nicht bereitgestellte Änderungen nach Aktualisierung der Bereitstellung:" -#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186 +#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:275 #, c-format msgid "pathspec '%s' did not match any files" msgstr "Pfadspezifikation '%s' stimmt mit keinen Dateien überein" @@ -974,117 +1474,172 @@ msgstr "Leerer Patch. Abgebrochen." msgid "Could not apply '%s'" msgstr "Konnte '%s' nicht anwenden." -#: builtin/add.c:312 +#: builtin/add.c:313 msgid "The following paths are ignored by one of your .gitignore files:\n" msgstr "" "Die folgenden Pfade werden durch eine deiner \".gitignore\" Dateien " "ignoriert:\n" -#: builtin/add.c:352 +#: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63 +#: builtin/prune-packed.c:76 builtin/push.c:388 builtin/remote.c:1253 +#: builtin/rm.c:206 +msgid "dry run" +msgstr "Probelauf" + +#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1160 +#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1483 +#: builtin/mv.c:62 builtin/read-tree.c:112 +msgid "be verbose" +msgstr "erweiterte Ausgaben" + +#: builtin/add.c:322 +msgid "interactive picking" +msgstr "interaktives Auswählen" + +#: builtin/add.c:323 builtin/checkout.c:1031 builtin/reset.c:248 +msgid "select hunks interactively" +msgstr "interaktiv Bereiche auswählen" + +#: builtin/add.c:324 +msgid "edit current diff and apply" +msgstr "aktuelle Unterschiede editieren und anwenden" + +#: builtin/add.c:325 +msgid "allow adding otherwise ignored files" +msgstr "erlaubt das Hinzufügen andernfalls ignorierter Dateien" + +#: builtin/add.c:326 +msgid "update tracked files" +msgstr "aktualisiert beobachtete Dateien" + +#: builtin/add.c:327 +msgid "record only the fact that the path will be added later" +msgstr "speichert nur, dass der Pfad später hinzugefügt werden soll" + +#: builtin/add.c:328 +msgid "add changes from all tracked and untracked files" +msgstr "" +"fügt Änderungen von allen beobachteten und unbeobachteten Dateien hinzu" + +#: builtin/add.c:329 +msgid "don't add, only refresh the index" +msgstr "fügt nichts hinzu, aktualisiert nur die Bereitstellung" + +#: builtin/add.c:330 +msgid "just skip files which cannot be added because of errors" +msgstr "" +"überspringt Dateien, die aufgrund von Fehlern nicht hinzugefügt werden " +"konnten" + +#: builtin/add.c:331 +msgid "check if - even missing - files are ignored in dry run" +msgstr "prüft ob - auch fehlende - Dateien im Probelauf ignoriert werden" + +#: builtin/add.c:353 #, c-format msgid "Use -f if you really want to add them.\n" msgstr "Verwende -f wenn du diese wirklich hinzufügen möchtest.\n" -#: builtin/add.c:353 +#: builtin/add.c:354 msgid "no files added" msgstr "keine Dateien hinzugefügt" -#: builtin/add.c:359 +#: builtin/add.c:360 msgid "adding files failed" msgstr "Hinzufügen von Dateien fehlgeschlagen" -#: builtin/add.c:391 +#: builtin/add.c:392 msgid "-A and -u are mutually incompatible" msgstr "-A und -u sind zueinander inkompatibel" -#: builtin/add.c:393 +#: builtin/add.c:394 msgid "Option --ignore-missing can only be used together with --dry-run" msgstr "" "Die Option --ignore-missing kann nur zusammen mit --dry-run benutzt werden." -#: builtin/add.c:413 +#: builtin/add.c:414 #, c-format msgid "Nothing specified, nothing added.\n" msgstr "Nichts spezifiziert, nichts hinzugefügt.\n" -#: builtin/add.c:414 +#: builtin/add.c:415 #, c-format msgid "Maybe you wanted to say 'git add .'?\n" msgstr "Wolltest du vielleicht 'git add .' sagen?\n" -#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82 -#: builtin/rm.c:162 +#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:291 builtin/mv.c:82 +#: builtin/rm.c:235 msgid "index file corrupt" msgstr "Bereitstellungsdatei beschädigt" -#: builtin/add.c:476 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260 +#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:370 msgid "Unable to write new index file" msgstr "Konnte neue Bereitstellungsdatei nicht schreiben." -#: builtin/apply.c:53 +#: builtin/apply.c:57 msgid "git apply [options] [<patch>...]" msgstr "git apply [Optionen] [<Patch>...]" -#: builtin/apply.c:106 +#: builtin/apply.c:110 #, c-format msgid "unrecognized whitespace option '%s'" msgstr "nicht erkannte Option für Leerzeichen: '%s'" -#: builtin/apply.c:121 +#: builtin/apply.c:125 #, c-format msgid "unrecognized whitespace ignore option '%s'" msgstr "nicht erkannte Option zum Ignorieren von Leerzeichen: '%s'" -#: builtin/apply.c:815 +#: builtin/apply.c:823 #, c-format msgid "Cannot prepare timestamp regexp %s" msgstr "Kann regulären Ausdruck für Zeitstempel %s nicht verarbeiten" -#: builtin/apply.c:824 +#: builtin/apply.c:832 #, c-format msgid "regexec returned %d for input: %s" msgstr "Ausführung des regulären Ausdrucks gab %d zurück. Eingabe: %s" -#: builtin/apply.c:905 +#: builtin/apply.c:913 #, c-format msgid "unable to find filename in patch at line %d" msgstr "Konnte keinen Dateinamen in Zeile %d des Patches finden." -#: builtin/apply.c:937 +#: builtin/apply.c:945 #, c-format msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" msgstr "" "git apply: ungültiges 'git-diff' - erwartete /dev/null, erhielt %s in Zeile " "%d" -#: builtin/apply.c:941 +#: builtin/apply.c:949 #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "" "git apply: ungültiges 'git-diff' - Inkonsistenter neuer Dateiname in Zeile %d" -#: builtin/apply.c:942 +#: builtin/apply.c:950 #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "" "git apply: ungültiges 'git-diff' - Inkonsistenter alter Dateiname in Zeile %d" -#: builtin/apply.c:949 +#: builtin/apply.c:957 #, c-format msgid "git apply: bad git-diff - expected /dev/null on line %d" msgstr "git apply: ungültiges 'git-diff' - erwartete /dev/null in Zeile %d" -#: builtin/apply.c:1394 +#: builtin/apply.c:1420 #, c-format msgid "recount: unexpected line: %.*s" msgstr "recount: unerwartete Zeile: %.*s" -#: builtin/apply.c:1451 +#: builtin/apply.c:1477 #, c-format msgid "patch fragment without header at line %d: %.*s" msgstr "Patch-Fragment ohne Kopfbereich bei Zeile %d: %.*s" -#: builtin/apply.c:1468 +#: builtin/apply.c:1494 #, c-format msgid "" "git diff header lacks filename information when removing %d leading pathname " @@ -1099,70 +1654,70 @@ msgstr[1] "" "Dem Kopfbereich von \"git diff\" fehlen Informationen zum Dateinamen, wenn " "%d vorangestellte Teile des Pfades entfernt werden (Zeile %d)" -#: builtin/apply.c:1628 +#: builtin/apply.c:1654 msgid "new file depends on old contents" msgstr "neue Datei hängt von alten Inhalten ab" -#: builtin/apply.c:1630 +#: builtin/apply.c:1656 msgid "deleted file still has contents" msgstr "entfernte Datei hat noch Inhalte" -#: builtin/apply.c:1656 +#: builtin/apply.c:1682 #, c-format msgid "corrupt patch at line %d" msgstr "fehlerhafter Patch bei Zeile %d" -#: builtin/apply.c:1692 +#: builtin/apply.c:1718 #, c-format msgid "new file %s depends on old contents" msgstr "neue Datei %s hängt von alten Inhalten ab" -#: builtin/apply.c:1694 +#: builtin/apply.c:1720 #, c-format msgid "deleted file %s still has contents" msgstr "entfernte Datei %s hat noch Inhalte" -#: builtin/apply.c:1697 +#: builtin/apply.c:1723 #, c-format msgid "** warning: file %s becomes empty but is not deleted" msgstr "** Warnung: Datei %s wird leer, aber nicht entfernt." -#: builtin/apply.c:1843 +#: builtin/apply.c:1869 #, c-format msgid "corrupt binary patch at line %d: %.*s" msgstr "fehlerhafter Binär-Patch bei Zeile %d: %.*s" #. there has to be one hunk (forward hunk) -#: builtin/apply.c:1872 +#: builtin/apply.c:1898 #, c-format msgid "unrecognized binary patch at line %d" msgstr "nicht erkannter Binär-Patch bei Zeile %d" -#: builtin/apply.c:1958 +#: builtin/apply.c:1984 #, c-format msgid "patch with only garbage at line %d" msgstr "Patch mit nutzlosen Informationen bei Zeile %d" -#: builtin/apply.c:2048 +#: builtin/apply.c:2074 #, c-format msgid "unable to read symlink %s" msgstr "konnte symbolische Verknüpfung %s nicht lesen" -#: builtin/apply.c:2052 +#: builtin/apply.c:2078 #, c-format msgid "unable to open or read %s" msgstr "konnte %s nicht öffnen oder lesen" -#: builtin/apply.c:2123 +#: builtin/apply.c:2149 msgid "oops" msgstr "Ups" -#: builtin/apply.c:2645 +#: builtin/apply.c:2671 #, c-format msgid "invalid start of line: '%c'" msgstr "Ungültiger Zeilenanfang: '%c'" -#: builtin/apply.c:2763 +#: builtin/apply.c:2789 #, c-format msgid "Hunk #%d succeeded at %d (offset %d line)." msgid_plural "Hunk #%d succeeded at %d (offset %d lines)." @@ -1170,12 +1725,12 @@ msgstr[0] "Patch-Bereich #%d erfolgreich angewendet bei %d (%d Zeile versetzt)" msgstr[1] "" "Patch-Bereich #%d erfolgreich angewendet bei %d (%d Zeilen versetzt)" -#: builtin/apply.c:2775 +#: builtin/apply.c:2801 #, c-format msgid "Context reduced to (%ld/%ld) to apply fragment at %d" msgstr "Kontext reduziert zu (%ld/%ld) um Patch-Bereich bei %d anzuwenden" -#: builtin/apply.c:2781 +#: builtin/apply.c:2807 #, c-format msgid "" "while searching for:\n" @@ -1184,329 +1739,335 @@ msgstr "" "bei der Suche nach:\n" "%.*s" -#: builtin/apply.c:2800 +#: builtin/apply.c:2826 #, c-format msgid "missing binary patch data for '%s'" msgstr "keine Daten in Binär-Patch für '%s'" -#: builtin/apply.c:2903 +#: builtin/apply.c:2929 #, c-format msgid "binary patch does not apply to '%s'" msgstr "Konnte Binär-Patch nicht auf '%s' anwenden" -#: builtin/apply.c:2909 +#: builtin/apply.c:2935 #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" msgstr "" "Binär-Patch für '%s' erzeugt falsches Ergebnis (erwartete %s, bekam %s)" -#: builtin/apply.c:2930 +#: builtin/apply.c:2956 #, c-format msgid "patch failed: %s:%ld" msgstr "Anwendung des Patches fehlgeschlagen: %s:%ld" -#: builtin/apply.c:3045 +#: builtin/apply.c:3078 #, c-format -msgid "patch %s has been renamed/deleted" -msgstr "Patch %s wurde umbenannt/gelöscht" +msgid "cannot checkout %s" +msgstr "kann %s nicht auschecken" -#: builtin/apply.c:3052 builtin/apply.c:3069 +#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176 #, c-format msgid "read of %s failed" msgstr "Konnte %s nicht lesen" -#: builtin/apply.c:3084 -msgid "removal patch leaves file contents" -msgstr "Lösch-Patch hinterlässt Dateiinhalte" - -#: builtin/apply.c:3105 +#: builtin/apply.c:3156 builtin/apply.c:3378 #, c-format -msgid "%s: already exists in working directory" -msgstr "%s existiert bereits im Arbeitsverzeichnis" +msgid "path %s has been renamed/deleted" +msgstr "Pfad %s wurde umbenannt/gelöscht" -#: builtin/apply.c:3143 +#: builtin/apply.c:3237 builtin/apply.c:3392 #, c-format -msgid "%s: has been deleted/renamed" -msgstr "%s wurde gelöscht/umbenannt" +msgid "%s: does not exist in index" +msgstr "%s ist nicht bereitgestellt" -#: builtin/apply.c:3148 builtin/apply.c:3179 +#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: builtin/apply.c:3159 -#, c-format -msgid "%s: does not exist in index" -msgstr "%s ist nicht bereitgestellt" - -#: builtin/apply.c:3173 +#: builtin/apply.c:3246 builtin/apply.c:3400 #, c-format msgid "%s: does not match index" msgstr "%s entspricht nicht der Bereitstellung" -#: builtin/apply.c:3190 +#: builtin/apply.c:3348 +msgid "removal patch leaves file contents" +msgstr "Lösch-Patch hinterlässt Dateiinhalte" + +#: builtin/apply.c:3417 #, c-format msgid "%s: wrong type" msgstr "%s: falscher Typ" -#: builtin/apply.c:3192 +#: builtin/apply.c:3419 #, c-format msgid "%s has type %o, expected %o" msgstr "%s ist vom Typ %o, erwartete %o" -#: builtin/apply.c:3247 +#: builtin/apply.c:3520 #, c-format msgid "%s: already exists in index" msgstr "%s ist bereits bereitgestellt" -#: builtin/apply.c:3267 +#: builtin/apply.c:3523 +#, c-format +msgid "%s: already exists in working directory" +msgstr "%s existiert bereits im Arbeitsverzeichnis" + +#: builtin/apply.c:3543 #, c-format msgid "new mode (%o) of %s does not match old mode (%o)" msgstr "neuer Modus (%o) von %s entspricht nicht dem alten Modus (%o)" -#: builtin/apply.c:3272 +#: builtin/apply.c:3548 #, c-format msgid "new mode (%o) of %s does not match old mode (%o) of %s" msgstr "neuer Modus (%o) von %s entspricht nicht dem alten Modus (%o) von %s" -#: builtin/apply.c:3280 +#: builtin/apply.c:3556 #, c-format msgid "%s: patch does not apply" msgstr "%s: Patch konnte nicht angewendet werden" -#: builtin/apply.c:3293 +#: builtin/apply.c:3569 #, c-format msgid "Checking patch %s..." msgstr "Prüfe Patch %s..." -#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158 +#: builtin/apply.c:3624 builtin/checkout.c:215 builtin/reset.c:158 #, c-format msgid "make_cache_entry failed for path '%s'" msgstr "make_cache_entry für Pfad '%s' fehlgeschlagen" -#: builtin/apply.c:3491 +#: builtin/apply.c:3767 #, c-format msgid "unable to remove %s from index" msgstr "konnte %s nicht aus der Bereitstellung entfernen" -#: builtin/apply.c:3518 +#: builtin/apply.c:3795 #, c-format msgid "corrupt patch for subproject %s" msgstr "fehlerhafter Patch für Unterprojekt %s" -#: builtin/apply.c:3522 +#: builtin/apply.c:3799 #, c-format msgid "unable to stat newly created file '%s'" msgstr "konnte neu erstellte Datei '%s' nicht lesen" -#: builtin/apply.c:3527 +#: builtin/apply.c:3804 #, c-format msgid "unable to create backing store for newly created file %s" msgstr "kann internen Speicher für eben erstellte Datei %s nicht erzeugen" -#: builtin/apply.c:3530 +#: builtin/apply.c:3807 builtin/apply.c:3915 #, c-format msgid "unable to add cache entry for %s" msgstr "kann für %s keinen Eintrag in den Zwischenspeicher hinzufügen" -#: builtin/apply.c:3563 +#: builtin/apply.c:3840 #, c-format msgid "closing file '%s'" msgstr "schließe Datei '%s'" -#: builtin/apply.c:3612 +#: builtin/apply.c:3889 #, c-format msgid "unable to write file '%s' mode %o" msgstr "konnte Datei '%s' mit Modus %o nicht schreiben" -#: builtin/apply.c:3668 +#: builtin/apply.c:3976 #, c-format msgid "Applied patch %s cleanly." msgstr "Patch %s sauber angewendet" -#: builtin/apply.c:3676 +#: builtin/apply.c:3984 msgid "internal error" msgstr "interner Fehler" #. Say this even without --verbose -#: builtin/apply.c:3679 +#: builtin/apply.c:3987 #, c-format msgid "Applying patch %%s with %d reject..." msgid_plural "Applying patch %%s with %d rejects..." msgstr[0] "Wende Patch %%s mit %d Zurückweisung an..." msgstr[1] "Wende Patch %%s mit %d Zurückweisungen an..." -#: builtin/apply.c:3689 +#: builtin/apply.c:3997 #, c-format msgid "truncating .rej filename to %.*s.rej" msgstr "Verkürze Name von .rej Datei zu %.*s.rej" -#: builtin/apply.c:3710 +#: builtin/apply.c:4018 #, c-format msgid "Hunk #%d applied cleanly." msgstr "Patch-Bereich #%d sauber angewendet." -#: builtin/apply.c:3713 +#: builtin/apply.c:4021 #, c-format msgid "Rejected hunk #%d." msgstr "Patch-Bereich #%d zurückgewiesen." -#: builtin/apply.c:3844 +#: builtin/apply.c:4171 msgid "unrecognized input" msgstr "nicht erkannte Eingabe" -#: builtin/apply.c:3855 +#: builtin/apply.c:4182 msgid "unable to read index file" msgstr "Konnte Bereitstellungsdatei nicht lesen" -#: builtin/apply.c:3970 builtin/apply.c:3973 +#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91 +#: builtin/fetch.c:63 msgid "path" msgstr "Pfad" -#: builtin/apply.c:3971 +#: builtin/apply.c:4302 msgid "don't apply changes matching the given path" msgstr "wendet keine Änderungen im angegebenen Pfad an" -#: builtin/apply.c:3974 +#: builtin/apply.c:4305 msgid "apply changes matching the given path" msgstr "wendet Änderungen nur im angegebenen Pfad an" -#: builtin/apply.c:3976 +#: builtin/apply.c:4307 msgid "num" msgstr "Anzahl" -#: builtin/apply.c:3977 +#: builtin/apply.c:4308 msgid "remove <num> leading slashes from traditional diff paths" msgstr "" -"entfernt <Anzahl> vorrangestellte Schrägstriche von herkömmlichen " +"entfernt <Anzahl> vorangestellte Schrägstriche von herkömmlichen " "Differenzpfaden" -#: builtin/apply.c:3980 +#: builtin/apply.c:4311 msgid "ignore additions made by the patch" msgstr "ignoriert hinzugefügte Zeilen des Patches" -#: builtin/apply.c:3982 +#: builtin/apply.c:4313 msgid "instead of applying the patch, output diffstat for the input" msgstr "" "anstatt der Anwendung des Patches, wird der \"diffstat\" für die Eingabe " "ausgegeben" -#: builtin/apply.c:3986 -msgid "shows number of added and deleted lines in decimal notation" +#: builtin/apply.c:4317 +msgid "show number of added and deleted lines in decimal notation" msgstr "" "zeigt die Anzahl von hinzugefügten/entfernten Zeilen in Dezimalnotation" -#: builtin/apply.c:3988 +#: builtin/apply.c:4319 msgid "instead of applying the patch, output a summary for the input" msgstr "" "anstatt der Anwendung des Patches, wird eine Zusammenfassung für die Eingabe " "ausgegeben" -#: builtin/apply.c:3990 +#: builtin/apply.c:4321 msgid "instead of applying the patch, see if the patch is applicable" msgstr "" "anstatt der Anwendung des Patches, zeige ob Patch angewendet werden kann" -#: builtin/apply.c:3992 +#: builtin/apply.c:4323 msgid "make sure the patch is applicable to the current index" msgstr "" "stellt sicher, dass der Patch in der aktuellen Bereitstellung angewendet " "werden kann" -#: builtin/apply.c:3994 +#: builtin/apply.c:4325 msgid "apply a patch without touching the working tree" msgstr "wendet einen Patch an, ohne Änderungen im Arbeitszweig vorzunehmen" -#: builtin/apply.c:3996 +#: builtin/apply.c:4327 msgid "also apply the patch (use with --stat/--summary/--check)" msgstr "wendet den Patch an (Benutzung mit --stat/--summary/--check)" -#: builtin/apply.c:3998 +#: builtin/apply.c:4329 +msgid "attempt three-way merge if a patch does not apply" +msgstr "" +"versucht 3-Wege-Zusammenführung, wenn der Patch nicht angewendet werden " +"konnte" + +#: builtin/apply.c:4331 msgid "build a temporary index based on embedded index information" msgstr "" "erstellt eine temporäre Bereitstellung basierend auf den integrierten " "Bereitstellungsinformationen" -#: builtin/apply.c:4000 +#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460 msgid "paths are separated with NUL character" msgstr "Pfade sind getrennt durch NUL Zeichen" -#: builtin/apply.c:4003 +#: builtin/apply.c:4336 msgid "ensure at least <n> lines of context match" -msgstr "" -"stellt sicher, dass mindestens <Anzahl> Zeilen des Kontextes übereinstimmen" +msgstr "stellt sicher, dass mindestens <n> Zeilen des Kontextes übereinstimmen" -#: builtin/apply.c:4004 +#: builtin/apply.c:4337 msgid "action" msgstr "Aktion" -#: builtin/apply.c:4005 +#: builtin/apply.c:4338 msgid "detect new or modified lines that have whitespace errors" msgstr "ermittelt neue oder geänderte Zeilen die Fehler in Leerzeichen haben" -#: builtin/apply.c:4008 builtin/apply.c:4011 +#: builtin/apply.c:4341 builtin/apply.c:4344 msgid "ignore changes in whitespace when finding context" msgstr "ignoriert Änderungen in Leerzeichen bei der Suche des Kontextes" -#: builtin/apply.c:4014 +#: builtin/apply.c:4347 msgid "apply the patch in reverse" msgstr "wendet den Patch in umgekehrter Reihenfolge an" -#: builtin/apply.c:4016 +#: builtin/apply.c:4349 msgid "don't expect at least one line of context" msgstr "erwartet keinen Kontext" -#: builtin/apply.c:4018 +#: builtin/apply.c:4351 msgid "leave the rejected hunks in corresponding *.rej files" msgstr "" "hinterlässt zurückgewiesene Patch-Bereiche in den entsprechenden *.rej " "Dateien" -#: builtin/apply.c:4020 +#: builtin/apply.c:4353 msgid "allow overlapping hunks" msgstr "erlaubt sich überlappende Patch-Bereiche" -#: builtin/apply.c:4021 -msgid "be verbose" -msgstr "erweiterte Ausgaben" - -#: builtin/apply.c:4023 +#: builtin/apply.c:4356 msgid "tolerate incorrectly detected missing new-line at the end of file" msgstr "toleriert fehlerhaft erkannten fehlenden Zeilenumbruch am Dateiende" -#: builtin/apply.c:4026 +#: builtin/apply.c:4359 msgid "do not trust the line counts in the hunk headers" msgstr "vertraut nicht den Zeilennummern im Kopf des Patch-Bereiches" -#: builtin/apply.c:4028 +#: builtin/apply.c:4361 msgid "root" msgstr "Wurzelverzeichnis" -#: builtin/apply.c:4029 +#: builtin/apply.c:4362 msgid "prepend <root> to all filenames" msgstr "stellt <Wurzelverzeichnis> vor alle Dateinamen" -#: builtin/apply.c:4050 +#: builtin/apply.c:4384 +msgid "--3way outside a repository" +msgstr "--3way außerhalb eines Projektarchivs" + +#: builtin/apply.c:4392 msgid "--index outside a repository" msgstr "--index außerhalb eines Projektarchivs" -#: builtin/apply.c:4053 +#: builtin/apply.c:4395 msgid "--cached outside a repository" msgstr "--cached außerhalb eines Projektarchivs" -#: builtin/apply.c:4069 +#: builtin/apply.c:4411 #, c-format msgid "can't open patch '%s'" msgstr "kann Patch '%s' nicht öffnen" -#: builtin/apply.c:4083 +#: builtin/apply.c:4425 #, c-format msgid "squelched %d whitespace error" msgid_plural "squelched %d whitespace errors" msgstr[0] "unterdrückte %d Fehler in Leerzeichen" msgstr[1] "unterdrückte %d Fehler in Leerzeichen" -#: builtin/apply.c:4089 builtin/apply.c:4099 +#: builtin/apply.c:4431 builtin/apply.c:4441 #, c-format msgid "%d line adds whitespace errors." msgid_plural "%d lines add whitespace errors." @@ -1548,7 +2109,136 @@ msgstr "git archive: Protokollfehler" msgid "git archive: expected a flush" msgstr "git archive: erwartete eine Spülung (flush)" -#: builtin/branch.c:144 +#: builtin/bisect--helper.c:7 +msgid "git bisect--helper --next-all [--no-checkout]" +msgstr "git bisect--helper --next-all [--no-checkout]" + +#: builtin/bisect--helper.c:17 +msgid "perform 'git bisect next'" +msgstr "führt 'git bisect next' aus" + +#: builtin/bisect--helper.c:19 +msgid "update BISECT_HEAD instead of checking out the current commit" +msgstr "aktualisiert BISECT_HEAD, anstatt die aktuelle Version auszuchecken" + +#: builtin/blame.c:25 +msgid "git blame [options] [rev-opts] [rev] [--] file" +msgstr "git blame [Optionen] [rev-opts] [rev] [--] Datei" + +#: builtin/blame.c:30 builtin/shortlog.c:15 +msgid "[rev-opts] are documented in git-rev-list(1)" +msgstr "[rev-opts] sind dokumentiert in git-rev-list(1)" + +#: builtin/blame.c:2374 +msgid "Show blame entries as we find them, incrementally" +msgstr "Zeigt \"blame\"-Einträge schrittweise, während wir sie generieren" + +#: builtin/blame.c:2375 +msgid "Show blank SHA-1 for boundary commits (Default: off)" +msgstr "Zeigt leere SHA-1 für Grenzversionen (Standard: aus)" + +#: builtin/blame.c:2376 +msgid "Do not treat root commits as boundaries (Default: off)" +msgstr "Behandelt Ursprungsversionen nicht als Grenzen (Standard: aus)" + +#: builtin/blame.c:2377 +msgid "Show work cost statistics" +msgstr "Zeigt Statistiken zum Arbeitsaufwand" + +#: builtin/blame.c:2378 +msgid "Show output score for blame entries" +msgstr "Zeigt Ausgabebewertung für \"blame\"-Einträge" + +#: builtin/blame.c:2379 +msgid "Show original filename (Default: auto)" +msgstr "Zeigt ursprünglichen Dateinamen (Standard: auto)" + +#: builtin/blame.c:2380 +msgid "Show original linenumber (Default: off)" +msgstr "Zeigt ursprüngliche Zeilennummer (Standard: aus)" + +#: builtin/blame.c:2381 +msgid "Show in a format designed for machine consumption" +msgstr "Anzeige in einem Format für maschinelle Auswertung" + +#: builtin/blame.c:2382 +msgid "Show porcelain format with per-line commit information" +msgstr "" +"Anzeige in Format für Fremdprogramme mit Versionsinformationen pro Zeile" + +#: builtin/blame.c:2383 +msgid "Use the same output mode as git-annotate (Default: off)" +msgstr "Benutzt den gleichen Ausgabemodus wie \"git-annotate\" (Standard: aus)" + +#: builtin/blame.c:2384 +msgid "Show raw timestamp (Default: off)" +msgstr "Zeigt unbearbeiteten Zeitstempel (Standard: aus)" + +#: builtin/blame.c:2385 +msgid "Show long commit SHA1 (Default: off)" +msgstr "Zeigt langen Versions-SHA1 (Standard: aus)" + +#: builtin/blame.c:2386 +msgid "Suppress author name and timestamp (Default: off)" +msgstr "Unterdrückt den Namen des Autors und den Zeitstempel (Standard: aus)" + +#: builtin/blame.c:2387 +msgid "Show author email instead of name (Default: off)" +msgstr "Zeigt anstatt des Namens die Email-Adresse des Autors (Standard: aus)" + +#: builtin/blame.c:2388 +msgid "Ignore whitespace differences" +msgstr "Ignoriert Unterschiede in Leerzeichen" + +#: builtin/blame.c:2389 +msgid "Spend extra cycles to find better match" +msgstr "arbeite länger, um bessere Übereinstimmungen zu finden" + +#: builtin/blame.c:2390 +msgid "Use revisions from <file> instead of calling git-rev-list" +msgstr "Benutzt Revisionen von <Datei> anstatt \"git-rev-list\" aufzurufen" + +#: builtin/blame.c:2391 +msgid "Use <file>'s contents as the final image" +msgstr "Benutzt Inhalte der <Datei>en als entgültiges Abbild" + +#: builtin/blame.c:2392 builtin/blame.c:2393 +msgid "score" +msgstr "Bewertung" + +#: builtin/blame.c:2392 +msgid "Find line copies within and across files" +msgstr "Findet kopierte Zeilen innerhalb oder zwischen Dateien" + +#: builtin/blame.c:2393 +msgid "Find line movements within and across files" +msgstr "Findet verschobene Zeilen innerhalb oder zwischen Dateien" + +#: builtin/blame.c:2394 +msgid "n,m" +msgstr "n,m" + +#: builtin/blame.c:2394 +msgid "Process only line range n,m, counting from 1" +msgstr "Verarbeitet nur Zeilen im Bereich n,m, gezählt von 1" + +#: builtin/branch.c:23 +msgid "git branch [options] [-r | -a] [--merged | --no-merged]" +msgstr "git branch [Optionen] [-r | -a] [--merged | --no-merged]" + +#: builtin/branch.c:24 +msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]" +msgstr "git branch [Optionen] [-l] [-f] <Zweigname> [<Startpunkt>]" + +#: builtin/branch.c:25 +msgid "git branch [options] [-r] (-d | -D) <branchname>..." +msgstr "git branch [Optionen] [-r] (-d | -D) <Zweigname>..." + +#: builtin/branch.c:26 +msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>" +msgstr "git branch [Optionen] (-m | -M) [<alterZweig>] <neuerZweig>" + +#: builtin/branch.c:145 #, c-format msgid "" "deleting branch '%s' that has been merged to\n" @@ -1558,7 +2248,7 @@ msgstr "" " '%s', aber noch nicht mit der Zweigspitze (HEAD) zusammengeführt " "wurde." -#: builtin/branch.c:148 +#: builtin/branch.c:149 #, c-format msgid "" "not deleting branch '%s' that is not yet merged to\n" @@ -1567,169 +2257,300 @@ msgstr "" "entferne Zweig '%s' nicht, der noch nicht zusammengeführt wurde mit\n" " '%s', obwohl er mit der Zweigspitze (HEAD) zusammengeführt wurde." +#: builtin/branch.c:163 +#, c-format +msgid "Couldn't look up commit object for '%s'" +msgstr "Konnte Versionsobjekt für '%s' nicht nachschlagen." + +#: builtin/branch.c:167 +#, c-format +msgid "" +"The branch '%s' is not fully merged.\n" +"If you are sure you want to delete it, run 'git branch -D %s'." +msgstr "" +"Der Zweig '%s' ist nicht vollständig zusammengeführt.\n" +"Wenn du sicher bist diesen Zweig zu entfernen, führe 'git branch -D %s' aus." + #: builtin/branch.c:180 +msgid "Update of config-file failed" +msgstr "Aktualisierung der Konfigurationsdatei fehlgeschlagen." + +#: builtin/branch.c:208 msgid "cannot use -a with -d" msgstr "kann -a nicht mit -d benutzen" -#: builtin/branch.c:186 +#: builtin/branch.c:214 msgid "Couldn't look up commit object for HEAD" msgstr "Konnte Versionsobjekt für Zweigspitze (HEAD) nicht nachschlagen." -#: builtin/branch.c:191 +#: builtin/branch.c:222 #, c-format msgid "Cannot delete the branch '%s' which you are currently on." msgstr "" "Kann Zweig '%s' nicht entfernen, da du dich gerade auf diesem befindest." -#: builtin/branch.c:202 +#: builtin/branch.c:235 #, c-format msgid "remote branch '%s' not found." msgstr "externer Zweig '%s' nicht gefunden" -#: builtin/branch.c:203 +#: builtin/branch.c:236 #, c-format msgid "branch '%s' not found." msgstr "Zweig '%s' nicht gefunden." -#: builtin/branch.c:210 -#, c-format -msgid "Couldn't look up commit object for '%s'" -msgstr "Konnte Versionsobjekt für '%s' nicht nachschlagen." - -#: builtin/branch.c:216 -#, c-format -msgid "" -"The branch '%s' is not fully merged.\n" -"If you are sure you want to delete it, run 'git branch -D %s'." -msgstr "" -"Der Zweig '%s' ist nicht vollständig zusammengeführt.\n" -"Wenn du sicher bist diesen Zweig zu entfernen, führe 'git branch -D %s' aus." - -#: builtin/branch.c:225 +#: builtin/branch.c:250 #, c-format msgid "Error deleting remote branch '%s'" msgstr "Fehler beim Entfernen des externen Zweiges '%s'" -#: builtin/branch.c:226 +#: builtin/branch.c:251 #, c-format msgid "Error deleting branch '%s'" msgstr "Fehler beim Entfernen des Zweiges '%s'" -#: builtin/branch.c:233 +#: builtin/branch.c:258 #, c-format msgid "Deleted remote branch %s (was %s).\n" msgstr "Externer Zweig %s entfernt (war %s).\n" -#: builtin/branch.c:234 +#: builtin/branch.c:259 #, c-format msgid "Deleted branch %s (was %s).\n" msgstr "Zweig %s entfernt (war %s).\n" -#: builtin/branch.c:239 -msgid "Update of config-file failed" -msgstr "Aktualisierung der Konfigurationsdatei fehlgeschlagen." - -#: builtin/branch.c:337 +#: builtin/branch.c:361 #, c-format msgid "branch '%s' does not point at a commit" msgstr "Zweig '%s' zeigt auf keine Version" -#: builtin/branch.c:409 +#: builtin/branch.c:433 #, c-format msgid "[%s: behind %d]" msgstr "[%s: %d hinterher]" -#: builtin/branch.c:411 +#: builtin/branch.c:435 #, c-format msgid "[behind %d]" msgstr "[%d hinterher]" -#: builtin/branch.c:415 +#: builtin/branch.c:439 #, c-format msgid "[%s: ahead %d]" msgstr "[%s: %d voraus]" -#: builtin/branch.c:417 +#: builtin/branch.c:441 #, c-format msgid "[ahead %d]" msgstr "[%d voraus]" -#: builtin/branch.c:420 +#: builtin/branch.c:444 #, c-format msgid "[%s: ahead %d, behind %d]" msgstr "[%s: %d voraus, %d hinterher]" -#: builtin/branch.c:423 +#: builtin/branch.c:447 #, c-format msgid "[ahead %d, behind %d]" msgstr "[%d voraus, %d hinterher]" -#: builtin/branch.c:535 +#: builtin/branch.c:560 msgid "(no branch)" msgstr "(kein Zweig)" -#: builtin/branch.c:600 +#: builtin/branch.c:625 msgid "some refs could not be read" msgstr "Konnte einige Referenzen nicht lesen" -#: builtin/branch.c:613 +#: builtin/branch.c:638 msgid "cannot rename the current branch while not on any." msgstr "" -"Kann aktuellen Zweig nicht umbennen, solange du dich auf keinem befindest." +"Kann aktuellen Zweig nicht umbenennen, solange du dich auf keinem befindest." -#: builtin/branch.c:623 +#: builtin/branch.c:648 #, c-format msgid "Invalid branch name: '%s'" msgstr "Ungültiger Zweig-Name: '%s'" -#: builtin/branch.c:638 +#: builtin/branch.c:663 msgid "Branch rename failed" msgstr "Umbenennung des Zweiges fehlgeschlagen" -#: builtin/branch.c:642 +#: builtin/branch.c:667 #, c-format msgid "Renamed a misnamed branch '%s' away" msgstr "falsch benannten Zweig '%s' umbenannt" -#: builtin/branch.c:646 +#: builtin/branch.c:671 #, c-format msgid "Branch renamed to %s, but HEAD is not updated!" msgstr "Zweig umbenannt zu %s, aber Zweigspitze (HEAD) ist nicht aktualisiert!" -#: builtin/branch.c:653 +#: builtin/branch.c:678 msgid "Branch is renamed, but update of config-file failed" msgstr "" "Zweig ist umbenannt, aber die Aktualisierung der Konfigurationsdatei ist " "fehlgeschlagen." -#: builtin/branch.c:668 +#: builtin/branch.c:693 #, c-format msgid "malformed object name %s" msgstr "Missgebildeter Objektname %s" -#: builtin/branch.c:692 +#: builtin/branch.c:717 #, c-format msgid "could not write branch description template: %s" msgstr "Konnte Beschreibungsvorlage für Zweig nicht schreiben: %s" -#: builtin/branch.c:783 +#: builtin/branch.c:747 +msgid "Generic options" +msgstr "Allgemeine Optionen" + +#: builtin/branch.c:749 +msgid "show hash and subject, give twice for upstream branch" +msgstr "Zeigt Hash und Betreff; -vv: zusätzlich externen Übernahmezweig" + +#: builtin/branch.c:750 +msgid "suppress informational messages" +msgstr "unterdrückt Informationsmeldungen" + +#: builtin/branch.c:751 +msgid "set up tracking mode (see git-pull(1))" +msgstr "stellt den Übernahmemodus ein (siehe git-pull(1))" + +#: builtin/branch.c:753 +msgid "change upstream info" +msgstr "ändert Informationen zum externen Übernahmezweig" + +#: builtin/branch.c:757 +msgid "use colored output" +msgstr "verwendet farbliche Ausgaben" + +#: builtin/branch.c:758 +msgid "act on remote-tracking branches" +msgstr "wirkt auf externe Übernahmezweige" + +#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788 +#: builtin/branch.c:794 builtin/commit.c:1376 builtin/commit.c:1377 +#: builtin/commit.c:1378 builtin/commit.c:1379 builtin/tag.c:470 +msgid "commit" +msgstr "Version" + +#: builtin/branch.c:762 builtin/branch.c:768 +msgid "print only branches that contain the commit" +msgstr "gibt nur Zweige aus, welche diese Version beinhalten" + +#: builtin/branch.c:774 +msgid "Specific git-branch actions:" +msgstr "spezifische Aktionen für \"git-branch\":" + +#: builtin/branch.c:775 +msgid "list both remote-tracking and local branches" +msgstr "listet externe Übernahmezweige und lokale Zweige auf" + +#: builtin/branch.c:777 +msgid "delete fully merged branch" +msgstr "entfernt vollständig zusammengeführten Zweig" + +#: builtin/branch.c:778 +msgid "delete branch (even if not merged)" +msgstr "löscht Zweig (auch wenn nicht zusammengeführt)" + +#: builtin/branch.c:779 +msgid "move/rename a branch and its reflog" +msgstr "verschiebt/benennt einen Zweig und dessen Referenzprotokoll um" + +#: builtin/branch.c:780 +msgid "move/rename a branch, even if target exists" +msgstr "" +"verschiebt/benennt einen Zweig um, auch wenn das Ziel bereits existiert" + +#: builtin/branch.c:781 +msgid "list branch names" +msgstr "listet Zweignamen auf" + +#: builtin/branch.c:782 +msgid "create the branch's reflog" +msgstr "erzeugt das Referenzprotokoll des Zweiges" + +#: builtin/branch.c:784 +msgid "edit the description for the branch" +msgstr "bearbeitet die Beschreibung für den Zweig" + +#: builtin/branch.c:785 +msgid "force creation (when already exists)" +msgstr "erzeuge auch, wenn der Zweig bereits existiert" + +#: builtin/branch.c:788 +msgid "print only not merged branches" +msgstr "gibt nur Zweige aus, die nicht zusammengeführt sind" + +#: builtin/branch.c:794 +msgid "print only merged branches" +msgstr "gibt nur Zweige aus, die zusammengeführt sind" + +#: builtin/branch.c:798 +msgid "list branches in columns" +msgstr "listet Zweige in Spalten auf" + +#: builtin/branch.c:811 msgid "Failed to resolve HEAD as a valid ref." msgstr "Konnte Zweigspitze (HEAD) nicht als gültige Referenz auflösen." -#: builtin/branch.c:788 builtin/clone.c:558 +#: builtin/branch.c:816 builtin/clone.c:561 msgid "HEAD not found below refs/heads!" msgstr "Zweigspitze (HEAD) wurde nicht unter \"refs/heads\" gefunden!" -#: builtin/branch.c:808 +#: builtin/branch.c:836 msgid "--column and --verbose are incompatible" msgstr "--column und --verbose sind inkompatibel" -#: builtin/branch.c:857 +#: builtin/branch.c:887 +#, c-format +msgid "branch '%s' does not exist" +msgstr "Zweig '%s' existiert nicht" + +#: builtin/branch.c:899 +#, c-format +msgid "Branch '%s' has no upstream information" +msgstr "Zweig '%s' hat keinen externen Übernahmezweig gesetzt" + +#: builtin/branch.c:914 msgid "-a and -r options to 'git branch' do not make sense with a branch name" msgstr "" "Die Optionen -a und -r bei 'git branch' machen mit einem Zweignamen keinen " "Sinn." +#: builtin/branch.c:917 +#, c-format +msgid "" +"The --set-upstream flag is deprecated and will be removed. Consider using --" +"track or --set-upstream-to\n" +msgstr "" +"Die --set-upstream Option ist veraltet und wird entfernt. Benutze --track " +"oder --set-upstream-to\n" + +#: builtin/branch.c:934 +#, c-format +msgid "" +"\n" +"If you wanted to make '%s' track '%s', do this:\n" +"\n" +msgstr "" +"\n" +"Wenn du wolltest, dass '%s' den Zweig '%s' als externen Übernahmezweig hat, " +"führe aus:\n" + +#: builtin/branch.c:935 +#, c-format +msgid " git branch -d %s\n" +msgstr " git branch -d %s\n" + +#: builtin/branch.c:936 +#, c-format +msgid " git branch --set-upstream-to %s\n" +msgstr " git branch --set-upstream-to %s\n" + #: builtin/bundle.c:47 #, c-format msgid "%s is okay\n" @@ -1743,99 +2564,228 @@ msgstr "Um ein Paket zu erstellen wird ein Projektarchiv benötigt." msgid "Need a repository to unbundle." msgstr "Zum Entpacken wird ein Projektarchiv benötigt." -#: builtin/checkout.c:113 builtin/checkout.c:146 +#: builtin/cat-file.c:247 +msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>" +msgstr "git cat-file (-t|-s|-e|-p|<Art>|--textconv) <Objekt>" + +#: builtin/cat-file.c:248 +msgid "git cat-file (--batch|--batch-check) < <list_of_objects>" +msgstr "git cat-file (--batch|--batch-check) < <Liste_von_Objekten>" + +#: builtin/cat-file.c:266 +msgid "<type> can be one of: blob, tree, commit, tag" +msgstr "<Art> kann sein: blob, tree, commit, tag" + +#: builtin/cat-file.c:267 +msgid "show object type" +msgstr "zeigt Objektart" + +#: builtin/cat-file.c:268 +msgid "show object size" +msgstr "zeigt Objektgröße" + +#: builtin/cat-file.c:270 +msgid "exit with zero when there's no error" +msgstr "beendet mit Rückgabewert 0, wenn kein Fehler aufgetreten ist" + +#: builtin/cat-file.c:271 +msgid "pretty-print object's content" +msgstr "ansprechende Anzeige des Objektinhaltes" + +#: builtin/cat-file.c:273 +msgid "for blob objects, run textconv on object's content" +msgstr "führt eine Textkonvertierung auf den Inhalt von Blob-Objekten aus" + +#: builtin/cat-file.c:275 +msgid "show info and content of objects fed from the standard input" +msgstr "" +"Anzeige von Informationen und Inhalt von Objekten, gelesen von der Standard-" +"Eingabe" + +#: builtin/cat-file.c:278 +msgid "show info about objects fed from the standard input" +msgstr "" +"Anzeige von Informationen über Objekte, gelesen von der Standard-Eingabe" + +#: builtin/check-attr.c:11 +msgid "git check-attr [-a | --all | attr...] [--] pathname..." +msgstr "git check-attr [-a | --all | Attribut...] [--] Pfadname..." + +#: builtin/check-attr.c:12 +msgid "git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>" +msgstr "git check-attr --stdin [-z] [-a | --all | Attribut...] < <Liste-von-Pfaden>" + +#: builtin/check-attr.c:19 +msgid "report all attributes set on file" +msgstr "gibt alle Attribute einer Datei aus" + +#: builtin/check-attr.c:20 +msgid "use .gitattributes only from the index" +msgstr "verwendet .gitattributes nur von der Bereitstellung" + +#: builtin/check-attr.c:21 builtin/hash-object.c:75 +msgid "read file names from stdin" +msgstr "liest Dateinamen von der Standard-Eingabe" + +#: builtin/check-attr.c:23 +msgid "input paths are terminated by a null character" +msgstr "Eingabepfade sind durch ein NUL Zeichen abgeschlossen" + +#: builtin/checkout-index.c:126 +msgid "git checkout-index [options] [--] [<file>...]" +msgstr "git checkout-index [Optionen] [--] [<Datei>...]" + +#: builtin/checkout-index.c:187 +msgid "check out all files in the index" +msgstr "checkt alle Dateien in der Bereitstellung aus" + +#: builtin/checkout-index.c:188 +msgid "force overwrite of existing files" +msgstr "erzwingt das Überschreiben bereits existierender Dateien" + +#: builtin/checkout-index.c:190 +msgid "no warning for existing files and files not in index" +msgstr "" +"keine Warnung für existierende Dateien, und Dateien, die sich nicht in der " +"Bereitstellung befinden" + +#: builtin/checkout-index.c:192 +msgid "don't checkout new files" +msgstr "checkt keine neuen Dateien aus" + +#: builtin/checkout-index.c:194 +msgid "update stat information in the index file" +msgstr "aktualisiert Dateiinformationen in der Bereitstellungsdatei" + +#: builtin/checkout-index.c:200 +msgid "read list of paths from the standard input" +msgstr "liest eine Liste von Pfaden von der Standard-Eingabe" + +#: builtin/checkout-index.c:202 +msgid "write the content to temporary files" +msgstr "schreibt den Inhalt in temporäre Dateien" + +#: builtin/checkout-index.c:203 builtin/column.c:30 +msgid "string" +msgstr "Zeichenkette" + +#: builtin/checkout-index.c:204 +msgid "when creating files, prepend <string>" +msgstr "" +"wenn Dateien erzeugt werden, stelle <Zeichenkette> dem Dateinamen voran" + +#: builtin/checkout-index.c:207 +msgid "copy out the files from named stage" +msgstr "kopiert Dateien von dem benannten Stand" + +#: builtin/checkout.c:25 +msgid "git checkout [options] <branch>" +msgstr "git checkout [Optionen] <Zweig>" + +#: builtin/checkout.c:26 +msgid "git checkout [options] [<branch>] -- <file>..." +msgstr "git checkout [Optionen] [Zweig>] -- <Datei>..." + +#: builtin/checkout.c:116 builtin/checkout.c:149 #, c-format msgid "path '%s' does not have our version" msgstr "Pfad '%s' hat nicht unsere Version." -#: builtin/checkout.c:115 builtin/checkout.c:148 +#: builtin/checkout.c:118 builtin/checkout.c:151 #, c-format msgid "path '%s' does not have their version" msgstr "Pfad '%s' hat nicht deren Version." -#: builtin/checkout.c:131 +#: builtin/checkout.c:134 #, c-format msgid "path '%s' does not have all necessary versions" msgstr "Pfad '%s' hat nicht alle notwendigen Versionen." -#: builtin/checkout.c:175 +#: builtin/checkout.c:178 #, c-format msgid "path '%s' does not have necessary versions" msgstr "Pfad '%s' hat nicht die notwendigen Versionen." -#: builtin/checkout.c:192 +#: builtin/checkout.c:195 #, c-format msgid "path '%s': cannot merge" msgstr "Pfad '%s': kann nicht zusammenführen" -#: builtin/checkout.c:209 +#: builtin/checkout.c:212 #, c-format msgid "Unable to add merge result for '%s'" msgstr "Konnte Ergebnis der Zusammenführung von '%s' nicht hinzufügen." -#: builtin/checkout.c:234 builtin/checkout.c:392 +#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242 +#: builtin/checkout.c:245 +#, c-format +msgid "'%s' cannot be used with updating paths" +msgstr "'%s' kann nicht mit Pfaden benutzt werden" + +#: builtin/checkout.c:248 builtin/checkout.c:251 +#, c-format +msgid "'%s' cannot be used with %s" +msgstr "'%s' kann nicht mit '%s' benutzt werden" + +#: builtin/checkout.c:254 +#, c-format +msgid "Cannot update paths and switch to branch '%s' at the same time." +msgstr "Kann nicht gleichzeitig Pfade aktualisieren und zu Zweig '%s' wechseln" + +#: builtin/checkout.c:265 builtin/checkout.c:426 msgid "corrupt index file" msgstr "beschädigte Bereitstellungsdatei" -#: builtin/checkout.c:264 builtin/checkout.c:271 +#: builtin/checkout.c:295 builtin/checkout.c:302 #, c-format msgid "path '%s' is unmerged" msgstr "Pfad '%s' ist nicht zusammengeführt." -#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583 -#: builtin/merge.c:812 -msgid "unable to write new index file" -msgstr "Konnte neue Bereitstellungsdatei nicht schreiben." - -#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408 -msgid "diff_setup_done failed" -msgstr "diff_setup_done fehlgeschlagen" - -#: builtin/checkout.c:414 +#: builtin/checkout.c:448 msgid "you need to resolve your current index first" msgstr "Du musst zuerst deine aktuelle Bereitstellung auflösen." -#: builtin/checkout.c:533 +#: builtin/checkout.c:569 #, c-format msgid "Can not do reflog for '%s'\n" msgstr "Konnte \"reflog\" für '%s' nicht durchführen\n" -#: builtin/checkout.c:566 +#: builtin/checkout.c:602 msgid "HEAD is now at" msgstr "Zweigspitze (HEAD) ist jetzt bei" -#: builtin/checkout.c:573 +#: builtin/checkout.c:609 #, c-format msgid "Reset branch '%s'\n" msgstr "Setze Zweig '%s' zurück\n" -#: builtin/checkout.c:576 +#: builtin/checkout.c:612 #, c-format msgid "Already on '%s'\n" msgstr "Bereits auf '%s'\n" -#: builtin/checkout.c:580 +#: builtin/checkout.c:616 #, c-format msgid "Switched to and reset branch '%s'\n" msgstr "Gewechselt zu zurückgesetztem Zweig '%s'\n" -#: builtin/checkout.c:582 +#: builtin/checkout.c:618 builtin/checkout.c:955 #, c-format msgid "Switched to a new branch '%s'\n" msgstr "Gewechselt zu einem neuen Zweig '%s'\n" -#: builtin/checkout.c:584 +#: builtin/checkout.c:620 #, c-format msgid "Switched to branch '%s'\n" msgstr "Gewechselt zu Zweig '%s'\n" -#: builtin/checkout.c:640 +#: builtin/checkout.c:676 #, c-format msgid " ... and %d more.\n" msgstr " ... und %d weitere.\n" #. The singular version -#: builtin/checkout.c:646 +#: builtin/checkout.c:682 #, c-format msgid "" "Warning: you are leaving %d commit behind, not connected to\n" @@ -1858,7 +2808,7 @@ msgstr[1] "" "\n" "%s\n" -#: builtin/checkout.c:664 +#: builtin/checkout.c:700 #, c-format msgid "" "If you want to keep them by creating a new branch, this may be a good time\n" @@ -1873,106 +2823,190 @@ msgstr "" " git branch neuer_zweig_name %s\n" "\n" -#: builtin/checkout.c:694 +#: builtin/checkout.c:730 msgid "internal error in revision walk" msgstr "interner Fehler im Revisionsgang" -#: builtin/checkout.c:698 +#: builtin/checkout.c:734 msgid "Previous HEAD position was" msgstr "Vorherige Position der Zweigspitze (HEAD) war" -#: builtin/checkout.c:724 +#: builtin/checkout.c:761 builtin/checkout.c:950 msgid "You are on a branch yet to be born" msgstr "du bist auf einem Zweig, der noch geboren wird" #. case (1) -#: builtin/checkout.c:855 +#: builtin/checkout.c:886 #, c-format msgid "invalid reference: %s" msgstr "Ungültige Referenz: %s" #. case (1): want a tree -#: builtin/checkout.c:894 +#: builtin/checkout.c:925 #, c-format msgid "reference is not a tree: %s" msgstr "Referenz ist kein Baum: %s" -#: builtin/checkout.c:974 -msgid "-B cannot be used with -b" -msgstr "-B kann nicht mit -b benutzt werden" +#: builtin/checkout.c:964 +msgid "paths cannot be used with switching branches" +msgstr "Pfade können nicht mit dem Wechseln von Zweigen benutzt werden" -#: builtin/checkout.c:983 -msgid "--patch is incompatible with all other options" -msgstr "--patch ist inkompatibel mit allen anderen Optionen" +#: builtin/checkout.c:967 builtin/checkout.c:971 +#, c-format +msgid "'%s' cannot be used with switching branches" +msgstr "'%s' kann nicht mit dem Wechseln von Zweigen benutzt werden" +#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983 #: builtin/checkout.c:986 -msgid "--detach cannot be used with -b/-B/--orphan" -msgstr "--detach kann nicht mit -b/-B/--orphan benutzt werden" +#, c-format +msgid "'%s' cannot be used with '%s'" +msgstr "'%s' kann nicht mit '%s' benutzt werden" -#: builtin/checkout.c:988 -msgid "--detach cannot be used with -t" -msgstr "--detach kann nicht mit -t benutzt werden" +#: builtin/checkout.c:991 +#, c-format +msgid "Cannot switch branch to a non-commit '%s'" +msgstr "Kann Zweig nicht zu Nicht-Version '%s' wechseln" -#: builtin/checkout.c:994 -msgid "--track needs a branch name" -msgstr "--track benötigt einen Zweignamen" +#: builtin/checkout.c:1012 builtin/gc.c:177 +msgid "suppress progress reporting" +msgstr "unterdrückt Fortschrittsanzeige" -#: builtin/checkout.c:1001 -msgid "Missing branch name; try -b" -msgstr "Vermisse Zweignamen; versuche -b" +#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89 +#: builtin/remote.c:169 builtin/remote.c:171 +msgid "branch" +msgstr "Zweig" + +#: builtin/checkout.c:1014 +msgid "create and checkout a new branch" +msgstr "erzeugt und checkt einen neuen Zweig aus" + +#: builtin/checkout.c:1016 +msgid "create/reset and checkout a branch" +msgstr "erzeugt/setzt neu und checkt einen Zweig aus" -#: builtin/checkout.c:1007 -msgid "--orphan and -b|-B are mutually exclusive" -msgstr "--orphan und -b|-B sind gegenseitig exklusiv" +#: builtin/checkout.c:1017 +msgid "create reflog for new branch" +msgstr "erzeugt Referenzprotokoll für den neuen Zweig" -#: builtin/checkout.c:1009 -msgid "--orphan cannot be used with -t" -msgstr "--orphan kann nicht mit -t benutzt werden" +#: builtin/checkout.c:1018 +msgid "detach the HEAD at named commit" +msgstr "setzt die Zweigspitze (HEAD) zu benannter Version" #: builtin/checkout.c:1019 -msgid "git checkout: -f and -m are incompatible" -msgstr "git checkout: -f und -m sind inkompatibel" +msgid "set upstream info for new branch" +msgstr "setzt Informationen zum externen Übernahmezweig für den neuen Zweig" + +#: builtin/checkout.c:1021 +msgid "new branch" +msgstr "neuer Zweig" + +#: builtin/checkout.c:1021 +msgid "new unparented branch" +msgstr "neuer Zweig ohne Elternversion" + +#: builtin/checkout.c:1022 +msgid "checkout our version for unmerged files" +msgstr "checkt unsere Variante für nicht zusammengeführte Dateien aus" + +#: builtin/checkout.c:1024 +msgid "checkout their version for unmerged files" +msgstr "checkt ihre Variante für nicht zusammengeführte Dateien aus" + +#: builtin/checkout.c:1026 +msgid "force checkout (throw away local modifications)" +msgstr "erzwingt Auschecken (verwirft lokale Änderungen)" + +#: builtin/checkout.c:1027 +msgid "perform a 3-way merge with the new branch" +msgstr "führt eine 3-Wege-Zusammenführung mit dem neuen Zweig aus" + +#: builtin/checkout.c:1028 builtin/merge.c:215 +msgid "update ignored files (default)" +msgstr "aktualisiert ignorierte Dateien (Standard)" + +#: builtin/checkout.c:1029 builtin/log.c:1116 parse-options.h:241 +msgid "style" +msgstr "Stil" + +#: builtin/checkout.c:1030 +msgid "conflict style (merge or diff3)" +msgstr "Konfliktstil (merge oder diff3)" + +#: builtin/checkout.c:1033 +msgid "second guess 'git checkout no-such-branch'" +msgstr "second guess 'git checkout no-such-branch'" + +#: builtin/checkout.c:1057 +msgid "-b, -B and --orphan are mutually exclusive" +msgstr "-b, -B und --orphan schliessen sich gegenseitig aus" + +#: builtin/checkout.c:1074 +msgid "--track needs a branch name" +msgstr "--track benötigt einen Zweignamen" + +#: builtin/checkout.c:1081 +msgid "Missing branch name; try -b" +msgstr "Vermisse Zweignamen; versuche -b" -#: builtin/checkout.c:1053 +#: builtin/checkout.c:1116 msgid "invalid path specification" msgstr "ungültige Pfadspezifikation" -#: builtin/checkout.c:1061 +#: builtin/checkout.c:1123 #, c-format msgid "" -"git checkout: updating paths is incompatible with switching branches.\n" +"Cannot update paths and switch to branch '%s' at the same time.\n" "Did you intend to checkout '%s' which can not be resolved as commit?" msgstr "" -"git checkout: Die Aktualisierung von Pfaden ist inkompatibel mit dem Wechsel " -"von Zweigen.\n" +"Kann nicht gleichzeitig Pfade aktualisieren und zu Zweig '%s' wechseln.\n" "Hast du beabsichtigt '%s' auszuchecken, welcher nicht als Version aufgelöst " "werden kann?" -#: builtin/checkout.c:1063 -msgid "git checkout: updating paths is incompatible with switching branches." -msgstr "" -"git checkout: Die Aktualisierung von Pfaden ist inkompatibel mit dem Wechsel " -"von Zweigen." - -#: builtin/checkout.c:1068 -msgid "git checkout: --detach does not take a path argument" -msgstr "git checkout: --detach nimmt kein Pfad-Argument" +#: builtin/checkout.c:1128 +#, c-format +msgid "git checkout: --detach does not take a path argument '%s'" +msgstr "git checkout: --detach nimmt kein Pfad-Argument '%s'" -#: builtin/checkout.c:1071 +#: builtin/checkout.c:1132 msgid "" "git checkout: --ours/--theirs, --force and --merge are incompatible when\n" "checking out of the index." msgstr "" -"git checkout: --ours/--theirs, --force and --merge sind inkompatibel wenn\n" +"git checkout: --ours/--theirs, --force und --merge sind inkompatibel wenn\n" "du aus der Bereitstellung auscheckst." -#: builtin/checkout.c:1090 -msgid "Cannot switch branch to a non-commit." -msgstr "Kann Zweig nur zu einer Version wechseln." +#: builtin/clean.c:19 +msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..." +msgstr "git clean [-d] [-f] [-n] [-q] [-e <Muster>] [-x | -X] [--] <Pfade>..." + +#: builtin/clean.c:51 +msgid "do not print names of files removed" +msgstr "gibt keine Namen von gelöschten Dateien aus" + +#: builtin/clean.c:53 +msgid "force" +msgstr "erzwingt Aktion" + +#: builtin/clean.c:55 +msgid "remove whole directories" +msgstr "löscht ganze Verzeichnisse" + +#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:717 +#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:182 +msgid "pattern" +msgstr "Muster" -#: builtin/checkout.c:1093 -msgid "--ours/--theirs is incompatible with switching branches." -msgstr "--ours/--theirs ist inkompatibel mit den Wechseln von Zweigen." +#: builtin/clean.c:57 +msgid "add <pattern> to ignore rules" +msgstr "fügt <Muster> zu den Regeln für ignorierte Pfade hinzu" + +#: builtin/clean.c:58 +msgid "remove ignored files, too" +msgstr "löscht auch ignorierte Dateien" + +#: builtin/clean.c:60 +msgid "remove only ignored files" +msgstr "löscht nur ignorierte Dateien" #: builtin/clean.c:78 msgid "-x and -X cannot be used together" @@ -1996,44 +3030,133 @@ msgstr "" #: builtin/clean.c:155 builtin/clean.c:176 #, c-format msgid "Would remove %s\n" -msgstr "Würde %s entfernen\n" +msgstr "Würde %s löschen\n" #: builtin/clean.c:159 builtin/clean.c:179 #, c-format msgid "Removing %s\n" -msgstr "Entferne %s\n" +msgstr "Lösche %s\n" #: builtin/clean.c:162 builtin/clean.c:182 #, c-format msgid "failed to remove %s" -msgstr "Fehler beim Entfernen von %s" +msgstr "Fehler beim Löschen von %s" #: builtin/clean.c:166 #, c-format msgid "Would not remove %s\n" -msgstr "Würde nicht entfernen %s\n" +msgstr "Würde '%s' nicht löschen\n" #: builtin/clean.c:168 #, c-format msgid "Not removing %s\n" msgstr "Entferne nicht %s\n" +#: builtin/clone.c:36 +msgid "git clone [options] [--] <repo> [<dir>]" +msgstr "git clone [Optionen] [--] <Projektarchiv> [<Verzeichnis>]" + +#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212 +#: builtin/push.c:399 +msgid "force progress reporting" +msgstr "erzwingt Fortschrittsanzeige" + +#: builtin/clone.c:66 +msgid "don't create a checkout" +msgstr "kein Auschecken" + +#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488 +msgid "create a bare repository" +msgstr "erstellt ein bloßes Projektarchiv" + +#: builtin/clone.c:72 +msgid "create a mirror repository (implies bare)" +msgstr "erstellt ein Spiegelarchiv (impliziert bloßes Projektarchiv)" + +#: builtin/clone.c:74 +msgid "to clone from a local repository" +msgstr "um von einem lokalen Projektarchiv zu klonen" + +#: builtin/clone.c:76 +msgid "don't use local hardlinks, always copy" +msgstr "benutzt lokal keine harten Links, immer Kopien" + +#: builtin/clone.c:78 +msgid "setup as shared repository" +msgstr "Einrichtung als verteiltes Projektarchiv" + +#: builtin/clone.c:80 builtin/clone.c:82 +msgid "initialize submodules in the clone" +msgstr "initialisiert Unterprojekte im Klon" + +#: builtin/clone.c:83 builtin/init-db.c:485 +msgid "template-directory" +msgstr "Vorlagenverzeichnis" + +#: builtin/clone.c:84 builtin/init-db.c:486 +msgid "directory from which templates will be used" +msgstr "Verzeichnis, von welchem die Vorlagen verwendet werden" + +#: builtin/clone.c:86 +msgid "reference repository" +msgstr "referenziert Projektarchiv" + +#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44 +msgid "name" +msgstr "Name" + +#: builtin/clone.c:88 +msgid "use <name> instead of 'origin' to track upstream" +msgstr "benutzt <Name> statt 'origin' für externes Projektarchiv" + +#: builtin/clone.c:90 +msgid "checkout <branch> instead of the remote's HEAD" +msgstr "" +"checkt <Zweig> aus, anstatt Zweigspitze (HEAD) des externen Projektarchivs" + +#: builtin/clone.c:92 +msgid "path to git-upload-pack on the remote" +msgstr "Pfad zu \"git-upload-pack\" auf der Gegenseite" + +#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662 +msgid "depth" +msgstr "Tiefe" + +#: builtin/clone.c:94 +msgid "create a shallow clone of that depth" +msgstr "erstellt einen flachen Klon mit dieser Tiefe" + +#: builtin/clone.c:96 +msgid "clone only one branch, HEAD or --branch" +msgstr "klont nur einen Zweig, Zweigspitze (HEAD) oder --branch" + +#: builtin/clone.c:97 builtin/init-db.c:494 +msgid "gitdir" +msgstr ".git-Verzeichnis" + +#: builtin/clone.c:98 builtin/init-db.c:495 +msgid "separate git dir from working tree" +msgstr "separiert Git-Verzeichnis vom Arbeitsbaum" + +#: builtin/clone.c:99 +msgid "key=value" +msgstr "Schlüssel=Wert" + +#: builtin/clone.c:100 +msgid "set config inside the new repository" +msgstr "setzt Konfiguration innerhalb des neuen Projektarchivs" + #: builtin/clone.c:243 #, c-format msgid "reference repository '%s' is not a local directory." msgstr "Referenziertes Projektarchiv '%s' ist kein lokales Verzeichnis." -#: builtin/clone.c:302 -#, c-format -msgid "failed to open '%s'" -msgstr "Fehler beim Öffnen von '%s'" - #: builtin/clone.c:306 #, c-format msgid "failed to create directory '%s'" msgstr "Fehler beim Erstellen von Verzeichnis '%s'" -#: builtin/clone.c:308 builtin/diff.c:75 +#: builtin/clone.c:308 builtin/diff.c:77 #, c-format msgid "failed to stat '%s'" msgstr "Konnte '%s' nicht lesen" @@ -2048,11 +3171,6 @@ msgstr "%s existiert und ist kein Verzeichnis" msgid "failed to stat %s\n" msgstr "Konnte %s nicht lesen\n" -#: builtin/clone.c:341 -#, c-format -msgid "failed to unlink '%s'" -msgstr "Konnte '%s' nicht entfernen" - #: builtin/clone.c:346 #, c-format msgid "failed to create link '%s'" @@ -2068,88 +3186,124 @@ msgstr "Konnte Datei nicht nach '%s' kopieren" msgid "done.\n" msgstr "Fertig.\n" -#: builtin/clone.c:440 +#: builtin/clone.c:443 #, c-format msgid "Could not find remote branch %s to clone." msgstr "Konnte zu klonenden externer Zweig %s nicht finden." -#: builtin/clone.c:549 +#: builtin/clone.c:552 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" msgstr "" "Externe Zweigspitze (HEAD) bezieht sich auf eine nicht existierende Referenz " "und kann nicht ausgecheckt werden.\n" -#: builtin/clone.c:639 +#: builtin/clone.c:690 msgid "Too many arguments." msgstr "Zu viele Argumente." -#: builtin/clone.c:643 +#: builtin/clone.c:694 msgid "You must specify a repository to clone." msgstr "Du musst ein Projektarchiv zum Klonen angeben." -#: builtin/clone.c:654 +#: builtin/clone.c:705 #, c-format msgid "--bare and --origin %s options are incompatible." msgstr "--bare und --origin %s Optionen sind inkompatibel." -#: builtin/clone.c:668 +#: builtin/clone.c:719 #, c-format msgid "repository '%s' does not exist" msgstr "Projektarchiv '%s' existiert nicht." -#: builtin/clone.c:673 +#: builtin/clone.c:724 msgid "--depth is ignored in local clones; use file:// instead." msgstr "--depth wird in lokalen Klonen ignoriert; benutze stattdessen file://." -#: builtin/clone.c:683 +#: builtin/clone.c:734 #, c-format msgid "destination path '%s' already exists and is not an empty directory." msgstr "Zielpfad '%s' existiert bereits und ist kein leeres Verzeichnis." -#: builtin/clone.c:693 +#: builtin/clone.c:744 #, c-format msgid "working tree '%s' already exists." msgstr "Arbeitsbaum '%s' existiert bereits." -#: builtin/clone.c:706 builtin/clone.c:720 +#: builtin/clone.c:757 builtin/clone.c:771 #, c-format msgid "could not create leading directories of '%s'" msgstr "Konnte führende Verzeichnisse von '%s' nicht erstellen." -#: builtin/clone.c:709 +#: builtin/clone.c:760 #, c-format msgid "could not create work tree dir '%s'." msgstr "Konnte Arbeitsverzeichnis '%s' nicht erstellen." -#: builtin/clone.c:728 +#: builtin/clone.c:779 #, c-format msgid "Cloning into bare repository '%s'...\n" msgstr "Klone in bloßes Projektarchiv '%s'...\n" -#: builtin/clone.c:730 +#: builtin/clone.c:781 #, c-format msgid "Cloning into '%s'...\n" msgstr "Klone nach '%s'...\n" -#: builtin/clone.c:786 +#: builtin/clone.c:823 #, c-format msgid "Don't know how to clone %s" msgstr "Weiß nicht wie %s zu klonen ist." -#: builtin/clone.c:835 +#: builtin/clone.c:872 #, c-format msgid "Remote branch %s not found in upstream %s" msgstr "externer Zweig %s nicht im anderen Projektarchiv %s gefunden" -#: builtin/clone.c:842 +#: builtin/clone.c:879 msgid "You appear to have cloned an empty repository." msgstr "Du scheinst ein leeres Projektarchiv geklont zu haben." +#: builtin/column.c:9 +msgid "git column [options]" +msgstr "git column [Optionen]" + +#: builtin/column.c:26 +msgid "lookup config vars" +msgstr "schlägt Konfigurationsvariablen nach" + +#: builtin/column.c:27 builtin/column.c:28 +msgid "layout to use" +msgstr "zu verwendende Anordnung" + +#: builtin/column.c:29 +msgid "Maximum width" +msgstr "maximale Breite" + +#: builtin/column.c:30 +msgid "Padding space on left border" +msgstr "Abstand zum linken Rand" + +#: builtin/column.c:31 +msgid "Padding space on right border" +msgstr "Abstand zur rechten Rand" + +#: builtin/column.c:32 +msgid "Padding space between columns" +msgstr "Abstand zwischen Spalten" + #: builtin/column.c:51 msgid "--command must be the first argument" msgstr "Option --command muss zuerst angegeben werden" -#: builtin/commit.c:43 +#: builtin/commit.c:34 +msgid "git commit [options] [--] <filepattern>..." +msgstr "git commit [Optionen] [--] <Dateimuster>..." + +#: builtin/commit.c:39 +msgid "git status [options] [--] <filepattern>..." +msgstr "git status [Optionen] [--] <Dateimuster>..." + +#: builtin/commit.c:44 msgid "" "Your name and email address were configured automatically based\n" "on your username and hostname. Please check that they are accurate.\n" @@ -2175,7 +3329,7 @@ msgstr "" "\n" " git commit --amend --reset-author\n" -#: builtin/commit.c:55 +#: builtin/commit.c:56 msgid "" "You asked to amend the most recent commit, but doing so would make\n" "it empty. You can repeat your command with --allow-empty, or you can\n" @@ -2185,7 +3339,7 @@ msgstr "" "machen. Du kannst Dein Kommando mit --allow-empty wiederholen, oder die\n" "Version mit \"git reset HEAD^\" vollständig entfernen.\n" -#: builtin/commit.c:60 +#: builtin/commit.c:61 msgid "" "The previous cherry-pick is now empty, possibly due to conflict resolution.\n" "If you wish to commit it anyway, use:\n" @@ -2202,97 +3356,97 @@ msgstr "" "\n" "Andernfalls benutze bitte 'git reset'\n" -#: builtin/commit.c:253 +#: builtin/commit.c:258 msgid "failed to unpack HEAD tree object" msgstr "Fehler beim Entpacken des Baum-Objektes der Zweigspitze (HEAD)." -#: builtin/commit.c:295 +#: builtin/commit.c:300 msgid "unable to create temporary index" msgstr "Konnte temporäre Bereitstellung nicht erstellen." -#: builtin/commit.c:301 +#: builtin/commit.c:306 msgid "interactive add failed" msgstr "interaktives Hinzufügen fehlgeschlagen" -#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405 +#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410 msgid "unable to write new_index file" msgstr "Konnte new_index Datei nicht schreiben" -#: builtin/commit.c:386 +#: builtin/commit.c:391 msgid "cannot do a partial commit during a merge." msgstr "" "Kann keine partielle Eintragung durchführen, während eine Zusammenführung im " "Gange ist." -#: builtin/commit.c:388 +#: builtin/commit.c:393 msgid "cannot do a partial commit during a cherry-pick." msgstr "" "Kann keine partielle Eintragung durchführen, während \"cherry-pick\" im " "Gange ist." -#: builtin/commit.c:398 +#: builtin/commit.c:403 msgid "cannot read the index" msgstr "Kann Bereitstellung nicht lesen" -#: builtin/commit.c:418 +#: builtin/commit.c:423 msgid "unable to write temporary index file" msgstr "Konnte temporäre Bereitstellungsdatei nicht schreiben." -#: builtin/commit.c:493 builtin/commit.c:499 +#: builtin/commit.c:511 builtin/commit.c:517 #, c-format msgid "invalid commit: %s" msgstr "Ungültige Version: %s" -#: builtin/commit.c:522 +#: builtin/commit.c:540 msgid "malformed --author parameter" msgstr "Fehlerhafter --author Parameter" -#: builtin/commit.c:582 +#: builtin/commit.c:560 #, c-format msgid "Malformed ident string: '%s'" msgstr "Fehlerhafte Identifikations-String: '%s'" -#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967 +#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954 #, c-format msgid "could not lookup commit %s" msgstr "Konnte Version %s nicht nachschlagen" -#: builtin/commit.c:632 builtin/shortlog.c:296 +#: builtin/commit.c:610 builtin/shortlog.c:296 #, c-format msgid "(reading log message from standard input)\n" msgstr "(lese Log-Nachricht von Standard-Eingabe)\n" -#: builtin/commit.c:634 +#: builtin/commit.c:612 msgid "could not read log from standard input" msgstr "Konnte Log nicht von Standard-Eingabe lesen." -#: builtin/commit.c:638 +#: builtin/commit.c:616 #, c-format msgid "could not read log file '%s'" msgstr "Konnte Log-Datei '%s' nicht lesen" -#: builtin/commit.c:644 +#: builtin/commit.c:622 msgid "commit has empty message" msgstr "Version hat eine leere Beschreibung" -#: builtin/commit.c:660 +#: builtin/commit.c:638 msgid "could not read MERGE_MSG" msgstr "Konnte MERGE_MSG nicht lesen" -#: builtin/commit.c:664 +#: builtin/commit.c:642 msgid "could not read SQUASH_MSG" msgstr "Konnte SQUASH_MSG nicht lesen" -#: builtin/commit.c:668 +#: builtin/commit.c:646 #, c-format msgid "could not read '%s'" msgstr "Konnte '%s' nicht lesen" -#: builtin/commit.c:720 +#: builtin/commit.c:707 msgid "could not write commit template" msgstr "Konnte Versionsvorlage nicht schreiben" -#: builtin/commit.c:731 +#: builtin/commit.c:718 #, c-format msgid "" "\n" @@ -2303,11 +3457,11 @@ msgid "" msgstr "" "\n" "Es sieht so aus, als trägst du eine Zusammenführung ein.\n" -"Falls das nicht korrekt ist, entferne bitte die Datei\n" +"Falls das nicht korrekt ist, lösche bitte die Datei\n" "\t%s\n" "und versuche es erneut.\n" -#: builtin/commit.c:736 +#: builtin/commit.c:723 #, c-format msgid "" "\n" @@ -2318,11 +3472,11 @@ msgid "" msgstr "" "\n" "Es sieht so aus, als trägst du ein \"cherry-pick\" ein.\n" -"Falls das nicht korrekt ist, entferne bitte die Datei\n" +"Falls das nicht korrekt ist, lösche bitte die Datei\n" "\t%s\n" "und versuche es erneut.\n" -#: builtin/commit.c:748 +#: builtin/commit.c:735 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be ignored, and an empty message aborts the commit.\n" @@ -2331,7 +3485,7 @@ msgstr "" "die mit '#' beginnen, werden ignoriert, und eine leere Versionsbeschreibung\n" "bricht die Eintragung ab.\n" -#: builtin/commit.c:753 +#: builtin/commit.c:740 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be kept; you may remove them yourself if you want to.\n" @@ -2342,174 +3496,504 @@ msgstr "" "entfernen.\n" "Eine leere Versionsbeschreibung bricht die Eintragung ab.\n" -#: builtin/commit.c:766 +#: builtin/commit.c:753 #, c-format msgid "%sAuthor: %s" msgstr "%sAutor: %s" -#: builtin/commit.c:773 +#: builtin/commit.c:760 #, c-format msgid "%sCommitter: %s" msgstr "%sEintragender: %s" -#: builtin/commit.c:793 +#: builtin/commit.c:780 msgid "Cannot read index" msgstr "Kann Bereitstellung nicht lesen" -#: builtin/commit.c:830 +#: builtin/commit.c:817 msgid "Error building trees" msgstr "Fehler beim Erzeugen der Zweige" -#: builtin/commit.c:845 builtin/tag.c:361 +#: builtin/commit.c:832 builtin/tag.c:361 #, c-format msgid "Please supply the message using either -m or -F option.\n" msgstr "Bitte liefere eine Beschreibung entweder mit der Option -m oder -F.\n" -#: builtin/commit.c:942 +#: builtin/commit.c:929 #, c-format msgid "No existing author found with '%s'" msgstr "Kein existierender Autor mit '%s' gefunden." -#: builtin/commit.c:957 builtin/commit.c:1157 +#: builtin/commit.c:944 builtin/commit.c:1148 #, c-format msgid "Invalid untracked files mode '%s'" msgstr "Ungültiger Modus '%s' für unbeobachtete Dateien" -#: builtin/commit.c:997 +#: builtin/commit.c:984 msgid "Using both --reset-author and --author does not make sense" msgstr "Verwendung von --reset-author und --author macht keinen Sinn." -#: builtin/commit.c:1008 +#: builtin/commit.c:995 msgid "You have nothing to amend." msgstr "Du hast nichts zum nachbessern." -#: builtin/commit.c:1011 +#: builtin/commit.c:998 msgid "You are in the middle of a merge -- cannot amend." msgstr "Eine Zusammenführung ist im Gange -- kann nicht nachbessern." -#: builtin/commit.c:1013 +#: builtin/commit.c:1000 msgid "You are in the middle of a cherry-pick -- cannot amend." msgstr "\"cherry-pick\" ist im Gange -- kann nicht nachbessern." -#: builtin/commit.c:1016 +#: builtin/commit.c:1003 msgid "Options --squash and --fixup cannot be used together" msgstr "" "Die Optionen --squash und --fixup können nicht gemeinsam benutzt werden." -#: builtin/commit.c:1026 +#: builtin/commit.c:1013 msgid "Only one of -c/-C/-F/--fixup can be used." msgstr "Nur eines von -c/-C/-F/--fixup kann benutzt werden." -#: builtin/commit.c:1028 +#: builtin/commit.c:1015 msgid "Option -m cannot be combined with -c/-C/-F/--fixup." msgstr "Option -m kann nicht mit -c/-C/-F/--fixup kombiniert werden" -#: builtin/commit.c:1036 +#: builtin/commit.c:1023 msgid "--reset-author can be used only with -C, -c or --amend." msgstr "--reset--author kann nur mit -C, -c oder --amend benutzt werden" -#: builtin/commit.c:1053 +#: builtin/commit.c:1040 msgid "Only one of --include/--only/--all/--interactive/--patch can be used." msgstr "" "Nur eines von --include/--only/--all/--interactive/--patch kann benutzt " "werden." -#: builtin/commit.c:1055 +#: builtin/commit.c:1042 msgid "No paths with --include/--only does not make sense." msgstr "--include/--only machen ohne Pfade keinen Sinn." -#: builtin/commit.c:1057 +#: builtin/commit.c:1044 msgid "Clever... amending the last one with dirty index." msgstr "" "Klug... die letzte Version mit einer unsauberen Bereitstellung nachbessern." -#: builtin/commit.c:1059 +#: builtin/commit.c:1046 msgid "Explicit paths specified without -i nor -o; assuming --only paths..." msgstr "" "Explizite Pfade ohne -i oder -o angegeben; unter der Annahme von --only " "Pfaden..." -#: builtin/commit.c:1069 builtin/tag.c:577 +#: builtin/commit.c:1056 builtin/tag.c:577 #, c-format msgid "Invalid cleanup mode %s" msgstr "Ungültiger \"cleanup\" Modus %s" -#: builtin/commit.c:1074 +#: builtin/commit.c:1061 msgid "Paths with -a does not make sense." msgstr "Pfade mit -a machen keinen Sinn." -#: builtin/commit.c:1257 +#: builtin/commit.c:1067 builtin/commit.c:1202 +msgid "--long and -z are incompatible" +msgstr "--long und -z sind inkompatibel" + +#: builtin/commit.c:1162 builtin/commit.c:1398 +msgid "show status concisely" +msgstr "zeigt Status im Kurzformat" + +#: builtin/commit.c:1164 builtin/commit.c:1400 +msgid "show branch information" +msgstr "zeigt Zweiginformationen" + +#: builtin/commit.c:1166 builtin/commit.c:1402 builtin/push.c:389 +msgid "machine-readable output" +msgstr "maschinenlesbare Ausgabe" + +#: builtin/commit.c:1169 builtin/commit.c:1404 +msgid "show status in long format (default)" +msgstr "zeigt Status im Langformat (Standard)" + +#: builtin/commit.c:1172 builtin/commit.c:1407 +msgid "terminate entries with NUL" +msgstr "schließt Einträge mit NUL-Zeichen ab" + +#: builtin/commit.c:1174 builtin/commit.c:1410 builtin/fast-export.c:636 +#: builtin/fast-export.c:639 builtin/tag.c:461 +msgid "mode" +msgstr "Modus" + +#: builtin/commit.c:1175 builtin/commit.c:1410 +msgid "show untracked files, optional modes: all, normal, no. (Default: all)" +msgstr "" +"zeigt nicht beobachtete Dateien, optionale Modi: all, normal, no. (Standard: " +"all)" + +#: builtin/commit.c:1178 +msgid "show ignored files" +msgstr "zeigt ignorierte Dateien" + +#: builtin/commit.c:1179 parse-options.h:151 +msgid "when" +msgstr "wann" + +#: builtin/commit.c:1180 +msgid "" +"ignore changes to submodules, optional when: all, dirty, untracked. " +"(Default: all)" +msgstr "" +"ignoriert Änderungen in Unterprojekten, optional wenn: all, dirty, " +"untracked. (Standard: all)" + +#: builtin/commit.c:1182 +msgid "list untracked files in columns" +msgstr "listet unbeobachtete Dateien in Spalten auf" + +#: builtin/commit.c:1256 msgid "couldn't look up newly created commit" msgstr "Konnte neu erstellte Version nicht nachschlagen." -#: builtin/commit.c:1259 +#: builtin/commit.c:1258 msgid "could not parse newly created commit" msgstr "Konnte neulich erstellte Version nicht analysieren." -#: builtin/commit.c:1300 +#: builtin/commit.c:1299 msgid "detached HEAD" msgstr "losgelöste Zweigspitze (HEAD)" -#: builtin/commit.c:1302 +#: builtin/commit.c:1301 msgid " (root-commit)" msgstr " (Basis-Version)" -#: builtin/commit.c:1446 +#: builtin/commit.c:1368 +msgid "suppress summary after successful commit" +msgstr "unterdrückt Zusammenfassung nach erfolgreicher Eintragung" + +#: builtin/commit.c:1369 +msgid "show diff in commit message template" +msgstr "zeigt Unterschiede in Versionsbeschreibungsvorlage an" + +#: builtin/commit.c:1371 +msgid "Commit message options" +msgstr "Optionen für Versionsbeschreibung" + +#: builtin/commit.c:1372 builtin/tag.c:459 +msgid "read message from file" +msgstr "liest Beschreibung von Datei" + +#: builtin/commit.c:1373 +msgid "author" +msgstr "Autor" + +#: builtin/commit.c:1373 +msgid "override author for commit" +msgstr "überschreibt Autor von Version" + +#: builtin/commit.c:1374 builtin/gc.c:178 +msgid "date" +msgstr "Datum" + +#: builtin/commit.c:1374 +msgid "override date for commit" +msgstr "überschreibt Datum von Version" + +#: builtin/commit.c:1375 builtin/merge.c:206 builtin/notes.c:537 +#: builtin/notes.c:694 builtin/tag.c:457 +msgid "message" +msgstr "Beschreibung" + +#: builtin/commit.c:1375 +msgid "commit message" +msgstr "Versionsbeschreibung" + +#: builtin/commit.c:1376 +msgid "reuse and edit message from specified commit" +msgstr "verwendet wieder und editiert Beschreibung von der angegebenen Version" + +#: builtin/commit.c:1377 +msgid "reuse message from specified commit" +msgstr "verwendet Beschreibung der angegebenen Version wieder" + +#: builtin/commit.c:1378 +msgid "use autosquash formatted message to fixup specified commit" +msgstr "" +"benutzt eine automatisch zusammengesetzte Beschreibung zum Nachbessern der " +"angegebenen Version" + +#: builtin/commit.c:1379 +msgid "use autosquash formatted message to squash specified commit" +msgstr "" +"benutzt eine automatisch zusammengesetzte Beschreibung zum Zusammenführen " +"der angegebenen Version" + +#: builtin/commit.c:1380 +msgid "the commit is authored by me now (used with -C/-c/--amend)" +msgstr "Setze mich als Autor der Version (benutzt mit -C/-c/--amend)" + +#: builtin/commit.c:1381 builtin/log.c:1073 builtin/revert.c:109 +msgid "add Signed-off-by:" +msgstr "fügt 'Signed-off-by:'-Zeile hinzu" + +#: builtin/commit.c:1382 +msgid "use specified template file" +msgstr "benutzt angegebene Vorlagendatei" + +#: builtin/commit.c:1383 +msgid "force edit of commit" +msgstr "erzwingt Bearbeitung der Version" + +#: builtin/commit.c:1384 +msgid "default" +msgstr "Standard" + +#: builtin/commit.c:1384 builtin/tag.c:462 +msgid "how to strip spaces and #comments from message" +msgstr "" +"wie Leerzeichen und #Kommentare von der Beschreibung getrennt werden sollen" + +#: builtin/commit.c:1385 +msgid "include status in commit message template" +msgstr "fügt Status in die Versionsbeschreibungsvorlage ein" + +#: builtin/commit.c:1386 builtin/merge.c:213 builtin/tag.c:463 +msgid "key id" +msgstr "Schlüssel-ID" + +#: builtin/commit.c:1387 builtin/merge.c:214 +msgid "GPG sign commit" +msgstr "signiert Version mit GPG" + +#. end commit message options +#: builtin/commit.c:1390 +msgid "Commit contents options" +msgstr "Optionen für Versionsinhalt" + +#: builtin/commit.c:1391 +msgid "commit all changed files" +msgstr "trägt alle geänderten Dateien ein" + +#: builtin/commit.c:1392 +msgid "add specified files to index for commit" +msgstr "trägt die angegebenen Dateien zusätzlich zur Bereitstellung ein" + +#: builtin/commit.c:1393 +msgid "interactively add files" +msgstr "interaktives Hinzufügen von Dateien" + +#: builtin/commit.c:1394 +msgid "interactively add changes" +msgstr "interaktives Hinzufügen von Änderungen" + +#: builtin/commit.c:1395 +msgid "commit only specified files" +msgstr "trägt nur die angegebenen Dateien ein" + +#: builtin/commit.c:1396 +msgid "bypass pre-commit hook" +msgstr "umgeht \"pre-commit hook\"" + +#: builtin/commit.c:1397 +msgid "show what would be committed" +msgstr "zeigt an, was eingetragen werden würde" + +#: builtin/commit.c:1408 +msgid "amend previous commit" +msgstr "ändert vorherige Version" + +#: builtin/commit.c:1409 +msgid "bypass post-rewrite hook" +msgstr "umgeht \"post-rewrite hook\"" + +#: builtin/commit.c:1414 +msgid "ok to record an empty change" +msgstr "erlaubt Aufzeichnung einer leeren Änderung" + +#: builtin/commit.c:1417 +msgid "ok to record a change with an empty message" +msgstr "erlaubt Aufzeichnung einer Änderung mit einer leeren Beschreibung" + +#: builtin/commit.c:1449 msgid "could not parse HEAD commit" msgstr "Konnte Version der Zweigspitze (HEAD) nicht analysieren." -#: builtin/commit.c:1484 builtin/merge.c:509 +#: builtin/commit.c:1487 builtin/merge.c:508 #, c-format msgid "could not open '%s' for reading" msgstr "Konnte '%s' nicht zum Lesen öffnen." -#: builtin/commit.c:1491 +#: builtin/commit.c:1494 #, c-format msgid "Corrupt MERGE_HEAD file (%s)" msgstr "Beschädigte MERGE_HEAD-Datei (%s)" -#: builtin/commit.c:1498 +#: builtin/commit.c:1501 msgid "could not read MERGE_MODE" msgstr "Konnte MERGE_MODE nicht lesen" -#: builtin/commit.c:1517 +#: builtin/commit.c:1520 #, c-format msgid "could not read commit message: %s" msgstr "Konnte Versionsbeschreibung nicht lesen: %s" -#: builtin/commit.c:1531 +#: builtin/commit.c:1534 #, c-format msgid "Aborting commit; you did not edit the message.\n" msgstr "Eintragung abgebrochen; du hast die Beschreibung nicht editiert.\n" -#: builtin/commit.c:1536 +#: builtin/commit.c:1539 #, c-format msgid "Aborting commit due to empty commit message.\n" msgstr "Eintragung aufgrund leerer Versionsbeschreibung abgebrochen.\n" -#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961 +#: builtin/commit.c:1554 builtin/merge.c:832 builtin/merge.c:857 msgid "failed to write commit object" msgstr "Fehler beim Schreiben des Versionsobjektes." -#: builtin/commit.c:1572 +#: builtin/commit.c:1575 msgid "cannot lock HEAD ref" msgstr "Kann Referenz der Zweigspitze (HEAD) nicht sperren." -#: builtin/commit.c:1576 +#: builtin/commit.c:1579 msgid "cannot update HEAD ref" msgstr "Kann Referenz der Zweigspitze (HEAD) nicht aktualisieren." -#: builtin/commit.c:1587 +#: builtin/commit.c:1590 msgid "" "Repository has been updated, but unable to write\n" "new_index file. Check that disk is not full or quota is\n" "not exceeded, and then \"git reset HEAD\" to recover." msgstr "" "Das Projektarchiv wurde aktualisiert, aber die \"new_index\"-Datei\n" -"konnte nicht geschrieben werden. Prüfe, dass dein Speicher nicht\n" +"konnte nicht geschrieben werden. Prüfe, dass deine Festplatte nicht\n" "voll und Dein Kontingent nicht aufgebraucht ist und führe\n" "anschließend \"git reset HEAD\" zu Wiederherstellung aus." +#: builtin/config.c:7 +msgid "git config [options]" +msgstr "git config [Optionen]" + +#: builtin/config.c:51 +msgid "Config file location" +msgstr "Ort der Konfigurationsdatei" + +#: builtin/config.c:52 +msgid "use global config file" +msgstr "benutzt globale Konfigurationsdatei" + +#: builtin/config.c:53 +msgid "use system config file" +msgstr "benutzt systemweite Konfigurationsdatei" + +#: builtin/config.c:54 +msgid "use repository config file" +msgstr "benutzt Konfigurationsdatei des Projektarchivs" + +#: builtin/config.c:55 +msgid "use given config file" +msgstr "benutzt die angegebene Konfigurationsdatei" + +#: builtin/config.c:56 +msgid "Action" +msgstr "Aktion" + +#: builtin/config.c:57 +msgid "get value: name [value-regex]" +msgstr "gibt Wert zurück: Name [Wert-regex]" + +#: builtin/config.c:58 +msgid "get all values: key [value-regex]" +msgstr "gibt alle Werte zurück: Schlüssel [Wert-regex]" + +#: builtin/config.c:59 +msgid "get values for regexp: name-regex [value-regex]" +msgstr "gibt Werte für den regulären Ausdruck zurück: Name-regex [Wert-regex]" + +#: builtin/config.c:60 +msgid "replace all matching variables: name value [value_regex]" +msgstr "ersetzt alle passenden Variablen: Name Wert [Wert-regex] " + +#: builtin/config.c:61 +msgid "add a new variable: name value" +msgstr "fügt neue Variable hinzu: Name Wert" + +#: builtin/config.c:62 +msgid "remove a variable: name [value-regex]" +msgstr "entfernt eine Variable: Name [Wert-regex]" + +#: builtin/config.c:63 +msgid "remove all matches: name [value-regex]" +msgstr "entfernt alle Übereinstimmungen: Name [Wert-regex]" + +#: builtin/config.c:64 +msgid "rename section: old-name new-name" +msgstr "benennt eine Sektion um: alter-Name neuer-Name" + +#: builtin/config.c:65 +msgid "remove a section: name" +msgstr "entfernt eine Sektion: Name" + +#: builtin/config.c:66 +msgid "list all" +msgstr "listet alles auf" + +#: builtin/config.c:67 +msgid "open an editor" +msgstr "öffnet einen Editor" + +#: builtin/config.c:68 builtin/config.c:69 +msgid "slot" +msgstr "Slot" + +#: builtin/config.c:68 +msgid "find the color configured: [default]" +msgstr "findet die konfigurierte Farbe: [Standard]" + +#: builtin/config.c:69 +msgid "find the color setting: [stdout-is-tty]" +msgstr "findet die Farbeinstellung: [Standard-Ausgabe-ist-Terminal]" + +#: builtin/config.c:70 +msgid "Type" +msgstr "Typ" + +#: builtin/config.c:71 +msgid "value is \"true\" or \"false\"" +msgstr "Wert ist \"true\" oder \"false\"" + +#: builtin/config.c:72 +msgid "value is decimal number" +msgstr "Wert ist eine Dezimalzahl" + +#: builtin/config.c:73 +msgid "value is --bool or --int" +msgstr "Wert ist --bool oder --int" + +#: builtin/config.c:74 +msgid "value is a path (file or directory name)" +msgstr "Wert ist ein Pfad (Datei oder Verzeichnisname)" + +#: builtin/config.c:75 +msgid "Other" +msgstr "Sonstiges" + +#: builtin/config.c:76 +msgid "terminate values with NUL byte" +msgstr "schließt Werte mit NUL-Byte ab" + +#: builtin/config.c:77 +msgid "respect include directives on lookup" +msgstr "beachtet \"include\"-Direktiven beim Nachschlagen" + +#: builtin/count-objects.c:69 +msgid "git count-objects [-v]" +msgstr "git count-objects [-v]" + +#: builtin/describe.c:15 +msgid "git describe [options] <committish>*" +msgstr "git describe [Optionen] <committish>*" + +#: builtin/describe.c:16 +msgid "git describe [options] --dirty" +msgstr "git describe [Optionen] --dirty" + #: builtin/describe.c:234 #, c-format msgid "annotated tag %s not available" @@ -2582,6 +4066,51 @@ msgstr "" "mehr als %i Markierungen gefunden; Führe die ersten %i auf\n" "Suche bei %s aufgegeben\n" +#: builtin/describe.c:403 +msgid "find the tag that comes after the commit" +msgstr "findet die Markierung, die nach der Version kommt" + +#: builtin/describe.c:404 +msgid "debug search strategy on stderr" +msgstr "protokolliert die Suchstrategie in der Standard-Fehlerausgabe" + +#: builtin/describe.c:405 +msgid "use any ref in .git/refs" +msgstr "benutzt jede Referenz in .git/refs" + +#: builtin/describe.c:406 +msgid "use any tag in .git/refs/tags" +msgstr "benutzt alle Markierungen in .git/refs/tags" + +#: builtin/describe.c:407 +msgid "always use long format" +msgstr "benutzt immer langes Format" + +#: builtin/describe.c:410 +msgid "only output exact matches" +msgstr "gibt nur exakte Übereinstimmungen aus" + +#: builtin/describe.c:412 +msgid "consider <n> most recent tags (default: 10)" +msgstr "betrachtet die jüngsten <n> Markierungen (Standard: 10)" + +#: builtin/describe.c:414 +msgid "only consider tags matching <pattern>" +msgstr "betrachtet nur Markierungen die <Muster> entsprechen" + +#: builtin/describe.c:416 builtin/name-rev.c:238 +msgid "show abbreviated commit object as fallback" +msgstr "zeigt gekürztes Versionsobjekt, wenn sonst nichts zutrifft" + +#: builtin/describe.c:417 +msgid "mark" +msgstr "Kennzeichen" + +#: builtin/describe.c:418 +msgid "append <mark> on dirty working tree (default: \"-dirty\")" +msgstr "" +"fügt <Kennzeichen> bei geändertem Arbeitsbaum hinzu (Standard: \"-dirty\")" + #: builtin/describe.c:436 msgid "--long is incompatible with --abbrev=0" msgstr "--long ist inkompatibel mit --abbrev=0" @@ -2594,45 +4123,167 @@ msgstr "Keine Namen gefunden, kann nichts beschreiben." msgid "--dirty is incompatible with committishes" msgstr "--dirty ist inkompatibel mit Versionen" -#: builtin/diff.c:77 +#: builtin/diff.c:79 #, c-format msgid "'%s': not a regular file or symlink" msgstr "'%s': keine reguläre Datei oder symbolischer Link" -#: builtin/diff.c:220 +#: builtin/diff.c:228 #, c-format msgid "invalid option: %s" msgstr "Ungültige Option: %s" -#: builtin/diff.c:297 +#: builtin/diff.c:305 msgid "Not a git repository" msgstr "Kein Git-Projektarchiv" -#: builtin/diff.c:347 +#: builtin/diff.c:348 #, c-format msgid "invalid object '%s' given." msgstr "Objekt '%s' ist ungültig." -#: builtin/diff.c:352 +#: builtin/diff.c:353 #, c-format msgid "more than %d trees given: '%s'" msgstr "Mehr als %d Zweige angegeben: '%s'" -#: builtin/diff.c:362 +#: builtin/diff.c:363 #, c-format msgid "more than two blobs given: '%s'" msgstr "Mehr als zwei Blobs angegeben: '%s'" -#: builtin/diff.c:370 +#: builtin/diff.c:371 #, c-format msgid "unhandled object '%s' given." msgstr "unbehandeltes Objekt '%s' angegeben" -#: builtin/fetch.c:200 +#: builtin/fast-export.c:22 +msgid "git fast-export [rev-list-opts]" +msgstr "git fast-export [rev-list-opts]" + +#: builtin/fast-export.c:635 +msgid "show progress after <n> objects" +msgstr "zeigt Fortschritt nach <n> Objekten an" + +#: builtin/fast-export.c:637 +msgid "select handling of signed tags" +msgstr "wählt Behandlung von signierten Markierungen" + +#: builtin/fast-export.c:640 +msgid "select handling of tags that tag filtered objects" +msgstr "wählt Behandlung von Markierungen, die gefilterte Objekte markieren" + +#: builtin/fast-export.c:643 +msgid "Dump marks to this file" +msgstr "Schreibt Kennzeichen in diese Datei" + +#: builtin/fast-export.c:645 +msgid "Import marks from this file" +msgstr "Importiert Kennzeichen von dieser Datei" + +#: builtin/fast-export.c:647 +msgid "Fake a tagger when tags lack one" +msgstr "" +"erzeugt künstlich einen Markierungsersteller, wenn die Markierung keinen hat" + +#: builtin/fast-export.c:649 +msgid "Output full tree for each commit" +msgstr "gibt für jede Version den gesamten Baum aus" + +#: builtin/fast-export.c:651 +msgid "Use the done feature to terminate the stream" +msgstr "Benutzt die \"done\"-Funktion um den Strom abzuschließen" + +#: builtin/fast-export.c:652 +msgid "Skip output of blob data" +msgstr "Überspringt Ausgabe von Blob-Daten" + +#: builtin/fetch.c:20 +msgid "git fetch [<options>] [<repository> [<refspec>...]]" +msgstr "git fetch [<Optionen>] [<Projektarchiv> [<Referenzspezifikation>...]]" + +#: builtin/fetch.c:21 +msgid "git fetch [<options>] <group>" +msgstr "git fetch [<Optionen>] <Gruppe>" + +#: builtin/fetch.c:22 +msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]" +msgstr "git fetch --multiple [<Optionen>] [(<Projektarchiv> | <Gruppe>)...]" + +#: builtin/fetch.c:23 +msgid "git fetch --all [<options>]" +msgstr "git fetch --all [<Optionen>]" + +#: builtin/fetch.c:60 +msgid "fetch from all remotes" +msgstr "fordert von allen externen Projektarchiven an" + +#: builtin/fetch.c:62 +msgid "append to .git/FETCH_HEAD instead of overwriting" +msgstr "hängt an .git/FETCH_HEAD an, anstatt zu überschreiben" + +#: builtin/fetch.c:64 +msgid "path to upload pack on remote end" +msgstr "Pfad des Programms zum Hochladen von Paketen auf der Gegenseite" + +#: builtin/fetch.c:65 +msgid "force overwrite of local branch" +msgstr "erzwingt das Überschreiben von lokalen Zweigen" + +#: builtin/fetch.c:67 +msgid "fetch from multiple remotes" +msgstr "fordert von mehreren externen Projektarchiven an" + +#: builtin/fetch.c:69 +msgid "fetch all tags and associated objects" +msgstr "fordert alle Markierungen und verbundene Objekte an" + +#: builtin/fetch.c:71 +msgid "do not fetch all tags (--no-tags)" +msgstr "fordert nicht alle Markierungen an (--no-tags)" + +#: builtin/fetch.c:73 +msgid "prune remote-tracking branches no longer on remote" +msgstr "" +"entfernt externe Übernahmezweige, die sich nicht mehr im Fernarchiv befinden" + +#: builtin/fetch.c:74 +msgid "on-demand" +msgstr "bei-Bedarf" + +#: builtin/fetch.c:75 +msgid "control recursive fetching of submodules" +msgstr "kontrolliert rekursive Anforderungen von Unterprojekten" + +#: builtin/fetch.c:79 +msgid "keep downloaded pack" +msgstr "behält heruntergeladenes Paket" + +#: builtin/fetch.c:81 +msgid "allow updating of HEAD ref" +msgstr "erlaubt Aktualisierung der \"HEAD\"-Referenz" + +#: builtin/fetch.c:84 +msgid "deepen history of shallow clone" +msgstr "vertieft die Historie eines flachen Klon" + +#: builtin/fetch.c:85 builtin/log.c:1088 +msgid "dir" +msgstr "Verzeichnis" + +#: builtin/fetch.c:86 +msgid "prepend this to submodule path output" +msgstr "stellt dies an die Ausgabe der Unterprojekt-Pfade voran" + +#: builtin/fetch.c:89 +msgid "default mode for recursion" +msgstr "Standard-Modus für Rekursion" + +#: builtin/fetch.c:201 msgid "Couldn't find remote ref HEAD" msgstr "Konnte externe Referenz der Zweigspitze (HEAD) nicht finden." -#: builtin/fetch.c:253 +#: builtin/fetch.c:254 #, c-format msgid "object %s not found" msgstr "Objekt %s nicht gefunden" @@ -2704,7 +4355,7 @@ msgid "" " 'git remote prune %s' to remove any old, conflicting branches" msgstr "" "Einige lokale Referenzen konnten nicht aktualisiert werden; versuche\n" -"'git remote prune %s' um jeden älteren, widersprüchlichen Zweig zu entfernen." +"'git remote prune %s' um jeden älteren, widersprüchlichen Zweig zu löschen." #: builtin/fetch.c:549 #, c-format @@ -2746,17 +4397,17 @@ msgstr "Option \"%s\" Wert \"%s\" ist nicht gültig für %s" msgid "Option \"%s\" is ignored for %s\n" msgstr "Option \"%s\" wird ignoriert für %s\n" -#: builtin/fetch.c:888 +#: builtin/fetch.c:891 #, c-format msgid "Fetching %s\n" msgstr "Fordere an von %s\n" -#: builtin/fetch.c:890 builtin/remote.c:100 +#: builtin/fetch.c:893 builtin/remote.c:100 #, c-format msgid "Could not fetch %s" msgstr "Konnte nicht von %s anfordern" -#: builtin/fetch.c:907 +#: builtin/fetch.c:912 msgid "" "No remote repository specified. Please, specify either a URL or a\n" "remote name from which new revisions should be fetched." @@ -2765,29 +4416,148 @@ msgstr "" "oder den Namen des externen Archivs an, von welchem neue\n" "Versionen angefordert werden sollen." -#: builtin/fetch.c:927 +#: builtin/fetch.c:932 msgid "You need to specify a tag name." msgstr "Du musst den Namen der Markierung angeben." -#: builtin/fetch.c:979 +#: builtin/fetch.c:984 msgid "fetch --all does not take a repository argument" msgstr "fetch --all akzeptiert kein Projektarchiv als Argument" -#: builtin/fetch.c:981 +#: builtin/fetch.c:986 msgid "fetch --all does not make sense with refspecs" msgstr "fetch --all macht keinen Sinn mit Referenzspezifikationen" -#: builtin/fetch.c:992 +#: builtin/fetch.c:997 #, c-format msgid "No such remote or remote group: %s" msgstr "Kein externes Archiv (einzeln oder Gruppe): %s" -#: builtin/fetch.c:1000 +#: builtin/fetch.c:1005 msgid "Fetching a group and specifying refspecs does not make sense" msgstr "" "Abholen einer Gruppe mit Angabe von Referenzspezifikationen macht keinen " "Sinn." +#: builtin/fmt-merge-msg.c:13 +msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]" +msgstr "" +"git fmt-merge-msg [-m <Beschreibung>] [--log[=<n>]|--no-log] [--file <Datei>]" + +#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:701 +#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175 +#: builtin/tag.c:448 parse-options.h:133 parse-options.h:235 +msgid "n" +msgstr "Anzahl" + +#: builtin/fmt-merge-msg.c:654 +msgid "populate log with at most <n> entries from shortlog" +msgstr "fügt Historie mit höchstens <n> Einträgen von \"shortlog\" hinzu" + +#: builtin/fmt-merge-msg.c:657 +msgid "alias for --log (deprecated)" +msgstr "Alias für --log (veraltet)" + +#: builtin/fmt-merge-msg.c:660 +msgid "text" +msgstr "Text" + +#: builtin/fmt-merge-msg.c:661 +msgid "use <text> as start of message" +msgstr "benutzt <Text> als Beschreibungsanfang" + +#: builtin/fmt-merge-msg.c:662 +msgid "file to read from" +msgstr "Datei zum Einlesen" + +#: builtin/for-each-ref.c:979 +msgid "git for-each-ref [options] [<pattern>]" +msgstr "git for-each-ref [Optionen] [<Muster>]" + +#: builtin/for-each-ref.c:994 +msgid "quote placeholders suitably for shells" +msgstr "formatiert Platzhalter als Shell-String" + +#: builtin/for-each-ref.c:996 +msgid "quote placeholders suitably for perl" +msgstr "formatiert Platzhalter als Perl-String" + +#: builtin/for-each-ref.c:998 +msgid "quote placeholders suitably for python" +msgstr "formatiert Platzhalter als Python-String" + +#: builtin/for-each-ref.c:1000 +msgid "quote placeholders suitably for tcl" +msgstr "formatiert Platzhalter als TCL-String" + +#: builtin/for-each-ref.c:1003 +msgid "show only <n> matched refs" +msgstr "zeigt nur <n> passende Referenzen" + +#: builtin/for-each-ref.c:1004 +msgid "format" +msgstr "Format" + +#: builtin/for-each-ref.c:1004 +msgid "format to use for the output" +msgstr "für die Ausgabe zu verwendendes Format" + +#: builtin/for-each-ref.c:1005 +msgid "key" +msgstr "Schüssel" + +#: builtin/for-each-ref.c:1006 +msgid "field name to sort on" +msgstr "sortiere nach diesem Feld" + +#: builtin/fsck.c:608 +msgid "git fsck [options] [<object>...]" +msgstr "git fsck [Optionen] [<Objekt>...]" + +#: builtin/fsck.c:614 +msgid "show unreachable objects" +msgstr "zeigt unerreichbare Objekte" + +#: builtin/fsck.c:615 +msgid "show dangling objects" +msgstr "zeigt unreferenzierte Objekte" + +#: builtin/fsck.c:616 +msgid "report tags" +msgstr "meldet Markierungen" + +#: builtin/fsck.c:617 +msgid "report root nodes" +msgstr "meldet Hauptwurzeln" + +#: builtin/fsck.c:618 +msgid "make index objects head nodes" +msgstr "erzeugt Kopfknoten der Bereitstellungsobjekte" + +#: builtin/fsck.c:619 +msgid "make reflogs head nodes (default)" +msgstr "erzeugt Kopfknoten des Referenzprotokolls (Standard)" + +#: builtin/fsck.c:620 +msgid "also consider packs and alternate objects" +msgstr "" + +#: builtin/fsck.c:621 +msgid "enable more strict checking" +msgstr "aktiviert genauere Prüfung" + +#: builtin/fsck.c:623 +msgid "write dangling objects in .git/lost-found" +msgstr "schreibt unreferenzierte Objekte nach .git/lost-found" + +#: builtin/fsck.c:624 builtin/prune.c:134 +msgid "show progress" +msgstr "zeigt Fortschrittsanzeige" + +#: builtin/gc.c:22 +msgid "git gc [options]" +msgstr "git gc [Optionen]" + #: builtin/gc.c:63 #, c-format msgid "Invalid %s: '%s'" @@ -2798,14 +4568,19 @@ msgstr "Ungültiger %s: '%s'" msgid "insanely long object directory %.*s" msgstr "zu langes Objekt-Verzeichnis %.*s" -#: builtin/gc.c:221 -#, c-format -msgid "Auto packing the repository for optimum performance.\n" -msgstr "" -"Die Datenbank des Projektarchivs wird für eine optimale Performance " -"komprimiert.\n" +#: builtin/gc.c:179 +msgid "prune unreferenced objects" +msgstr "entfernt unreferenzierte Objekte" -#: builtin/gc.c:224 +#: builtin/gc.c:181 +msgid "be more thorough (increased runtime)" +msgstr "mehr Gründlichkeit (erhöht Laufzeit)" + +#: builtin/gc.c:182 +msgid "enable auto-gc mode" +msgstr "aktiviert \"auto-gc\" Modus" + +#: builtin/gc.c:222 #, c-format msgid "" "Auto packing the repository for optimum performance. You may also\n" @@ -2815,97 +4590,328 @@ msgstr "" "komprimiert. Du kannst auch \"git gc\" manuell ausführen.\n" "Siehe \"git help gc\" für weitere Informationen.\n" -#: builtin/gc.c:251 +#: builtin/gc.c:249 msgid "" "There are too many unreachable loose objects; run 'git prune' to remove them." msgstr "" "Es gibt zu viele unerreichbare lose Objekte; führe 'git prune' aus, um diese " -"zu entfernen." +"zu löschen." + +#: builtin/grep.c:22 +msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]" +msgstr "git grep [Optionen] [-e] <Muster> [<Version>...] [[--] <Pfad>...]" -#: builtin/grep.c:216 +#: builtin/grep.c:217 #, c-format msgid "grep: failed to create thread: %s" msgstr "grep: Fehler beim Erzeugen eines Thread: %s" -#: builtin/grep.c:402 +#: builtin/grep.c:365 #, c-format msgid "Failed to chdir: %s" msgstr "Fehler beim Verzeichniswechsel: %s" -#: builtin/grep.c:478 builtin/grep.c:512 +#: builtin/grep.c:443 builtin/grep.c:478 #, c-format msgid "unable to read tree (%s)" msgstr "konnte Zweig (%s) nicht lesen" -#: builtin/grep.c:526 +#: builtin/grep.c:493 #, c-format msgid "unable to grep from object of type %s" msgstr "kann \"grep\" nicht mit Objekten des Typs %s durchführen" -#: builtin/grep.c:584 +#: builtin/grep.c:551 #, c-format msgid "switch `%c' expects a numerical value" msgstr "Schalter '%c' erwartet einen numerischen Wert" -#: builtin/grep.c:601 +#: builtin/grep.c:568 #, c-format msgid "cannot open '%s'" msgstr "kann '%s' nicht öffnen" -#: builtin/grep.c:885 +#: builtin/grep.c:643 +msgid "search in index instead of in the work tree" +msgstr "sucht in der Bereitstellung anstatt im Arbeitsbaum" + +#: builtin/grep.c:645 +msgid "find in contents not managed by git" +msgstr "findet auch in Inhalten, die nicht von Git verwaltet werden" + +#: builtin/grep.c:647 +msgid "search in both tracked and untracked files" +msgstr "sucht in beobachteten und unbeobachteten Dateien" + +#: builtin/grep.c:649 +msgid "search also in ignored files" +msgstr "sucht auch in ignorierten Dateien" + +#: builtin/grep.c:652 +msgid "show non-matching lines" +msgstr "zeigt Zeilen ohne Übereinstimmungen" + +#: builtin/grep.c:654 +msgid "case insensitive matching" +msgstr "findet Übereinstimmungen unabhängig von Groß- und Kleinschreibung" + +#: builtin/grep.c:656 +msgid "match patterns only at word boundaries" +msgstr "sucht nur ganze Wörter" + +#: builtin/grep.c:658 +msgid "process binary files as text" +msgstr "verarbeitet binäre Dateien als Text" + +#: builtin/grep.c:660 +msgid "don't match patterns in binary files" +msgstr "findet keine Muster in Binärdateien" + +#: builtin/grep.c:663 +msgid "descend at most <depth> levels" +msgstr "durchläuft höchstens <Tiefe> Ebenen" + +#: builtin/grep.c:667 +msgid "use extended POSIX regular expressions" +msgstr "benutzt erweiterte reguläre Ausdrücke aus POSIX" + +#: builtin/grep.c:670 +msgid "use basic POSIX regular expressions (default)" +msgstr "benutzt grundlegende reguläre Ausdrücke aus POSIX (Standard)" + +#: builtin/grep.c:673 +msgid "interpret patterns as fixed strings" +msgstr "interpretiert Muster als feste Zeichenketten" + +#: builtin/grep.c:676 +msgid "use Perl-compatible regular expressions" +msgstr "benutzt Perl-kompatible reguläre Ausdrücke" + +#: builtin/grep.c:679 +msgid "show line numbers" +msgstr "zeigt Zeilennummern" + +#: builtin/grep.c:680 +msgid "don't show filenames" +msgstr "zeigt keine Dateinamen" + +#: builtin/grep.c:681 +msgid "show filenames" +msgstr "zeigt Dateinamen" + +#: builtin/grep.c:683 +msgid "show filenames relative to top directory" +msgstr "zeigt Dateinamen relativ zum Projektverzeichnis" + +#: builtin/grep.c:685 +msgid "show only filenames instead of matching lines" +msgstr "zeigt nur Dateinamen anstatt übereinstimmende Zeilen" + +#: builtin/grep.c:687 +msgid "synonym for --files-with-matches" +msgstr "Synonym für --files-with-matches" + +#: builtin/grep.c:690 +msgid "show only the names of files without match" +msgstr "zeigt nur die Dateinamen ohne Übereinstimmungen" + +#: builtin/grep.c:692 +msgid "print NUL after filenames" +msgstr "gibt NUL-Zeichen nach Dateinamen aus" + +#: builtin/grep.c:694 +msgid "show the number of matches instead of matching lines" +msgstr "zeigt, anstatt der Zeilen, die Anzahl der übereinstimmenden Zeilen" + +#: builtin/grep.c:695 +msgid "highlight matches" +msgstr "hebt Übereinstimmungen hervor" + +#: builtin/grep.c:697 +msgid "print empty line between matches from different files" +msgstr "" +"gibt eine Leerzeile zwischen Übereinstimmungen in verschiedenen Dateien aus" + +#: builtin/grep.c:699 +msgid "show filename only once above matches from same file" +msgstr "" +"zeigt den Dateinamen nur einmal oberhalb der Übereinstimmungen aus dieser " +"Datei an" + +#: builtin/grep.c:702 +msgid "show <n> context lines before and after matches" +msgstr "zeigt <n> Zeilen vor und nach den Übereinstimmungen an" + +#: builtin/grep.c:705 +msgid "show <n> context lines before matches" +msgstr "zeigt <n> Zeilen vor den Übereinstimmungen an" + +#: builtin/grep.c:707 +msgid "show <n> context lines after matches" +msgstr "zeigt <n> Zeilen nach den Übereinstimmungen an" + +#: builtin/grep.c:708 +msgid "shortcut for -C NUM" +msgstr "Kurzform für -C NUM" + +#: builtin/grep.c:711 +msgid "show a line with the function name before matches" +msgstr "zeigt eine Zeile mit dem Funktionsnamen vor Übereinstimmungen an" + +#: builtin/grep.c:713 +msgid "show the surrounding function" +msgstr "zeigt die umgebende Funktion an" + +#: builtin/grep.c:716 +msgid "read patterns from file" +msgstr "liest Muster von einer Datei" + +#: builtin/grep.c:718 +msgid "match <pattern>" +msgstr "findet <Muster>" + +#: builtin/grep.c:720 +msgid "combine patterns specified with -e" +msgstr "kombiniert Muster, die mit -e angegeben wurden" + +#: builtin/grep.c:732 +msgid "indicate hit with exit status without output" +msgstr "zeigt Übereinstimmungen nur durch Beendigungsstatus an" + +#: builtin/grep.c:734 +msgid "show only matches from files that match all patterns" +msgstr "zeigt nur Übereinstimmungen von Dateien, die allen Mustern entsprechen" + +#: builtin/grep.c:736 +msgid "show parse tree for grep expression" +msgstr "zeigt geparsten Baum für \"grep\"-Ausdruck" + +#: builtin/grep.c:740 +msgid "pager" +msgstr "Anzeigeprogramm" + +#: builtin/grep.c:740 +msgid "show matching files in the pager" +msgstr "zeigt Dateien mit Übereinstimmungen im Anzeigeprogramm" + +#: builtin/grep.c:743 +msgid "allow calling of grep(1) (ignored by this build)" +msgstr "erlaubt den Aufruf von grep(1) (von dieser Programmversion ignoriert)" + +#: builtin/grep.c:744 builtin/show-ref.c:184 +msgid "show usage" +msgstr "zeigt Verwendung" + +#: builtin/grep.c:811 msgid "no pattern given." msgstr "keine Muster angegeben" -#: builtin/grep.c:899 +#: builtin/grep.c:825 #, c-format msgid "bad object %s" msgstr "ungültiges Objekt %s" -#: builtin/grep.c:940 +#: builtin/grep.c:866 msgid "--open-files-in-pager only works on the worktree" msgstr "--open-files-in-pager arbeitet nur innerhalb des Arbeitsbaums" -#: builtin/grep.c:963 +#: builtin/grep.c:889 msgid "--cached or --untracked cannot be used with --no-index." msgstr "--cached oder --untracked kann nicht mit --no-index benutzt werden" -#: builtin/grep.c:968 +#: builtin/grep.c:894 msgid "--no-index or --untracked cannot be used with revs." msgstr "--no-index oder --untracked kann nicht mit Versionen benutzt werden" -#: builtin/grep.c:971 +#: builtin/grep.c:897 msgid "--[no-]exclude-standard cannot be used for tracked contents." msgstr "" "--[no-]exlude-standard kann nicht mit beobachteten Inhalten benutzt werden" -#: builtin/grep.c:979 +#: builtin/grep.c:905 msgid "both --cached and trees are given." msgstr "sowohl --cached als auch Zweige gegeben" -#: builtin/help.c:59 +#: builtin/hash-object.c:60 +msgid "" +"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] " +"<file>..." +msgstr "" +"git hash-object [-t <Art>] [-w] [--path=<Datei>|--no-filters] [--stdin] [--] " +"<Datei>..." + +#: builtin/hash-object.c:61 +msgid "git hash-object --stdin-paths < <list-of-paths>" +msgstr "git hash-object --stdin-paths < <Liste-von-Pfaden>" + +#: builtin/hash-object.c:72 +msgid "type" +msgstr "Art" + +#: builtin/hash-object.c:72 +msgid "object type" +msgstr "Art des Objektes" + +#: builtin/hash-object.c:73 +msgid "write the object into the object database" +msgstr "schreibt das Objekt in die Objektdatenbank" + +#: builtin/hash-object.c:74 +msgid "read the object from stdin" +msgstr "liest das Objekt von der Standard-Eingabe" + +#: builtin/hash-object.c:76 +msgid "store file as is without filters" +msgstr "speichert Datei wie sie ist, ohne Filter" + +#: builtin/hash-object.c:77 +msgid "process file as it were from this path" +msgstr "verarbeitet Datei, als ob sie von diesem Pfad wäre" + +#: builtin/help.c:43 +msgid "print all available commands" +msgstr "Anzeige aller vorhandenen Kommandos" + +#: builtin/help.c:44 +msgid "show man page" +msgstr "zeigt Handbuch" + +#: builtin/help.c:45 +msgid "show manual in web browser" +msgstr "zeigt Handbuch in einem Webbrowser" + +#: builtin/help.c:47 +msgid "show info page" +msgstr "zeigt Info-Seite" + +#: builtin/help.c:53 +msgid "git help [--all] [--man|--web|--info] [command]" +msgstr "git help [--all] [--man|--web|--info] [Kommando]" + +#: builtin/help.c:65 #, c-format msgid "unrecognized help format '%s'" msgstr "nicht erkanntes Hilfeformat: %s" -#: builtin/help.c:87 +#: builtin/help.c:93 msgid "Failed to start emacsclient." msgstr "Konnte emacsclient nicht starten." -#: builtin/help.c:100 +#: builtin/help.c:106 msgid "Failed to parse emacsclient version." msgstr "Konnte Version des emacsclient nicht parsen." -#: builtin/help.c:108 +#: builtin/help.c:114 #, c-format msgid "emacsclient version '%d' too old (< 22)." msgstr "Version des emacsclient '%d' ist zu alt (< 22)." -#: builtin/help.c:126 builtin/help.c:154 builtin/help.c:163 builtin/help.c:171 +#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177 #, c-format msgid "failed to exec '%s': %s" msgstr "Fehler beim Ausführen von '%s': %s" -#: builtin/help.c:211 +#: builtin/help.c:217 #, c-format msgid "" "'%s': path for unsupported man viewer.\n" @@ -2914,7 +4920,7 @@ msgstr "" "'%s': Pfad für nicht unterstützten Handbuchbetrachter.\n" "Du könntest stattdessen 'man.<Werkzeug>.cmd' benutzen." -#: builtin/help.c:223 +#: builtin/help.c:229 #, c-format msgid "" "'%s': cmd for supported man viewer.\n" @@ -2923,267 +4929,308 @@ msgstr "" "'%s': Kommando für unterstützten Handbuchbetrachter.\n" "Du könntest stattdessen 'man.<Werkzeug>.path' benutzen." -#: builtin/help.c:287 +#: builtin/help.c:299 msgid "The most commonly used git commands are:" msgstr "Die allgemein verwendeten Git-Kommandos sind:" -#: builtin/help.c:355 +#: builtin/help.c:367 #, c-format msgid "'%s': unknown man viewer." msgstr "'%s': unbekannter Handbuch-Betrachter." -#: builtin/help.c:372 +#: builtin/help.c:384 msgid "no man viewer handled the request" msgstr "kein Handbuch-Betrachter konnte mit dieser Anfrage umgehen" -#: builtin/help.c:380 +#: builtin/help.c:392 msgid "no info viewer handled the request" msgstr "kein Informations-Betrachter konnte mit dieser Anfrage umgehen" -#: builtin/help.c:391 -#, c-format -msgid "'%s': not a documentation directory." -msgstr "'%s' ist kein Dokumentationsverzeichnis" - -#: builtin/help.c:432 builtin/help.c:439 +#: builtin/help.c:447 builtin/help.c:454 #, c-format msgid "usage: %s%s" msgstr "Verwendung: %s%s" -#: builtin/help.c:453 +#: builtin/help.c:470 #, c-format msgid "`git %s' is aliased to `%s'" msgstr "für `git %s' wurde der Alias `%s' angelegt" -#: builtin/index-pack.c:169 +#: builtin/index-pack.c:170 #, c-format msgid "object type mismatch at %s" msgstr "Objekt-Typen passen bei %s nicht zusammen" -#: builtin/index-pack.c:189 +#: builtin/index-pack.c:190 msgid "object of unexpected type" msgstr "Objekt hat unerwarteten Typ" -#: builtin/index-pack.c:226 +#: builtin/index-pack.c:227 #, c-format msgid "cannot fill %d byte" msgid_plural "cannot fill %d bytes" msgstr[0] "kann %d Byte nicht lesen" msgstr[1] "kann %d Bytes nicht lesen" -#: builtin/index-pack.c:236 +#: builtin/index-pack.c:237 msgid "early EOF" msgstr "zu frühes Dateiende" -#: builtin/index-pack.c:237 +#: builtin/index-pack.c:238 msgid "read error on input" msgstr "Fehler beim Lesen der Eingabe" -#: builtin/index-pack.c:249 +#: builtin/index-pack.c:250 msgid "used more bytes than were available" msgstr "verwendete mehr Bytes als verfügbar waren" -#: builtin/index-pack.c:256 +#: builtin/index-pack.c:257 msgid "pack too large for current definition of off_t" msgstr "Paket ist zu groß für die aktuelle Definition von off_t" -#: builtin/index-pack.c:272 +#: builtin/index-pack.c:273 #, c-format msgid "unable to create '%s'" msgstr "konnte '%s' nicht erstellen" -#: builtin/index-pack.c:277 +#: builtin/index-pack.c:278 #, c-format msgid "cannot open packfile '%s'" msgstr "Kann Paketdatei '%s' nicht öffnen" -#: builtin/index-pack.c:291 +#: builtin/index-pack.c:292 msgid "pack signature mismatch" msgstr "Paketsignatur stimmt nicht überein" -#: builtin/index-pack.c:311 +#: builtin/index-pack.c:294 +#, c-format +msgid "pack version %<PRIu32> unsupported" +msgstr "Paketversion %<PRIu32> nicht unterstützt" + +#: builtin/index-pack.c:312 #, c-format msgid "pack has bad object at offset %lu: %s" msgstr "Paket hat ein ungültiges Objekt bei Versatz %lu: %s" -#: builtin/index-pack.c:405 +#: builtin/index-pack.c:434 #, c-format msgid "inflate returned %d" msgstr "Dekomprimierung gab %d zurück" -#: builtin/index-pack.c:450 +#: builtin/index-pack.c:483 msgid "offset value overflow for delta base object" msgstr "Wert für Versatz bei Differenzobjekt übergelaufen" -#: builtin/index-pack.c:458 +#: builtin/index-pack.c:491 msgid "delta base offset is out of bound" msgstr "" "Wert für Versatz bei Differenzobjekt liegt außerhalb des gültigen Bereichs" -#: builtin/index-pack.c:466 +#: builtin/index-pack.c:499 #, c-format msgid "unknown object type %d" msgstr "Unbekannter Objekt-Typ %d" -#: builtin/index-pack.c:495 +#: builtin/index-pack.c:530 msgid "cannot pread pack file" msgstr "Kann Paketdatei %s nicht lesen" -#: builtin/index-pack.c:497 +#: builtin/index-pack.c:532 #, c-format msgid "premature end of pack file, %lu byte missing" msgid_plural "premature end of pack file, %lu bytes missing" msgstr[0] "frühzeitiges Ende der Paketdatei, vermisse %lu Byte" msgstr[1] "frühzeitiges Ende der Paketdatei, vermisse %lu Bytes" -#: builtin/index-pack.c:510 +#: builtin/index-pack.c:558 msgid "serious inflate inconsistency" msgstr "ernsthafte Inkonsistenz nach Dekomprimierung" -#: builtin/index-pack.c:583 -#, c-format -msgid "cannot read existing object %s" -msgstr "Kann existierendes Objekt %s nicht lesen." - -#: builtin/index-pack.c:586 +#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678 +#: builtin/index-pack.c:712 builtin/index-pack.c:721 #, c-format msgid "SHA1 COLLISION FOUND WITH %s !" msgstr "SHA1 KOLLISION MIT %s GEFUNDEN !" -#: builtin/index-pack.c:598 +#: builtin/index-pack.c:652 builtin/pack-objects.c:170 +#: builtin/pack-objects.c:262 +#, c-format +msgid "unable to read %s" +msgstr "kann %s nicht lesen" + +#: builtin/index-pack.c:718 +#, c-format +msgid "cannot read existing object %s" +msgstr "Kann existierendes Objekt %s nicht lesen." + +#: builtin/index-pack.c:732 #, c-format msgid "invalid blob object %s" msgstr "ungültiges Blob-Objekt %s" -#: builtin/index-pack.c:610 +#: builtin/index-pack.c:747 #, c-format msgid "invalid %s" msgstr "Ungültiger Objekt-Typ %s" -#: builtin/index-pack.c:612 +#: builtin/index-pack.c:749 msgid "Error in object" msgstr "Fehler in Objekt" -#: builtin/index-pack.c:614 +#: builtin/index-pack.c:751 #, c-format msgid "Not all child objects of %s are reachable" msgstr "Nicht alle Kind-Objekte von %s sind erreichbar" -#: builtin/index-pack.c:687 builtin/index-pack.c:713 +#: builtin/index-pack.c:821 builtin/index-pack.c:847 msgid "failed to apply delta" msgstr "Konnte Dateiunterschied nicht anwenden" -#: builtin/index-pack.c:850 +#: builtin/index-pack.c:986 msgid "Receiving objects" msgstr "Empfange Objekte" -#: builtin/index-pack.c:850 +#: builtin/index-pack.c:986 msgid "Indexing objects" msgstr "Indiziere Objekte" -#: builtin/index-pack.c:872 +#: builtin/index-pack.c:1012 msgid "pack is corrupted (SHA1 mismatch)" msgstr "Paket ist beschädigt (SHA1 unterschiedlich)" -#: builtin/index-pack.c:877 +#: builtin/index-pack.c:1017 msgid "cannot fstat packfile" msgstr "kann Paketdatei nicht lesen" -#: builtin/index-pack.c:880 +#: builtin/index-pack.c:1020 msgid "pack has junk at the end" msgstr "Paketende enthält nicht verwendbaren Inhalt" -#: builtin/index-pack.c:903 +#: builtin/index-pack.c:1031 +msgid "confusion beyond insanity in parse_pack_objects()" +msgstr "Fehler beim Ausführen von \"parse_pack_objects()\"" + +#: builtin/index-pack.c:1054 msgid "Resolving deltas" msgstr "Löse Unterschiede auf" -#: builtin/index-pack.c:954 +#: builtin/index-pack.c:1064 +#, c-format +msgid "unable to create thread: %s" +msgstr "kann Thread nicht erzeugen: %s" + +#: builtin/index-pack.c:1106 msgid "confusion beyond insanity" msgstr "Fehler beim Auflösen der Unterschiede" -#: builtin/index-pack.c:973 +#: builtin/index-pack.c:1112 +#, c-format +msgid "completed with %d local objects" +msgstr "vervollständigt mit %d lokalen Objekten" + +#: builtin/index-pack.c:1121 +#, c-format +msgid "Unexpected tail checksum for %s (disk corruption?)" +msgstr "Unerwartete Prüfsumme für %s (Festplattenfehler?)" + +#: builtin/index-pack.c:1125 #, c-format msgid "pack has %d unresolved delta" msgid_plural "pack has %d unresolved deltas" msgstr[0] "Paket hat %d unaufgelöste Unterschied" msgstr[1] "Paket hat %d unaufgelöste Unterschiede" -#: builtin/index-pack.c:998 +#: builtin/index-pack.c:1150 #, c-format msgid "unable to deflate appended object (%d)" msgstr "Konnte angehängtes Objekt (%d) nicht komprimieren" -#: builtin/index-pack.c:1077 +#: builtin/index-pack.c:1229 #, c-format msgid "local object %s is corrupt" msgstr "lokales Objekt %s ist beschädigt" -#: builtin/index-pack.c:1101 +#: builtin/index-pack.c:1253 msgid "error while closing pack file" msgstr "Fehler beim Schließen der Paketdatei" -#: builtin/index-pack.c:1114 +#: builtin/index-pack.c:1266 #, c-format msgid "cannot write keep file '%s'" msgstr "Kann Paketbeschreibungsdatei '%s' nicht schreiben" -#: builtin/index-pack.c:1122 +#: builtin/index-pack.c:1274 #, c-format msgid "cannot close written keep file '%s'" msgstr "Kann eben erstellte Paketbeschreibungsdatei '%s' nicht schließen" -#: builtin/index-pack.c:1135 +#: builtin/index-pack.c:1287 msgid "cannot store pack file" msgstr "Kann Paketdatei nicht speichern" -#: builtin/index-pack.c:1146 +#: builtin/index-pack.c:1298 msgid "cannot store index file" msgstr "Kann Indexdatei nicht speichern" -#: builtin/index-pack.c:1247 +#: builtin/index-pack.c:1331 +#, c-format +msgid "bad pack.indexversion=%<PRIu32>" +msgstr "\"pack.indexversion=%<PRIu32>\" ist ungültig" + +#: builtin/index-pack.c:1337 +#, c-format +msgid "invalid number of threads specified (%d)" +msgstr "ungültige Anzahl von Threads angegeben (%d)" + +#: builtin/index-pack.c:1341 builtin/index-pack.c:1514 +#, c-format +msgid "no threads support, ignoring %s" +msgstr "keine Unterstützung von Threads, '%s' wird ignoriert" + +#: builtin/index-pack.c:1399 #, c-format msgid "Cannot open existing pack file '%s'" msgstr "Kann existierende Paketdatei '%s' nicht öffnen" -#: builtin/index-pack.c:1249 +#: builtin/index-pack.c:1401 #, c-format msgid "Cannot open existing pack idx file for '%s'" msgstr "Kann existierende Indexdatei für Paket '%s' nicht öffnen" -#: builtin/index-pack.c:1296 +#: builtin/index-pack.c:1448 #, c-format msgid "non delta: %d object" msgid_plural "non delta: %d objects" msgstr[0] "kein Unterschied: %d Objekt" msgstr[1] "kein Unterschied: %d Objekte" -#: builtin/index-pack.c:1303 +#: builtin/index-pack.c:1455 #, c-format msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" msgstr[0] "Länge der Objekt-Liste = %d: %lu Objekt" msgstr[1] "Länge der Objekt-Liste = %d: %lu Objekte" -#: builtin/index-pack.c:1330 +#: builtin/index-pack.c:1482 msgid "Cannot come back to cwd" msgstr "Kann nicht zurück zu Arbeitsverzeichnis wechseln" -#: builtin/index-pack.c:1374 builtin/index-pack.c:1377 -#: builtin/index-pack.c:1389 builtin/index-pack.c:1393 +#: builtin/index-pack.c:1526 builtin/index-pack.c:1529 +#: builtin/index-pack.c:1541 builtin/index-pack.c:1545 #, c-format msgid "bad %s" msgstr "%s ist ungültig" -#: builtin/index-pack.c:1407 +#: builtin/index-pack.c:1559 msgid "--fix-thin cannot be used without --stdin" msgstr "--fix-thin kann nicht ohne --stdin benutzt werden" -#: builtin/index-pack.c:1411 builtin/index-pack.c:1421 +#: builtin/index-pack.c:1563 builtin/index-pack.c:1573 #, c-format msgid "packfile name '%s' does not end with '.pack'" msgstr "Name der Paketdatei '%s' endet nicht mit '.pack'" -#: builtin/index-pack.c:1430 +#: builtin/index-pack.c:1582 msgid "--verify with no packfile name given" msgstr "--verify ohne Name der Paketdatei angegeben" @@ -3257,63 +5304,84 @@ msgstr "kopiere keine Vorlagen mit einer falschen Formatversion %d von '%s'" msgid "insane git directory %s" msgstr "ungültiges Git-Verzeichnis %s" -#: builtin/init-db.c:322 builtin/init-db.c:325 +#: builtin/init-db.c:323 builtin/init-db.c:326 #, c-format msgid "%s already exists" msgstr "%s existiert bereits" -#: builtin/init-db.c:354 +#: builtin/init-db.c:355 #, c-format msgid "unable to handle file type %d" msgstr "kann nicht mit Dateityp %d umgehen" -#: builtin/init-db.c:357 +#: builtin/init-db.c:358 #, c-format msgid "unable to move %s to %s" msgstr "Konnte %s nicht nach %s verschieben" -#: builtin/init-db.c:362 +#: builtin/init-db.c:363 #, c-format msgid "Could not create git link %s" -msgstr "Konnte git-Verknüfung %s nicht erstellen" +msgstr "Konnte git-Verknüpfung %s nicht erstellen" #. #. * TRANSLATORS: The first '%s' is either "Reinitialized #. * existing" or "Initialized empty", the second " shared" or #. * "", and the last '%s%s' is the verbatim directory name. #. -#: builtin/init-db.c:419 +#: builtin/init-db.c:420 #, c-format msgid "%s%s Git repository in %s%s\n" msgstr "%s%s Git-Projektarchiv in %s%s\n" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Reinitialized existing" msgstr "Reinitialisierte existierendes" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Initialized empty" msgstr "Initialisierte leeres" -#: builtin/init-db.c:421 +#: builtin/init-db.c:422 msgid " shared" msgstr " gemeinsames" -#: builtin/init-db.c:440 +#: builtin/init-db.c:441 msgid "cannot tell cwd" msgstr "kann aktuelles Arbeitsverzeichnis nicht ermitteln" -#: builtin/init-db.c:521 builtin/init-db.c:528 +#: builtin/init-db.c:467 +msgid "" +"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared" +"[=<permissions>]] [directory]" +msgstr "" +"git init [-q | --quiet] [--bare] [--template=<Vorlagenverzeichnis>] [--shared" +"[=<Berechtigungen>]] [Verzeichnis]" + +#: builtin/init-db.c:490 +msgid "permissions" +msgstr "Berechtigungen" + +#: builtin/init-db.c:491 +msgid "specify that the git repository is to be shared amongst several users" +msgstr "" +"gibt an, dass das Git-Projektarchiv mit mehreren Benutzern geteilt wird" + +#: builtin/init-db.c:493 builtin/prune-packed.c:77 +msgid "be quiet" +msgstr "weniger Ausgaben" + +#: builtin/init-db.c:522 builtin/init-db.c:529 #, c-format msgid "cannot mkdir %s" msgstr "kann Verzeichnis %s nicht erstellen" -#: builtin/init-db.c:532 +#: builtin/init-db.c:533 #, c-format msgid "cannot chdir to %s" msgstr "kann nicht in Verzeichnis %s wechseln" -#: builtin/init-db.c:554 +#: builtin/init-db.c:555 #, c-format msgid "" "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" @@ -3322,103 +5390,248 @@ msgstr "" "%s (oder --work-tree=<Verzeichnis>) nicht erlaubt ohne Spezifizierung von %s " "(oder --git-dir=<Verzeichnis>)" -#: builtin/init-db.c:578 +#: builtin/init-db.c:579 msgid "Cannot access current working directory" msgstr "Kann nicht auf aktuelles Arbeitsverzeichnis zugreifen." -#: builtin/init-db.c:585 +#: builtin/init-db.c:586 #, c-format msgid "Cannot access work tree '%s'" msgstr "Kann nicht auf Arbeitsbaum '%s' zugreifen." -#: builtin/log.c:188 +#: builtin/log.c:37 +msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n" +msgstr "git log [<Optionen>] [<seit>..<bis>] [[--] <Pfad>...]\n" + +#: builtin/log.c:38 +msgid " or: git show [options] <object>..." +msgstr " oder: git show [Optionen] <Objekt>..." + +#: builtin/log.c:100 +msgid "suppress diff output" +msgstr "unterdrückt Ausgabe der Unterschiede" + +#: builtin/log.c:101 +msgid "show source" +msgstr "zeigt Quelle" + +#: builtin/log.c:102 +msgid "decorate options" +msgstr "decorate-Optionen" + +#: builtin/log.c:189 #, c-format msgid "Final output: %d %s\n" msgstr "letzte Ausgabe: %d %s\n" -#: builtin/log.c:401 builtin/log.c:489 +#: builtin/log.c:405 builtin/log.c:497 #, c-format msgid "Could not read object %s" msgstr "Kann Objekt %s nicht lesen." -#: builtin/log.c:513 +#: builtin/log.c:521 #, c-format msgid "Unknown type: %d" msgstr "Unbekannter Typ: %d" -#: builtin/log.c:602 +#: builtin/log.c:613 msgid "format.headers without value" msgstr "format.headers ohne Wert" -#: builtin/log.c:676 +#: builtin/log.c:687 msgid "name of output directory is too long" msgstr "Name des Ausgabeverzeichnisses ist zu lang." -#: builtin/log.c:687 +#: builtin/log.c:698 #, c-format msgid "Cannot open patch file %s" msgstr "Kann Patch-Datei %s nicht öffnen" -#: builtin/log.c:701 +#: builtin/log.c:712 msgid "Need exactly one range." msgstr "Brauche genau einen Versionsbereich." -#: builtin/log.c:709 +#: builtin/log.c:720 msgid "Not a range." msgstr "Kein Versionsbereich." -#: builtin/log.c:786 +#: builtin/log.c:794 msgid "Cover letter needs email format" msgstr "Anschreiben benötigt E-Mail-Format" -#: builtin/log.c:859 +#: builtin/log.c:867 #, c-format msgid "insane in-reply-to: %s" msgstr "ungültiges in-reply-to: %s" -#: builtin/log.c:932 +#: builtin/log.c:895 +msgid "git format-patch [options] [<since> | <revision range>]" +msgstr "git format-patch [Optionen] [<seit> | <Versionsbereich>]" + +#: builtin/log.c:940 msgid "Two output directories?" msgstr "Zwei Ausgabeverzeichnisse?" -#: builtin/log.c:1153 +#: builtin/log.c:1068 +msgid "use [PATCH n/m] even with a single patch" +msgstr "benutzt [PATCH n/m] auch mit einzelnem Patch" + +#: builtin/log.c:1071 +msgid "use [PATCH] even with multiple patches" +msgstr "benutzt [PATCH] auch mit mehreren Patches" + +#: builtin/log.c:1075 +msgid "print patches to standard out" +msgstr "Ausgabe der Patches in Standard-Ausgabe" + +#: builtin/log.c:1077 +msgid "generate a cover letter" +msgstr "erzeugt ein Deckblatt" + +#: builtin/log.c:1079 +msgid "use simple number sequence for output file names" +msgstr "benutzt einfache Nummernfolge für die Namen der Ausgabedateien" + +#: builtin/log.c:1080 +msgid "sfx" +msgstr "Dateiendung" + +#: builtin/log.c:1081 +msgid "use <sfx> instead of '.patch'" +msgstr "verwendet <Dateiendung> anstatt '.patch'" + +#: builtin/log.c:1083 +msgid "start numbering patches at <n> instead of 1" +msgstr "beginnt die Nummerierung der Patches bei <n> anstatt bei 1" + +#: builtin/log.c:1085 +msgid "Use [<prefix>] instead of [PATCH]" +msgstr "benutzt [<Prefix>] anstatt [PATCH]" + +#: builtin/log.c:1088 +msgid "store resulting files in <dir>" +msgstr "speichert erzeugte Dateien in <Verzeichnis>" + +#: builtin/log.c:1091 +msgid "don't strip/add [PATCH]" +msgstr "[PATCH] wird nicht entfernt/hinzugefügt" + +#: builtin/log.c:1094 +msgid "don't output binary diffs" +msgstr "gibt keine binären Unterschiede aus" + +#: builtin/log.c:1096 +msgid "don't include a patch matching a commit upstream" +msgstr "" +"schließt keine Patches ein, die einer Version im Übernahmezweig entsprechen" + +#: builtin/log.c:1098 +msgid "show patch format instead of default (patch + stat)" +msgstr "zeigt Patchformat anstatt des Standards (Patch + Zusammenfassung)" + +#: builtin/log.c:1100 +msgid "Messaging" +msgstr "Email-Einstellungen" + +#: builtin/log.c:1101 +msgid "header" +msgstr "Header" + +#: builtin/log.c:1102 +msgid "add email header" +msgstr "fügt Email-Header hinzu" + +#: builtin/log.c:1103 builtin/log.c:1105 +msgid "email" +msgstr "Email" + +#: builtin/log.c:1103 +msgid "add To: header" +msgstr "fügt \"To:\"-Header hinzu" + +#: builtin/log.c:1105 +msgid "add Cc: header" +msgstr "fügt \"Cc:\"-Header hinzu" + +#: builtin/log.c:1107 +msgid "message-id" +msgstr "message-id" + +#: builtin/log.c:1108 +msgid "make first mail a reply to <message-id>" +msgstr "macht aus erster Email eine Antwort zu <message-id>" + +#: builtin/log.c:1109 builtin/log.c:1112 +msgid "boundary" +msgstr "Grenze" + +#: builtin/log.c:1110 +msgid "attach the patch" +msgstr "hängt einen Patch an" + +#: builtin/log.c:1113 +msgid "inline the patch" +msgstr "fügt den Patch direkt in die Nachricht ein" + +#: builtin/log.c:1117 +msgid "enable message threading, styles: shallow, deep" +msgstr "aktiviert Nachrichtenverkettung, Stile: shallow, deep" + +#: builtin/log.c:1119 +msgid "signature" +msgstr "Signatur" + +#: builtin/log.c:1120 +msgid "add a signature" +msgstr "fügt eine Signatur hinzu" + +#: builtin/log.c:1122 +msgid "don't print the patch filenames" +msgstr "zeigt keine Dateinamen der Patches" + +#: builtin/log.c:1163 #, c-format msgid "bogus committer info %s" msgstr "unechte Einreicher-Informationen %s" -#: builtin/log.c:1198 +#: builtin/log.c:1208 msgid "-n and -k are mutually exclusive." -msgstr "-n und -k schliessen sich gegenseitig aus" +msgstr "-n und -k schließen sich gegenseitig aus" -#: builtin/log.c:1200 +#: builtin/log.c:1210 msgid "--subject-prefix and -k are mutually exclusive." -msgstr "--subject-prefix und -k schliessen sich gegenseitig aus" +msgstr "--subject-prefix und -k schließen sich gegenseitig aus" -#: builtin/log.c:1208 +#: builtin/log.c:1218 msgid "--name-only does not make sense" msgstr "--name-only macht keinen Sinn" -#: builtin/log.c:1210 +#: builtin/log.c:1220 msgid "--name-status does not make sense" msgstr "--name-status macht keinen Sinn" -#: builtin/log.c:1212 +#: builtin/log.c:1222 msgid "--check does not make sense" msgstr "--check macht keinen Sinn" -#: builtin/log.c:1235 +#: builtin/log.c:1245 msgid "standard output, or directory, which one?" msgstr "Standard-Ausgabe oder Verzeichnis, welches von beidem?" -#: builtin/log.c:1237 +#: builtin/log.c:1247 #, c-format msgid "Could not create directory '%s'" msgstr "Konnte Verzeichnis '%s' nicht erstellen." -#: builtin/log.c:1390 +#: builtin/log.c:1400 msgid "Failed to create output files" msgstr "Fehler beim Erstellen der Ausgabedateien." -#: builtin/log.c:1494 +#: builtin/log.c:1449 +msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]" +msgstr "git cherry [-v] [<Übernahmezweig> [<Arbeitszweig> [<Limit>]]]" + +#: builtin/log.c:1504 #, c-format msgid "" "Could not find a tracked remote branch, please specify <upstream> manually.\n" @@ -3426,11 +5639,157 @@ msgstr "" "Konnte gefolgten, externen Zweig nicht finden, bitte gebe <upstream> manuell " "an.\n" -#: builtin/log.c:1510 builtin/log.c:1512 builtin/log.c:1524 +#: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531 #, c-format msgid "Unknown commit %s" msgstr "Unbekannte Version %s" +#: builtin/ls-files.c:408 +msgid "git ls-files [options] [<file>...]" +msgstr "git ls-files [Optionen] [<Datei>...]" + +#: builtin/ls-files.c:463 +msgid "identify the file status with tags" +msgstr "zeigt den Dateistatus mit Markierungen" + +#: builtin/ls-files.c:465 +msgid "use lowercase letters for 'assume unchanged' files" +msgstr "benutzt Kleinbuchstaben für Dateien mit 'assume unchanged' Markierung" + +#: builtin/ls-files.c:467 +msgid "show cached files in the output (default)" +msgstr "zeigt zwischengespeicherten Dateien in der Ausgabe an (Standard)" + +#: builtin/ls-files.c:469 +msgid "show deleted files in the output" +msgstr "zeigt entfernte Dateien in der Ausgabe an" + +#: builtin/ls-files.c:471 +msgid "show modified files in the output" +msgstr "zeigt geänderte Dateien in der Ausgabe an" + +#: builtin/ls-files.c:473 +msgid "show other files in the output" +msgstr "zeigt sonstige Dateien in der Ausgabe an" + +#: builtin/ls-files.c:475 +msgid "show ignored files in the output" +msgstr "zeigt ignorierte Dateien in der Ausgabe an" + +#: builtin/ls-files.c:478 +msgid "show staged contents' object name in the output" +msgstr "zeigt Objektnamen von Inhalten in der Bereitstellung in der Ausgabe an" + +#: builtin/ls-files.c:480 +msgid "show files on the filesystem that need to be removed" +msgstr "zeigt Dateien im Dateisystem, die gelöscht werden müssen, an" + +#: builtin/ls-files.c:482 +msgid "show 'other' directories' name only" +msgstr "zeigt nur Namen von 'sonstigen' Verzeichnissen an" + +#: builtin/ls-files.c:485 +msgid "don't show empty directories" +msgstr "zeigt keine leeren Verzeichnisse an" + +#: builtin/ls-files.c:488 +msgid "show unmerged files in the output" +msgstr "zeigt nicht zusammengeführte Dateien in der Ausgabe an" + +#: builtin/ls-files.c:490 +msgid "show resolve-undo information" +msgstr "zeigt 'resolve-undo' Informationen an" + +#: builtin/ls-files.c:492 +msgid "skip files matching pattern" +msgstr "lässt Dateien aus, die einem Muster entsprechen" + +#: builtin/ls-files.c:495 +msgid "exclude patterns are read from <file>" +msgstr "schließt Muster, gelesen von <Datei>, aus" + +#: builtin/ls-files.c:498 +msgid "read additional per-directory exclude patterns in <file>" +msgstr "liest zusätzliche pro-Verzeichnis Auschlussmuster aus <Datei>" + +#: builtin/ls-files.c:500 +msgid "add the standard git exclusions" +msgstr "fügt die standardmäßigen Git-Ausschlüsse hinzu" + +#: builtin/ls-files.c:503 +msgid "make the output relative to the project top directory" +msgstr "Ausgabe relativ zum Projektverzeichnis" + +#: builtin/ls-files.c:506 +msgid "if any <file> is not in the index, treat this as an error" +msgstr "" +"behandle es als Fehler, wenn sich eine <Datei> nicht in der Bereitstellung " +"befindet" + +#: builtin/ls-files.c:507 +msgid "tree-ish" +msgstr "Versionsreferenz" + +#: builtin/ls-files.c:508 +msgid "pretend that paths removed since <tree-ish> are still present" +msgstr "" +"gibt vor, dass Pfade, die seit <Versionsreferenz> gelöscht wurden, immer " +"noch vorhanden sind" + +#: builtin/ls-files.c:510 +msgid "show debugging data" +msgstr "zeigt Ausgaben zur Fehlersuche an" + +#: builtin/ls-tree.c:27 +msgid "git ls-tree [<options>] <tree-ish> [<path>...]" +msgstr "git ls-tree [<Optionen>] <Versionsreferenz> [<Pfad>...]" + +#: builtin/ls-tree.c:125 +msgid "only show trees" +msgstr "zeigt nur Bäume an" + +#: builtin/ls-tree.c:127 +msgid "recurse into subtrees" +msgstr "führt Rekursion in Teilbäumen durch" + +#: builtin/ls-tree.c:129 +msgid "show trees when recursing" +msgstr "zeigt Bäume bei Rekursion an" + +#: builtin/ls-tree.c:132 +msgid "terminate entries with NUL byte" +msgstr "schließt Einträge mit NUL-Byte ab" + +#: builtin/ls-tree.c:133 +msgid "include object size" +msgstr "schließt Objektgröße ein" + +#: builtin/ls-tree.c:135 builtin/ls-tree.c:137 +msgid "list only filenames" +msgstr "listet nur Dateinamen auf" + +#: builtin/ls-tree.c:140 +msgid "use full path names" +msgstr "benutzt vollständige Pfadnamen" + +#: builtin/ls-tree.c:142 +msgid "list entire tree; not just current directory (implies --full-name)" +msgstr "" +"listet den gesamten Baum auf; nicht nur das aktuelle Verzeichnis (impliziert " +"--full-name)" + +#: builtin/merge.c:43 +msgid "git merge [options] [<commit>...]" +msgstr "git merge [Optionen] [<Version>...]" + +#: builtin/merge.c:44 +msgid "git merge [options] <msg> HEAD <commit>" +msgstr "git merge [Optionen] <Beschreibung> HEAD <Version>" + +#: builtin/merge.c:45 +msgid "git merge --abort" +msgstr "git merge --abort" + #: builtin/merge.c:90 msgid "switch `m' requires a value" msgstr "Schalter 'm' erfordert einen Wert." @@ -3450,6 +5809,75 @@ msgstr "Verfügbare Strategien sind:" msgid "Available custom strategies are:" msgstr "Verfügbare benutzerdefinierte Strategien sind:" +#: builtin/merge.c:183 +msgid "do not show a diffstat at the end of the merge" +msgstr "" +"zeigt keine Zusammenfassung der Unterschiede am Schluss der Zusammenführung " +"an" + +#: builtin/merge.c:186 +msgid "show a diffstat at the end of the merge" +msgstr "" +"zeigt eine Zusammenfassung der Unterschiede am Schluss der Zusammenführung an" + +#: builtin/merge.c:187 +msgid "(synonym to --stat)" +msgstr "(Synonym für --stat)" + +#: builtin/merge.c:189 +msgid "add (at most <n>) entries from shortlog to merge commit message" +msgstr "" +"fügt (höchstens <n>) Einträge von \"shortlog\" zur Beschreibung der " +"Zusammenführung hinzu" + +#: builtin/merge.c:192 +msgid "create a single commit instead of doing a merge" +msgstr "erzeugt eine einzelne Version anstatt einer Zusammenführung" + +#: builtin/merge.c:194 +msgid "perform a commit if the merge succeeds (default)" +msgstr "" +"führt eine Eintragung durch, wenn die Zusammenführung erfolgreich war " +"(Standard)" + +#: builtin/merge.c:196 +msgid "edit message before committing" +msgstr "Bearbeitung der Versionsbeschreibung vor der Eintragung" + +#: builtin/merge.c:198 +msgid "allow fast-forward (default)" +msgstr "erlaubt Vorspulen (Standard)" + +#: builtin/merge.c:200 +msgid "abort if fast-forward is not possible" +msgstr "bricht ab, wenn kein Vorspulen möglich ist" + +#: builtin/merge.c:202 builtin/notes.c:870 builtin/revert.c:112 +msgid "strategy" +msgstr "Strategie" + +#: builtin/merge.c:203 +msgid "merge strategy to use" +msgstr "zu verwendende Zusammenführungsstrategie" + +#: builtin/merge.c:204 +msgid "option=value" +msgstr "Option=Wert" + +#: builtin/merge.c:205 +msgid "option for selected merge strategy" +msgstr "Option für ausgewählte Zusammenführungsstrategie" + +#: builtin/merge.c:207 +msgid "merge commit message (for a non-fast-forward merge)" +msgstr "" +"führt Versionsbeschreibung zusammen (für eine Zusammenführung, die kein " +"Vorspulen war)" + +#: builtin/merge.c:211 +msgid "abort the current in-progress merge" +msgstr "bricht die sich im Gange befindliche Zusammenführung ab" + #: builtin/merge.c:240 msgid "could not run stash." msgstr "Konnte \"stash\" nicht ausführen." @@ -3491,55 +5919,47 @@ msgstr "" "Keine Zusammenführungsbeschreibung -- Zweigspitze (HEAD) wird nicht " "aktualisiert\n" -#: builtin/merge.c:437 +#: builtin/merge.c:436 #, c-format msgid "'%s' does not point to a commit" msgstr "'%s' zeigt auf keine Version" -#: builtin/merge.c:536 +#: builtin/merge.c:535 #, c-format msgid "Bad branch.%s.mergeoptions string: %s" msgstr "Ungültiger branch.%s.mergeoptions String: %s" -#: builtin/merge.c:629 +#: builtin/merge.c:628 msgid "git write-tree failed to write a tree" msgstr "\"git write-tree\" schlug beim Schreiben eines Baumes fehl" -#: builtin/merge.c:679 -msgid "failed to read the cache" -msgstr "Lesen des Zwischenspeichers fehlgeschlagen" - -#: builtin/merge.c:697 -msgid "Unable to write index." -msgstr "Konnte Bereitstellung nicht schreiben." - -#: builtin/merge.c:710 +#: builtin/merge.c:656 msgid "Not handling anything other than two heads merge." msgstr "Es wird nur die Zusammenführung von zwei Zweigen behandelt." -#: builtin/merge.c:724 +#: builtin/merge.c:670 #, c-format msgid "Unknown option for merge-recursive: -X%s" msgstr "Unbekannte Option für merge-recursive: -X%s" -#: builtin/merge.c:738 +#: builtin/merge.c:684 #, c-format msgid "unable to write %s" msgstr "konnte %s nicht schreiben" -#: builtin/merge.c:877 +#: builtin/merge.c:773 #, c-format msgid "Could not read from '%s'" msgstr "konnte nicht von '%s' lesen" -#: builtin/merge.c:886 +#: builtin/merge.c:782 #, c-format msgid "Not committing merge; use 'git commit' to complete the merge.\n" msgstr "" "Zusammenführung wurde nicht eingetragen; benutze 'git commit' um die " "Zusammenführung abzuschließen.\n" -#: builtin/merge.c:892 +#: builtin/merge.c:788 msgid "" "Please enter a commit message to explain why this merge is necessary,\n" "especially if it merges an updated upstream into a topic branch.\n" @@ -3555,56 +5975,56 @@ msgstr "" "Zeilen beginnend mit '#' werden ignoriert, und eine leere Beschreibung " "bricht die Eintragung ab.\n" -#: builtin/merge.c:916 +#: builtin/merge.c:812 msgid "Empty commit message." msgstr "Leere Versionsbeschreibung" -#: builtin/merge.c:928 +#: builtin/merge.c:824 #, c-format msgid "Wonderful.\n" msgstr "Wunderbar.\n" -#: builtin/merge.c:993 +#: builtin/merge.c:889 #, c-format msgid "Automatic merge failed; fix conflicts and then commit the result.\n" msgstr "" "Automatische Zusammenführung fehlgeschlagen; behebe die Konflikte und trage " "dann das Ergebnis ein.\n" -#: builtin/merge.c:1009 +#: builtin/merge.c:905 #, c-format msgid "'%s' is not a commit" msgstr "'%s' ist keine Version" -#: builtin/merge.c:1050 +#: builtin/merge.c:946 msgid "No current branch." msgstr "Du befindest dich auf keinem Zweig." -#: builtin/merge.c:1052 +#: builtin/merge.c:948 msgid "No remote for the current branch." msgstr "Kein externes Archiv für den aktuellen Zweig." -#: builtin/merge.c:1054 +#: builtin/merge.c:950 msgid "No default upstream defined for the current branch." msgstr "" "Es ist kein externes Standard-Projektarchiv für den aktuellen Zweig " "definiert." -#: builtin/merge.c:1059 +#: builtin/merge.c:955 #, c-format msgid "No remote tracking branch for %s from %s" msgstr "Kein externer Übernahmezweig für %s von %s" -#: builtin/merge.c:1146 builtin/merge.c:1303 +#: builtin/merge.c:1042 builtin/merge.c:1199 #, c-format msgid "%s - not something we can merge" msgstr "%s - nichts was wir zusammenführen können" -#: builtin/merge.c:1214 +#: builtin/merge.c:1110 msgid "There is no merge to abort (MERGE_HEAD missing)." msgstr "Es gibt keine Zusammenführung zum Abbrechen (vermisse MERGE_HEAD)" -#: builtin/merge.c:1230 git-pull.sh:31 +#: builtin/merge.c:1126 git-pull.sh:31 msgid "" "You have not concluded your merge (MERGE_HEAD exists).\n" "Please, commit your changes before you can merge." @@ -3612,12 +6032,12 @@ msgstr "" "Du hast deine Zusammenführung nicht abgeschlossen (MERGE_HEAD existiert).\n" "Bitte trage deine Änderungen ein, bevor du zusammenführen kannst." -#: builtin/merge.c:1233 git-pull.sh:34 +#: builtin/merge.c:1129 git-pull.sh:34 msgid "You have not concluded your merge (MERGE_HEAD exists)." msgstr "" "Du hast deine Zusammenführung nicht abgeschlossen (MERGE_HEAD existiert)." -#: builtin/merge.c:1237 +#: builtin/merge.c:1133 msgid "" "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" "Please, commit your changes before you can merge." @@ -3625,86 +6045,186 @@ msgstr "" "Du hast \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert).\n" "Bitte trage deine Änderungen ein, bevor du zusammenführen kannst." -#: builtin/merge.c:1240 +#: builtin/merge.c:1136 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)." msgstr "" "Du hast \"cherry-pick\" nicht abgeschlossen (CHERRY_PICK_HEAD existiert)." -#: builtin/merge.c:1249 +#: builtin/merge.c:1145 msgid "You cannot combine --squash with --no-ff." msgstr "Du kannst --squash nicht mit --no-ff kombinieren." -#: builtin/merge.c:1254 +#: builtin/merge.c:1150 msgid "You cannot combine --no-ff with --ff-only." msgstr "Du kannst --no-ff nicht mit --ff--only kombinieren." -#: builtin/merge.c:1261 +#: builtin/merge.c:1157 msgid "No commit specified and merge.defaultToUpstream not set." msgstr "Keine Version angegeben und merge.defaultToUpstream ist nicht gesetzt." -#: builtin/merge.c:1293 +#: builtin/merge.c:1189 msgid "Can merge only exactly one commit into empty head" msgstr "Kann nur exakt eine Version in einem leeren Zweig zusammenführen." -#: builtin/merge.c:1296 +#: builtin/merge.c:1192 msgid "Squash commit into empty head not supported yet" msgstr "Bin auf einem Zweig, der noch geboren wird; kann nicht quetschen." -#: builtin/merge.c:1298 +#: builtin/merge.c:1194 msgid "Non-fast-forward commit does not make sense into an empty head" msgstr "nicht vorzuspulende Version macht in einem leeren Zweig keinen Sinn" -#: builtin/merge.c:1413 +#: builtin/merge.c:1309 #, c-format msgid "Updating %s..%s\n" msgstr "Aktualisiere %s..%s\n" -#: builtin/merge.c:1451 +#: builtin/merge.c:1348 #, c-format msgid "Trying really trivial in-index merge...\n" msgstr "Probiere wirklich triviale \"in-index\"-Zusammenführung...\n" -#: builtin/merge.c:1458 +#: builtin/merge.c:1355 #, c-format msgid "Nope.\n" msgstr "Nein.\n" -#: builtin/merge.c:1490 +#: builtin/merge.c:1387 msgid "Not possible to fast-forward, aborting." msgstr "Vorspulen nicht möglich, breche ab." -#: builtin/merge.c:1513 builtin/merge.c:1592 +#: builtin/merge.c:1410 builtin/merge.c:1489 #, c-format msgid "Rewinding the tree to pristine...\n" msgstr "Rücklauf des Zweiges bis zum Ursprung...\n" -#: builtin/merge.c:1517 +#: builtin/merge.c:1414 #, c-format msgid "Trying merge strategy %s...\n" msgstr "Probiere Zusammenführungsstrategie %s...\n" -#: builtin/merge.c:1583 +#: builtin/merge.c:1480 #, c-format msgid "No merge strategy handled the merge.\n" msgstr "Keine Zusammenführungsstrategie behandelt diese Zusammenführung.\n" -#: builtin/merge.c:1585 +#: builtin/merge.c:1482 #, c-format msgid "Merge with strategy %s failed.\n" msgstr "Zusammenführung mit Strategie %s fehlgeschlagen.\n" -#: builtin/merge.c:1594 +#: builtin/merge.c:1491 #, c-format msgid "Using the %s to prepare resolving by hand.\n" msgstr "Benutze \"%s\" um die Auflösung per Hand vorzubereiten.\n" -#: builtin/merge.c:1606 +#: builtin/merge.c:1503 #, c-format msgid "Automatic merge went well; stopped before committing as requested\n" msgstr "" "Automatische Zusammenführung abgeschlossen; halte, wie gewünscht, vor der " "Eintragung an\n" +#: builtin/merge-base.c:26 +msgid "git merge-base [-a|--all] <commit> <commit>..." +msgstr "git merge-base [-a|--all] <Version> <Version>..." + +#: builtin/merge-base.c:27 +msgid "git merge-base [-a|--all] --octopus <commit>..." +msgstr "git merge-base [-a|--all] --octopus <Version>..." + +#: builtin/merge-base.c:28 +msgid "git merge-base --independent <commit>..." +msgstr "git merge-base --independent <Version>..." + +#: builtin/merge-base.c:29 +msgid "git merge-base --is-ancestor <commit> <commit>" +msgstr "git merge-base --is-ancestor <Version> <Version>" + +#: builtin/merge-base.c:98 +msgid "output all common ancestors" +msgstr "Ausgabe aller gemeinsamen Vorfahren" + +#: builtin/merge-base.c:99 +msgid "find ancestors for a single n-way merge" +msgstr "findet Vorfahren für eine einzelne n-Wege-Zusammenführung" + +#: builtin/merge-base.c:100 +msgid "list revs not reachable from others" +msgstr "listet Revisionen auf, die nicht durch Andere erreichbar sind" + +#: builtin/merge-base.c:102 +msgid "is the first one ancestor of the other?" +msgstr "ist der Erste ein Vorfahre von dem Anderen?" + +#: builtin/merge-file.c:8 +msgid "" +"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file " +"file2" +msgstr "" +"git merge-file [Optionen] [-L Name1 [-L orig [-L Name2]]] Datei1 orig_Datei " +"Datei2" + +#: builtin/merge-file.c:33 +msgid "send results to standard output" +msgstr "sendet Ergebnisse zur Standard-Ausgabe" + +#: builtin/merge-file.c:34 +msgid "use a diff3 based merge" +msgstr "benutzt eine diff3 basierte Zusammenführung" + +#: builtin/merge-file.c:35 +msgid "for conflicts, use our version" +msgstr "verwendet bei Konflikten unsere Variante" + +#: builtin/merge-file.c:37 +msgid "for conflicts, use their version" +msgstr "verwendet bei Konflikten ihre Variante" + +#: builtin/merge-file.c:39 +msgid "for conflicts, use a union version" +msgstr "verwendet bei Konflikten eine gemeinsame Variante" + +#: builtin/merge-file.c:42 +msgid "for conflicts, use this marker size" +msgstr "verwendet bei Konflikten diese Kennzeichnungslänge" + +#: builtin/merge-file.c:43 +msgid "do not warn about conflicts" +msgstr "keine Warnung bei Konflikten" + +#: builtin/merge-file.c:45 +msgid "set labels for file1/orig_file/file2" +msgstr "setzt Beschriftung für Datei1/orig_Datei/Datei2" + +#: builtin/mktree.c:67 +msgid "git mktree [-z] [--missing] [--batch]" +msgstr "git mktree [-z] [--missing] [--batch]" + +#: builtin/mktree.c:153 +msgid "input is NUL terminated" +msgstr "Eingabe ist durch NUL-Zeichen abgeschlossen" + +#: builtin/mktree.c:154 builtin/write-tree.c:24 +msgid "allow missing objects" +msgstr "erlaubt fehlende Objekte" + +#: builtin/mktree.c:155 +msgid "allow creation of more than one tree" +msgstr "erlaubt die Erstellung von mehr als einem Baum" + +#: builtin/mv.c:14 +msgid "git mv [options] <source>... <destination>" +msgstr "git mv [Optionen] <Quelle>... <Ziel>" + +#: builtin/mv.c:64 +msgid "force move/rename even if target exists" +msgstr "erzwingt Verschieben/Umbenennen, auch wenn das Ziel existiert" + +#: builtin/mv.c:65 +msgid "skip move/rename errors" +msgstr "überspringt Fehler beim Verschieben oder Umbenennen" + #: builtin/mv.c:108 #, c-format msgid "Checking rename of '%s' to '%s'\n" @@ -3767,115 +6287,288 @@ msgstr "Benenne %s nach %s um\n" msgid "renaming '%s' failed" msgstr "Umbenennung von '%s' fehlgeschlagen" -#: builtin/notes.c:139 +#: builtin/name-rev.c:175 +msgid "git name-rev [options] <commit>..." +msgstr "git name-rev [Optionen] <Version>..." + +#: builtin/name-rev.c:176 +msgid "git name-rev [options] --all" +msgstr "git name-rev [Optionen] --all" + +#: builtin/name-rev.c:177 +msgid "git name-rev [options] --stdin" +msgstr "git name-rev [Optionen] --stdin" + +#: builtin/name-rev.c:229 +msgid "print only names (no SHA-1)" +msgstr "zeigt nur Namen an (keine SHA-1)" + +#: builtin/name-rev.c:230 +msgid "only use tags to name the commits" +msgstr "benutzt nur Markierungen um die Versionen zu benennen" + +#: builtin/name-rev.c:232 +msgid "only use refs matching <pattern>" +msgstr "benutzt nur Referenzen die <Muster> entsprechen" + +#: builtin/name-rev.c:234 +msgid "list all commits reachable from all refs" +msgstr "listet alle Versionen auf, die von allen Referenzen erreichbar sind" + +#: builtin/name-rev.c:235 +msgid "read from stdin" +msgstr "liest von der Standard-Eingabe" + +#: builtin/name-rev.c:236 +msgid "allow to print `undefined` names" +msgstr "erlaubt Ausgabe von `undefinierten` Namen" + +#: builtin/notes.c:26 +msgid "git notes [--ref <notes_ref>] [list [<object>]]" +msgstr "git notes [--ref <Notiz-Referenz>] [list [<Objekt>]]" + +#: builtin/notes.c:27 +msgid "" +"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) " +"<object>] [<object>]" +msgstr "" +"git notes [--ref <Notiz-Referenz>] add [-f] [-m <Nachricht> | -F <Datei> | (-" +"c | -C) <Objekt>] [<Objekt>]" + +#: builtin/notes.c:28 +msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>" +msgstr "" +"git notes [--ref <Notiz-Referenz>] copy [-f] <von-Objekt> <nach-Objekt>" + +#: builtin/notes.c:29 +msgid "" +"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) " +"<object>] [<object>]" +msgstr "" +"git notes [--ref <Notiz-Referenz>] append [-m <Nachricht> | -F <Datei> | (-c " +"| -C) <Objekt>] [<Objekt>]" + +#: builtin/notes.c:30 +msgid "git notes [--ref <notes_ref>] edit [<object>]" +msgstr "git notes [--ref <Notiz-Referenz>] edit [<Objekt>]" + +#: builtin/notes.c:31 +msgid "git notes [--ref <notes_ref>] show [<object>]" +msgstr "git notes [--ref <Notiz-Referenz>] show [<Objekt>]" + +#: builtin/notes.c:32 +msgid "" +"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>" +msgstr "" +"git notes [--ref <Notiz-Referenz>] merge [-v | -q] [-s <Strategie> ] <Notiz-" +"Referenz>" + +#: builtin/notes.c:33 +msgid "git notes merge --commit [-v | -q]" +msgstr "git notes merge --commit [-v | -q]" + +#: builtin/notes.c:34 +msgid "git notes merge --abort [-v | -q]" +msgstr "git notes merge --abort [-v | -q]" + +#: builtin/notes.c:35 +msgid "git notes [--ref <notes_ref>] remove [<object>...]" +msgstr "git notes [--ref <Notiz-Referenz>] remove [<Objekt>...]" + +#: builtin/notes.c:36 +msgid "git notes [--ref <notes_ref>] prune [-n | -v]" +msgstr "git notes [--ref <Notiz-Referenz>] prune [-n | -v]" + +#: builtin/notes.c:37 +msgid "git notes [--ref <notes_ref>] get-ref" +msgstr "git notes [--ref <Notiz-Referenz>] get-ref" + +#: builtin/notes.c:42 +msgid "git notes [list [<object>]]" +msgstr "git notes [list [<Objekt>]]" + +#: builtin/notes.c:47 +msgid "git notes add [<options>] [<object>]" +msgstr "git notes add [<Optionen>] [<Objekt>]" + +#: builtin/notes.c:52 +msgid "git notes copy [<options>] <from-object> <to-object>" +msgstr "git notes copy [<Optionen>] <von-Objekt> <nach-Objekt>" + +#: builtin/notes.c:53 +msgid "git notes copy --stdin [<from-object> <to-object>]..." +msgstr "git notes copy --stdin [<von-Objekt> <nach-Objekt>]..." + +#: builtin/notes.c:58 +msgid "git notes append [<options>] [<object>]" +msgstr "git notes append [<Optionen>] [<Objekt>]" + +#: builtin/notes.c:63 +msgid "git notes edit [<object>]" +msgstr "git notes edit [<Objekt>]" + +#: builtin/notes.c:68 +msgid "git notes show [<object>]" +msgstr "git notes show [<Objekt>]" + +#: builtin/notes.c:73 +msgid "git notes merge [<options>] <notes_ref>" +msgstr "git notes merge [<Optionen>] <Notiz-Referenz>" + +#: builtin/notes.c:74 +msgid "git notes merge --commit [<options>]" +msgstr "git notes merge --commit [<Optionen>]" + +#: builtin/notes.c:75 +msgid "git notes merge --abort [<options>]" +msgstr "git notes merge --abort [<Optionen>]" + +#: builtin/notes.c:80 +msgid "git notes remove [<object>]" +msgstr "git notes remove [<Objekt>]" + +#: builtin/notes.c:85 +msgid "git notes prune [<options>]" +msgstr "git notes prune [<Optionen>]" + +#: builtin/notes.c:90 +msgid "git notes get-ref" +msgstr "git notes get-ref" + +#: builtin/notes.c:142 #, c-format msgid "unable to start 'show' for object '%s'" msgstr "konnte 'show' für Objekt '%s' nicht starten" -#: builtin/notes.c:145 +#: builtin/notes.c:148 msgid "can't fdopen 'show' output fd" msgstr "konnte Datei-Deskriptor für Ausgabe von 'show' nicht öffnen" -#: builtin/notes.c:155 +#: builtin/notes.c:158 #, c-format msgid "failed to close pipe to 'show' for object '%s'" msgstr "Schließen der Verbindung zu 'show' ist für Objekt '%s' fehlgeschlagen." -#: builtin/notes.c:158 +#: builtin/notes.c:161 #, c-format msgid "failed to finish 'show' for object '%s'" msgstr "konnte 'show' für Objekt '%s' nicht abschließen" -#: builtin/notes.c:175 builtin/tag.c:347 +#: builtin/notes.c:178 builtin/tag.c:347 #, c-format msgid "could not create file '%s'" msgstr "konnte Datei '%s' nicht erstellen" -#: builtin/notes.c:189 +#: builtin/notes.c:192 msgid "Please supply the note contents using either -m or -F option" msgstr "Bitte liefere den Notiz-Inhalt unter Verwendung der Option -m oder -F." -#: builtin/notes.c:210 builtin/notes.c:973 +#: builtin/notes.c:213 builtin/notes.c:976 #, c-format msgid "Removing note for object %s\n" msgstr "Entferne Notiz für Objekt %s\n" -#: builtin/notes.c:215 +#: builtin/notes.c:218 msgid "unable to write note object" msgstr "Konnte Notiz-Objekt nicht schreiben" -#: builtin/notes.c:217 +#: builtin/notes.c:220 #, c-format msgid "The note contents has been left in %s" msgstr "Die Notiz-Inhalte wurden in %s belassen" -#: builtin/notes.c:251 builtin/tag.c:542 +#: builtin/notes.c:254 builtin/tag.c:542 #, c-format msgid "cannot read '%s'" msgstr "kann '%s' nicht lesen" -#: builtin/notes.c:253 builtin/tag.c:545 +#: builtin/notes.c:256 builtin/tag.c:545 #, c-format msgid "could not open or read '%s'" msgstr "konnte '%s' nicht öffnen oder lesen" -#: builtin/notes.c:272 builtin/notes.c:445 builtin/notes.c:447 -#: builtin/notes.c:507 builtin/notes.c:561 builtin/notes.c:644 -#: builtin/notes.c:649 builtin/notes.c:724 builtin/notes.c:766 -#: builtin/notes.c:968 builtin/reset.c:293 builtin/tag.c:558 +#: builtin/notes.c:275 builtin/notes.c:448 builtin/notes.c:450 +#: builtin/notes.c:510 builtin/notes.c:564 builtin/notes.c:647 +#: builtin/notes.c:652 builtin/notes.c:727 builtin/notes.c:769 +#: builtin/notes.c:971 builtin/reset.c:293 builtin/tag.c:558 #, c-format msgid "Failed to resolve '%s' as a valid ref." msgstr "Konnte '%s' nicht als gültige Referenz auflösen." -#: builtin/notes.c:275 +#: builtin/notes.c:278 #, c-format msgid "Failed to read object '%s'." msgstr "Fehler beim Lesen des Objektes '%s'." -#: builtin/notes.c:299 +#: builtin/notes.c:302 msgid "Cannot commit uninitialized/unreferenced notes tree" msgstr "Kann uninitialisierten/unreferenzierten Notiz-Baum nicht eintragen." -#: builtin/notes.c:340 +#: builtin/notes.c:343 #, c-format msgid "Bad notes.rewriteMode value: '%s'" msgstr "Ungültiger notes.rewriteMode Wert: '%s'" -#: builtin/notes.c:350 +#: builtin/notes.c:353 #, c-format msgid "Refusing to rewrite notes in %s (outside of refs/notes/)" msgstr "" -"Neuschreiben der Notizen in %s zurückgewiesen (außerhalb von refs/notes/)" +"Umschreiben der Notizen in %s zurückgewiesen (außerhalb von refs/notes/)" #. TRANSLATORS: The first %s is the name of the #. environment variable, the second %s is its value -#: builtin/notes.c:377 +#: builtin/notes.c:380 #, c-format msgid "Bad %s value: '%s'" msgstr "Ungültiger %s Wert: '%s'" -#: builtin/notes.c:441 +#: builtin/notes.c:444 #, c-format msgid "Malformed input line: '%s'." msgstr "Fehlerhafte Eingabezeile: '%s'." -#: builtin/notes.c:456 +#: builtin/notes.c:459 #, c-format msgid "Failed to copy notes from '%s' to '%s'" msgstr "Fehler beim Kopieren der Notizen von '%s' nach '%s'" -#: builtin/notes.c:500 builtin/notes.c:554 builtin/notes.c:627 -#: builtin/notes.c:639 builtin/notes.c:712 builtin/notes.c:759 -#: builtin/notes.c:1033 +#: builtin/notes.c:503 builtin/notes.c:557 builtin/notes.c:630 +#: builtin/notes.c:642 builtin/notes.c:715 builtin/notes.c:762 +#: builtin/notes.c:1036 msgid "too many parameters" msgstr "zu viele Parameter" -#: builtin/notes.c:513 builtin/notes.c:772 +#: builtin/notes.c:516 builtin/notes.c:775 #, c-format msgid "No note found for object %s." msgstr "Kein Notiz für Objekt %s gefunden." -#: builtin/notes.c:580 +#: builtin/notes.c:538 builtin/notes.c:695 +msgid "note contents as a string" +msgstr "Notizinhalte als Zeichenkette" + +#: builtin/notes.c:541 builtin/notes.c:698 +msgid "note contents in a file" +msgstr "Notizinhalte in einer Datei" + +#: builtin/notes.c:543 builtin/notes.c:546 builtin/notes.c:700 +#: builtin/notes.c:703 builtin/tag.c:476 +msgid "object" +msgstr "Objekt" + +#: builtin/notes.c:544 builtin/notes.c:701 +msgid "reuse and edit specified note object" +msgstr "Wiederverwendung und Bearbeitung des angegebenen Notiz-Objektes" + +#: builtin/notes.c:547 builtin/notes.c:704 +msgid "reuse specified note object" +msgstr "Wiederverwendung des angegebenen Notiz-Objektes" + +#: builtin/notes.c:549 builtin/notes.c:617 +msgid "replace existing notes" +msgstr "ersetzt existierende Notizen" + +#: builtin/notes.c:583 #, c-format msgid "" "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite " @@ -3884,16 +6577,26 @@ msgstr "" "Konnte Notizen nicht hinzufügen. Existierende Notizen für Objekt %s " "gefunden. Verwende '-f' um die existierenden Notizen zu überschreiben." -#: builtin/notes.c:585 builtin/notes.c:662 +#: builtin/notes.c:588 builtin/notes.c:665 #, c-format msgid "Overwriting existing notes for object %s\n" msgstr "Überschreibe existierende Notizen für Objekt %s\n" -#: builtin/notes.c:635 +#: builtin/notes.c:618 +msgid "read objects from stdin" +msgstr "liest Objekte von der Standard-Eingabe" + +#: builtin/notes.c:620 +msgid "load rewriting config for <command> (implies --stdin)" +msgstr "" +"lädt Konfiguration für <Kommando> beim Umschreiben von Versionen (impliziert " +"--stdin)" + +#: builtin/notes.c:638 msgid "too few parameters" msgstr "zu wenig Parameter" -#: builtin/notes.c:656 +#: builtin/notes.c:659 #, c-format msgid "" "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite " @@ -3902,12 +6605,12 @@ msgstr "" "Kann Notizen nicht kopieren. Existierende Notizen für Objekt %s gefunden. " "Verwende '-f' um die existierenden Notizen zu überschreiben." -#: builtin/notes.c:668 +#: builtin/notes.c:671 #, c-format msgid "Missing notes on source object %s. Cannot copy." msgstr "Keine Notizen für Quell-Objekt %s. Kopie nicht möglich." -#: builtin/notes.c:717 +#: builtin/notes.c:720 #, c-format msgid "" "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n" @@ -3916,36 +6619,264 @@ msgstr "" "Die Optionen -m/-F/-c/-C sind für das Unterkommando 'edit' veraltet.\n" "Bitte benutze stattdessen 'git notes add -f -m/-F/-c/-C'.\n" -#: builtin/notes.c:971 +#: builtin/notes.c:867 +msgid "General options" +msgstr "Allgemeine Optionen" + +#: builtin/notes.c:869 +msgid "Merge options" +msgstr "Optionen für Zusammenführung" + +#: builtin/notes.c:871 +msgid "" +"resolve notes conflicts using the given strategy (manual/ours/theirs/union/" +"cat_sort_uniq)" +msgstr "" +"löst Konflikte bei Notizen mit der angegebenen Strategie auf (manual/ours/" +"theirs/union/cat_sort_uniq)" + +#: builtin/notes.c:873 +msgid "Committing unmerged notes" +msgstr "trägt nicht zusammengeführte Notizen ein" + +#: builtin/notes.c:875 +msgid "finalize notes merge by committing unmerged notes" +msgstr "" +"schließt Zusammenführung von Notizen ab, in dem nicht zusammengeführte " +"Notizen eingetragen werden" + +#: builtin/notes.c:877 +msgid "Aborting notes merge resolution" +msgstr "bricht Konfliktauflösung bei Zusammenführung von Notizen ab" + +#: builtin/notes.c:879 +msgid "abort notes merge" +msgstr "bricht Zusammenführung von Notizen ab" + +#: builtin/notes.c:974 #, c-format msgid "Object %s has no note\n" msgstr "Objekt %s hat keine Notiz\n" -#: builtin/notes.c:1103 builtin/remote.c:1598 +#: builtin/notes.c:986 +msgid "attempt to remove non-existent note is not an error" +msgstr "der Versuch, eine nicht existierende Notiz zu löschen, ist kein Fehler" + +#: builtin/notes.c:989 +msgid "read object names from the standard input" +msgstr "liest Objektnamen von der Standard-Eingabe" + +#: builtin/notes.c:1070 +msgid "notes_ref" +msgstr "Notiz-Referenz" + +#: builtin/notes.c:1071 +msgid "use notes from <notes_ref>" +msgstr "benutzt Notizen von <Notiz-Referenz>" + +#: builtin/notes.c:1106 builtin/remote.c:1598 #, c-format msgid "Unknown subcommand: %s" msgstr "Unbekanntes Unterkommando: %s" -#: builtin/pack-objects.c:2337 +#: builtin/pack-objects.c:23 +msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]" +msgstr "" +"git pack-objects --stdout [Optionen...] [< Referenzliste | < Objektliste]" + +#: builtin/pack-objects.c:24 +msgid "git pack-objects [options...] base-name [< ref-list | < object-list]" +msgstr "" +"git pack-objects [Optionen...] Basis-Name [< Referenzliste | < Objektliste]" + +#: builtin/pack-objects.c:183 builtin/pack-objects.c:186 +#, c-format +msgid "deflate error (%d)" +msgstr "Fehler beim Komprimieren (%d)" + +#: builtin/pack-objects.c:2397 #, c-format msgid "unsupported index version %s" msgstr "Nicht unterstützte Bereitstellungsversion %s" -#: builtin/pack-objects.c:2341 +#: builtin/pack-objects.c:2401 #, c-format msgid "bad index version '%s'" msgstr "Ungültige Bereitstellungsversion '%s'" -#: builtin/pack-objects.c:2364 +#: builtin/pack-objects.c:2424 #, c-format msgid "option %s does not accept negative form" msgstr "Option %s akzeptiert keine negative Form" -#: builtin/pack-objects.c:2368 +#: builtin/pack-objects.c:2428 #, c-format msgid "unable to parse value '%s' for option %s" msgstr "konnte Wert '%s' für Option %s nicht parsen" +#: builtin/pack-objects.c:2447 +msgid "do not show progress meter" +msgstr "zeigt keine Fortschrittsanzeige" + +#: builtin/pack-objects.c:2449 +msgid "show progress meter" +msgstr "zeigt Fortschrittsanzeige" + +#: builtin/pack-objects.c:2451 +msgid "show progress meter during object writing phase" +msgstr "zeigt Forschrittsanzeige während der Phase des Schreibens der Objekte" + +#: builtin/pack-objects.c:2454 +msgid "similar to --all-progress when progress meter is shown" +msgstr "ähnlich zu --all-progress wenn Fortschrittsanzeige darstellt wird" + +#: builtin/pack-objects.c:2455 +msgid "version[,offset]" +msgstr "version[,offset]" + +#: builtin/pack-objects.c:2456 +msgid "write the pack index file in the specified idx format version" +msgstr "" +"schreibt die Index-Datei des Paketes in der angegebenen Indexformat-Version" + +#: builtin/pack-objects.c:2459 +msgid "maximum size of each output pack file" +msgstr "maximale Größe für jede ausgegebene Paketdatei" + +#: builtin/pack-objects.c:2461 +msgid "ignore borrowed objects from alternate object store" +msgstr "ignoriert geliehene Objekte von alternativem Objektspeicher" + +#: builtin/pack-objects.c:2463 +msgid "ignore packed objects" +msgstr "ignoriert gepackte Objekte" + +#: builtin/pack-objects.c:2465 +msgid "limit pack window by objects" +msgstr "begrenzt Paketfenster durch Objekte" + +#: builtin/pack-objects.c:2467 +msgid "limit pack window by memory in addition to object limit" +msgstr "begrenzt Paketfenster, zusätzlich zur Objektbegrenzung, durch Speicher" + +#: builtin/pack-objects.c:2469 +msgid "maximum length of delta chain allowed in the resulting pack" +msgstr "" +"maximale Länge der erlaubten Differenzverkettung im resultierenden Paket" + +#: builtin/pack-objects.c:2471 +msgid "reuse existing deltas" +msgstr "verwendet existierende Unterschiede wieder" + +#: builtin/pack-objects.c:2473 +msgid "reuse existing objects" +msgstr "verwendet existierende Objekte wieder" + +#: builtin/pack-objects.c:2475 +msgid "use OFS_DELTA objects" +msgstr "benutzt OFS_DELTA Objekte" + +#: builtin/pack-objects.c:2477 +msgid "use threads when searching for best delta matches" +msgstr "" +"benutzt Threads bei der Suche nach den besten Übereinstimmungen bei " +"Unterschieden" + +#: builtin/pack-objects.c:2479 +msgid "do not create an empty pack output" +msgstr "erzeugt keine leeren Pakete" + +#: builtin/pack-objects.c:2481 +msgid "read revision arguments from standard input" +msgstr "liest Argumente bezüglich Revisionen von der Standard-Eingabe" + +#: builtin/pack-objects.c:2483 +msgid "limit the objects to those that are not yet packed" +msgstr "begrenzt die Objekte zu solchen, die noch nicht gepackt wurden" + +#: builtin/pack-objects.c:2486 +msgid "include objects reachable from any reference" +msgstr "schließt Objekte ein, die von jeder Referenz erreichbar sind" + +#: builtin/pack-objects.c:2489 +msgid "include objects referred by reflog entries" +msgstr "" +"schließt Objekte ein, die von Einträgen des Referenzprotokolls referenziert " +"werden" + +#: builtin/pack-objects.c:2492 +msgid "output pack to stdout" +msgstr "schreibt Paket in die Standard-Ausgabe" + +#: builtin/pack-objects.c:2494 +msgid "include tag objects that refer to objects to be packed" +msgstr "" +"schließt Markierungsobjekte ein, die auf gepackte Objekte referenzieren" + +#: builtin/pack-objects.c:2496 +msgid "keep unreachable objects" +msgstr "behält nicht erreichbare Objekte" + +#: builtin/pack-objects.c:2497 parse-options.h:141 +msgid "time" +msgstr "Zeit" + +#: builtin/pack-objects.c:2498 +msgid "unpack unreachable objects newer than <time>" +msgstr "entpackt nicht erreichbare Objekte, die neuer als <Zeit> sind" + +#: builtin/pack-objects.c:2501 +msgid "create thin packs" +msgstr "erzeugt dünnere Pakete" + +#: builtin/pack-objects.c:2503 +msgid "ignore packs that have companion .keep file" +msgstr "ignoriert Pakete die .keep Dateien haben" + +#: builtin/pack-objects.c:2505 +msgid "pack compression level" +msgstr "Komprimierungsgrad für Paketierung" + +#: builtin/pack-objects.c:2507 +msgid "do not hide commits by grafts" +msgstr "verbirgt keine Versionen mit künstlichen Vorgängern (\"grafts\")" + +#: builtin/pack-refs.c:6 +msgid "git pack-refs [options]" +msgstr "git pack-refs [Optionen]" + +#: builtin/pack-refs.c:14 +msgid "pack everything" +msgstr "packt alles" + +#: builtin/pack-refs.c:15 +msgid "prune loose refs (default)" +msgstr "entfernt lose Referenzen (Standard)" + +#: builtin/prune-packed.c:7 +msgid "git prune-packed [-n|--dry-run] [-q|--quiet]" +msgstr "git prune-packed [-n|--dry-run] [-q|--quiet]" + +#: builtin/prune.c:12 +msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]" +msgstr "git prune [-n] [-v] [--expire <Zeit>] [--] [<Zweigspitze>...]" + +#: builtin/prune.c:132 +msgid "do not remove, show only" +msgstr "nicht löschen, nur anzeigen" + +#: builtin/prune.c:133 +msgid "report pruned objects" +msgstr "meldet gelöschte Objekte" + +#: builtin/prune.c:136 +msgid "expire objects older than <time>" +msgstr "lässt Objekte älter als <Zeit> verfallen" + +#: builtin/push.c:14 +msgid "git push [<options>] [<repository> [<refspec>...]]" +msgstr "git push [<Optionen>] [<Projektarchiv> [<Referenzspezifikation>...]]" + #: builtin/push.c:45 msgid "tag shorthand without <tag>" msgstr "Kurzschrift für Markierung ohne <Markierung>" @@ -4034,14 +6965,49 @@ msgstr "" "aktuellen Zweiges '%s' ist, ohne mir mitzuteilen, was ich versenden\n" "soll, um welchen externen Zweig zu aktualisieren." -#: builtin/push.c:174 +#: builtin/push.c:151 +msgid "" +"push.default is unset; its implicit value is changing in\n" +"Git 2.0 from 'matching' to 'simple'. To squelch this message\n" +"and maintain the current behavior after the default changes, use:\n" +"\n" +" git config --global push.default matching\n" +"\n" +"To squelch this message and adopt the new behavior now, use:\n" +"\n" +" git config --global push.default simple\n" +"\n" +"See 'git help config' and search for 'push.default' for further " +"information.\n" +"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n" +"'current' instead of 'simple' if you sometimes use older versions of Git)" +msgstr "" +"'push.default' ist nicht gesetzt; der implizit gesetzte Wert\n" +"wird in Git 2.0 von 'matching' nach 'simple' geändert. Um diese Meldung zu\n" +"unterdrücken und das aktuelle Verhalten nach Änderung des Standardwertes\n" +"beizubehalten, benutze:\n" +" git config --global push.default matching\n" +"\n" +"Um diese Meldung zu unterdrücken und das neue Verhalten jetzt zu " +"übernehmen,\n" +"benutze:\n" +"\n" +" git config --global push.default simple\n" +"\n" +"Führe 'git help config' aus und suche nach 'push.default' für weitere " +"Informationen.\n" +"(Der Modus 'simple' wurde in Git 1.7.11 eingeführt. Benutze den ähnlichen " +"Modus 'current' anstatt 'simple', falls du gelegentlich ältere Versionen von " +"Git benutzt.)" + +#: builtin/push.c:199 msgid "" "You didn't specify any refspecs to push, and push.default is \"nothing\"." msgstr "" "Du hast keine Referenzspezifikationen zum Versenden angegeben, und push." "default ist \"nothing\"." -#: builtin/push.c:181 +#: builtin/push.c:206 msgid "" "Updates were rejected because the tip of your current branch is behind\n" "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n" @@ -4054,22 +7020,22 @@ msgstr "" "Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n" "für weitere Details." -#: builtin/push.c:187 +#: builtin/push.c:212 msgid "" "Updates were rejected because a pushed branch tip is behind its remote\n" "counterpart. If you did not intend to push that branch, you may want to\n" -"specify branches to push or set the 'push.default' configuration\n" -"variable to 'current' or 'upstream' to push only the current branch." +"specify branches to push or set the 'push.default' configuration variable\n" +"to 'simple', 'current' or 'upstream' to push only the current branch." msgstr "" "Aktualisierungen wurden zurückgewiesen, weil die Spitze eines versendeten\n" "Zweiges hinter seinem externen Gegenstück zurückgefallen ist. Wenn du nicht\n" "beabsichtigt hast, diesen Zweig zu versenden, kannst du auch den zu " "versendenden\n" "Zweig spezifizieren oder die Konfigurationsvariable 'push.default' zu " -"'current'\n" +"'simple', 'current'\n" "oder 'upstream' setzen, um nur den aktuellen Zweig zu versenden." -#: builtin/push.c:193 +#: builtin/push.c:218 msgid "" "Updates were rejected because a pushed branch tip is behind its remote\n" "counterpart. Check out this branch and merge the remote changes\n" @@ -4083,22 +7049,22 @@ msgstr "" "Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'\n" "für weitere Details." -#: builtin/push.c:233 +#: builtin/push.c:258 #, c-format msgid "Pushing to %s\n" msgstr "Versende nach %s\n" -#: builtin/push.c:237 +#: builtin/push.c:262 #, c-format msgid "failed to push some refs to '%s'" msgstr "Fehler beim Versenden einiger Referenzen nach '%s'" -#: builtin/push.c:269 +#: builtin/push.c:294 #, c-format msgid "bad repository '%s'" msgstr "ungültiges Projektarchiv '%s'" -#: builtin/push.c:270 +#: builtin/push.c:295 msgid "" "No configured push destination.\n" "Either specify the URL from the command-line or configure a remote " @@ -4120,34 +7086,240 @@ msgstr "" "\n" " git push <Name>\n" -#: builtin/push.c:285 +#: builtin/push.c:310 msgid "--all and --tags are incompatible" msgstr "--all und --tags sind inkompatibel" -#: builtin/push.c:286 +#: builtin/push.c:311 msgid "--all can't be combined with refspecs" msgstr "--all kann nicht mit Referenzspezifikationen kombiniert werden" -#: builtin/push.c:291 +#: builtin/push.c:316 msgid "--mirror and --tags are incompatible" msgstr "--mirror und --tags sind inkompatibel" -#: builtin/push.c:292 +#: builtin/push.c:317 msgid "--mirror can't be combined with refspecs" msgstr "--mirror kann nicht mit Referenzspezifikationen kombiniert werden" -#: builtin/push.c:297 +#: builtin/push.c:322 msgid "--all and --mirror are incompatible" msgstr "--all und --mirror sind inkompatibel" -#: builtin/push.c:385 +#: builtin/push.c:382 +msgid "repository" +msgstr "Projektarchiv" + +#: builtin/push.c:383 +msgid "push all refs" +msgstr "versendet alle Referenzen" + +#: builtin/push.c:384 +msgid "mirror all refs" +msgstr "spiegelt alle Referenzen" + +#: builtin/push.c:386 +msgid "delete refs" +msgstr "löscht Referenzen" + +#: builtin/push.c:387 +msgid "push tags (can't be used with --all or --mirror)" +msgstr "" +"versendet Markierungen (kann nicht mit --all oder --mirror benutzt werden)" + +#: builtin/push.c:390 +msgid "force updates" +msgstr "erzwingt Aktualisierung" + +#: builtin/push.c:391 +msgid "check" +msgstr "" + +#: builtin/push.c:392 +msgid "control recursive pushing of submodules" +msgstr "steuert rekursives Versenden von Unterprojekten" + +#: builtin/push.c:394 +msgid "use thin pack" +msgstr "benutzt kleinere Pakete" + +#: builtin/push.c:395 builtin/push.c:396 +msgid "receive pack program" +msgstr "'receive pack' Programm" + +#: builtin/push.c:397 +msgid "set upstream for git pull/status" +msgstr "setzt externes Projektarchiv für \"git pull/status\"" + +#: builtin/push.c:400 +msgid "prune locally removed refs" +msgstr "entfernt lokal gelöschte Referenzen" + +#: builtin/push.c:410 msgid "--delete is incompatible with --all, --mirror and --tags" msgstr "--delete ist inkompatibel mit --all, --mirror und --tags" -#: builtin/push.c:387 +#: builtin/push.c:412 msgid "--delete doesn't make sense without any refs" msgstr "--delete macht ohne irgendeine Referenz keinen Sinn" +#: builtin/read-tree.c:36 +msgid "" +"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] " +"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--" +"index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])" +msgstr "" +"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<Prefix>] " +"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--" +"index-output=<Datei>] (--empty | <Versionsreferenz1> [<Versionsreferenz2> " +"[<Versionsreferenz3>]])" + +#: builtin/read-tree.c:108 +msgid "write resulting index to <file>" +msgstr "schreibt resultierende Bereitstellung nach <Datei>" + +#: builtin/read-tree.c:111 +msgid "only empty the index" +msgstr "leert die Bereitstellung" + +#: builtin/read-tree.c:113 +msgid "Merging" +msgstr "Zusammenführung" + +#: builtin/read-tree.c:115 +msgid "perform a merge in addition to a read" +msgstr "führt eine Zusammenführung zusätzlich zum Lesen aus" + +#: builtin/read-tree.c:117 +msgid "3-way merge if no file level merging required" +msgstr "" +"3-Wege-Zusammenführung, wenn keine Zusammenführung auf Dateiebene " +"erforderlich ist" + +#: builtin/read-tree.c:119 +msgid "3-way merge in presence of adds and removes" +msgstr "" +"3-Wege-Zusammenführung bei Vorhandensein von hinzugefügten/entfernten Zeilen" + +#: builtin/read-tree.c:121 +msgid "same as -m, but discard unmerged entries" +msgstr "genau wie -m, verwirft aber nicht zusammengeführte Einträge" + +#: builtin/read-tree.c:122 +msgid "<subdirectory>/" +msgstr "<Unterverzeichnis>/" + +#: builtin/read-tree.c:123 +msgid "read the tree into the index under <subdirectory>/" +msgstr "liest den Baum in die Bereitstellung unter <Unterverzeichnis>/" + +#: builtin/read-tree.c:126 +msgid "update working tree with merge result" +msgstr "aktualisiert Arbeitsbaum mit Ergebnis der Zusammenführung" + +#: builtin/read-tree.c:128 +msgid "gitignore" +msgstr "gitignore" + +#: builtin/read-tree.c:129 +msgid "allow explicitly ignored files to be overwritten" +msgstr "erlaubt explizit ignorierte Dateien zu überschreiben" + +#: builtin/read-tree.c:132 +msgid "don't check the working tree after merging" +msgstr "prüft nicht den Arbeitsbaum nach der Zusammenführung" + +#: builtin/read-tree.c:133 +msgid "don't update the index or the work tree" +msgstr "aktualisiert weder die Bereitstellung, noch den Arbeitsbaum" + +#: builtin/read-tree.c:135 +msgid "skip applying sparse checkout filter" +msgstr "überspringt Anwendung des Filters für spärliches Auschecken" + +#: builtin/read-tree.c:137 +msgid "debug unpack-trees" +msgstr "protokolliert Entpacken der Bäume" + +#: builtin/remote.c:11 +msgid "git remote [-v | --verbose]" +msgstr "git remote [-v | --verbose]" + +#: builtin/remote.c:12 +msgid "" +"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--" +"mirror=<fetch|push>] <name> <url>" +msgstr "" +"git remote add [-t <Zweig>] [-m <master>] [-f] [--tags|--no-tags] [--" +"mirror=<fetch|push>] <Name> <URL>" + +#: builtin/remote.c:13 builtin/remote.c:32 +msgid "git remote rename <old> <new>" +msgstr "git remote rename <alt> <neu>" + +#: builtin/remote.c:14 builtin/remote.c:37 +msgid "git remote remove <name>" +msgstr "git remote remove <Name>" + +#: builtin/remote.c:15 builtin/remote.c:42 +msgid "git remote set-head <name> (-a | -d | <branch>)" +msgstr "git remote set-head <Name> (-a | -d | <Zweig>)" + +#: builtin/remote.c:16 +msgid "git remote [-v | --verbose] show [-n] <name>" +msgstr "git remote [-v | --verbose] show [-n] <Name>" + +#: builtin/remote.c:17 +msgid "git remote prune [-n | --dry-run] <name>" +msgstr "git remote prune [-n | --dry-run] <Name>" + +#: builtin/remote.c:18 +msgid "" +"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]" +msgstr "" +"git remote [-v | --verbose] update [-p | --prune] [(<Gruppe> | " +"<externesProjektarchiv>)...]" + +#: builtin/remote.c:19 +msgid "git remote set-branches [--add] <name> <branch>..." +msgstr "git remote set-branches [--add] <Name> <Zweig>..." + +#: builtin/remote.c:20 builtin/remote.c:68 +msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]" +msgstr "git remote set-url [--push] <Name> <neueURL> [<alteURL>]" + +#: builtin/remote.c:21 builtin/remote.c:69 +msgid "git remote set-url --add <name> <newurl>" +msgstr "git remote set-url --add <Name> <neueURL>" + +#: builtin/remote.c:22 builtin/remote.c:70 +msgid "git remote set-url --delete <name> <url>" +msgstr "git remote set-url --delete <Name> <URL>" + +#: builtin/remote.c:27 +msgid "git remote add [<options>] <name> <url>" +msgstr "git remote add [<Optionen>] <Name> <URL>" + +#: builtin/remote.c:47 +msgid "git remote set-branches <name> <branch>..." +msgstr "git remote set-branches <Name> <Zweig>..." + +#: builtin/remote.c:48 +msgid "git remote set-branches --add <name> <branch>..." +msgstr "git remote set-branches --add <Name> <Zweig>..." + +#: builtin/remote.c:53 +msgid "git remote show [<options>] <name>" +msgstr "git remote show [<Optionen>] <Name>" + +#: builtin/remote.c:58 +msgid "git remote prune [<options>] <name>" +msgstr "git remote prune [<Optionen>] <Name>" + +#: builtin/remote.c:63 +msgid "git remote update [<options>] [<group> | <remote>]..." +msgstr "git remote update [<Optionen>] [<Gruppe> | <externesProjektarchiv>]..." + #: builtin/remote.c:98 #, c-format msgid "Updating %s" @@ -4166,6 +7338,35 @@ msgstr "" msgid "unknown mirror argument: %s" msgstr "unbekanntes Argument für Option --mirror: %s" +#: builtin/remote.c:163 +msgid "fetch the remote branches" +msgstr "fordert die externen Zweige an" + +#: builtin/remote.c:165 +msgid "import all tags and associated objects when fetching" +msgstr "importiert alle Markierungen und verbundene Objekte beim Anfordern" + +#: builtin/remote.c:168 +msgid "or do not fetch any tag at all (--no-tags)" +msgstr "oder fordere gar keine Zweige an (--no-tags)" + +#: builtin/remote.c:170 +msgid "branch(es) to track" +msgstr "Zweige zur Übernahme" + +#: builtin/remote.c:171 +msgid "master branch" +msgstr "Hauptzweig" + +#: builtin/remote.c:172 +msgid "push|fetch" +msgstr "push|fetch" + +#: builtin/remote.c:173 +msgid "set up remote as a mirror to push to or fetch from" +msgstr "" +"Aufsetzen des Fernarchivs als Spiegelarchiv zum Versenden und Anfordern" + #: builtin/remote.c:185 msgid "specifying a master branch makes no sense with --mirror" msgstr "Angabe eines Hauptzweiges macht mit --mirror keinen Sinn" @@ -4173,7 +7374,7 @@ msgstr "Angabe eines Hauptzweiges macht mit --mirror keinen Sinn" #: builtin/remote.c:187 msgid "specifying branches to track makes sense only with fetch mirrors" msgstr "" -"die Angabe von zu folgenden Zweigen macht nur mit dem Abholen von " +"die Angabe von zu folgenden Zweigen macht nur mit dem Anfordern von " "Spiegelarchiven Sinn" #: builtin/remote.c:195 builtin/remote.c:646 @@ -4264,7 +7465,7 @@ msgstr "Konnte '%s' nicht erstellen" #: builtin/remote.c:764 #, c-format msgid "Could not remove branch %s" -msgstr "Konnte Zweig %s nicht entfernen" +msgstr "Konnte Zweig %s nicht löschen" #: builtin/remote.c:834 msgid "" @@ -4275,8 +7476,8 @@ msgid_plural "" "to delete them, use:" msgstr[0] "" "Hinweis: Ein Zweig außerhalb der /refs/remotes/ Hierachie wurde nicht " -"entfernt;\n" -"um diesen zu entfernen, benutze:" +"gelöscht;\n" +"um diesen zu löschen, benutze:" msgstr[1] "" "Hinweis: Einige Zweige außer der /refs/remotes/ Hierarchie wurden nicht " "entfernt;\n" @@ -4293,7 +7494,7 @@ msgstr " gefolgt" #: builtin/remote.c:948 msgid " stale (use 'git remote prune' to remove)" -msgstr " veraltet (benutze 'git remote prune' zum Entfernen)" +msgstr " veraltet (benutze 'git remote prune' zum Löschen)" #: builtin/remote.c:950 msgid " ???" @@ -4367,6 +7568,10 @@ msgstr " %-*s erzwingt Versand nach %s" msgid " %-*s pushes to %s" msgstr " %-*s versendet nach %s" +#: builtin/remote.c:1091 +msgid "do not query remotes" +msgstr "keine Abfrage von Fernarchiven" + #: builtin/remote.c:1118 #, c-format msgid "* remote %s" @@ -4427,6 +7632,14 @@ msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] " Lokale Referenz konfiguriert für 'git push'%s:" msgstr[1] " Lokale Referenzen konfiguriert für 'git push'%s:" +#: builtin/remote.c:1199 +msgid "set refs/remotes/<name>/HEAD according to remote" +msgstr "setzt refs/remotes/<Name>/HEAD gemäß dem Fernarchiv" + +#: builtin/remote.c:1201 +msgid "delete refs/remotes/<name>/HEAD" +msgstr "entfernt refs/remotes/<Name>/HEAD" + #: builtin/remote.c:1216 msgid "Cannot determine remote HEAD" msgstr "Kann Hauptzweig des externen Projektarchivs nicht bestimmen" @@ -4482,15 +7695,35 @@ msgstr " * [würde veralteten Zweig entfernen] %s" msgid " * [pruned] %s" msgstr "* [veralteten Zweig entfernt] %s" +#: builtin/remote.c:1321 +msgid "prune remotes after fetching" +msgstr "entfernt veraltete Zweige im Fernarchiv nach dem Abholen" + #: builtin/remote.c:1387 builtin/remote.c:1461 #, c-format msgid "No such remote '%s'" msgstr "Kein solches externes Projektarchiv '%s'" +#: builtin/remote.c:1407 +msgid "add branch" +msgstr "fügt Zweig hinzu" + #: builtin/remote.c:1414 msgid "no remote specified" msgstr "kein externes Projektarchiv angegeben" +#: builtin/remote.c:1436 +msgid "manipulate push URLs" +msgstr "manipuliert URLs zum Versenden" + +#: builtin/remote.c:1438 +msgid "add URL" +msgstr "fügt URL hinzu" + +#: builtin/remote.c:1440 +msgid "delete URLs" +msgstr "löscht URLs" + #: builtin/remote.c:1447 msgid "--add --delete doesn't make sense" msgstr "--add --delete macht keinen Sinn" @@ -4509,6 +7742,56 @@ msgstr "Keine solche URL gefunden: %s" msgid "Will not delete all non-push URLs" msgstr "Werde keine URLs entfernen, die nicht für den Versand bestimmt sind" +#: builtin/remote.c:1569 +msgid "be verbose; must be placed before a subcommand" +msgstr "erweiterte Ausgaben; muss vor einem Unterkommando angegeben werden" + +#: builtin/replace.c:17 +msgid "git replace [-f] <object> <replacement>" +msgstr "git replace [-f] <Objekt> <Ersetzung>" + +#: builtin/replace.c:18 +msgid "git replace -d <object>..." +msgstr "git replace -d <Objekt>..." + +#: builtin/replace.c:19 +msgid "git replace -l [<pattern>]" +msgstr "git replace -l [<Muster>]" + +#: builtin/replace.c:121 +msgid "list replace refs" +msgstr "listet ersetzende Referenzen auf" + +#: builtin/replace.c:122 +msgid "delete replace refs" +msgstr "löscht ersetzende Referenzen" + +#: builtin/replace.c:123 +msgid "replace the ref if it exists" +msgstr "ersetzt die Referenz, wenn sie existiert" + +#: builtin/rerere.c:11 +msgid "git rerere [clear | forget path... | status | remaining | diff | gc]" +msgstr "git rerere [clean | forget path... | status | remaining | diff | gc]" + +#: builtin/rerere.c:56 +msgid "register clean resolutions in index" +msgstr "registriert saubere Auflösungen in der Bereitstellung" + +#: builtin/reset.c:25 +msgid "" +"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]" +msgstr "" +"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<Version>]" + +#: builtin/reset.c:26 +msgid "git reset [-q] <commit> [--] <paths>..." +msgstr "git reset [-q] <Version> [--] <Pfade>..." + +#: builtin/reset.c:27 +msgid "git reset --patch [<commit>] [--] [<paths>...]" +msgstr "git reset --patch [<Version>] [--] [<Pfade>...]" + #: builtin/reset.c:33 msgid "mixed" msgstr "mixed" @@ -4566,53 +7849,186 @@ msgstr "" "Kann keine '%s' Zurücksetzung durchführen, während eine Zusammenführung im " "Gange ist." -#: builtin/reset.c:297 +#: builtin/reset.c:238 +msgid "be quiet, only report errors" +msgstr "weniger Ausgaben, meldet nur Fehler" + +#: builtin/reset.c:240 +msgid "reset HEAD and index" +msgstr "setzt Zweigspitze (HEAD) und Bereitstellung zurück" + +#: builtin/reset.c:241 +msgid "reset only HEAD" +msgstr "setzt nur Zweigspitze (HEAD) zurück" + +#: builtin/reset.c:243 builtin/reset.c:245 +msgid "reset HEAD, index and working tree" +msgstr "setzt Zweigspitze (HEAD), Bereitstellung und Arbeitsbaum zurück" + +#: builtin/reset.c:247 +msgid "reset HEAD but keep local changes" +msgstr "setzt Zweigspitze (HEAD) zurück, behält aber lokale Änderungen" + +#: builtin/reset.c:303 #, c-format msgid "Could not parse object '%s'." msgstr "Konnte Objekt '%s' nicht parsen." -#: builtin/reset.c:302 +#: builtin/reset.c:308 msgid "--patch is incompatible with --{hard,mixed,soft}" msgstr "--patch ist inkompatibel mit --{hard,mixed,soft}" -#: builtin/reset.c:311 +#: builtin/reset.c:317 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." msgstr "" "--mixed mit Pfaden ist veraltet; benutze stattdessen 'git reset -- <Pfade>'." -#: builtin/reset.c:313 +#: builtin/reset.c:319 #, c-format msgid "Cannot do %s reset with paths." msgstr "Eine '%s' Zurücksetzung mit Pfaden ist nicht möglich." -#: builtin/reset.c:325 +#: builtin/reset.c:331 #, c-format msgid "%s reset is not allowed in a bare repository" msgstr "'%s' Zurücksetzung ist in einem bloßen Projektarchiv nicht erlaubt" -#: builtin/reset.c:341 +#: builtin/reset.c:347 #, c-format msgid "Could not reset index file to revision '%s'." msgstr "Konnte Bereitstellungsdatei nicht zu Version '%s' zurücksetzen." +#: builtin/rev-parse.c:339 +msgid "git rev-parse --parseopt [options] -- [<args>...]" +msgstr "git rev-parse --parseopt [Optionen] -- [<Argumente>...]" + +#: builtin/rev-parse.c:344 +msgid "keep the `--` passed as an arg" +msgstr "lässt `--` als Argument" + +#: builtin/rev-parse.c:346 +msgid "stop parsing after the first non-option argument" +msgstr "stoppt das Parsen nach dem ersten Argument was keine Option ist" + +#: builtin/rev-parse.c:464 +msgid "" +"git rev-parse --parseopt [options] -- [<args>...]\n" +" or: git rev-parse --sq-quote [<arg>...]\n" +" or: git rev-parse [options] [<arg>...]\n" +"\n" +"Run \"git rev-parse --parseopt -h\" for more information on the first usage." +msgstr "" +"git rev-parse --parseopt [Optionen] -- [<Argumente>...]\n" +" oder: git rev-parse --sq-quote [<Argumente>...]\n" +" oder: git rev-parse [Optionen] [<Argumente>...]\n" +"\n" +"Führe \"git rev-parse --parseopt -h\" für weitere Informationen bei erster " +"Verwendung aus." + +#: builtin/revert.c:22 +msgid "git revert [options] <commit-ish>" +msgstr "git revert [options] <Versionsangabe>" + +#: builtin/revert.c:23 +msgid "git revert <subcommand>" +msgstr "git revert <Unterkommando>" + +#: builtin/revert.c:28 +msgid "git cherry-pick [options] <commit-ish>" +msgstr "git cherry-pick [Optionen] <Versionsangabe>" + +#: builtin/revert.c:29 +msgid "git cherry-pick <subcommand>" +msgstr "git cherry-pick <Unterkommando>" + #: builtin/revert.c:70 builtin/revert.c:92 #, c-format msgid "%s: %s cannot be used with %s" msgstr "%s: %s kann nicht mit %s benutzt werden" -#: builtin/revert.c:131 +#: builtin/revert.c:103 +msgid "end revert or cherry-pick sequence" +msgstr "beendet \"revert\" oder \"cherry-pick\" Ablauf" + +#: builtin/revert.c:104 +msgid "resume revert or cherry-pick sequence" +msgstr "setzt \"revert\" oder \"cherry-pick\" Ablauf fort" + +#: builtin/revert.c:105 +msgid "cancel revert or cherry-pick sequence" +msgstr "bricht \"revert\" oder \"cherry-pick\" Ablauf ab" + +#: builtin/revert.c:106 +msgid "don't automatically commit" +msgstr "trägt nicht automatisch ein" + +#: builtin/revert.c:107 +msgid "edit the commit message" +msgstr "Bearbeitung der Versionsbeschreibung" + +#: builtin/revert.c:110 +msgid "parent number" +msgstr "Nummer des Elternteils" + +#: builtin/revert.c:112 +msgid "merge strategy" +msgstr "Zusammenführungsstrategie" + +#: builtin/revert.c:113 +msgid "option" +msgstr "Option" + +#: builtin/revert.c:114 +msgid "option for merge strategy" +msgstr "Option für Zusammenführungsstrategie" + +#: builtin/revert.c:125 +msgid "append commit name" +msgstr "hängt Versionsnamen an" + +#: builtin/revert.c:126 +msgid "allow fast-forward" +msgstr "erlaubt Vorspulen" + +#: builtin/revert.c:127 +msgid "preserve initially empty commits" +msgstr "erhält ursprüngliche, leere Versionen" + +#: builtin/revert.c:128 +msgid "allow commits with empty messages" +msgstr "erlaubt Version mit leerer Beschreibung" + +#: builtin/revert.c:129 +msgid "keep redundant, empty commits" +msgstr "behält redundante, leere Versionen" + +#: builtin/revert.c:133 msgid "program error" msgstr "Programmfehler" -#: builtin/revert.c:221 +#: builtin/revert.c:223 msgid "revert failed" msgstr "\"revert\" fehlgeschlagen" -#: builtin/revert.c:236 +#: builtin/revert.c:238 msgid "cherry-pick failed" msgstr "\"cherry-pick\" fehlgeschlagen" -#: builtin/rm.c:109 +#: builtin/rm.c:15 +msgid "git rm [options] [--] <file>..." +msgstr "git rm [Optionen] [--] [<Datei>...]" + +#: builtin/rm.c:64 builtin/rm.c:186 +#, c-format +msgid "" +"submodule '%s' (or one of its nested submodules) uses a .git directory\n" +"(use 'rm -rf' if you really want to remove it including all of its history)" +msgstr "" +"Unterprojekt '%s' (oder ein geschachteltes Unterprojekt hiervon) verwendet\n" +"ein .git-Verzeichnis (benutze 'rm -rf' wenn du dieses wirklich mitsamt\n" +"seiner Historie löschen möchtest)" + +#: builtin/rm.c:174 #, c-format msgid "" "'%s' has staged content different from both the file and the HEAD\n" @@ -4621,7 +8037,7 @@ msgstr "" "'%s' hat bereitgestellten Inhalt unterschiedlich zu der Datei und der\n" "Zweigspitze (HEAD) (benutze -f um die Entfernung zu erzwingen)" -#: builtin/rm.c:115 +#: builtin/rm.c:180 #, c-format msgid "" "'%s' has changes staged in the index\n" @@ -4631,7 +8047,7 @@ msgstr "" "(benutze --cached um die Datei zu behalten, oder -f um die Entfernung zu " "erzwingen)" -#: builtin/rm.c:119 +#: builtin/rm.c:191 #, c-format msgid "" "'%s' has local modifications\n" @@ -4641,21 +8057,248 @@ msgstr "" "(benutze --cached um die Datei zu behalten, oder -f um die Entfernung zu " "erzwingen)" -#: builtin/rm.c:194 +#: builtin/rm.c:207 +msgid "do not list removed files" +msgstr "listet keine gelöschten Dateien auf" + +#: builtin/rm.c:208 +msgid "only remove from the index" +msgstr "entfernt nur aus der Bereitstellung" + +#: builtin/rm.c:209 +msgid "override the up-to-date check" +msgstr "überschreibt die \"up-to-date\" Prüfung" + +#: builtin/rm.c:210 +msgid "allow recursive removal" +msgstr "erlaubt rekursive Entfernung" + +#: builtin/rm.c:212 +msgid "exit with a zero status even if nothing matched" +msgstr "beendet mit Rückgabewert 0, wenn keine Übereinstimmung gefunden wurde" + +#: builtin/rm.c:283 #, c-format msgid "not removing '%s' recursively without -r" msgstr "'%s' wird nicht ohne -r rekursiv entfernt" -#: builtin/rm.c:230 +#: builtin/rm.c:322 #, c-format msgid "git rm: unable to remove %s" -msgstr "git rm: konnte %s nicht entfernen" +msgstr "git rm: konnte %s nicht löschen" + +#: builtin/shortlog.c:13 +msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]" +msgstr "" +"git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] " +"[<Versionsidentifikation>... ]" #: builtin/shortlog.c:157 #, c-format msgid "Missing author: %s" msgstr "fehlender Autor: %s" +#: builtin/shortlog.c:253 +msgid "sort output according to the number of commits per author" +msgstr "sortiert die Ausgabe entsprechend der Anzahl von Versionen pro Autor" + +#: builtin/shortlog.c:255 +msgid "Suppress commit descriptions, only provides commit count" +msgstr "Unterdrückt Versionsbeschreibungen, liefert nur Anzahl der Versionen" + +#: builtin/shortlog.c:257 +msgid "Show the email address of each author" +msgstr "Zeigt die Email-Adresse von jedem Autor" + +#: builtin/shortlog.c:258 +msgid "w[,i1[,i2]]" +msgstr "w[,i1[,i2]]" + +#: builtin/shortlog.c:259 +msgid "Linewrap output" +msgstr "Ausgabe mit Zeilenumbrüchen" + +#: builtin/show-branch.c:9 +msgid "" +"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--" +"current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --" +"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | " +"<glob>)...]" +msgstr "" +"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--" +"current] [--color[=<Wann>] | --no-color] [--sparse] [--more=<n> | --list | --" +"independent | --merge-base] [--no-name | --sha1-name] [--topics] " +"[(<Revision> | <glob>)...]" + +#: builtin/show-branch.c:10 +msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]" +msgstr "git show-branch (-g|--reflog)[=<n>[,<Basis>]] [--list] [<Referenz>]" + +#: builtin/show-branch.c:651 +msgid "show remote-tracking and local branches" +msgstr "zeigt externe Übernahmezweige und lokale Zweige an" + +#: builtin/show-branch.c:653 +msgid "show remote-tracking branches" +msgstr "zeigt externe Übernahmezweige an" + +#: builtin/show-branch.c:655 +msgid "color '*!+-' corresponding to the branch" +msgstr "färbt '*!+-' entsprechend des Zweiges ein" + +#: builtin/show-branch.c:657 +msgid "show <n> more commits after the common ancestor" +msgstr "zeigt <n> weitere Versionen nach dem gemeinsamen Vorfahren" + +#: builtin/show-branch.c:659 +msgid "synonym to more=-1" +msgstr "Synonym für more=-1" + +#: builtin/show-branch.c:660 +msgid "suppress naming strings" +msgstr "unterdrückt Namen" + +#: builtin/show-branch.c:662 +msgid "include the current branch" +msgstr "bezieht den aktuellen Zweig ein" + +#: builtin/show-branch.c:664 +msgid "name commits with their object names" +msgstr "benennt Versionen nach ihren Objektnamen" + +#: builtin/show-branch.c:666 +msgid "show possible merge bases" +msgstr "zeigt mögliche Basen für Zusammenführung" + +#: builtin/show-branch.c:668 +msgid "show refs unreachable from any other ref" +msgstr "zeigt Referenzen die unerreichbar von allen anderen Referenzen sind" + +#: builtin/show-branch.c:670 +msgid "show commits in topological order" +msgstr "zeigt Versionen in topologischer Ordnung" + +#: builtin/show-branch.c:672 +msgid "show only commits not on the first branch" +msgstr "zeigt nur Versionen, die sich nicht im ersten Zweig befinden" + +#: builtin/show-branch.c:674 +msgid "show merges reachable from only one tip" +msgstr "" +"zeigt Zusammenführungen, die nur von einer Zweigspitze aus erreichbar sind" + +#: builtin/show-branch.c:676 +msgid "show commits where no parent comes before its children" +msgstr "zeigt Versionen, wo kein Elternteil vor seinem Kind kommt" + +#: builtin/show-branch.c:678 +msgid "<n>[,<base>]" +msgstr "<n>[,<Basis>]" + +#: builtin/show-branch.c:679 +msgid "show <n> most recent ref-log entries starting at base" +msgstr "" +"zeigt die <n> jüngsten Einträge im Referenzprotokoll beginnend an der Basis" + +#: builtin/show-ref.c:10 +msgid "" +"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash" +"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] " +msgstr "" +"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash" +"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] " + +#: builtin/show-ref.c:11 +msgid "git show-ref --exclude-existing[=pattern] < ref-list" +msgstr "git show-ref --exclude-existing[=Muster] < ref-list" + +#: builtin/show-ref.c:165 +msgid "only show tags (can be combined with heads)" +msgstr "zeigt nur Markierungen (kann mit \"heads\" kombiniert werden)" + +#: builtin/show-ref.c:166 +msgid "only show heads (can be combined with tags)" +msgstr "zeigt nur Zweigspitzen (kann mit \"tags\" kombiniert werden)" + +#: builtin/show-ref.c:167 +msgid "stricter reference checking, requires exact ref path" +msgstr "strengere Referenzprüfung, erfordert exakten Referenzpfad" + +#: builtin/show-ref.c:170 builtin/show-ref.c:172 +msgid "show the HEAD reference" +msgstr "zeigt Referenz der Zweigspitze (HEAD)" + +#: builtin/show-ref.c:174 +msgid "dereference tags into object IDs" +msgstr "dereferenziert Markierungen in Objekt-Identifikationen" + +#: builtin/show-ref.c:176 +msgid "only show SHA1 hash using <n> digits" +msgstr "zeigt nur SHA1 Hash mit <n> Ziffern" + +#: builtin/show-ref.c:180 +msgid "do not print results to stdout (useful with --verify)" +msgstr "" +"keine Ausgabe der Ergebnisse in die Standard-Ausgabe (nützlich mit --verify)" + +#: builtin/show-ref.c:182 +msgid "show refs from stdin that aren't in local repository" +msgstr "" +"zeigt Referenzen von der Standard-Eingabe, die sich nicht im lokalen " +"Projektarchiv befinden, an" + +#: builtin/symbolic-ref.c:7 +msgid "git symbolic-ref [options] name [ref]" +msgstr "git symbolic-ref [Optionen] name [ref]" + +#: builtin/symbolic-ref.c:8 +msgid "git symbolic-ref -d [-q] name" +msgstr "git symbolic-ref -d [-q] name" + +#: builtin/symbolic-ref.c:40 +msgid "suppress error message for non-symbolic (detached) refs" +msgstr "" +"unterdrückt Fehlermeldungen für nicht-symbolische (losgelöste) Referenzen" + +#: builtin/symbolic-ref.c:41 +msgid "delete symbolic ref" +msgstr "löscht symbolische Referenzen" + +#: builtin/symbolic-ref.c:42 +msgid "shorten ref output" +msgstr "verkürzte Ausgabe der Referenzen" + +#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18 +msgid "reason" +msgstr "Grund" + +#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18 +msgid "reason of the update" +msgstr "Grund für die Aktualisierung" + +#: builtin/tag.c:22 +msgid "" +"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]" +msgstr "" +"git tag [-a|-s|-u <Schlüssel-id>] [-f] [-m <Nachricht>|-F <Datei>] " +"<Markierungsname> [<Zweig>]" + +#: builtin/tag.c:23 +msgid "git tag -d <tagname>..." +msgstr "git tag -d <Markierungsname>..." + +#: builtin/tag.c:24 +msgid "" +"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n" +"\t\t[<pattern>...]" +msgstr "" +"git tag -l [-n[<Nummer>]] [--contains <Version>] [--points-at <Objekt>] \n" +"\t\t[<Muster>...]" + +#: builtin/tag.c:26 +msgid "git tag -v <tagname>..." +msgstr "git tag -v <Markierungsname>..." + #: builtin/tag.c:60 #, c-format msgid "malformed object at '%s'" @@ -4745,6 +8388,62 @@ msgstr "Option 'points-at' erfordert ein Objekt" msgid "malformed object name '%s'" msgstr "fehlerhafter Objekt-Name '%s'" +#: builtin/tag.c:447 +msgid "list tag names" +msgstr "listet Markierungsnamen auf" + +#: builtin/tag.c:449 +msgid "print <n> lines of each tag message" +msgstr "zeigt <n> Zeilen jeder Markierungsbeschreibung" + +#: builtin/tag.c:451 +msgid "delete tags" +msgstr "löscht Markierungen" + +#: builtin/tag.c:452 +msgid "verify tags" +msgstr "überprüft Markierungen" + +#: builtin/tag.c:454 +msgid "Tag creation options" +msgstr "Optionen für Erstellung von Markierungen" + +#: builtin/tag.c:456 +msgid "annotated tag, needs a message" +msgstr "annotierte Markierung, benötigt eine Beschreibung" + +#: builtin/tag.c:458 +msgid "tag message" +msgstr "Markierungsbeschreibung" + +#: builtin/tag.c:460 +msgid "annotated and GPG-signed tag" +msgstr "annotierte und GPG-signierte Markierung" + +#: builtin/tag.c:464 +msgid "use another key to sign the tag" +msgstr "benutzt einen anderen Schlüssel um die Markierung zu signieren" + +#: builtin/tag.c:465 +msgid "replace the tag if exists" +msgstr "ersetzt die Markierung, wenn sie existiert" + +#: builtin/tag.c:466 +msgid "show tag list in columns" +msgstr "zeigt Liste der Markierungen in Spalten" + +#: builtin/tag.c:468 +msgid "Tag listing options" +msgstr "Optionen für Auflistung der Markierungen" + +#: builtin/tag.c:471 +msgid "print only tags that contain the commit" +msgstr "gibt nur Markierungen aus, die diese Version beinhalten" + +#: builtin/tag.c:477 +msgid "print only tags of the object" +msgstr "gibt nur Markierungen von dem Objekt aus" + #: builtin/tag.c:506 msgid "--column and -n are incompatible" msgstr "--column und -n sind inkompatibel" @@ -4794,27 +8493,191 @@ msgstr "%s: kann Referenz nicht aktualisieren" msgid "Updated tag '%s' (was %s)\n" msgstr "Aktualisierte Markierung '%s' (war %s)\n" -#: git.c:16 -msgid "See 'git help <command>' for more information on a specific command." +#: builtin/update-index.c:401 +msgid "git update-index [options] [--] [<file>...]" +msgstr "git update-index [Optionen] [--] [<Datei>...]" + +#: builtin/update-index.c:718 +msgid "continue refresh even when index needs update" msgstr "" -"Siehe 'git help <Kommando>' für weitere Informationen zu einem spezifischen " -"Kommando" +"Aktualisierung fortsetzen, auch wenn die Bereitstellung aktualisiert werden " +"muss" -#: parse-options.h:133 parse-options.h:235 -msgid "n" -msgstr "Anzahl" +#: builtin/update-index.c:721 +msgid "refresh: ignore submodules" +msgstr "Aktualisierung: ignoriert Unterprojekte" -#: parse-options.h:141 -msgid "time" -msgstr "Zeit" +#: builtin/update-index.c:724 +msgid "do not ignore new files" +msgstr "ignoriert keine neuen Dateien" -#: parse-options.h:149 -msgid "file" -msgstr "Datei" +#: builtin/update-index.c:726 +msgid "let files replace directories and vice-versa" +msgstr "lässt Dateien Verzeichnisse ersetzen, und umgedreht" -#: parse-options.h:151 -msgid "when" -msgstr "wann" +#: builtin/update-index.c:728 +msgid "notice files missing from worktree" +msgstr "beachtet fehlende Dateien im Arbeitsbaum" + +#: builtin/update-index.c:730 +msgid "refresh even if index contains unmerged entries" +msgstr "" +"aktualisiert, auch wenn die Bereitstellung nicht zusammengeführte Einträge " +"beinhaltet" + +#: builtin/update-index.c:733 +msgid "refresh stat information" +msgstr "aktualisiert Dateiinformationen" + +#: builtin/update-index.c:737 +msgid "like --refresh, but ignore assume-unchanged setting" +msgstr "wie --refresh, ignoriert aber \"assume-unchanged\" Einstellung" + +#: builtin/update-index.c:741 +msgid "<mode> <object> <path>" +msgstr "<Modus> <Objekt> <Pfad>" + +#: builtin/update-index.c:742 +msgid "add the specified entry to the index" +msgstr "stellt den angegebenen Eintrag zur Eintragung bereit" + +#: builtin/update-index.c:746 +msgid "(+/-)x" +msgstr "(+/-)x" + +#: builtin/update-index.c:747 +msgid "override the executable bit of the listed files" +msgstr "überschreibt das \"ausführbar\"-Bit der aufgelisteten Dateien" + +#: builtin/update-index.c:751 +msgid "mark files as \"not changing\"" +msgstr "betrachte diese Datei immer als unverändert" + +#: builtin/update-index.c:754 +msgid "clear assumed-unchanged bit" +msgstr "löscht \"assumed-unchanged\"-Bit" + +#: builtin/update-index.c:757 +msgid "mark files as \"index-only\"" +msgstr "markiert Dateien als \"index-only\"" + +#: builtin/update-index.c:760 +msgid "clear skip-worktree bit" +msgstr "löscht \"skip-worktree\"-Bit" + +#: builtin/update-index.c:763 +msgid "add to index only; do not add content to object database" +msgstr "" +"fügt nur der Bereitstellung hinzu; Inhalt wird nicht der Objekt-Datenbank " +"hinzugefügt" + +#: builtin/update-index.c:765 +msgid "remove named paths even if present in worktree" +msgstr "löscht benannte Pfade, auch wenn sie sich im Arbeitsbaum befinden" + +#: builtin/update-index.c:767 +msgid "with --stdin: input lines are terminated by null bytes" +msgstr "mit --stdin: eingegebene Zeilen sind durch NUL-Bytes abgeschlossen" + +#: builtin/update-index.c:769 +msgid "read list of paths to be updated from standard input" +msgstr "liest Liste der zu aktualisierenden Pfade von der Standard-Eingabe" + +#: builtin/update-index.c:773 +msgid "add entries from standard input to the index" +msgstr "fügt Einträge von der Standard-Eingabe der Bereitstellung hinzu" + +#: builtin/update-index.c:777 +msgid "repopulate stages #2 and #3 for the listed paths" +msgstr "" +"wiederholtes Einpflegen der Zustände #2 und #3 für die aufgelisteten Pfade" + +#: builtin/update-index.c:781 +msgid "only update entries that differ from HEAD" +msgstr "" +"aktualisiert nur Einträge, die unterschiedlich zur Zweigspitze (HEAD) sind" + +#: builtin/update-index.c:785 +msgid "ignore files missing from worktree" +msgstr "ignoriert fehlende Dateien im Arbeitsbaum" + +#: builtin/update-index.c:788 +msgid "report actions to standard output" +msgstr "gibt die Aktionen in der Standard-Ausgabe aus" + +#: builtin/update-index.c:790 +msgid "(for porcelains) forget saved unresolved conflicts" +msgstr "(für Fremdprogramme) keine gespeicherten, nicht aufgelöste Konflikte" + +#: builtin/update-index.c:794 +msgid "write index in this format" +msgstr "schreibt Bereitstellungsdatei in diesem Format" + +#: builtin/update-ref.c:7 +msgid "git update-ref [options] -d <refname> [<oldval>]" +msgstr "git update-ref [Optionen] -d <Referenzname> [<alterWert>]" + +#: builtin/update-ref.c:8 +msgid "git update-ref [options] <refname> <newval> [<oldval>]" +msgstr "git update-ref [Optionen] <Referenzname> <neuerWert> [<alterWert>]" + +#: builtin/update-ref.c:19 +msgid "delete the reference" +msgstr "löscht diese Referenz" + +#: builtin/update-ref.c:21 +msgid "update <refname> not the one it points to" +msgstr "aktualisiert <Referenzname>, nicht den Verweis" + +#: builtin/update-server-info.c:6 +msgid "git update-server-info [--force]" +msgstr "git update-server-info [--force]" + +#: builtin/update-server-info.c:14 +msgid "update the info files from scratch" +msgstr "aktualisiert die Informationsdateien von Grund auf" + +#: builtin/verify-pack.c:56 +msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..." +msgstr "git verify-pack [-v|--verbose] [-s|--stat-only] <Paket>..." + +#: builtin/verify-pack.c:66 +msgid "verbose" +msgstr "erweiterte Ausgaben" + +#: builtin/verify-pack.c:68 +msgid "show statistics only" +msgstr "zeigt nur Statistiken" + +#: builtin/verify-tag.c:17 +msgid "git verify-tag [-v|--verbose] <tag>..." +msgstr "git verify-tag [-v|--verbose] <Markierung>..." + +#: builtin/verify-tag.c:73 +msgid "print tag contents" +msgstr "gibt Markierungsinhalte aus" + +#: builtin/write-tree.c:13 +msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]" +msgstr "git write-tree [--missing-ok] [--prefix=<Prefix>/]" + +#: builtin/write-tree.c:26 +msgid "<prefix>/" +msgstr "<Prefix>/" + +#: builtin/write-tree.c:27 +msgid "write tree object for a subdirectory <prefix>" +msgstr "schreibt das Baumobjekt für ein Unterverzeichnis <Prefix>" + +#: builtin/write-tree.c:30 +msgid "only useful for debugging" +msgstr "nur nützlich für Fehlersuche" + +#: git.c:16 +msgid "See 'git help <command>' for more information on a specific command." +msgstr "" +"Siehe 'git help <Kommando>' für weitere Informationen zu einem spezifischen " +"Kommando" #: parse-options.h:156 msgid "no-op (backward compatibility)" @@ -4941,14 +8804,15 @@ msgstr "" #: git-am.sh:105 #, sh-format msgid "" -"When you have resolved this problem run \"$cmdline --resolved\".\n" -"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n" -"To restore the original branch and stop patching run \"$cmdline --abort\"." -msgstr "" -"Wenn du das Problem aufgelöst hast, führe \"$cmdline --resolved\" aus.\n" -"Falls du diesen Patch auslassen möchtest, führe stattdessen " -"\"$cmdline --skip\" aus.\n" -"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der Patches\n" +"When you have resolved this problem, run \"$cmdline --resolved\".\n" +"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n" +"To restore the original branch and stop patching, run \"$cmdline --abort\"." +msgstr "" +"Wenn du das Problem gelöst hast, führe \"$cmdline --resolved\" aus.\n" +"Falls du diesen Patch auslassen möchtest, führe stattdessen \"$cmdline --skip" +"\" aus.\n" +"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der " +"Patches\n" "abzubrechen, führe \"$cmdline --abort\" aus." #: git-am.sh:121 @@ -4961,6 +8825,12 @@ msgstr "" "Dem Projektarchiv fehlen notwendige Blobs um auf eine 3-Wege-Zusammenführung " "zurückzufallen." +#: git-am.sh:139 +msgid "Using index info to reconstruct a base tree..." +msgstr "" +"Verwende Informationen aus der Bereitstellung um einen Basisbaum " +"nachzustellen" + #: git-am.sh:154 msgid "" "Did you hand edit your patch?\n" @@ -4973,45 +8843,53 @@ msgstr "" msgid "Falling back to patching base and 3-way merge..." msgstr "Falle zurück zum Patchen der Basis und der 3-Wege-Zusammenführung..." -#: git-am.sh:275 +#: git-am.sh:179 +msgid "Failed to merge in the changes." +msgstr "Zusammenführung der Änderungen fehlgeschlagen" + +#: git-am.sh:274 msgid "Only one StGIT patch series can be applied at once" msgstr "Es kann nur eine StGIT Patch-Serie auf einmal angewendet werden." -#: git-am.sh:362 +#: git-am.sh:361 #, sh-format msgid "Patch format $patch_format is not supported." msgstr "Patch-Format $patch_format wird nicht unterstützt." -#: git-am.sh:364 +#: git-am.sh:363 msgid "Patch format detection failed." msgstr "Patch-Formaterkennung fehlgeschlagen." -#: git-am.sh:418 -msgid "-d option is no longer supported. Do not use." -msgstr "-d Option wird nicht länger unterstützt. Nicht benutzen." +#: git-am.sh:389 +msgid "" +"The -b/--binary option has been a no-op for long time, and\n" +"it will be removed. Please do not use it anymore." +msgstr "" +"Die -b/--binary Option hat seit Langem keinen Effekt und wird\n" +"entfernt. Bitte nicht mehr verwenden." -#: git-am.sh:481 +#: git-am.sh:477 #, sh-format msgid "previous rebase directory $dotest still exists but mbox given." msgstr "" "Vorheriges Verzeichnis des Neuaufbaus $dotest existiert noch, aber mbox " "gegeben." -#: git-am.sh:486 +#: git-am.sh:482 msgid "Please make up your mind. --skip or --abort?" msgstr "Bitte werde dir klar. --skip oder --abort?" -#: git-am.sh:513 +#: git-am.sh:509 msgid "Resolve operation not in progress, we are not resuming." msgstr "Es ist keine Auflösung im Gange, es wird nicht fortgesetzt." -#: git-am.sh:579 +#: git-am.sh:575 #, sh-format msgid "Dirty index: cannot apply patches (dirty: $files)" msgstr "" "Unsaubere Bereitstellung: kann Patches nicht anwenden (unsauber: $files)" -#: git-am.sh:671 +#: git-am.sh:679 #, sh-format msgid "" "Patch is empty. Was it split wrong?\n" @@ -5019,38 +8897,39 @@ msgid "" "To restore the original branch and stop patching run \"$cmdline --abort\"." msgstr "" "Patch ist leer. Wurde er falsch aufgeteilt?\n" -"Wenn du diesen Patch auslassen möchtest, führe stattdessen " -"\"$cmdline --skip\" aus.\n" -"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der Patches\n" +"Wenn du diesen Patch auslassen möchtest, führe stattdessen \"$cmdline --skip" +"\" aus.\n" +"Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der " +"Patches\n" "abzubrechen, führe \"$cmdline --abort\" aus." -#: git-am.sh:708 +#: git-am.sh:706 msgid "Patch does not have a valid e-mail address." -msgstr "Patch enthält keine gültige eMail-Adresse." +msgstr "Patch enthält keine gültige Email-Adresse." -#: git-am.sh:755 +#: git-am.sh:753 msgid "cannot be interactive without stdin connected to a terminal." msgstr "" "Kann nicht interaktiv sein, ohne dass die Standard-Eingabe mit einem " "Terminal verbunden ist." -#: git-am.sh:759 +#: git-am.sh:757 msgid "Commit Body is:" msgstr "Beschreibung der Eintragung ist:" #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] #. in your translation. The program will only accept English #. input at this point. -#: git-am.sh:766 +#: git-am.sh:764 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " msgstr "Anwenden? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " -#: git-am.sh:802 +#: git-am.sh:800 #, sh-format msgid "Applying: $FIRSTLINE" msgstr "Wende an: $FIRSTLINE" -#: git-am.sh:823 +#: git-am.sh:821 msgid "" "No changes - did you forget to use 'git add'?\n" "If there is nothing left to stage, chances are that something else\n" @@ -5061,7 +8940,7 @@ msgstr "" "diese bereits anderweitig eingefügt worden sein; du könntest diesen Patch\n" "auslassen." -#: git-am.sh:831 +#: git-am.sh:829 msgid "" "You still have unmerged paths in your index\n" "did you forget to use 'git add'?" @@ -5069,16 +8948,25 @@ msgstr "" "Du hast immer noch nicht zusammengeführte Pfade in der Bereitstellung.\n" "Hast du vergessen 'git add' zu benutzen?" -#: git-am.sh:847 +#: git-am.sh:845 msgid "No changes -- Patch already applied." msgstr "Keine Änderungen -- Patches bereits angewendet." -#: git-am.sh:857 +#: git-am.sh:855 #, sh-format msgid "Patch failed at $msgnum $FIRSTLINE" msgstr "Anwendung des Patches fehlgeschlagen bei $msgnum $FIRSTLINE" -#: git-am.sh:873 +#: git-am.sh:858 +#, sh-format +msgid "" +"The copy of the patch that failed is found in:\n" +" $dotest/patch" +msgstr "" +"Die Kopie des fehlgeschlagenen Patches befindet sich in:\n" +" $dotest/patch" + +#: git-am.sh:876 msgid "applying to an empty history" msgstr "wende zu leerer Historie an" @@ -5265,7 +9153,7 @@ msgstr "" #. The working tree and the index file is still based on the #. $orig_head commit, but we are merging into $curr_head. #. First update the working tree to match $curr_head. -#: git-pull.sh:228 +#: git-pull.sh:229 #, sh-format msgid "" "Warning: fetch updated the current branch head.\n" @@ -5275,14 +9163,144 @@ msgstr "" "Warnung: Die Anforderung aktualisierte die Spitze des aktuellen Zweiges.\n" "Warnung: Spule deinen Arbeitszweig von Version $orig_head vor." -#: git-pull.sh:253 +#: git-pull.sh:254 msgid "Cannot merge multiple branches into empty head" msgstr "Kann nicht mehrere Zweige in einen ungeborenen Zweig zusammenführen" -#: git-pull.sh:257 +#: git-pull.sh:258 msgid "Cannot rebase onto multiple branches" msgstr "kann nicht auf mehrere Zweige neu aufbauen" +#: git-rebase.sh:53 +msgid "" +"When you have resolved this problem, run \"git rebase --continue\".\n" +"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n" +"To check out the original branch and stop rebasing, run \"git rebase --abort" +"\"." +msgstr "" +"Wenn du das Problem aufgelöst hast, führe \"git rebase --continue\" aus.\n" +"Falls du diesen Patch auslassen möchtest, führe stattdessen \"git rebase --" +"skip\" aus.\n" +"Um den ursprünglichen Zweig wiederherzustellen und den Neuaufbau " +"abzubrechen,\n" +"führe \"git rebase --abort\" aus." + +#: git-rebase.sh:160 +msgid "The pre-rebase hook refused to rebase." +msgstr "Der \"pre-rebase hook\" hat den Neuaufbau zurückgewiesen." + +#: git-rebase.sh:165 +msgid "It looks like git-am is in progress. Cannot rebase." +msgstr "\"git-am\" scheint im Gange zu sein. Kann nicht neu aufbauen." + +#: git-rebase.sh:296 +msgid "The --exec option must be used with the --interactive option" +msgstr "Die --exec Option muss mit der --interactive Option benutzt werden" + +#: git-rebase.sh:301 +msgid "No rebase in progress?" +msgstr "Kein Neuaufbau im Gange?" + +#: git-rebase.sh:312 +msgid "The --edit-todo action can only be used during interactive rebase." +msgstr "Die --edit-todo Aktion kann nur während eines interaktiven " +"Neuaufbaus benutzt werden." + +#: git-rebase.sh:319 +msgid "Cannot read HEAD" +msgstr "Kann Zweigspitze (HEAD) nicht lesen" + +#: git-rebase.sh:322 +msgid "" +"You must edit all merge conflicts and then\n" +"mark them as resolved using git add" +msgstr "" +"Du musst alle Zusammenführungskonflikte editieren und diese dann\n" +"mittels \"git add\" als aufgelöst markieren" + +#: git-rebase.sh:340 +#, sh-format +msgid "Could not move back to $head_name" +msgstr "Konnte nicht zu $head_name zurückgehen" + +#: git-rebase.sh:359 +#, sh-format +msgid "" +"It seems that there is already a $state_dir_base directory, and\n" +"I wonder if you are in the middle of another rebase. If that is the\n" +"case, please try\n" +"\t$cmd_live_rebase\n" +"If that is not the case, please\n" +"\t$cmd_clear_stale_rebase\n" +"and run me again. I am stopping in case you still have something\n" +"valuable there." +msgstr "" +"Es sieht so aus, als ob es das Verzeichnis $state_dir_base bereits gibt\n" +"und es könnte ein anderer Neuaufbau im Gange sein. Wenn das der Fall ist,\n" +"probiere bitte\n" +"\t$cmd_live_rebase\n" +"Wenn das nicht der Fall ist, probiere bitte\n" +"\t$cmd_clear_stale_rebase\n" +"und führe dieses Kommando nochmal aus. Es wird angehalten, falls noch\n" +"etwas Schützenswertes vorhanden ist." + +#: git-rebase.sh:404 +#, sh-format +msgid "invalid upstream $upstream_name" +msgstr "ungültiger Übernahmezweig $upstream_name" + +#: git-rebase.sh:428 +#, sh-format +msgid "$onto_name: there are more than one merge bases" +msgstr "$onto_name: es gibt mehr als eine Zusammenführungsbasis" + +#: git-rebase.sh:431 git-rebase.sh:435 +#, sh-format +msgid "$onto_name: there is no merge base" +msgstr "$onto_name: es gibt keine Zusammenführungsbasis" + +#: git-rebase.sh:440 +#, sh-format +msgid "Does not point to a valid commit: $onto_name" +msgstr "$onto_name zeigt auf keine gültige Version" + +#: git-rebase.sh:463 +#, sh-format +msgid "fatal: no such branch: $branch_name" +msgstr "fatal: Zweig $branch_name nicht gefunden" + +#: git-rebase.sh:483 +msgid "Please commit or stash them." +msgstr "Bitte trage die Änderungen ein oder benutze \"stash\"." + +#: git-rebase.sh:501 +#, sh-format +msgid "Current branch $branch_name is up to date." +msgstr "Aktueller Zweig $branch_name ist auf dem neusten Stand." + +#: git-rebase.sh:504 +#, sh-format +msgid "Current branch $branch_name is up to date, rebase forced." +msgstr "" +"Aktueller Zweig $branch_name ist auf dem neusten Stand, Neuaufbau erzwungen." + +#: git-rebase.sh:515 +#, sh-format +msgid "Changes from $mb to $onto:" +msgstr "Änderungen von $mb zu $onto:" + +#. Detach HEAD and reset the tree +#: git-rebase.sh:524 +msgid "First, rewinding head to replay your work on top of it..." +msgstr "" +"Zunächst wird die Zweigspitze zurückgespult, um deine Änderungen\n" +"darauf neu anzuwenden..." + +#: git-rebase.sh:532 +#, sh-format +msgid "Fast-forwarded $branch_name to $onto_name." +msgstr "$branch_name zu $onto_name vorgespult." + #: git-stash.sh:51 msgid "git stash clear with parameters is unimplemented" msgstr "git stash clear mit Parametern ist nicht implementiert" @@ -5305,7 +9323,7 @@ msgstr "Keine Änderungen ausgewählt" #: git-stash.sh:143 msgid "Cannot remove temporary index (can't happen)" -msgstr "Kann temporäre Bereitstellung nicht entfernen (kann nicht passieren)" +msgstr "Kann temporäre Bereitstellung nicht löschen (kann nicht passieren)" #: git-stash.sh:156 msgid "Cannot record working tree state" @@ -5345,7 +9363,7 @@ msgstr "Kann den aktuellen Status nicht speichern" #: git-stash.sh:253 msgid "Cannot remove worktree changes" -msgstr "Kann Änderungen am Arbeitsbaum nicht entfernen" +msgstr "Kann Änderungen am Arbeitsbaum nicht löschen" #: git-stash.sh:352 msgid "No stash found." @@ -5392,131 +9410,166 @@ msgstr "Konnte Bereitstellungsbaum nicht speichern" msgid "Cannot unstage modified files" msgstr "Kann geänderte Dateien nicht aus der Bereitstellung herausnehmen" -#: git-stash.sh:474 +#: git-stash.sh:475 msgid "Index was not unstashed." msgstr "Bereitstellung wurde nicht ausgelagert." -#: git-stash.sh:491 +#: git-stash.sh:492 #, sh-format msgid "Dropped ${REV} ($s)" msgstr "Gelöscht ${REV} ($s)" -#: git-stash.sh:492 +#: git-stash.sh:493 #, sh-format msgid "${REV}: Could not drop stash entry" msgstr "${REV}: Konnte \"stash\"-Eintrag nicht löschen" -#: git-stash.sh:499 +#: git-stash.sh:500 msgid "No branch name specified" msgstr "Kein Zweigname spezifiziert" -#: git-stash.sh:570 +#: git-stash.sh:571 msgid "(To restore them type \"git stash apply\")" msgstr "(Zur Wiederherstellung gebe \"git stash apply\" ein)" -#: git-submodule.sh:56 +#: git-submodule.sh:89 #, sh-format msgid "cannot strip one component off url '$remoteurl'" msgstr "Kann eine Komponente von URL '$remoteurl' nicht extrahieren" -#: git-submodule.sh:109 +#: git-submodule.sh:168 #, sh-format msgid "No submodule mapping found in .gitmodules for path '$sm_path'" msgstr "" "Keine Unterprojekt-Zuordnung in .gitmodules für Pfad '$sm_path' gefunden" -#: git-submodule.sh:150 +#: git-submodule.sh:211 #, sh-format msgid "Clone of '$url' into submodule path '$sm_path' failed" msgstr "Klonen von '$url' in Unterprojekt-Pfad '$sm_path' fehlgeschlagen" -#: git-submodule.sh:160 +#: git-submodule.sh:223 #, sh-format msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa" msgstr "" "Git-Verzeichnis '$a' ist Teil des Unterprojekt-Pfades '$b', oder umgekehrt" -#: git-submodule.sh:249 +#: git-submodule.sh:316 #, sh-format msgid "repo URL: '$repo' must be absolute or begin with ./|../" msgstr "repo URL: '$repo' muss absolut sein oder mit ./|../ beginnen" -#: git-submodule.sh:266 +#: git-submodule.sh:333 #, sh-format msgid "'$sm_path' already exists in the index" msgstr "'$sm_path' existiert bereits in der Bereitstellung" -#: git-submodule.sh:270 +#: git-submodule.sh:337 #, sh-format msgid "" "The following path is ignored by one of your .gitignore files:\n" "$sm_path\n" "Use -f if you really want to add it." msgstr "" -"Der folgende Pfad wird durch eine deiner \".gitignore\" Dateien " -"ignoriert:\n" +"Der folgende Pfad wird durch eine deiner \".gitignore\" Dateien ignoriert:\n" "$sm_path\n" "Benutze -f wenn du diesen wirklich hinzufügen möchtest." -#: git-submodule.sh:281 +#: git-submodule.sh:355 #, sh-format msgid "Adding existing repo at '$sm_path' to the index" -msgstr "Füge existierendes Projektarchiv in '$sm_path' der Bereitstellung " -"hinzu." +msgstr "" +"Füge existierendes Projektarchiv in '$sm_path' der Bereitstellung hinzu." -#: git-submodule.sh:283 +#: git-submodule.sh:357 #, sh-format msgid "'$sm_path' already exists and is not a valid git repo" msgstr "'$sm_path' existiert bereits und ist kein gültiges Git-Projektarchiv" -#: git-submodule.sh:297 +#: git-submodule.sh:365 +#, sh-format +msgid "A git directory for '$sm_name' is found locally with remote(s):" +msgstr "Ein Git-Verzeichnis für '$sm_name' wurde lokal gefunden mit den " +"Fernarchiv(en):" + +#: git-submodule.sh:367 +#, sh-format +msgid "" +"If you want to reuse this local git directory instead of cloning again from" +msgstr "" +"Wenn du dieses lokale Git-Verzeichnis wiederverwenden möchtest, anstatt " +"erneut zu klonen" + +#: git-submodule.sh:369 +#, sh-format +msgid "" +"use the '--force' option. If the local git directory is not the correct repo" +msgstr "" +"benutze die Option '--force'. Wenn das lokale Git-Verzeichnis nicht das " +"korrekte Projektarchiv ist" + +#: git-submodule.sh:370 +#, sh-format +msgid "" +"or you are unsure what this means choose another name with the '--name' " +"option." +msgstr "" +"oder du dir unsicher bist, was das bedeutet, wähle einen anderen Namen mit " +"der Option '--name'." + +#: git-submodule.sh:372 +#, sh-format +msgid "Reactivating local git directory for submodule '$sm_name'." +msgstr "Reaktiviere lokales Git-Verzeichnis für Unterprojekt '$sm_name'." + +#: git-submodule.sh:384 #, sh-format msgid "Unable to checkout submodule '$sm_path'" msgstr "Unfähig Unterprojekt '$sm_path' auszuchecken" -#: git-submodule.sh:302 +#: git-submodule.sh:389 #, sh-format msgid "Failed to add submodule '$sm_path'" msgstr "Hinzufügen von Unterprojekt '$sm_path' fehlgeschlagen" -#: git-submodule.sh:307 +#: git-submodule.sh:394 #, sh-format msgid "Failed to register submodule '$sm_path'" msgstr "Registierung von Unterprojekt '$sm_path' fehlgeschlagen" -#: git-submodule.sh:349 +#: git-submodule.sh:437 #, sh-format msgid "Entering '$prefix$sm_path'" msgstr "Betrete '$prefix$sm_path'" -#: git-submodule.sh:363 +#: git-submodule.sh:451 #, sh-format msgid "Stopping at '$sm_path'; script returned non-zero status." msgstr "Stoppe bei '$sm_path'; Skript gab nicht-Null Status zurück." -#: git-submodule.sh:406 +#: git-submodule.sh:495 #, sh-format msgid "No url found for submodule path '$sm_path' in .gitmodules" msgstr "Keine URL für Unterprojekt-Pfad '$sm_path' in .gitmodules gefunden" -#: git-submodule.sh:415 +#: git-submodule.sh:504 #, sh-format msgid "Failed to register url for submodule path '$sm_path'" msgstr "Registrierung der URL für Unterprojekt-Pfad '$sm_path' fehlgeschlagen" -#: git-submodule.sh:417 +#: git-submodule.sh:506 #, sh-format msgid "Submodule '$name' ($url) registered for path '$sm_path'" msgstr "Unterprojekt '$name' ($url) ist für Pfad '$sm_path' registriert" -#: git-submodule.sh:425 +#: git-submodule.sh:514 #, sh-format msgid "Failed to register update mode for submodule path '$sm_path'" msgstr "" "Registrierung des Aktualisierungsmodus für Unterprojekt-Pfad '$sm_path' " "fehlgeschlagen" -#: git-submodule.sh:524 +#: git-submodule.sh:614 #, sh-format msgid "" "Submodule path '$sm_path' not initialized\n" @@ -5525,98 +9578,168 @@ msgstr "" "Unterprojekt-Pfad '$sm_path' ist nicht initialisiert\n" "Vielleicht möchtest du 'update --init' benutzen?" -#: git-submodule.sh:537 +#: git-submodule.sh:627 #, sh-format msgid "Unable to find current revision in submodule path '$sm_path'" msgstr "Konnte aktuelle Version in Unterprojekt-Pfad '$sm_path' nicht finden" -#: git-submodule.sh:556 +#: git-submodule.sh:646 #, sh-format msgid "Unable to fetch in submodule path '$sm_path'" msgstr "Konnte in Unterprojekt-Pfad '$sm_path' nicht anfordern" -#: git-submodule.sh:570 +#: git-submodule.sh:660 #, sh-format msgid "Unable to rebase '$sha1' in submodule path '$sm_path'" msgstr "Neuaufbau von '$sha1' in Unterprojekt-Pfad '$sm_path' nicht möglich" -#: git-submodule.sh:571 +#: git-submodule.sh:661 #, sh-format msgid "Submodule path '$sm_path': rebased into '$sha1'" msgstr "Unterprojekt-Pfad '$sm_path': neu aufgebaut in '$sha1'" -#: git-submodule.sh:576 +#: git-submodule.sh:666 #, sh-format msgid "Unable to merge '$sha1' in submodule path '$sm_path'" msgstr "" "Zusammenführung von '$sha1' in Unterprojekt-Pfad '$sm_path' fehlgeschlagen" -#: git-submodule.sh:577 +#: git-submodule.sh:667 #, sh-format msgid "Submodule path '$sm_path': merged in '$sha1'" msgstr "Unterprojekt-Pfad '$sm_path': zusammengeführt in '$sha1'" -#: git-submodule.sh:582 +#: git-submodule.sh:672 #, sh-format msgid "Unable to checkout '$sha1' in submodule path '$sm_path'" msgstr "Konnte '$sha1' in Unterprojekt-Pfad '$sm_path' nicht auschecken." -#: git-submodule.sh:583 +#: git-submodule.sh:673 #, sh-format msgid "Submodule path '$sm_path': checked out '$sha1'" msgstr "Unterprojekt-Pfad: '$sm_path': '$sha1' ausgecheckt" -#: git-submodule.sh:605 git-submodule.sh:928 +#: git-submodule.sh:695 git-submodule.sh:1017 #, sh-format msgid "Failed to recurse into submodule path '$sm_path'" msgstr "Fehler bei Rekursion in Unterprojekt-Pfad '$sm_path'" -#: git-submodule.sh:713 -msgid "--cached cannot be used with --files" -msgstr "--cached kann nicht mit --files benutzt werden" +#: git-submodule.sh:803 +msgid "The --cached option cannot be used with the --files option" +msgstr "Die --cached Option kann nicht mit der --files Option benutzt werden" #. unexpected type -#: git-submodule.sh:753 +#: git-submodule.sh:843 #, sh-format msgid "unexpected mode $mod_dst" msgstr "unerwarteter Modus $mod_dst" -#: git-submodule.sh:771 +#: git-submodule.sh:861 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_src" msgstr " Warnung: $name beinhaltet nicht Version $sha1_src" -#: git-submodule.sh:774 +#: git-submodule.sh:864 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_dst" msgstr " Warnung: $name beinhaltet nicht Version $sha1_dst" -#: git-submodule.sh:777 +#: git-submodule.sh:867 #, sh-format msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst" msgstr "" " Warnung: $name beinhaltet nicht die Versionen $sha1_src und $sha1_dst" -#: git-submodule.sh:802 +#: git-submodule.sh:892 msgid "blob" msgstr "Blob" -#: git-submodule.sh:803 -msgid "submodule" -msgstr "Unterprojekt" - -#: git-submodule.sh:840 +#: git-submodule.sh:930 msgid "# Submodules changed but not updated:" msgstr "# Unterprojekte geändert, aber nicht aktualisiert:" -#: git-submodule.sh:842 +#: git-submodule.sh:932 msgid "# Submodule changes to be committed:" msgstr "# Änderungen in Unterprojekt zum Eintragen:" -#: git-submodule.sh:974 +#: git-submodule.sh:1080 #, sh-format -msgid "Synchronizing submodule url for '$name'" -msgstr "Synchronisiere Unterprojekt-URL für '$name'" +msgid "Synchronizing submodule url for '$prefix$sm_path'" +msgstr "Synchronisiere Unterprojekt-URL für '$prefix$sm_path'" + +#~ msgid " 0 files changed" +#~ msgstr " 0 Dateien geändert" + +#~ msgid " %d file changed" +#~ msgid_plural " %d files changed" +#~ msgstr[0] " %d Datei geändert" +#~ msgstr[1] " %d Dateien geändert" + +#~ msgid ", %d insertion(+)" +#~ msgid_plural ", %d insertions(+)" +#~ msgstr[0] ", %d Zeile hinzugefügt(+)" +#~ msgstr[1] ", %d Zeilen hinzugefügt(+)" + +#~ msgid ", %d deletion(-)" +#~ msgid_plural ", %d deletions(-)" +#~ msgstr[0] ", %d Zeile entfernt(-)" +#~ msgstr[1] ", %d Zeilen entfernt(-)" + +#~ msgid "Auto packing the repository for optimum performance.\n" +#~ msgstr "" +#~ "Die Datenbank des Projektarchivs wird für eine optimale Performance " +#~ "komprimiert.\n" + +#~ msgid "git remote set-head <name> (-a | -d | <branch>])" +#~ msgstr "git remote set-head <Name> (-a | -d | <Zweig>])" + +#~ msgid " (use \"git add\" to track)" +#~ msgstr " (benutze \"git add\" zum Beobachten)" + +#~ msgid "-B cannot be used with -b" +#~ msgstr "-B kann nicht mit -b benutzt werden" + +#~ msgid "--patch is incompatible with all other options" +#~ msgstr "--patch ist inkompatibel mit allen anderen Optionen" + +#~ msgid "--detach cannot be used with -b/-B/--orphan" +#~ msgstr "--detach kann nicht mit -b/-B/--orphan benutzt werden" + +#~ msgid "--detach cannot be used with -t" +#~ msgstr "--detach kann nicht mit -t benutzt werden" + +#~ msgid "--orphan and -b|-B are mutually exclusive" +#~ msgstr "--orphan und -b|-B sind gegenseitig exklusiv" + +#~ msgid "--orphan cannot be used with -t" +#~ msgstr "--orphan kann nicht mit -t benutzt werden" + +#~ msgid "git checkout: -f and -m are incompatible" +#~ msgstr "git checkout: -f und -m sind inkompatibel" + +#~ msgid "" +#~ "git checkout: updating paths is incompatible with switching branches." +#~ msgstr "" +#~ "git checkout: Die Aktualisierung von Pfaden ist inkompatibel mit dem " +#~ "Wechsel von Zweigen." + +#~ msgid "diff setup failed" +#~ msgstr "diff_setup_done fehlgeschlagen" + +#~ msgid "merge-recursive: disk full?" +#~ msgstr "merge-recursive: Festplatte voll?" + +#~ msgid "diff_setup_done failed" +#~ msgstr "diff_setup_done fehlgeschlagen" + +#~ msgid "-d option is no longer supported. Do not use." +#~ msgstr "-d Option wird nicht länger unterstützt. Nicht benutzen." + +#~ msgid "%s: has been deleted/renamed" +#~ msgstr "%s wurde gelöscht/umbenannt" + +#~ msgid "'%s': not a documentation directory." +#~ msgstr "'%s' ist kein Dokumentationsverzeichnis" #~ msgid "--" #~ msgstr "--" @@ -5630,9 +9753,6 @@ msgstr "Synchronisiere Unterprojekt-URL für '$name'" #~ msgid "Please enter the commit message for your changes." #~ msgstr "Bitte gebe die Versionsbeschreibung für deine Änderungen ein." -#~ msgid "Too many options specified" -#~ msgstr "Zu viele Optionen angegeben" - #~ msgid "" #~ "To prevent you from losing history, non-fast-forward updates were " #~ "rejected\n" diff --git a/po/git.pot b/po/git.pot index b6665060d..430d033aa 100644 --- a/po/git.pot +++ b/po/git.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2012-06-08 10:20+0800\n" +"POT-Creation-Date: 2012-11-30 12:40+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -35,6 +35,97 @@ msgid "" "or use 'git commit -a'." msgstr "" +#: archive.c:10 +msgid "git archive [options] <tree-ish> [<path>...]" +msgstr "" + +#: archive.c:11 +msgid "git archive --list" +msgstr "" + +#: archive.c:12 +msgid "" +"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]" +msgstr "" + +#: archive.c:13 +msgid "git archive --remote <repo> [--exec <cmd>] --list" +msgstr "" + +#: archive.c:322 +msgid "fmt" +msgstr "" + +#: archive.c:322 +msgid "archive format" +msgstr "" + +#: archive.c:323 builtin/log.c:1084 +msgid "prefix" +msgstr "" + +#: archive.c:324 +msgid "prepend prefix to each pathname in the archive" +msgstr "" + +#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2390 +#: builtin/blame.c:2391 builtin/config.c:55 builtin/fast-export.c:642 +#: builtin/fast-export.c:644 builtin/grep.c:715 builtin/hash-object.c:77 +#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:540 +#: builtin/notes.c:697 builtin/read-tree.c:107 parse-options.h:149 +msgid "file" +msgstr "" + +#: archive.c:326 builtin/archive.c:92 +msgid "write the archive to this file" +msgstr "" + +#: archive.c:328 +msgid "read .gitattributes in working directory" +msgstr "" + +#: archive.c:329 +msgid "report archived files on stderr" +msgstr "" + +#: archive.c:330 +msgid "store only" +msgstr "" + +#: archive.c:331 +msgid "compress faster" +msgstr "" + +#: archive.c:339 +msgid "compress better" +msgstr "" + +#: archive.c:342 +msgid "list supported archive formats" +msgstr "" + +#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85 +msgid "repo" +msgstr "" + +#: archive.c:345 builtin/archive.c:94 +msgid "retrieve the archive from remote repository <repo>" +msgstr "" + +#: archive.c:346 builtin/archive.c:95 builtin/notes.c:619 +msgid "command" +msgstr "" + +#: archive.c:347 builtin/archive.c:96 +msgid "path to the remote git-upload-archive command" +msgstr "" + +#: attr.c:259 +msgid "" +"Negative patterns are forbidden in git attributes\n" +"Use '\\!' for literal leading exclamation." +msgstr "" + #: bundle.c:36 #, c-format msgid "'%s' does not look like a v2 bundle file" @@ -45,7 +136,7 @@ msgstr "" msgid "unrecognized header: %s%s (%d)" msgstr "" -#: bundle.c:89 builtin/commit.c:696 +#: bundle.c:89 builtin/commit.c:674 #, c-format msgid "could not open '%s'" msgstr "" @@ -54,8 +145,8 @@ msgstr "" msgid "Repository lacks these prerequisite commits:" msgstr "" -#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:289 -#: builtin/log.c:720 builtin/log.c:1309 builtin/log.c:1528 builtin/merge.c:347 +#: bundle.c:164 sequencer.c:562 sequencer.c:994 builtin/log.c:290 +#: builtin/log.c:732 builtin/log.c:1319 builtin/log.c:1535 builtin/merge.c:347 #: builtin/shortlog.c:181 msgid "revision walk setup failed" msgstr "" @@ -68,53 +159,57 @@ msgstr[0] "" msgstr[1] "" #: bundle.c:192 +msgid "The bundle records a complete history." +msgstr "" + +#: bundle.c:195 #, c-format msgid "The bundle requires this ref" msgid_plural "The bundle requires these %d refs" msgstr[0] "" msgstr[1] "" -#: bundle.c:290 +#: bundle.c:294 msgid "rev-list died" msgstr "" -#: bundle.c:296 builtin/log.c:1205 builtin/shortlog.c:284 +#: bundle.c:300 builtin/log.c:1215 builtin/shortlog.c:284 #, c-format msgid "unrecognized argument: %s" msgstr "" -#: bundle.c:331 +#: bundle.c:335 #, c-format msgid "ref '%s' is excluded by the rev-list options" msgstr "" -#: bundle.c:376 +#: bundle.c:380 msgid "Refusing to create empty bundle." msgstr "" -#: bundle.c:394 +#: bundle.c:398 msgid "Could not spawn pack-objects" msgstr "" -#: bundle.c:412 +#: bundle.c:416 msgid "pack-objects died" msgstr "" -#: bundle.c:415 +#: bundle.c:419 #, c-format msgid "cannot create '%s'" msgstr "" -#: bundle.c:437 +#: bundle.c:441 msgid "index-pack died" msgstr "" -#: commit.c:48 +#: commit.c:50 #, c-format msgid "could not parse %s" msgstr "" -#: commit.c:50 +#: commit.c:52 #, c-format msgid "%s %s is not a commit!" msgstr "" @@ -204,55 +299,40 @@ msgid_plural "%lu years ago" msgstr[0] "" msgstr[1] "" -#: diff.c:105 +#: diff.c:111 +#, c-format +msgid " Failed to parse dirstat cut-off percentage '%s'\n" +msgstr "" + +#: diff.c:116 #, c-format -msgid " Failed to parse dirstat cut-off percentage '%.*s'\n" +msgid " Unknown dirstat parameter '%s'\n" msgstr "" -#: diff.c:110 +#: diff.c:194 #, c-format -msgid " Unknown dirstat parameter '%.*s'\n" +msgid "Unknown value for 'diff.submodule' config variable: '%s'" msgstr "" -#: diff.c:210 +#: diff.c:237 #, c-format msgid "" "Found errors in 'diff.dirstat' config variable:\n" "%s" msgstr "" -#: diff.c:1400 -msgid " 0 files changed\n" -msgstr "" - -#: diff.c:1404 -#, c-format -msgid " %d file changed" -msgid_plural " %d files changed" -msgstr[0] "" -msgstr[1] "" - -#: diff.c:1421 -#, c-format -msgid ", %d insertion(+)" -msgid_plural ", %d insertions(+)" -msgstr[0] "" -msgstr[1] "" - -#: diff.c:1432 -#, c-format -msgid ", %d deletion(-)" -msgid_plural ", %d deletions(-)" -msgstr[0] "" -msgstr[1] "" - -#: diff.c:3478 +#: diff.c:3494 #, c-format msgid "" "Failed to parse --dirstat/-X option parameter:\n" "%s" msgstr "" +#: diff.c:3508 +#, c-format +msgid "Failed to parse --submodule option parameter: '%s'" +msgstr "" + #: gpg-interface.c:59 msgid "could not run gpg." msgstr "" @@ -265,59 +345,59 @@ msgstr "" msgid "gpg failed to sign the data" msgstr "" -#: grep.c:1320 +#: grep.c:1622 #, c-format msgid "'%s': unable to read %s" msgstr "" -#: grep.c:1337 +#: grep.c:1639 #, c-format msgid "'%s': %s" msgstr "" -#: grep.c:1348 +#: grep.c:1650 #, c-format msgid "'%s': short read %s" msgstr "" -#: help.c:207 +#: help.c:212 #, c-format msgid "available git commands in '%s'" msgstr "" -#: help.c:214 +#: help.c:219 msgid "git commands available from elsewhere on your $PATH" msgstr "" -#: help.c:270 +#: help.c:275 #, c-format msgid "" "'%s' appears to be a git command, but we were not\n" "able to execute it. Maybe git-%s is broken?" msgstr "" -#: help.c:327 +#: help.c:332 msgid "Uh oh. Your system reports no Git commands at all." msgstr "" -#: help.c:349 +#: help.c:354 #, c-format msgid "" "WARNING: You called a Git command named '%s', which does not exist.\n" "Continuing under the assumption that you meant '%s'" msgstr "" -#: help.c:354 +#: help.c:359 #, c-format msgid "in %0.1f seconds automatically..." msgstr "" -#: help.c:361 +#: help.c:366 #, c-format msgid "git: '%s' is not a git command. See 'git --help'." msgstr "" -#: help.c:365 +#: help.c:370 msgid "" "\n" "Did you mean this?" @@ -327,35 +407,294 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: parse-options.c:493 +#: merge.c:56 +msgid "failed to read the cache" +msgstr "" + +#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534 +#: builtin/clone.c:586 +msgid "unable to write new index file" +msgstr "" + +#: merge-recursive.c:190 +#, c-format +msgid "(bad commit)\n" +msgstr "" + +#: merge-recursive.c:206 +#, c-format +msgid "addinfo_cache failed for path '%s'" +msgstr "" + +#: merge-recursive.c:268 +msgid "error building trees" +msgstr "" + +#: merge-recursive.c:672 +#, c-format +msgid "failed to create path '%s'%s" +msgstr "" + +#: merge-recursive.c:683 +#, c-format +msgid "Removing %s to make room for subdirectory\n" +msgstr "" + +#. something else exists +#. .. but not some other error (who really cares what?) +#: merge-recursive.c:697 merge-recursive.c:718 +msgid ": perhaps a D/F conflict?" +msgstr "" + +#: merge-recursive.c:708 +#, c-format +msgid "refusing to lose untracked file at '%s'" +msgstr "" + +#: merge-recursive.c:748 +#, c-format +msgid "cannot read object %s '%s'" +msgstr "" + +#: merge-recursive.c:750 +#, c-format +msgid "blob expected for %s '%s'" +msgstr "" + +#: merge-recursive.c:773 builtin/clone.c:302 +#, c-format +msgid "failed to open '%s'" +msgstr "" + +#: merge-recursive.c:781 +#, c-format +msgid "failed to symlink '%s'" +msgstr "" + +#: merge-recursive.c:784 +#, c-format +msgid "do not know what to do with %06o %s '%s'" +msgstr "" + +#: merge-recursive.c:922 +msgid "Failed to execute internal merge" +msgstr "" + +#: merge-recursive.c:926 +#, c-format +msgid "Unable to add %s to database" +msgstr "" + +#: merge-recursive.c:942 +msgid "unsupported object type in the tree" +msgstr "" + +#: merge-recursive.c:1021 merge-recursive.c:1035 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree." +msgstr "" + +#: merge-recursive.c:1027 merge-recursive.c:1040 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree at %s." +msgstr "" + +#: merge-recursive.c:1081 +msgid "rename" +msgstr "" + +#: merge-recursive.c:1081 +msgid "renamed" +msgstr "" + +#: merge-recursive.c:1137 +#, c-format +msgid "%s is a directory in %s adding as %s instead" +msgstr "" + +#: merge-recursive.c:1159 +#, c-format +msgid "" +"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s" +"\"->\"%s\" in \"%s\"%s" +msgstr "" + +#: merge-recursive.c:1164 +msgid " (left unresolved)" +msgstr "" + +#: merge-recursive.c:1218 +#, c-format +msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s" +msgstr "" + +#: merge-recursive.c:1248 +#, c-format +msgid "Renaming %s to %s and %s to %s instead" +msgstr "" + +#: merge-recursive.c:1447 +#, c-format +msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s" +msgstr "" + +#: merge-recursive.c:1457 +#, c-format +msgid "Adding merged %s" +msgstr "" + +#: merge-recursive.c:1462 merge-recursive.c:1660 +#, c-format +msgid "Adding as %s instead" +msgstr "" + +#: merge-recursive.c:1513 +#, c-format +msgid "cannot read object %s" +msgstr "" + +#: merge-recursive.c:1516 +#, c-format +msgid "object %s is not a blob" +msgstr "" + +#: merge-recursive.c:1564 +msgid "modify" +msgstr "" + +#: merge-recursive.c:1564 +msgid "modified" +msgstr "" + +#: merge-recursive.c:1574 +msgid "content" +msgstr "" + +#: merge-recursive.c:1581 +msgid "add/add" +msgstr "" + +#: merge-recursive.c:1615 +#, c-format +msgid "Skipped %s (merged same as existing)" +msgstr "" + +#: merge-recursive.c:1629 +#, c-format +msgid "Auto-merging %s" +msgstr "" + +#: merge-recursive.c:1633 git-submodule.sh:893 +msgid "submodule" +msgstr "" + +#: merge-recursive.c:1634 +#, c-format +msgid "CONFLICT (%s): Merge conflict in %s" +msgstr "" + +#: merge-recursive.c:1724 +#, c-format +msgid "Removing %s" +msgstr "" + +#: merge-recursive.c:1749 +msgid "file/directory" +msgstr "" + +#: merge-recursive.c:1755 +msgid "directory/file" +msgstr "" + +#: merge-recursive.c:1760 +#, c-format +msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s" +msgstr "" + +#: merge-recursive.c:1770 +#, c-format +msgid "Adding %s" +msgstr "" + +#: merge-recursive.c:1787 +msgid "Fatal merge failure, shouldn't happen." +msgstr "" + +#: merge-recursive.c:1806 +msgid "Already up-to-date!" +msgstr "" + +#: merge-recursive.c:1815 +#, c-format +msgid "merging of trees %s and %s failed" +msgstr "" + +#: merge-recursive.c:1845 +#, c-format +msgid "Unprocessed path??? %s" +msgstr "" + +#: merge-recursive.c:1890 +msgid "Merging:" +msgstr "" + +#: merge-recursive.c:1903 +#, c-format +msgid "found %u common ancestor:" +msgid_plural "found %u common ancestors:" +msgstr[0] "" +msgstr[1] "" + +#: merge-recursive.c:1940 +msgid "merge returned no commit" +msgstr "" + +#: merge-recursive.c:1997 +#, c-format +msgid "Could not parse object '%s'" +msgstr "" + +#: merge-recursive.c:2009 builtin/merge.c:643 +msgid "Unable to write index." +msgstr "" + +#: parse-options.c:494 msgid "..." msgstr "" -#: parse-options.c:511 +#: parse-options.c:512 #, c-format msgid "usage: %s" msgstr "" #. TRANSLATORS: the colon here should align with the #. one in "usage: %s" translation -#: parse-options.c:515 +#: parse-options.c:516 #, c-format msgid " or: %s" msgstr "" -#: parse-options.c:518 +#: parse-options.c:519 #, c-format msgid " %s" msgstr "" -#: remote.c:1629 +#: remote.c:1632 #, c-format msgid "Your branch is ahead of '%s' by %d commit.\n" msgid_plural "Your branch is ahead of '%s' by %d commits.\n" msgstr[0] "" msgstr[1] "" -#: remote.c:1635 +#: remote.c:1637 +msgid " (use \"git push\" to publish your local commits)\n" +msgstr "" + +#: remote.c:1640 #, c-format msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n" msgid_plural "" @@ -363,7 +702,11 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: remote.c:1643 +#: remote.c:1647 +msgid " (use \"git pull\" to update your local branch)\n" +msgstr "" + +#: remote.c:1650 #, c-format msgid "" "Your branch and '%s' have diverged,\n" @@ -374,505 +717,626 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: sequencer.c:121 builtin/merge.c:865 builtin/merge.c:978 -#: builtin/merge.c:1088 builtin/merge.c:1098 +#: remote.c:1659 +msgid " (use \"git pull\" to merge the remote branch into yours)\n" +msgstr "" + +#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984 +#: builtin/merge.c:994 #, c-format msgid "Could not open '%s' for writing" msgstr "" -#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:868 -#: builtin/merge.c:1090 builtin/merge.c:1103 +#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986 +#: builtin/merge.c:999 #, c-format msgid "Could not write to '%s'" msgstr "" -#: sequencer.c:144 +#: sequencer.c:146 msgid "" "after resolving the conflicts, mark the corrected paths\n" "with 'git add <paths>' or 'git rm <paths>'" msgstr "" -#: sequencer.c:147 +#: sequencer.c:149 msgid "" "after resolving the conflicts, mark the corrected paths\n" "with 'git add <paths>' or 'git rm <paths>'\n" "and commit the result with 'git commit'" msgstr "" -#: sequencer.c:160 sequencer.c:758 sequencer.c:841 +#: sequencer.c:162 sequencer.c:770 sequencer.c:853 #, c-format msgid "Could not write to %s" msgstr "" -#: sequencer.c:163 +#: sequencer.c:165 #, c-format msgid "Error wrapping up %s" msgstr "" -#: sequencer.c:178 +#: sequencer.c:180 msgid "Your local changes would be overwritten by cherry-pick." msgstr "" -#: sequencer.c:180 +#: sequencer.c:182 msgid "Your local changes would be overwritten by revert." msgstr "" -#: sequencer.c:183 +#: sequencer.c:185 msgid "Commit your changes or stash them to proceed." msgstr "" #. TRANSLATORS: %s will be "revert" or "cherry-pick" -#: sequencer.c:233 +#: sequencer.c:235 #, c-format msgid "%s: Unable to write new index file" msgstr "" -#: sequencer.c:261 +#: sequencer.c:266 msgid "Could not resolve HEAD commit\n" msgstr "" -#: sequencer.c:282 +#: sequencer.c:287 msgid "Unable to update cache tree\n" msgstr "" -#: sequencer.c:324 +#: sequencer.c:332 #, c-format msgid "Could not parse commit %s\n" msgstr "" -#: sequencer.c:329 +#: sequencer.c:337 #, c-format msgid "Could not parse parent commit %s\n" msgstr "" -#: sequencer.c:395 +#: sequencer.c:403 msgid "Your index file is unmerged." msgstr "" -#: sequencer.c:398 +#: sequencer.c:406 msgid "You do not have a valid HEAD" msgstr "" -#: sequencer.c:413 +#: sequencer.c:421 #, c-format msgid "Commit %s is a merge but no -m option was given." msgstr "" -#: sequencer.c:421 +#: sequencer.c:429 #, c-format msgid "Commit %s does not have parent %d" msgstr "" -#: sequencer.c:425 +#: sequencer.c:433 #, c-format msgid "Mainline was specified but commit %s is not a merge." msgstr "" #. TRANSLATORS: The first %s will be "revert" or #. "cherry-pick", the second %s a SHA1 -#: sequencer.c:436 +#: sequencer.c:444 #, c-format msgid "%s: cannot parse parent commit %s" msgstr "" -#: sequencer.c:440 +#: sequencer.c:448 #, c-format msgid "Cannot get commit message for %s" msgstr "" -#: sequencer.c:524 +#: sequencer.c:532 #, c-format msgid "could not revert %s... %s" msgstr "" -#: sequencer.c:525 +#: sequencer.c:533 #, c-format msgid "could not apply %s... %s" msgstr "" -#: sequencer.c:553 +#: sequencer.c:565 msgid "empty commit set passed" msgstr "" -#: sequencer.c:561 +#: sequencer.c:573 #, c-format msgid "git %s: failed to read the index" msgstr "" -#: sequencer.c:566 +#: sequencer.c:578 #, c-format msgid "git %s: failed to refresh the index" msgstr "" -#: sequencer.c:624 +#: sequencer.c:636 #, c-format msgid "Cannot %s during a %s" msgstr "" -#: sequencer.c:646 +#: sequencer.c:658 #, c-format msgid "Could not parse line %d." msgstr "" -#: sequencer.c:651 +#: sequencer.c:663 msgid "No commits parsed." msgstr "" -#: sequencer.c:664 +#: sequencer.c:676 #, c-format msgid "Could not open %s" msgstr "" -#: sequencer.c:668 +#: sequencer.c:680 #, c-format msgid "Could not read %s." msgstr "" -#: sequencer.c:675 +#: sequencer.c:687 #, c-format msgid "Unusable instruction sheet: %s" msgstr "" -#: sequencer.c:703 +#: sequencer.c:715 #, c-format msgid "Invalid key: %s" msgstr "" -#: sequencer.c:706 +#: sequencer.c:718 #, c-format msgid "Invalid value for %s: %s" msgstr "" -#: sequencer.c:718 +#: sequencer.c:730 #, c-format msgid "Malformed options sheet: %s" msgstr "" -#: sequencer.c:739 +#: sequencer.c:751 msgid "a cherry-pick or revert is already in progress" msgstr "" -#: sequencer.c:740 +#: sequencer.c:752 msgid "try \"git cherry-pick (--continue | --quit | --abort)\"" msgstr "" -#: sequencer.c:744 +#: sequencer.c:756 #, c-format msgid "Could not create sequencer directory %s" msgstr "" -#: sequencer.c:760 sequencer.c:845 +#: sequencer.c:772 sequencer.c:857 #, c-format msgid "Error wrapping up %s." msgstr "" -#: sequencer.c:779 sequencer.c:913 +#: sequencer.c:791 sequencer.c:925 msgid "no cherry-pick or revert in progress" msgstr "" -#: sequencer.c:781 +#: sequencer.c:793 msgid "cannot resolve HEAD" msgstr "" -#: sequencer.c:783 +#: sequencer.c:795 msgid "cannot abort from a branch yet to be born" msgstr "" -#: sequencer.c:805 builtin/apply.c:3697 +#: sequencer.c:817 builtin/apply.c:4005 #, c-format msgid "cannot open %s: %s" msgstr "" -#: sequencer.c:808 +#: sequencer.c:820 #, c-format msgid "cannot read %s: %s" msgstr "" -#: sequencer.c:809 +#: sequencer.c:821 msgid "unexpected end of file" msgstr "" -#: sequencer.c:815 +#: sequencer.c:827 #, c-format msgid "stored pre-cherry-pick HEAD file '%s' is corrupt" msgstr "" -#: sequencer.c:838 +#: sequencer.c:850 #, c-format msgid "Could not format %s." msgstr "" -#: sequencer.c:1000 +#: sequencer.c:1012 msgid "Can't revert as initial commit" msgstr "" -#: sequencer.c:1001 +#: sequencer.c:1013 msgid "Can't cherry-pick into empty head" msgstr "" -#: sha1_name.c:864 +#: sha1_name.c:1044 msgid "HEAD does not point to a branch" msgstr "" -#: sha1_name.c:867 +#: sha1_name.c:1047 #, c-format msgid "No such branch: '%s'" msgstr "" -#: sha1_name.c:869 +#: sha1_name.c:1049 #, c-format msgid "No upstream configured for branch '%s'" msgstr "" -#: sha1_name.c:872 +#: sha1_name.c:1052 #, c-format msgid "Upstream branch '%s' not stored as a remote-tracking branch" msgstr "" -#: wrapper.c:413 +#: wrapper.c:408 +#, c-format +msgid "unable to access '%s': %s" +msgstr "" + +#: wrapper.c:426 #, c-format msgid "unable to look up current user in the passwd file: %s" msgstr "" -#: wrapper.c:414 +#: wrapper.c:427 msgid "no such user" msgstr "" -#: wt-status.c:135 +#: wt-status.c:140 msgid "Unmerged paths:" msgstr "" -#: wt-status.c:141 wt-status.c:158 +#: wt-status.c:167 wt-status.c:194 #, c-format msgid " (use \"git reset %s <file>...\" to unstage)" msgstr "" -#: wt-status.c:143 wt-status.c:160 +#: wt-status.c:169 wt-status.c:196 msgid " (use \"git rm --cached <file>...\" to unstage)" msgstr "" -#: wt-status.c:144 +#: wt-status.c:173 +msgid " (use \"git add <file>...\" to mark resolution)" +msgstr "" + +#: wt-status.c:175 wt-status.c:179 msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" msgstr "" -#: wt-status.c:152 +#: wt-status.c:177 +msgid " (use \"git rm <file>...\" to mark resolution)" +msgstr "" + +#: wt-status.c:188 msgid "Changes to be committed:" msgstr "" -#: wt-status.c:170 +#: wt-status.c:206 msgid "Changes not staged for commit:" msgstr "" -#: wt-status.c:174 +#: wt-status.c:210 msgid " (use \"git add <file>...\" to update what will be committed)" msgstr "" -#: wt-status.c:176 +#: wt-status.c:212 msgid " (use \"git add/rm <file>...\" to update what will be committed)" msgstr "" -#: wt-status.c:177 +#: wt-status.c:213 msgid "" " (use \"git checkout -- <file>...\" to discard changes in working directory)" msgstr "" -#: wt-status.c:179 +#: wt-status.c:215 msgid " (commit or discard the untracked or modified content in submodules)" msgstr "" -#: wt-status.c:188 -#, c-format -msgid "%s files:" -msgstr "" - -#: wt-status.c:191 +#: wt-status.c:227 #, c-format msgid " (use \"git %s <file>...\" to include in what will be committed)" msgstr "" -#: wt-status.c:208 +#: wt-status.c:244 msgid "bug" msgstr "" -#: wt-status.c:213 +#: wt-status.c:249 msgid "both deleted:" msgstr "" -#: wt-status.c:214 +#: wt-status.c:250 msgid "added by us:" msgstr "" -#: wt-status.c:215 +#: wt-status.c:251 msgid "deleted by them:" msgstr "" -#: wt-status.c:216 +#: wt-status.c:252 msgid "added by them:" msgstr "" -#: wt-status.c:217 +#: wt-status.c:253 msgid "deleted by us:" msgstr "" -#: wt-status.c:218 +#: wt-status.c:254 msgid "both added:" msgstr "" -#: wt-status.c:219 +#: wt-status.c:255 msgid "both modified:" msgstr "" -#: wt-status.c:249 +#: wt-status.c:285 msgid "new commits, " msgstr "" -#: wt-status.c:251 +#: wt-status.c:287 msgid "modified content, " msgstr "" -#: wt-status.c:253 +#: wt-status.c:289 msgid "untracked content, " msgstr "" -#: wt-status.c:267 +#: wt-status.c:303 #, c-format msgid "new file: %s" msgstr "" -#: wt-status.c:270 +#: wt-status.c:306 #, c-format msgid "copied: %s -> %s" msgstr "" -#: wt-status.c:273 +#: wt-status.c:309 #, c-format msgid "deleted: %s" msgstr "" -#: wt-status.c:276 +#: wt-status.c:312 #, c-format msgid "modified: %s" msgstr "" -#: wt-status.c:279 +#: wt-status.c:315 #, c-format msgid "renamed: %s -> %s" msgstr "" -#: wt-status.c:282 +#: wt-status.c:318 #, c-format msgid "typechange: %s" msgstr "" -#: wt-status.c:285 +#: wt-status.c:321 #, c-format msgid "unknown: %s" msgstr "" -#: wt-status.c:288 +#: wt-status.c:324 #, c-format msgid "unmerged: %s" msgstr "" -#: wt-status.c:291 +#: wt-status.c:327 #, c-format msgid "bug: unhandled diff status %c" msgstr "" -#: wt-status.c:737 +#: wt-status.c:785 +msgid "You have unmerged paths." +msgstr "" + +#: wt-status.c:788 wt-status.c:912 +msgid " (fix conflicts and run \"git commit\")" +msgstr "" + +#: wt-status.c:791 +msgid "All conflicts fixed but you are still merging." +msgstr "" + +#: wt-status.c:794 +msgid " (use \"git commit\" to conclude merge)" +msgstr "" + +#: wt-status.c:804 +msgid "You are in the middle of an am session." +msgstr "" + +#: wt-status.c:807 +msgid "The current patch is empty." +msgstr "" + +#: wt-status.c:811 +msgid " (fix conflicts and then run \"git am --resolved\")" +msgstr "" + +#: wt-status.c:813 +msgid " (use \"git am --skip\" to skip this patch)" +msgstr "" + +#: wt-status.c:815 +msgid " (use \"git am --abort\" to restore the original branch)" +msgstr "" + +#: wt-status.c:873 wt-status.c:883 +msgid "You are currently rebasing." +msgstr "" + +#: wt-status.c:876 +msgid " (fix conflicts and then run \"git rebase --continue\")" +msgstr "" + +#: wt-status.c:878 +msgid " (use \"git rebase --skip\" to skip this patch)" +msgstr "" + +#: wt-status.c:880 +msgid " (use \"git rebase --abort\" to check out the original branch)" +msgstr "" + +#: wt-status.c:886 +msgid " (all conflicts fixed: run \"git rebase --continue\")" +msgstr "" + +#: wt-status.c:888 +msgid "You are currently splitting a commit during a rebase." +msgstr "" + +#: wt-status.c:891 +msgid " (Once your working directory is clean, run \"git rebase --continue\")" +msgstr "" + +#: wt-status.c:893 +msgid "You are currently editing a commit during a rebase." +msgstr "" + +#: wt-status.c:896 +msgid " (use \"git commit --amend\" to amend the current commit)" +msgstr "" + +#: wt-status.c:898 +msgid "" +" (use \"git rebase --continue\" once you are satisfied with your changes)" +msgstr "" + +#: wt-status.c:908 +msgid "You are currently cherry-picking." +msgstr "" + +#: wt-status.c:915 +msgid " (all conflicts fixed: run \"git commit\")" +msgstr "" + +#: wt-status.c:924 +msgid "You are currently bisecting." +msgstr "" + +#: wt-status.c:927 +msgid " (use \"git bisect reset\" to get back to the original branch)" +msgstr "" + +#: wt-status.c:978 msgid "On branch " msgstr "" -#: wt-status.c:744 +#: wt-status.c:985 msgid "Not currently on any branch." msgstr "" -#: wt-status.c:755 +#: wt-status.c:997 msgid "Initial commit" msgstr "" -#: wt-status.c:769 -msgid "Untracked" +#: wt-status.c:1011 +msgid "Untracked files" msgstr "" -#: wt-status.c:771 -msgid "Ignored" +#: wt-status.c:1013 +msgid "Ignored files" msgstr "" -#: wt-status.c:773 +#: wt-status.c:1015 #, c-format msgid "Untracked files not listed%s" msgstr "" -#: wt-status.c:775 +#: wt-status.c:1017 msgid " (use -u option to show untracked files)" msgstr "" -#: wt-status.c:781 +#: wt-status.c:1023 msgid "No changes" msgstr "" -#: wt-status.c:785 +#: wt-status.c:1028 #, c-format -msgid "no changes added to commit%s\n" +msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n" msgstr "" -#: wt-status.c:787 -msgid " (use \"git add\" and/or \"git commit -a\")" +#: wt-status.c:1031 +#, c-format +msgid "no changes added to commit\n" msgstr "" -#: wt-status.c:789 +#: wt-status.c:1034 #, c-format -msgid "nothing added to commit but untracked files present%s\n" +msgid "" +"nothing added to commit but untracked files present (use \"git add\" to " +"track)\n" msgstr "" -#: wt-status.c:791 -msgid " (use \"git add\" to track)" +#: wt-status.c:1037 +#, c-format +msgid "nothing added to commit but untracked files present\n" msgstr "" -#: wt-status.c:793 wt-status.c:796 wt-status.c:799 +#: wt-status.c:1040 #, c-format -msgid "nothing to commit%s\n" +msgid "nothing to commit (create/copy files and use \"git add\" to track)\n" msgstr "" -#: wt-status.c:794 -msgid " (create/copy files and use \"git add\" to track)" +#: wt-status.c:1043 wt-status.c:1048 +#, c-format +msgid "nothing to commit\n" msgstr "" -#: wt-status.c:797 -msgid " (use -u to show untracked files)" +#: wt-status.c:1046 +#, c-format +msgid "nothing to commit (use -u to show untracked files)\n" msgstr "" -#: wt-status.c:800 -msgid " (working directory clean)" +#: wt-status.c:1050 +#, c-format +msgid "nothing to commit, working directory clean\n" msgstr "" -#: wt-status.c:908 +#: wt-status.c:1158 msgid "HEAD (no branch)" msgstr "" -#: wt-status.c:914 +#: wt-status.c:1164 msgid "Initial commit on " msgstr "" -#: wt-status.c:929 +#: wt-status.c:1179 msgid "behind " msgstr "" -#: wt-status.c:932 wt-status.c:935 +#: wt-status.c:1182 wt-status.c:1185 msgid "ahead " msgstr "" -#: wt-status.c:937 +#: wt-status.c:1187 msgid ", behind " msgstr "" +#: compat/precompose_utf8.c:58 builtin/clone.c:341 +#, c-format +msgid "failed to unlink '%s'" +msgstr "" + +#: builtin/add.c:19 +msgid "git add [options] [--] <filepattern>..." +msgstr "" + #: builtin/add.c:62 #, c-format msgid "unexpected diff status %c" msgstr "" -#: builtin/add.c:67 builtin/commit.c:226 +#: builtin/add.c:67 builtin/commit.c:231 msgid "updating files failed" msgstr "" @@ -890,7 +1354,7 @@ msgstr "" msgid "Unstaged changes after refreshing the index:" msgstr "" -#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186 +#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:275 #, c-format msgid "pathspec '%s' did not match any files" msgstr "" @@ -927,110 +1391,162 @@ msgstr "" msgid "Could not apply '%s'" msgstr "" -#: builtin/add.c:312 +#: builtin/add.c:313 msgid "The following paths are ignored by one of your .gitignore files:\n" msgstr "" -#: builtin/add.c:352 +#: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63 +#: builtin/prune-packed.c:76 builtin/push.c:388 builtin/remote.c:1253 +#: builtin/rm.c:206 +msgid "dry run" +msgstr "" + +#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1160 +#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1483 +#: builtin/mv.c:62 builtin/read-tree.c:112 +msgid "be verbose" +msgstr "" + +#: builtin/add.c:322 +msgid "interactive picking" +msgstr "" + +#: builtin/add.c:323 builtin/checkout.c:1031 builtin/reset.c:248 +msgid "select hunks interactively" +msgstr "" + +#: builtin/add.c:324 +msgid "edit current diff and apply" +msgstr "" + +#: builtin/add.c:325 +msgid "allow adding otherwise ignored files" +msgstr "" + +#: builtin/add.c:326 +msgid "update tracked files" +msgstr "" + +#: builtin/add.c:327 +msgid "record only the fact that the path will be added later" +msgstr "" + +#: builtin/add.c:328 +msgid "add changes from all tracked and untracked files" +msgstr "" + +#: builtin/add.c:329 +msgid "don't add, only refresh the index" +msgstr "" + +#: builtin/add.c:330 +msgid "just skip files which cannot be added because of errors" +msgstr "" + +#: builtin/add.c:331 +msgid "check if - even missing - files are ignored in dry run" +msgstr "" + +#: builtin/add.c:353 #, c-format msgid "Use -f if you really want to add them.\n" msgstr "" -#: builtin/add.c:353 +#: builtin/add.c:354 msgid "no files added" msgstr "" -#: builtin/add.c:359 +#: builtin/add.c:360 msgid "adding files failed" msgstr "" -#: builtin/add.c:391 +#: builtin/add.c:392 msgid "-A and -u are mutually incompatible" msgstr "" -#: builtin/add.c:393 +#: builtin/add.c:394 msgid "Option --ignore-missing can only be used together with --dry-run" msgstr "" -#: builtin/add.c:413 +#: builtin/add.c:414 #, c-format msgid "Nothing specified, nothing added.\n" msgstr "" -#: builtin/add.c:414 +#: builtin/add.c:415 #, c-format msgid "Maybe you wanted to say 'git add .'?\n" msgstr "" -#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82 -#: builtin/rm.c:162 +#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:291 builtin/mv.c:82 +#: builtin/rm.c:235 msgid "index file corrupt" msgstr "" -#: builtin/add.c:476 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260 +#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:370 msgid "Unable to write new index file" msgstr "" -#: builtin/apply.c:53 +#: builtin/apply.c:57 msgid "git apply [options] [<patch>...]" msgstr "" -#: builtin/apply.c:106 +#: builtin/apply.c:110 #, c-format msgid "unrecognized whitespace option '%s'" msgstr "" -#: builtin/apply.c:121 +#: builtin/apply.c:125 #, c-format msgid "unrecognized whitespace ignore option '%s'" msgstr "" -#: builtin/apply.c:815 +#: builtin/apply.c:823 #, c-format msgid "Cannot prepare timestamp regexp %s" msgstr "" -#: builtin/apply.c:824 +#: builtin/apply.c:832 #, c-format msgid "regexec returned %d for input: %s" msgstr "" -#: builtin/apply.c:905 +#: builtin/apply.c:913 #, c-format msgid "unable to find filename in patch at line %d" msgstr "" -#: builtin/apply.c:937 +#: builtin/apply.c:945 #, c-format msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" msgstr "" -#: builtin/apply.c:941 +#: builtin/apply.c:949 #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "" -#: builtin/apply.c:942 +#: builtin/apply.c:950 #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "" -#: builtin/apply.c:949 +#: builtin/apply.c:957 #, c-format msgid "git apply: bad git-diff - expected /dev/null on line %d" msgstr "" -#: builtin/apply.c:1394 +#: builtin/apply.c:1420 #, c-format msgid "recount: unexpected line: %.*s" msgstr "" -#: builtin/apply.c:1451 +#: builtin/apply.c:1477 #, c-format msgid "patch fragment without header at line %d: %.*s" msgstr "" -#: builtin/apply.c:1468 +#: builtin/apply.c:1494 #, c-format msgid "" "git diff header lacks filename information when removing %d leading pathname " @@ -1041,395 +1557,400 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: builtin/apply.c:1628 +#: builtin/apply.c:1654 msgid "new file depends on old contents" msgstr "" -#: builtin/apply.c:1630 +#: builtin/apply.c:1656 msgid "deleted file still has contents" msgstr "" -#: builtin/apply.c:1656 +#: builtin/apply.c:1682 #, c-format msgid "corrupt patch at line %d" msgstr "" -#: builtin/apply.c:1692 +#: builtin/apply.c:1718 #, c-format msgid "new file %s depends on old contents" msgstr "" -#: builtin/apply.c:1694 +#: builtin/apply.c:1720 #, c-format msgid "deleted file %s still has contents" msgstr "" -#: builtin/apply.c:1697 +#: builtin/apply.c:1723 #, c-format msgid "** warning: file %s becomes empty but is not deleted" msgstr "" -#: builtin/apply.c:1843 +#: builtin/apply.c:1869 #, c-format msgid "corrupt binary patch at line %d: %.*s" msgstr "" #. there has to be one hunk (forward hunk) -#: builtin/apply.c:1872 +#: builtin/apply.c:1898 #, c-format msgid "unrecognized binary patch at line %d" msgstr "" -#: builtin/apply.c:1958 +#: builtin/apply.c:1984 #, c-format msgid "patch with only garbage at line %d" msgstr "" -#: builtin/apply.c:2048 +#: builtin/apply.c:2074 #, c-format msgid "unable to read symlink %s" msgstr "" -#: builtin/apply.c:2052 +#: builtin/apply.c:2078 #, c-format msgid "unable to open or read %s" msgstr "" -#: builtin/apply.c:2123 +#: builtin/apply.c:2149 msgid "oops" msgstr "" -#: builtin/apply.c:2645 +#: builtin/apply.c:2671 #, c-format msgid "invalid start of line: '%c'" msgstr "" -#: builtin/apply.c:2763 +#: builtin/apply.c:2789 #, c-format msgid "Hunk #%d succeeded at %d (offset %d line)." msgid_plural "Hunk #%d succeeded at %d (offset %d lines)." msgstr[0] "" msgstr[1] "" -#: builtin/apply.c:2775 +#: builtin/apply.c:2801 #, c-format msgid "Context reduced to (%ld/%ld) to apply fragment at %d" msgstr "" -#: builtin/apply.c:2781 +#: builtin/apply.c:2807 #, c-format msgid "" "while searching for:\n" "%.*s" msgstr "" -#: builtin/apply.c:2800 +#: builtin/apply.c:2826 #, c-format msgid "missing binary patch data for '%s'" msgstr "" -#: builtin/apply.c:2903 +#: builtin/apply.c:2929 #, c-format msgid "binary patch does not apply to '%s'" msgstr "" -#: builtin/apply.c:2909 +#: builtin/apply.c:2935 #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" msgstr "" -#: builtin/apply.c:2930 +#: builtin/apply.c:2956 #, c-format msgid "patch failed: %s:%ld" msgstr "" -#: builtin/apply.c:3045 +#: builtin/apply.c:3078 #, c-format -msgid "patch %s has been renamed/deleted" +msgid "cannot checkout %s" msgstr "" -#: builtin/apply.c:3052 builtin/apply.c:3069 +#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176 #, c-format msgid "read of %s failed" msgstr "" -#: builtin/apply.c:3084 -msgid "removal patch leaves file contents" -msgstr "" - -#: builtin/apply.c:3105 +#: builtin/apply.c:3156 builtin/apply.c:3378 #, c-format -msgid "%s: already exists in working directory" +msgid "path %s has been renamed/deleted" msgstr "" -#: builtin/apply.c:3143 +#: builtin/apply.c:3237 builtin/apply.c:3392 #, c-format -msgid "%s: has been deleted/renamed" +msgid "%s: does not exist in index" msgstr "" -#: builtin/apply.c:3148 builtin/apply.c:3179 +#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406 #, c-format msgid "%s: %s" msgstr "" -#: builtin/apply.c:3159 +#: builtin/apply.c:3246 builtin/apply.c:3400 #, c-format -msgid "%s: does not exist in index" +msgid "%s: does not match index" msgstr "" -#: builtin/apply.c:3173 -#, c-format -msgid "%s: does not match index" +#: builtin/apply.c:3348 +msgid "removal patch leaves file contents" msgstr "" -#: builtin/apply.c:3190 +#: builtin/apply.c:3417 #, c-format msgid "%s: wrong type" msgstr "" -#: builtin/apply.c:3192 +#: builtin/apply.c:3419 #, c-format msgid "%s has type %o, expected %o" msgstr "" -#: builtin/apply.c:3247 +#: builtin/apply.c:3520 #, c-format msgid "%s: already exists in index" msgstr "" -#: builtin/apply.c:3267 +#: builtin/apply.c:3523 +#, c-format +msgid "%s: already exists in working directory" +msgstr "" + +#: builtin/apply.c:3543 #, c-format msgid "new mode (%o) of %s does not match old mode (%o)" msgstr "" -#: builtin/apply.c:3272 +#: builtin/apply.c:3548 #, c-format msgid "new mode (%o) of %s does not match old mode (%o) of %s" msgstr "" -#: builtin/apply.c:3280 +#: builtin/apply.c:3556 #, c-format msgid "%s: patch does not apply" msgstr "" -#: builtin/apply.c:3293 +#: builtin/apply.c:3569 #, c-format msgid "Checking patch %s..." msgstr "" -#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158 +#: builtin/apply.c:3624 builtin/checkout.c:215 builtin/reset.c:158 #, c-format msgid "make_cache_entry failed for path '%s'" msgstr "" -#: builtin/apply.c:3491 +#: builtin/apply.c:3767 #, c-format msgid "unable to remove %s from index" msgstr "" -#: builtin/apply.c:3518 +#: builtin/apply.c:3795 #, c-format msgid "corrupt patch for subproject %s" msgstr "" -#: builtin/apply.c:3522 +#: builtin/apply.c:3799 #, c-format msgid "unable to stat newly created file '%s'" msgstr "" -#: builtin/apply.c:3527 +#: builtin/apply.c:3804 #, c-format msgid "unable to create backing store for newly created file %s" msgstr "" -#: builtin/apply.c:3530 +#: builtin/apply.c:3807 builtin/apply.c:3915 #, c-format msgid "unable to add cache entry for %s" msgstr "" -#: builtin/apply.c:3563 +#: builtin/apply.c:3840 #, c-format msgid "closing file '%s'" msgstr "" -#: builtin/apply.c:3612 +#: builtin/apply.c:3889 #, c-format msgid "unable to write file '%s' mode %o" msgstr "" -#: builtin/apply.c:3668 +#: builtin/apply.c:3976 #, c-format msgid "Applied patch %s cleanly." msgstr "" -#: builtin/apply.c:3676 +#: builtin/apply.c:3984 msgid "internal error" msgstr "" #. Say this even without --verbose -#: builtin/apply.c:3679 +#: builtin/apply.c:3987 #, c-format msgid "Applying patch %%s with %d reject..." msgid_plural "Applying patch %%s with %d rejects..." msgstr[0] "" msgstr[1] "" -#: builtin/apply.c:3689 +#: builtin/apply.c:3997 #, c-format msgid "truncating .rej filename to %.*s.rej" msgstr "" -#: builtin/apply.c:3710 +#: builtin/apply.c:4018 #, c-format msgid "Hunk #%d applied cleanly." msgstr "" -#: builtin/apply.c:3713 +#: builtin/apply.c:4021 #, c-format msgid "Rejected hunk #%d." msgstr "" -#: builtin/apply.c:3844 +#: builtin/apply.c:4171 msgid "unrecognized input" msgstr "" -#: builtin/apply.c:3855 +#: builtin/apply.c:4182 msgid "unable to read index file" msgstr "" -#: builtin/apply.c:3970 builtin/apply.c:3973 +#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91 +#: builtin/fetch.c:63 msgid "path" msgstr "" -#: builtin/apply.c:3971 +#: builtin/apply.c:4302 msgid "don't apply changes matching the given path" msgstr "" -#: builtin/apply.c:3974 +#: builtin/apply.c:4305 msgid "apply changes matching the given path" msgstr "" -#: builtin/apply.c:3976 +#: builtin/apply.c:4307 msgid "num" msgstr "" -#: builtin/apply.c:3977 +#: builtin/apply.c:4308 msgid "remove <num> leading slashes from traditional diff paths" msgstr "" -#: builtin/apply.c:3980 +#: builtin/apply.c:4311 msgid "ignore additions made by the patch" msgstr "" -#: builtin/apply.c:3982 +#: builtin/apply.c:4313 msgid "instead of applying the patch, output diffstat for the input" msgstr "" -#: builtin/apply.c:3986 -msgid "shows number of added and deleted lines in decimal notation" +#: builtin/apply.c:4317 +msgid "show number of added and deleted lines in decimal notation" msgstr "" -#: builtin/apply.c:3988 +#: builtin/apply.c:4319 msgid "instead of applying the patch, output a summary for the input" msgstr "" -#: builtin/apply.c:3990 +#: builtin/apply.c:4321 msgid "instead of applying the patch, see if the patch is applicable" msgstr "" -#: builtin/apply.c:3992 +#: builtin/apply.c:4323 msgid "make sure the patch is applicable to the current index" msgstr "" -#: builtin/apply.c:3994 +#: builtin/apply.c:4325 msgid "apply a patch without touching the working tree" msgstr "" -#: builtin/apply.c:3996 +#: builtin/apply.c:4327 msgid "also apply the patch (use with --stat/--summary/--check)" msgstr "" -#: builtin/apply.c:3998 +#: builtin/apply.c:4329 +msgid "attempt three-way merge if a patch does not apply" +msgstr "" + +#: builtin/apply.c:4331 msgid "build a temporary index based on embedded index information" msgstr "" -#: builtin/apply.c:4000 +#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460 msgid "paths are separated with NUL character" msgstr "" -#: builtin/apply.c:4003 +#: builtin/apply.c:4336 msgid "ensure at least <n> lines of context match" msgstr "" -#: builtin/apply.c:4004 +#: builtin/apply.c:4337 msgid "action" msgstr "" -#: builtin/apply.c:4005 +#: builtin/apply.c:4338 msgid "detect new or modified lines that have whitespace errors" msgstr "" -#: builtin/apply.c:4008 builtin/apply.c:4011 +#: builtin/apply.c:4341 builtin/apply.c:4344 msgid "ignore changes in whitespace when finding context" msgstr "" -#: builtin/apply.c:4014 +#: builtin/apply.c:4347 msgid "apply the patch in reverse" msgstr "" -#: builtin/apply.c:4016 +#: builtin/apply.c:4349 msgid "don't expect at least one line of context" msgstr "" -#: builtin/apply.c:4018 +#: builtin/apply.c:4351 msgid "leave the rejected hunks in corresponding *.rej files" msgstr "" -#: builtin/apply.c:4020 +#: builtin/apply.c:4353 msgid "allow overlapping hunks" msgstr "" -#: builtin/apply.c:4021 -msgid "be verbose" -msgstr "" - -#: builtin/apply.c:4023 +#: builtin/apply.c:4356 msgid "tolerate incorrectly detected missing new-line at the end of file" msgstr "" -#: builtin/apply.c:4026 +#: builtin/apply.c:4359 msgid "do not trust the line counts in the hunk headers" msgstr "" -#: builtin/apply.c:4028 +#: builtin/apply.c:4361 msgid "root" msgstr "" -#: builtin/apply.c:4029 +#: builtin/apply.c:4362 msgid "prepend <root> to all filenames" msgstr "" -#: builtin/apply.c:4050 +#: builtin/apply.c:4384 +msgid "--3way outside a repository" +msgstr "" + +#: builtin/apply.c:4392 msgid "--index outside a repository" msgstr "" -#: builtin/apply.c:4053 +#: builtin/apply.c:4395 msgid "--cached outside a repository" msgstr "" -#: builtin/apply.c:4069 +#: builtin/apply.c:4411 #, c-format msgid "can't open patch '%s'" msgstr "" -#: builtin/apply.c:4083 +#: builtin/apply.c:4425 #, c-format msgid "squelched %d whitespace error" msgid_plural "squelched %d whitespace errors" msgstr[0] "" msgstr[1] "" -#: builtin/apply.c:4089 builtin/apply.c:4099 +#: builtin/apply.c:4431 builtin/apply.c:4441 #, c-format msgid "%d line adds whitespace errors." msgid_plural "%d lines add whitespace errors." @@ -1471,175 +1992,428 @@ msgstr "" msgid "git archive: expected a flush" msgstr "" -#: builtin/branch.c:144 +#: builtin/bisect--helper.c:7 +msgid "git bisect--helper --next-all [--no-checkout]" +msgstr "" + +#: builtin/bisect--helper.c:17 +msgid "perform 'git bisect next'" +msgstr "" + +#: builtin/bisect--helper.c:19 +msgid "update BISECT_HEAD instead of checking out the current commit" +msgstr "" + +#: builtin/blame.c:25 +msgid "git blame [options] [rev-opts] [rev] [--] file" +msgstr "" + +#: builtin/blame.c:30 builtin/shortlog.c:15 +msgid "[rev-opts] are documented in git-rev-list(1)" +msgstr "" + +#: builtin/blame.c:2374 +msgid "Show blame entries as we find them, incrementally" +msgstr "" + +#: builtin/blame.c:2375 +msgid "Show blank SHA-1 for boundary commits (Default: off)" +msgstr "" + +#: builtin/blame.c:2376 +msgid "Do not treat root commits as boundaries (Default: off)" +msgstr "" + +#: builtin/blame.c:2377 +msgid "Show work cost statistics" +msgstr "" + +#: builtin/blame.c:2378 +msgid "Show output score for blame entries" +msgstr "" + +#: builtin/blame.c:2379 +msgid "Show original filename (Default: auto)" +msgstr "" + +#: builtin/blame.c:2380 +msgid "Show original linenumber (Default: off)" +msgstr "" + +#: builtin/blame.c:2381 +msgid "Show in a format designed for machine consumption" +msgstr "" + +#: builtin/blame.c:2382 +msgid "Show porcelain format with per-line commit information" +msgstr "" + +#: builtin/blame.c:2383 +msgid "Use the same output mode as git-annotate (Default: off)" +msgstr "" + +#: builtin/blame.c:2384 +msgid "Show raw timestamp (Default: off)" +msgstr "" + +#: builtin/blame.c:2385 +msgid "Show long commit SHA1 (Default: off)" +msgstr "" + +#: builtin/blame.c:2386 +msgid "Suppress author name and timestamp (Default: off)" +msgstr "" + +#: builtin/blame.c:2387 +msgid "Show author email instead of name (Default: off)" +msgstr "" + +#: builtin/blame.c:2388 +msgid "Ignore whitespace differences" +msgstr "" + +#: builtin/blame.c:2389 +msgid "Spend extra cycles to find better match" +msgstr "" + +#: builtin/blame.c:2390 +msgid "Use revisions from <file> instead of calling git-rev-list" +msgstr "" + +#: builtin/blame.c:2391 +msgid "Use <file>'s contents as the final image" +msgstr "" + +#: builtin/blame.c:2392 builtin/blame.c:2393 +msgid "score" +msgstr "" + +#: builtin/blame.c:2392 +msgid "Find line copies within and across files" +msgstr "" + +#: builtin/blame.c:2393 +msgid "Find line movements within and across files" +msgstr "" + +#: builtin/blame.c:2394 +msgid "n,m" +msgstr "" + +#: builtin/blame.c:2394 +msgid "Process only line range n,m, counting from 1" +msgstr "" + +#: builtin/branch.c:23 +msgid "git branch [options] [-r | -a] [--merged | --no-merged]" +msgstr "" + +#: builtin/branch.c:24 +msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]" +msgstr "" + +#: builtin/branch.c:25 +msgid "git branch [options] [-r] (-d | -D) <branchname>..." +msgstr "" + +#: builtin/branch.c:26 +msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>" +msgstr "" + +#: builtin/branch.c:145 #, c-format msgid "" "deleting branch '%s' that has been merged to\n" " '%s', but not yet merged to HEAD." msgstr "" -#: builtin/branch.c:148 +#: builtin/branch.c:149 #, c-format msgid "" "not deleting branch '%s' that is not yet merged to\n" " '%s', even though it is merged to HEAD." msgstr "" +#: builtin/branch.c:163 +#, c-format +msgid "Couldn't look up commit object for '%s'" +msgstr "" + +#: builtin/branch.c:167 +#, c-format +msgid "" +"The branch '%s' is not fully merged.\n" +"If you are sure you want to delete it, run 'git branch -D %s'." +msgstr "" + #: builtin/branch.c:180 +msgid "Update of config-file failed" +msgstr "" + +#: builtin/branch.c:208 msgid "cannot use -a with -d" msgstr "" -#: builtin/branch.c:186 +#: builtin/branch.c:214 msgid "Couldn't look up commit object for HEAD" msgstr "" -#: builtin/branch.c:191 +#: builtin/branch.c:222 #, c-format msgid "Cannot delete the branch '%s' which you are currently on." msgstr "" -#: builtin/branch.c:202 +#: builtin/branch.c:235 #, c-format msgid "remote branch '%s' not found." msgstr "" -#: builtin/branch.c:203 +#: builtin/branch.c:236 #, c-format msgid "branch '%s' not found." msgstr "" -#: builtin/branch.c:210 -#, c-format -msgid "Couldn't look up commit object for '%s'" -msgstr "" - -#: builtin/branch.c:216 -#, c-format -msgid "" -"The branch '%s' is not fully merged.\n" -"If you are sure you want to delete it, run 'git branch -D %s'." -msgstr "" - -#: builtin/branch.c:225 +#: builtin/branch.c:250 #, c-format msgid "Error deleting remote branch '%s'" msgstr "" -#: builtin/branch.c:226 +#: builtin/branch.c:251 #, c-format msgid "Error deleting branch '%s'" msgstr "" -#: builtin/branch.c:233 +#: builtin/branch.c:258 #, c-format msgid "Deleted remote branch %s (was %s).\n" msgstr "" -#: builtin/branch.c:234 +#: builtin/branch.c:259 #, c-format msgid "Deleted branch %s (was %s).\n" msgstr "" -#: builtin/branch.c:239 -msgid "Update of config-file failed" -msgstr "" - -#: builtin/branch.c:337 +#: builtin/branch.c:361 #, c-format msgid "branch '%s' does not point at a commit" msgstr "" -#: builtin/branch.c:409 +#: builtin/branch.c:433 #, c-format msgid "[%s: behind %d]" msgstr "" -#: builtin/branch.c:411 +#: builtin/branch.c:435 #, c-format msgid "[behind %d]" msgstr "" -#: builtin/branch.c:415 +#: builtin/branch.c:439 #, c-format msgid "[%s: ahead %d]" msgstr "" -#: builtin/branch.c:417 +#: builtin/branch.c:441 #, c-format msgid "[ahead %d]" msgstr "" -#: builtin/branch.c:420 +#: builtin/branch.c:444 #, c-format msgid "[%s: ahead %d, behind %d]" msgstr "" -#: builtin/branch.c:423 +#: builtin/branch.c:447 #, c-format msgid "[ahead %d, behind %d]" msgstr "" -#: builtin/branch.c:535 +#: builtin/branch.c:560 msgid "(no branch)" msgstr "" -#: builtin/branch.c:600 +#: builtin/branch.c:625 msgid "some refs could not be read" msgstr "" -#: builtin/branch.c:613 +#: builtin/branch.c:638 msgid "cannot rename the current branch while not on any." msgstr "" -#: builtin/branch.c:623 +#: builtin/branch.c:648 #, c-format msgid "Invalid branch name: '%s'" msgstr "" -#: builtin/branch.c:638 +#: builtin/branch.c:663 msgid "Branch rename failed" msgstr "" -#: builtin/branch.c:642 +#: builtin/branch.c:667 #, c-format msgid "Renamed a misnamed branch '%s' away" msgstr "" -#: builtin/branch.c:646 +#: builtin/branch.c:671 #, c-format msgid "Branch renamed to %s, but HEAD is not updated!" msgstr "" -#: builtin/branch.c:653 +#: builtin/branch.c:678 msgid "Branch is renamed, but update of config-file failed" msgstr "" -#: builtin/branch.c:668 +#: builtin/branch.c:693 #, c-format msgid "malformed object name %s" msgstr "" -#: builtin/branch.c:692 +#: builtin/branch.c:717 #, c-format msgid "could not write branch description template: %s" msgstr "" -#: builtin/branch.c:783 +#: builtin/branch.c:747 +msgid "Generic options" +msgstr "" + +#: builtin/branch.c:749 +msgid "show hash and subject, give twice for upstream branch" +msgstr "" + +#: builtin/branch.c:750 +msgid "suppress informational messages" +msgstr "" + +#: builtin/branch.c:751 +msgid "set up tracking mode (see git-pull(1))" +msgstr "" + +#: builtin/branch.c:753 +msgid "change upstream info" +msgstr "" + +#: builtin/branch.c:757 +msgid "use colored output" +msgstr "" + +#: builtin/branch.c:758 +msgid "act on remote-tracking branches" +msgstr "" + +#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788 +#: builtin/branch.c:794 builtin/commit.c:1376 builtin/commit.c:1377 +#: builtin/commit.c:1378 builtin/commit.c:1379 builtin/tag.c:470 +msgid "commit" +msgstr "" + +#: builtin/branch.c:762 builtin/branch.c:768 +msgid "print only branches that contain the commit" +msgstr "" + +#: builtin/branch.c:774 +msgid "Specific git-branch actions:" +msgstr "" + +#: builtin/branch.c:775 +msgid "list both remote-tracking and local branches" +msgstr "" + +#: builtin/branch.c:777 +msgid "delete fully merged branch" +msgstr "" + +#: builtin/branch.c:778 +msgid "delete branch (even if not merged)" +msgstr "" + +#: builtin/branch.c:779 +msgid "move/rename a branch and its reflog" +msgstr "" + +#: builtin/branch.c:780 +msgid "move/rename a branch, even if target exists" +msgstr "" + +#: builtin/branch.c:781 +msgid "list branch names" +msgstr "" + +#: builtin/branch.c:782 +msgid "create the branch's reflog" +msgstr "" + +#: builtin/branch.c:784 +msgid "edit the description for the branch" +msgstr "" + +#: builtin/branch.c:785 +msgid "force creation (when already exists)" +msgstr "" + +#: builtin/branch.c:788 +msgid "print only not merged branches" +msgstr "" + +#: builtin/branch.c:794 +msgid "print only merged branches" +msgstr "" + +#: builtin/branch.c:798 +msgid "list branches in columns" +msgstr "" + +#: builtin/branch.c:811 msgid "Failed to resolve HEAD as a valid ref." msgstr "" -#: builtin/branch.c:788 builtin/clone.c:558 +#: builtin/branch.c:816 builtin/clone.c:561 msgid "HEAD not found below refs/heads!" msgstr "" -#: builtin/branch.c:808 +#: builtin/branch.c:836 msgid "--column and --verbose are incompatible" msgstr "" -#: builtin/branch.c:857 +#: builtin/branch.c:887 +#, c-format +msgid "branch '%s' does not exist" +msgstr "" + +#: builtin/branch.c:899 +#, c-format +msgid "Branch '%s' has no upstream information" +msgstr "" + +#: builtin/branch.c:914 msgid "-a and -r options to 'git branch' do not make sense with a branch name" msgstr "" +#: builtin/branch.c:917 +#, c-format +msgid "" +"The --set-upstream flag is deprecated and will be removed. Consider using --" +"track or --set-upstream-to\n" +msgstr "" + +#: builtin/branch.c:934 +#, c-format +msgid "" +"\n" +"If you wanted to make '%s' track '%s', do this:\n" +"\n" +msgstr "" + +#: builtin/branch.c:935 +#, c-format +msgid " git branch -d %s\n" +msgstr "" + +#: builtin/branch.c:936 +#, c-format +msgid " git branch --set-upstream-to %s\n" +msgstr "" + #: builtin/bundle.c:47 #, c-format msgid "%s is okay\n" @@ -1653,99 +2427,222 @@ msgstr "" msgid "Need a repository to unbundle." msgstr "" -#: builtin/checkout.c:113 builtin/checkout.c:146 +#: builtin/cat-file.c:247 +msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>" +msgstr "" + +#: builtin/cat-file.c:248 +msgid "git cat-file (--batch|--batch-check) < <list_of_objects>" +msgstr "" + +#: builtin/cat-file.c:266 +msgid "<type> can be one of: blob, tree, commit, tag" +msgstr "" + +#: builtin/cat-file.c:267 +msgid "show object type" +msgstr "" + +#: builtin/cat-file.c:268 +msgid "show object size" +msgstr "" + +#: builtin/cat-file.c:270 +msgid "exit with zero when there's no error" +msgstr "" + +#: builtin/cat-file.c:271 +msgid "pretty-print object's content" +msgstr "" + +#: builtin/cat-file.c:273 +msgid "for blob objects, run textconv on object's content" +msgstr "" + +#: builtin/cat-file.c:275 +msgid "show info and content of objects fed from the standard input" +msgstr "" + +#: builtin/cat-file.c:278 +msgid "show info about objects fed from the standard input" +msgstr "" + +#: builtin/check-attr.c:11 +msgid "git check-attr [-a | --all | attr...] [--] pathname..." +msgstr "" + +#: builtin/check-attr.c:12 +msgid "git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>" +msgstr "" + +#: builtin/check-attr.c:19 +msgid "report all attributes set on file" +msgstr "" + +#: builtin/check-attr.c:20 +msgid "use .gitattributes only from the index" +msgstr "" + +#: builtin/check-attr.c:21 builtin/hash-object.c:75 +msgid "read file names from stdin" +msgstr "" + +#: builtin/check-attr.c:23 +msgid "input paths are terminated by a null character" +msgstr "" + +#: builtin/checkout-index.c:126 +msgid "git checkout-index [options] [--] [<file>...]" +msgstr "" + +#: builtin/checkout-index.c:187 +msgid "check out all files in the index" +msgstr "" + +#: builtin/checkout-index.c:188 +msgid "force overwrite of existing files" +msgstr "" + +#: builtin/checkout-index.c:190 +msgid "no warning for existing files and files not in index" +msgstr "" + +#: builtin/checkout-index.c:192 +msgid "don't checkout new files" +msgstr "" + +#: builtin/checkout-index.c:194 +msgid "update stat information in the index file" +msgstr "" + +#: builtin/checkout-index.c:200 +msgid "read list of paths from the standard input" +msgstr "" + +#: builtin/checkout-index.c:202 +msgid "write the content to temporary files" +msgstr "" + +#: builtin/checkout-index.c:203 builtin/column.c:30 +msgid "string" +msgstr "" + +#: builtin/checkout-index.c:204 +msgid "when creating files, prepend <string>" +msgstr "" + +#: builtin/checkout-index.c:207 +msgid "copy out the files from named stage" +msgstr "" + +#: builtin/checkout.c:25 +msgid "git checkout [options] <branch>" +msgstr "" + +#: builtin/checkout.c:26 +msgid "git checkout [options] [<branch>] -- <file>..." +msgstr "" + +#: builtin/checkout.c:116 builtin/checkout.c:149 #, c-format msgid "path '%s' does not have our version" msgstr "" -#: builtin/checkout.c:115 builtin/checkout.c:148 +#: builtin/checkout.c:118 builtin/checkout.c:151 #, c-format msgid "path '%s' does not have their version" msgstr "" -#: builtin/checkout.c:131 +#: builtin/checkout.c:134 #, c-format msgid "path '%s' does not have all necessary versions" msgstr "" -#: builtin/checkout.c:175 +#: builtin/checkout.c:178 #, c-format msgid "path '%s' does not have necessary versions" msgstr "" -#: builtin/checkout.c:192 +#: builtin/checkout.c:195 #, c-format msgid "path '%s': cannot merge" msgstr "" -#: builtin/checkout.c:209 +#: builtin/checkout.c:212 #, c-format msgid "Unable to add merge result for '%s'" msgstr "" -#: builtin/checkout.c:234 builtin/checkout.c:392 -msgid "corrupt index file" +#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242 +#: builtin/checkout.c:245 +#, c-format +msgid "'%s' cannot be used with updating paths" msgstr "" -#: builtin/checkout.c:264 builtin/checkout.c:271 +#: builtin/checkout.c:248 builtin/checkout.c:251 #, c-format -msgid "path '%s' is unmerged" +msgid "'%s' cannot be used with %s" msgstr "" -#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583 -#: builtin/merge.c:812 -msgid "unable to write new index file" +#: builtin/checkout.c:254 +#, c-format +msgid "Cannot update paths and switch to branch '%s' at the same time." +msgstr "" + +#: builtin/checkout.c:265 builtin/checkout.c:426 +msgid "corrupt index file" msgstr "" -#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408 -msgid "diff_setup_done failed" +#: builtin/checkout.c:295 builtin/checkout.c:302 +#, c-format +msgid "path '%s' is unmerged" msgstr "" -#: builtin/checkout.c:414 +#: builtin/checkout.c:448 msgid "you need to resolve your current index first" msgstr "" -#: builtin/checkout.c:533 +#: builtin/checkout.c:569 #, c-format msgid "Can not do reflog for '%s'\n" msgstr "" -#: builtin/checkout.c:566 +#: builtin/checkout.c:602 msgid "HEAD is now at" msgstr "" -#: builtin/checkout.c:573 +#: builtin/checkout.c:609 #, c-format msgid "Reset branch '%s'\n" msgstr "" -#: builtin/checkout.c:576 +#: builtin/checkout.c:612 #, c-format msgid "Already on '%s'\n" msgstr "" -#: builtin/checkout.c:580 +#: builtin/checkout.c:616 #, c-format msgid "Switched to and reset branch '%s'\n" msgstr "" -#: builtin/checkout.c:582 +#: builtin/checkout.c:618 builtin/checkout.c:955 #, c-format msgid "Switched to a new branch '%s'\n" msgstr "" -#: builtin/checkout.c:584 +#: builtin/checkout.c:620 #, c-format msgid "Switched to branch '%s'\n" msgstr "" -#: builtin/checkout.c:640 +#: builtin/checkout.c:676 #, c-format msgid " ... and %d more.\n" msgstr "" #. The singular version -#: builtin/checkout.c:646 +#: builtin/checkout.c:682 #, c-format msgid "" "Warning: you are leaving %d commit behind, not connected to\n" @@ -1760,7 +2657,7 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: builtin/checkout.c:664 +#: builtin/checkout.c:700 #, c-format msgid "" "If you want to keep them by creating a new branch, this may be a good time\n" @@ -1770,97 +2667,184 @@ msgid "" "\n" msgstr "" -#: builtin/checkout.c:694 +#: builtin/checkout.c:730 msgid "internal error in revision walk" msgstr "" -#: builtin/checkout.c:698 +#: builtin/checkout.c:734 msgid "Previous HEAD position was" msgstr "" -#: builtin/checkout.c:724 +#: builtin/checkout.c:761 builtin/checkout.c:950 msgid "You are on a branch yet to be born" msgstr "" #. case (1) -#: builtin/checkout.c:855 +#: builtin/checkout.c:886 #, c-format msgid "invalid reference: %s" msgstr "" #. case (1): want a tree -#: builtin/checkout.c:894 +#: builtin/checkout.c:925 #, c-format msgid "reference is not a tree: %s" msgstr "" -#: builtin/checkout.c:974 -msgid "-B cannot be used with -b" +#: builtin/checkout.c:964 +msgid "paths cannot be used with switching branches" msgstr "" -#: builtin/checkout.c:983 -msgid "--patch is incompatible with all other options" +#: builtin/checkout.c:967 builtin/checkout.c:971 +#, c-format +msgid "'%s' cannot be used with switching branches" msgstr "" +#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983 #: builtin/checkout.c:986 -msgid "--detach cannot be used with -b/-B/--orphan" +#, c-format +msgid "'%s' cannot be used with '%s'" msgstr "" -#: builtin/checkout.c:988 -msgid "--detach cannot be used with -t" +#: builtin/checkout.c:991 +#, c-format +msgid "Cannot switch branch to a non-commit '%s'" msgstr "" -#: builtin/checkout.c:994 -msgid "--track needs a branch name" +#: builtin/checkout.c:1012 builtin/gc.c:177 +msgid "suppress progress reporting" msgstr "" -#: builtin/checkout.c:1001 -msgid "Missing branch name; try -b" +#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89 +#: builtin/remote.c:169 builtin/remote.c:171 +msgid "branch" +msgstr "" + +#: builtin/checkout.c:1014 +msgid "create and checkout a new branch" msgstr "" -#: builtin/checkout.c:1007 -msgid "--orphan and -b|-B are mutually exclusive" +#: builtin/checkout.c:1016 +msgid "create/reset and checkout a branch" msgstr "" -#: builtin/checkout.c:1009 -msgid "--orphan cannot be used with -t" +#: builtin/checkout.c:1017 +msgid "create reflog for new branch" +msgstr "" + +#: builtin/checkout.c:1018 +msgid "detach the HEAD at named commit" msgstr "" #: builtin/checkout.c:1019 -msgid "git checkout: -f and -m are incompatible" +msgid "set upstream info for new branch" +msgstr "" + +#: builtin/checkout.c:1021 +msgid "new branch" +msgstr "" + +#: builtin/checkout.c:1021 +msgid "new unparented branch" +msgstr "" + +#: builtin/checkout.c:1022 +msgid "checkout our version for unmerged files" +msgstr "" + +#: builtin/checkout.c:1024 +msgid "checkout their version for unmerged files" +msgstr "" + +#: builtin/checkout.c:1026 +msgid "force checkout (throw away local modifications)" +msgstr "" + +#: builtin/checkout.c:1027 +msgid "perform a 3-way merge with the new branch" +msgstr "" + +#: builtin/checkout.c:1028 builtin/merge.c:215 +msgid "update ignored files (default)" +msgstr "" + +#: builtin/checkout.c:1029 builtin/log.c:1116 parse-options.h:241 +msgid "style" +msgstr "" + +#: builtin/checkout.c:1030 +msgid "conflict style (merge or diff3)" +msgstr "" + +#: builtin/checkout.c:1033 +msgid "second guess 'git checkout no-such-branch'" +msgstr "" + +#: builtin/checkout.c:1057 +msgid "-b, -B and --orphan are mutually exclusive" +msgstr "" + +#: builtin/checkout.c:1074 +msgid "--track needs a branch name" +msgstr "" + +#: builtin/checkout.c:1081 +msgid "Missing branch name; try -b" msgstr "" -#: builtin/checkout.c:1053 +#: builtin/checkout.c:1116 msgid "invalid path specification" msgstr "" -#: builtin/checkout.c:1061 +#: builtin/checkout.c:1123 #, c-format msgid "" -"git checkout: updating paths is incompatible with switching branches.\n" +"Cannot update paths and switch to branch '%s' at the same time.\n" "Did you intend to checkout '%s' which can not be resolved as commit?" msgstr "" -#: builtin/checkout.c:1063 -msgid "git checkout: updating paths is incompatible with switching branches." -msgstr "" - -#: builtin/checkout.c:1068 -msgid "git checkout: --detach does not take a path argument" +#: builtin/checkout.c:1128 +#, c-format +msgid "git checkout: --detach does not take a path argument '%s'" msgstr "" -#: builtin/checkout.c:1071 +#: builtin/checkout.c:1132 msgid "" "git checkout: --ours/--theirs, --force and --merge are incompatible when\n" "checking out of the index." msgstr "" -#: builtin/checkout.c:1090 -msgid "Cannot switch branch to a non-commit." +#: builtin/clean.c:19 +msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..." msgstr "" -#: builtin/checkout.c:1093 -msgid "--ours/--theirs is incompatible with switching branches." +#: builtin/clean.c:51 +msgid "do not print names of files removed" +msgstr "" + +#: builtin/clean.c:53 +msgid "force" +msgstr "" + +#: builtin/clean.c:55 +msgid "remove whole directories" +msgstr "" + +#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:717 +#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:182 +msgid "pattern" +msgstr "" + +#: builtin/clean.c:57 +msgid "add <pattern> to ignore rules" +msgstr "" + +#: builtin/clean.c:58 +msgid "remove ignored files, too" +msgstr "" + +#: builtin/clean.c:60 +msgid "remove only ignored files" msgstr "" #: builtin/clean.c:78 @@ -1903,14 +2887,102 @@ msgstr "" msgid "Not removing %s\n" msgstr "" -#: builtin/clone.c:243 -#, c-format -msgid "reference repository '%s' is not a local directory." +#: builtin/clone.c:36 +msgid "git clone [options] [--] <repo> [<dir>]" +msgstr "" + +#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212 +#: builtin/push.c:399 +msgid "force progress reporting" +msgstr "" + +#: builtin/clone.c:66 +msgid "don't create a checkout" +msgstr "" + +#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488 +msgid "create a bare repository" +msgstr "" + +#: builtin/clone.c:72 +msgid "create a mirror repository (implies bare)" +msgstr "" + +#: builtin/clone.c:74 +msgid "to clone from a local repository" +msgstr "" + +#: builtin/clone.c:76 +msgid "don't use local hardlinks, always copy" +msgstr "" + +#: builtin/clone.c:78 +msgid "setup as shared repository" +msgstr "" + +#: builtin/clone.c:80 builtin/clone.c:82 +msgid "initialize submodules in the clone" +msgstr "" + +#: builtin/clone.c:83 builtin/init-db.c:485 +msgid "template-directory" +msgstr "" + +#: builtin/clone.c:84 builtin/init-db.c:486 +msgid "directory from which templates will be used" +msgstr "" + +#: builtin/clone.c:86 +msgid "reference repository" +msgstr "" + +#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44 +msgid "name" +msgstr "" + +#: builtin/clone.c:88 +msgid "use <name> instead of 'origin' to track upstream" +msgstr "" + +#: builtin/clone.c:90 +msgid "checkout <branch> instead of the remote's HEAD" +msgstr "" + +#: builtin/clone.c:92 +msgid "path to git-upload-pack on the remote" +msgstr "" + +#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662 +msgid "depth" msgstr "" -#: builtin/clone.c:302 +#: builtin/clone.c:94 +msgid "create a shallow clone of that depth" +msgstr "" + +#: builtin/clone.c:96 +msgid "clone only one branch, HEAD or --branch" +msgstr "" + +#: builtin/clone.c:97 builtin/init-db.c:494 +msgid "gitdir" +msgstr "" + +#: builtin/clone.c:98 builtin/init-db.c:495 +msgid "separate git dir from working tree" +msgstr "" + +#: builtin/clone.c:99 +msgid "key=value" +msgstr "" + +#: builtin/clone.c:100 +msgid "set config inside the new repository" +msgstr "" + +#: builtin/clone.c:243 #, c-format -msgid "failed to open '%s'" +msgid "reference repository '%s' is not a local directory." msgstr "" #: builtin/clone.c:306 @@ -1918,7 +2990,7 @@ msgstr "" msgid "failed to create directory '%s'" msgstr "" -#: builtin/clone.c:308 builtin/diff.c:75 +#: builtin/clone.c:308 builtin/diff.c:77 #, c-format msgid "failed to stat '%s'" msgstr "" @@ -1933,11 +3005,6 @@ msgstr "" msgid "failed to stat %s\n" msgstr "" -#: builtin/clone.c:341 -#, c-format -msgid "failed to unlink '%s'" -msgstr "" - #: builtin/clone.c:346 #, c-format msgid "failed to create link '%s'" @@ -1953,86 +3020,122 @@ msgstr "" msgid "done.\n" msgstr "" -#: builtin/clone.c:440 +#: builtin/clone.c:443 #, c-format msgid "Could not find remote branch %s to clone." msgstr "" -#: builtin/clone.c:549 +#: builtin/clone.c:552 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" msgstr "" -#: builtin/clone.c:639 +#: builtin/clone.c:690 msgid "Too many arguments." msgstr "" -#: builtin/clone.c:643 +#: builtin/clone.c:694 msgid "You must specify a repository to clone." msgstr "" -#: builtin/clone.c:654 +#: builtin/clone.c:705 #, c-format msgid "--bare and --origin %s options are incompatible." msgstr "" -#: builtin/clone.c:668 +#: builtin/clone.c:719 #, c-format msgid "repository '%s' does not exist" msgstr "" -#: builtin/clone.c:673 +#: builtin/clone.c:724 msgid "--depth is ignored in local clones; use file:// instead." msgstr "" -#: builtin/clone.c:683 +#: builtin/clone.c:734 #, c-format msgid "destination path '%s' already exists and is not an empty directory." msgstr "" -#: builtin/clone.c:693 +#: builtin/clone.c:744 #, c-format msgid "working tree '%s' already exists." msgstr "" -#: builtin/clone.c:706 builtin/clone.c:720 +#: builtin/clone.c:757 builtin/clone.c:771 #, c-format msgid "could not create leading directories of '%s'" msgstr "" -#: builtin/clone.c:709 +#: builtin/clone.c:760 #, c-format msgid "could not create work tree dir '%s'." msgstr "" -#: builtin/clone.c:728 +#: builtin/clone.c:779 #, c-format msgid "Cloning into bare repository '%s'...\n" msgstr "" -#: builtin/clone.c:730 +#: builtin/clone.c:781 #, c-format msgid "Cloning into '%s'...\n" msgstr "" -#: builtin/clone.c:786 +#: builtin/clone.c:823 #, c-format msgid "Don't know how to clone %s" msgstr "" -#: builtin/clone.c:835 +#: builtin/clone.c:872 #, c-format msgid "Remote branch %s not found in upstream %s" msgstr "" -#: builtin/clone.c:842 +#: builtin/clone.c:879 msgid "You appear to have cloned an empty repository." msgstr "" +#: builtin/column.c:9 +msgid "git column [options]" +msgstr "" + +#: builtin/column.c:26 +msgid "lookup config vars" +msgstr "" + +#: builtin/column.c:27 builtin/column.c:28 +msgid "layout to use" +msgstr "" + +#: builtin/column.c:29 +msgid "Maximum width" +msgstr "" + +#: builtin/column.c:30 +msgid "Padding space on left border" +msgstr "" + +#: builtin/column.c:31 +msgid "Padding space on right border" +msgstr "" + +#: builtin/column.c:32 +msgid "Padding space between columns" +msgstr "" + #: builtin/column.c:51 msgid "--command must be the first argument" msgstr "" -#: builtin/commit.c:43 +#: builtin/commit.c:34 +msgid "git commit [options] [--] <filepattern>..." +msgstr "" + +#: builtin/commit.c:39 +msgid "git status [options] [--] <filepattern>..." +msgstr "" + +#: builtin/commit.c:44 msgid "" "Your name and email address were configured automatically based\n" "on your username and hostname. Please check that they are accurate.\n" @@ -2046,14 +3149,14 @@ msgid "" " git commit --amend --reset-author\n" msgstr "" -#: builtin/commit.c:55 +#: builtin/commit.c:56 msgid "" "You asked to amend the most recent commit, but doing so would make\n" "it empty. You can repeat your command with --allow-empty, or you can\n" "remove the commit entirely with \"git reset HEAD^\".\n" msgstr "" -#: builtin/commit.c:60 +#: builtin/commit.c:61 msgid "" "The previous cherry-pick is now empty, possibly due to conflict resolution.\n" "If you wish to commit it anyway, use:\n" @@ -2063,93 +3166,93 @@ msgid "" "Otherwise, please use 'git reset'\n" msgstr "" -#: builtin/commit.c:253 +#: builtin/commit.c:258 msgid "failed to unpack HEAD tree object" msgstr "" -#: builtin/commit.c:295 +#: builtin/commit.c:300 msgid "unable to create temporary index" msgstr "" -#: builtin/commit.c:301 +#: builtin/commit.c:306 msgid "interactive add failed" msgstr "" -#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405 +#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410 msgid "unable to write new_index file" msgstr "" -#: builtin/commit.c:386 +#: builtin/commit.c:391 msgid "cannot do a partial commit during a merge." msgstr "" -#: builtin/commit.c:388 +#: builtin/commit.c:393 msgid "cannot do a partial commit during a cherry-pick." msgstr "" -#: builtin/commit.c:398 +#: builtin/commit.c:403 msgid "cannot read the index" msgstr "" -#: builtin/commit.c:418 +#: builtin/commit.c:423 msgid "unable to write temporary index file" msgstr "" -#: builtin/commit.c:493 builtin/commit.c:499 +#: builtin/commit.c:511 builtin/commit.c:517 #, c-format msgid "invalid commit: %s" msgstr "" -#: builtin/commit.c:522 +#: builtin/commit.c:540 msgid "malformed --author parameter" msgstr "" -#: builtin/commit.c:582 +#: builtin/commit.c:560 #, c-format msgid "Malformed ident string: '%s'" msgstr "" -#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967 +#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954 #, c-format msgid "could not lookup commit %s" msgstr "" -#: builtin/commit.c:632 builtin/shortlog.c:296 +#: builtin/commit.c:610 builtin/shortlog.c:296 #, c-format msgid "(reading log message from standard input)\n" msgstr "" -#: builtin/commit.c:634 +#: builtin/commit.c:612 msgid "could not read log from standard input" msgstr "" -#: builtin/commit.c:638 +#: builtin/commit.c:616 #, c-format msgid "could not read log file '%s'" msgstr "" -#: builtin/commit.c:644 +#: builtin/commit.c:622 msgid "commit has empty message" msgstr "" -#: builtin/commit.c:660 +#: builtin/commit.c:638 msgid "could not read MERGE_MSG" msgstr "" -#: builtin/commit.c:664 +#: builtin/commit.c:642 msgid "could not read SQUASH_MSG" msgstr "" -#: builtin/commit.c:668 +#: builtin/commit.c:646 #, c-format msgid "could not read '%s'" msgstr "" -#: builtin/commit.c:720 +#: builtin/commit.c:707 msgid "could not write commit template" msgstr "" -#: builtin/commit.c:731 +#: builtin/commit.c:718 #, c-format msgid "" "\n" @@ -2159,7 +3262,7 @@ msgid "" "and try again.\n" msgstr "" -#: builtin/commit.c:736 +#: builtin/commit.c:723 #, c-format msgid "" "\n" @@ -2169,177 +3272,498 @@ msgid "" "and try again.\n" msgstr "" -#: builtin/commit.c:748 +#: builtin/commit.c:735 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be ignored, and an empty message aborts the commit.\n" msgstr "" -#: builtin/commit.c:753 +#: builtin/commit.c:740 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be kept; you may remove them yourself if you want to.\n" "An empty message aborts the commit.\n" msgstr "" -#: builtin/commit.c:766 +#: builtin/commit.c:753 #, c-format msgid "%sAuthor: %s" msgstr "" -#: builtin/commit.c:773 +#: builtin/commit.c:760 #, c-format msgid "%sCommitter: %s" msgstr "" -#: builtin/commit.c:793 +#: builtin/commit.c:780 msgid "Cannot read index" msgstr "" -#: builtin/commit.c:830 +#: builtin/commit.c:817 msgid "Error building trees" msgstr "" -#: builtin/commit.c:845 builtin/tag.c:361 +#: builtin/commit.c:832 builtin/tag.c:361 #, c-format msgid "Please supply the message using either -m or -F option.\n" msgstr "" -#: builtin/commit.c:942 +#: builtin/commit.c:929 #, c-format msgid "No existing author found with '%s'" msgstr "" -#: builtin/commit.c:957 builtin/commit.c:1157 +#: builtin/commit.c:944 builtin/commit.c:1148 #, c-format msgid "Invalid untracked files mode '%s'" msgstr "" -#: builtin/commit.c:997 +#: builtin/commit.c:984 msgid "Using both --reset-author and --author does not make sense" msgstr "" -#: builtin/commit.c:1008 +#: builtin/commit.c:995 msgid "You have nothing to amend." msgstr "" -#: builtin/commit.c:1011 +#: builtin/commit.c:998 msgid "You are in the middle of a merge -- cannot amend." msgstr "" -#: builtin/commit.c:1013 +#: builtin/commit.c:1000 msgid "You are in the middle of a cherry-pick -- cannot amend." msgstr "" -#: builtin/commit.c:1016 +#: builtin/commit.c:1003 msgid "Options --squash and --fixup cannot be used together" msgstr "" -#: builtin/commit.c:1026 +#: builtin/commit.c:1013 msgid "Only one of -c/-C/-F/--fixup can be used." msgstr "" -#: builtin/commit.c:1028 +#: builtin/commit.c:1015 msgid "Option -m cannot be combined with -c/-C/-F/--fixup." msgstr "" -#: builtin/commit.c:1036 +#: builtin/commit.c:1023 msgid "--reset-author can be used only with -C, -c or --amend." msgstr "" -#: builtin/commit.c:1053 +#: builtin/commit.c:1040 msgid "Only one of --include/--only/--all/--interactive/--patch can be used." msgstr "" -#: builtin/commit.c:1055 +#: builtin/commit.c:1042 msgid "No paths with --include/--only does not make sense." msgstr "" -#: builtin/commit.c:1057 +#: builtin/commit.c:1044 msgid "Clever... amending the last one with dirty index." msgstr "" -#: builtin/commit.c:1059 +#: builtin/commit.c:1046 msgid "Explicit paths specified without -i nor -o; assuming --only paths..." msgstr "" -#: builtin/commit.c:1069 builtin/tag.c:577 +#: builtin/commit.c:1056 builtin/tag.c:577 #, c-format msgid "Invalid cleanup mode %s" msgstr "" -#: builtin/commit.c:1074 +#: builtin/commit.c:1061 msgid "Paths with -a does not make sense." msgstr "" -#: builtin/commit.c:1257 +#: builtin/commit.c:1067 builtin/commit.c:1202 +msgid "--long and -z are incompatible" +msgstr "" + +#: builtin/commit.c:1162 builtin/commit.c:1398 +msgid "show status concisely" +msgstr "" + +#: builtin/commit.c:1164 builtin/commit.c:1400 +msgid "show branch information" +msgstr "" + +#: builtin/commit.c:1166 builtin/commit.c:1402 builtin/push.c:389 +msgid "machine-readable output" +msgstr "" + +#: builtin/commit.c:1169 builtin/commit.c:1404 +msgid "show status in long format (default)" +msgstr "" + +#: builtin/commit.c:1172 builtin/commit.c:1407 +msgid "terminate entries with NUL" +msgstr "" + +#: builtin/commit.c:1174 builtin/commit.c:1410 builtin/fast-export.c:636 +#: builtin/fast-export.c:639 builtin/tag.c:461 +msgid "mode" +msgstr "" + +#: builtin/commit.c:1175 builtin/commit.c:1410 +msgid "show untracked files, optional modes: all, normal, no. (Default: all)" +msgstr "" + +#: builtin/commit.c:1178 +msgid "show ignored files" +msgstr "" + +#: builtin/commit.c:1179 parse-options.h:151 +msgid "when" +msgstr "" + +#: builtin/commit.c:1180 +msgid "" +"ignore changes to submodules, optional when: all, dirty, untracked. " +"(Default: all)" +msgstr "" + +#: builtin/commit.c:1182 +msgid "list untracked files in columns" +msgstr "" + +#: builtin/commit.c:1256 msgid "couldn't look up newly created commit" msgstr "" -#: builtin/commit.c:1259 +#: builtin/commit.c:1258 msgid "could not parse newly created commit" msgstr "" -#: builtin/commit.c:1300 +#: builtin/commit.c:1299 msgid "detached HEAD" msgstr "" -#: builtin/commit.c:1302 +#: builtin/commit.c:1301 msgid " (root-commit)" msgstr "" -#: builtin/commit.c:1446 +#: builtin/commit.c:1368 +msgid "suppress summary after successful commit" +msgstr "" + +#: builtin/commit.c:1369 +msgid "show diff in commit message template" +msgstr "" + +#: builtin/commit.c:1371 +msgid "Commit message options" +msgstr "" + +#: builtin/commit.c:1372 builtin/tag.c:459 +msgid "read message from file" +msgstr "" + +#: builtin/commit.c:1373 +msgid "author" +msgstr "" + +#: builtin/commit.c:1373 +msgid "override author for commit" +msgstr "" + +#: builtin/commit.c:1374 builtin/gc.c:178 +msgid "date" +msgstr "" + +#: builtin/commit.c:1374 +msgid "override date for commit" +msgstr "" + +#: builtin/commit.c:1375 builtin/merge.c:206 builtin/notes.c:537 +#: builtin/notes.c:694 builtin/tag.c:457 +msgid "message" +msgstr "" + +#: builtin/commit.c:1375 +msgid "commit message" +msgstr "" + +#: builtin/commit.c:1376 +msgid "reuse and edit message from specified commit" +msgstr "" + +#: builtin/commit.c:1377 +msgid "reuse message from specified commit" +msgstr "" + +#: builtin/commit.c:1378 +msgid "use autosquash formatted message to fixup specified commit" +msgstr "" + +#: builtin/commit.c:1379 +msgid "use autosquash formatted message to squash specified commit" +msgstr "" + +#: builtin/commit.c:1380 +msgid "the commit is authored by me now (used with -C/-c/--amend)" +msgstr "" + +#: builtin/commit.c:1381 builtin/log.c:1073 builtin/revert.c:109 +msgid "add Signed-off-by:" +msgstr "" + +#: builtin/commit.c:1382 +msgid "use specified template file" +msgstr "" + +#: builtin/commit.c:1383 +msgid "force edit of commit" +msgstr "" + +#: builtin/commit.c:1384 +msgid "default" +msgstr "" + +#: builtin/commit.c:1384 builtin/tag.c:462 +msgid "how to strip spaces and #comments from message" +msgstr "" + +#: builtin/commit.c:1385 +msgid "include status in commit message template" +msgstr "" + +#: builtin/commit.c:1386 builtin/merge.c:213 builtin/tag.c:463 +msgid "key id" +msgstr "" + +#: builtin/commit.c:1387 builtin/merge.c:214 +msgid "GPG sign commit" +msgstr "" + +#. end commit message options +#: builtin/commit.c:1390 +msgid "Commit contents options" +msgstr "" + +#: builtin/commit.c:1391 +msgid "commit all changed files" +msgstr "" + +#: builtin/commit.c:1392 +msgid "add specified files to index for commit" +msgstr "" + +#: builtin/commit.c:1393 +msgid "interactively add files" +msgstr "" + +#: builtin/commit.c:1394 +msgid "interactively add changes" +msgstr "" + +#: builtin/commit.c:1395 +msgid "commit only specified files" +msgstr "" + +#: builtin/commit.c:1396 +msgid "bypass pre-commit hook" +msgstr "" + +#: builtin/commit.c:1397 +msgid "show what would be committed" +msgstr "" + +#: builtin/commit.c:1408 +msgid "amend previous commit" +msgstr "" + +#: builtin/commit.c:1409 +msgid "bypass post-rewrite hook" +msgstr "" + +#: builtin/commit.c:1414 +msgid "ok to record an empty change" +msgstr "" + +#: builtin/commit.c:1417 +msgid "ok to record a change with an empty message" +msgstr "" + +#: builtin/commit.c:1449 msgid "could not parse HEAD commit" msgstr "" -#: builtin/commit.c:1484 builtin/merge.c:509 +#: builtin/commit.c:1487 builtin/merge.c:508 #, c-format msgid "could not open '%s' for reading" msgstr "" -#: builtin/commit.c:1491 +#: builtin/commit.c:1494 #, c-format msgid "Corrupt MERGE_HEAD file (%s)" msgstr "" -#: builtin/commit.c:1498 +#: builtin/commit.c:1501 msgid "could not read MERGE_MODE" msgstr "" -#: builtin/commit.c:1517 +#: builtin/commit.c:1520 #, c-format msgid "could not read commit message: %s" msgstr "" -#: builtin/commit.c:1531 +#: builtin/commit.c:1534 #, c-format msgid "Aborting commit; you did not edit the message.\n" msgstr "" -#: builtin/commit.c:1536 +#: builtin/commit.c:1539 #, c-format msgid "Aborting commit due to empty commit message.\n" msgstr "" -#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961 +#: builtin/commit.c:1554 builtin/merge.c:832 builtin/merge.c:857 msgid "failed to write commit object" msgstr "" -#: builtin/commit.c:1572 +#: builtin/commit.c:1575 msgid "cannot lock HEAD ref" msgstr "" -#: builtin/commit.c:1576 +#: builtin/commit.c:1579 msgid "cannot update HEAD ref" msgstr "" -#: builtin/commit.c:1587 +#: builtin/commit.c:1590 msgid "" "Repository has been updated, but unable to write\n" "new_index file. Check that disk is not full or quota is\n" "not exceeded, and then \"git reset HEAD\" to recover." msgstr "" +#: builtin/config.c:7 +msgid "git config [options]" +msgstr "" + +#: builtin/config.c:51 +msgid "Config file location" +msgstr "" + +#: builtin/config.c:52 +msgid "use global config file" +msgstr "" + +#: builtin/config.c:53 +msgid "use system config file" +msgstr "" + +#: builtin/config.c:54 +msgid "use repository config file" +msgstr "" + +#: builtin/config.c:55 +msgid "use given config file" +msgstr "" + +#: builtin/config.c:56 +msgid "Action" +msgstr "" + +#: builtin/config.c:57 +msgid "get value: name [value-regex]" +msgstr "" + +#: builtin/config.c:58 +msgid "get all values: key [value-regex]" +msgstr "" + +#: builtin/config.c:59 +msgid "get values for regexp: name-regex [value-regex]" +msgstr "" + +#: builtin/config.c:60 +msgid "replace all matching variables: name value [value_regex]" +msgstr "" + +#: builtin/config.c:61 +msgid "add a new variable: name value" +msgstr "" + +#: builtin/config.c:62 +msgid "remove a variable: name [value-regex]" +msgstr "" + +#: builtin/config.c:63 +msgid "remove all matches: name [value-regex]" +msgstr "" + +#: builtin/config.c:64 +msgid "rename section: old-name new-name" +msgstr "" + +#: builtin/config.c:65 +msgid "remove a section: name" +msgstr "" + +#: builtin/config.c:66 +msgid "list all" +msgstr "" + +#: builtin/config.c:67 +msgid "open an editor" +msgstr "" + +#: builtin/config.c:68 builtin/config.c:69 +msgid "slot" +msgstr "" + +#: builtin/config.c:68 +msgid "find the color configured: [default]" +msgstr "" + +#: builtin/config.c:69 +msgid "find the color setting: [stdout-is-tty]" +msgstr "" + +#: builtin/config.c:70 +msgid "Type" +msgstr "" + +#: builtin/config.c:71 +msgid "value is \"true\" or \"false\"" +msgstr "" + +#: builtin/config.c:72 +msgid "value is decimal number" +msgstr "" + +#: builtin/config.c:73 +msgid "value is --bool or --int" +msgstr "" + +#: builtin/config.c:74 +msgid "value is a path (file or directory name)" +msgstr "" + +#: builtin/config.c:75 +msgid "Other" +msgstr "" + +#: builtin/config.c:76 +msgid "terminate values with NUL byte" +msgstr "" + +#: builtin/config.c:77 +msgid "respect include directives on lookup" +msgstr "" + +#: builtin/count-objects.c:69 +msgid "git count-objects [-v]" +msgstr "" + +#: builtin/describe.c:15 +msgid "git describe [options] <committish>*" +msgstr "" + +#: builtin/describe.c:16 +msgid "git describe [options] --dirty" +msgstr "" + #: builtin/describe.c:234 #, c-format msgid "annotated tag %s not available" @@ -2406,6 +3830,50 @@ msgid "" "gave up search at %s\n" msgstr "" +#: builtin/describe.c:403 +msgid "find the tag that comes after the commit" +msgstr "" + +#: builtin/describe.c:404 +msgid "debug search strategy on stderr" +msgstr "" + +#: builtin/describe.c:405 +msgid "use any ref in .git/refs" +msgstr "" + +#: builtin/describe.c:406 +msgid "use any tag in .git/refs/tags" +msgstr "" + +#: builtin/describe.c:407 +msgid "always use long format" +msgstr "" + +#: builtin/describe.c:410 +msgid "only output exact matches" +msgstr "" + +#: builtin/describe.c:412 +msgid "consider <n> most recent tags (default: 10)" +msgstr "" + +#: builtin/describe.c:414 +msgid "only consider tags matching <pattern>" +msgstr "" + +#: builtin/describe.c:416 builtin/name-rev.c:238 +msgid "show abbreviated commit object as fallback" +msgstr "" + +#: builtin/describe.c:417 +msgid "mark" +msgstr "" + +#: builtin/describe.c:418 +msgid "append <mark> on dirty working tree (default: \"-dirty\")" +msgstr "" + #: builtin/describe.c:436 msgid "--long is incompatible with --abbrev=0" msgstr "" @@ -2418,45 +3886,165 @@ msgstr "" msgid "--dirty is incompatible with committishes" msgstr "" -#: builtin/diff.c:77 +#: builtin/diff.c:79 #, c-format msgid "'%s': not a regular file or symlink" msgstr "" -#: builtin/diff.c:220 +#: builtin/diff.c:228 #, c-format msgid "invalid option: %s" msgstr "" -#: builtin/diff.c:297 +#: builtin/diff.c:305 msgid "Not a git repository" msgstr "" -#: builtin/diff.c:347 +#: builtin/diff.c:348 #, c-format msgid "invalid object '%s' given." msgstr "" -#: builtin/diff.c:352 +#: builtin/diff.c:353 #, c-format msgid "more than %d trees given: '%s'" msgstr "" -#: builtin/diff.c:362 +#: builtin/diff.c:363 #, c-format msgid "more than two blobs given: '%s'" msgstr "" -#: builtin/diff.c:370 +#: builtin/diff.c:371 #, c-format msgid "unhandled object '%s' given." msgstr "" -#: builtin/fetch.c:200 +#: builtin/fast-export.c:22 +msgid "git fast-export [rev-list-opts]" +msgstr "" + +#: builtin/fast-export.c:635 +msgid "show progress after <n> objects" +msgstr "" + +#: builtin/fast-export.c:637 +msgid "select handling of signed tags" +msgstr "" + +#: builtin/fast-export.c:640 +msgid "select handling of tags that tag filtered objects" +msgstr "" + +#: builtin/fast-export.c:643 +msgid "Dump marks to this file" +msgstr "" + +#: builtin/fast-export.c:645 +msgid "Import marks from this file" +msgstr "" + +#: builtin/fast-export.c:647 +msgid "Fake a tagger when tags lack one" +msgstr "" + +#: builtin/fast-export.c:649 +msgid "Output full tree for each commit" +msgstr "" + +#: builtin/fast-export.c:651 +msgid "Use the done feature to terminate the stream" +msgstr "" + +#: builtin/fast-export.c:652 +msgid "Skip output of blob data" +msgstr "" + +#: builtin/fetch.c:20 +msgid "git fetch [<options>] [<repository> [<refspec>...]]" +msgstr "" + +#: builtin/fetch.c:21 +msgid "git fetch [<options>] <group>" +msgstr "" + +#: builtin/fetch.c:22 +msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]" +msgstr "" + +#: builtin/fetch.c:23 +msgid "git fetch --all [<options>]" +msgstr "" + +#: builtin/fetch.c:60 +msgid "fetch from all remotes" +msgstr "" + +#: builtin/fetch.c:62 +msgid "append to .git/FETCH_HEAD instead of overwriting" +msgstr "" + +#: builtin/fetch.c:64 +msgid "path to upload pack on remote end" +msgstr "" + +#: builtin/fetch.c:65 +msgid "force overwrite of local branch" +msgstr "" + +#: builtin/fetch.c:67 +msgid "fetch from multiple remotes" +msgstr "" + +#: builtin/fetch.c:69 +msgid "fetch all tags and associated objects" +msgstr "" + +#: builtin/fetch.c:71 +msgid "do not fetch all tags (--no-tags)" +msgstr "" + +#: builtin/fetch.c:73 +msgid "prune remote-tracking branches no longer on remote" +msgstr "" + +#: builtin/fetch.c:74 +msgid "on-demand" +msgstr "" + +#: builtin/fetch.c:75 +msgid "control recursive fetching of submodules" +msgstr "" + +#: builtin/fetch.c:79 +msgid "keep downloaded pack" +msgstr "" + +#: builtin/fetch.c:81 +msgid "allow updating of HEAD ref" +msgstr "" + +#: builtin/fetch.c:84 +msgid "deepen history of shallow clone" +msgstr "" + +#: builtin/fetch.c:85 builtin/log.c:1088 +msgid "dir" +msgstr "" + +#: builtin/fetch.c:86 +msgid "prepend this to submodule path output" +msgstr "" + +#: builtin/fetch.c:89 +msgid "default mode for recursion" +msgstr "" + +#: builtin/fetch.c:201 msgid "Couldn't find remote ref HEAD" msgstr "" -#: builtin/fetch.c:253 +#: builtin/fetch.c:254 #, c-format msgid "object %s not found" msgstr "" @@ -2566,43 +4154,161 @@ msgstr "" msgid "Option \"%s\" is ignored for %s\n" msgstr "" -#: builtin/fetch.c:888 +#: builtin/fetch.c:891 #, c-format msgid "Fetching %s\n" msgstr "" -#: builtin/fetch.c:890 builtin/remote.c:100 +#: builtin/fetch.c:893 builtin/remote.c:100 #, c-format msgid "Could not fetch %s" msgstr "" -#: builtin/fetch.c:907 +#: builtin/fetch.c:912 msgid "" "No remote repository specified. Please, specify either a URL or a\n" "remote name from which new revisions should be fetched." msgstr "" -#: builtin/fetch.c:927 +#: builtin/fetch.c:932 msgid "You need to specify a tag name." msgstr "" -#: builtin/fetch.c:979 +#: builtin/fetch.c:984 msgid "fetch --all does not take a repository argument" msgstr "" -#: builtin/fetch.c:981 +#: builtin/fetch.c:986 msgid "fetch --all does not make sense with refspecs" msgstr "" -#: builtin/fetch.c:992 +#: builtin/fetch.c:997 #, c-format msgid "No such remote or remote group: %s" msgstr "" -#: builtin/fetch.c:1000 +#: builtin/fetch.c:1005 msgid "Fetching a group and specifying refspecs does not make sense" msgstr "" +#: builtin/fmt-merge-msg.c:13 +msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]" +msgstr "" + +#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:701 +#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175 +#: builtin/tag.c:448 parse-options.h:133 parse-options.h:235 +msgid "n" +msgstr "" + +#: builtin/fmt-merge-msg.c:654 +msgid "populate log with at most <n> entries from shortlog" +msgstr "" + +#: builtin/fmt-merge-msg.c:657 +msgid "alias for --log (deprecated)" +msgstr "" + +#: builtin/fmt-merge-msg.c:660 +msgid "text" +msgstr "" + +#: builtin/fmt-merge-msg.c:661 +msgid "use <text> as start of message" +msgstr "" + +#: builtin/fmt-merge-msg.c:662 +msgid "file to read from" +msgstr "" + +#: builtin/for-each-ref.c:979 +msgid "git for-each-ref [options] [<pattern>]" +msgstr "" + +#: builtin/for-each-ref.c:994 +msgid "quote placeholders suitably for shells" +msgstr "" + +#: builtin/for-each-ref.c:996 +msgid "quote placeholders suitably for perl" +msgstr "" + +#: builtin/for-each-ref.c:998 +msgid "quote placeholders suitably for python" +msgstr "" + +#: builtin/for-each-ref.c:1000 +msgid "quote placeholders suitably for tcl" +msgstr "" + +#: builtin/for-each-ref.c:1003 +msgid "show only <n> matched refs" +msgstr "" + +#: builtin/for-each-ref.c:1004 +msgid "format" +msgstr "" + +#: builtin/for-each-ref.c:1004 +msgid "format to use for the output" +msgstr "" + +#: builtin/for-each-ref.c:1005 +msgid "key" +msgstr "" + +#: builtin/for-each-ref.c:1006 +msgid "field name to sort on" +msgstr "" + +#: builtin/fsck.c:608 +msgid "git fsck [options] [<object>...]" +msgstr "" + +#: builtin/fsck.c:614 +msgid "show unreachable objects" +msgstr "" + +#: builtin/fsck.c:615 +msgid "show dangling objects" +msgstr "" + +#: builtin/fsck.c:616 +msgid "report tags" +msgstr "" + +#: builtin/fsck.c:617 +msgid "report root nodes" +msgstr "" + +#: builtin/fsck.c:618 +msgid "make index objects head nodes" +msgstr "" + +#: builtin/fsck.c:619 +msgid "make reflogs head nodes (default)" +msgstr "" + +#: builtin/fsck.c:620 +msgid "also consider packs and alternate objects" +msgstr "" + +#: builtin/fsck.c:621 +msgid "enable more strict checking" +msgstr "" + +#: builtin/fsck.c:623 +msgid "write dangling objects in .git/lost-found" +msgstr "" + +#: builtin/fsck.c:624 builtin/prune.c:134 +msgid "show progress" +msgstr "" + +#: builtin/gc.c:22 +msgid "git gc [options]" +msgstr "" + #: builtin/gc.c:63 #, c-format msgid "Invalid %s: '%s'" @@ -2613,379 +4319,653 @@ msgstr "" msgid "insanely long object directory %.*s" msgstr "" -#: builtin/gc.c:221 -#, c-format -msgid "Auto packing the repository for optimum performance.\n" +#: builtin/gc.c:179 +msgid "prune unreferenced objects" +msgstr "" + +#: builtin/gc.c:181 +msgid "be more thorough (increased runtime)" +msgstr "" + +#: builtin/gc.c:182 +msgid "enable auto-gc mode" msgstr "" -#: builtin/gc.c:224 +#: builtin/gc.c:222 #, c-format msgid "" "Auto packing the repository for optimum performance. You may also\n" "run \"git gc\" manually. See \"git help gc\" for more information.\n" msgstr "" -#: builtin/gc.c:251 +#: builtin/gc.c:249 msgid "" "There are too many unreachable loose objects; run 'git prune' to remove them." msgstr "" -#: builtin/grep.c:216 +#: builtin/grep.c:22 +msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]" +msgstr "" + +#: builtin/grep.c:217 #, c-format msgid "grep: failed to create thread: %s" msgstr "" -#: builtin/grep.c:402 +#: builtin/grep.c:365 #, c-format msgid "Failed to chdir: %s" msgstr "" -#: builtin/grep.c:478 builtin/grep.c:512 +#: builtin/grep.c:443 builtin/grep.c:478 #, c-format msgid "unable to read tree (%s)" msgstr "" -#: builtin/grep.c:526 +#: builtin/grep.c:493 #, c-format msgid "unable to grep from object of type %s" msgstr "" -#: builtin/grep.c:584 +#: builtin/grep.c:551 #, c-format msgid "switch `%c' expects a numerical value" msgstr "" -#: builtin/grep.c:601 +#: builtin/grep.c:568 #, c-format msgid "cannot open '%s'" msgstr "" -#: builtin/grep.c:885 +#: builtin/grep.c:643 +msgid "search in index instead of in the work tree" +msgstr "" + +#: builtin/grep.c:645 +msgid "find in contents not managed by git" +msgstr "" + +#: builtin/grep.c:647 +msgid "search in both tracked and untracked files" +msgstr "" + +#: builtin/grep.c:649 +msgid "search also in ignored files" +msgstr "" + +#: builtin/grep.c:652 +msgid "show non-matching lines" +msgstr "" + +#: builtin/grep.c:654 +msgid "case insensitive matching" +msgstr "" + +#: builtin/grep.c:656 +msgid "match patterns only at word boundaries" +msgstr "" + +#: builtin/grep.c:658 +msgid "process binary files as text" +msgstr "" + +#: builtin/grep.c:660 +msgid "don't match patterns in binary files" +msgstr "" + +#: builtin/grep.c:663 +msgid "descend at most <depth> levels" +msgstr "" + +#: builtin/grep.c:667 +msgid "use extended POSIX regular expressions" +msgstr "" + +#: builtin/grep.c:670 +msgid "use basic POSIX regular expressions (default)" +msgstr "" + +#: builtin/grep.c:673 +msgid "interpret patterns as fixed strings" +msgstr "" + +#: builtin/grep.c:676 +msgid "use Perl-compatible regular expressions" +msgstr "" + +#: builtin/grep.c:679 +msgid "show line numbers" +msgstr "" + +#: builtin/grep.c:680 +msgid "don't show filenames" +msgstr "" + +#: builtin/grep.c:681 +msgid "show filenames" +msgstr "" + +#: builtin/grep.c:683 +msgid "show filenames relative to top directory" +msgstr "" + +#: builtin/grep.c:685 +msgid "show only filenames instead of matching lines" +msgstr "" + +#: builtin/grep.c:687 +msgid "synonym for --files-with-matches" +msgstr "" + +#: builtin/grep.c:690 +msgid "show only the names of files without match" +msgstr "" + +#: builtin/grep.c:692 +msgid "print NUL after filenames" +msgstr "" + +#: builtin/grep.c:694 +msgid "show the number of matches instead of matching lines" +msgstr "" + +#: builtin/grep.c:695 +msgid "highlight matches" +msgstr "" + +#: builtin/grep.c:697 +msgid "print empty line between matches from different files" +msgstr "" + +#: builtin/grep.c:699 +msgid "show filename only once above matches from same file" +msgstr "" + +#: builtin/grep.c:702 +msgid "show <n> context lines before and after matches" +msgstr "" + +#: builtin/grep.c:705 +msgid "show <n> context lines before matches" +msgstr "" + +#: builtin/grep.c:707 +msgid "show <n> context lines after matches" +msgstr "" + +#: builtin/grep.c:708 +msgid "shortcut for -C NUM" +msgstr "" + +#: builtin/grep.c:711 +msgid "show a line with the function name before matches" +msgstr "" + +#: builtin/grep.c:713 +msgid "show the surrounding function" +msgstr "" + +#: builtin/grep.c:716 +msgid "read patterns from file" +msgstr "" + +#: builtin/grep.c:718 +msgid "match <pattern>" +msgstr "" + +#: builtin/grep.c:720 +msgid "combine patterns specified with -e" +msgstr "" + +#: builtin/grep.c:732 +msgid "indicate hit with exit status without output" +msgstr "" + +#: builtin/grep.c:734 +msgid "show only matches from files that match all patterns" +msgstr "" + +#: builtin/grep.c:736 +msgid "show parse tree for grep expression" +msgstr "" + +#: builtin/grep.c:740 +msgid "pager" +msgstr "" + +#: builtin/grep.c:740 +msgid "show matching files in the pager" +msgstr "" + +#: builtin/grep.c:743 +msgid "allow calling of grep(1) (ignored by this build)" +msgstr "" + +#: builtin/grep.c:744 builtin/show-ref.c:184 +msgid "show usage" +msgstr "" + +#: builtin/grep.c:811 msgid "no pattern given." msgstr "" -#: builtin/grep.c:899 +#: builtin/grep.c:825 #, c-format msgid "bad object %s" msgstr "" -#: builtin/grep.c:940 +#: builtin/grep.c:866 msgid "--open-files-in-pager only works on the worktree" msgstr "" -#: builtin/grep.c:963 +#: builtin/grep.c:889 msgid "--cached or --untracked cannot be used with --no-index." msgstr "" -#: builtin/grep.c:968 +#: builtin/grep.c:894 msgid "--no-index or --untracked cannot be used with revs." msgstr "" -#: builtin/grep.c:971 +#: builtin/grep.c:897 msgid "--[no-]exclude-standard cannot be used for tracked contents." msgstr "" -#: builtin/grep.c:979 +#: builtin/grep.c:905 msgid "both --cached and trees are given." msgstr "" -#: builtin/help.c:59 +#: builtin/hash-object.c:60 +msgid "" +"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] " +"<file>..." +msgstr "" + +#: builtin/hash-object.c:61 +msgid "git hash-object --stdin-paths < <list-of-paths>" +msgstr "" + +#: builtin/hash-object.c:72 +msgid "type" +msgstr "" + +#: builtin/hash-object.c:72 +msgid "object type" +msgstr "" + +#: builtin/hash-object.c:73 +msgid "write the object into the object database" +msgstr "" + +#: builtin/hash-object.c:74 +msgid "read the object from stdin" +msgstr "" + +#: builtin/hash-object.c:76 +msgid "store file as is without filters" +msgstr "" + +#: builtin/hash-object.c:77 +msgid "process file as it were from this path" +msgstr "" + +#: builtin/help.c:43 +msgid "print all available commands" +msgstr "" + +#: builtin/help.c:44 +msgid "show man page" +msgstr "" + +#: builtin/help.c:45 +msgid "show manual in web browser" +msgstr "" + +#: builtin/help.c:47 +msgid "show info page" +msgstr "" + +#: builtin/help.c:53 +msgid "git help [--all] [--man|--web|--info] [command]" +msgstr "" + +#: builtin/help.c:65 #, c-format msgid "unrecognized help format '%s'" msgstr "" -#: builtin/help.c:87 +#: builtin/help.c:93 msgid "Failed to start emacsclient." msgstr "" -#: builtin/help.c:100 +#: builtin/help.c:106 msgid "Failed to parse emacsclient version." msgstr "" -#: builtin/help.c:108 +#: builtin/help.c:114 #, c-format msgid "emacsclient version '%d' too old (< 22)." msgstr "" -#: builtin/help.c:126 builtin/help.c:154 builtin/help.c:163 builtin/help.c:171 +#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177 #, c-format msgid "failed to exec '%s': %s" msgstr "" -#: builtin/help.c:211 +#: builtin/help.c:217 #, c-format msgid "" "'%s': path for unsupported man viewer.\n" "Please consider using 'man.<tool>.cmd' instead." msgstr "" -#: builtin/help.c:223 +#: builtin/help.c:229 #, c-format msgid "" "'%s': cmd for supported man viewer.\n" "Please consider using 'man.<tool>.path' instead." msgstr "" -#: builtin/help.c:287 +#: builtin/help.c:299 msgid "The most commonly used git commands are:" msgstr "" -#: builtin/help.c:355 +#: builtin/help.c:367 #, c-format msgid "'%s': unknown man viewer." msgstr "" -#: builtin/help.c:372 +#: builtin/help.c:384 msgid "no man viewer handled the request" msgstr "" -#: builtin/help.c:380 +#: builtin/help.c:392 msgid "no info viewer handled the request" msgstr "" -#: builtin/help.c:391 -#, c-format -msgid "'%s': not a documentation directory." -msgstr "" - -#: builtin/help.c:432 builtin/help.c:439 +#: builtin/help.c:447 builtin/help.c:454 #, c-format msgid "usage: %s%s" msgstr "" -#: builtin/help.c:453 +#: builtin/help.c:470 #, c-format msgid "`git %s' is aliased to `%s'" msgstr "" -#: builtin/index-pack.c:169 +#: builtin/index-pack.c:170 #, c-format msgid "object type mismatch at %s" msgstr "" -#: builtin/index-pack.c:189 +#: builtin/index-pack.c:190 msgid "object of unexpected type" msgstr "" -#: builtin/index-pack.c:226 +#: builtin/index-pack.c:227 #, c-format msgid "cannot fill %d byte" msgid_plural "cannot fill %d bytes" msgstr[0] "" msgstr[1] "" -#: builtin/index-pack.c:236 +#: builtin/index-pack.c:237 msgid "early EOF" msgstr "" -#: builtin/index-pack.c:237 +#: builtin/index-pack.c:238 msgid "read error on input" msgstr "" -#: builtin/index-pack.c:249 +#: builtin/index-pack.c:250 msgid "used more bytes than were available" msgstr "" -#: builtin/index-pack.c:256 +#: builtin/index-pack.c:257 msgid "pack too large for current definition of off_t" msgstr "" -#: builtin/index-pack.c:272 +#: builtin/index-pack.c:273 #, c-format msgid "unable to create '%s'" msgstr "" -#: builtin/index-pack.c:277 +#: builtin/index-pack.c:278 #, c-format msgid "cannot open packfile '%s'" msgstr "" -#: builtin/index-pack.c:291 +#: builtin/index-pack.c:292 msgid "pack signature mismatch" msgstr "" -#: builtin/index-pack.c:311 +#: builtin/index-pack.c:294 +#, c-format +msgid "pack version %<PRIu32> unsupported" +msgstr "" + +#: builtin/index-pack.c:312 #, c-format msgid "pack has bad object at offset %lu: %s" msgstr "" -#: builtin/index-pack.c:405 +#: builtin/index-pack.c:434 #, c-format msgid "inflate returned %d" msgstr "" -#: builtin/index-pack.c:450 +#: builtin/index-pack.c:483 msgid "offset value overflow for delta base object" msgstr "" -#: builtin/index-pack.c:458 +#: builtin/index-pack.c:491 msgid "delta base offset is out of bound" msgstr "" -#: builtin/index-pack.c:466 +#: builtin/index-pack.c:499 #, c-format msgid "unknown object type %d" msgstr "" -#: builtin/index-pack.c:495 +#: builtin/index-pack.c:530 msgid "cannot pread pack file" msgstr "" -#: builtin/index-pack.c:497 +#: builtin/index-pack.c:532 #, c-format msgid "premature end of pack file, %lu byte missing" msgid_plural "premature end of pack file, %lu bytes missing" msgstr[0] "" msgstr[1] "" -#: builtin/index-pack.c:510 +#: builtin/index-pack.c:558 msgid "serious inflate inconsistency" msgstr "" -#: builtin/index-pack.c:583 +#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678 +#: builtin/index-pack.c:712 builtin/index-pack.c:721 #, c-format -msgid "cannot read existing object %s" +msgid "SHA1 COLLISION FOUND WITH %s !" msgstr "" -#: builtin/index-pack.c:586 +#: builtin/index-pack.c:652 builtin/pack-objects.c:170 +#: builtin/pack-objects.c:262 #, c-format -msgid "SHA1 COLLISION FOUND WITH %s !" +msgid "unable to read %s" +msgstr "" + +#: builtin/index-pack.c:718 +#, c-format +msgid "cannot read existing object %s" msgstr "" -#: builtin/index-pack.c:598 +#: builtin/index-pack.c:732 #, c-format msgid "invalid blob object %s" msgstr "" -#: builtin/index-pack.c:610 +#: builtin/index-pack.c:747 #, c-format msgid "invalid %s" msgstr "" -#: builtin/index-pack.c:612 +#: builtin/index-pack.c:749 msgid "Error in object" msgstr "" -#: builtin/index-pack.c:614 +#: builtin/index-pack.c:751 #, c-format msgid "Not all child objects of %s are reachable" msgstr "" -#: builtin/index-pack.c:687 builtin/index-pack.c:713 +#: builtin/index-pack.c:821 builtin/index-pack.c:847 msgid "failed to apply delta" msgstr "" -#: builtin/index-pack.c:850 +#: builtin/index-pack.c:986 msgid "Receiving objects" msgstr "" -#: builtin/index-pack.c:850 +#: builtin/index-pack.c:986 msgid "Indexing objects" msgstr "" -#: builtin/index-pack.c:872 +#: builtin/index-pack.c:1012 msgid "pack is corrupted (SHA1 mismatch)" msgstr "" -#: builtin/index-pack.c:877 +#: builtin/index-pack.c:1017 msgid "cannot fstat packfile" msgstr "" -#: builtin/index-pack.c:880 +#: builtin/index-pack.c:1020 msgid "pack has junk at the end" msgstr "" -#: builtin/index-pack.c:903 +#: builtin/index-pack.c:1031 +msgid "confusion beyond insanity in parse_pack_objects()" +msgstr "" + +#: builtin/index-pack.c:1054 msgid "Resolving deltas" msgstr "" -#: builtin/index-pack.c:954 +#: builtin/index-pack.c:1064 +#, c-format +msgid "unable to create thread: %s" +msgstr "" + +#: builtin/index-pack.c:1106 msgid "confusion beyond insanity" msgstr "" -#: builtin/index-pack.c:973 +#: builtin/index-pack.c:1112 +#, c-format +msgid "completed with %d local objects" +msgstr "" + +#: builtin/index-pack.c:1121 +#, c-format +msgid "Unexpected tail checksum for %s (disk corruption?)" +msgstr "" + +#: builtin/index-pack.c:1125 #, c-format msgid "pack has %d unresolved delta" msgid_plural "pack has %d unresolved deltas" msgstr[0] "" msgstr[1] "" -#: builtin/index-pack.c:998 +#: builtin/index-pack.c:1150 #, c-format msgid "unable to deflate appended object (%d)" msgstr "" -#: builtin/index-pack.c:1077 +#: builtin/index-pack.c:1229 #, c-format msgid "local object %s is corrupt" msgstr "" -#: builtin/index-pack.c:1101 +#: builtin/index-pack.c:1253 msgid "error while closing pack file" msgstr "" -#: builtin/index-pack.c:1114 +#: builtin/index-pack.c:1266 #, c-format msgid "cannot write keep file '%s'" msgstr "" -#: builtin/index-pack.c:1122 +#: builtin/index-pack.c:1274 #, c-format msgid "cannot close written keep file '%s'" msgstr "" -#: builtin/index-pack.c:1135 +#: builtin/index-pack.c:1287 msgid "cannot store pack file" msgstr "" -#: builtin/index-pack.c:1146 +#: builtin/index-pack.c:1298 msgid "cannot store index file" msgstr "" -#: builtin/index-pack.c:1247 +#: builtin/index-pack.c:1331 +#, c-format +msgid "bad pack.indexversion=%<PRIu32>" +msgstr "" + +#: builtin/index-pack.c:1337 +#, c-format +msgid "invalid number of threads specified (%d)" +msgstr "" + +#: builtin/index-pack.c:1341 builtin/index-pack.c:1514 +#, c-format +msgid "no threads support, ignoring %s" +msgstr "" + +#: builtin/index-pack.c:1399 #, c-format msgid "Cannot open existing pack file '%s'" msgstr "" -#: builtin/index-pack.c:1249 +#: builtin/index-pack.c:1401 #, c-format msgid "Cannot open existing pack idx file for '%s'" msgstr "" -#: builtin/index-pack.c:1296 +#: builtin/index-pack.c:1448 #, c-format msgid "non delta: %d object" msgid_plural "non delta: %d objects" msgstr[0] "" msgstr[1] "" -#: builtin/index-pack.c:1303 +#: builtin/index-pack.c:1455 #, c-format msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" msgstr[0] "" msgstr[1] "" -#: builtin/index-pack.c:1330 +#: builtin/index-pack.c:1482 msgid "Cannot come back to cwd" msgstr "" -#: builtin/index-pack.c:1374 builtin/index-pack.c:1377 -#: builtin/index-pack.c:1389 builtin/index-pack.c:1393 +#: builtin/index-pack.c:1526 builtin/index-pack.c:1529 +#: builtin/index-pack.c:1541 builtin/index-pack.c:1545 #, c-format msgid "bad %s" msgstr "" -#: builtin/index-pack.c:1407 +#: builtin/index-pack.c:1559 msgid "--fix-thin cannot be used without --stdin" msgstr "" -#: builtin/index-pack.c:1411 builtin/index-pack.c:1421 +#: builtin/index-pack.c:1563 builtin/index-pack.c:1573 #, c-format msgid "packfile name '%s' does not end with '.pack'" msgstr "" -#: builtin/index-pack.c:1430 +#: builtin/index-pack.c:1582 msgid "--verify with no packfile name given" msgstr "" @@ -3059,22 +5039,22 @@ msgstr "" msgid "insane git directory %s" msgstr "" -#: builtin/init-db.c:322 builtin/init-db.c:325 +#: builtin/init-db.c:323 builtin/init-db.c:326 #, c-format msgid "%s already exists" msgstr "" -#: builtin/init-db.c:354 +#: builtin/init-db.c:355 #, c-format msgid "unable to handle file type %d" msgstr "" -#: builtin/init-db.c:357 +#: builtin/init-db.c:358 #, c-format msgid "unable to move %s to %s" msgstr "" -#: builtin/init-db.c:362 +#: builtin/init-db.c:363 #, c-format msgid "Could not create git link %s" msgstr "" @@ -3084,151 +5064,453 @@ msgstr "" #. * existing" or "Initialized empty", the second " shared" or #. * "", and the last '%s%s' is the verbatim directory name. #. -#: builtin/init-db.c:419 +#: builtin/init-db.c:420 #, c-format msgid "%s%s Git repository in %s%s\n" msgstr "" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Reinitialized existing" msgstr "" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Initialized empty" msgstr "" -#: builtin/init-db.c:421 +#: builtin/init-db.c:422 msgid " shared" msgstr "" -#: builtin/init-db.c:440 +#: builtin/init-db.c:441 msgid "cannot tell cwd" msgstr "" -#: builtin/init-db.c:521 builtin/init-db.c:528 +#: builtin/init-db.c:467 +msgid "" +"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared" +"[=<permissions>]] [directory]" +msgstr "" + +#: builtin/init-db.c:490 +msgid "permissions" +msgstr "" + +#: builtin/init-db.c:491 +msgid "specify that the git repository is to be shared amongst several users" +msgstr "" + +#: builtin/init-db.c:493 builtin/prune-packed.c:77 +msgid "be quiet" +msgstr "" + +#: builtin/init-db.c:522 builtin/init-db.c:529 #, c-format msgid "cannot mkdir %s" msgstr "" -#: builtin/init-db.c:532 +#: builtin/init-db.c:533 #, c-format msgid "cannot chdir to %s" msgstr "" -#: builtin/init-db.c:554 +#: builtin/init-db.c:555 #, c-format msgid "" "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" "dir=<directory>)" msgstr "" -#: builtin/init-db.c:578 +#: builtin/init-db.c:579 msgid "Cannot access current working directory" msgstr "" -#: builtin/init-db.c:585 +#: builtin/init-db.c:586 #, c-format msgid "Cannot access work tree '%s'" msgstr "" -#: builtin/log.c:188 +#: builtin/log.c:37 +msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n" +msgstr "" + +#: builtin/log.c:38 +msgid " or: git show [options] <object>..." +msgstr "" + +#: builtin/log.c:100 +msgid "suppress diff output" +msgstr "" + +#: builtin/log.c:101 +msgid "show source" +msgstr "" + +#: builtin/log.c:102 +msgid "decorate options" +msgstr "" + +#: builtin/log.c:189 #, c-format msgid "Final output: %d %s\n" msgstr "" -#: builtin/log.c:401 builtin/log.c:489 +#: builtin/log.c:405 builtin/log.c:497 #, c-format msgid "Could not read object %s" msgstr "" -#: builtin/log.c:513 +#: builtin/log.c:521 #, c-format msgid "Unknown type: %d" msgstr "" -#: builtin/log.c:602 +#: builtin/log.c:613 msgid "format.headers without value" msgstr "" -#: builtin/log.c:676 +#: builtin/log.c:687 msgid "name of output directory is too long" msgstr "" -#: builtin/log.c:687 +#: builtin/log.c:698 #, c-format msgid "Cannot open patch file %s" msgstr "" -#: builtin/log.c:701 +#: builtin/log.c:712 msgid "Need exactly one range." msgstr "" -#: builtin/log.c:709 +#: builtin/log.c:720 msgid "Not a range." msgstr "" -#: builtin/log.c:786 +#: builtin/log.c:794 msgid "Cover letter needs email format" msgstr "" -#: builtin/log.c:859 +#: builtin/log.c:867 #, c-format msgid "insane in-reply-to: %s" msgstr "" -#: builtin/log.c:932 +#: builtin/log.c:895 +msgid "git format-patch [options] [<since> | <revision range>]" +msgstr "" + +#: builtin/log.c:940 msgid "Two output directories?" msgstr "" -#: builtin/log.c:1153 +#: builtin/log.c:1068 +msgid "use [PATCH n/m] even with a single patch" +msgstr "" + +#: builtin/log.c:1071 +msgid "use [PATCH] even with multiple patches" +msgstr "" + +#: builtin/log.c:1075 +msgid "print patches to standard out" +msgstr "" + +#: builtin/log.c:1077 +msgid "generate a cover letter" +msgstr "" + +#: builtin/log.c:1079 +msgid "use simple number sequence for output file names" +msgstr "" + +#: builtin/log.c:1080 +msgid "sfx" +msgstr "" + +#: builtin/log.c:1081 +msgid "use <sfx> instead of '.patch'" +msgstr "" + +#: builtin/log.c:1083 +msgid "start numbering patches at <n> instead of 1" +msgstr "" + +#: builtin/log.c:1085 +msgid "Use [<prefix>] instead of [PATCH]" +msgstr "" + +#: builtin/log.c:1088 +msgid "store resulting files in <dir>" +msgstr "" + +#: builtin/log.c:1091 +msgid "don't strip/add [PATCH]" +msgstr "" + +#: builtin/log.c:1094 +msgid "don't output binary diffs" +msgstr "" + +#: builtin/log.c:1096 +msgid "don't include a patch matching a commit upstream" +msgstr "" + +#: builtin/log.c:1098 +msgid "show patch format instead of default (patch + stat)" +msgstr "" + +#: builtin/log.c:1100 +msgid "Messaging" +msgstr "" + +#: builtin/log.c:1101 +msgid "header" +msgstr "" + +#: builtin/log.c:1102 +msgid "add email header" +msgstr "" + +#: builtin/log.c:1103 builtin/log.c:1105 +msgid "email" +msgstr "" + +#: builtin/log.c:1103 +msgid "add To: header" +msgstr "" + +#: builtin/log.c:1105 +msgid "add Cc: header" +msgstr "" + +#: builtin/log.c:1107 +msgid "message-id" +msgstr "" + +#: builtin/log.c:1108 +msgid "make first mail a reply to <message-id>" +msgstr "" + +#: builtin/log.c:1109 builtin/log.c:1112 +msgid "boundary" +msgstr "" + +#: builtin/log.c:1110 +msgid "attach the patch" +msgstr "" + +#: builtin/log.c:1113 +msgid "inline the patch" +msgstr "" + +#: builtin/log.c:1117 +msgid "enable message threading, styles: shallow, deep" +msgstr "" + +#: builtin/log.c:1119 +msgid "signature" +msgstr "" + +#: builtin/log.c:1120 +msgid "add a signature" +msgstr "" + +#: builtin/log.c:1122 +msgid "don't print the patch filenames" +msgstr "" + +#: builtin/log.c:1163 #, c-format msgid "bogus committer info %s" msgstr "" -#: builtin/log.c:1198 +#: builtin/log.c:1208 msgid "-n and -k are mutually exclusive." msgstr "" -#: builtin/log.c:1200 +#: builtin/log.c:1210 msgid "--subject-prefix and -k are mutually exclusive." msgstr "" -#: builtin/log.c:1208 +#: builtin/log.c:1218 msgid "--name-only does not make sense" msgstr "" -#: builtin/log.c:1210 +#: builtin/log.c:1220 msgid "--name-status does not make sense" msgstr "" -#: builtin/log.c:1212 +#: builtin/log.c:1222 msgid "--check does not make sense" msgstr "" -#: builtin/log.c:1235 +#: builtin/log.c:1245 msgid "standard output, or directory, which one?" msgstr "" -#: builtin/log.c:1237 +#: builtin/log.c:1247 #, c-format msgid "Could not create directory '%s'" msgstr "" -#: builtin/log.c:1390 +#: builtin/log.c:1400 msgid "Failed to create output files" msgstr "" -#: builtin/log.c:1494 +#: builtin/log.c:1449 +msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]" +msgstr "" + +#: builtin/log.c:1504 #, c-format msgid "" "Could not find a tracked remote branch, please specify <upstream> manually.\n" msgstr "" -#: builtin/log.c:1510 builtin/log.c:1512 builtin/log.c:1524 +#: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531 #, c-format msgid "Unknown commit %s" msgstr "" +#: builtin/ls-files.c:408 +msgid "git ls-files [options] [<file>...]" +msgstr "" + +#: builtin/ls-files.c:463 +msgid "identify the file status with tags" +msgstr "" + +#: builtin/ls-files.c:465 +msgid "use lowercase letters for 'assume unchanged' files" +msgstr "" + +#: builtin/ls-files.c:467 +msgid "show cached files in the output (default)" +msgstr "" + +#: builtin/ls-files.c:469 +msgid "show deleted files in the output" +msgstr "" + +#: builtin/ls-files.c:471 +msgid "show modified files in the output" +msgstr "" + +#: builtin/ls-files.c:473 +msgid "show other files in the output" +msgstr "" + +#: builtin/ls-files.c:475 +msgid "show ignored files in the output" +msgstr "" + +#: builtin/ls-files.c:478 +msgid "show staged contents' object name in the output" +msgstr "" + +#: builtin/ls-files.c:480 +msgid "show files on the filesystem that need to be removed" +msgstr "" + +#: builtin/ls-files.c:482 +msgid "show 'other' directories' name only" +msgstr "" + +#: builtin/ls-files.c:485 +msgid "don't show empty directories" +msgstr "" + +#: builtin/ls-files.c:488 +msgid "show unmerged files in the output" +msgstr "" + +#: builtin/ls-files.c:490 +msgid "show resolve-undo information" +msgstr "" + +#: builtin/ls-files.c:492 +msgid "skip files matching pattern" +msgstr "" + +#: builtin/ls-files.c:495 +msgid "exclude patterns are read from <file>" +msgstr "" + +#: builtin/ls-files.c:498 +msgid "read additional per-directory exclude patterns in <file>" +msgstr "" + +#: builtin/ls-files.c:500 +msgid "add the standard git exclusions" +msgstr "" + +#: builtin/ls-files.c:503 +msgid "make the output relative to the project top directory" +msgstr "" + +#: builtin/ls-files.c:506 +msgid "if any <file> is not in the index, treat this as an error" +msgstr "" + +#: builtin/ls-files.c:507 +msgid "tree-ish" +msgstr "" + +#: builtin/ls-files.c:508 +msgid "pretend that paths removed since <tree-ish> are still present" +msgstr "" + +#: builtin/ls-files.c:510 +msgid "show debugging data" +msgstr "" + +#: builtin/ls-tree.c:27 +msgid "git ls-tree [<options>] <tree-ish> [<path>...]" +msgstr "" + +#: builtin/ls-tree.c:125 +msgid "only show trees" +msgstr "" + +#: builtin/ls-tree.c:127 +msgid "recurse into subtrees" +msgstr "" + +#: builtin/ls-tree.c:129 +msgid "show trees when recursing" +msgstr "" + +#: builtin/ls-tree.c:132 +msgid "terminate entries with NUL byte" +msgstr "" + +#: builtin/ls-tree.c:133 +msgid "include object size" +msgstr "" + +#: builtin/ls-tree.c:135 builtin/ls-tree.c:137 +msgid "list only filenames" +msgstr "" + +#: builtin/ls-tree.c:140 +msgid "use full path names" +msgstr "" + +#: builtin/ls-tree.c:142 +msgid "list entire tree; not just current directory (implies --full-name)" +msgstr "" + +#: builtin/merge.c:43 +msgid "git merge [options] [<commit>...]" +msgstr "" + +#: builtin/merge.c:44 +msgid "git merge [options] <msg> HEAD <commit>" +msgstr "" + +#: builtin/merge.c:45 +msgid "git merge --abort" +msgstr "" + #: builtin/merge.c:90 msgid "switch `m' requires a value" msgstr "" @@ -3248,6 +5530,66 @@ msgstr "" msgid "Available custom strategies are:" msgstr "" +#: builtin/merge.c:183 +msgid "do not show a diffstat at the end of the merge" +msgstr "" + +#: builtin/merge.c:186 +msgid "show a diffstat at the end of the merge" +msgstr "" + +#: builtin/merge.c:187 +msgid "(synonym to --stat)" +msgstr "" + +#: builtin/merge.c:189 +msgid "add (at most <n>) entries from shortlog to merge commit message" +msgstr "" + +#: builtin/merge.c:192 +msgid "create a single commit instead of doing a merge" +msgstr "" + +#: builtin/merge.c:194 +msgid "perform a commit if the merge succeeds (default)" +msgstr "" + +#: builtin/merge.c:196 +msgid "edit message before committing" +msgstr "" + +#: builtin/merge.c:198 +msgid "allow fast-forward (default)" +msgstr "" + +#: builtin/merge.c:200 +msgid "abort if fast-forward is not possible" +msgstr "" + +#: builtin/merge.c:202 builtin/notes.c:870 builtin/revert.c:112 +msgid "strategy" +msgstr "" + +#: builtin/merge.c:203 +msgid "merge strategy to use" +msgstr "" + +#: builtin/merge.c:204 +msgid "option=value" +msgstr "" + +#: builtin/merge.c:205 +msgid "option for selected merge strategy" +msgstr "" + +#: builtin/merge.c:207 +msgid "merge commit message (for a non-fast-forward merge)" +msgstr "" + +#: builtin/merge.c:211 +msgid "abort the current in-progress merge" +msgstr "" + #: builtin/merge.c:240 msgid "could not run stash." msgstr "" @@ -3287,53 +5629,45 @@ msgstr "" msgid "No merge message -- not updating HEAD\n" msgstr "" -#: builtin/merge.c:437 +#: builtin/merge.c:436 #, c-format msgid "'%s' does not point to a commit" msgstr "" -#: builtin/merge.c:536 +#: builtin/merge.c:535 #, c-format msgid "Bad branch.%s.mergeoptions string: %s" msgstr "" -#: builtin/merge.c:629 +#: builtin/merge.c:628 msgid "git write-tree failed to write a tree" msgstr "" -#: builtin/merge.c:679 -msgid "failed to read the cache" -msgstr "" - -#: builtin/merge.c:697 -msgid "Unable to write index." -msgstr "" - -#: builtin/merge.c:710 +#: builtin/merge.c:656 msgid "Not handling anything other than two heads merge." msgstr "" -#: builtin/merge.c:724 +#: builtin/merge.c:670 #, c-format msgid "Unknown option for merge-recursive: -X%s" msgstr "" -#: builtin/merge.c:738 +#: builtin/merge.c:684 #, c-format msgid "unable to write %s" msgstr "" -#: builtin/merge.c:877 +#: builtin/merge.c:773 #, c-format msgid "Could not read from '%s'" msgstr "" -#: builtin/merge.c:886 +#: builtin/merge.c:782 #, c-format msgid "Not committing merge; use 'git commit' to complete the merge.\n" msgstr "" -#: builtin/merge.c:892 +#: builtin/merge.c:788 msgid "" "Please enter a commit message to explain why this merge is necessary,\n" "especially if it merges an updated upstream into a topic branch.\n" @@ -3342,144 +5676,242 @@ msgid "" "the commit.\n" msgstr "" -#: builtin/merge.c:916 +#: builtin/merge.c:812 msgid "Empty commit message." msgstr "" -#: builtin/merge.c:928 +#: builtin/merge.c:824 #, c-format msgid "Wonderful.\n" msgstr "" -#: builtin/merge.c:993 +#: builtin/merge.c:889 #, c-format msgid "Automatic merge failed; fix conflicts and then commit the result.\n" msgstr "" -#: builtin/merge.c:1009 +#: builtin/merge.c:905 #, c-format msgid "'%s' is not a commit" msgstr "" -#: builtin/merge.c:1050 +#: builtin/merge.c:946 msgid "No current branch." msgstr "" -#: builtin/merge.c:1052 +#: builtin/merge.c:948 msgid "No remote for the current branch." msgstr "" -#: builtin/merge.c:1054 +#: builtin/merge.c:950 msgid "No default upstream defined for the current branch." msgstr "" -#: builtin/merge.c:1059 +#: builtin/merge.c:955 #, c-format msgid "No remote tracking branch for %s from %s" msgstr "" -#: builtin/merge.c:1146 builtin/merge.c:1303 +#: builtin/merge.c:1042 builtin/merge.c:1199 #, c-format msgid "%s - not something we can merge" msgstr "" -#: builtin/merge.c:1214 +#: builtin/merge.c:1110 msgid "There is no merge to abort (MERGE_HEAD missing)." msgstr "" -#: builtin/merge.c:1230 git-pull.sh:31 +#: builtin/merge.c:1126 git-pull.sh:31 msgid "" "You have not concluded your merge (MERGE_HEAD exists).\n" "Please, commit your changes before you can merge." msgstr "" -#: builtin/merge.c:1233 git-pull.sh:34 +#: builtin/merge.c:1129 git-pull.sh:34 msgid "You have not concluded your merge (MERGE_HEAD exists)." msgstr "" -#: builtin/merge.c:1237 +#: builtin/merge.c:1133 msgid "" "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" "Please, commit your changes before you can merge." msgstr "" -#: builtin/merge.c:1240 +#: builtin/merge.c:1136 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)." msgstr "" -#: builtin/merge.c:1249 +#: builtin/merge.c:1145 msgid "You cannot combine --squash with --no-ff." msgstr "" -#: builtin/merge.c:1254 +#: builtin/merge.c:1150 msgid "You cannot combine --no-ff with --ff-only." msgstr "" -#: builtin/merge.c:1261 +#: builtin/merge.c:1157 msgid "No commit specified and merge.defaultToUpstream not set." msgstr "" -#: builtin/merge.c:1293 +#: builtin/merge.c:1189 msgid "Can merge only exactly one commit into empty head" msgstr "" -#: builtin/merge.c:1296 +#: builtin/merge.c:1192 msgid "Squash commit into empty head not supported yet" msgstr "" -#: builtin/merge.c:1298 +#: builtin/merge.c:1194 msgid "Non-fast-forward commit does not make sense into an empty head" msgstr "" -#: builtin/merge.c:1413 +#: builtin/merge.c:1309 #, c-format msgid "Updating %s..%s\n" msgstr "" -#: builtin/merge.c:1451 +#: builtin/merge.c:1348 #, c-format msgid "Trying really trivial in-index merge...\n" msgstr "" -#: builtin/merge.c:1458 +#: builtin/merge.c:1355 #, c-format msgid "Nope.\n" msgstr "" -#: builtin/merge.c:1490 +#: builtin/merge.c:1387 msgid "Not possible to fast-forward, aborting." msgstr "" -#: builtin/merge.c:1513 builtin/merge.c:1592 +#: builtin/merge.c:1410 builtin/merge.c:1489 #, c-format msgid "Rewinding the tree to pristine...\n" msgstr "" -#: builtin/merge.c:1517 +#: builtin/merge.c:1414 #, c-format msgid "Trying merge strategy %s...\n" msgstr "" -#: builtin/merge.c:1583 +#: builtin/merge.c:1480 #, c-format msgid "No merge strategy handled the merge.\n" msgstr "" -#: builtin/merge.c:1585 +#: builtin/merge.c:1482 #, c-format msgid "Merge with strategy %s failed.\n" msgstr "" -#: builtin/merge.c:1594 +#: builtin/merge.c:1491 #, c-format msgid "Using the %s to prepare resolving by hand.\n" msgstr "" -#: builtin/merge.c:1606 +#: builtin/merge.c:1503 #, c-format msgid "Automatic merge went well; stopped before committing as requested\n" msgstr "" +#: builtin/merge-base.c:26 +msgid "git merge-base [-a|--all] <commit> <commit>..." +msgstr "" + +#: builtin/merge-base.c:27 +msgid "git merge-base [-a|--all] --octopus <commit>..." +msgstr "" + +#: builtin/merge-base.c:28 +msgid "git merge-base --independent <commit>..." +msgstr "" + +#: builtin/merge-base.c:29 +msgid "git merge-base --is-ancestor <commit> <commit>" +msgstr "" + +#: builtin/merge-base.c:98 +msgid "output all common ancestors" +msgstr "" + +#: builtin/merge-base.c:99 +msgid "find ancestors for a single n-way merge" +msgstr "" + +#: builtin/merge-base.c:100 +msgid "list revs not reachable from others" +msgstr "" + +#: builtin/merge-base.c:102 +msgid "is the first one ancestor of the other?" +msgstr "" + +#: builtin/merge-file.c:8 +msgid "" +"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file " +"file2" +msgstr "" + +#: builtin/merge-file.c:33 +msgid "send results to standard output" +msgstr "" + +#: builtin/merge-file.c:34 +msgid "use a diff3 based merge" +msgstr "" + +#: builtin/merge-file.c:35 +msgid "for conflicts, use our version" +msgstr "" + +#: builtin/merge-file.c:37 +msgid "for conflicts, use their version" +msgstr "" + +#: builtin/merge-file.c:39 +msgid "for conflicts, use a union version" +msgstr "" + +#: builtin/merge-file.c:42 +msgid "for conflicts, use this marker size" +msgstr "" + +#: builtin/merge-file.c:43 +msgid "do not warn about conflicts" +msgstr "" + +#: builtin/merge-file.c:45 +msgid "set labels for file1/orig_file/file2" +msgstr "" + +#: builtin/mktree.c:67 +msgid "git mktree [-z] [--missing] [--batch]" +msgstr "" + +#: builtin/mktree.c:153 +msgid "input is NUL terminated" +msgstr "" + +#: builtin/mktree.c:154 builtin/write-tree.c:24 +msgid "allow missing objects" +msgstr "" + +#: builtin/mktree.c:155 +msgid "allow creation of more than one tree" +msgstr "" + +#: builtin/mv.c:14 +msgid "git mv [options] <source>... <destination>" +msgstr "" + +#: builtin/mv.c:64 +msgid "force move/rename even if target exists" +msgstr "" + +#: builtin/mv.c:65 +msgid "skip move/rename errors" +msgstr "" + #: builtin/mv.c:108 #, c-format msgid "Checking rename of '%s' to '%s'\n" @@ -3542,178 +5974,567 @@ msgstr "" msgid "renaming '%s' failed" msgstr "" -#: builtin/notes.c:139 +#: builtin/name-rev.c:175 +msgid "git name-rev [options] <commit>..." +msgstr "" + +#: builtin/name-rev.c:176 +msgid "git name-rev [options] --all" +msgstr "" + +#: builtin/name-rev.c:177 +msgid "git name-rev [options] --stdin" +msgstr "" + +#: builtin/name-rev.c:229 +msgid "print only names (no SHA-1)" +msgstr "" + +#: builtin/name-rev.c:230 +msgid "only use tags to name the commits" +msgstr "" + +#: builtin/name-rev.c:232 +msgid "only use refs matching <pattern>" +msgstr "" + +#: builtin/name-rev.c:234 +msgid "list all commits reachable from all refs" +msgstr "" + +#: builtin/name-rev.c:235 +msgid "read from stdin" +msgstr "" + +#: builtin/name-rev.c:236 +msgid "allow to print `undefined` names" +msgstr "" + +#: builtin/notes.c:26 +msgid "git notes [--ref <notes_ref>] [list [<object>]]" +msgstr "" + +#: builtin/notes.c:27 +msgid "" +"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) " +"<object>] [<object>]" +msgstr "" + +#: builtin/notes.c:28 +msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>" +msgstr "" + +#: builtin/notes.c:29 +msgid "" +"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) " +"<object>] [<object>]" +msgstr "" + +#: builtin/notes.c:30 +msgid "git notes [--ref <notes_ref>] edit [<object>]" +msgstr "" + +#: builtin/notes.c:31 +msgid "git notes [--ref <notes_ref>] show [<object>]" +msgstr "" + +#: builtin/notes.c:32 +msgid "" +"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>" +msgstr "" + +#: builtin/notes.c:33 +msgid "git notes merge --commit [-v | -q]" +msgstr "" + +#: builtin/notes.c:34 +msgid "git notes merge --abort [-v | -q]" +msgstr "" + +#: builtin/notes.c:35 +msgid "git notes [--ref <notes_ref>] remove [<object>...]" +msgstr "" + +#: builtin/notes.c:36 +msgid "git notes [--ref <notes_ref>] prune [-n | -v]" +msgstr "" + +#: builtin/notes.c:37 +msgid "git notes [--ref <notes_ref>] get-ref" +msgstr "" + +#: builtin/notes.c:42 +msgid "git notes [list [<object>]]" +msgstr "" + +#: builtin/notes.c:47 +msgid "git notes add [<options>] [<object>]" +msgstr "" + +#: builtin/notes.c:52 +msgid "git notes copy [<options>] <from-object> <to-object>" +msgstr "" + +#: builtin/notes.c:53 +msgid "git notes copy --stdin [<from-object> <to-object>]..." +msgstr "" + +#: builtin/notes.c:58 +msgid "git notes append [<options>] [<object>]" +msgstr "" + +#: builtin/notes.c:63 +msgid "git notes edit [<object>]" +msgstr "" + +#: builtin/notes.c:68 +msgid "git notes show [<object>]" +msgstr "" + +#: builtin/notes.c:73 +msgid "git notes merge [<options>] <notes_ref>" +msgstr "" + +#: builtin/notes.c:74 +msgid "git notes merge --commit [<options>]" +msgstr "" + +#: builtin/notes.c:75 +msgid "git notes merge --abort [<options>]" +msgstr "" + +#: builtin/notes.c:80 +msgid "git notes remove [<object>]" +msgstr "" + +#: builtin/notes.c:85 +msgid "git notes prune [<options>]" +msgstr "" + +#: builtin/notes.c:90 +msgid "git notes get-ref" +msgstr "" + +#: builtin/notes.c:142 #, c-format msgid "unable to start 'show' for object '%s'" msgstr "" -#: builtin/notes.c:145 +#: builtin/notes.c:148 msgid "can't fdopen 'show' output fd" msgstr "" -#: builtin/notes.c:155 +#: builtin/notes.c:158 #, c-format msgid "failed to close pipe to 'show' for object '%s'" msgstr "" -#: builtin/notes.c:158 +#: builtin/notes.c:161 #, c-format msgid "failed to finish 'show' for object '%s'" msgstr "" -#: builtin/notes.c:175 builtin/tag.c:347 +#: builtin/notes.c:178 builtin/tag.c:347 #, c-format msgid "could not create file '%s'" msgstr "" -#: builtin/notes.c:189 +#: builtin/notes.c:192 msgid "Please supply the note contents using either -m or -F option" msgstr "" -#: builtin/notes.c:210 builtin/notes.c:973 +#: builtin/notes.c:213 builtin/notes.c:976 #, c-format msgid "Removing note for object %s\n" msgstr "" -#: builtin/notes.c:215 +#: builtin/notes.c:218 msgid "unable to write note object" msgstr "" -#: builtin/notes.c:217 +#: builtin/notes.c:220 #, c-format msgid "The note contents has been left in %s" msgstr "" -#: builtin/notes.c:251 builtin/tag.c:542 +#: builtin/notes.c:254 builtin/tag.c:542 #, c-format msgid "cannot read '%s'" msgstr "" -#: builtin/notes.c:253 builtin/tag.c:545 +#: builtin/notes.c:256 builtin/tag.c:545 #, c-format msgid "could not open or read '%s'" msgstr "" -#: builtin/notes.c:272 builtin/notes.c:445 builtin/notes.c:447 -#: builtin/notes.c:507 builtin/notes.c:561 builtin/notes.c:644 -#: builtin/notes.c:649 builtin/notes.c:724 builtin/notes.c:766 -#: builtin/notes.c:968 builtin/reset.c:293 builtin/tag.c:558 +#: builtin/notes.c:275 builtin/notes.c:448 builtin/notes.c:450 +#: builtin/notes.c:510 builtin/notes.c:564 builtin/notes.c:647 +#: builtin/notes.c:652 builtin/notes.c:727 builtin/notes.c:769 +#: builtin/notes.c:971 builtin/reset.c:293 builtin/tag.c:558 #, c-format msgid "Failed to resolve '%s' as a valid ref." msgstr "" -#: builtin/notes.c:275 +#: builtin/notes.c:278 #, c-format msgid "Failed to read object '%s'." msgstr "" -#: builtin/notes.c:299 +#: builtin/notes.c:302 msgid "Cannot commit uninitialized/unreferenced notes tree" msgstr "" -#: builtin/notes.c:340 +#: builtin/notes.c:343 #, c-format msgid "Bad notes.rewriteMode value: '%s'" msgstr "" -#: builtin/notes.c:350 +#: builtin/notes.c:353 #, c-format msgid "Refusing to rewrite notes in %s (outside of refs/notes/)" msgstr "" #. TRANSLATORS: The first %s is the name of the #. environment variable, the second %s is its value -#: builtin/notes.c:377 +#: builtin/notes.c:380 #, c-format msgid "Bad %s value: '%s'" msgstr "" -#: builtin/notes.c:441 +#: builtin/notes.c:444 #, c-format msgid "Malformed input line: '%s'." msgstr "" -#: builtin/notes.c:456 +#: builtin/notes.c:459 #, c-format msgid "Failed to copy notes from '%s' to '%s'" msgstr "" -#: builtin/notes.c:500 builtin/notes.c:554 builtin/notes.c:627 -#: builtin/notes.c:639 builtin/notes.c:712 builtin/notes.c:759 -#: builtin/notes.c:1033 +#: builtin/notes.c:503 builtin/notes.c:557 builtin/notes.c:630 +#: builtin/notes.c:642 builtin/notes.c:715 builtin/notes.c:762 +#: builtin/notes.c:1036 msgid "too many parameters" msgstr "" -#: builtin/notes.c:513 builtin/notes.c:772 +#: builtin/notes.c:516 builtin/notes.c:775 #, c-format msgid "No note found for object %s." msgstr "" -#: builtin/notes.c:580 +#: builtin/notes.c:538 builtin/notes.c:695 +msgid "note contents as a string" +msgstr "" + +#: builtin/notes.c:541 builtin/notes.c:698 +msgid "note contents in a file" +msgstr "" + +#: builtin/notes.c:543 builtin/notes.c:546 builtin/notes.c:700 +#: builtin/notes.c:703 builtin/tag.c:476 +msgid "object" +msgstr "" + +#: builtin/notes.c:544 builtin/notes.c:701 +msgid "reuse and edit specified note object" +msgstr "" + +#: builtin/notes.c:547 builtin/notes.c:704 +msgid "reuse specified note object" +msgstr "" + +#: builtin/notes.c:549 builtin/notes.c:617 +msgid "replace existing notes" +msgstr "" + +#: builtin/notes.c:583 #, c-format msgid "" "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite " "existing notes" msgstr "" -#: builtin/notes.c:585 builtin/notes.c:662 +#: builtin/notes.c:588 builtin/notes.c:665 #, c-format msgid "Overwriting existing notes for object %s\n" msgstr "" -#: builtin/notes.c:635 +#: builtin/notes.c:618 +msgid "read objects from stdin" +msgstr "" + +#: builtin/notes.c:620 +msgid "load rewriting config for <command> (implies --stdin)" +msgstr "" + +#: builtin/notes.c:638 msgid "too few parameters" msgstr "" -#: builtin/notes.c:656 +#: builtin/notes.c:659 #, c-format msgid "" "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite " "existing notes" msgstr "" -#: builtin/notes.c:668 +#: builtin/notes.c:671 #, c-format msgid "Missing notes on source object %s. Cannot copy." msgstr "" -#: builtin/notes.c:717 +#: builtin/notes.c:720 #, c-format msgid "" "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n" "Please use 'git notes add -f -m/-F/-c/-C' instead.\n" msgstr "" -#: builtin/notes.c:971 +#: builtin/notes.c:867 +msgid "General options" +msgstr "" + +#: builtin/notes.c:869 +msgid "Merge options" +msgstr "" + +#: builtin/notes.c:871 +msgid "" +"resolve notes conflicts using the given strategy (manual/ours/theirs/union/" +"cat_sort_uniq)" +msgstr "" + +#: builtin/notes.c:873 +msgid "Committing unmerged notes" +msgstr "" + +#: builtin/notes.c:875 +msgid "finalize notes merge by committing unmerged notes" +msgstr "" + +#: builtin/notes.c:877 +msgid "Aborting notes merge resolution" +msgstr "" + +#: builtin/notes.c:879 +msgid "abort notes merge" +msgstr "" + +#: builtin/notes.c:974 #, c-format msgid "Object %s has no note\n" msgstr "" -#: builtin/notes.c:1103 builtin/remote.c:1598 +#: builtin/notes.c:986 +msgid "attempt to remove non-existent note is not an error" +msgstr "" + +#: builtin/notes.c:989 +msgid "read object names from the standard input" +msgstr "" + +#: builtin/notes.c:1070 +msgid "notes_ref" +msgstr "" + +#: builtin/notes.c:1071 +msgid "use notes from <notes_ref>" +msgstr "" + +#: builtin/notes.c:1106 builtin/remote.c:1598 #, c-format msgid "Unknown subcommand: %s" msgstr "" -#: builtin/pack-objects.c:2337 +#: builtin/pack-objects.c:23 +msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]" +msgstr "" + +#: builtin/pack-objects.c:24 +msgid "git pack-objects [options...] base-name [< ref-list | < object-list]" +msgstr "" + +#: builtin/pack-objects.c:183 builtin/pack-objects.c:186 +#, c-format +msgid "deflate error (%d)" +msgstr "" + +#: builtin/pack-objects.c:2397 #, c-format msgid "unsupported index version %s" msgstr "" -#: builtin/pack-objects.c:2341 +#: builtin/pack-objects.c:2401 #, c-format msgid "bad index version '%s'" msgstr "" -#: builtin/pack-objects.c:2364 +#: builtin/pack-objects.c:2424 #, c-format msgid "option %s does not accept negative form" msgstr "" -#: builtin/pack-objects.c:2368 +#: builtin/pack-objects.c:2428 #, c-format msgid "unable to parse value '%s' for option %s" msgstr "" +#: builtin/pack-objects.c:2447 +msgid "do not show progress meter" +msgstr "" + +#: builtin/pack-objects.c:2449 +msgid "show progress meter" +msgstr "" + +#: builtin/pack-objects.c:2451 +msgid "show progress meter during object writing phase" +msgstr "" + +#: builtin/pack-objects.c:2454 +msgid "similar to --all-progress when progress meter is shown" +msgstr "" + +#: builtin/pack-objects.c:2455 +msgid "version[,offset]" +msgstr "" + +#: builtin/pack-objects.c:2456 +msgid "write the pack index file in the specified idx format version" +msgstr "" + +#: builtin/pack-objects.c:2459 +msgid "maximum size of each output pack file" +msgstr "" + +#: builtin/pack-objects.c:2461 +msgid "ignore borrowed objects from alternate object store" +msgstr "" + +#: builtin/pack-objects.c:2463 +msgid "ignore packed objects" +msgstr "" + +#: builtin/pack-objects.c:2465 +msgid "limit pack window by objects" +msgstr "" + +#: builtin/pack-objects.c:2467 +msgid "limit pack window by memory in addition to object limit" +msgstr "" + +#: builtin/pack-objects.c:2469 +msgid "maximum length of delta chain allowed in the resulting pack" +msgstr "" + +#: builtin/pack-objects.c:2471 +msgid "reuse existing deltas" +msgstr "" + +#: builtin/pack-objects.c:2473 +msgid "reuse existing objects" +msgstr "" + +#: builtin/pack-objects.c:2475 +msgid "use OFS_DELTA objects" +msgstr "" + +#: builtin/pack-objects.c:2477 +msgid "use threads when searching for best delta matches" +msgstr "" + +#: builtin/pack-objects.c:2479 +msgid "do not create an empty pack output" +msgstr "" + +#: builtin/pack-objects.c:2481 +msgid "read revision arguments from standard input" +msgstr "" + +#: builtin/pack-objects.c:2483 +msgid "limit the objects to those that are not yet packed" +msgstr "" + +#: builtin/pack-objects.c:2486 +msgid "include objects reachable from any reference" +msgstr "" + +#: builtin/pack-objects.c:2489 +msgid "include objects referred by reflog entries" +msgstr "" + +#: builtin/pack-objects.c:2492 +msgid "output pack to stdout" +msgstr "" + +#: builtin/pack-objects.c:2494 +msgid "include tag objects that refer to objects to be packed" +msgstr "" + +#: builtin/pack-objects.c:2496 +msgid "keep unreachable objects" +msgstr "" + +#: builtin/pack-objects.c:2497 parse-options.h:141 +msgid "time" +msgstr "" + +#: builtin/pack-objects.c:2498 +msgid "unpack unreachable objects newer than <time>" +msgstr "" + +#: builtin/pack-objects.c:2501 +msgid "create thin packs" +msgstr "" + +#: builtin/pack-objects.c:2503 +msgid "ignore packs that have companion .keep file" +msgstr "" + +#: builtin/pack-objects.c:2505 +msgid "pack compression level" +msgstr "" + +#: builtin/pack-objects.c:2507 +msgid "do not hide commits by grafts" +msgstr "" + +#: builtin/pack-refs.c:6 +msgid "git pack-refs [options]" +msgstr "" + +#: builtin/pack-refs.c:14 +msgid "pack everything" +msgstr "" + +#: builtin/pack-refs.c:15 +msgid "prune loose refs (default)" +msgstr "" + +#: builtin/prune-packed.c:7 +msgid "git prune-packed [-n|--dry-run] [-q|--quiet]" +msgstr "" + +#: builtin/prune.c:12 +msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]" +msgstr "" + +#: builtin/prune.c:132 +msgid "do not remove, show only" +msgstr "" + +#: builtin/prune.c:133 +msgid "report pruned objects" +msgstr "" + +#: builtin/prune.c:136 +msgid "expire objects older than <time>" +msgstr "" + +#: builtin/push.c:14 +msgid "git push [<options>] [<repository> [<refspec>...]]" +msgstr "" + #: builtin/push.c:45 msgid "tag shorthand without <tag>" msgstr "" @@ -3775,12 +6596,30 @@ msgid "" "to update which remote branch." msgstr "" -#: builtin/push.c:174 +#: builtin/push.c:151 +msgid "" +"push.default is unset; its implicit value is changing in\n" +"Git 2.0 from 'matching' to 'simple'. To squelch this message\n" +"and maintain the current behavior after the default changes, use:\n" +"\n" +" git config --global push.default matching\n" +"\n" +"To squelch this message and adopt the new behavior now, use:\n" +"\n" +" git config --global push.default simple\n" +"\n" +"See 'git help config' and search for 'push.default' for further " +"information.\n" +"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n" +"'current' instead of 'simple' if you sometimes use older versions of Git)" +msgstr "" + +#: builtin/push.c:199 msgid "" "You didn't specify any refspecs to push, and push.default is \"nothing\"." msgstr "" -#: builtin/push.c:181 +#: builtin/push.c:206 msgid "" "Updates were rejected because the tip of your current branch is behind\n" "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n" @@ -3788,15 +6627,15 @@ msgid "" "See the 'Note about fast-forwards' in 'git push --help' for details." msgstr "" -#: builtin/push.c:187 +#: builtin/push.c:212 msgid "" "Updates were rejected because a pushed branch tip is behind its remote\n" "counterpart. If you did not intend to push that branch, you may want to\n" -"specify branches to push or set the 'push.default' configuration\n" -"variable to 'current' or 'upstream' to push only the current branch." +"specify branches to push or set the 'push.default' configuration variable\n" +"to 'simple', 'current' or 'upstream' to push only the current branch." msgstr "" -#: builtin/push.c:193 +#: builtin/push.c:218 msgid "" "Updates were rejected because a pushed branch tip is behind its remote\n" "counterpart. Check out this branch and merge the remote changes\n" @@ -3804,22 +6643,22 @@ msgid "" "See the 'Note about fast-forwards' in 'git push --help' for details." msgstr "" -#: builtin/push.c:233 +#: builtin/push.c:258 #, c-format msgid "Pushing to %s\n" msgstr "" -#: builtin/push.c:237 +#: builtin/push.c:262 #, c-format msgid "failed to push some refs to '%s'" msgstr "" -#: builtin/push.c:269 +#: builtin/push.c:294 #, c-format msgid "bad repository '%s'" msgstr "" -#: builtin/push.c:270 +#: builtin/push.c:295 msgid "" "No configured push destination.\n" "Either specify the URL from the command-line or configure a remote " @@ -3832,34 +6671,228 @@ msgid "" " git push <name>\n" msgstr "" -#: builtin/push.c:285 +#: builtin/push.c:310 msgid "--all and --tags are incompatible" msgstr "" -#: builtin/push.c:286 +#: builtin/push.c:311 msgid "--all can't be combined with refspecs" msgstr "" -#: builtin/push.c:291 +#: builtin/push.c:316 msgid "--mirror and --tags are incompatible" msgstr "" -#: builtin/push.c:292 +#: builtin/push.c:317 msgid "--mirror can't be combined with refspecs" msgstr "" -#: builtin/push.c:297 +#: builtin/push.c:322 msgid "--all and --mirror are incompatible" msgstr "" -#: builtin/push.c:385 -msgid "--delete is incompatible with --all, --mirror and --tags" +#: builtin/push.c:382 +msgid "repository" +msgstr "" + +#: builtin/push.c:383 +msgid "push all refs" +msgstr "" + +#: builtin/push.c:384 +msgid "mirror all refs" +msgstr "" + +#: builtin/push.c:386 +msgid "delete refs" msgstr "" #: builtin/push.c:387 +msgid "push tags (can't be used with --all or --mirror)" +msgstr "" + +#: builtin/push.c:390 +msgid "force updates" +msgstr "" + +#: builtin/push.c:391 +msgid "check" +msgstr "" + +#: builtin/push.c:392 +msgid "control recursive pushing of submodules" +msgstr "" + +#: builtin/push.c:394 +msgid "use thin pack" +msgstr "" + +#: builtin/push.c:395 builtin/push.c:396 +msgid "receive pack program" +msgstr "" + +#: builtin/push.c:397 +msgid "set upstream for git pull/status" +msgstr "" + +#: builtin/push.c:400 +msgid "prune locally removed refs" +msgstr "" + +#: builtin/push.c:410 +msgid "--delete is incompatible with --all, --mirror and --tags" +msgstr "" + +#: builtin/push.c:412 msgid "--delete doesn't make sense without any refs" msgstr "" +#: builtin/read-tree.c:36 +msgid "" +"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] " +"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--" +"index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])" +msgstr "" + +#: builtin/read-tree.c:108 +msgid "write resulting index to <file>" +msgstr "" + +#: builtin/read-tree.c:111 +msgid "only empty the index" +msgstr "" + +#: builtin/read-tree.c:113 +msgid "Merging" +msgstr "" + +#: builtin/read-tree.c:115 +msgid "perform a merge in addition to a read" +msgstr "" + +#: builtin/read-tree.c:117 +msgid "3-way merge if no file level merging required" +msgstr "" + +#: builtin/read-tree.c:119 +msgid "3-way merge in presence of adds and removes" +msgstr "" + +#: builtin/read-tree.c:121 +msgid "same as -m, but discard unmerged entries" +msgstr "" + +#: builtin/read-tree.c:122 +msgid "<subdirectory>/" +msgstr "" + +#: builtin/read-tree.c:123 +msgid "read the tree into the index under <subdirectory>/" +msgstr "" + +#: builtin/read-tree.c:126 +msgid "update working tree with merge result" +msgstr "" + +#: builtin/read-tree.c:128 +msgid "gitignore" +msgstr "" + +#: builtin/read-tree.c:129 +msgid "allow explicitly ignored files to be overwritten" +msgstr "" + +#: builtin/read-tree.c:132 +msgid "don't check the working tree after merging" +msgstr "" + +#: builtin/read-tree.c:133 +msgid "don't update the index or the work tree" +msgstr "" + +#: builtin/read-tree.c:135 +msgid "skip applying sparse checkout filter" +msgstr "" + +#: builtin/read-tree.c:137 +msgid "debug unpack-trees" +msgstr "" + +#: builtin/remote.c:11 +msgid "git remote [-v | --verbose]" +msgstr "" + +#: builtin/remote.c:12 +msgid "" +"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--" +"mirror=<fetch|push>] <name> <url>" +msgstr "" + +#: builtin/remote.c:13 builtin/remote.c:32 +msgid "git remote rename <old> <new>" +msgstr "" + +#: builtin/remote.c:14 builtin/remote.c:37 +msgid "git remote remove <name>" +msgstr "" + +#: builtin/remote.c:15 builtin/remote.c:42 +msgid "git remote set-head <name> (-a | -d | <branch>)" +msgstr "" + +#: builtin/remote.c:16 +msgid "git remote [-v | --verbose] show [-n] <name>" +msgstr "" + +#: builtin/remote.c:17 +msgid "git remote prune [-n | --dry-run] <name>" +msgstr "" + +#: builtin/remote.c:18 +msgid "" +"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]" +msgstr "" + +#: builtin/remote.c:19 +msgid "git remote set-branches [--add] <name> <branch>..." +msgstr "" + +#: builtin/remote.c:20 builtin/remote.c:68 +msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]" +msgstr "" + +#: builtin/remote.c:21 builtin/remote.c:69 +msgid "git remote set-url --add <name> <newurl>" +msgstr "" + +#: builtin/remote.c:22 builtin/remote.c:70 +msgid "git remote set-url --delete <name> <url>" +msgstr "" + +#: builtin/remote.c:27 +msgid "git remote add [<options>] <name> <url>" +msgstr "" + +#: builtin/remote.c:47 +msgid "git remote set-branches <name> <branch>..." +msgstr "" + +#: builtin/remote.c:48 +msgid "git remote set-branches --add <name> <branch>..." +msgstr "" + +#: builtin/remote.c:53 +msgid "git remote show [<options>] <name>" +msgstr "" + +#: builtin/remote.c:58 +msgid "git remote prune [<options>] <name>" +msgstr "" + +#: builtin/remote.c:63 +msgid "git remote update [<options>] [<group> | <remote>]..." +msgstr "" + #: builtin/remote.c:98 #, c-format msgid "Updating %s" @@ -3876,6 +6909,34 @@ msgstr "" msgid "unknown mirror argument: %s" msgstr "" +#: builtin/remote.c:163 +msgid "fetch the remote branches" +msgstr "" + +#: builtin/remote.c:165 +msgid "import all tags and associated objects when fetching" +msgstr "" + +#: builtin/remote.c:168 +msgid "or do not fetch any tag at all (--no-tags)" +msgstr "" + +#: builtin/remote.c:170 +msgid "branch(es) to track" +msgstr "" + +#: builtin/remote.c:171 +msgid "master branch" +msgstr "" + +#: builtin/remote.c:172 +msgid "push|fetch" +msgstr "" + +#: builtin/remote.c:173 +msgid "set up remote as a mirror to push to or fetch from" +msgstr "" + #: builtin/remote.c:185 msgid "specifying a master branch makes no sense with --mirror" msgstr "" @@ -4065,6 +7126,10 @@ msgstr "" msgid " %-*s pushes to %s" msgstr "" +#: builtin/remote.c:1091 +msgid "do not query remotes" +msgstr "" + #: builtin/remote.c:1118 #, c-format msgid "* remote %s" @@ -4123,6 +7188,14 @@ msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] "" msgstr[1] "" +#: builtin/remote.c:1199 +msgid "set refs/remotes/<name>/HEAD according to remote" +msgstr "" + +#: builtin/remote.c:1201 +msgid "delete refs/remotes/<name>/HEAD" +msgstr "" + #: builtin/remote.c:1216 msgid "Cannot determine remote HEAD" msgstr "" @@ -4176,15 +7249,35 @@ msgstr "" msgid " * [pruned] %s" msgstr "" +#: builtin/remote.c:1321 +msgid "prune remotes after fetching" +msgstr "" + #: builtin/remote.c:1387 builtin/remote.c:1461 #, c-format msgid "No such remote '%s'" msgstr "" +#: builtin/remote.c:1407 +msgid "add branch" +msgstr "" + #: builtin/remote.c:1414 msgid "no remote specified" msgstr "" +#: builtin/remote.c:1436 +msgid "manipulate push URLs" +msgstr "" + +#: builtin/remote.c:1438 +msgid "add URL" +msgstr "" + +#: builtin/remote.c:1440 +msgid "delete URLs" +msgstr "" + #: builtin/remote.c:1447 msgid "--add --delete doesn't make sense" msgstr "" @@ -4203,6 +7296,55 @@ msgstr "" msgid "Will not delete all non-push URLs" msgstr "" +#: builtin/remote.c:1569 +msgid "be verbose; must be placed before a subcommand" +msgstr "" + +#: builtin/replace.c:17 +msgid "git replace [-f] <object> <replacement>" +msgstr "" + +#: builtin/replace.c:18 +msgid "git replace -d <object>..." +msgstr "" + +#: builtin/replace.c:19 +msgid "git replace -l [<pattern>]" +msgstr "" + +#: builtin/replace.c:121 +msgid "list replace refs" +msgstr "" + +#: builtin/replace.c:122 +msgid "delete replace refs" +msgstr "" + +#: builtin/replace.c:123 +msgid "replace the ref if it exists" +msgstr "" + +#: builtin/rerere.c:11 +msgid "git rerere [clear | forget path... | status | remaining | diff | gc]" +msgstr "" + +#: builtin/rerere.c:56 +msgid "register clean resolutions in index" +msgstr "" + +#: builtin/reset.c:25 +msgid "" +"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]" +msgstr "" + +#: builtin/reset.c:26 +msgid "git reset [-q] <commit> [--] <paths>..." +msgstr "" + +#: builtin/reset.c:27 +msgid "git reset --patch [<commit>] [--] [<paths>...]" +msgstr "" + #: builtin/reset.c:33 msgid "mixed" msgstr "" @@ -4258,87 +7400,420 @@ msgstr "" msgid "Cannot do a %s reset in the middle of a merge." msgstr "" -#: builtin/reset.c:297 +#: builtin/reset.c:238 +msgid "be quiet, only report errors" +msgstr "" + +#: builtin/reset.c:240 +msgid "reset HEAD and index" +msgstr "" + +#: builtin/reset.c:241 +msgid "reset only HEAD" +msgstr "" + +#: builtin/reset.c:243 builtin/reset.c:245 +msgid "reset HEAD, index and working tree" +msgstr "" + +#: builtin/reset.c:247 +msgid "reset HEAD but keep local changes" +msgstr "" + +#: builtin/reset.c:303 #, c-format msgid "Could not parse object '%s'." msgstr "" -#: builtin/reset.c:302 +#: builtin/reset.c:308 msgid "--patch is incompatible with --{hard,mixed,soft}" msgstr "" -#: builtin/reset.c:311 +#: builtin/reset.c:317 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." msgstr "" -#: builtin/reset.c:313 +#: builtin/reset.c:319 #, c-format msgid "Cannot do %s reset with paths." msgstr "" -#: builtin/reset.c:325 +#: builtin/reset.c:331 #, c-format msgid "%s reset is not allowed in a bare repository" msgstr "" -#: builtin/reset.c:341 +#: builtin/reset.c:347 #, c-format msgid "Could not reset index file to revision '%s'." msgstr "" +#: builtin/rev-parse.c:339 +msgid "git rev-parse --parseopt [options] -- [<args>...]" +msgstr "" + +#: builtin/rev-parse.c:344 +msgid "keep the `--` passed as an arg" +msgstr "" + +#: builtin/rev-parse.c:346 +msgid "stop parsing after the first non-option argument" +msgstr "" + +#: builtin/rev-parse.c:464 +msgid "" +"git rev-parse --parseopt [options] -- [<args>...]\n" +" or: git rev-parse --sq-quote [<arg>...]\n" +" or: git rev-parse [options] [<arg>...]\n" +"\n" +"Run \"git rev-parse --parseopt -h\" for more information on the first usage." +msgstr "" + +#: builtin/revert.c:22 +msgid "git revert [options] <commit-ish>" +msgstr "" + +#: builtin/revert.c:23 +msgid "git revert <subcommand>" +msgstr "" + +#: builtin/revert.c:28 +msgid "git cherry-pick [options] <commit-ish>" +msgstr "" + +#: builtin/revert.c:29 +msgid "git cherry-pick <subcommand>" +msgstr "" + #: builtin/revert.c:70 builtin/revert.c:92 #, c-format msgid "%s: %s cannot be used with %s" msgstr "" -#: builtin/revert.c:131 +#: builtin/revert.c:103 +msgid "end revert or cherry-pick sequence" +msgstr "" + +#: builtin/revert.c:104 +msgid "resume revert or cherry-pick sequence" +msgstr "" + +#: builtin/revert.c:105 +msgid "cancel revert or cherry-pick sequence" +msgstr "" + +#: builtin/revert.c:106 +msgid "don't automatically commit" +msgstr "" + +#: builtin/revert.c:107 +msgid "edit the commit message" +msgstr "" + +#: builtin/revert.c:110 +msgid "parent number" +msgstr "" + +#: builtin/revert.c:112 +msgid "merge strategy" +msgstr "" + +#: builtin/revert.c:113 +msgid "option" +msgstr "" + +#: builtin/revert.c:114 +msgid "option for merge strategy" +msgstr "" + +#: builtin/revert.c:125 +msgid "append commit name" +msgstr "" + +#: builtin/revert.c:126 +msgid "allow fast-forward" +msgstr "" + +#: builtin/revert.c:127 +msgid "preserve initially empty commits" +msgstr "" + +#: builtin/revert.c:128 +msgid "allow commits with empty messages" +msgstr "" + +#: builtin/revert.c:129 +msgid "keep redundant, empty commits" +msgstr "" + +#: builtin/revert.c:133 msgid "program error" msgstr "" -#: builtin/revert.c:221 +#: builtin/revert.c:223 msgid "revert failed" msgstr "" -#: builtin/revert.c:236 +#: builtin/revert.c:238 msgid "cherry-pick failed" msgstr "" -#: builtin/rm.c:109 +#: builtin/rm.c:15 +msgid "git rm [options] [--] <file>..." +msgstr "" + +#: builtin/rm.c:64 builtin/rm.c:186 +#, c-format +msgid "" +"submodule '%s' (or one of its nested submodules) uses a .git directory\n" +"(use 'rm -rf' if you really want to remove it including all of its history)" +msgstr "" + +#: builtin/rm.c:174 #, c-format msgid "" "'%s' has staged content different from both the file and the HEAD\n" "(use -f to force removal)" msgstr "" -#: builtin/rm.c:115 +#: builtin/rm.c:180 #, c-format msgid "" "'%s' has changes staged in the index\n" "(use --cached to keep the file, or -f to force removal)" msgstr "" -#: builtin/rm.c:119 +#: builtin/rm.c:191 #, c-format msgid "" "'%s' has local modifications\n" "(use --cached to keep the file, or -f to force removal)" msgstr "" -#: builtin/rm.c:194 +#: builtin/rm.c:207 +msgid "do not list removed files" +msgstr "" + +#: builtin/rm.c:208 +msgid "only remove from the index" +msgstr "" + +#: builtin/rm.c:209 +msgid "override the up-to-date check" +msgstr "" + +#: builtin/rm.c:210 +msgid "allow recursive removal" +msgstr "" + +#: builtin/rm.c:212 +msgid "exit with a zero status even if nothing matched" +msgstr "" + +#: builtin/rm.c:283 #, c-format msgid "not removing '%s' recursively without -r" msgstr "" -#: builtin/rm.c:230 +#: builtin/rm.c:322 #, c-format msgid "git rm: unable to remove %s" msgstr "" +#: builtin/shortlog.c:13 +msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]" +msgstr "" + #: builtin/shortlog.c:157 #, c-format msgid "Missing author: %s" msgstr "" +#: builtin/shortlog.c:253 +msgid "sort output according to the number of commits per author" +msgstr "" + +#: builtin/shortlog.c:255 +msgid "Suppress commit descriptions, only provides commit count" +msgstr "" + +#: builtin/shortlog.c:257 +msgid "Show the email address of each author" +msgstr "" + +#: builtin/shortlog.c:258 +msgid "w[,i1[,i2]]" +msgstr "" + +#: builtin/shortlog.c:259 +msgid "Linewrap output" +msgstr "" + +#: builtin/show-branch.c:9 +msgid "" +"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--" +"current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --" +"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | " +"<glob>)...]" +msgstr "" + +#: builtin/show-branch.c:10 +msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]" +msgstr "" + +#: builtin/show-branch.c:651 +msgid "show remote-tracking and local branches" +msgstr "" + +#: builtin/show-branch.c:653 +msgid "show remote-tracking branches" +msgstr "" + +#: builtin/show-branch.c:655 +msgid "color '*!+-' corresponding to the branch" +msgstr "" + +#: builtin/show-branch.c:657 +msgid "show <n> more commits after the common ancestor" +msgstr "" + +#: builtin/show-branch.c:659 +msgid "synonym to more=-1" +msgstr "" + +#: builtin/show-branch.c:660 +msgid "suppress naming strings" +msgstr "" + +#: builtin/show-branch.c:662 +msgid "include the current branch" +msgstr "" + +#: builtin/show-branch.c:664 +msgid "name commits with their object names" +msgstr "" + +#: builtin/show-branch.c:666 +msgid "show possible merge bases" +msgstr "" + +#: builtin/show-branch.c:668 +msgid "show refs unreachable from any other ref" +msgstr "" + +#: builtin/show-branch.c:670 +msgid "show commits in topological order" +msgstr "" + +#: builtin/show-branch.c:672 +msgid "show only commits not on the first branch" +msgstr "" + +#: builtin/show-branch.c:674 +msgid "show merges reachable from only one tip" +msgstr "" + +#: builtin/show-branch.c:676 +msgid "show commits where no parent comes before its children" +msgstr "" + +#: builtin/show-branch.c:678 +msgid "<n>[,<base>]" +msgstr "" + +#: builtin/show-branch.c:679 +msgid "show <n> most recent ref-log entries starting at base" +msgstr "" + +#: builtin/show-ref.c:10 +msgid "" +"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash" +"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] " +msgstr "" + +#: builtin/show-ref.c:11 +msgid "git show-ref --exclude-existing[=pattern] < ref-list" +msgstr "" + +#: builtin/show-ref.c:165 +msgid "only show tags (can be combined with heads)" +msgstr "" + +#: builtin/show-ref.c:166 +msgid "only show heads (can be combined with tags)" +msgstr "" + +#: builtin/show-ref.c:167 +msgid "stricter reference checking, requires exact ref path" +msgstr "" + +#: builtin/show-ref.c:170 builtin/show-ref.c:172 +msgid "show the HEAD reference" +msgstr "" + +#: builtin/show-ref.c:174 +msgid "dereference tags into object IDs" +msgstr "" + +#: builtin/show-ref.c:176 +msgid "only show SHA1 hash using <n> digits" +msgstr "" + +#: builtin/show-ref.c:180 +msgid "do not print results to stdout (useful with --verify)" +msgstr "" + +#: builtin/show-ref.c:182 +msgid "show refs from stdin that aren't in local repository" +msgstr "" + +#: builtin/symbolic-ref.c:7 +msgid "git symbolic-ref [options] name [ref]" +msgstr "" + +#: builtin/symbolic-ref.c:8 +msgid "git symbolic-ref -d [-q] name" +msgstr "" + +#: builtin/symbolic-ref.c:40 +msgid "suppress error message for non-symbolic (detached) refs" +msgstr "" + +#: builtin/symbolic-ref.c:41 +msgid "delete symbolic ref" +msgstr "" + +#: builtin/symbolic-ref.c:42 +msgid "shorten ref output" +msgstr "" + +#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18 +msgid "reason" +msgstr "" + +#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18 +msgid "reason of the update" +msgstr "" + +#: builtin/tag.c:22 +msgid "" +"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]" +msgstr "" + +#: builtin/tag.c:23 +msgid "git tag -d <tagname>..." +msgstr "" + +#: builtin/tag.c:24 +msgid "" +"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n" +"\t\t[<pattern>...]" +msgstr "" + +#: builtin/tag.c:26 +msgid "git tag -v <tagname>..." +msgstr "" + #: builtin/tag.c:60 #, c-format msgid "malformed object at '%s'" @@ -4417,6 +7892,62 @@ msgstr "" msgid "malformed object name '%s'" msgstr "" +#: builtin/tag.c:447 +msgid "list tag names" +msgstr "" + +#: builtin/tag.c:449 +msgid "print <n> lines of each tag message" +msgstr "" + +#: builtin/tag.c:451 +msgid "delete tags" +msgstr "" + +#: builtin/tag.c:452 +msgid "verify tags" +msgstr "" + +#: builtin/tag.c:454 +msgid "Tag creation options" +msgstr "" + +#: builtin/tag.c:456 +msgid "annotated tag, needs a message" +msgstr "" + +#: builtin/tag.c:458 +msgid "tag message" +msgstr "" + +#: builtin/tag.c:460 +msgid "annotated and GPG-signed tag" +msgstr "" + +#: builtin/tag.c:464 +msgid "use another key to sign the tag" +msgstr "" + +#: builtin/tag.c:465 +msgid "replace the tag if exists" +msgstr "" + +#: builtin/tag.c:466 +msgid "show tag list in columns" +msgstr "" + +#: builtin/tag.c:468 +msgid "Tag listing options" +msgstr "" + +#: builtin/tag.c:471 +msgid "print only tags that contain the commit" +msgstr "" + +#: builtin/tag.c:477 +msgid "print only tags of the object" +msgstr "" + #: builtin/tag.c:506 msgid "--column and -n are incompatible" msgstr "" @@ -4466,24 +7997,180 @@ msgstr "" msgid "Updated tag '%s' (was %s)\n" msgstr "" -#: git.c:16 -msgid "See 'git help <command>' for more information on a specific command." +#: builtin/update-index.c:401 +msgid "git update-index [options] [--] [<file>...]" msgstr "" -#: parse-options.h:133 parse-options.h:235 -msgid "n" +#: builtin/update-index.c:718 +msgid "continue refresh even when index needs update" msgstr "" -#: parse-options.h:141 -msgid "time" +#: builtin/update-index.c:721 +msgid "refresh: ignore submodules" msgstr "" -#: parse-options.h:149 -msgid "file" +#: builtin/update-index.c:724 +msgid "do not ignore new files" msgstr "" -#: parse-options.h:151 -msgid "when" +#: builtin/update-index.c:726 +msgid "let files replace directories and vice-versa" +msgstr "" + +#: builtin/update-index.c:728 +msgid "notice files missing from worktree" +msgstr "" + +#: builtin/update-index.c:730 +msgid "refresh even if index contains unmerged entries" +msgstr "" + +#: builtin/update-index.c:733 +msgid "refresh stat information" +msgstr "" + +#: builtin/update-index.c:737 +msgid "like --refresh, but ignore assume-unchanged setting" +msgstr "" + +#: builtin/update-index.c:741 +msgid "<mode> <object> <path>" +msgstr "" + +#: builtin/update-index.c:742 +msgid "add the specified entry to the index" +msgstr "" + +#: builtin/update-index.c:746 +msgid "(+/-)x" +msgstr "" + +#: builtin/update-index.c:747 +msgid "override the executable bit of the listed files" +msgstr "" + +#: builtin/update-index.c:751 +msgid "mark files as \"not changing\"" +msgstr "" + +#: builtin/update-index.c:754 +msgid "clear assumed-unchanged bit" +msgstr "" + +#: builtin/update-index.c:757 +msgid "mark files as \"index-only\"" +msgstr "" + +#: builtin/update-index.c:760 +msgid "clear skip-worktree bit" +msgstr "" + +#: builtin/update-index.c:763 +msgid "add to index only; do not add content to object database" +msgstr "" + +#: builtin/update-index.c:765 +msgid "remove named paths even if present in worktree" +msgstr "" + +#: builtin/update-index.c:767 +msgid "with --stdin: input lines are terminated by null bytes" +msgstr "" + +#: builtin/update-index.c:769 +msgid "read list of paths to be updated from standard input" +msgstr "" + +#: builtin/update-index.c:773 +msgid "add entries from standard input to the index" +msgstr "" + +#: builtin/update-index.c:777 +msgid "repopulate stages #2 and #3 for the listed paths" +msgstr "" + +#: builtin/update-index.c:781 +msgid "only update entries that differ from HEAD" +msgstr "" + +#: builtin/update-index.c:785 +msgid "ignore files missing from worktree" +msgstr "" + +#: builtin/update-index.c:788 +msgid "report actions to standard output" +msgstr "" + +#: builtin/update-index.c:790 +msgid "(for porcelains) forget saved unresolved conflicts" +msgstr "" + +#: builtin/update-index.c:794 +msgid "write index in this format" +msgstr "" + +#: builtin/update-ref.c:7 +msgid "git update-ref [options] -d <refname> [<oldval>]" +msgstr "" + +#: builtin/update-ref.c:8 +msgid "git update-ref [options] <refname> <newval> [<oldval>]" +msgstr "" + +#: builtin/update-ref.c:19 +msgid "delete the reference" +msgstr "" + +#: builtin/update-ref.c:21 +msgid "update <refname> not the one it points to" +msgstr "" + +#: builtin/update-server-info.c:6 +msgid "git update-server-info [--force]" +msgstr "" + +#: builtin/update-server-info.c:14 +msgid "update the info files from scratch" +msgstr "" + +#: builtin/verify-pack.c:56 +msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..." +msgstr "" + +#: builtin/verify-pack.c:66 +msgid "verbose" +msgstr "" + +#: builtin/verify-pack.c:68 +msgid "show statistics only" +msgstr "" + +#: builtin/verify-tag.c:17 +msgid "git verify-tag [-v|--verbose] <tag>..." +msgstr "" + +#: builtin/verify-tag.c:73 +msgid "print tag contents" +msgstr "" + +#: builtin/write-tree.c:13 +msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]" +msgstr "" + +#: builtin/write-tree.c:26 +msgid "<prefix>/" +msgstr "" + +#: builtin/write-tree.c:27 +msgid "write tree object for a subdirectory <prefix>" +msgstr "" + +#: builtin/write-tree.c:30 +msgid "only useful for debugging" +msgstr "" + +#: git.c:16 +msgid "See 'git help <command>' for more information on a specific command." msgstr "" #: parse-options.h:156 @@ -4599,9 +8286,9 @@ msgstr "" #: git-am.sh:105 #, sh-format msgid "" -"When you have resolved this problem run \"$cmdline --resolved\".\n" -"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n" -"To restore the original branch and stop patching run \"$cmdline --abort\"." +"When you have resolved this problem, run \"$cmdline --resolved\".\n" +"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n" +"To restore the original branch and stop patching, run \"$cmdline --abort\"." msgstr "" #: git-am.sh:121 @@ -4612,6 +8299,10 @@ msgstr "" msgid "Repository lacks necessary blobs to fall back on 3-way merge." msgstr "" +#: git-am.sh:139 +msgid "Using index info to reconstruct a base tree..." +msgstr "" + #: git-am.sh:154 msgid "" "Did you hand edit your patch?\n" @@ -4622,42 +8313,48 @@ msgstr "" msgid "Falling back to patching base and 3-way merge..." msgstr "" -#: git-am.sh:275 +#: git-am.sh:179 +msgid "Failed to merge in the changes." +msgstr "" + +#: git-am.sh:274 msgid "Only one StGIT patch series can be applied at once" msgstr "" -#: git-am.sh:362 +#: git-am.sh:361 #, sh-format msgid "Patch format $patch_format is not supported." msgstr "" -#: git-am.sh:364 +#: git-am.sh:363 msgid "Patch format detection failed." msgstr "" -#: git-am.sh:418 -msgid "-d option is no longer supported. Do not use." +#: git-am.sh:389 +msgid "" +"The -b/--binary option has been a no-op for long time, and\n" +"it will be removed. Please do not use it anymore." msgstr "" -#: git-am.sh:481 +#: git-am.sh:477 #, sh-format msgid "previous rebase directory $dotest still exists but mbox given." msgstr "" -#: git-am.sh:486 +#: git-am.sh:482 msgid "Please make up your mind. --skip or --abort?" msgstr "" -#: git-am.sh:513 +#: git-am.sh:509 msgid "Resolve operation not in progress, we are not resuming." msgstr "" -#: git-am.sh:579 +#: git-am.sh:575 #, sh-format msgid "Dirty index: cannot apply patches (dirty: $files)" msgstr "" -#: git-am.sh:671 +#: git-am.sh:679 #, sh-format msgid "" "Patch is empty. Was it split wrong?\n" @@ -4665,53 +8362,60 @@ msgid "" "To restore the original branch and stop patching run \"$cmdline --abort\"." msgstr "" -#: git-am.sh:708 +#: git-am.sh:706 msgid "Patch does not have a valid e-mail address." msgstr "" -#: git-am.sh:755 +#: git-am.sh:753 msgid "cannot be interactive without stdin connected to a terminal." msgstr "" -#: git-am.sh:759 +#: git-am.sh:757 msgid "Commit Body is:" msgstr "" #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] #. in your translation. The program will only accept English #. input at this point. -#: git-am.sh:766 +#: git-am.sh:764 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " msgstr "" -#: git-am.sh:802 +#: git-am.sh:800 #, sh-format msgid "Applying: $FIRSTLINE" msgstr "" -#: git-am.sh:823 +#: git-am.sh:821 msgid "" "No changes - did you forget to use 'git add'?\n" "If there is nothing left to stage, chances are that something else\n" "already introduced the same changes; you might want to skip this patch." msgstr "" -#: git-am.sh:831 +#: git-am.sh:829 msgid "" "You still have unmerged paths in your index\n" "did you forget to use 'git add'?" msgstr "" -#: git-am.sh:847 +#: git-am.sh:845 msgid "No changes -- Patch already applied." msgstr "" -#: git-am.sh:857 +#: git-am.sh:855 #, sh-format msgid "Patch failed at $msgnum $FIRSTLINE" msgstr "" -#: git-am.sh:873 +#: git-am.sh:858 +#, sh-format +msgid "" +"The copy of the patch that failed is found in:\n" +" $dotest/patch" +msgstr "" + +#: git-am.sh:876 msgid "applying to an empty history" msgstr "" @@ -4878,7 +8582,7 @@ msgstr "" #. The working tree and the index file is still based on the #. $orig_head commit, but we are merging into $curr_head. #. First update the working tree to match $curr_head. -#: git-pull.sh:228 +#: git-pull.sh:229 #, sh-format msgid "" "Warning: fetch updated the current branch head.\n" @@ -4886,14 +8590,124 @@ msgid "" "Warning: commit $orig_head." msgstr "" -#: git-pull.sh:253 +#: git-pull.sh:254 msgid "Cannot merge multiple branches into empty head" msgstr "" -#: git-pull.sh:257 +#: git-pull.sh:258 msgid "Cannot rebase onto multiple branches" msgstr "" +#: git-rebase.sh:53 +msgid "" +"When you have resolved this problem, run \"git rebase --continue\".\n" +"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n" +"To check out the original branch and stop rebasing, run \"git rebase --abort" +"\"." +msgstr "" + +#: git-rebase.sh:160 +msgid "The pre-rebase hook refused to rebase." +msgstr "" + +#: git-rebase.sh:165 +msgid "It looks like git-am is in progress. Cannot rebase." +msgstr "" + +#: git-rebase.sh:296 +msgid "The --exec option must be used with the --interactive option" +msgstr "" + +#: git-rebase.sh:301 +msgid "No rebase in progress?" +msgstr "" + +#: git-rebase.sh:312 +msgid "The --edit-todo action can only be used during interactive rebase." +msgstr "" + +#: git-rebase.sh:319 +msgid "Cannot read HEAD" +msgstr "" + +#: git-rebase.sh:322 +msgid "" +"You must edit all merge conflicts and then\n" +"mark them as resolved using git add" +msgstr "" + +#: git-rebase.sh:340 +#, sh-format +msgid "Could not move back to $head_name" +msgstr "" + +#: git-rebase.sh:359 +#, sh-format +msgid "" +"It seems that there is already a $state_dir_base directory, and\n" +"I wonder if you are in the middle of another rebase. If that is the\n" +"case, please try\n" +"\t$cmd_live_rebase\n" +"If that is not the case, please\n" +"\t$cmd_clear_stale_rebase\n" +"and run me again. I am stopping in case you still have something\n" +"valuable there." +msgstr "" + +#: git-rebase.sh:404 +#, sh-format +msgid "invalid upstream $upstream_name" +msgstr "" + +#: git-rebase.sh:428 +#, sh-format +msgid "$onto_name: there are more than one merge bases" +msgstr "" + +#: git-rebase.sh:431 git-rebase.sh:435 +#, sh-format +msgid "$onto_name: there is no merge base" +msgstr "" + +#: git-rebase.sh:440 +#, sh-format +msgid "Does not point to a valid commit: $onto_name" +msgstr "" + +#: git-rebase.sh:463 +#, sh-format +msgid "fatal: no such branch: $branch_name" +msgstr "" + +#: git-rebase.sh:483 +msgid "Please commit or stash them." +msgstr "" + +#: git-rebase.sh:501 +#, sh-format +msgid "Current branch $branch_name is up to date." +msgstr "" + +#: git-rebase.sh:504 +#, sh-format +msgid "Current branch $branch_name is up to date, rebase forced." +msgstr "" + +#: git-rebase.sh:515 +#, sh-format +msgid "Changes from $mb to $onto:" +msgstr "" + +#. Detach HEAD and reset the tree +#: git-rebase.sh:524 +msgid "First, rewinding head to replay your work on top of it..." +msgstr "" + +#: git-rebase.sh:532 +#, sh-format +msgid "Fast-forwarded $branch_name to $onto_name." +msgstr "" + #: git-stash.sh:51 msgid "git stash clear with parameters is unimplemented" msgstr "" @@ -4999,59 +8813,59 @@ msgstr "" msgid "Cannot unstage modified files" msgstr "" -#: git-stash.sh:474 +#: git-stash.sh:475 msgid "Index was not unstashed." msgstr "" -#: git-stash.sh:491 +#: git-stash.sh:492 #, sh-format msgid "Dropped ${REV} ($s)" msgstr "" -#: git-stash.sh:492 +#: git-stash.sh:493 #, sh-format msgid "${REV}: Could not drop stash entry" msgstr "" -#: git-stash.sh:499 +#: git-stash.sh:500 msgid "No branch name specified" msgstr "" -#: git-stash.sh:570 +#: git-stash.sh:571 msgid "(To restore them type \"git stash apply\")" msgstr "" -#: git-submodule.sh:56 +#: git-submodule.sh:89 #, sh-format msgid "cannot strip one component off url '$remoteurl'" msgstr "" -#: git-submodule.sh:109 +#: git-submodule.sh:168 #, sh-format msgid "No submodule mapping found in .gitmodules for path '$sm_path'" msgstr "" -#: git-submodule.sh:150 +#: git-submodule.sh:211 #, sh-format msgid "Clone of '$url' into submodule path '$sm_path' failed" msgstr "" -#: git-submodule.sh:160 +#: git-submodule.sh:223 #, sh-format msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa" msgstr "" -#: git-submodule.sh:249 +#: git-submodule.sh:316 #, sh-format msgid "repo URL: '$repo' must be absolute or begin with ./|../" msgstr "" -#: git-submodule.sh:266 +#: git-submodule.sh:333 #, sh-format msgid "'$sm_path' already exists in the index" msgstr "" -#: git-submodule.sh:270 +#: git-submodule.sh:337 #, sh-format msgid "" "The following path is ignored by one of your .gitignore files:\n" @@ -5059,155 +8873,180 @@ msgid "" "Use -f if you really want to add it." msgstr "" -#: git-submodule.sh:281 +#: git-submodule.sh:355 #, sh-format msgid "Adding existing repo at '$sm_path' to the index" msgstr "" -#: git-submodule.sh:283 +#: git-submodule.sh:357 #, sh-format msgid "'$sm_path' already exists and is not a valid git repo" msgstr "" -#: git-submodule.sh:297 +#: git-submodule.sh:365 +#, sh-format +msgid "A git directory for '$sm_name' is found locally with remote(s):" +msgstr "" + +#: git-submodule.sh:367 +#, sh-format +msgid "" +"If you want to reuse this local git directory instead of cloning again from" +msgstr "" + +#: git-submodule.sh:369 +#, sh-format +msgid "" +"use the '--force' option. If the local git directory is not the correct repo" +msgstr "" + +#: git-submodule.sh:370 +#, sh-format +msgid "" +"or you are unsure what this means choose another name with the '--name' " +"option." +msgstr "" + +#: git-submodule.sh:372 +#, sh-format +msgid "Reactivating local git directory for submodule '$sm_name'." +msgstr "" + +#: git-submodule.sh:384 #, sh-format msgid "Unable to checkout submodule '$sm_path'" msgstr "" -#: git-submodule.sh:302 +#: git-submodule.sh:389 #, sh-format msgid "Failed to add submodule '$sm_path'" msgstr "" -#: git-submodule.sh:307 +#: git-submodule.sh:394 #, sh-format msgid "Failed to register submodule '$sm_path'" msgstr "" -#: git-submodule.sh:349 +#: git-submodule.sh:437 #, sh-format msgid "Entering '$prefix$sm_path'" msgstr "" -#: git-submodule.sh:363 +#: git-submodule.sh:451 #, sh-format msgid "Stopping at '$sm_path'; script returned non-zero status." msgstr "" -#: git-submodule.sh:406 +#: git-submodule.sh:495 #, sh-format msgid "No url found for submodule path '$sm_path' in .gitmodules" msgstr "" -#: git-submodule.sh:415 +#: git-submodule.sh:504 #, sh-format msgid "Failed to register url for submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:417 +#: git-submodule.sh:506 #, sh-format msgid "Submodule '$name' ($url) registered for path '$sm_path'" msgstr "" -#: git-submodule.sh:425 +#: git-submodule.sh:514 #, sh-format msgid "Failed to register update mode for submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:524 +#: git-submodule.sh:614 #, sh-format msgid "" "Submodule path '$sm_path' not initialized\n" "Maybe you want to use 'update --init'?" msgstr "" -#: git-submodule.sh:537 +#: git-submodule.sh:627 #, sh-format msgid "Unable to find current revision in submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:556 +#: git-submodule.sh:646 #, sh-format msgid "Unable to fetch in submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:570 +#: git-submodule.sh:660 #, sh-format msgid "Unable to rebase '$sha1' in submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:571 +#: git-submodule.sh:661 #, sh-format msgid "Submodule path '$sm_path': rebased into '$sha1'" msgstr "" -#: git-submodule.sh:576 +#: git-submodule.sh:666 #, sh-format msgid "Unable to merge '$sha1' in submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:577 +#: git-submodule.sh:667 #, sh-format msgid "Submodule path '$sm_path': merged in '$sha1'" msgstr "" -#: git-submodule.sh:582 +#: git-submodule.sh:672 #, sh-format msgid "Unable to checkout '$sha1' in submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:583 +#: git-submodule.sh:673 #, sh-format msgid "Submodule path '$sm_path': checked out '$sha1'" msgstr "" -#: git-submodule.sh:605 git-submodule.sh:928 +#: git-submodule.sh:695 git-submodule.sh:1017 #, sh-format msgid "Failed to recurse into submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:713 -msgid "--cached cannot be used with --files" +#: git-submodule.sh:803 +msgid "The --cached option cannot be used with the --files option" msgstr "" #. unexpected type -#: git-submodule.sh:753 +#: git-submodule.sh:843 #, sh-format msgid "unexpected mode $mod_dst" msgstr "" -#: git-submodule.sh:771 +#: git-submodule.sh:861 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_src" msgstr "" -#: git-submodule.sh:774 +#: git-submodule.sh:864 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_dst" msgstr "" -#: git-submodule.sh:777 +#: git-submodule.sh:867 #, sh-format msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst" msgstr "" -#: git-submodule.sh:802 +#: git-submodule.sh:892 msgid "blob" msgstr "" -#: git-submodule.sh:803 -msgid "submodule" -msgstr "" - -#: git-submodule.sh:840 +#: git-submodule.sh:930 msgid "# Submodules changed but not updated:" msgstr "" -#: git-submodule.sh:842 +#: git-submodule.sh:932 msgid "# Submodule changes to be committed:" msgstr "" -#: git-submodule.sh:974 +#: git-submodule.sh:1080 #, sh-format -msgid "Synchronizing submodule url for '$name'" +msgid "Synchronizing submodule url for '$prefix$sm_path'" msgstr "" @@ -5,10 +5,10 @@ # msgid "" msgstr "" -"Project-Id-Version: git 1.7.10\n" +"Project-Id-Version: git 1.8.1\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2012-06-08 10:20+0800\n" -"PO-Revision-Date: 2012-07-01 22:59+0100\n" +"POT-Creation-Date: 2012-11-30 12:40+0800\n" +"PO-Revision-Date: 2012-11-30 10:49+0100\n" "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n" "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n" "Language: sv\n" @@ -38,6 +38,101 @@ msgstr "" "lämpligt för att ange lösning och checka in,\n" "eller använd \"git commit -a\"." +#: archive.c:10 +msgid "git archive [options] <tree-ish> [<path>...]" +msgstr "git archive [flaggor] <träd-igt> [<sökväg>...]" + +#: archive.c:11 +msgid "git archive --list" +msgstr "git archive --list" + +#: archive.c:12 +msgid "" +"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]" +msgstr "" +"git archive --remote <arkiv> [--exec <kmd>] [flaggor] <träd-igt> " +"[<sökväg>...]" + +#: archive.c:13 +msgid "git archive --remote <repo> [--exec <cmd>] --list" +msgstr "git archive --remote <arkiv> [--exec <kmd>] --list" + +#: archive.c:322 +msgid "fmt" +msgstr "fmt" + +#: archive.c:322 +msgid "archive format" +msgstr "arkivformat" + +#: archive.c:323 builtin/log.c:1084 +msgid "prefix" +msgstr "prefix" + +#: archive.c:324 +msgid "prepend prefix to each pathname in the archive" +msgstr "lägg till prefix till varje sökväg i arkivet" + +#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2390 +#: builtin/blame.c:2391 builtin/config.c:55 builtin/fast-export.c:642 +#: builtin/fast-export.c:644 builtin/grep.c:715 builtin/hash-object.c:77 +#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:540 +#: builtin/notes.c:697 builtin/read-tree.c:107 parse-options.h:149 +msgid "file" +msgstr "fil" + +#: archive.c:326 builtin/archive.c:92 +msgid "write the archive to this file" +msgstr "skriv arkivet till filen" + +#: archive.c:328 +msgid "read .gitattributes in working directory" +msgstr "läs .gitattributes i arbetskatalogen" + +#: archive.c:329 +msgid "report archived files on stderr" +msgstr "rapportera arkiverade filer pÃ¥ standard fel" + +#: archive.c:330 +msgid "store only" +msgstr "endast spara" + +#: archive.c:331 +msgid "compress faster" +msgstr "komprimera snabbare" + +#: archive.c:339 +msgid "compress better" +msgstr "komprimera bättre" + +#: archive.c:342 +msgid "list supported archive formats" +msgstr "visa understödda arkivformat" + +#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85 +msgid "repo" +msgstr "arkiv" + +#: archive.c:345 builtin/archive.c:94 +msgid "retrieve the archive from remote repository <repo>" +msgstr "hämta arkivet frÃ¥n fjärrarkivet <arkiv>" + +#: archive.c:346 builtin/archive.c:95 builtin/notes.c:619 +msgid "command" +msgstr "kommando" + +#: archive.c:347 builtin/archive.c:96 +msgid "path to the remote git-upload-archive command" +msgstr "sökväg till kommandot git-upload-archive pÃ¥ fjärren" + +#: attr.c:259 +msgid "" +"Negative patterns are forbidden in git attributes\n" +"Use '\\!' for literal leading exclamation." +msgstr "" +"Negativa mönster är förbjudna i git-attribut\n" +"Använd '\\!' för att inleda med ett utropstecken." + #: bundle.c:36 #, c-format msgid "'%s' does not look like a v2 bundle file" @@ -48,7 +143,7 @@ msgstr "'%s' ser inte ut som en v2-bundle-fil" msgid "unrecognized header: %s%s (%d)" msgstr "okänt huvud: %s%s (%d)" -#: bundle.c:89 builtin/commit.c:696 +#: bundle.c:89 builtin/commit.c:674 #, c-format msgid "could not open '%s'" msgstr "kunde inte öppna \"%s\"" @@ -57,8 +152,8 @@ msgstr "kunde inte öppna \"%s\"" msgid "Repository lacks these prerequisite commits:" msgstr "Arkivet saknar dessa nödvändiga incheckningar:" -#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:289 -#: builtin/log.c:720 builtin/log.c:1309 builtin/log.c:1528 builtin/merge.c:347 +#: bundle.c:164 sequencer.c:562 sequencer.c:994 builtin/log.c:290 +#: builtin/log.c:732 builtin/log.c:1319 builtin/log.c:1535 builtin/merge.c:347 #: builtin/shortlog.c:181 msgid "revision walk setup failed" msgstr "misslyckades skapa revisionstraversering" @@ -71,53 +166,57 @@ msgstr[0] "Paketet (bundlen) innehÃ¥ller %d referens" msgstr[1] "Paketet (bundlen) innehÃ¥ller %d referenser" #: bundle.c:192 +msgid "The bundle records a complete history." +msgstr "Paketet (bundlen) beskriver en komplett historik." + +#: bundle.c:195 #, c-format msgid "The bundle requires this ref" msgid_plural "The bundle requires these %d refs" msgstr[0] "Paketet (bundlen) kräver denna referens" msgstr[1] "Paketet (bundlen) kräver dessa %d referenser" -#: bundle.c:290 +#: bundle.c:294 msgid "rev-list died" msgstr "rev-list dog" -#: bundle.c:296 builtin/log.c:1205 builtin/shortlog.c:284 +#: bundle.c:300 builtin/log.c:1215 builtin/shortlog.c:284 #, c-format msgid "unrecognized argument: %s" msgstr "okänt argument: %s" -#: bundle.c:331 +#: bundle.c:335 #, c-format msgid "ref '%s' is excluded by the rev-list options" msgstr "referensen \"%s\" exkluderas av argumenten till rev-list" -#: bundle.c:376 +#: bundle.c:380 msgid "Refusing to create empty bundle." msgstr "Vägrar skapa ett tomt paket (bundle)." -#: bundle.c:394 +#: bundle.c:398 msgid "Could not spawn pack-objects" msgstr "Kunde inte starta pack-objects" -#: bundle.c:412 +#: bundle.c:416 msgid "pack-objects died" msgstr "pack-objects misslyckades" -#: bundle.c:415 +#: bundle.c:419 #, c-format msgid "cannot create '%s'" msgstr "kan inte skapa \"%s\"" -#: bundle.c:437 +#: bundle.c:441 msgid "index-pack died" msgstr "index-pack dog" -#: commit.c:48 +#: commit.c:50 #, c-format msgid "could not parse %s" msgstr "kunde inte tolka %s" -#: commit.c:50 +#: commit.c:52 #, c-format msgid "%s %s is not a commit!" msgstr "%s %s är inte en incheckning!" @@ -207,17 +306,22 @@ msgid_plural "%lu years ago" msgstr[0] "%lu Ã¥r sedan" msgstr[1] "%lu Ã¥r sedan" -#: diff.c:105 +#: diff.c:111 +#, c-format +msgid " Failed to parse dirstat cut-off percentage '%s'\n" +msgstr " Misslyckades tolka dirstat-avskärningsprocentandel \"%s\"\n" + +#: diff.c:116 #, c-format -msgid " Failed to parse dirstat cut-off percentage '%.*s'\n" -msgstr " Misslyckades tolka dirstat-avskärningsprocentandel \"%.*s\"\n" +msgid " Unknown dirstat parameter '%s'\n" +msgstr " Okänd dirstat-parameter \"%s\"\n" -#: diff.c:110 +#: diff.c:194 #, c-format -msgid " Unknown dirstat parameter '%.*s'\n" -msgstr " Okänd dirstat-parameter \"%.*s\"\n" +msgid "Unknown value for 'diff.submodule' config variable: '%s'" +msgstr "Okänt värde för konfigurationsvariabeln \"diff.submodule\": \"%s\"" -#: diff.c:210 +#: diff.c:237 #, c-format msgid "" "Found errors in 'diff.dirstat' config variable:\n" @@ -226,32 +330,7 @@ msgstr "" "Hittade fel i konfigurationsvariabeln \"diff.dirstat\":\n" "%s" -#: diff.c:1400 -msgid " 0 files changed\n" -msgstr " 0 filer ändrade\n" - -#: diff.c:1404 -#, c-format -msgid " %d file changed" -msgid_plural " %d files changed" -msgstr[0] " %d fil ändrad" -msgstr[1] " %d filer ändrade" - -#: diff.c:1421 -#, c-format -msgid ", %d insertion(+)" -msgid_plural ", %d insertions(+)" -msgstr[0] ", %d tillägg(+)" -msgstr[1] ", %d tillägg(+)" - -#: diff.c:1432 -#, c-format -msgid ", %d deletion(-)" -msgid_plural ", %d deletions(-)" -msgstr[0] ", %d borttagning(-)" -msgstr[1] ", %d borttagningar(-)" - -#: diff.c:3478 +#: diff.c:3494 #, c-format msgid "" "Failed to parse --dirstat/-X option parameter:\n" @@ -260,6 +339,11 @@ msgstr "" "Misslyckades tolka argument till flaggan --dirstat/-X;\n" "%s" +#: diff.c:3508 +#, c-format +msgid "Failed to parse --submodule option parameter: '%s'" +msgstr "Misslyckades tolka argument till flaggan --submodule: \"%s\"" + #: gpg-interface.c:59 msgid "could not run gpg." msgstr "kunde inte köra gpg." @@ -272,31 +356,31 @@ msgstr "gpg godtog inte data" msgid "gpg failed to sign the data" msgstr "gpg misslyckades signera data" -#: grep.c:1320 +#: grep.c:1622 #, c-format msgid "'%s': unable to read %s" msgstr "\"%s\" kunde inte läsa %s" -#: grep.c:1337 +#: grep.c:1639 #, c-format msgid "'%s': %s" msgstr "\"%s\": %s" -#: grep.c:1348 +#: grep.c:1650 #, c-format msgid "'%s': short read %s" msgstr "\"%s\": kort läsning %s" -#: help.c:207 +#: help.c:212 #, c-format msgid "available git commands in '%s'" msgstr "git-kommandon tillgängliga i \"%s\"" -#: help.c:214 +#: help.c:219 msgid "git commands available from elsewhere on your $PATH" msgstr "git-kommandon frÃ¥n andra platser i din $PATH" -#: help.c:270 +#: help.c:275 #, c-format msgid "" "'%s' appears to be a git command, but we were not\n" @@ -305,11 +389,11 @@ msgstr "" "\"%s\" verkar vara ett git-kommando, men vi kan inte\n" "köra det. Kanske git-%s är trasigt?" -#: help.c:327 +#: help.c:332 msgid "Uh oh. Your system reports no Git commands at all." msgstr "Oj dÃ¥. Ditt system rapporterar inga Git-kommandon alls." -#: help.c:349 +#: help.c:354 #, c-format msgid "" "WARNING: You called a Git command named '%s', which does not exist.\n" @@ -318,17 +402,17 @@ msgstr "" "VARNING: Du anropade ett Git-kommando vid namn \"%s\", som inte finns.\n" "Fortsätter under förutsättningen att du menade \"%s\"" -#: help.c:354 +#: help.c:359 #, c-format msgid "in %0.1f seconds automatically..." msgstr "automatiskt om %0.1f sekunder..." -#: help.c:361 +#: help.c:366 #, c-format msgid "git: '%s' is not a git command. See 'git --help'." msgstr "git: \"%s\" är inte ett git-kommando. Se \"git --help\"." -#: help.c:365 +#: help.c:370 msgid "" "\n" "Did you mean this?" @@ -342,35 +426,302 @@ msgstr[1] "" "\n" "Menade du ett av dessa?" -#: parse-options.c:493 +#: merge.c:56 +msgid "failed to read the cache" +msgstr "misslyckads läsa cachen" + +#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534 +#: builtin/clone.c:586 +msgid "unable to write new index file" +msgstr "kunde inte skriva ny indexfil" + +#: merge-recursive.c:190 +#, c-format +msgid "(bad commit)\n" +msgstr "(felaktig incheckning)\n" + +#: merge-recursive.c:206 +#, c-format +msgid "addinfo_cache failed for path '%s'" +msgstr "addinfo_cache misslyckades för sökvägen \"%s\"" + +#: merge-recursive.c:268 +msgid "error building trees" +msgstr "fel vid byggande av träd" + +#: merge-recursive.c:672 +#, c-format +msgid "failed to create path '%s'%s" +msgstr "misslyckades skapa sökvägen \"%s\"%s" + +#: merge-recursive.c:683 +#, c-format +msgid "Removing %s to make room for subdirectory\n" +msgstr "Tar bort %s för att göra plats för underkatalog\n" + +#. something else exists +#. .. but not some other error (who really cares what?) +#: merge-recursive.c:697 merge-recursive.c:718 +msgid ": perhaps a D/F conflict?" +msgstr ": kanske en K/F-konflikt?" + +#: merge-recursive.c:708 +#, c-format +msgid "refusing to lose untracked file at '%s'" +msgstr "vägrar förlora ospÃ¥rad fil vid \"%s\"" + +#: merge-recursive.c:748 +#, c-format +msgid "cannot read object %s '%s'" +msgstr "kan inte läsa objektet %s: \"%s\"" + +#: merge-recursive.c:750 +#, c-format +msgid "blob expected for %s '%s'" +msgstr "blob förväntades för %s \"%s\"" + +#: merge-recursive.c:773 builtin/clone.c:302 +#, c-format +msgid "failed to open '%s'" +msgstr "misslyckades öppna \"%s\"" + +#: merge-recursive.c:781 +#, c-format +msgid "failed to symlink '%s'" +msgstr "misslyckades ta skapa symboliska länken \"%s\"" + +#: merge-recursive.c:784 +#, c-format +msgid "do not know what to do with %06o %s '%s'" +msgstr "vet inte hur %06o %s \"%s\" skall hanteras" + +#: merge-recursive.c:922 +msgid "Failed to execute internal merge" +msgstr "Misslyckades exekvera intern sammanslagning" + +#: merge-recursive.c:926 +#, c-format +msgid "Unable to add %s to database" +msgstr "Kunde inte lägga till %s till databasen" + +#: merge-recursive.c:942 +msgid "unsupported object type in the tree" +msgstr "objekttyp som ej stöds upptäcktes i trädet" + +#: merge-recursive.c:1021 merge-recursive.c:1035 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree." +msgstr "" +"KONFLIKT (%s/radera): %s raderad i %s och %s i %s. Versionen %s av %s lämnad " +"i trädet." + +#: merge-recursive.c:1027 merge-recursive.c:1040 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree at %s." +msgstr "" +"KONFLIKT (%s/radera): %s raderad i %s och %s i %s. Versionen %s av %s lämnad " +"i trädet vid %s." + +#: merge-recursive.c:1081 +msgid "rename" +msgstr "namnbyte" + +#: merge-recursive.c:1081 +msgid "renamed" +msgstr "namnbytt" + +#: merge-recursive.c:1137 +#, c-format +msgid "%s is a directory in %s adding as %s instead" +msgstr "%s är en katalog i %s lägger till som %s istället" + +#: merge-recursive.c:1159 +#, c-format +msgid "" +"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s" +"\"->\"%s\" in \"%s\"%s" +msgstr "" +"KONFLIKT (namnbyte/namnbyte): Namnbyte \"%s\"->\"%s\" pÃ¥ grenen \"%s\" " +"namnbyte \"%s\"->\"%s\" i \"%s\"%s" + +#: merge-recursive.c:1164 +msgid " (left unresolved)" +msgstr " (lämnad olöst)" + +#: merge-recursive.c:1218 +#, c-format +msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s" +msgstr "" +"KONFLIKT (namnbyte/namnbyte): Namnbyte %s->%s i %s. Namnbyte %s->%s i %s" + +#: merge-recursive.c:1248 +#, c-format +msgid "Renaming %s to %s and %s to %s instead" +msgstr "Byter namn pÃ¥ %s till %s och %s till %s istället" + +#: merge-recursive.c:1447 +#, c-format +msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s" +msgstr "KONFLIKT (namnbyte/tillägg): Namnbyte %s->%s i %s. %s tillagd i %s" + +#: merge-recursive.c:1457 +#, c-format +msgid "Adding merged %s" +msgstr "Lägger till sammanslagen %s" + +#: merge-recursive.c:1462 merge-recursive.c:1660 +#, c-format +msgid "Adding as %s instead" +msgstr "Lägger till som %s iställer" + +#: merge-recursive.c:1513 +#, c-format +msgid "cannot read object %s" +msgstr "kan inte läsa objektet %s" + +#: merge-recursive.c:1516 +#, c-format +msgid "object %s is not a blob" +msgstr "objektet %s är inte en blob" + +#: merge-recursive.c:1564 +msgid "modify" +msgstr "ändra" + +#: merge-recursive.c:1564 +msgid "modified" +msgstr "ändrad" + +#: merge-recursive.c:1574 +msgid "content" +msgstr "innehÃ¥ll" + +#: merge-recursive.c:1581 +msgid "add/add" +msgstr "tillägg/tillägg" + +#: merge-recursive.c:1615 +#, c-format +msgid "Skipped %s (merged same as existing)" +msgstr "Hoppade över %s (sammanslagen samma som befintlig)" + +#: merge-recursive.c:1629 +#, c-format +msgid "Auto-merging %s" +msgstr "SlÃ¥r ihop %s automatiskt" + +#: merge-recursive.c:1633 git-submodule.sh:893 +msgid "submodule" +msgstr "undermodul" + +#: merge-recursive.c:1634 +#, c-format +msgid "CONFLICT (%s): Merge conflict in %s" +msgstr "KONFLIKT (%s): Sammanslagningskonflikt i %s" + +#: merge-recursive.c:1724 +#, c-format +msgid "Removing %s" +msgstr "Tar bort %s" + +#: merge-recursive.c:1749 +msgid "file/directory" +msgstr "fil/katalog" + +#: merge-recursive.c:1755 +msgid "directory/file" +msgstr "katalog/fil" + +#: merge-recursive.c:1760 +#, c-format +msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s" +msgstr "" +"KONFLIKT (%s): Det finns en katalog med namnet %s i %s. Lägger till %s som %s" + +#: merge-recursive.c:1770 +#, c-format +msgid "Adding %s" +msgstr "Lägger till %s" + +#: merge-recursive.c:1787 +msgid "Fatal merge failure, shouldn't happen." +msgstr "Ödesdigert sammanslagningsfel, borde inte inträffa." + +#: merge-recursive.c:1806 +msgid "Already up-to-date!" +msgstr "Redan à jour!" + +#: merge-recursive.c:1815 +#, c-format +msgid "merging of trees %s and %s failed" +msgstr "sammanslagning av träden %s och %s misslyckades" + +#: merge-recursive.c:1845 +#, c-format +msgid "Unprocessed path??? %s" +msgstr "Obehandlad sökväg??? %s" + +#: merge-recursive.c:1890 +msgid "Merging:" +msgstr "SlÃ¥r ihop:" + +#: merge-recursive.c:1903 +#, c-format +msgid "found %u common ancestor:" +msgid_plural "found %u common ancestors:" +msgstr[0] "hittade %u gemensam förfader:" +msgstr[1] "hittade %u gemensamma förfäder:" + +#: merge-recursive.c:1940 +msgid "merge returned no commit" +msgstr "sammanslagningen returnerade ingen incheckning" + +#: merge-recursive.c:1997 +#, c-format +msgid "Could not parse object '%s'" +msgstr "Kunde inte tolka objektet \"%s\"" + +#: merge-recursive.c:2009 builtin/merge.c:643 +msgid "Unable to write index." +msgstr "Kunde inte skriva indexet." + +#: parse-options.c:494 msgid "..." msgstr "..." -#: parse-options.c:511 +#: parse-options.c:512 #, c-format msgid "usage: %s" msgstr "användning: %s" #. TRANSLATORS: the colon here should align with the #. one in "usage: %s" translation -#: parse-options.c:515 +#: parse-options.c:516 #, c-format msgid " or: %s" msgstr " eller: %s" -#: parse-options.c:518 +#: parse-options.c:519 #, c-format msgid " %s" msgstr " %s" -#: remote.c:1629 +#: remote.c:1632 #, c-format msgid "Your branch is ahead of '%s' by %d commit.\n" msgid_plural "Your branch is ahead of '%s' by %d commits.\n" msgstr[0] "Din gren ligger före \"%s\" med %d incheckning.\n" msgstr[1] "Din gren ligger före \"%s\" med %d incheckningar.\n" -#: remote.c:1635 +#: remote.c:1637 +msgid " (use \"git push\" to publish your local commits)\n" +msgstr " (använd \"git push\" för att publicera dina lokala incheckningar)\n" + +#: remote.c:1640 #, c-format msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n" msgid_plural "" @@ -380,7 +731,11 @@ msgstr[0] "" msgstr[1] "" "Din gren ligger efter \"%s\" med %d incheckningar, och kan snabbspolas.\n" -#: remote.c:1643 +#: remote.c:1647 +msgid " (use \"git pull\" to update your local branch)\n" +msgstr " (använd \"git pull\" för att uppdatera din lokala gren)\n" + +#: remote.c:1650 #, c-format msgid "" "Your branch and '%s' have diverged,\n" @@ -395,19 +750,23 @@ msgstr[1] "" "Din gren och \"%s\" har divergerat,\n" "och har %d respektive %d olika incheckningar.\n" -#: sequencer.c:121 builtin/merge.c:865 builtin/merge.c:978 -#: builtin/merge.c:1088 builtin/merge.c:1098 +#: remote.c:1659 +msgid " (use \"git pull\" to merge the remote branch into yours)\n" +msgstr " (använd \"git pull\" för att slÃ¥ ihop fjärrgrenen med din egen)\n" + +#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984 +#: builtin/merge.c:994 #, c-format msgid "Could not open '%s' for writing" msgstr "Kunde inte öppna \"%s\" för skrivning" -#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:868 -#: builtin/merge.c:1090 builtin/merge.c:1103 +#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986 +#: builtin/merge.c:999 #, c-format msgid "Could not write to '%s'" msgstr "Kunde inte skriva till \"%s\"" -#: sequencer.c:144 +#: sequencer.c:146 msgid "" "after resolving the conflicts, mark the corrected paths\n" "with 'git add <paths>' or 'git rm <paths>'" @@ -415,7 +774,7 @@ msgstr "" "efter att ha löst konflikterna, markera de rättade sökvägarna\n" "med \"git add <sökvägar>\" eller \"git rm <sökvägar>\"" -#: sequencer.c:147 +#: sequencer.c:149 msgid "" "after resolving the conflicts, mark the corrected paths\n" "with 'git add <paths>' or 'git rm <paths>'\n" @@ -425,488 +784,610 @@ msgstr "" "med \"git add <sökvägar>\" eller \"git rm <sökvägar>\"\n" "och checka in resultatet med \"git commit\"" -#: sequencer.c:160 sequencer.c:758 sequencer.c:841 +#: sequencer.c:162 sequencer.c:770 sequencer.c:853 #, c-format msgid "Could not write to %s" msgstr "Kunde inte skriva till %s" -#: sequencer.c:163 +#: sequencer.c:165 #, c-format msgid "Error wrapping up %s" msgstr "Fel vid ombrytning av %s" -#: sequencer.c:178 +#: sequencer.c:180 msgid "Your local changes would be overwritten by cherry-pick." msgstr "Dina lokala ändringar skulle skrivas över av \"cherry-pick\"." -#: sequencer.c:180 +#: sequencer.c:182 msgid "Your local changes would be overwritten by revert." msgstr "Dina lokala ändringar skulle skrivas över av \"revert\"." -#: sequencer.c:183 +#: sequencer.c:185 msgid "Commit your changes or stash them to proceed." msgstr "Checka in dina ändringar eller använd \"stash\" för att fortsätta." #. TRANSLATORS: %s will be "revert" or "cherry-pick" -#: sequencer.c:233 +#: sequencer.c:235 #, c-format msgid "%s: Unable to write new index file" msgstr "%s: Kunde inte skriva ny indexfil" -#: sequencer.c:261 +#: sequencer.c:266 msgid "Could not resolve HEAD commit\n" msgstr "Kunde inte bestämma HEAD:s incheckning\n" -#: sequencer.c:282 +#: sequencer.c:287 msgid "Unable to update cache tree\n" msgstr "Kan inte uppdatera cacheträd\n" -#: sequencer.c:324 +#: sequencer.c:332 #, c-format msgid "Could not parse commit %s\n" msgstr "Kunde inte tolka incheckningen %s\n" -#: sequencer.c:329 +#: sequencer.c:337 #, c-format msgid "Could not parse parent commit %s\n" msgstr "Kunde inte tolka föräldraincheckningen %s\n" -#: sequencer.c:395 +#: sequencer.c:403 msgid "Your index file is unmerged." msgstr "Din indexfil har inte slagits ihop." -#: sequencer.c:398 +#: sequencer.c:406 msgid "You do not have a valid HEAD" msgstr "Du har ingen giltig HEAD" -#: sequencer.c:413 +#: sequencer.c:421 #, c-format msgid "Commit %s is a merge but no -m option was given." msgstr "Incheckning %s är en sammanslagning, men flaggan -m angavs inte." -#: sequencer.c:421 +#: sequencer.c:429 #, c-format msgid "Commit %s does not have parent %d" msgstr "Incheckning %s har inte förälder %d" -#: sequencer.c:425 +#: sequencer.c:433 #, c-format msgid "Mainline was specified but commit %s is not a merge." msgstr "Huvudlinje angavs, men incheckningen %s är inte en sammanslagning" #. TRANSLATORS: The first %s will be "revert" or #. "cherry-pick", the second %s a SHA1 -#: sequencer.c:436 +#: sequencer.c:444 #, c-format msgid "%s: cannot parse parent commit %s" msgstr "%s: kan inte tolka föräldraincheckningen %s" -#: sequencer.c:440 +#: sequencer.c:448 #, c-format msgid "Cannot get commit message for %s" msgstr "Kan inte hämta incheckningsmeddelande för %s" -#: sequencer.c:524 +#: sequencer.c:532 #, c-format msgid "could not revert %s... %s" msgstr "kunde inte Ã¥ngra %s... %s" -#: sequencer.c:525 +#: sequencer.c:533 #, c-format msgid "could not apply %s... %s" msgstr "kunde inte tillämpa %s... %s" -#: sequencer.c:553 +#: sequencer.c:565 msgid "empty commit set passed" msgstr "den angivna uppsättningen incheckningar är tom" -#: sequencer.c:561 +#: sequencer.c:573 #, c-format msgid "git %s: failed to read the index" msgstr "git %s: misslyckades läsa indexet" -#: sequencer.c:566 +#: sequencer.c:578 #, c-format msgid "git %s: failed to refresh the index" msgstr "git %s: misslyckades uppdatera indexet" -#: sequencer.c:624 +#: sequencer.c:636 #, c-format msgid "Cannot %s during a %s" msgstr "kan inte %s under en %s" -#: sequencer.c:646 +#: sequencer.c:658 #, c-format msgid "Could not parse line %d." msgstr "Kan inte tolka rad %d." -#: sequencer.c:651 +#: sequencer.c:663 msgid "No commits parsed." msgstr "Inga incheckningar lästes." -#: sequencer.c:664 +#: sequencer.c:676 #, c-format msgid "Could not open %s" msgstr "Kunde inte öppna %s" -#: sequencer.c:668 +#: sequencer.c:680 #, c-format msgid "Could not read %s." msgstr "kunde inte läsa %s." -#: sequencer.c:675 +#: sequencer.c:687 #, c-format msgid "Unusable instruction sheet: %s" msgstr "Oanvändbart manus: %s" -#: sequencer.c:703 +#: sequencer.c:715 #, c-format msgid "Invalid key: %s" msgstr "Felaktig nyckel: %s" -#: sequencer.c:706 +#: sequencer.c:718 #, c-format msgid "Invalid value for %s: %s" msgstr "Felaktigt värde för %s: %s" -#: sequencer.c:718 +#: sequencer.c:730 #, c-format msgid "Malformed options sheet: %s" msgstr "Trasigt manus: %s" -#: sequencer.c:739 +#: sequencer.c:751 msgid "a cherry-pick or revert is already in progress" msgstr "en \"cherry-pick\" eller \"revert\" pÃ¥gÃ¥r redan" -#: sequencer.c:740 +#: sequencer.c:752 msgid "try \"git cherry-pick (--continue | --quit | --abort)\"" msgstr "testa \"git cherry-pick (--continue | --quit | --abort)\"" -#: sequencer.c:744 +#: sequencer.c:756 #, c-format msgid "Could not create sequencer directory %s" msgstr "Kunde inte skapa \"sequencer\"-katalogen \"%s\"" -#: sequencer.c:760 sequencer.c:845 +#: sequencer.c:772 sequencer.c:857 #, c-format msgid "Error wrapping up %s." msgstr "Fel vid ombrytning av %s." -#: sequencer.c:779 sequencer.c:913 +#: sequencer.c:791 sequencer.c:925 msgid "no cherry-pick or revert in progress" msgstr "ingen \"cherry-pick\" eller \"revert\" pÃ¥gÃ¥r" -#: sequencer.c:781 +#: sequencer.c:793 msgid "cannot resolve HEAD" msgstr "kan inte bestämma HEAD" -#: sequencer.c:783 +#: sequencer.c:795 msgid "cannot abort from a branch yet to be born" msgstr "kan inte avbryta frÃ¥n en gren som ännu inte är född" -#: sequencer.c:805 builtin/apply.c:3697 +#: sequencer.c:817 builtin/apply.c:4005 #, c-format msgid "cannot open %s: %s" msgstr "kan inte öppna %s: %s" -#: sequencer.c:808 +#: sequencer.c:820 #, c-format msgid "cannot read %s: %s" msgstr "kan inte läsa %s: %s" -#: sequencer.c:809 +#: sequencer.c:821 msgid "unexpected end of file" msgstr "oväntat filslut" -#: sequencer.c:815 +#: sequencer.c:827 #, c-format msgid "stored pre-cherry-pick HEAD file '%s' is corrupt" msgstr "sparad HEAD-fil frÃ¥n före \"cherry-pick\", \"%s\", är trasig" -#: sequencer.c:838 +#: sequencer.c:850 #, c-format msgid "Could not format %s." msgstr "Kunde inte formatera %s." -#: sequencer.c:1000 +#: sequencer.c:1012 msgid "Can't revert as initial commit" msgstr "Kan inte Ã¥ngra som första incheckning" -#: sequencer.c:1001 +#: sequencer.c:1013 msgid "Can't cherry-pick into empty head" msgstr "Kan inte göra \"cherry-pick\" i ett tomt huvud" -#: sha1_name.c:864 +#: sha1_name.c:1044 msgid "HEAD does not point to a branch" msgstr "HEAD pekar inte pÃ¥ en gren" -#: sha1_name.c:867 +#: sha1_name.c:1047 #, c-format msgid "No such branch: '%s'" msgstr "Okänd gren: \"%s\"" -#: sha1_name.c:869 +#: sha1_name.c:1049 #, c-format msgid "No upstream configured for branch '%s'" msgstr "Ingen standarduppström angiven för grenen \"%s\"" -#: sha1_name.c:872 +#: sha1_name.c:1052 #, c-format msgid "Upstream branch '%s' not stored as a remote-tracking branch" msgstr "Uppströmsgrenen \"%s\" är inte lagrad som en fjärrspÃ¥rande gren" -#: wrapper.c:413 +#: wrapper.c:408 +#, c-format +msgid "unable to access '%s': %s" +msgstr "kan inte komma Ã¥t \"%s\": %s" + +#: wrapper.c:426 #, c-format msgid "unable to look up current user in the passwd file: %s" msgstr "kan inte slÃ¥ upp aktuell användare i passwd-filen: %s" -#: wrapper.c:414 +#: wrapper.c:427 msgid "no such user" msgstr "okänd användare" -#: wt-status.c:135 +#: wt-status.c:140 msgid "Unmerged paths:" msgstr "Ej sammanslagna sökvägar:" -#: wt-status.c:141 wt-status.c:158 +#: wt-status.c:167 wt-status.c:194 #, c-format msgid " (use \"git reset %s <file>...\" to unstage)" msgstr " (använd \"git reset %s <fil>...\" för att ta bort frÃ¥n kö)" -#: wt-status.c:143 wt-status.c:160 +#: wt-status.c:169 wt-status.c:196 msgid " (use \"git rm --cached <file>...\" to unstage)" msgstr " (använd \"git rm --cached <fil>...\" för att ta bort frÃ¥n kö)" -#: wt-status.c:144 +#: wt-status.c:173 +msgid " (use \"git add <file>...\" to mark resolution)" +msgstr " (använd \"git add <fil>...\" för att ange lösning)" + +#: wt-status.c:175 wt-status.c:179 msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" msgstr " (använd \"git add/rm <fil>...\" som lämpligt för att ange lösning)" -#: wt-status.c:152 +#: wt-status.c:177 +msgid " (use \"git rm <file>...\" to mark resolution)" +msgstr " (använd \"git rm <fil>...\" för att ange lösning)" + +#: wt-status.c:188 msgid "Changes to be committed:" msgstr "Ändringar att checka in:" -#: wt-status.c:170 +#: wt-status.c:206 msgid "Changes not staged for commit:" msgstr "Ändringar ej i incheckningskön:" -#: wt-status.c:174 +#: wt-status.c:210 msgid " (use \"git add <file>...\" to update what will be committed)" msgstr "" " (använd \"git add <fil>...\" för att uppdatera vad som skall checkas in)" -#: wt-status.c:176 +#: wt-status.c:212 msgid " (use \"git add/rm <file>...\" to update what will be committed)" msgstr "" " (använd \"git add/rm <fil>...\" för att uppdatera vad som skall checkas in)" -#: wt-status.c:177 +#: wt-status.c:213 msgid "" " (use \"git checkout -- <file>...\" to discard changes in working directory)" msgstr "" " (använd \"git checkout -- <fil>...\" för att förkasta ändringar i " "arbetskatalogen)" -#: wt-status.c:179 +#: wt-status.c:215 msgid " (commit or discard the untracked or modified content in submodules)" msgstr "" " (checka in eller förkasta ospÃ¥rat eller ändrat innehÃ¥ll i undermoduler)" -# %s är ett verb ("Untracked"/"Ignored"); lägg till ett -e. -#: wt-status.c:188 -#, c-format -msgid "%s files:" -msgstr "%se filer:" - -#: wt-status.c:191 +#: wt-status.c:227 #, c-format msgid " (use \"git %s <file>...\" to include in what will be committed)" msgstr "" -" (använd \"git %s <fil>...\" för att ta med i vad som skall checkas in)" +" (använd \"git %s <fil>...\" för att ta med i det som skall checkas in)" -#: wt-status.c:208 +#: wt-status.c:244 msgid "bug" msgstr "programfel" -#: wt-status.c:213 +#: wt-status.c:249 msgid "both deleted:" msgstr "borttaget av bägge:" -#: wt-status.c:214 +#: wt-status.c:250 msgid "added by us:" msgstr "tillagt av oss:" -#: wt-status.c:215 +#: wt-status.c:251 msgid "deleted by them:" msgstr "borttaget av dem:" -#: wt-status.c:216 +#: wt-status.c:252 msgid "added by them:" msgstr "tillagt av dem:" -#: wt-status.c:217 +#: wt-status.c:253 msgid "deleted by us:" msgstr "borttaget av oss:" -#: wt-status.c:218 +#: wt-status.c:254 msgid "both added:" msgstr "tillagt av bägge:" -#: wt-status.c:219 +#: wt-status.c:255 msgid "both modified:" msgstr "ändrat av bägge:" -#: wt-status.c:249 +#: wt-status.c:285 msgid "new commits, " msgstr "nya incheckningar, " -#: wt-status.c:251 +#: wt-status.c:287 msgid "modified content, " msgstr "ändrat innehÃ¥ll, " -#: wt-status.c:253 +#: wt-status.c:289 msgid "untracked content, " msgstr "ospÃ¥rat innehÃ¥ll, " -#: wt-status.c:267 +#: wt-status.c:303 #, c-format msgid "new file: %s" msgstr "ny fil: %s" -#: wt-status.c:270 +#: wt-status.c:306 #, c-format msgid "copied: %s -> %s" msgstr "kopierad: %s -> %s" -#: wt-status.c:273 +#: wt-status.c:309 #, c-format msgid "deleted: %s" msgstr "borttagen: %s" -#: wt-status.c:276 +#: wt-status.c:312 #, c-format msgid "modified: %s" msgstr "ändrad: %s" -#: wt-status.c:279 +#: wt-status.c:315 #, c-format msgid "renamed: %s -> %s" msgstr "namnbyte: %s -> %s" -#: wt-status.c:282 +#: wt-status.c:318 #, c-format msgid "typechange: %s" msgstr "typbyte: %s" -#: wt-status.c:285 +#: wt-status.c:321 #, c-format msgid "unknown: %s" msgstr "okänd: %s" -#: wt-status.c:288 +#: wt-status.c:324 #, c-format msgid "unmerged: %s" msgstr "osammansl.: %s" -#: wt-status.c:291 +#: wt-status.c:327 #, c-format msgid "bug: unhandled diff status %c" msgstr "programfel: diff-status %c ej hanterad" -#: wt-status.c:737 +#: wt-status.c:785 +msgid "You have unmerged paths." +msgstr "Du har ej sammanslagna sökvägar." + +#: wt-status.c:788 wt-status.c:912 +msgid " (fix conflicts and run \"git commit\")" +msgstr " (rätta konflikter och kör \"git commit\")" + +#: wt-status.c:791 +msgid "All conflicts fixed but you are still merging." +msgstr "Alla konflikter har rättats men du är fortfarande i en sammanslagning." + +#: wt-status.c:794 +msgid " (use \"git commit\" to conclude merge)" +msgstr " (använd \"git commit\" för att slutföra sammanslagningen)" + +#: wt-status.c:804 +msgid "You are in the middle of an am session." +msgstr "Du är i mitten av en körning av \"git am\"." + +#: wt-status.c:807 +msgid "The current patch is empty." +msgstr "Aktuell patch är tom." + +#: wt-status.c:811 +msgid " (fix conflicts and then run \"git am --resolved\")" +msgstr " (rätta konflikter och kör sedan \"git am --resolved\")" + +#: wt-status.c:813 +msgid " (use \"git am --skip\" to skip this patch)" +msgstr " (använd \"git am --skip\" för att hoppa över patchen)" + +#: wt-status.c:815 +msgid " (use \"git am --abort\" to restore the original branch)" +msgstr " (använd \"git am --abort\" för att Ã¥terställa ursprungsgrenen)" + +#: wt-status.c:873 wt-status.c:883 +msgid "You are currently rebasing." +msgstr "Du hÃ¥ller pÃ¥ med en ombasering." + +#: wt-status.c:876 +msgid " (fix conflicts and then run \"git rebase --continue\")" +msgstr " (rätta konflikter och kör sedan \"git rebase --continue\")" + +#: wt-status.c:878 +msgid " (use \"git rebase --skip\" to skip this patch)" +msgstr " (använd \"git rebase --skip\" för att hoppa över patchen)" + +#: wt-status.c:880 +msgid " (use \"git rebase --abort\" to check out the original branch)" +msgstr " (använd \"git rebase --abort\" för att checka ut ursprungsgrenen)" + +#: wt-status.c:886 +msgid " (all conflicts fixed: run \"git rebase --continue\")" +msgstr " (alla konflikter rättade: kör \"git rebase --continue\")" + +#: wt-status.c:888 +msgid "You are currently splitting a commit during a rebase." +msgstr "Du hÃ¥ller pÃ¥ att dela upp en incheckning i en ombasering." + +#: wt-status.c:891 +msgid " (Once your working directory is clean, run \"git rebase --continue\")" +msgstr " (SÃ¥ fort din arbetskatalog är ren, kör \"git rebase --continue\")" + +#: wt-status.c:893 +msgid "You are currently editing a commit during a rebase." +msgstr "Du hÃ¥ller pÃ¥ att redigera en incheckning under en ombasering." + +#: wt-status.c:896 +msgid " (use \"git commit --amend\" to amend the current commit)" +msgstr "" +" (använd \"git commit --amend\" för att lägga till pÃ¥ aktuell incheckning)" + +#: wt-status.c:898 +msgid "" +" (use \"git rebase --continue\" once you are satisfied with your changes)" +msgstr " (använd \"git rebase --continue\" när du är nöjd med dina ändringar)" + +#: wt-status.c:908 +msgid "You are currently cherry-picking." +msgstr "Du hÃ¥ller pÃ¥ med en \"cherry-pick\"." + +#: wt-status.c:915 +msgid " (all conflicts fixed: run \"git commit\")" +msgstr " (alla konflikter har rättats: kör \"git commit\")" + +#: wt-status.c:924 +msgid "You are currently bisecting." +msgstr "Du hÃ¥ller pÃ¥ med en \"bisect\"." + +#: wt-status.c:927 +msgid " (use \"git bisect reset\" to get back to the original branch)" +msgstr "" +" (använd \"git bisect reset\" för att komma tillbaka till ursprungsgrenen)" + +#: wt-status.c:978 msgid "On branch " msgstr "PÃ¥ grenen " -#: wt-status.c:744 +#: wt-status.c:985 msgid "Not currently on any branch." msgstr "Inte pÃ¥ nÃ¥gon gren för närvarande." -#: wt-status.c:755 +#: wt-status.c:997 msgid "Initial commit" msgstr "Första incheckning" -#: wt-status.c:769 -msgid "Untracked" -msgstr "OspÃ¥rad" +#: wt-status.c:1011 +msgid "Untracked files" +msgstr "OspÃ¥rade filer" -#: wt-status.c:771 -msgid "Ignored" -msgstr "Ignorerad" +#: wt-status.c:1013 +msgid "Ignored files" +msgstr "Ignorerade filer" # %s är nästa sträng eller tom. -#: wt-status.c:773 +#: wt-status.c:1015 #, c-format msgid "Untracked files not listed%s" msgstr "OspÃ¥rade filer visas ej%s" -#: wt-status.c:775 +#: wt-status.c:1017 msgid " (use -u option to show untracked files)" msgstr " (använd flaggan -u för att visa ospÃ¥rade filer)" -#: wt-status.c:781 +#: wt-status.c:1023 msgid "No changes" msgstr "Inga ändringar" -#: wt-status.c:785 +#: wt-status.c:1028 #, c-format -msgid "no changes added to commit%s\n" -msgstr "inga ändringar att checka in%s\n" +msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n" +msgstr "" +"inga ändringar att checka in (använd \"git add\" och/eller \"git commit -a" +"\")\n" -#: wt-status.c:787 -msgid " (use \"git add\" and/or \"git commit -a\")" -msgstr " (använd \"git add\" och/eller \"git commit -a\")" +#: wt-status.c:1031 +#, c-format +msgid "no changes added to commit\n" +msgstr "inga ändringar att checka in\n" -#: wt-status.c:789 +#: wt-status.c:1034 #, c-format -msgid "nothing added to commit but untracked files present%s\n" -msgstr "inget köat för incheckning, men ospÃ¥rade filer finns%s\n" +msgid "" +"nothing added to commit but untracked files present (use \"git add\" to " +"track)\n" +msgstr "" +"inget köat för incheckning, men ospÃ¥rade filer finns (spÃ¥ra med \"git add" +"\")\n" -#: wt-status.c:791 -msgid " (use \"git add\" to track)" -msgstr " (använd \"git add\" för att spÃ¥ra)" +#: wt-status.c:1037 +#, c-format +msgid "nothing added to commit but untracked files present\n" +msgstr "inget köat för incheckning, men ospÃ¥rade filer finns\n" -#: wt-status.c:793 wt-status.c:796 wt-status.c:799 +#: wt-status.c:1040 #, c-format -msgid "nothing to commit%s\n" -msgstr "inget att checka in%s\n" +msgid "nothing to commit (create/copy files and use \"git add\" to track)\n" +msgstr "inget att checka in (skapa/kopiera filer och spÃ¥ra med \"git add\")\n" -#: wt-status.c:794 -msgid " (create/copy files and use \"git add\" to track)" -msgstr " (skapa/kopiera filer och använd \"git add\" för att spÃ¥ra)" +#: wt-status.c:1043 wt-status.c:1048 +#, c-format +msgid "nothing to commit\n" +msgstr "inget att checka in\n" -#: wt-status.c:797 -msgid " (use -u to show untracked files)" -msgstr " (använd -u för att visa ospÃ¥rade filer)" +#: wt-status.c:1046 +#, c-format +msgid "nothing to commit (use -u to show untracked files)\n" +msgstr "inget att checka in (använd -u för att visa ospÃ¥rade filer)\n" -#: wt-status.c:800 -msgid " (working directory clean)" -msgstr " (arbetskatalogen ren)" +#: wt-status.c:1050 +#, c-format +msgid "nothing to commit, working directory clean\n" +msgstr "inget att checka in, arbetskatalogen ren\n" -#: wt-status.c:908 +#: wt-status.c:1158 msgid "HEAD (no branch)" msgstr "HEAD (ingen gren)" -#: wt-status.c:914 +#: wt-status.c:1164 msgid "Initial commit on " msgstr "Första incheckning pÃ¥ " -#: wt-status.c:929 +#: wt-status.c:1179 msgid "behind " msgstr "efter " -#: wt-status.c:932 wt-status.c:935 +#: wt-status.c:1182 wt-status.c:1185 msgid "ahead " msgstr "före " -#: wt-status.c:937 +#: wt-status.c:1187 msgid ", behind " msgstr ", efter " +#: compat/precompose_utf8.c:58 builtin/clone.c:341 +#, c-format +msgid "failed to unlink '%s'" +msgstr "misslyckades ta bort länken \"%s\"" + +#: builtin/add.c:19 +msgid "git add [options] [--] <filepattern>..." +msgstr "git add [flaggor] [--] <filmönster>..." + #: builtin/add.c:62 #, c-format msgid "unexpected diff status %c" msgstr "diff-status %c förväntades inte" -#: builtin/add.c:67 builtin/commit.c:226 +#: builtin/add.c:67 builtin/commit.c:231 msgid "updating files failed" msgstr "misslyckades uppdatera filer" @@ -924,7 +1405,7 @@ msgstr "Sökvägen \"%s\" är i undermodulen \"%.*s\"" msgid "Unstaged changes after refreshing the index:" msgstr "OspÃ¥rade ändringar efter att ha uppdaterat indexet:" -#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186 +#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:275 #, c-format msgid "pathspec '%s' did not match any files" msgstr "sökvägsangivelsen \"%s\" motsvarade inte nÃ¥gra filer" @@ -961,110 +1442,162 @@ msgstr "Tom patch. Avbryter." msgid "Could not apply '%s'" msgstr "Kunde inte tillämpa \"%s\"" -#: builtin/add.c:312 +#: builtin/add.c:313 msgid "The following paths are ignored by one of your .gitignore files:\n" msgstr "Följande sökvägar ignoreras av en av dina .gitignore-filer:\n" -#: builtin/add.c:352 +#: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63 +#: builtin/prune-packed.c:76 builtin/push.c:388 builtin/remote.c:1253 +#: builtin/rm.c:206 +msgid "dry run" +msgstr "testkörning" + +#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1160 +#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1483 +#: builtin/mv.c:62 builtin/read-tree.c:112 +msgid "be verbose" +msgstr "var pratsam" + +#: builtin/add.c:322 +msgid "interactive picking" +msgstr "plocka interaktivt" + +#: builtin/add.c:323 builtin/checkout.c:1031 builtin/reset.c:248 +msgid "select hunks interactively" +msgstr "välj stycken interaktivt" + +#: builtin/add.c:324 +msgid "edit current diff and apply" +msgstr "redigera aktuell diff och applicera" + +#: builtin/add.c:325 +msgid "allow adding otherwise ignored files" +msgstr "tillÃ¥t lägga till annars ignorerade filer" + +#: builtin/add.c:326 +msgid "update tracked files" +msgstr "uppdatera spÃ¥rade filer" + +#: builtin/add.c:327 +msgid "record only the fact that the path will be added later" +msgstr "registrera endast att sökvägen kommer läggas till senare" + +#: builtin/add.c:328 +msgid "add changes from all tracked and untracked files" +msgstr "lägg till ändringar frÃ¥n alla spÃ¥rade och ospÃ¥rade filer" + +#: builtin/add.c:329 +msgid "don't add, only refresh the index" +msgstr "lägg inte till, uppdatera endast indexet" + +#: builtin/add.c:330 +msgid "just skip files which cannot be added because of errors" +msgstr "hoppa bara över filer som inte kan läggas till pÃ¥ grund av fel" + +#: builtin/add.c:331 +msgid "check if - even missing - files are ignored in dry run" +msgstr "se om - även saknade - filer ignoreras i testkörning" + +#: builtin/add.c:353 #, c-format msgid "Use -f if you really want to add them.\n" msgstr "Använd -f om du verkligen vill lägga till dem.\n" -#: builtin/add.c:353 +#: builtin/add.c:354 msgid "no files added" msgstr "inga filer har lagts till" -#: builtin/add.c:359 +#: builtin/add.c:360 msgid "adding files failed" msgstr "misslyckades lägga till filer" -#: builtin/add.c:391 +#: builtin/add.c:392 msgid "-A and -u are mutually incompatible" msgstr "-A och -u är ömsesidigt inkompatibla" -#: builtin/add.c:393 +#: builtin/add.c:394 msgid "Option --ignore-missing can only be used together with --dry-run" msgstr "Flaggan --ignore-missing kan endast användas tillsammans med --dry-run" -#: builtin/add.c:413 +#: builtin/add.c:414 #, c-format msgid "Nothing specified, nothing added.\n" msgstr "Inget angivet, inget tillagt.\n" -#: builtin/add.c:414 +#: builtin/add.c:415 #, c-format msgid "Maybe you wanted to say 'git add .'?\n" msgstr "Kanske menade du att skriva \"git add .\"?\n" -#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82 -#: builtin/rm.c:162 +#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:291 builtin/mv.c:82 +#: builtin/rm.c:235 msgid "index file corrupt" msgstr "indexfilen trasig" -#: builtin/add.c:476 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260 +#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:370 msgid "Unable to write new index file" msgstr "Kunde inte skriva ny indexfil" -#: builtin/apply.c:53 +#: builtin/apply.c:57 msgid "git apply [options] [<patch>...]" msgstr "git apply [flaggor] [<patch>...]" -#: builtin/apply.c:106 +#: builtin/apply.c:110 #, c-format msgid "unrecognized whitespace option '%s'" msgstr "okänt alternativ för whitespace: \"%s\"" -#: builtin/apply.c:121 +#: builtin/apply.c:125 #, c-format msgid "unrecognized whitespace ignore option '%s'" msgstr "okänt alternativ för ignore-whitespace: \"%s\"" -#: builtin/apply.c:815 +#: builtin/apply.c:823 #, c-format msgid "Cannot prepare timestamp regexp %s" msgstr "Kan inte förbereda reguljärt uttryck för tidsstämpeln %s" -#: builtin/apply.c:824 +#: builtin/apply.c:832 #, c-format msgid "regexec returned %d for input: %s" msgstr "regexec returnerade %d för indata: %s" -#: builtin/apply.c:905 +#: builtin/apply.c:913 #, c-format msgid "unable to find filename in patch at line %d" msgstr "kan inte hitta filnamn i patchen pÃ¥ rad %d" -#: builtin/apply.c:937 +#: builtin/apply.c:945 #, c-format msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" msgstr "git apply: dÃ¥lig git-diff - förväntade /dev/null, fick %s pÃ¥ rad %d" -#: builtin/apply.c:941 +#: builtin/apply.c:949 #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "git apply: dÃ¥lig git-diff - motsägande nytt filnamn pÃ¥ rad %d" -#: builtin/apply.c:942 +#: builtin/apply.c:950 #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "git apply: dÃ¥lig git-diff - motsägande gammalt filnamn pÃ¥ rad %d" -#: builtin/apply.c:949 +#: builtin/apply.c:957 #, c-format msgid "git apply: bad git-diff - expected /dev/null on line %d" msgstr "git apply: dÃ¥lig git-diff - förväntade /dev/null pÃ¥ rad %d" -#: builtin/apply.c:1394 +#: builtin/apply.c:1420 #, c-format msgid "recount: unexpected line: %.*s" msgstr "recount: förväntade rad: %.*s" -#: builtin/apply.c:1451 +#: builtin/apply.c:1477 #, c-format msgid "patch fragment without header at line %d: %.*s" msgstr "patch-fragment utan huvud pÃ¥ rad %d: %.*s" -#: builtin/apply.c:1468 +#: builtin/apply.c:1494 #, c-format msgid "" "git diff header lacks filename information when removing %d leading pathname " @@ -1080,82 +1613,82 @@ msgstr[1] "" "sökvägskomponenter\n" "tas bort (rad %d)" -#: builtin/apply.c:1628 +#: builtin/apply.c:1654 msgid "new file depends on old contents" msgstr "ny fil beror pÃ¥ gammalt innehÃ¥ll" -#: builtin/apply.c:1630 +#: builtin/apply.c:1656 msgid "deleted file still has contents" msgstr "borttagen fil har fortfarande innehÃ¥ll" -#: builtin/apply.c:1656 +#: builtin/apply.c:1682 #, c-format msgid "corrupt patch at line %d" msgstr "trasig patch pÃ¥ rad %d" -#: builtin/apply.c:1692 +#: builtin/apply.c:1718 #, c-format msgid "new file %s depends on old contents" msgstr "nya filen %s beror pÃ¥ gammalt innehÃ¥ll" -#: builtin/apply.c:1694 +#: builtin/apply.c:1720 #, c-format msgid "deleted file %s still has contents" msgstr "borttagna filen %s har fortfarande innehÃ¥ll" -#: builtin/apply.c:1697 +#: builtin/apply.c:1723 #, c-format msgid "** warning: file %s becomes empty but is not deleted" msgstr "** varning: filen %s blir tom men har inte tagits bort" -#: builtin/apply.c:1843 +#: builtin/apply.c:1869 #, c-format msgid "corrupt binary patch at line %d: %.*s" msgstr "trasig binärpatch pÃ¥ rad %d: %.*s" #. there has to be one hunk (forward hunk) -#: builtin/apply.c:1872 +#: builtin/apply.c:1898 #, c-format msgid "unrecognized binary patch at line %d" msgstr "binärpatchen pÃ¥ rad %d känns inte igen" -#: builtin/apply.c:1958 +#: builtin/apply.c:1984 #, c-format msgid "patch with only garbage at line %d" msgstr "patch med bara skräp pÃ¥ rad %d" -#: builtin/apply.c:2048 +#: builtin/apply.c:2074 #, c-format msgid "unable to read symlink %s" msgstr "kunde inte läsa symboliska länken %s" -#: builtin/apply.c:2052 +#: builtin/apply.c:2078 #, c-format msgid "unable to open or read %s" msgstr "kunde inte öppna eller läsa %s" -#: builtin/apply.c:2123 +#: builtin/apply.c:2149 msgid "oops" msgstr "hoppsan" -#: builtin/apply.c:2645 +#: builtin/apply.c:2671 #, c-format msgid "invalid start of line: '%c'" msgstr "felaktig inledning pÃ¥ rad: \"%c\"" -#: builtin/apply.c:2763 +#: builtin/apply.c:2789 #, c-format msgid "Hunk #%d succeeded at %d (offset %d line)." msgid_plural "Hunk #%d succeeded at %d (offset %d lines)." msgstr[0] "Stycke %d lyckades pÃ¥ %d (offset %d rad)." msgstr[1] "Stycke %d lyckades pÃ¥ %d (offset %d rader)." -#: builtin/apply.c:2775 +#: builtin/apply.c:2801 #, c-format msgid "Context reduced to (%ld/%ld) to apply fragment at %d" msgstr "Sammanhang reducerat till (%ld/%ld) för att tillämpa fragment vid %d" -#: builtin/apply.c:2781 +#: builtin/apply.c:2807 #, c-format msgid "" "while searching for:\n" @@ -1164,313 +1697,318 @@ msgstr "" "vid sökning efter:\n" "%.*s" -#: builtin/apply.c:2800 +#: builtin/apply.c:2826 #, c-format msgid "missing binary patch data for '%s'" msgstr "saknar binära patchdata för \"%s\"" -#: builtin/apply.c:2903 +#: builtin/apply.c:2929 #, c-format msgid "binary patch does not apply to '%s'" msgstr "binärpatchen kan inte tillämpas pÃ¥ \"%s\"" -#: builtin/apply.c:2909 +#: builtin/apply.c:2935 #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" msgstr "binärpatchen pÃ¥ \"%s\" ger felaktigt resultat (förväntade %s, fick %s)" -#: builtin/apply.c:2930 +#: builtin/apply.c:2956 #, c-format msgid "patch failed: %s:%ld" msgstr "patch misslyckades: %s:%ld" -#: builtin/apply.c:3045 +#: builtin/apply.c:3078 #, c-format -msgid "patch %s has been renamed/deleted" -msgstr "patchen %s har ändrat namn/tagits bort" +msgid "cannot checkout %s" +msgstr "kan inte checka ut %s" -#: builtin/apply.c:3052 builtin/apply.c:3069 +#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176 #, c-format msgid "read of %s failed" msgstr "misslyckades läsa %s" -#: builtin/apply.c:3084 -msgid "removal patch leaves file contents" -msgstr "patch för borttagning lämnar kvar filinnehÃ¥ll" - -#: builtin/apply.c:3105 +#: builtin/apply.c:3156 builtin/apply.c:3378 #, c-format -msgid "%s: already exists in working directory" -msgstr "%s: finns redan i arbetskatalogen" +msgid "path %s has been renamed/deleted" +msgstr "sökvägen %s har ändrat namn/tagits bort" -#: builtin/apply.c:3143 +#: builtin/apply.c:3237 builtin/apply.c:3392 #, c-format -msgid "%s: has been deleted/renamed" -msgstr "%s: har tagits bort/ändrat namn" +msgid "%s: does not exist in index" +msgstr "%s: finns inte i indexet" -#: builtin/apply.c:3148 builtin/apply.c:3179 +#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: builtin/apply.c:3159 -#, c-format -msgid "%s: does not exist in index" -msgstr "%s: finns inte i indexet" - -#: builtin/apply.c:3173 +#: builtin/apply.c:3246 builtin/apply.c:3400 #, c-format msgid "%s: does not match index" msgstr "%s: motsvarar inte indexet" -#: builtin/apply.c:3190 +#: builtin/apply.c:3348 +msgid "removal patch leaves file contents" +msgstr "patch för borttagning lämnar kvar filinnehÃ¥ll" + +#: builtin/apply.c:3417 #, c-format msgid "%s: wrong type" msgstr "%s: fel typ" -#: builtin/apply.c:3192 +#: builtin/apply.c:3419 #, c-format msgid "%s has type %o, expected %o" msgstr "%s har typen %o, förväntade %o" -#: builtin/apply.c:3247 +#: builtin/apply.c:3520 #, c-format msgid "%s: already exists in index" msgstr "%s: finns redan i indexet" -#: builtin/apply.c:3267 +#: builtin/apply.c:3523 +#, c-format +msgid "%s: already exists in working directory" +msgstr "%s: finns redan i arbetskatalogen" + +#: builtin/apply.c:3543 #, c-format msgid "new mode (%o) of %s does not match old mode (%o)" msgstr "nytt läge (%o) för %s motsvarar inte gammalt läge (%o)" -#: builtin/apply.c:3272 +#: builtin/apply.c:3548 #, c-format msgid "new mode (%o) of %s does not match old mode (%o) of %s" msgstr "nytt läge (%o) för %s motsvarar inte gammalt läge (%o) för %s" -#: builtin/apply.c:3280 +#: builtin/apply.c:3556 #, c-format msgid "%s: patch does not apply" msgstr "%s: patchen kan inte tillämpas" -#: builtin/apply.c:3293 +#: builtin/apply.c:3569 #, c-format msgid "Checking patch %s..." msgstr "Kontrollerar patchen %s..." -#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158 +#: builtin/apply.c:3624 builtin/checkout.c:215 builtin/reset.c:158 #, c-format msgid "make_cache_entry failed for path '%s'" msgstr "make_cache_entry misslyckades för sökvägen \"%s\"" -#: builtin/apply.c:3491 +#: builtin/apply.c:3767 #, c-format msgid "unable to remove %s from index" msgstr "kan inte ta bort %s frÃ¥n indexet" -#: builtin/apply.c:3518 +#: builtin/apply.c:3795 #, c-format msgid "corrupt patch for subproject %s" msgstr "trasig patch för underprojektet %s" -#: builtin/apply.c:3522 +#: builtin/apply.c:3799 #, c-format msgid "unable to stat newly created file '%s'" msgstr "kan inte ta status pÃ¥ nyligen skapade filen \"%s\"" -#: builtin/apply.c:3527 +#: builtin/apply.c:3804 #, c-format msgid "unable to create backing store for newly created file %s" msgstr "kan inte skapa säkerhetsminne för nyligen skapade filen %s" -#: builtin/apply.c:3530 +#: builtin/apply.c:3807 builtin/apply.c:3915 #, c-format msgid "unable to add cache entry for %s" msgstr "kan inte lägga till cachepost för %s" -#: builtin/apply.c:3563 +#: builtin/apply.c:3840 #, c-format msgid "closing file '%s'" msgstr "stänger filen \"%s\"" -#: builtin/apply.c:3612 +#: builtin/apply.c:3889 #, c-format msgid "unable to write file '%s' mode %o" msgstr "kan inte skriva filen \"%s\" läge %o" -#: builtin/apply.c:3668 +#: builtin/apply.c:3976 #, c-format msgid "Applied patch %s cleanly." msgstr "Tillämpade patchen %s rent." -#: builtin/apply.c:3676 +#: builtin/apply.c:3984 msgid "internal error" msgstr "internt fel" #. Say this even without --verbose -#: builtin/apply.c:3679 +#: builtin/apply.c:3987 #, c-format msgid "Applying patch %%s with %d reject..." msgid_plural "Applying patch %%s with %d rejects..." msgstr[0] "Tillämpade patchen %%s med %d refuserad..." msgstr[1] "Tillämpade patchen %%s med %d refuserade..." -#: builtin/apply.c:3689 +#: builtin/apply.c:3997 #, c-format msgid "truncating .rej filename to %.*s.rej" msgstr "trunkerar .rej-filnamnet till %.*s.rej" -#: builtin/apply.c:3710 +#: builtin/apply.c:4018 #, c-format msgid "Hunk #%d applied cleanly." msgstr "Stycke %d tillämpades rent." -#: builtin/apply.c:3713 +#: builtin/apply.c:4021 #, c-format msgid "Rejected hunk #%d." msgstr "Refuserar stycke %d." -#: builtin/apply.c:3844 +#: builtin/apply.c:4171 msgid "unrecognized input" msgstr "indata känns inte igen" -#: builtin/apply.c:3855 +#: builtin/apply.c:4182 msgid "unable to read index file" msgstr "kan inte läsa indexfilen" -#: builtin/apply.c:3970 builtin/apply.c:3973 +#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91 +#: builtin/fetch.c:63 msgid "path" msgstr "sökväg" -#: builtin/apply.c:3971 +#: builtin/apply.c:4302 msgid "don't apply changes matching the given path" msgstr "tillämpa inte ändringar som motsvarar given sökväg" -#: builtin/apply.c:3974 +#: builtin/apply.c:4305 msgid "apply changes matching the given path" msgstr "tillämpa ändringar som motsvarar given sökväg" -#: builtin/apply.c:3976 +#: builtin/apply.c:4307 msgid "num" msgstr "antal" -#: builtin/apply.c:3977 +#: builtin/apply.c:4308 msgid "remove <num> leading slashes from traditional diff paths" msgstr "ta bort <antal> inledande snedstreck frÃ¥n traditionella diff-sökvägar" -#: builtin/apply.c:3980 +#: builtin/apply.c:4311 msgid "ignore additions made by the patch" msgstr "ignorera tillägg gjorda av patchen" -#: builtin/apply.c:3982 +#: builtin/apply.c:4313 msgid "instead of applying the patch, output diffstat for the input" msgstr "istället för att tillämpa patchen, skriv ut diffstat för indata" -#: builtin/apply.c:3986 -msgid "shows number of added and deleted lines in decimal notation" -msgstr "visar antal tillagda och borttagna rader decimalt" +#: builtin/apply.c:4317 +msgid "show number of added and deleted lines in decimal notation" +msgstr "visa antal tillagda och borttagna rader decimalt" -#: builtin/apply.c:3988 +#: builtin/apply.c:4319 msgid "instead of applying the patch, output a summary for the input" msgstr "istället för att tillämpa patchen, skriv ut en summering av indata" -#: builtin/apply.c:3990 +#: builtin/apply.c:4321 msgid "instead of applying the patch, see if the patch is applicable" msgstr "istället för att tillämpa patchen, se om patchen kan tillämpas" -#: builtin/apply.c:3992 +#: builtin/apply.c:4323 msgid "make sure the patch is applicable to the current index" msgstr "se till att patchen kan tillämpas pÃ¥ aktuellt index" -#: builtin/apply.c:3994 +#: builtin/apply.c:4325 msgid "apply a patch without touching the working tree" msgstr "tillämpa en patch utan att röra arbetskatalogen" -#: builtin/apply.c:3996 +#: builtin/apply.c:4327 msgid "also apply the patch (use with --stat/--summary/--check)" msgstr "tillämpa ocksÃ¥ patchen (använd med --stat/--summary/--check)" -#: builtin/apply.c:3998 +#: builtin/apply.c:4329 +msgid "attempt three-way merge if a patch does not apply" +msgstr "försök en trevägssammanslagning om patchen inte kan tillämpas" + +#: builtin/apply.c:4331 msgid "build a temporary index based on embedded index information" msgstr "bygg ett temporärt index baserat pÃ¥ inbyggd indexinformation" -#: builtin/apply.c:4000 +#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460 msgid "paths are separated with NUL character" msgstr "sökvägar avdelas med NUL-tecken" -#: builtin/apply.c:4003 +#: builtin/apply.c:4336 msgid "ensure at least <n> lines of context match" msgstr "se till att Ã¥tminstone <n> rader sammanhang är lika" -#: builtin/apply.c:4004 +#: builtin/apply.c:4337 msgid "action" msgstr "Ã¥tgärd" -#: builtin/apply.c:4005 +#: builtin/apply.c:4338 msgid "detect new or modified lines that have whitespace errors" msgstr "detektera nya eller ändrade rader som har fel i blanktecken" -#: builtin/apply.c:4008 builtin/apply.c:4011 +#: builtin/apply.c:4341 builtin/apply.c:4344 msgid "ignore changes in whitespace when finding context" msgstr "ignorera ändringar i blanktecken för sammanhang" -#: builtin/apply.c:4014 +#: builtin/apply.c:4347 msgid "apply the patch in reverse" msgstr "tillämpa patchen baklänges" -#: builtin/apply.c:4016 +#: builtin/apply.c:4349 msgid "don't expect at least one line of context" msgstr "förvänta inte minst en rad sammanhang" -#: builtin/apply.c:4018 +#: builtin/apply.c:4351 msgid "leave the rejected hunks in corresponding *.rej files" msgstr "lämna refuserade stycken i motsvarande *.rej-filer" -#: builtin/apply.c:4020 +#: builtin/apply.c:4353 msgid "allow overlapping hunks" msgstr "tillÃ¥t överlappande stycken" -#: builtin/apply.c:4021 -msgid "be verbose" -msgstr "var pratsam" - -#: builtin/apply.c:4023 +#: builtin/apply.c:4356 msgid "tolerate incorrectly detected missing new-line at the end of file" msgstr "tolerera felaktigt detekterade saknade nyradstecken vid filslut" -#: builtin/apply.c:4026 +#: builtin/apply.c:4359 msgid "do not trust the line counts in the hunk headers" msgstr "lite inte pÃ¥ antalet linjer i styckehuvuden" -#: builtin/apply.c:4028 +#: builtin/apply.c:4361 msgid "root" msgstr "rot" -#: builtin/apply.c:4029 +#: builtin/apply.c:4362 msgid "prepend <root> to all filenames" msgstr "lägg till <rot> i alla filnamn" -#: builtin/apply.c:4050 +#: builtin/apply.c:4384 +msgid "--3way outside a repository" +msgstr "--3way utanför arkiv" + +#: builtin/apply.c:4392 msgid "--index outside a repository" msgstr "--index utanför arkiv" -#: builtin/apply.c:4053 +#: builtin/apply.c:4395 msgid "--cached outside a repository" msgstr "--cached utanför arkiv" -#: builtin/apply.c:4069 +#: builtin/apply.c:4411 #, c-format msgid "can't open patch '%s'" msgstr "kan inte öppna patchen \"%s\"" -#: builtin/apply.c:4083 +#: builtin/apply.c:4425 #, c-format msgid "squelched %d whitespace error" msgid_plural "squelched %d whitespace errors" msgstr[0] "undertryckte %d fel i blanksteg" msgstr[1] "undertryckte %d fel i blanksteg" -#: builtin/apply.c:4089 builtin/apply.c:4099 +#: builtin/apply.c:4431 builtin/apply.c:4441 #, c-format msgid "%d line adds whitespace errors." msgid_plural "%d lines add whitespace errors." @@ -1512,7 +2050,135 @@ msgstr "git archive: protokollfel" msgid "git archive: expected a flush" msgstr "git archive: förväntade en tömning (flush)" -#: builtin/branch.c:144 +#: builtin/bisect--helper.c:7 +msgid "git bisect--helper --next-all [--no-checkout]" +msgstr "git bisect--helper --next-all [--no-checkout]" + +#: builtin/bisect--helper.c:17 +msgid "perform 'git bisect next'" +msgstr "utför 'git bisect next'" + +#: builtin/bisect--helper.c:19 +msgid "update BISECT_HEAD instead of checking out the current commit" +msgstr "uppdatera BISECT_HEAD istället för att checka ut aktuell incheckning" + +#: builtin/blame.c:25 +msgid "git blame [options] [rev-opts] [rev] [--] file" +msgstr "git blame [flaggor] [rev-flaggor] [rev] [--] fil" + +#: builtin/blame.c:30 builtin/shortlog.c:15 +msgid "[rev-opts] are documented in git-rev-list(1)" +msgstr "[rev-flaggor] dokumenteras i git-rev-list(1)" + +#: builtin/blame.c:2374 +msgid "Show blame entries as we find them, incrementally" +msgstr "Visa klandringsposter när vi hittar dem, interaktivt" + +#: builtin/blame.c:2375 +msgid "Show blank SHA-1 for boundary commits (Default: off)" +msgstr "Visa blank SHA-1 för gränsincheckningar (Standard: av)" + +#: builtin/blame.c:2376 +msgid "Do not treat root commits as boundaries (Default: off)" +msgstr "Behandla inte rotincheckningar som gränser (Standard: av)" + +#: builtin/blame.c:2377 +msgid "Show work cost statistics" +msgstr "Visa statistik över arbetskostnad" + +#: builtin/blame.c:2378 +msgid "Show output score for blame entries" +msgstr "Visa utdatapoäng för klandringsposter" + +#: builtin/blame.c:2379 +msgid "Show original filename (Default: auto)" +msgstr "Visa originalfilnamn (Standard: auto)" + +#: builtin/blame.c:2380 +msgid "Show original linenumber (Default: off)" +msgstr "Visa ursprungligt radnummer (Standard: av)" + +#: builtin/blame.c:2381 +msgid "Show in a format designed for machine consumption" +msgstr "Visa i ett format avsett för maskinkonsumtion" + +#: builtin/blame.c:2382 +msgid "Show porcelain format with per-line commit information" +msgstr "Visa porslinsformat med per-rad-incheckningsinformation" + +#: builtin/blame.c:2383 +msgid "Use the same output mode as git-annotate (Default: off)" +msgstr "Använd samma utdataläge som git-annotate (Standard: av)" + +#: builtin/blame.c:2384 +msgid "Show raw timestamp (Default: off)" +msgstr "Visa rÃ¥ tidsstämpel (Standard: av)" + +#: builtin/blame.c:2385 +msgid "Show long commit SHA1 (Default: off)" +msgstr "Visa lÃ¥ng inchecknings-SHA1 (Standard: av)" + +#: builtin/blame.c:2386 +msgid "Suppress author name and timestamp (Default: off)" +msgstr "Undertryck författarnamn och tidsstämpel (Standard: av)" + +#: builtin/blame.c:2387 +msgid "Show author email instead of name (Default: off)" +msgstr "Visa författarens e-post istället för namn (Standard: av)" + +#: builtin/blame.c:2388 +msgid "Ignore whitespace differences" +msgstr "Ignorera ändringar i blanksteg" + +#: builtin/blame.c:2389 +msgid "Spend extra cycles to find better match" +msgstr "Slösa extra cykler med att hitta bättre träff" + +#: builtin/blame.c:2390 +msgid "Use revisions from <file> instead of calling git-rev-list" +msgstr "Använd revisioner frÃ¥n <fil> istället för att anropa git-rev-list" + +#: builtin/blame.c:2391 +msgid "Use <file>'s contents as the final image" +msgstr "Använd <fil>s innehÃ¥ll som slutgiltig bild" + +#: builtin/blame.c:2392 builtin/blame.c:2393 +msgid "score" +msgstr "poäng" + +#: builtin/blame.c:2392 +msgid "Find line copies within and across files" +msgstr "Hitta kopierade rader inuti och mellan filer" + +#: builtin/blame.c:2393 +msgid "Find line movements within and across files" +msgstr "Hitta flyttade rader inuti och mellan filer" + +#: builtin/blame.c:2394 +msgid "n,m" +msgstr "n,m" + +#: builtin/blame.c:2394 +msgid "Process only line range n,m, counting from 1" +msgstr "Behandla endast radintervallet n,m, med början pÃ¥ 1" + +#: builtin/branch.c:23 +msgid "git branch [options] [-r | -a] [--merged | --no-merged]" +msgstr "git branch [flaggor] [-r | -a] [--merged | --no-merged]" + +#: builtin/branch.c:24 +msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]" +msgstr "git branch [flaggor] [-l] [-f] <grennamn> [<startpunkt>]" + +#: builtin/branch.c:25 +msgid "git branch [options] [-r] (-d | -D) <branchname>..." +msgstr "git branch [flaggor] [-r] (-d | -D) <grennamn>..." + +#: builtin/branch.c:26 +msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>" +msgstr "git branch [flaggor] (-m | -M) [<gammal_gren>] <ny_gren>" + +#: builtin/branch.c:145 #, c-format msgid "" "deleting branch '%s' that has been merged to\n" @@ -1521,7 +2187,7 @@ msgstr "" "tar bort grenen \"%s\" som har slagits ihop med\n" " \"%s\", men ännu inte slagits ihop med HEAD." -#: builtin/branch.c:148 +#: builtin/branch.c:149 #, c-format msgid "" "not deleting branch '%s' that is not yet merged to\n" @@ -1530,166 +2196,296 @@ msgstr "" "tar inte bort grenen \"%s\" som inte har slagits ihop med\n" " \"%s\", trots att den har slagits ihop med HEAD." +#: builtin/branch.c:163 +#, c-format +msgid "Couldn't look up commit object for '%s'" +msgstr "Kunde inte slÃ¥ upp incheckningsobjekt för \"%s\"" + +#: builtin/branch.c:167 +#, c-format +msgid "" +"The branch '%s' is not fully merged.\n" +"If you are sure you want to delete it, run 'git branch -D %s'." +msgstr "" +"Grenen \"%s\" har inte slagits samman i sin helhet.\n" +"Om du är säker pÃ¥ att du vill ta bort den, kör \"git branch -D %s\"." + #: builtin/branch.c:180 +msgid "Update of config-file failed" +msgstr "Misslyckades uppdatera konfigurationsfil" + +#: builtin/branch.c:208 msgid "cannot use -a with -d" msgstr "kan inte ange -a med -d" -#: builtin/branch.c:186 +#: builtin/branch.c:214 msgid "Couldn't look up commit object for HEAD" msgstr "Kunde inte slÃ¥ upp incheckningsobjekt för HEAD" -#: builtin/branch.c:191 +#: builtin/branch.c:222 #, c-format msgid "Cannot delete the branch '%s' which you are currently on." msgstr "Kan inte ta bort grenen \"%s\" som du befinner dig pÃ¥ för närvarande." -#: builtin/branch.c:202 +#: builtin/branch.c:235 #, c-format msgid "remote branch '%s' not found." msgstr "fjärrgrenen \"%s\" hittades inte." -#: builtin/branch.c:203 +#: builtin/branch.c:236 #, c-format msgid "branch '%s' not found." msgstr "grenen \"%s\" hittades inte." -#: builtin/branch.c:210 -#, c-format -msgid "Couldn't look up commit object for '%s'" -msgstr "Kunde inte slÃ¥ upp incheckningsobjekt för \"%s\"" - -#: builtin/branch.c:216 -#, c-format -msgid "" -"The branch '%s' is not fully merged.\n" -"If you are sure you want to delete it, run 'git branch -D %s'." -msgstr "" -"Grenen \"%s\" har inte slagits samman i sin helhet.\n" -"Om du är säker pÃ¥ att du vill ta bort den, kör \"git branch -D %s\"." - -#: builtin/branch.c:225 +#: builtin/branch.c:250 #, c-format msgid "Error deleting remote branch '%s'" msgstr "Fel vid borttagning av fjärrgrenen \"%s\"" -#: builtin/branch.c:226 +#: builtin/branch.c:251 #, c-format msgid "Error deleting branch '%s'" msgstr "Fel vid borttagning av grenen \"%s\"" -#: builtin/branch.c:233 +#: builtin/branch.c:258 #, c-format msgid "Deleted remote branch %s (was %s).\n" msgstr "Tog bort fjärrgrenen %s (var %s).\n" -#: builtin/branch.c:234 +#: builtin/branch.c:259 #, c-format msgid "Deleted branch %s (was %s).\n" msgstr "Tog bort grenen %s (var %s).\n" -#: builtin/branch.c:239 -msgid "Update of config-file failed" -msgstr "Misslyckades uppdatera konfigurationsfil" - -#: builtin/branch.c:337 +#: builtin/branch.c:361 #, c-format msgid "branch '%s' does not point at a commit" msgstr "grenen \"%s\" pekar inte pÃ¥ en incheckning" -#: builtin/branch.c:409 +#: builtin/branch.c:433 #, c-format msgid "[%s: behind %d]" msgstr "[%s: bakom %d] " -#: builtin/branch.c:411 +#: builtin/branch.c:435 #, c-format msgid "[behind %d]" msgstr "[bakom %d] " -#: builtin/branch.c:415 +#: builtin/branch.c:439 #, c-format msgid "[%s: ahead %d]" msgstr "[%s: före %d] " -#: builtin/branch.c:417 +#: builtin/branch.c:441 #, c-format msgid "[ahead %d]" msgstr "[före %d] " -#: builtin/branch.c:420 +#: builtin/branch.c:444 #, c-format msgid "[%s: ahead %d, behind %d]" msgstr "[%s: före %d, bakom %d] " -#: builtin/branch.c:423 +#: builtin/branch.c:447 #, c-format msgid "[ahead %d, behind %d]" msgstr "[före %d, bakom %d] " -#: builtin/branch.c:535 +#: builtin/branch.c:560 msgid "(no branch)" msgstr "(ingen gren)" -#: builtin/branch.c:600 +#: builtin/branch.c:625 msgid "some refs could not be read" msgstr "vissa referenser kunde inte läsas" -#: builtin/branch.c:613 +#: builtin/branch.c:638 msgid "cannot rename the current branch while not on any." msgstr "" "kunde inte byta namn pÃ¥ aktuell gren när du inte befinner dig pÃ¥ nÃ¥gon." -#: builtin/branch.c:623 +#: builtin/branch.c:648 #, c-format msgid "Invalid branch name: '%s'" msgstr "Felaktigt namn pÃ¥ gren: \"%s\"" -#: builtin/branch.c:638 +#: builtin/branch.c:663 msgid "Branch rename failed" msgstr "Misslyckades byta namn pÃ¥ gren" -#: builtin/branch.c:642 +#: builtin/branch.c:667 #, c-format msgid "Renamed a misnamed branch '%s' away" msgstr "Bytte bort namn pÃ¥ en felaktigt namngiven gren \"%s\"" -#: builtin/branch.c:646 +#: builtin/branch.c:671 #, c-format msgid "Branch renamed to %s, but HEAD is not updated!" msgstr "Grenen namnbytt till %s, men HEAD har inte uppdaterats!" -#: builtin/branch.c:653 +#: builtin/branch.c:678 msgid "Branch is renamed, but update of config-file failed" msgstr "Grenen namnbytt, men misslyckades uppdatera konfigurationsfilen" -#: builtin/branch.c:668 +#: builtin/branch.c:693 #, c-format msgid "malformed object name %s" msgstr "felformat objektnamn %s" -#: builtin/branch.c:692 +#: builtin/branch.c:717 #, c-format msgid "could not write branch description template: %s" msgstr "kunde inte skriva grenbeskrivningsmall: %s" -#: builtin/branch.c:783 +#: builtin/branch.c:747 +msgid "Generic options" +msgstr "Allmänna flaggor" + +#: builtin/branch.c:749 +msgid "show hash and subject, give twice for upstream branch" +msgstr "visa hash och ärenderad, ange tvÃ¥ gÃ¥nger för uppströmsgren" + +#: builtin/branch.c:750 +msgid "suppress informational messages" +msgstr "undertryck informationsmeddelanden" + +#: builtin/branch.c:751 +msgid "set up tracking mode (see git-pull(1))" +msgstr "ställ in spÃ¥rningsläge (se git-pull(1))" + +#: builtin/branch.c:753 +msgid "change upstream info" +msgstr "ändra uppströmsinformation" + +#: builtin/branch.c:757 +msgid "use colored output" +msgstr "använd färgad utdata" + +#: builtin/branch.c:758 +msgid "act on remote-tracking branches" +msgstr "arbeta pÃ¥ fjärrspÃ¥rande grenar" + +#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788 +#: builtin/branch.c:794 builtin/commit.c:1376 builtin/commit.c:1377 +#: builtin/commit.c:1378 builtin/commit.c:1379 builtin/tag.c:470 +msgid "commit" +msgstr "incheckning" + +#: builtin/branch.c:762 builtin/branch.c:768 +msgid "print only branches that contain the commit" +msgstr "visa endast grenar som innehÃ¥ller incheckningen" + +#: builtin/branch.c:774 +msgid "Specific git-branch actions:" +msgstr "Specifika git-branch-Ã¥tgärder:" + +#: builtin/branch.c:775 +msgid "list both remote-tracking and local branches" +msgstr "visa bÃ¥de fjärrspÃ¥rande och lokala grenar" + +#: builtin/branch.c:777 +msgid "delete fully merged branch" +msgstr "ta bort helt sammanslagen gren" + +#: builtin/branch.c:778 +msgid "delete branch (even if not merged)" +msgstr "ta bort gren (även om inte helt sammanslagen)" + +#: builtin/branch.c:779 +msgid "move/rename a branch and its reflog" +msgstr "flytta/ta bort en gren och dess reflogg" + +#: builtin/branch.c:780 +msgid "move/rename a branch, even if target exists" +msgstr "flytta/ta bort en gren, även om mÃ¥let finns" + +#: builtin/branch.c:781 +msgid "list branch names" +msgstr "lista namn pÃ¥ grenar" + +#: builtin/branch.c:782 +msgid "create the branch's reflog" +msgstr "skapa grenens reflogg" + +#: builtin/branch.c:784 +msgid "edit the description for the branch" +msgstr "redigera beskrivning för grenen" + +#: builtin/branch.c:785 +msgid "force creation (when already exists)" +msgstr "tvinga skapande (när den redan finns)" + +#: builtin/branch.c:788 +msgid "print only not merged branches" +msgstr "visa endast ej sammanslagna grenar" + +#: builtin/branch.c:794 +msgid "print only merged branches" +msgstr "visa endast sammanslagna grenar" + +#: builtin/branch.c:798 +msgid "list branches in columns" +msgstr "visa grenar i spalter" + +#: builtin/branch.c:811 msgid "Failed to resolve HEAD as a valid ref." msgstr "Misslyckades slÃ¥ upp HEAD som giltig referens" -#: builtin/branch.c:788 builtin/clone.c:558 +#: builtin/branch.c:816 builtin/clone.c:561 msgid "HEAD not found below refs/heads!" msgstr "HEAD hittades inte under refs/heads!" -#: builtin/branch.c:808 +#: builtin/branch.c:836 msgid "--column and --verbose are incompatible" msgstr "--column och --verbose är inkompatibla" -#: builtin/branch.c:857 +#: builtin/branch.c:887 +#, c-format +msgid "branch '%s' does not exist" +msgstr "grenen \"%s\" finns inte" + +#: builtin/branch.c:899 +#, c-format +msgid "Branch '%s' has no upstream information" +msgstr "Grenen \"%s\" har ingen uppströmsinformation" + +#: builtin/branch.c:914 msgid "-a and -r options to 'git branch' do not make sense with a branch name" msgstr "" "flaggorna -a och -r pÃ¥ \"git branch\" kan inte anges tillsammans med ett " "grennamn" +#: builtin/branch.c:917 +#, c-format +msgid "" +"The --set-upstream flag is deprecated and will be removed. Consider using --" +"track or --set-upstream-to\n" +msgstr "" +"Flaggan --set-upstream rekommenderas ej och kommer tas bort. Använd --track " +"eller --set-upstream-to\n" + +#: builtin/branch.c:934 +#, c-format +msgid "" +"\n" +"If you wanted to make '%s' track '%s', do this:\n" +"\n" +msgstr "" +"\n" +"Om du vill göra sÃ¥ att \"%s\" spÃ¥rar \"%s\" gör du sÃ¥ här:\n" +"\n" + +#: builtin/branch.c:935 +#, c-format +msgid " git branch -d %s\n" +msgstr " git branch -d %s\n" + +#: builtin/branch.c:936 +#, c-format +msgid " git branch --set-upstream-to %s\n" +msgstr " git branch --set-upstream-to %s\n" + #: builtin/bundle.c:47 #, c-format msgid "%s is okay\n" @@ -1703,99 +2499,222 @@ msgstr "Behöver ett arkiv för att skapa ett paket (bundle)." msgid "Need a repository to unbundle." msgstr "Behöver ett arkiv för att packa upp ett paket (bundle)." -#: builtin/checkout.c:113 builtin/checkout.c:146 +#: builtin/cat-file.c:247 +msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>" +msgstr "git cat-file (-t|-s|-e|-p|<typ>|--textconv) <objekt>" + +#: builtin/cat-file.c:248 +msgid "git cat-file (--batch|--batch-check) < <list_of_objects>" +msgstr "git cat-file (--batch|--batch-check) < <objektlista>" + +#: builtin/cat-file.c:266 +msgid "<type> can be one of: blob, tree, commit, tag" +msgstr "<typ> kan vara en av: blob, tree, commit, tag" + +#: builtin/cat-file.c:267 +msgid "show object type" +msgstr "visa objekttyp" + +#: builtin/cat-file.c:268 +msgid "show object size" +msgstr "visa objektstorlek" + +#: builtin/cat-file.c:270 +msgid "exit with zero when there's no error" +msgstr "avsluta med noll när det inte uppstÃ¥tt nÃ¥got fel" + +#: builtin/cat-file.c:271 +msgid "pretty-print object's content" +msgstr "visa objektets innehÃ¥ll snyggt" + +#: builtin/cat-file.c:273 +msgid "for blob objects, run textconv on object's content" +msgstr "för blob-objekt, kör textconv pÃ¥ objektets innehÃ¥ll" + +#: builtin/cat-file.c:275 +msgid "show info and content of objects fed from the standard input" +msgstr "visa information och innehÃ¥ll för objekt som listas pÃ¥ standard in" + +#: builtin/cat-file.c:278 +msgid "show info about objects fed from the standard input" +msgstr "visa information för objekt som listas pÃ¥ standard in" + +#: builtin/check-attr.c:11 +msgid "git check-attr [-a | --all | attr...] [--] pathname..." +msgstr "git check-attr [-a | --all | attr...] [--] sökväg..." + +#: builtin/check-attr.c:12 +msgid "git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>" +msgstr "git check-attr --stdin [-z] [-a | --all | attr...] < <sökvägslista>" + +#: builtin/check-attr.c:19 +msgid "report all attributes set on file" +msgstr "visa alla attribut som satts pÃ¥ filen" + +#: builtin/check-attr.c:20 +msgid "use .gitattributes only from the index" +msgstr "använd .gitattributes endast frÃ¥n indexet" + +#: builtin/check-attr.c:21 builtin/hash-object.c:75 +msgid "read file names from stdin" +msgstr "läs filnamn frÃ¥n standard in" + +#: builtin/check-attr.c:23 +msgid "input paths are terminated by a null character" +msgstr "sökvägar avdelas med null-tecken" + +#: builtin/checkout-index.c:126 +msgid "git checkout-index [options] [--] [<file>...]" +msgstr "git checkout-index [flaggor] [--] [<fil>...]" + +#: builtin/checkout-index.c:187 +msgid "check out all files in the index" +msgstr "checka ut alla filer i indexet" + +#: builtin/checkout-index.c:188 +msgid "force overwrite of existing files" +msgstr "tvinga överskrivning av befintliga filer" + +#: builtin/checkout-index.c:190 +msgid "no warning for existing files and files not in index" +msgstr "ingen varning för existerande filer och filer ej i indexet" + +#: builtin/checkout-index.c:192 +msgid "don't checkout new files" +msgstr "checka inte ut nya filer" + +#: builtin/checkout-index.c:194 +msgid "update stat information in the index file" +msgstr "uppdatera stat-information i indexfilen" + +#: builtin/checkout-index.c:200 +msgid "read list of paths from the standard input" +msgstr "läs listan över sökvägar frÃ¥n standard in" + +#: builtin/checkout-index.c:202 +msgid "write the content to temporary files" +msgstr "skriv innehÃ¥ll till temporära filer" + +#: builtin/checkout-index.c:203 builtin/column.c:30 +msgid "string" +msgstr "sträng" + +#: builtin/checkout-index.c:204 +msgid "when creating files, prepend <string>" +msgstr "när filer skapas, lägg till <sträng> först" + +#: builtin/checkout-index.c:207 +msgid "copy out the files from named stage" +msgstr "kopiera ut filer frÃ¥n namngiven etapp" + +#: builtin/checkout.c:25 +msgid "git checkout [options] <branch>" +msgstr "git checkout [flaggor] <gren>" + +#: builtin/checkout.c:26 +msgid "git checkout [options] [<branch>] -- <file>..." +msgstr "git checkout [flaggor] [<gren>] -- <fil>..." + +#: builtin/checkout.c:116 builtin/checkout.c:149 #, c-format msgid "path '%s' does not have our version" msgstr "sökvägen \"%s\" har inte vÃ¥r version" -#: builtin/checkout.c:115 builtin/checkout.c:148 +#: builtin/checkout.c:118 builtin/checkout.c:151 #, c-format msgid "path '%s' does not have their version" msgstr "sökvägen \"%s\" har inte deras version" -#: builtin/checkout.c:131 +#: builtin/checkout.c:134 #, c-format msgid "path '%s' does not have all necessary versions" msgstr "sökvägen \"%s\" innehÃ¥ller inte alla nödvändiga versioner" -#: builtin/checkout.c:175 +#: builtin/checkout.c:178 #, c-format msgid "path '%s' does not have necessary versions" msgstr "sökvägen \"%s\" innehÃ¥ller inte nödvändiga versioner" -#: builtin/checkout.c:192 +#: builtin/checkout.c:195 #, c-format msgid "path '%s': cannot merge" msgstr "sökväg \"%s\": kan inte slÃ¥ ihop" -#: builtin/checkout.c:209 +#: builtin/checkout.c:212 #, c-format msgid "Unable to add merge result for '%s'" msgstr "Kunde inte lägga till sammanslagningsresultat för \"%s\"" -#: builtin/checkout.c:234 builtin/checkout.c:392 +#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242 +#: builtin/checkout.c:245 +#, c-format +msgid "'%s' cannot be used with updating paths" +msgstr "\"%s\" kan inte användas vid uppdatering av sökvägar" + +#: builtin/checkout.c:248 builtin/checkout.c:251 +#, c-format +msgid "'%s' cannot be used with %s" +msgstr "\"%s\" kan inte användas med %s" + +#: builtin/checkout.c:254 +#, c-format +msgid "Cannot update paths and switch to branch '%s' at the same time." +msgstr "Kan inte uppdatera sökvägar och växla till grenen \"%s\" samtidigt." + +#: builtin/checkout.c:265 builtin/checkout.c:426 msgid "corrupt index file" msgstr "indexfilen är trasig" -#: builtin/checkout.c:264 builtin/checkout.c:271 +#: builtin/checkout.c:295 builtin/checkout.c:302 #, c-format msgid "path '%s' is unmerged" msgstr "sökvägen \"%s\" har inte slagits ihop" -#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583 -#: builtin/merge.c:812 -msgid "unable to write new index file" -msgstr "kunde inte skriva ny indexfil" - -#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408 -msgid "diff_setup_done failed" -msgstr "diff_setup_done misslyckades" - -#: builtin/checkout.c:414 +#: builtin/checkout.c:448 msgid "you need to resolve your current index first" msgstr "du mÃ¥ste lösa ditt befintliga index först" -#: builtin/checkout.c:533 +#: builtin/checkout.c:569 #, c-format msgid "Can not do reflog for '%s'\n" msgstr "Kan inte skapa referenslog för \"%s\"\n" -#: builtin/checkout.c:566 +#: builtin/checkout.c:602 msgid "HEAD is now at" msgstr "HEAD är nu pÃ¥" -#: builtin/checkout.c:573 +#: builtin/checkout.c:609 #, c-format msgid "Reset branch '%s'\n" msgstr "Ã…terställ gren \"%s\"\n" -#: builtin/checkout.c:576 +#: builtin/checkout.c:612 #, c-format msgid "Already on '%s'\n" msgstr "Redan pÃ¥ \"%s\"\n" -#: builtin/checkout.c:580 +#: builtin/checkout.c:616 #, c-format msgid "Switched to and reset branch '%s'\n" msgstr "Växlade till och nollställde grenen \"%s\"\n" -#: builtin/checkout.c:582 +#: builtin/checkout.c:618 builtin/checkout.c:955 #, c-format msgid "Switched to a new branch '%s'\n" msgstr "Växlade till en ny gren \"%s\"\n" -#: builtin/checkout.c:584 +#: builtin/checkout.c:620 #, c-format msgid "Switched to branch '%s'\n" msgstr "Växlade till grenen \"%s\"\n" -#: builtin/checkout.c:640 +#: builtin/checkout.c:676 #, c-format msgid " ... and %d more.\n" msgstr " ... och %d till.\n" #. The singular version -#: builtin/checkout.c:646 +#: builtin/checkout.c:682 #, c-format msgid "" "Warning: you are leaving %d commit behind, not connected to\n" @@ -1818,7 +2737,7 @@ msgstr[1] "" "\n" "%s\n" -#: builtin/checkout.c:664 +#: builtin/checkout.c:700 #, c-format msgid "" "If you want to keep them by creating a new branch, this may be a good time\n" @@ -1833,88 +2752,150 @@ msgstr "" " git branch nytt_grennamn %s\n" "\n" -#: builtin/checkout.c:694 +#: builtin/checkout.c:730 msgid "internal error in revision walk" msgstr "internt fel vid genomgÃ¥ng av revisioner (revision walk)" -#: builtin/checkout.c:698 +#: builtin/checkout.c:734 msgid "Previous HEAD position was" msgstr "Tidigare position för HEAD var" -#: builtin/checkout.c:724 +#: builtin/checkout.c:761 builtin/checkout.c:950 msgid "You are on a branch yet to be born" msgstr "Du är pÃ¥ en gren som ännu inte är född" #. case (1) -#: builtin/checkout.c:855 +#: builtin/checkout.c:886 #, c-format msgid "invalid reference: %s" msgstr "felaktig referens: %s" #. case (1): want a tree -#: builtin/checkout.c:894 +#: builtin/checkout.c:925 #, c-format msgid "reference is not a tree: %s" msgstr "referensen är inte ett träd: %s" -#: builtin/checkout.c:974 -msgid "-B cannot be used with -b" -msgstr "-B kan inte användas med -b" +#: builtin/checkout.c:964 +msgid "paths cannot be used with switching branches" +msgstr "sökvägar kan inte användas vid byte av gren" -#: builtin/checkout.c:983 -msgid "--patch is incompatible with all other options" -msgstr "--patch är inkompatibel med alla andra flaggor" +#: builtin/checkout.c:967 builtin/checkout.c:971 +#, c-format +msgid "'%s' cannot be used with switching branches" +msgstr "\"%s\" kan inte användas vid byte av gren" +#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983 #: builtin/checkout.c:986 -msgid "--detach cannot be used with -b/-B/--orphan" -msgstr "--detcah kan inte användas med -b/-B/--orphan" +#, c-format +msgid "'%s' cannot be used with '%s'" +msgstr "\"%s\" kan inte användas med \"%s\"" + +#: builtin/checkout.c:991 +#, c-format +msgid "Cannot switch branch to a non-commit '%s'" +msgstr "Kan inte växla gren till icke-incheckningen \"%s\"" -#: builtin/checkout.c:988 -msgid "--detach cannot be used with -t" -msgstr "--detach kan inte användas med -t" +#: builtin/checkout.c:1012 builtin/gc.c:177 +msgid "suppress progress reporting" +msgstr "undertryck förloppsrapportering" -#: builtin/checkout.c:994 -msgid "--track needs a branch name" -msgstr "--track behöver ett namn pÃ¥ en gren" +#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89 +#: builtin/remote.c:169 builtin/remote.c:171 +msgid "branch" +msgstr "gren" -#: builtin/checkout.c:1001 -msgid "Missing branch name; try -b" -msgstr "Grennamn saknas; försök med -b" +#: builtin/checkout.c:1014 +msgid "create and checkout a new branch" +msgstr "skapa och checka ut en ny gren" -#: builtin/checkout.c:1007 -msgid "--orphan and -b|-B are mutually exclusive" -msgstr "--orphan och -b|-B kan inte användas samtidigt" +#: builtin/checkout.c:1016 +msgid "create/reset and checkout a branch" +msgstr "skapa/nollställ och checka ut en gren" -#: builtin/checkout.c:1009 -msgid "--orphan cannot be used with -t" -msgstr "--orphan kan inte användas med -t" +#: builtin/checkout.c:1017 +msgid "create reflog for new branch" +msgstr "skapa reflogg för ny gren" + +#: builtin/checkout.c:1018 +msgid "detach the HEAD at named commit" +msgstr "koppla frÃ¥n HEAD vid namngiven incheckning" #: builtin/checkout.c:1019 -msgid "git checkout: -f and -m are incompatible" -msgstr "git checkout: -f och -m är inkompatibla" +msgid "set upstream info for new branch" +msgstr "sätt uppströmsinformation för ny gren" + +#: builtin/checkout.c:1021 +msgid "new branch" +msgstr "ny gren" + +#: builtin/checkout.c:1021 +msgid "new unparented branch" +msgstr "ny gren utan förälder" + +#: builtin/checkout.c:1022 +msgid "checkout our version for unmerged files" +msgstr "checka ut vÃ¥r version för ej sammanslagna filer" + +#: builtin/checkout.c:1024 +msgid "checkout their version for unmerged files" +msgstr "checka ut deras version för ej sammanslagna filer" + +#: builtin/checkout.c:1026 +msgid "force checkout (throw away local modifications)" +msgstr "tvinga utcheckning (kasta bort lokala ändringar)" + +#: builtin/checkout.c:1027 +msgid "perform a 3-way merge with the new branch" +msgstr "utför en 3-vägssammanslagning för den nya grenen" + +#: builtin/checkout.c:1028 builtin/merge.c:215 +msgid "update ignored files (default)" +msgstr "uppdatera ignorerade filer (standard)" + +#: builtin/checkout.c:1029 builtin/log.c:1116 parse-options.h:241 +msgid "style" +msgstr "stil" + +#: builtin/checkout.c:1030 +msgid "conflict style (merge or diff3)" +msgstr "konfliktstil (merge eller diff3)" + +#: builtin/checkout.c:1033 +msgid "second guess 'git checkout no-such-branch'" +msgstr "förutspÃ¥ \"git checkout gren-saknas\"" -#: builtin/checkout.c:1053 +#: builtin/checkout.c:1057 +msgid "-b, -B and --orphan are mutually exclusive" +msgstr "-b, -B och --orphan är ömsesidigt uteslutande" + +#: builtin/checkout.c:1074 +msgid "--track needs a branch name" +msgstr "--track behöver ett namn pÃ¥ en gren" + +#: builtin/checkout.c:1081 +msgid "Missing branch name; try -b" +msgstr "Grennamn saknas; försök med -b" + +#: builtin/checkout.c:1116 msgid "invalid path specification" msgstr "felaktig sökvägsangivelse" -#: builtin/checkout.c:1061 +#: builtin/checkout.c:1123 #, c-format msgid "" -"git checkout: updating paths is incompatible with switching branches.\n" +"Cannot update paths and switch to branch '%s' at the same time.\n" "Did you intend to checkout '%s' which can not be resolved as commit?" msgstr "" -"git checkout: uppdatera sökvägar är inkompatibelt med att växla gren.\n" -"Ville du checka ut \"%s\" som inte kan lösas som en sammanslaning?" - -#: builtin/checkout.c:1063 -msgid "git checkout: updating paths is incompatible with switching branches." -msgstr "git checkout: uppdatera sökvägar är inkompatibelt med att växla gren." +"Kan inte uppdatera sökvägar och växla till grenen \"%s\" samtidigt.\n" +"Ville du checka ut \"%s\" som inte kan lösas som en utcheckning?" -#: builtin/checkout.c:1068 -msgid "git checkout: --detach does not take a path argument" -msgstr "git checkout: --detach tar inte en sökväg som argument" +#: builtin/checkout.c:1128 +#, c-format +msgid "git checkout: --detach does not take a path argument '%s'" +msgstr "git checkout: --detach tar inte en sökväg som argument \"%s\"" -#: builtin/checkout.c:1071 +#: builtin/checkout.c:1132 msgid "" "git checkout: --ours/--theirs, --force and --merge are incompatible when\n" "checking out of the index." @@ -1922,13 +2903,39 @@ msgstr "" "git checkout: --ours/--theirs, --force och --merge är inkompatibla när\n" "du checkar ut frÃ¥n indexet." -#: builtin/checkout.c:1090 -msgid "Cannot switch branch to a non-commit." -msgstr "Kan inte växla gren pÃ¥ en icke-incheckning." +#: builtin/clean.c:19 +msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..." +msgstr "" +"git clean [-d] [-f] [-n] [-q] [-e <mönster>] [-x | -X] [--] <sökvägar>..." + +#: builtin/clean.c:51 +msgid "do not print names of files removed" +msgstr "skriv inte ut namn pÃ¥ borttagna filer" + +#: builtin/clean.c:53 +msgid "force" +msgstr "tvinga" + +#: builtin/clean.c:55 +msgid "remove whole directories" +msgstr "ta bort hela kataloger" + +#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:717 +#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:182 +msgid "pattern" +msgstr "mönster" + +#: builtin/clean.c:57 +msgid "add <pattern> to ignore rules" +msgstr "lägg till <mönster> till ignoreringsregler" + +#: builtin/clean.c:58 +msgid "remove ignored files, too" +msgstr "ta även bort ignorerade filer" -#: builtin/checkout.c:1093 -msgid "--ours/--theirs is incompatible with switching branches." -msgstr "--ours/--theirs är inkompatibla med att byta gren." +#: builtin/clean.c:60 +msgid "remove only ignored files" +msgstr "ta endast bort ignorerade filer" #: builtin/clean.c:78 msgid "-x and -X cannot be used together" @@ -1974,22 +2981,110 @@ msgstr "Skulle inte ta bort %s\n" msgid "Not removing %s\n" msgstr "Tar inte bort %s\n" +#: builtin/clone.c:36 +msgid "git clone [options] [--] <repo> [<dir>]" +msgstr "git clone [flaggor] [--] <arkiv> [<kat>]" + +#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212 +#: builtin/push.c:399 +msgid "force progress reporting" +msgstr "tvinga förloppsrapportering" + +#: builtin/clone.c:66 +msgid "don't create a checkout" +msgstr "skapa inte nÃ¥gon utcheckning" + +#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488 +msgid "create a bare repository" +msgstr "skapa ett naket (\"bare\") arkiv" + +#: builtin/clone.c:72 +msgid "create a mirror repository (implies bare)" +msgstr "skapa ett spegelarkiv (implicerar \"bare\")" + +#: builtin/clone.c:74 +msgid "to clone from a local repository" +msgstr "för att klona frÃ¥n ett lokalt arkiv" + +#: builtin/clone.c:76 +msgid "don't use local hardlinks, always copy" +msgstr "skapa inte lokala hÃ¥rda länkar, kopiera alltid" + +#: builtin/clone.c:78 +msgid "setup as shared repository" +msgstr "skapa som ett delat arkiv" + +#: builtin/clone.c:80 builtin/clone.c:82 +msgid "initialize submodules in the clone" +msgstr "initiera undermoduler i klonen" + +#: builtin/clone.c:83 builtin/init-db.c:485 +msgid "template-directory" +msgstr "mallkatalog" + +#: builtin/clone.c:84 builtin/init-db.c:486 +msgid "directory from which templates will be used" +msgstr "katalog att använda mallar frÃ¥n" + +#: builtin/clone.c:86 +msgid "reference repository" +msgstr "referensarkiv" + +#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44 +msgid "name" +msgstr "namn" + +#: builtin/clone.c:88 +msgid "use <name> instead of 'origin' to track upstream" +msgstr "använd <namn> istället för \"origin\" för att spÃ¥ra uppströms" + +#: builtin/clone.c:90 +msgid "checkout <branch> instead of the remote's HEAD" +msgstr "checka ut <gren> istället för fjärrens HEAD" + +#: builtin/clone.c:92 +msgid "path to git-upload-pack on the remote" +msgstr "sökväg till git-upload-pack pÃ¥ fjärren" + +#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662 +msgid "depth" +msgstr "djup" + +#: builtin/clone.c:94 +msgid "create a shallow clone of that depth" +msgstr "skapa en grund klon pÃ¥ detta djup" + +#: builtin/clone.c:96 +msgid "clone only one branch, HEAD or --branch" +msgstr "klona endast en gren, HEAD eller --branch" + +#: builtin/clone.c:97 builtin/init-db.c:494 +msgid "gitdir" +msgstr "gitkat" + +#: builtin/clone.c:98 builtin/init-db.c:495 +msgid "separate git dir from working tree" +msgstr "separera gitkatalogen frÃ¥n arbetskatalogen" + +#: builtin/clone.c:99 +msgid "key=value" +msgstr "nyckel=värde" + +#: builtin/clone.c:100 +msgid "set config inside the new repository" +msgstr "ställ in konfiguration i det nya arkivet" + #: builtin/clone.c:243 #, c-format msgid "reference repository '%s' is not a local directory." msgstr "referensarkivet \"%s\" är inte en lokal katalog." -#: builtin/clone.c:302 -#, c-format -msgid "failed to open '%s'" -msgstr "misslyckades öppna \"%s\"" - #: builtin/clone.c:306 #, c-format msgid "failed to create directory '%s'" msgstr "misslyckades skapa katalogen \"%s\"" -#: builtin/clone.c:308 builtin/diff.c:75 +#: builtin/clone.c:308 builtin/diff.c:77 #, c-format msgid "failed to stat '%s'" msgstr "misslyckades ta status pÃ¥ \"%s\"" @@ -2004,11 +3099,6 @@ msgstr "%s finns och är ingen katalog" msgid "failed to stat %s\n" msgstr "misslyckades ta status pÃ¥ %s\n" -#: builtin/clone.c:341 -#, c-format -msgid "failed to unlink '%s'" -msgstr "misslyckades ta bort länken \"%s\"" - #: builtin/clone.c:346 #, c-format msgid "failed to create link '%s'" @@ -2024,87 +3114,123 @@ msgstr "misslyckades kopiera filen till \"%s\"" msgid "done.\n" msgstr "klart.\n" -#: builtin/clone.c:440 +#: builtin/clone.c:443 #, c-format msgid "Could not find remote branch %s to clone." msgstr "Kunde inte hitta fjärrgrenen %s för att klona." -#: builtin/clone.c:549 +#: builtin/clone.c:552 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" msgstr "" "HEAD hos fjärren pekar pÃ¥ en obefintlig referens, kan inte checka ut.\n" -#: builtin/clone.c:639 +#: builtin/clone.c:690 msgid "Too many arguments." msgstr "För mÃ¥nga argument." -#: builtin/clone.c:643 +#: builtin/clone.c:694 msgid "You must specify a repository to clone." msgstr "Du mÃ¥ste ange ett arkiv att klona." -#: builtin/clone.c:654 +#: builtin/clone.c:705 #, c-format msgid "--bare and --origin %s options are incompatible." msgstr "flaggorna --bare och --origin %s är inkompatibla." -#: builtin/clone.c:668 +#: builtin/clone.c:719 #, c-format msgid "repository '%s' does not exist" msgstr "arkivet \"%s\" finns inte" -#: builtin/clone.c:673 +#: builtin/clone.c:724 msgid "--depth is ignored in local clones; use file:// instead." msgstr "--depth ignoreras i lokala kloningar; använd file:// istället" -#: builtin/clone.c:683 +#: builtin/clone.c:734 #, c-format msgid "destination path '%s' already exists and is not an empty directory." msgstr "destinationssökvägen \"%s\" finns redan och är inte en tom katalog." -#: builtin/clone.c:693 +#: builtin/clone.c:744 #, c-format msgid "working tree '%s' already exists." msgstr "arbetsträdet \"%s\" finns redan." -#: builtin/clone.c:706 builtin/clone.c:720 +#: builtin/clone.c:757 builtin/clone.c:771 #, c-format msgid "could not create leading directories of '%s'" msgstr "kunde inte skapa inledande kataloger för \"%s\"" -#: builtin/clone.c:709 +#: builtin/clone.c:760 #, c-format msgid "could not create work tree dir '%s'." msgstr "kunde inte skapa arbetskatalogen \"%s\"" -#: builtin/clone.c:728 +#: builtin/clone.c:779 #, c-format msgid "Cloning into bare repository '%s'...\n" msgstr "Klonar till ett naket arkiv \"%s\"...\n" -#: builtin/clone.c:730 +#: builtin/clone.c:781 #, c-format msgid "Cloning into '%s'...\n" msgstr "Klonar till \"%s\"...\n" -#: builtin/clone.c:786 +#: builtin/clone.c:823 #, c-format msgid "Don't know how to clone %s" msgstr "Vet inte hur man klonar %s" -#: builtin/clone.c:835 +#: builtin/clone.c:872 #, c-format msgid "Remote branch %s not found in upstream %s" msgstr "Fjärrgrenen %s hittades inte i uppströmsarkivet %s" -#: builtin/clone.c:842 +#: builtin/clone.c:879 msgid "You appear to have cloned an empty repository." msgstr "Du verkar ha klonat ett tomt arkiv." +#: builtin/column.c:9 +msgid "git column [options]" +msgstr "git column [flaggor]" + +#: builtin/column.c:26 +msgid "lookup config vars" +msgstr "slÃ¥ upp konfigurationsvariabler" + +#: builtin/column.c:27 builtin/column.c:28 +msgid "layout to use" +msgstr "utseende att använda" + +#: builtin/column.c:29 +msgid "Maximum width" +msgstr "Maximal bredd" + +#: builtin/column.c:30 +msgid "Padding space on left border" +msgstr "Spaltfyllnad i vänsterkanten" + +#: builtin/column.c:31 +msgid "Padding space on right border" +msgstr "Spaltfyllnad i högerkanten" + +#: builtin/column.c:32 +msgid "Padding space between columns" +msgstr "Spaltfyllnad mellan spalter" + #: builtin/column.c:51 msgid "--command must be the first argument" msgstr "--command mÃ¥ste vara första argument" -#: builtin/commit.c:43 +#: builtin/commit.c:34 +msgid "git commit [options] [--] <filepattern>..." +msgstr "git commit [flaggor] [--] <filmöster>..." + +#: builtin/commit.c:39 +msgid "git status [options] [--] <filepattern>..." +msgstr "git status [flaggor] [--] <filmönster>..." + +#: builtin/commit.c:44 msgid "" "Your name and email address were configured automatically based\n" "on your username and hostname. Please check that they are accurate.\n" @@ -2129,7 +3255,7 @@ msgstr "" "\n" " git commit --amend --reset-author\n" -#: builtin/commit.c:55 +#: builtin/commit.c:56 msgid "" "You asked to amend the most recent commit, but doing so would make\n" "it empty. You can repeat your command with --allow-empty, or you can\n" @@ -2139,7 +3265,7 @@ msgstr "" "blir den tom. Du kan köra kommandot pÃ¥ nytt med --allow-empty, eller\n" "sÃ¥ kan du ta bort incheckningen helt med \"git reset HEAD^\".\n" -#: builtin/commit.c:60 +#: builtin/commit.c:61 msgid "" "The previous cherry-pick is now empty, possibly due to conflict resolution.\n" "If you wish to commit it anyway, use:\n" @@ -2155,93 +3281,93 @@ msgstr "" "\n" "Annars använder du \"git reset\"\n" -#: builtin/commit.c:253 +#: builtin/commit.c:258 msgid "failed to unpack HEAD tree object" msgstr "misslyckades packa upp HEAD:s trädobjekt" -#: builtin/commit.c:295 +#: builtin/commit.c:300 msgid "unable to create temporary index" msgstr "kunde inte skapa temporär indexfil" -#: builtin/commit.c:301 +#: builtin/commit.c:306 msgid "interactive add failed" msgstr "interaktiv tilläggning misslyckades" -#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405 +#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410 msgid "unable to write new_index file" msgstr "kunde inte skriva filen new_index" -#: builtin/commit.c:386 +#: builtin/commit.c:391 msgid "cannot do a partial commit during a merge." msgstr "kan inte utföra en delvis incheckning under en sammanslagning." -#: builtin/commit.c:388 +#: builtin/commit.c:393 msgid "cannot do a partial commit during a cherry-pick." msgstr "kan inte utföra en delvis incheckning under en cherry-pick." -#: builtin/commit.c:398 +#: builtin/commit.c:403 msgid "cannot read the index" msgstr "kan inte läsa indexet" -#: builtin/commit.c:418 +#: builtin/commit.c:423 msgid "unable to write temporary index file" msgstr "kunde inte skriva temporär indexfil" -#: builtin/commit.c:493 builtin/commit.c:499 +#: builtin/commit.c:511 builtin/commit.c:517 #, c-format msgid "invalid commit: %s" msgstr "felaktig incheckning: %s" -#: builtin/commit.c:522 +#: builtin/commit.c:540 msgid "malformed --author parameter" msgstr "felformad \"--author\"-flagga" -#: builtin/commit.c:582 +#: builtin/commit.c:560 #, c-format msgid "Malformed ident string: '%s'" msgstr "Felaktig indragningssträng: \"%s\"" -#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967 +#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954 #, c-format msgid "could not lookup commit %s" msgstr "kunde inte slÃ¥ upp incheckningen %s" -#: builtin/commit.c:632 builtin/shortlog.c:296 +#: builtin/commit.c:610 builtin/shortlog.c:296 #, c-format msgid "(reading log message from standard input)\n" msgstr "(läser loggmeddelande frÃ¥n standard in)\n" -#: builtin/commit.c:634 +#: builtin/commit.c:612 msgid "could not read log from standard input" msgstr "kunde inte läsa logg frÃ¥n standard in" -#: builtin/commit.c:638 +#: builtin/commit.c:616 #, c-format msgid "could not read log file '%s'" msgstr "kunde inte läsa loggfilen \"%s\"" -#: builtin/commit.c:644 +#: builtin/commit.c:622 msgid "commit has empty message" msgstr "incheckningen har ett tomt meddelande" -#: builtin/commit.c:660 +#: builtin/commit.c:638 msgid "could not read MERGE_MSG" msgstr "kunde inte läsa MERGE_MSG" -#: builtin/commit.c:664 +#: builtin/commit.c:642 msgid "could not read SQUASH_MSG" msgstr "kunde inte läsa SQUASH_MSG" -#: builtin/commit.c:668 +#: builtin/commit.c:646 #, c-format msgid "could not read '%s'" msgstr "kunde inte läsa \"%s\"" -#: builtin/commit.c:720 +#: builtin/commit.c:707 msgid "could not write commit template" msgstr "kunde inte skriva incheckningsmall" -#: builtin/commit.c:731 +#: builtin/commit.c:718 #, c-format msgid "" "\n" @@ -2256,7 +3382,7 @@ msgstr "" "\t%s\n" "och försöker igen.\n" -#: builtin/commit.c:736 +#: builtin/commit.c:723 #, c-format msgid "" "\n" @@ -2271,7 +3397,7 @@ msgstr "" "\t%s\n" "och försöker igen.\n" -#: builtin/commit.c:748 +#: builtin/commit.c:735 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be ignored, and an empty message aborts the commit.\n" @@ -2279,7 +3405,7 @@ msgstr "" "Ange incheckningsmeddelandet för dina ändringar. Rader som inleds\n" "med \"#\" kommer ignoreras, och ett tomt meddelande avbryter incheckningen.\n" -#: builtin/commit.c:753 +#: builtin/commit.c:740 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be kept; you may remove them yourself if you want to.\n" @@ -2289,159 +3415,357 @@ msgstr "" "med \"#\" kommer behÃ¥llas; du kan själv ta bort dem om du vill.\n" "Ett tomt meddelande avbryter incheckningen.\n" -#: builtin/commit.c:766 +#: builtin/commit.c:753 #, c-format msgid "%sAuthor: %s" msgstr "%sFörfattare: %s" -#: builtin/commit.c:773 +#: builtin/commit.c:760 #, c-format msgid "%sCommitter: %s" msgstr "%sIncheckare: %s" -#: builtin/commit.c:793 +#: builtin/commit.c:780 msgid "Cannot read index" msgstr "Kan inte läsa indexet" -#: builtin/commit.c:830 +#: builtin/commit.c:817 msgid "Error building trees" msgstr "Fel vid byggande av träd" -#: builtin/commit.c:845 builtin/tag.c:361 +#: builtin/commit.c:832 builtin/tag.c:361 #, c-format msgid "Please supply the message using either -m or -F option.\n" msgstr "Ange meddelandet en av flaggorna -m eller -F.\n" -#: builtin/commit.c:942 +#: builtin/commit.c:929 #, c-format msgid "No existing author found with '%s'" msgstr "Hittade ingen befintlig författare med \"%s\"" -#: builtin/commit.c:957 builtin/commit.c:1157 +#: builtin/commit.c:944 builtin/commit.c:1148 #, c-format msgid "Invalid untracked files mode '%s'" msgstr "Ogiltigt läge för ospÃ¥rade filer: \"%s\"" -#: builtin/commit.c:997 +#: builtin/commit.c:984 msgid "Using both --reset-author and --author does not make sense" msgstr "Kan inte använda bÃ¥de --reset-author och --author" -#: builtin/commit.c:1008 +#: builtin/commit.c:995 msgid "You have nothing to amend." msgstr "Du har inget att utöka." -#: builtin/commit.c:1011 +#: builtin/commit.c:998 msgid "You are in the middle of a merge -- cannot amend." msgstr "Du är i mitten av en sammanslagning -- kan inte utöka." -#: builtin/commit.c:1013 +#: builtin/commit.c:1000 msgid "You are in the middle of a cherry-pick -- cannot amend." msgstr "Du är i mitten av en cherry-pick -- kan inte utöka." -#: builtin/commit.c:1016 +#: builtin/commit.c:1003 msgid "Options --squash and --fixup cannot be used together" msgstr "Flaggorna --squash och --fixup kan inte användas samtidigt" -#: builtin/commit.c:1026 +#: builtin/commit.c:1013 msgid "Only one of -c/-C/-F/--fixup can be used." msgstr "Endast en av -c/-C/-F/--fixup kan användas." -#: builtin/commit.c:1028 +#: builtin/commit.c:1015 msgid "Option -m cannot be combined with -c/-C/-F/--fixup." msgstr "Flaggan -m kan inte kombineras med -c/-C/-F/--fixup." -#: builtin/commit.c:1036 +#: builtin/commit.c:1023 msgid "--reset-author can be used only with -C, -c or --amend." msgstr "--reset-author kan endast användas med -C, -c eller --amend." -#: builtin/commit.c:1053 +#: builtin/commit.c:1040 msgid "Only one of --include/--only/--all/--interactive/--patch can be used." msgstr "" "Endast en av --include/--only/--all/--interactive/--patch kan användas." -#: builtin/commit.c:1055 +#: builtin/commit.c:1042 msgid "No paths with --include/--only does not make sense." msgstr "Du mÃ¥ste ange sökvägar tillsammans med --include/--only." -#: builtin/commit.c:1057 +#: builtin/commit.c:1044 msgid "Clever... amending the last one with dirty index." msgstr "Smart... utöka den senaste med smutsigt index." -#: builtin/commit.c:1059 +#: builtin/commit.c:1046 msgid "Explicit paths specified without -i nor -o; assuming --only paths..." msgstr "Explicita sökvägar angavs utan -i eller -o; antar --only sökvägar..." -#: builtin/commit.c:1069 builtin/tag.c:577 +#: builtin/commit.c:1056 builtin/tag.c:577 #, c-format msgid "Invalid cleanup mode %s" msgstr "Felaktigt städningsläge %s" -#: builtin/commit.c:1074 +#: builtin/commit.c:1061 msgid "Paths with -a does not make sense." msgstr "Kan inte ange sökvägar med -a." -#: builtin/commit.c:1257 +#: builtin/commit.c:1067 builtin/commit.c:1202 +msgid "--long and -z are incompatible" +msgstr "--long och -z är inkompatibla" + +#: builtin/commit.c:1162 builtin/commit.c:1398 +msgid "show status concisely" +msgstr "vis koncis status" + +#: builtin/commit.c:1164 builtin/commit.c:1400 +msgid "show branch information" +msgstr "visa information om gren" + +#: builtin/commit.c:1166 builtin/commit.c:1402 builtin/push.c:389 +msgid "machine-readable output" +msgstr "maskinläsbar utdata" + +#: builtin/commit.c:1169 builtin/commit.c:1404 +msgid "show status in long format (default)" +msgstr "visa status i lÃ¥ngt format (standard)" + +#: builtin/commit.c:1172 builtin/commit.c:1407 +msgid "terminate entries with NUL" +msgstr "terminera poster med NUL" + +#: builtin/commit.c:1174 builtin/commit.c:1410 builtin/fast-export.c:636 +#: builtin/fast-export.c:639 builtin/tag.c:461 +msgid "mode" +msgstr "läge" + +#: builtin/commit.c:1175 builtin/commit.c:1410 +msgid "show untracked files, optional modes: all, normal, no. (Default: all)" +msgstr "visa ospÃ¥rade filer, valfria lägen: alla, normal, no. (Standard: all)" + +#: builtin/commit.c:1178 +msgid "show ignored files" +msgstr "visa ignorerade filer" + +#: builtin/commit.c:1179 parse-options.h:151 +msgid "when" +msgstr "när" + +#: builtin/commit.c:1180 +msgid "" +"ignore changes to submodules, optional when: all, dirty, untracked. " +"(Default: all)" +msgstr "" +"ignorera ändringar i undermoduler, valfritt när: all, dirty, untracked. " +"(Default: all)" + +#: builtin/commit.c:1182 +msgid "list untracked files in columns" +msgstr "visa ospÃ¥rade filer i spalter" + +#: builtin/commit.c:1256 msgid "couldn't look up newly created commit" msgstr "kunde inte slÃ¥ upp en precis skapad incheckning" -#: builtin/commit.c:1259 +#: builtin/commit.c:1258 msgid "could not parse newly created commit" msgstr "kunde inte tolka en precis skapad incheckning" -#: builtin/commit.c:1300 +#: builtin/commit.c:1299 msgid "detached HEAD" msgstr "frÃ¥nkopplad HEAD" -#: builtin/commit.c:1302 +#: builtin/commit.c:1301 msgid " (root-commit)" msgstr " (rotincheckning)" -#: builtin/commit.c:1446 +#: builtin/commit.c:1368 +msgid "suppress summary after successful commit" +msgstr "undertryck sammanfattning efter framgÃ¥ngsrik incheckning" + +#: builtin/commit.c:1369 +msgid "show diff in commit message template" +msgstr "visa diff i mallen för incheckningsmeddelandet" + +#: builtin/commit.c:1371 +msgid "Commit message options" +msgstr "Alternativ för incheckningsmeddelande" + +#: builtin/commit.c:1372 builtin/tag.c:459 +msgid "read message from file" +msgstr "läs meddelande frÃ¥n fil" + +#: builtin/commit.c:1373 +msgid "author" +msgstr "författare" + +#: builtin/commit.c:1373 +msgid "override author for commit" +msgstr "överstyr författare för incheckningen" + +#: builtin/commit.c:1374 builtin/gc.c:178 +msgid "date" +msgstr "datum" + +#: builtin/commit.c:1374 +msgid "override date for commit" +msgstr "överstyr datum för inchecknignen" + +#: builtin/commit.c:1375 builtin/merge.c:206 builtin/notes.c:537 +#: builtin/notes.c:694 builtin/tag.c:457 +msgid "message" +msgstr "meddelande" + +#: builtin/commit.c:1375 +msgid "commit message" +msgstr "incheckningsmeddelande" + +#: builtin/commit.c:1376 +msgid "reuse and edit message from specified commit" +msgstr "Ã¥teranvänd och redigera meddelande frÃ¥n angiven incheckning" + +#: builtin/commit.c:1377 +msgid "reuse message from specified commit" +msgstr "Ã¥teranvänd meddelande frÃ¥n angiven incheckning" + +#: builtin/commit.c:1378 +msgid "use autosquash formatted message to fixup specified commit" +msgstr "" +"använd autosquash-formaterat meddelande för att fixa angiven incheckning" + +#: builtin/commit.c:1379 +msgid "use autosquash formatted message to squash specified commit" +msgstr "" +"använd autosquash-formaterat meddelande för att slÃ¥ ihop med angiven " +"incheckning" + +#: builtin/commit.c:1380 +msgid "the commit is authored by me now (used with -C/-c/--amend)" +msgstr "jag är nu författare av incheckningen (används med -C/-c/--amend)" + +#: builtin/commit.c:1381 builtin/log.c:1073 builtin/revert.c:109 +msgid "add Signed-off-by:" +msgstr "lägg till Signed-off-by:" + +#: builtin/commit.c:1382 +msgid "use specified template file" +msgstr "använd angiven mallfil" + +#: builtin/commit.c:1383 +msgid "force edit of commit" +msgstr "tvinga redigering av incheckning" + +#: builtin/commit.c:1384 +msgid "default" +msgstr "standard" + +#: builtin/commit.c:1384 builtin/tag.c:462 +msgid "how to strip spaces and #comments from message" +msgstr "hur blanksteg och #kommentarer skall tas bort frÃ¥n meddelande" + +#: builtin/commit.c:1385 +msgid "include status in commit message template" +msgstr "inkludera status i mallen för incheckningsmeddelandet" + +#: builtin/commit.c:1386 builtin/merge.c:213 builtin/tag.c:463 +msgid "key id" +msgstr "nyckel-id" + +#: builtin/commit.c:1387 builtin/merge.c:214 +msgid "GPG sign commit" +msgstr "GPG-signera incheckning" + +#. end commit message options +#: builtin/commit.c:1390 +msgid "Commit contents options" +msgstr "Alternativ för incheckningens innehÃ¥ll" + +#: builtin/commit.c:1391 +msgid "commit all changed files" +msgstr "checka in alla ändrade filer" + +#: builtin/commit.c:1392 +msgid "add specified files to index for commit" +msgstr "lägg till angivna filer till indexet för incheckning" + +#: builtin/commit.c:1393 +msgid "interactively add files" +msgstr "lägg till filer interaktivt" + +#: builtin/commit.c:1394 +msgid "interactively add changes" +msgstr "lägg till ändringar interaktivt" + +#: builtin/commit.c:1395 +msgid "commit only specified files" +msgstr "checka endast in angivna filer" + +#: builtin/commit.c:1396 +msgid "bypass pre-commit hook" +msgstr "förbigÃ¥ pre-commit-krok" + +#: builtin/commit.c:1397 +msgid "show what would be committed" +msgstr "visa vad som skulle checkas in" + +#: builtin/commit.c:1408 +msgid "amend previous commit" +msgstr "lägg till föregÃ¥ende incheckning" + +#: builtin/commit.c:1409 +msgid "bypass post-rewrite hook" +msgstr "förbigÃ¥ post-rewrite-krok" + +#: builtin/commit.c:1414 +msgid "ok to record an empty change" +msgstr "ok att registrera en tom ändring" + +#: builtin/commit.c:1417 +msgid "ok to record a change with an empty message" +msgstr "ok att registrera en ändring med tomt meddelande" + +#: builtin/commit.c:1449 msgid "could not parse HEAD commit" msgstr "kunde inte tolka HEAD:s incheckning" -#: builtin/commit.c:1484 builtin/merge.c:509 +#: builtin/commit.c:1487 builtin/merge.c:508 #, c-format msgid "could not open '%s' for reading" msgstr "kunde inte öppna \"%s\" för läsning" -#: builtin/commit.c:1491 +#: builtin/commit.c:1494 #, c-format msgid "Corrupt MERGE_HEAD file (%s)" msgstr "Trasig MERGE_HEAD-fil (%s)" -#: builtin/commit.c:1498 +#: builtin/commit.c:1501 msgid "could not read MERGE_MODE" msgstr "kunde inte läsa MERGE_MODE" -#: builtin/commit.c:1517 +#: builtin/commit.c:1520 #, c-format msgid "could not read commit message: %s" msgstr "kunde inte läsa incheckningsmeddelande: %s" -#: builtin/commit.c:1531 +#: builtin/commit.c:1534 #, c-format msgid "Aborting commit; you did not edit the message.\n" msgstr "Avbryter incheckning; meddelandet inte redigerat.\n" -#: builtin/commit.c:1536 +#: builtin/commit.c:1539 #, c-format msgid "Aborting commit due to empty commit message.\n" msgstr "Avbryter pÃ¥ grund av tomt incheckningsmeddelande.\n" -#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961 +#: builtin/commit.c:1554 builtin/merge.c:832 builtin/merge.c:857 msgid "failed to write commit object" msgstr "kunde inte skriva incheckningsobjekt" -#: builtin/commit.c:1572 +#: builtin/commit.c:1575 msgid "cannot lock HEAD ref" msgstr "kunde inte lÃ¥sa HEAD-referens" -#: builtin/commit.c:1576 +#: builtin/commit.c:1579 msgid "cannot update HEAD ref" msgstr "kunde inte uppdatera HEAD-referens" -#: builtin/commit.c:1587 +#: builtin/commit.c:1590 msgid "" "Repository has been updated, but unable to write\n" "new_index file. Check that disk is not full or quota is\n" @@ -2452,6 +3776,134 @@ msgstr "" "att kvoten inte har överskridits, och kör sedan\n" "\"git reset HEAD\" för att Ã¥terställa." +#: builtin/config.c:7 +msgid "git config [options]" +msgstr "git config [flaggor]" + +#: builtin/config.c:51 +msgid "Config file location" +msgstr "Konfigurationsfilens plats" + +#: builtin/config.c:52 +msgid "use global config file" +msgstr "använd global konfigurationsfil" + +#: builtin/config.c:53 +msgid "use system config file" +msgstr "använd systemets konfigurationsfil" + +#: builtin/config.c:54 +msgid "use repository config file" +msgstr "använd arkivets konfigurationsfil" + +#: builtin/config.c:55 +msgid "use given config file" +msgstr "använd angiven konfigurationsil" + +#: builtin/config.c:56 +msgid "Action" +msgstr "Ã…tgärd" + +#: builtin/config.c:57 +msgid "get value: name [value-regex]" +msgstr "hämta värde: namn [värde-reguttr]" + +#: builtin/config.c:58 +msgid "get all values: key [value-regex]" +msgstr "hämta alla värden: nyckel [värde-reguttr]" + +#: builtin/config.c:59 +msgid "get values for regexp: name-regex [value-regex]" +msgstr "hämta värden för reguttr: namn-reguttr [värde-reguttr]" + +#: builtin/config.c:60 +msgid "replace all matching variables: name value [value_regex]" +msgstr "ersätt alla motsvarande variabler: namn värde [värde-reguttr]" + +#: builtin/config.c:61 +msgid "add a new variable: name value" +msgstr "lägg till en ny variabel: namn värde" + +#: builtin/config.c:62 +msgid "remove a variable: name [value-regex]" +msgstr "ta bort en variabel: namn [värde-reguttr]" + +#: builtin/config.c:63 +msgid "remove all matches: name [value-regex]" +msgstr "ta bort alla träffar: namn [värde-reguttr]" + +#: builtin/config.c:64 +msgid "rename section: old-name new-name" +msgstr "byt namn pÃ¥ sektion: gammalt-namn nytt-namn" + +#: builtin/config.c:65 +msgid "remove a section: name" +msgstr "ta bort en sektion: namn" + +#: builtin/config.c:66 +msgid "list all" +msgstr "visa alla" + +#: builtin/config.c:67 +msgid "open an editor" +msgstr "öppna textredigeringsprogram" + +#: builtin/config.c:68 builtin/config.c:69 +msgid "slot" +msgstr "plats" + +#: builtin/config.c:68 +msgid "find the color configured: [default]" +msgstr "hitta den inställda färgen: [default]" + +#: builtin/config.c:69 +msgid "find the color setting: [stdout-is-tty]" +msgstr "hitta färginställningen: [stdout-is-tty]" + +#: builtin/config.c:70 +msgid "Type" +msgstr "Typ" + +#: builtin/config.c:71 +msgid "value is \"true\" or \"false\"" +msgstr "värdet är \"true\" eller \"false\"" + +#: builtin/config.c:72 +msgid "value is decimal number" +msgstr "värdet är ett decimalt tal" + +#: builtin/config.c:73 +msgid "value is --bool or --int" +msgstr "värdet är --bool eller --int" + +#: builtin/config.c:74 +msgid "value is a path (file or directory name)" +msgstr "värdet är en sökväg (fil- eller katalognamn)" + +#: builtin/config.c:75 +msgid "Other" +msgstr "Andra" + +#: builtin/config.c:76 +msgid "terminate values with NUL byte" +msgstr "terminera värden med NUL-byte" + +#: builtin/config.c:77 +msgid "respect include directives on lookup" +msgstr "respektera inkluderingsdirektiv vid uppslag" + +#: builtin/count-objects.c:69 +msgid "git count-objects [-v]" +msgstr "git count-objects [-v]" + +#: builtin/describe.c:15 +msgid "git describe [options] <committish>*" +msgstr "git describe [flaggor] <incheckning-igt>*" + +#: builtin/describe.c:16 +msgid "git describe [options] --dirty" +msgstr "git describe [flaggor] --dirty" + #: builtin/describe.c:234 #, c-format msgid "annotated tag %s not available" @@ -2524,6 +3976,50 @@ msgstr "" "mer än %i taggar hittades; listar de %i senaste\n" "gav upp sökningen vid %s\n" +#: builtin/describe.c:403 +msgid "find the tag that comes after the commit" +msgstr "hitta taggen som kommer efter incheckningen" + +#: builtin/describe.c:404 +msgid "debug search strategy on stderr" +msgstr "felsök sökstrategin pÃ¥ standard fel" + +#: builtin/describe.c:405 +msgid "use any ref in .git/refs" +msgstr "använd alla referenser i .git/refs" + +#: builtin/describe.c:406 +msgid "use any tag in .git/refs/tags" +msgstr "använd alla taggar i .git/refs/tags" + +#: builtin/describe.c:407 +msgid "always use long format" +msgstr "använd alltid lÃ¥ngt format" + +#: builtin/describe.c:410 +msgid "only output exact matches" +msgstr "skriv endast ut exakta träffar" + +#: builtin/describe.c:412 +msgid "consider <n> most recent tags (default: 10)" +msgstr "överväg de <n> nyaste taggarna (standard: 10)" + +#: builtin/describe.c:414 +msgid "only consider tags matching <pattern>" +msgstr "överväg endast taggar som motsvarar <mönster>" + +#: builtin/describe.c:416 builtin/name-rev.c:238 +msgid "show abbreviated commit object as fallback" +msgstr "visa förkortade incheckningsobjekt som standard" + +#: builtin/describe.c:417 +msgid "mark" +msgstr "märke" + +#: builtin/describe.c:418 +msgid "append <mark> on dirty working tree (default: \"-dirty\")" +msgstr "lägg till <märke> pÃ¥ lortigt arbetsträd (standard: \"-dirty\")" + #: builtin/describe.c:436 msgid "--long is incompatible with --abbrev=0" msgstr "--long är inkompatibel med --abbrev=0" @@ -2536,45 +4032,165 @@ msgstr "Inga namn hittades, kan inte beskriva nÃ¥got." msgid "--dirty is incompatible with committishes" msgstr "--dirty är inkompatibelt med \"committish\"-värden" -#: builtin/diff.c:77 +#: builtin/diff.c:79 #, c-format msgid "'%s': not a regular file or symlink" msgstr "\"%s\": inte en normal fil eller symbolisk länk" -#: builtin/diff.c:220 +#: builtin/diff.c:228 #, c-format msgid "invalid option: %s" msgstr "ogiltig flagga: %s" -#: builtin/diff.c:297 +#: builtin/diff.c:305 msgid "Not a git repository" msgstr "Inte ett git-arkiv" -#: builtin/diff.c:347 +#: builtin/diff.c:348 #, c-format msgid "invalid object '%s' given." msgstr "objektet \"%s\" som angavs är felaktigt." -#: builtin/diff.c:352 +#: builtin/diff.c:353 #, c-format msgid "more than %d trees given: '%s'" msgstr "mer än %d träd angavs: \"%s\"" -#: builtin/diff.c:362 +#: builtin/diff.c:363 #, c-format msgid "more than two blobs given: '%s'" msgstr "mer än tvÃ¥ blobbar angavs: \"%s\"" -#: builtin/diff.c:370 +#: builtin/diff.c:371 #, c-format msgid "unhandled object '%s' given." msgstr "ej hanterat objekt \"%s\" angavs." -#: builtin/fetch.c:200 +#: builtin/fast-export.c:22 +msgid "git fast-export [rev-list-opts]" +msgstr "git fast-export [rev-list-flaggor]" + +#: builtin/fast-export.c:635 +msgid "show progress after <n> objects" +msgstr "visa förlopp efter <n> objekt" + +#: builtin/fast-export.c:637 +msgid "select handling of signed tags" +msgstr "välj hantering av signerade taggar" + +#: builtin/fast-export.c:640 +msgid "select handling of tags that tag filtered objects" +msgstr "välj hantering av taggar som har taggfiltrerade objekt" + +#: builtin/fast-export.c:643 +msgid "Dump marks to this file" +msgstr "Dump märken till filen" + +#: builtin/fast-export.c:645 +msgid "Import marks from this file" +msgstr "Importera märken frÃ¥n filen" + +#: builtin/fast-export.c:647 +msgid "Fake a tagger when tags lack one" +msgstr "Fejka taggare när taggen saknar en" + +#: builtin/fast-export.c:649 +msgid "Output full tree for each commit" +msgstr "Skriv ut hela trädet för varje incheckning" + +#: builtin/fast-export.c:651 +msgid "Use the done feature to terminate the stream" +msgstr "Använd done-funktionen för att avsluta strömmen" + +#: builtin/fast-export.c:652 +msgid "Skip output of blob data" +msgstr "Hoppa över skrivning av blob-data" + +#: builtin/fetch.c:20 +msgid "git fetch [<options>] [<repository> [<refspec>...]]" +msgstr "git fetch [<flaggor>] [<arkiv> [<refspec>...]]" + +#: builtin/fetch.c:21 +msgid "git fetch [<options>] <group>" +msgstr "git fetch [<flaggor>] <grupp>" + +#: builtin/fetch.c:22 +msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]" +msgstr "git fetch --multiple [<flaggor>] [(<arkiv> | <grupp>)...]" + +#: builtin/fetch.c:23 +msgid "git fetch --all [<options>]" +msgstr "git fetch --all [<flaggor>]" + +#: builtin/fetch.c:60 +msgid "fetch from all remotes" +msgstr "hämta frÃ¥n alla fjärrar" + +#: builtin/fetch.c:62 +msgid "append to .git/FETCH_HEAD instead of overwriting" +msgstr "lägg till i .git/FETCH_HEAD istället för att skriva över" + +#: builtin/fetch.c:64 +msgid "path to upload pack on remote end" +msgstr "sökväg till upload pack pÃ¥ fjärren" + +#: builtin/fetch.c:65 +msgid "force overwrite of local branch" +msgstr "tvinga överskrivning av lokal gren" + +#: builtin/fetch.c:67 +msgid "fetch from multiple remotes" +msgstr "hämta frÃ¥n flera fjärrar" + +#: builtin/fetch.c:69 +msgid "fetch all tags and associated objects" +msgstr "hämta alla taggar och associerade objekt" + +#: builtin/fetch.c:71 +msgid "do not fetch all tags (--no-tags)" +msgstr "hämta inte alla taggar (--no-tags)" + +#: builtin/fetch.c:73 +msgid "prune remote-tracking branches no longer on remote" +msgstr "rensa fjärrspÃ¥rande grenar ej längre pÃ¥ fjärren" + +#: builtin/fetch.c:74 +msgid "on-demand" +msgstr "on-demand" + +#: builtin/fetch.c:75 +msgid "control recursive fetching of submodules" +msgstr "styr rekursiv hämtning av undermoduler" + +#: builtin/fetch.c:79 +msgid "keep downloaded pack" +msgstr "behÃ¥ll hämtade paket" + +#: builtin/fetch.c:81 +msgid "allow updating of HEAD ref" +msgstr "tillÃ¥t uppdatering av HEAD-referens" + +#: builtin/fetch.c:84 +msgid "deepen history of shallow clone" +msgstr "fördjupa historik för grund klon" + +#: builtin/fetch.c:85 builtin/log.c:1088 +msgid "dir" +msgstr "kat" + +#: builtin/fetch.c:86 +msgid "prepend this to submodule path output" +msgstr "lägg till i början av undermodulens sökvägsutdata" + +#: builtin/fetch.c:89 +msgid "default mode for recursion" +msgstr "standardläge för rekursion" + +#: builtin/fetch.c:201 msgid "Couldn't find remote ref HEAD" msgstr "Kunde inte hitta fjärr-referensen HEAD" -#: builtin/fetch.c:253 +#: builtin/fetch.c:254 #, c-format msgid "object %s not found" msgstr "objektet %s hittades inte" @@ -2686,17 +4302,17 @@ msgstr "Flaggan \"%s\" och värdet \"%s\" är inte giltigt för %s" msgid "Option \"%s\" is ignored for %s\n" msgstr "Flaggan \"%s\" ignoreras för %s\n" -#: builtin/fetch.c:888 +#: builtin/fetch.c:891 #, c-format msgid "Fetching %s\n" msgstr "Hämtar %s\n" -#: builtin/fetch.c:890 builtin/remote.c:100 +#: builtin/fetch.c:893 builtin/remote.c:100 #, c-format msgid "Could not fetch %s" msgstr "Kunde inte hämta %s" -#: builtin/fetch.c:907 +#: builtin/fetch.c:912 msgid "" "No remote repository specified. Please, specify either a URL or a\n" "remote name from which new revisions should be fetched." @@ -2704,27 +4320,146 @@ msgstr "" "Inget fjärrarkiv angavs. Ange antingen en URL eller namnet pÃ¥ ett\n" "fjärrarkiv som nya incheckningar skall hämtas frÃ¥n." -#: builtin/fetch.c:927 +#: builtin/fetch.c:932 msgid "You need to specify a tag name." msgstr "Du mÃ¥ste ange namnet pÃ¥ en tagg." -#: builtin/fetch.c:979 +#: builtin/fetch.c:984 msgid "fetch --all does not take a repository argument" msgstr "fetch --all tar inte namnet pÃ¥ ett arkiv som argument" -#: builtin/fetch.c:981 +#: builtin/fetch.c:986 msgid "fetch --all does not make sense with refspecs" msgstr "fetch --all kan inte anges med referensspecifikationer" -#: builtin/fetch.c:992 +#: builtin/fetch.c:997 #, c-format msgid "No such remote or remote group: %s" msgstr "Fjärren eller fjärrgruppen finns inte: %s" -#: builtin/fetch.c:1000 +#: builtin/fetch.c:1005 msgid "Fetching a group and specifying refspecs does not make sense" msgstr "Kan inte hämta frÃ¥n grupp och ange referensspecifikationer" +#: builtin/fmt-merge-msg.c:13 +msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]" +msgstr "" +"git fmt-merge-msg [-m <meddelande>] [--log[=<n>]|--no-log] [--file <fil>]" + +#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:701 +#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175 +#: builtin/tag.c:448 parse-options.h:133 parse-options.h:235 +msgid "n" +msgstr "n" + +#: builtin/fmt-merge-msg.c:654 +msgid "populate log with at most <n> entries from shortlog" +msgstr "fyll i loggen med som mest <n> poster frÃ¥n shortlog" + +#: builtin/fmt-merge-msg.c:657 +msgid "alias for --log (deprecated)" +msgstr "alias för --log (avrÃ¥ds)" + +#: builtin/fmt-merge-msg.c:660 +msgid "text" +msgstr "text" + +#: builtin/fmt-merge-msg.c:661 +msgid "use <text> as start of message" +msgstr "inled meddelande med <text>" + +#: builtin/fmt-merge-msg.c:662 +msgid "file to read from" +msgstr "fil att läsa frÃ¥n" + +#: builtin/for-each-ref.c:979 +msgid "git for-each-ref [options] [<pattern>]" +msgstr "git for-each-ref [flaggor] [<mönster>]" + +#: builtin/for-each-ref.c:994 +msgid "quote placeholders suitably for shells" +msgstr "citera platshÃ¥llare passande för skal" + +#: builtin/for-each-ref.c:996 +msgid "quote placeholders suitably for perl" +msgstr "citera platshÃ¥llare passande för perl" + +#: builtin/for-each-ref.c:998 +msgid "quote placeholders suitably for python" +msgstr "citera platshÃ¥llare passande för python" + +#: builtin/for-each-ref.c:1000 +msgid "quote placeholders suitably for tcl" +msgstr "citera platshÃ¥llare passande för tcl" + +#: builtin/for-each-ref.c:1003 +msgid "show only <n> matched refs" +msgstr "visa endast <n> träffade refs" + +#: builtin/for-each-ref.c:1004 +msgid "format" +msgstr "format" + +#: builtin/for-each-ref.c:1004 +msgid "format to use for the output" +msgstr "format att använda för utdata" + +#: builtin/for-each-ref.c:1005 +msgid "key" +msgstr "nyckel" + +#: builtin/for-each-ref.c:1006 +msgid "field name to sort on" +msgstr "fältnamn att sortera pÃ¥" + +#: builtin/fsck.c:608 +msgid "git fsck [options] [<object>...]" +msgstr "git fsck [flaggor] [<objekt>...]" + +#: builtin/fsck.c:614 +msgid "show unreachable objects" +msgstr "visa onÃ¥bara objekt" + +#: builtin/fsck.c:615 +msgid "show dangling objects" +msgstr "visa dinglande objekt" + +#: builtin/fsck.c:616 +msgid "report tags" +msgstr "rapportera taggar" + +#: builtin/fsck.c:617 +msgid "report root nodes" +msgstr "rapportera rotnoder" + +#: builtin/fsck.c:618 +msgid "make index objects head nodes" +msgstr "gör indexojekt till huvudnoder" + +#: builtin/fsck.c:619 +msgid "make reflogs head nodes (default)" +msgstr "gör refloggar till huvudnoder (standard)" + +#: builtin/fsck.c:620 +msgid "also consider packs and alternate objects" +msgstr "ta även hänsyn till paket och alternativa objekt" + +#: builtin/fsck.c:621 +msgid "enable more strict checking" +msgstr "aktivera striktare kontroll" + +#: builtin/fsck.c:623 +msgid "write dangling objects in .git/lost-found" +msgstr "skriv dinglande objekt i .git/lost-found" + +#: builtin/fsck.c:624 builtin/prune.c:134 +msgid "show progress" +msgstr "visa förlopp" + +#: builtin/gc.c:22 +msgid "git gc [options]" +msgstr "git gc [flaggor]" + #: builtin/gc.c:63 #, c-format msgid "Invalid %s: '%s'" @@ -2735,12 +4470,19 @@ msgstr "Felaktigt %s: \"%s\"" msgid "insanely long object directory %.*s" msgstr "tokigt lÃ¥ng objektkatalog %.*s" -#: builtin/gc.c:221 -#, c-format -msgid "Auto packing the repository for optimum performance.\n" -msgstr "Packar arkivet automatiskt för optimal prestanda.\n" +#: builtin/gc.c:179 +msgid "prune unreferenced objects" +msgstr "rensa ej refererade objekt" + +#: builtin/gc.c:181 +msgid "be more thorough (increased runtime)" +msgstr "var mer grundlig (ökar körtiden)" + +#: builtin/gc.c:182 +msgid "enable auto-gc mode" +msgstr "aktivera auto-gc-läge" -#: builtin/gc.c:224 +#: builtin/gc.c:222 #, c-format msgid "" "Auto packing the repository for optimum performance. You may also\n" @@ -2749,96 +4491,324 @@ msgstr "" "Packar arkivet automatiskt för optimal prestanda. Du kan även\n" "köra \"git gc\" manuellt. Se \"git help gc\" för mer information.\n" -#: builtin/gc.c:251 +#: builtin/gc.c:249 msgid "" "There are too many unreachable loose objects; run 'git prune' to remove them." msgstr "" "Det finns för mÃ¥nga onÃ¥bara lösa objekt; kör \"git prune\" för att ta bort " "dem." -#: builtin/grep.c:216 +#: builtin/grep.c:22 +msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]" +msgstr "git grep [flaggor] [-e] <mönster> [<rev>...] [[--] <sökväg>...]" + +#: builtin/grep.c:217 #, c-format msgid "grep: failed to create thread: %s" msgstr "grep: misslyckades skapa trÃ¥d. %s" -#: builtin/grep.c:402 +#: builtin/grep.c:365 #, c-format msgid "Failed to chdir: %s" msgstr "Kunde inte byta katalog (chdir): %s" -#: builtin/grep.c:478 builtin/grep.c:512 +#: builtin/grep.c:443 builtin/grep.c:478 #, c-format msgid "unable to read tree (%s)" msgstr "kunde inte läsa träd (%s)" -#: builtin/grep.c:526 +#: builtin/grep.c:493 #, c-format msgid "unable to grep from object of type %s" msgstr "Kunde inte \"grep\" frÃ¥n objekt av typen %s" -#: builtin/grep.c:584 +#: builtin/grep.c:551 #, c-format msgid "switch `%c' expects a numerical value" msgstr "flaggan \"%c\" antar ett numeriskt värde" -#: builtin/grep.c:601 +#: builtin/grep.c:568 #, c-format msgid "cannot open '%s'" msgstr "kan inte öppna \"%s\"" -#: builtin/grep.c:885 +#: builtin/grep.c:643 +msgid "search in index instead of in the work tree" +msgstr "sök i indexet istället för i arbetskatalogen" + +#: builtin/grep.c:645 +msgid "find in contents not managed by git" +msgstr "sök i innehÃ¥l som inte hanteras av git" + +#: builtin/grep.c:647 +msgid "search in both tracked and untracked files" +msgstr "sök i bÃ¥de spÃ¥rade och ospÃ¥rade filer" + +#: builtin/grep.c:649 +msgid "search also in ignored files" +msgstr "sök även i ignorerade filer" + +#: builtin/grep.c:652 +msgid "show non-matching lines" +msgstr "vis rader som inte träffas" + +#: builtin/grep.c:654 +msgid "case insensitive matching" +msgstr "skiftlägesokänslig sökning" + +#: builtin/grep.c:656 +msgid "match patterns only at word boundaries" +msgstr "matcha endast mönster vid ordgränser" + +#: builtin/grep.c:658 +msgid "process binary files as text" +msgstr "hantera binärfiler som text" + +#: builtin/grep.c:660 +msgid "don't match patterns in binary files" +msgstr "träffa inte mönster i binärfiler" + +#: builtin/grep.c:663 +msgid "descend at most <depth> levels" +msgstr "gÃ¥ som mest ned <djup> nivÃ¥er" + +#: builtin/grep.c:667 +msgid "use extended POSIX regular expressions" +msgstr "använd utökade POSIX-reguljära uttryck" + +#: builtin/grep.c:670 +msgid "use basic POSIX regular expressions (default)" +msgstr "använd grundläggande POSIX-reguljära uttryck (standard)" + +#: builtin/grep.c:673 +msgid "interpret patterns as fixed strings" +msgstr "tolka mönster som fixerade strängar" + +#: builtin/grep.c:676 +msgid "use Perl-compatible regular expressions" +msgstr "använd Perlkompatibla reguljära uttryck" + +#: builtin/grep.c:679 +msgid "show line numbers" +msgstr "visa radnummer" + +#: builtin/grep.c:680 +msgid "don't show filenames" +msgstr "visa inte filnamn" + +#: builtin/grep.c:681 +msgid "show filenames" +msgstr "visa filnamn" + +#: builtin/grep.c:683 +msgid "show filenames relative to top directory" +msgstr "visa filnamn relativa till toppkatalogen" + +#: builtin/grep.c:685 +msgid "show only filenames instead of matching lines" +msgstr "visa endast filnamn istället för träffade rader" + +#: builtin/grep.c:687 +msgid "synonym for --files-with-matches" +msgstr "synonym för --files-with-matches" + +#: builtin/grep.c:690 +msgid "show only the names of files without match" +msgstr "visa endast namn pÃ¥ filer utan träffar" + +#: builtin/grep.c:692 +msgid "print NUL after filenames" +msgstr "skriv NUL efter filnamn" + +#: builtin/grep.c:694 +msgid "show the number of matches instead of matching lines" +msgstr "visa antal träffar istället för träffade rader" + +#: builtin/grep.c:695 +msgid "highlight matches" +msgstr "ljusmarkera träffar" + +#: builtin/grep.c:697 +msgid "print empty line between matches from different files" +msgstr "skriv tomma rader mellan träffar frÃ¥n olika filer" + +#: builtin/grep.c:699 +msgid "show filename only once above matches from same file" +msgstr "visa filnamn endast en gÃ¥ng ovanför träffar frÃ¥n samma fil" + +#: builtin/grep.c:702 +msgid "show <n> context lines before and after matches" +msgstr "visa <n> rader sammanhang före och efter träffar" + +#: builtin/grep.c:705 +msgid "show <n> context lines before matches" +msgstr "visa <n> rader sammanhang före träffar" + +#: builtin/grep.c:707 +msgid "show <n> context lines after matches" +msgstr "visa <n> rader sammanhang efter träffar" + +#: builtin/grep.c:708 +msgid "shortcut for -C NUM" +msgstr "genväg för -C NUM" + +#: builtin/grep.c:711 +msgid "show a line with the function name before matches" +msgstr "visa en rad med funktionsnamnet före träffen" + +#: builtin/grep.c:713 +msgid "show the surrounding function" +msgstr "visa den omkringliggande funktionen" + +#: builtin/grep.c:716 +msgid "read patterns from file" +msgstr "läs mönster frÃ¥n fil" + +#: builtin/grep.c:718 +msgid "match <pattern>" +msgstr "träffa <mönster>" + +#: builtin/grep.c:720 +msgid "combine patterns specified with -e" +msgstr "kombinera mönster som anges med -e" + +#: builtin/grep.c:732 +msgid "indicate hit with exit status without output" +msgstr "ange träff med slutstatuskod utan utdata" + +#: builtin/grep.c:734 +msgid "show only matches from files that match all patterns" +msgstr "visa endast träffar frÃ¥n filer som träffar alla mönster" + +#: builtin/grep.c:736 +msgid "show parse tree for grep expression" +msgstr "visa analysträd för grep-uttryck" + +#: builtin/grep.c:740 +msgid "pager" +msgstr "bläddrare" + +#: builtin/grep.c:740 +msgid "show matching files in the pager" +msgstr "visa träffade filer i filbläddraren" + +#: builtin/grep.c:743 +msgid "allow calling of grep(1) (ignored by this build)" +msgstr "tillÃ¥t anropa grep(1) (ignoreras av detta bygge)" + +#: builtin/grep.c:744 builtin/show-ref.c:184 +msgid "show usage" +msgstr "visa användning" + +#: builtin/grep.c:811 msgid "no pattern given." msgstr "inget mönster angavs." -#: builtin/grep.c:899 +#: builtin/grep.c:825 #, c-format msgid "bad object %s" msgstr "felaktigt objekt %s" -#: builtin/grep.c:940 +#: builtin/grep.c:866 msgid "--open-files-in-pager only works on the worktree" msgstr "--open-files-in-pager fungerar endast i arbetskatalogen" -#: builtin/grep.c:963 +#: builtin/grep.c:889 msgid "--cached or --untracked cannot be used with --no-index." msgstr "--cached och --untracked kan inte användas med --no-index." -#: builtin/grep.c:968 +#: builtin/grep.c:894 msgid "--no-index or --untracked cannot be used with revs." msgstr "--no-index och --untracked kan inte användas med revisioner." -#: builtin/grep.c:971 +#: builtin/grep.c:897 msgid "--[no-]exclude-standard cannot be used for tracked contents." msgstr "--[no-]exclude-standard kan inte användas för spÃ¥rat innehÃ¥ll." -#: builtin/grep.c:979 +#: builtin/grep.c:905 msgid "both --cached and trees are given." msgstr "bÃ¥de --cached och träd angavs." -#: builtin/help.c:59 +#: builtin/hash-object.c:60 +msgid "" +"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] " +"<file>..." +msgstr "" +"git hash-object [-t <typ>] [-w] [--path=<fil>|--no-filters] [--stdin] [--] " +"<fil>..." + +#: builtin/hash-object.c:61 +msgid "git hash-object --stdin-paths < <list-of-paths>" +msgstr "git hash-object --stdin-paths < <sökvägslista>" + +#: builtin/hash-object.c:72 +msgid "type" +msgstr "typ" + +#: builtin/hash-object.c:72 +msgid "object type" +msgstr "objekttyp" + +#: builtin/hash-object.c:73 +msgid "write the object into the object database" +msgstr "skriv objektet till objektdatabasen" + +#: builtin/hash-object.c:74 +msgid "read the object from stdin" +msgstr "läs objektet frÃ¥n standard in" + +#: builtin/hash-object.c:76 +msgid "store file as is without filters" +msgstr "spara filen som den är utan filer" + +#: builtin/hash-object.c:77 +msgid "process file as it were from this path" +msgstr "hantera filen som om den kom frÃ¥n sökvägen" + +#: builtin/help.c:43 +msgid "print all available commands" +msgstr "visa alla tillgängliga kommandon" + +#: builtin/help.c:44 +msgid "show man page" +msgstr "visa manualsida" + +#: builtin/help.c:45 +msgid "show manual in web browser" +msgstr "visa manual i webbläsare" + +#: builtin/help.c:47 +msgid "show info page" +msgstr "visa info-sida" + +#: builtin/help.c:53 +msgid "git help [--all] [--man|--web|--info] [command]" +msgstr "git help [--all] [--man|--web|--info] [kommando]" + +#: builtin/help.c:65 #, c-format msgid "unrecognized help format '%s'" msgstr "okänt hjälpformat: %s" -#: builtin/help.c:87 +#: builtin/help.c:93 msgid "Failed to start emacsclient." msgstr "Misslyckades starta emacsclient." -#: builtin/help.c:100 +#: builtin/help.c:106 msgid "Failed to parse emacsclient version." msgstr "Kunde inte tolka emacsclient-version." -#: builtin/help.c:108 +#: builtin/help.c:114 #, c-format msgid "emacsclient version '%d' too old (< 22)." msgstr "emacsclient version \"%d\" för gammal (< 22)." -#: builtin/help.c:126 builtin/help.c:154 builtin/help.c:163 builtin/help.c:171 +#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177 #, c-format msgid "failed to exec '%s': %s" msgstr "exec misslyckades för \"%s\": %s" -#: builtin/help.c:211 +#: builtin/help.c:217 #, c-format msgid "" "'%s': path for unsupported man viewer.\n" @@ -2847,7 +4817,7 @@ msgstr "" "\"%s\": sökväg för man-visare som ej stöds.\n" "Använd \"man.<verktyg>.cmd\" istället." -#: builtin/help.c:223 +#: builtin/help.c:229 #, c-format msgid "" "'%s': cmd for supported man viewer.\n" @@ -2856,266 +4826,307 @@ msgstr "" "\"%s\": kommando för man-visare som stöds.\n" "Använd \"man.<verktyg>.path\" istället." -#: builtin/help.c:287 +#: builtin/help.c:299 msgid "The most commonly used git commands are:" msgstr "De mest använda git-kommandona är:" -#: builtin/help.c:355 +#: builtin/help.c:367 #, c-format msgid "'%s': unknown man viewer." msgstr "\"%s\": okänd man-visare." -#: builtin/help.c:372 +#: builtin/help.c:384 msgid "no man viewer handled the request" msgstr "ingen man-visare hanterade förfrÃ¥gan" -#: builtin/help.c:380 +#: builtin/help.c:392 msgid "no info viewer handled the request" msgstr "ingen info-visare hanterade förfrÃ¥gan" -#: builtin/help.c:391 -#, c-format -msgid "'%s': not a documentation directory." -msgstr "\"%s\": inte en dokumentationskatalog." - -#: builtin/help.c:432 builtin/help.c:439 +#: builtin/help.c:447 builtin/help.c:454 #, c-format msgid "usage: %s%s" msgstr "användning: %s%s" -#: builtin/help.c:453 +#: builtin/help.c:470 #, c-format msgid "`git %s' is aliased to `%s'" msgstr "\"git %s\" är ett alias för \"%s\"" -#: builtin/index-pack.c:169 +#: builtin/index-pack.c:170 #, c-format msgid "object type mismatch at %s" msgstr "objekttyp stämmer inte överens vid %s" -#: builtin/index-pack.c:189 +#: builtin/index-pack.c:190 msgid "object of unexpected type" msgstr "objekt av oväntad typ" -#: builtin/index-pack.c:226 +#: builtin/index-pack.c:227 #, c-format msgid "cannot fill %d byte" msgid_plural "cannot fill %d bytes" msgstr[0] "kan inte fylla %d byte" msgstr[1] "kan inte fylla %d byte" -#: builtin/index-pack.c:236 +#: builtin/index-pack.c:237 msgid "early EOF" msgstr "tidigt filslut" -#: builtin/index-pack.c:237 +#: builtin/index-pack.c:238 msgid "read error on input" msgstr "indataläsfel" -#: builtin/index-pack.c:249 +#: builtin/index-pack.c:250 msgid "used more bytes than were available" msgstr "använde fler byte än tillgängligt" -#: builtin/index-pack.c:256 +#: builtin/index-pack.c:257 msgid "pack too large for current definition of off_t" msgstr "paket för stort för nuvarande definition av off_t" -#: builtin/index-pack.c:272 +#: builtin/index-pack.c:273 #, c-format msgid "unable to create '%s'" msgstr "kunde inte skapa \"%s\"" -#: builtin/index-pack.c:277 +#: builtin/index-pack.c:278 #, c-format msgid "cannot open packfile '%s'" msgstr "kan inte öppna paketfilen \"%s\"" -#: builtin/index-pack.c:291 +#: builtin/index-pack.c:292 msgid "pack signature mismatch" msgstr "paketsignatur stämmer inte överens" -#: builtin/index-pack.c:311 +#: builtin/index-pack.c:294 +#, c-format +msgid "pack version %<PRIu32> unsupported" +msgstr "paketversion %<PRIu32> stöds ej" + +#: builtin/index-pack.c:312 #, c-format msgid "pack has bad object at offset %lu: %s" msgstr "paketet har felaktigt objekt vid index %lu: %s" -#: builtin/index-pack.c:405 +#: builtin/index-pack.c:434 #, c-format msgid "inflate returned %d" msgstr "inflate returnerade %d" -#: builtin/index-pack.c:450 +#: builtin/index-pack.c:483 msgid "offset value overflow for delta base object" msgstr "indexvärdespill för deltabasobjekt" -#: builtin/index-pack.c:458 +#: builtin/index-pack.c:491 msgid "delta base offset is out of bound" msgstr "deltabasindex utanför gränsen" -#: builtin/index-pack.c:466 +#: builtin/index-pack.c:499 #, c-format msgid "unknown object type %d" msgstr "okänd objekttyp %d" -#: builtin/index-pack.c:495 +#: builtin/index-pack.c:530 msgid "cannot pread pack file" msgstr "kan inte utföra \"pread\" pÃ¥ paketfil" -#: builtin/index-pack.c:497 +#: builtin/index-pack.c:532 #, c-format msgid "premature end of pack file, %lu byte missing" msgid_plural "premature end of pack file, %lu bytes missing" msgstr[0] "för tidigt slut pÃ¥ paketfilen, %lu byte saknas" msgstr[1] "för tidigt slut pÃ¥ paketfilen, %lu byte saknas" -#: builtin/index-pack.c:510 +#: builtin/index-pack.c:558 msgid "serious inflate inconsistency" msgstr "allvarlig inflate-inkonsekvens" -#: builtin/index-pack.c:583 -#, c-format -msgid "cannot read existing object %s" -msgstr "kan inte läsa befintligt objekt %s" - -#: builtin/index-pack.c:586 +#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678 +#: builtin/index-pack.c:712 builtin/index-pack.c:721 #, c-format msgid "SHA1 COLLISION FOUND WITH %s !" msgstr "SHA1-KOLLISION UPPTÄCKT VID %s !" -#: builtin/index-pack.c:598 +#: builtin/index-pack.c:652 builtin/pack-objects.c:170 +#: builtin/pack-objects.c:262 +#, c-format +msgid "unable to read %s" +msgstr "kunde inte läsa %s" + +#: builtin/index-pack.c:718 +#, c-format +msgid "cannot read existing object %s" +msgstr "kan inte läsa befintligt objekt %s" + +#: builtin/index-pack.c:732 #, c-format msgid "invalid blob object %s" msgstr "ogiltigt blob-objekt %s" -#: builtin/index-pack.c:610 +#: builtin/index-pack.c:747 #, c-format msgid "invalid %s" msgstr "ogiltigt %s" -#: builtin/index-pack.c:612 +#: builtin/index-pack.c:749 msgid "Error in object" msgstr "Fel i objekt" -#: builtin/index-pack.c:614 +#: builtin/index-pack.c:751 #, c-format msgid "Not all child objects of %s are reachable" msgstr "Inte alla barnobjekt för %s kan nÃ¥s" -#: builtin/index-pack.c:687 builtin/index-pack.c:713 +#: builtin/index-pack.c:821 builtin/index-pack.c:847 msgid "failed to apply delta" msgstr "misslyckades tillämpa delta" -#: builtin/index-pack.c:850 +#: builtin/index-pack.c:986 msgid "Receiving objects" -msgstr "Tar bort objeckt" +msgstr "Tar emot objekt" -#: builtin/index-pack.c:850 +#: builtin/index-pack.c:986 msgid "Indexing objects" msgstr "Skapar index för objekt" -#: builtin/index-pack.c:872 +#: builtin/index-pack.c:1012 msgid "pack is corrupted (SHA1 mismatch)" msgstr "paketet är trasigt (SHA1 stämmer inte)" -#: builtin/index-pack.c:877 +#: builtin/index-pack.c:1017 msgid "cannot fstat packfile" msgstr "kan inte utföra \"fstat\" pÃ¥ paketfil" -#: builtin/index-pack.c:880 +#: builtin/index-pack.c:1020 msgid "pack has junk at the end" msgstr "paket har skräp i slutet" -#: builtin/index-pack.c:903 +#: builtin/index-pack.c:1031 +msgid "confusion beyond insanity in parse_pack_objects()" +msgstr "förvirrad bortom vanvett i parse_pack_objects()" + +#: builtin/index-pack.c:1054 msgid "Resolving deltas" msgstr "Analyserar delta" -#: builtin/index-pack.c:954 +#: builtin/index-pack.c:1064 +#, c-format +msgid "unable to create thread: %s" +msgstr "kunde inte skapa trÃ¥d: %s" + +#: builtin/index-pack.c:1106 msgid "confusion beyond insanity" msgstr "förvirrad bortom vanvett" -#: builtin/index-pack.c:973 +#: builtin/index-pack.c:1112 +#, c-format +msgid "completed with %d local objects" +msgstr "slutfördes med %d lokala objekt" + +#: builtin/index-pack.c:1121 +#, c-format +msgid "Unexpected tail checksum for %s (disk corruption?)" +msgstr "Oväntad svanschecksumma för %s (trasig disk?)" + +#: builtin/index-pack.c:1125 #, c-format msgid "pack has %d unresolved delta" msgid_plural "pack has %d unresolved deltas" msgstr[0] "paketet har %d oanalyserat delta" msgstr[1] "paketet har %d oanalyserade delta" -#: builtin/index-pack.c:998 +#: builtin/index-pack.c:1150 #, c-format msgid "unable to deflate appended object (%d)" msgstr "kunde inte utföra \"deflate\" pÃ¥ tillagt objekt (%d)" -#: builtin/index-pack.c:1077 +#: builtin/index-pack.c:1229 #, c-format msgid "local object %s is corrupt" msgstr "lokalt objekt %s är trasigt" -#: builtin/index-pack.c:1101 +#: builtin/index-pack.c:1253 msgid "error while closing pack file" msgstr "fel vid stängning av paketfil" -#: builtin/index-pack.c:1114 +#: builtin/index-pack.c:1266 #, c-format msgid "cannot write keep file '%s'" msgstr "kan inte ta skriva \"keep\"-fil \"%s\"" -#: builtin/index-pack.c:1122 +#: builtin/index-pack.c:1274 #, c-format msgid "cannot close written keep file '%s'" msgstr "akn inte stänga skriven \"keep\"-fil \"%s\"" -#: builtin/index-pack.c:1135 +#: builtin/index-pack.c:1287 msgid "cannot store pack file" msgstr "kan inte spara paketfil" -#: builtin/index-pack.c:1146 +#: builtin/index-pack.c:1298 msgid "cannot store index file" msgstr "kan inte spara indexfil" -#: builtin/index-pack.c:1247 +#: builtin/index-pack.c:1331 +#, c-format +msgid "bad pack.indexversion=%<PRIu32>" +msgstr "felaktig pack.indexversion=%<PRIu32>" + +#: builtin/index-pack.c:1337 +#, c-format +msgid "invalid number of threads specified (%d)" +msgstr "felaktigt antal trÃ¥dar angivet (%d)" + +#: builtin/index-pack.c:1341 builtin/index-pack.c:1514 +#, c-format +msgid "no threads support, ignoring %s" +msgstr "trÃ¥dstöd saknas, ignorerar %s" + +#: builtin/index-pack.c:1399 #, c-format msgid "Cannot open existing pack file '%s'" msgstr "Kan inte öppna befintlig paketfil \"%s\"" -#: builtin/index-pack.c:1249 +#: builtin/index-pack.c:1401 #, c-format msgid "Cannot open existing pack idx file for '%s'" msgstr "Kan inte öppna befintligt paket-idx-fil för \"%s\"" -#: builtin/index-pack.c:1296 +#: builtin/index-pack.c:1448 #, c-format msgid "non delta: %d object" msgid_plural "non delta: %d objects" msgstr[0] "icke-delta: %d objekt" msgstr[1] "icke-delta: %d objekt" -#: builtin/index-pack.c:1303 +#: builtin/index-pack.c:1455 #, c-format msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" msgstr[0] "kedjelängd = %d: %lu objekt" msgstr[1] "kedjelängd = %d: %lu objekt" -#: builtin/index-pack.c:1330 +#: builtin/index-pack.c:1482 msgid "Cannot come back to cwd" msgstr "Kan inte gÃ¥ tillbaka till arbetskatalogen (cwd)" -#: builtin/index-pack.c:1374 builtin/index-pack.c:1377 -#: builtin/index-pack.c:1389 builtin/index-pack.c:1393 +#: builtin/index-pack.c:1526 builtin/index-pack.c:1529 +#: builtin/index-pack.c:1541 builtin/index-pack.c:1545 #, c-format msgid "bad %s" msgstr "felaktig %s" -#: builtin/index-pack.c:1407 +#: builtin/index-pack.c:1559 msgid "--fix-thin cannot be used without --stdin" msgstr "--fix-thin kan inte användas med --stdin" -#: builtin/index-pack.c:1411 builtin/index-pack.c:1421 +#: builtin/index-pack.c:1563 builtin/index-pack.c:1573 #, c-format msgid "packfile name '%s' does not end with '.pack'" msgstr "paketfilnamnet \"%s\" slutar inte med \".pack\"" -#: builtin/index-pack.c:1430 +#: builtin/index-pack.c:1582 msgid "--verify with no packfile name given" msgstr "--verify angavs utan paketfilnamn" @@ -3189,22 +5200,22 @@ msgstr "kopierade inte mallar frÃ¥n felaktig formatversion %d frÃ¥n \"%s\"" msgid "insane git directory %s" msgstr "tokig git-katalog %s" -#: builtin/init-db.c:322 builtin/init-db.c:325 +#: builtin/init-db.c:323 builtin/init-db.c:326 #, c-format msgid "%s already exists" msgstr "%s finns redan" -#: builtin/init-db.c:354 +#: builtin/init-db.c:355 #, c-format msgid "unable to handle file type %d" msgstr "kan inte hantera filtyp %d" -#: builtin/init-db.c:357 +#: builtin/init-db.c:358 #, c-format msgid "unable to move %s to %s" msgstr "kan inte flytta %s till %s" -#: builtin/init-db.c:362 +#: builtin/init-db.c:363 #, c-format msgid "Could not create git link %s" msgstr "Kunde inte skapa gitlänk %s" @@ -3214,38 +5225,58 @@ msgstr "Kunde inte skapa gitlänk %s" #. * existing" or "Initialized empty", the second " shared" or #. * "", and the last '%s%s' is the verbatim directory name. #. -#: builtin/init-db.c:419 +#: builtin/init-db.c:420 #, c-format msgid "%s%s Git repository in %s%s\n" msgstr "%s%s Git-arkiv i %s%s\n" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Reinitialized existing" msgstr "Ominitierade befintligt" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Initialized empty" msgstr "Initierade tomt" -#: builtin/init-db.c:421 +#: builtin/init-db.c:422 msgid " shared" msgstr " delat" -#: builtin/init-db.c:440 +#: builtin/init-db.c:441 msgid "cannot tell cwd" msgstr "kan inte läsa aktuell katalog (cwd)" -#: builtin/init-db.c:521 builtin/init-db.c:528 +#: builtin/init-db.c:467 +msgid "" +"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared" +"[=<permissions>]] [directory]" +msgstr "" +"git init [-q | --quiet] [--bare] [--template=<mallkatalog>] [--shared" +"[=<behörigheter>]] [katalog]" + +#: builtin/init-db.c:490 +msgid "permissions" +msgstr "behörigheter" + +#: builtin/init-db.c:491 +msgid "specify that the git repository is to be shared amongst several users" +msgstr "ange att git-arkivet skall delas bland flera användare" + +#: builtin/init-db.c:493 builtin/prune-packed.c:77 +msgid "be quiet" +msgstr "var tyst" + +#: builtin/init-db.c:522 builtin/init-db.c:529 #, c-format msgid "cannot mkdir %s" msgstr "kan inte skapa katalogen (mkdir) %s" -#: builtin/init-db.c:532 +#: builtin/init-db.c:533 #, c-format msgid "cannot chdir to %s" msgstr "kan inte byta katalog (chdir) till %s" -#: builtin/init-db.c:554 +#: builtin/init-db.c:555 #, c-format msgid "" "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" @@ -3254,113 +5285,397 @@ msgstr "" "%s (eller --work-tree=<katalog>) inte tillÃ¥tet utan att ange %s (eller --git-" "dir=<katalog>)" -#: builtin/init-db.c:578 +#: builtin/init-db.c:579 msgid "Cannot access current working directory" msgstr "Kan inte komma Ã¥t aktuell arbetskatalog" -#: builtin/init-db.c:585 +#: builtin/init-db.c:586 #, c-format msgid "Cannot access work tree '%s'" msgstr "Kan inte komma Ã¥t arbetskatalogen \"%s\"" -#: builtin/log.c:188 +#: builtin/log.c:37 +msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n" +msgstr "git log [<flaggor>] [<sedan>..<till>] [[--] <sökväg>...]\n" + +#: builtin/log.c:38 +msgid " or: git show [options] <object>..." +msgstr " eller: git show [flaggor] <objekt>..." + +#: builtin/log.c:100 +msgid "suppress diff output" +msgstr "undertryck diff-utdata" + +#: builtin/log.c:101 +msgid "show source" +msgstr "visa källkod" + +#: builtin/log.c:102 +msgid "decorate options" +msgstr "dekoreringsflaggor" + +#: builtin/log.c:189 #, c-format msgid "Final output: %d %s\n" msgstr "Slututdata: %d %s\n" -#: builtin/log.c:401 builtin/log.c:489 +#: builtin/log.c:405 builtin/log.c:497 #, c-format msgid "Could not read object %s" msgstr "Kunde inte läsa objektet %s" -#: builtin/log.c:513 +#: builtin/log.c:521 #, c-format msgid "Unknown type: %d" msgstr "Okänd typ: %d" -#: builtin/log.c:602 +#: builtin/log.c:613 msgid "format.headers without value" msgstr "format.headers utan värde" -#: builtin/log.c:676 +#: builtin/log.c:687 msgid "name of output directory is too long" msgstr "namnet pÃ¥ utdatakatalogen är för lÃ¥ngt" -#: builtin/log.c:687 +#: builtin/log.c:698 #, c-format msgid "Cannot open patch file %s" msgstr "Kan inte öppna patchfilen %s" -#: builtin/log.c:701 +#: builtin/log.c:712 msgid "Need exactly one range." msgstr "Behöver precis ett intervall." -#: builtin/log.c:709 +#: builtin/log.c:720 msgid "Not a range." msgstr "Inte ett intervall." -#: builtin/log.c:786 +#: builtin/log.c:794 msgid "Cover letter needs email format" msgstr "Omslagsbrevet behöver e-postformat" -#: builtin/log.c:859 +#: builtin/log.c:867 #, c-format msgid "insane in-reply-to: %s" msgstr "tokigt in-reply-to: %s" -#: builtin/log.c:932 +#: builtin/log.c:895 +msgid "git format-patch [options] [<since> | <revision range>]" +msgstr "git format-patch [flaggor] [<sedan> | <revisionsintervall>]" + +#: builtin/log.c:940 msgid "Two output directories?" msgstr "TvÃ¥ utdatakataloger?" -#: builtin/log.c:1153 +#: builtin/log.c:1068 +msgid "use [PATCH n/m] even with a single patch" +msgstr "använd [PATCH n/m] även för en ensam patch" + +#: builtin/log.c:1071 +msgid "use [PATCH] even with multiple patches" +msgstr "använd [PATCH] även för flera patchar" + +#: builtin/log.c:1075 +msgid "print patches to standard out" +msgstr "skriv patcharna pÃ¥ stnadard ut" + +#: builtin/log.c:1077 +msgid "generate a cover letter" +msgstr "generera ett följebrev" + +#: builtin/log.c:1079 +msgid "use simple number sequence for output file names" +msgstr "använd enkel nummersekvens för utdatafilnamn" + +#: builtin/log.c:1080 +msgid "sfx" +msgstr "sfx" + +#: builtin/log.c:1081 +msgid "use <sfx> instead of '.patch'" +msgstr "använd <sfx> istället för \".patch\"" + +#: builtin/log.c:1083 +msgid "start numbering patches at <n> instead of 1" +msgstr "börja numrera patchar pÃ¥ <n> istället för 1" + +#: builtin/log.c:1085 +msgid "Use [<prefix>] instead of [PATCH]" +msgstr "Använd [<prefix>] istället för [PATCH]" + +#: builtin/log.c:1088 +msgid "store resulting files in <dir>" +msgstr "spara filerna i <katalog>" + +#: builtin/log.c:1091 +msgid "don't strip/add [PATCH]" +msgstr "ta inte bort eller lägg till [PATCH]" + +#: builtin/log.c:1094 +msgid "don't output binary diffs" +msgstr "skriv inte binära diffar" + +#: builtin/log.c:1096 +msgid "don't include a patch matching a commit upstream" +msgstr "ta inte med patchar som motsvarar en uppströmsincheckning" + +#: builtin/log.c:1098 +msgid "show patch format instead of default (patch + stat)" +msgstr "visa patchformat istället för standard (patch + stat)" + +#: builtin/log.c:1100 +msgid "Messaging" +msgstr "E-post" + +#: builtin/log.c:1101 +msgid "header" +msgstr "huvud" + +#: builtin/log.c:1102 +msgid "add email header" +msgstr "lägg till e-posthuvud" + +#: builtin/log.c:1103 builtin/log.c:1105 +msgid "email" +msgstr "epost" + +#: builtin/log.c:1103 +msgid "add To: header" +msgstr "Lägg till mottagarhuvud (\"To:\")" + +#: builtin/log.c:1105 +msgid "add Cc: header" +msgstr "Lägg till kopiehuvud (\"Cc:\")" + +#: builtin/log.c:1107 +msgid "message-id" +msgstr "meddelande-id" + +#: builtin/log.c:1108 +msgid "make first mail a reply to <message-id>" +msgstr "Gör det första brevet ett svar till <meddelande-id>" + +#: builtin/log.c:1109 builtin/log.c:1112 +msgid "boundary" +msgstr "gräns" + +#: builtin/log.c:1110 +msgid "attach the patch" +msgstr "bifoga patchen" + +#: builtin/log.c:1113 +msgid "inline the patch" +msgstr "gör patchen ett inline-objekt" + +#: builtin/log.c:1117 +msgid "enable message threading, styles: shallow, deep" +msgstr "aktivera brevtrÃ¥dning, typer: shallow, deep" + +#: builtin/log.c:1119 +msgid "signature" +msgstr "signatur" + +#: builtin/log.c:1120 +msgid "add a signature" +msgstr "lägg till signatur" + +#: builtin/log.c:1122 +msgid "don't print the patch filenames" +msgstr "visa inte filnamn för patchar" + +#: builtin/log.c:1163 #, c-format msgid "bogus committer info %s" msgstr "felaktig incheckarinformation %s" -#: builtin/log.c:1198 +#: builtin/log.c:1208 msgid "-n and -k are mutually exclusive." msgstr "-n och -k kan inte användas samtidigt." -#: builtin/log.c:1200 +#: builtin/log.c:1210 msgid "--subject-prefix and -k are mutually exclusive." msgstr "--subject-prefix och -k kan inte användas samtidigt." -#: builtin/log.c:1208 +#: builtin/log.c:1218 msgid "--name-only does not make sense" msgstr "kan inte använda --name-only" -#: builtin/log.c:1210 +#: builtin/log.c:1220 msgid "--name-status does not make sense" msgstr "kan inte använda --name-status" -#: builtin/log.c:1212 +#: builtin/log.c:1222 msgid "--check does not make sense" msgstr "kan inte använda --check" -#: builtin/log.c:1235 +#: builtin/log.c:1245 msgid "standard output, or directory, which one?" msgstr "standard ut, eller katalog, vilken skall det vara?" -#: builtin/log.c:1237 +#: builtin/log.c:1247 #, c-format msgid "Could not create directory '%s'" msgstr "Kunde inte skapa katalogen \"%s\"" -#: builtin/log.c:1390 +#: builtin/log.c:1400 msgid "Failed to create output files" msgstr "Misslyckades skapa utdatafiler" -#: builtin/log.c:1494 +#: builtin/log.c:1449 +msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]" +msgstr "git cherry [-v] [<uppström> [<huvud> [<gräns>]]]" + +#: builtin/log.c:1504 #, c-format msgid "" "Could not find a tracked remote branch, please specify <upstream> manually.\n" msgstr "Kunde inte hitta en spÃ¥rad fjärrgren, ange <uppström> manuellt.\n" -#: builtin/log.c:1510 builtin/log.c:1512 builtin/log.c:1524 +#: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531 #, c-format msgid "Unknown commit %s" msgstr "Okänd incheckning %s" +#: builtin/ls-files.c:408 +msgid "git ls-files [options] [<file>...]" +msgstr "git ls-files [flaggor] [<fil>...]" + +#: builtin/ls-files.c:463 +msgid "identify the file status with tags" +msgstr "identifiera filstatus med taggar" + +#: builtin/ls-files.c:465 +msgid "use lowercase letters for 'assume unchanged' files" +msgstr "använd smÃ¥ bokstäver för \"anta oförändrade\"-filer" + +#: builtin/ls-files.c:467 +msgid "show cached files in the output (default)" +msgstr "visa cachade filer i utdata (standard)" + +#: builtin/ls-files.c:469 +msgid "show deleted files in the output" +msgstr "visa borttagna filer i utdata" + +#: builtin/ls-files.c:471 +msgid "show modified files in the output" +msgstr "visa modifierade filer i utdata" + +#: builtin/ls-files.c:473 +msgid "show other files in the output" +msgstr "visa andra filer i utdata" + +#: builtin/ls-files.c:475 +msgid "show ignored files in the output" +msgstr "visa ignorerade filer i utdata" + +#: builtin/ls-files.c:478 +msgid "show staged contents' object name in the output" +msgstr "visa köat innehÃ¥lls objektnamn i utdata" + +#: builtin/ls-files.c:480 +msgid "show files on the filesystem that need to be removed" +msgstr "visa filer i filsystemet som behöver tas bort" + +#: builtin/ls-files.c:482 +msgid "show 'other' directories' name only" +msgstr "visa endast namn för \"andra\" kataloger" + +#: builtin/ls-files.c:485 +msgid "don't show empty directories" +msgstr "visa inte tomma kataloger" + +#: builtin/ls-files.c:488 +msgid "show unmerged files in the output" +msgstr "visa ej sammanslagna filer i utdata" + +#: builtin/ls-files.c:490 +msgid "show resolve-undo information" +msgstr "visa \"resolve-undo\"-information" + +#: builtin/ls-files.c:492 +msgid "skip files matching pattern" +msgstr "hoppa över filer som motsvarar mönster" + +#: builtin/ls-files.c:495 +msgid "exclude patterns are read from <file>" +msgstr "exkludera mönster som läses frÃ¥n <fil>" + +#: builtin/ls-files.c:498 +msgid "read additional per-directory exclude patterns in <file>" +msgstr "läs ytterligare per-katalog-exkluderingsmönster frÃ¥n <fil>" + +#: builtin/ls-files.c:500 +msgid "add the standard git exclusions" +msgstr "lägg till git:s standardexkluderingar" + +#: builtin/ls-files.c:503 +msgid "make the output relative to the project top directory" +msgstr "gör utdata relativ till projektets toppkatalog" + +#: builtin/ls-files.c:506 +msgid "if any <file> is not in the index, treat this as an error" +msgstr "om en <fil> inte är indexet, betrakta det som ett fel" + +#: builtin/ls-files.c:507 +msgid "tree-ish" +msgstr "träd-igt" + +#: builtin/ls-files.c:508 +msgid "pretend that paths removed since <tree-ish> are still present" +msgstr "lÃ¥tsas att sökvägar borttagna sedan <träd-igt> fortfarande finns" + +#: builtin/ls-files.c:510 +msgid "show debugging data" +msgstr "visa felsökningsutdata" + +#: builtin/ls-tree.c:27 +msgid "git ls-tree [<options>] <tree-ish> [<path>...]" +msgstr "git ls-tree [<flaggor>] <träd-igt> [<sökväg>...]" + +#: builtin/ls-tree.c:125 +msgid "only show trees" +msgstr "visa endast träd" + +#: builtin/ls-tree.c:127 +msgid "recurse into subtrees" +msgstr "rekursera ner i underträd" + +#: builtin/ls-tree.c:129 +msgid "show trees when recursing" +msgstr "visa träd medan rekursering" + +#: builtin/ls-tree.c:132 +msgid "terminate entries with NUL byte" +msgstr "terminera poster med NUL-byte" + +#: builtin/ls-tree.c:133 +msgid "include object size" +msgstr "inkludera objektstorlek" + +#: builtin/ls-tree.c:135 builtin/ls-tree.c:137 +msgid "list only filenames" +msgstr "visa endast filnamn" + +#: builtin/ls-tree.c:140 +msgid "use full path names" +msgstr "använd fullständiga sökvägsnamn" + +#: builtin/ls-tree.c:142 +msgid "list entire tree; not just current directory (implies --full-name)" +msgstr "visa hela trädet; inte bara aktuell katalog (implicerar --full-name)" + +#: builtin/merge.c:43 +msgid "git merge [options] [<commit>...]" +msgstr "git merge [flaggor] [<incheckning>...]" + +#: builtin/merge.c:44 +msgid "git merge [options] <msg> HEAD <commit>" +msgstr "git merge [flaggor] <meddelande> HEAD <incheckning>" + +#: builtin/merge.c:45 +msgid "git merge --abort" +msgstr "git merge --abort" + #: builtin/merge.c:90 msgid "switch `m' requires a value" msgstr "flaggan \"m\" behöver ett värde" @@ -3380,6 +5695,67 @@ msgstr "Tillgängliga strategier är:" msgid "Available custom strategies are:" msgstr "Tillgängliga skräddarsydda strategier är:" +#: builtin/merge.c:183 +msgid "do not show a diffstat at the end of the merge" +msgstr "visa inte en diffstat när sammanslagningen är färdig" + +#: builtin/merge.c:186 +msgid "show a diffstat at the end of the merge" +msgstr "visa en diffstat när sammanslagningen är färdig" + +#: builtin/merge.c:187 +msgid "(synonym to --stat)" +msgstr "(synonym till --stat)" + +#: builtin/merge.c:189 +msgid "add (at most <n>) entries from shortlog to merge commit message" +msgstr "" +"lägg till (som mest <n>) poster frÃ¥n shortlog till incheckningsmeddelandet" + +#: builtin/merge.c:192 +msgid "create a single commit instead of doing a merge" +msgstr "skapa en ensam incheckning istället för en sammanslagning" + +#: builtin/merge.c:194 +msgid "perform a commit if the merge succeeds (default)" +msgstr "utför en incheckning om sammanslagningen lyckades (standard)" + +#: builtin/merge.c:196 +msgid "edit message before committing" +msgstr "redigera meddelande innan incheckning" + +#: builtin/merge.c:198 +msgid "allow fast-forward (default)" +msgstr "tillÃ¥t snabbspolning (standard)" + +#: builtin/merge.c:200 +msgid "abort if fast-forward is not possible" +msgstr "avbryt om snabbspolning inte är möjlig" + +#: builtin/merge.c:202 builtin/notes.c:870 builtin/revert.c:112 +msgid "strategy" +msgstr "strategi" + +#: builtin/merge.c:203 +msgid "merge strategy to use" +msgstr "sammanslagninsstrategi att använda" + +#: builtin/merge.c:204 +msgid "option=value" +msgstr "alternativ=värde" + +#: builtin/merge.c:205 +msgid "option for selected merge strategy" +msgstr "alternativ för vald sammanslagningsstrategi" + +#: builtin/merge.c:207 +msgid "merge commit message (for a non-fast-forward merge)" +msgstr "incheckningsmeddelande för (icke snabbspolande) sammanslagning" + +#: builtin/merge.c:211 +msgid "abort the current in-progress merge" +msgstr "avbryt den pÃ¥gÃ¥ende sammanslagningen" + #: builtin/merge.c:240 msgid "could not run stash." msgstr "kunde köra stash." @@ -3419,55 +5795,47 @@ msgstr "Avslutar SQUASH_MSG" msgid "No merge message -- not updating HEAD\n" msgstr "Inget sammanslagningsmeddelande -- uppdaterar inte HEAD\n" -#: builtin/merge.c:437 +#: builtin/merge.c:436 #, c-format msgid "'%s' does not point to a commit" msgstr "\"%s\" verkar inte peka pÃ¥ en incheckning" -#: builtin/merge.c:536 +#: builtin/merge.c:535 #, c-format msgid "Bad branch.%s.mergeoptions string: %s" msgstr "Felaktig branch.%s.mergeoptions-sträng: %s" -#: builtin/merge.c:629 +#: builtin/merge.c:628 msgid "git write-tree failed to write a tree" msgstr "git write-tree misslyckades skriva ett träd" -#: builtin/merge.c:679 -msgid "failed to read the cache" -msgstr "misslyckads läsa cachen" - -#: builtin/merge.c:697 -msgid "Unable to write index." -msgstr "Kunde inte skriva indexet." - -#: builtin/merge.c:710 +#: builtin/merge.c:656 msgid "Not handling anything other than two heads merge." msgstr "Hanterar inte nÃ¥got annat än en sammanslagning av tvÃ¥ huvuden." -#: builtin/merge.c:724 +#: builtin/merge.c:670 #, c-format msgid "Unknown option for merge-recursive: -X%s" msgstr "Felaktig flagga för merge-recursive: -X%s" -#: builtin/merge.c:738 +#: builtin/merge.c:684 #, c-format msgid "unable to write %s" msgstr "kunde inte skriva %s" -#: builtin/merge.c:877 +#: builtin/merge.c:773 #, c-format msgid "Could not read from '%s'" msgstr "Kunde inte läsa frÃ¥n \"%s\"" -#: builtin/merge.c:886 +#: builtin/merge.c:782 #, c-format msgid "Not committing merge; use 'git commit' to complete the merge.\n" msgstr "" "Checkar inte in sammanslagningen; använd \"git commit\" för att slutföra " "den.\n" -#: builtin/merge.c:892 +#: builtin/merge.c:788 msgid "" "Please enter a commit message to explain why this merge is necessary,\n" "especially if it merges an updated upstream into a topic branch.\n" @@ -3482,53 +5850,53 @@ msgstr "" "Rader som inleds med \"#\" kommer ignoreras, och ett tomt meddelande\n" "avbryter incheckningen.\n" -#: builtin/merge.c:916 +#: builtin/merge.c:812 msgid "Empty commit message." msgstr "Tomt incheckningsmeddelande." -#: builtin/merge.c:928 +#: builtin/merge.c:824 #, c-format msgid "Wonderful.\n" msgstr "Underbart.\n" -#: builtin/merge.c:993 +#: builtin/merge.c:889 #, c-format msgid "Automatic merge failed; fix conflicts and then commit the result.\n" msgstr "" "Kunde inte slÃ¥ ihop automatiskt; fixa konflikter och checka in resultatet.\n" -#: builtin/merge.c:1009 +#: builtin/merge.c:905 #, c-format msgid "'%s' is not a commit" msgstr "\"%s\" är inte en incheckning" -#: builtin/merge.c:1050 +#: builtin/merge.c:946 msgid "No current branch." msgstr "Inte pÃ¥ nÃ¥gon gren." -#: builtin/merge.c:1052 +#: builtin/merge.c:948 msgid "No remote for the current branch." msgstr "Ingen fjärr för aktuell gren." -#: builtin/merge.c:1054 +#: builtin/merge.c:950 msgid "No default upstream defined for the current branch." msgstr "Ingen standarduppström angiven för aktuell gren." -#: builtin/merge.c:1059 +#: builtin/merge.c:955 #, c-format msgid "No remote tracking branch for %s from %s" msgstr "Ingen fjärrspÃ¥rande gren för %s frÃ¥n %s" -#: builtin/merge.c:1146 builtin/merge.c:1303 +#: builtin/merge.c:1042 builtin/merge.c:1199 #, c-format msgid "%s - not something we can merge" msgstr "%s - inte nÃ¥got vi kan slÃ¥ ihop" -#: builtin/merge.c:1214 +#: builtin/merge.c:1110 msgid "There is no merge to abort (MERGE_HEAD missing)." msgstr "Det finns ingen sammanslagning att avbryta (MERGE_HEAD saknas)." -#: builtin/merge.c:1230 git-pull.sh:31 +#: builtin/merge.c:1126 git-pull.sh:31 msgid "" "You have not concluded your merge (MERGE_HEAD exists).\n" "Please, commit your changes before you can merge." @@ -3536,11 +5904,11 @@ msgstr "" "Du har inte avslutat sammanslagningen (MERGE_HEAD finns).\n" "Checka in dina ändringar innan du kan slÃ¥ ihop." -#: builtin/merge.c:1233 git-pull.sh:34 +#: builtin/merge.c:1129 git-pull.sh:34 msgid "You have not concluded your merge (MERGE_HEAD exists)." msgstr "Du har inte avslutat sammanslagningen (MERGE_HEAD finns)." -#: builtin/merge.c:1237 +#: builtin/merge.c:1133 msgid "" "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" "Please, commit your changes before you can merge." @@ -3548,84 +5916,183 @@ msgstr "" "Du har inte avslutat din \"cherry-pick\" (CHERRY_PICK_HEAD finns).\n" "Checka in dina ändringar innan du kan slÃ¥ ihop." -#: builtin/merge.c:1240 +#: builtin/merge.c:1136 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)." msgstr "Du har inte avslutat din \"cherry-pick\" (CHERRY_PICK_HEAD finns)." -#: builtin/merge.c:1249 +#: builtin/merge.c:1145 msgid "You cannot combine --squash with --no-ff." msgstr "Du kan inte kombinera --squash med --no-ff." -#: builtin/merge.c:1254 +#: builtin/merge.c:1150 msgid "You cannot combine --no-ff with --ff-only." msgstr "Du kan inte kombinera --no-ff med --ff-only." -#: builtin/merge.c:1261 +#: builtin/merge.c:1157 msgid "No commit specified and merge.defaultToUpstream not set." msgstr "Ingen incheckning angiven och merge.defaultToUpstream är ej satt." -#: builtin/merge.c:1293 +#: builtin/merge.c:1189 msgid "Can merge only exactly one commit into empty head" msgstr "Kan endast slÃ¥ ihop en enda incheckning i ett tomt huvud." -#: builtin/merge.c:1296 +#: builtin/merge.c:1192 msgid "Squash commit into empty head not supported yet" msgstr "Stöder inte en tillplattningsincheckning pÃ¥ ett tomt huvud ännu" -#: builtin/merge.c:1298 +#: builtin/merge.c:1194 msgid "Non-fast-forward commit does not make sense into an empty head" msgstr "Icke-snabbspolad incheckning kan inte användas med ett tomt huvud" -#: builtin/merge.c:1413 +#: builtin/merge.c:1309 #, c-format msgid "Updating %s..%s\n" msgstr "Uppdaterar %s..%s\n" -#: builtin/merge.c:1451 +#: builtin/merge.c:1348 #, c-format msgid "Trying really trivial in-index merge...\n" msgstr "Försöker riktigt enkel sammanslagning i indexet...\n" -#: builtin/merge.c:1458 +#: builtin/merge.c:1355 #, c-format msgid "Nope.\n" msgstr "Nej.\n" -#: builtin/merge.c:1490 +#: builtin/merge.c:1387 msgid "Not possible to fast-forward, aborting." msgstr "Kan inte snabbspola, avbryter." -#: builtin/merge.c:1513 builtin/merge.c:1592 +#: builtin/merge.c:1410 builtin/merge.c:1489 #, c-format msgid "Rewinding the tree to pristine...\n" msgstr "Ã…terspolar trädet till orört...\n" -#: builtin/merge.c:1517 +#: builtin/merge.c:1414 #, c-format msgid "Trying merge strategy %s...\n" msgstr "Försöker sammanslagninsstrategin %s...\n" -#: builtin/merge.c:1583 +#: builtin/merge.c:1480 #, c-format msgid "No merge strategy handled the merge.\n" msgstr "Ingen sammanslagningsstrategi hanterade sammanslagningen.\n" -#: builtin/merge.c:1585 +#: builtin/merge.c:1482 #, c-format msgid "Merge with strategy %s failed.\n" -msgstr "Sammanslaning med strategin %s misslyckades.\n" +msgstr "Sammanslagning med strategin %s misslyckades.\n" -#: builtin/merge.c:1594 +#: builtin/merge.c:1491 #, c-format msgid "Using the %s to prepare resolving by hand.\n" msgstr "Använder %s för att förbereda lösning för hand.\n" -#: builtin/merge.c:1606 +#: builtin/merge.c:1503 #, c-format msgid "Automatic merge went well; stopped before committing as requested\n" msgstr "" "Automatisk sammanslagning lyckades; stoppar före incheckning som önskat\n" +#: builtin/merge-base.c:26 +msgid "git merge-base [-a|--all] <commit> <commit>..." +msgstr "git merge-base [-a|--all] <incheckning> <incheckning>..." + +#: builtin/merge-base.c:27 +msgid "git merge-base [-a|--all] --octopus <commit>..." +msgstr "git merge-base [-a|--all] --octopus <incheckning>..." + +#: builtin/merge-base.c:28 +msgid "git merge-base --independent <commit>..." +msgstr "git merge-base --independent <incheckning>..." + +#: builtin/merge-base.c:29 +msgid "git merge-base --is-ancestor <commit> <commit>" +msgstr "git merge-base --is-ancestor <incheckning> <incheckning>" + +#: builtin/merge-base.c:98 +msgid "output all common ancestors" +msgstr "skriv ut alla gemensamma anfäder" + +#: builtin/merge-base.c:99 +msgid "find ancestors for a single n-way merge" +msgstr "hitta anfader för enkel n-vägssammanslagning" + +#: builtin/merge-base.c:100 +msgid "list revs not reachable from others" +msgstr "visa revisioner som inte kan nÃ¥s frÃ¥n andra" + +#: builtin/merge-base.c:102 +msgid "is the first one ancestor of the other?" +msgstr "är den första anfader till den andra?" + +#: builtin/merge-file.c:8 +msgid "" +"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file " +"file2" +msgstr "" +"git merge-file [alternativ] [-L namn1 [-L orig [-L namn2]]] fil1 origfil fil2" + +#: builtin/merge-file.c:33 +msgid "send results to standard output" +msgstr "sänd resultat till standard ut" + +#: builtin/merge-file.c:34 +msgid "use a diff3 based merge" +msgstr "använd diff3-baserad sammanslagning" + +#: builtin/merge-file.c:35 +msgid "for conflicts, use our version" +msgstr "för konflikter, använd vÃ¥r version" + +#: builtin/merge-file.c:37 +msgid "for conflicts, use their version" +msgstr "för konflikter, använd deras version" + +#: builtin/merge-file.c:39 +msgid "for conflicts, use a union version" +msgstr "för konflikter, använd en förenad version" + +#: builtin/merge-file.c:42 +msgid "for conflicts, use this marker size" +msgstr "för konflikter, använd denna markörstorlek" + +#: builtin/merge-file.c:43 +msgid "do not warn about conflicts" +msgstr "varna inte om konflikter" + +#: builtin/merge-file.c:45 +msgid "set labels for file1/orig_file/file2" +msgstr "sätt etiketter för fil1/origfil/fil2" + +#: builtin/mktree.c:67 +msgid "git mktree [-z] [--missing] [--batch]" +msgstr "git mktree [-z] [--missing] [--batch]" + +#: builtin/mktree.c:153 +msgid "input is NUL terminated" +msgstr "indata är NUL-terminerad" + +#: builtin/mktree.c:154 builtin/write-tree.c:24 +msgid "allow missing objects" +msgstr "tillÃ¥t saknade objekt" + +#: builtin/mktree.c:155 +msgid "allow creation of more than one tree" +msgstr "tillÃ¥t skapa mer än ett träd" + +#: builtin/mv.c:14 +msgid "git mv [options] <source>... <destination>" +msgstr "git mv [flaggor] <källa>... <mÃ¥l>" + +#: builtin/mv.c:64 +msgid "force move/rename even if target exists" +msgstr "tvinga flytta/ändra namn även om mÃ¥let finns" + +#: builtin/mv.c:65 +msgid "skip move/rename errors" +msgstr "hoppa över fel vid flytt/namnändring" + #: builtin/mv.c:108 #, c-format msgid "Checking rename of '%s' to '%s'\n" @@ -3688,114 +6155,287 @@ msgstr "Byter namn pÃ¥ %s till %s\n" msgid "renaming '%s' failed" msgstr "misslyckades byta namn pÃ¥ \"%s\"" -#: builtin/notes.c:139 +#: builtin/name-rev.c:175 +msgid "git name-rev [options] <commit>..." +msgstr "git name-rev [flaggor] <incheckning>..." + +#: builtin/name-rev.c:176 +msgid "git name-rev [options] --all" +msgstr "git name-rev [flaggor] --all" + +#: builtin/name-rev.c:177 +msgid "git name-rev [options] --stdin" +msgstr "git name-rev [flaggor] --stdin" + +#: builtin/name-rev.c:229 +msgid "print only names (no SHA-1)" +msgstr "skriv endast namn (ingen SHA-1)" + +#: builtin/name-rev.c:230 +msgid "only use tags to name the commits" +msgstr "använd endast taggar för att namnge incheckningar" + +#: builtin/name-rev.c:232 +msgid "only use refs matching <pattern>" +msgstr "använd endast referenser som motsvarar <mönster>" + +#: builtin/name-rev.c:234 +msgid "list all commits reachable from all refs" +msgstr "lista alla incheckningar som kan nÃ¥s alla referenser" + +#: builtin/name-rev.c:235 +msgid "read from stdin" +msgstr "läs frÃ¥n standard in" + +#: builtin/name-rev.c:236 +msgid "allow to print `undefined` names" +msgstr "tillÃ¥t att skriva \"odefinierade\" namn" + +#: builtin/notes.c:26 +msgid "git notes [--ref <notes_ref>] [list [<object>]]" +msgstr "git notes [--ref <anteckningsref>] [list [<objekt>]]" + +#: builtin/notes.c:27 +msgid "" +"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) " +"<object>] [<object>]" +msgstr "" +"git notes [--ref <anteckningsref>] add [-f] [-m <medd> | -F <fil> | (-c | -" +"C) <objekt>] [<objekt>]" + +#: builtin/notes.c:28 +msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>" +msgstr "" +"git notes [--ref <anteckningsref>] copy [-f] <frÃ¥n-objekt> <till-objekt>" + +#: builtin/notes.c:29 +msgid "" +"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) " +"<object>] [<object>]" +msgstr "" +"git notes [--ref <anteckningsref>] append [-m <medd> | -F <fil> | (-c | -C) " +"<objekt>] [<objekt>]" + +#: builtin/notes.c:30 +msgid "git notes [--ref <notes_ref>] edit [<object>]" +msgstr "git notes [--ref <anteckningsref>] edit [<objekt>]" + +#: builtin/notes.c:31 +msgid "git notes [--ref <notes_ref>] show [<object>]" +msgstr "git notes [--ref <anteckningsref>] show [<objekt>]" + +#: builtin/notes.c:32 +msgid "" +"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>" +msgstr "" +"git notes [--ref <anteckningsref>] merge [-v | -q] [-s <strategi> ] " +"<anteckningsref>" + +#: builtin/notes.c:33 +msgid "git notes merge --commit [-v | -q]" +msgstr "git notes merge --commit [-v | -q]" + +#: builtin/notes.c:34 +msgid "git notes merge --abort [-v | -q]" +msgstr "git notes merge --abort [-v | -q]" + +#: builtin/notes.c:35 +msgid "git notes [--ref <notes_ref>] remove [<object>...]" +msgstr "git notes [--ref <anteckningsref>] remove [<objekt>...]" + +#: builtin/notes.c:36 +msgid "git notes [--ref <notes_ref>] prune [-n | -v]" +msgstr "git notes [--ref <anteckningsref>] prune [-n | -v]" + +#: builtin/notes.c:37 +msgid "git notes [--ref <notes_ref>] get-ref" +msgstr "git notes [--ref <anteckningsref>] get-ref" + +#: builtin/notes.c:42 +msgid "git notes [list [<object>]]" +msgstr "git notes [list [<objekt>]]" + +#: builtin/notes.c:47 +msgid "git notes add [<options>] [<object>]" +msgstr "git notes add [<flaggor>] [<objekt>]" + +#: builtin/notes.c:52 +msgid "git notes copy [<options>] <from-object> <to-object>" +msgstr "git notes copy [<flaggor>] <frÃ¥n-objekt> <till-objekt>" + +#: builtin/notes.c:53 +msgid "git notes copy --stdin [<from-object> <to-object>]..." +msgstr "git notes copy --stdin [<frÃ¥n-objekt> <till-objekt>]..." + +#: builtin/notes.c:58 +msgid "git notes append [<options>] [<object>]" +msgstr "git notes append [<flaggor>] [<objekt>]" + +#: builtin/notes.c:63 +msgid "git notes edit [<object>]" +msgstr "git notes edit [<objekt>]" + +#: builtin/notes.c:68 +msgid "git notes show [<object>]" +msgstr "git notes show [<objekt>]" + +#: builtin/notes.c:73 +msgid "git notes merge [<options>] <notes_ref>" +msgstr "git notes merge [<flaggor>] <anteckningsref>" + +#: builtin/notes.c:74 +msgid "git notes merge --commit [<options>]" +msgstr "git notes merge --commit [<flaggor>]" + +#: builtin/notes.c:75 +msgid "git notes merge --abort [<options>]" +msgstr "git notes merge --abort [<flaggor>]" + +#: builtin/notes.c:80 +msgid "git notes remove [<object>]" +msgstr "git notes remove [<objekt>]" + +#: builtin/notes.c:85 +msgid "git notes prune [<options>]" +msgstr "git notes prune [<flaggor>]" + +#: builtin/notes.c:90 +msgid "git notes get-ref" +msgstr "git notes get-ref" + +#: builtin/notes.c:142 #, c-format msgid "unable to start 'show' for object '%s'" msgstr "kunde inte starta \"show\" för objektet \"%s\"" -#: builtin/notes.c:145 +#: builtin/notes.c:148 msgid "can't fdopen 'show' output fd" msgstr "kunde inte öppna (fdopen) \"show\"-utdata-filhandtag" -#: builtin/notes.c:155 +#: builtin/notes.c:158 #, c-format msgid "failed to close pipe to 'show' for object '%s'" msgstr "kunde inte stänga röret till \"show\" för objektet \"%s\"" -#: builtin/notes.c:158 +#: builtin/notes.c:161 #, c-format msgid "failed to finish 'show' for object '%s'" msgstr "kunde inte avsluta \"show\" för objektet \"%s\"" -#: builtin/notes.c:175 builtin/tag.c:347 +#: builtin/notes.c:178 builtin/tag.c:347 #, c-format msgid "could not create file '%s'" msgstr "kunde inte skapa filen \"%s\"" -#: builtin/notes.c:189 +#: builtin/notes.c:192 msgid "Please supply the note contents using either -m or -F option" msgstr "Ange innehÃ¥ll för anteckningen med antingen -m eller -F" -#: builtin/notes.c:210 builtin/notes.c:973 +#: builtin/notes.c:213 builtin/notes.c:976 #, c-format msgid "Removing note for object %s\n" msgstr "Tar bort anteckning för objektet %s\n" -#: builtin/notes.c:215 +#: builtin/notes.c:218 msgid "unable to write note object" msgstr "kunde inte skriva anteckningsobjekt" -#: builtin/notes.c:217 +#: builtin/notes.c:220 #, c-format msgid "The note contents has been left in %s" msgstr "Anteckningens innehÃ¥ll har lämnats kvar i %s" -#: builtin/notes.c:251 builtin/tag.c:542 +#: builtin/notes.c:254 builtin/tag.c:542 #, c-format msgid "cannot read '%s'" msgstr "kunde inte läsa \"%s\"" -#: builtin/notes.c:253 builtin/tag.c:545 +#: builtin/notes.c:256 builtin/tag.c:545 #, c-format msgid "could not open or read '%s'" msgstr "kunde inte öppna eller läsa \"%s\"" -#: builtin/notes.c:272 builtin/notes.c:445 builtin/notes.c:447 -#: builtin/notes.c:507 builtin/notes.c:561 builtin/notes.c:644 -#: builtin/notes.c:649 builtin/notes.c:724 builtin/notes.c:766 -#: builtin/notes.c:968 builtin/reset.c:293 builtin/tag.c:558 +#: builtin/notes.c:275 builtin/notes.c:448 builtin/notes.c:450 +#: builtin/notes.c:510 builtin/notes.c:564 builtin/notes.c:647 +#: builtin/notes.c:652 builtin/notes.c:727 builtin/notes.c:769 +#: builtin/notes.c:971 builtin/reset.c:293 builtin/tag.c:558 #, c-format msgid "Failed to resolve '%s' as a valid ref." msgstr "Kunde inte slÃ¥ upp \"%s\" som en giltig referens." -#: builtin/notes.c:275 +#: builtin/notes.c:278 #, c-format msgid "Failed to read object '%s'." msgstr "Kunde inte läsa objektet \"%s\"." -#: builtin/notes.c:299 +#: builtin/notes.c:302 msgid "Cannot commit uninitialized/unreferenced notes tree" msgstr "Kan inte checka in oinitierat/orefererat anteckningsträd" -#: builtin/notes.c:340 +#: builtin/notes.c:343 #, c-format msgid "Bad notes.rewriteMode value: '%s'" msgstr "Felaktigt värde för notes.rewriteMode: '%s'" -#: builtin/notes.c:350 +#: builtin/notes.c:353 #, c-format msgid "Refusing to rewrite notes in %s (outside of refs/notes/)" msgstr "Vägrar skriva över anteckningar i %s (utanför refs/notes/)" #. TRANSLATORS: The first %s is the name of the #. environment variable, the second %s is its value -#: builtin/notes.c:377 +#: builtin/notes.c:380 #, c-format msgid "Bad %s value: '%s'" msgstr "Felaktigt värde pÃ¥ %s: \"%s\"" -#: builtin/notes.c:441 +#: builtin/notes.c:444 #, c-format msgid "Malformed input line: '%s'." msgstr "Felaktig indatarad: \"%s\"." -#: builtin/notes.c:456 +#: builtin/notes.c:459 #, c-format msgid "Failed to copy notes from '%s' to '%s'" msgstr "Misslyckades kopiera anteckningar frÃ¥n \"%s\" till \"%s\"" -#: builtin/notes.c:500 builtin/notes.c:554 builtin/notes.c:627 -#: builtin/notes.c:639 builtin/notes.c:712 builtin/notes.c:759 -#: builtin/notes.c:1033 +#: builtin/notes.c:503 builtin/notes.c:557 builtin/notes.c:630 +#: builtin/notes.c:642 builtin/notes.c:715 builtin/notes.c:762 +#: builtin/notes.c:1036 msgid "too many parameters" msgstr "för mÃ¥nga parametrar" -#: builtin/notes.c:513 builtin/notes.c:772 +#: builtin/notes.c:516 builtin/notes.c:775 #, c-format msgid "No note found for object %s." msgstr "Inga anteckningar hittades för objektet %s." -#: builtin/notes.c:580 +#: builtin/notes.c:538 builtin/notes.c:695 +msgid "note contents as a string" +msgstr "anteckningsinnehÃ¥ll som sträng" + +#: builtin/notes.c:541 builtin/notes.c:698 +msgid "note contents in a file" +msgstr "anteckningsinnehÃ¥ll i en fil" + +#: builtin/notes.c:543 builtin/notes.c:546 builtin/notes.c:700 +#: builtin/notes.c:703 builtin/tag.c:476 +msgid "object" +msgstr "objekt" + +#: builtin/notes.c:544 builtin/notes.c:701 +msgid "reuse and edit specified note object" +msgstr "Ã¥teranvänd och redigera angivet anteckningsobjekt" + +#: builtin/notes.c:547 builtin/notes.c:704 +msgid "reuse specified note object" +msgstr "Ã¥teranvänd angivet anteckningsobjekt" + +#: builtin/notes.c:549 builtin/notes.c:617 +msgid "replace existing notes" +msgstr "ersätt befintliga anteckningar" + +#: builtin/notes.c:583 #, c-format msgid "" "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite " @@ -3804,16 +6444,24 @@ msgstr "" "Kan inte lägga till anteckningar. Hittade befintliga anteckningar för " "objektet %s. Använd \"-f\" för att skriva över befintliga anteckningar" -#: builtin/notes.c:585 builtin/notes.c:662 +#: builtin/notes.c:588 builtin/notes.c:665 #, c-format msgid "Overwriting existing notes for object %s\n" msgstr "Skriver över befintliga anteckningar för objektet %s\n" -#: builtin/notes.c:635 +#: builtin/notes.c:618 +msgid "read objects from stdin" +msgstr "läs objekt frÃ¥n standard in" + +#: builtin/notes.c:620 +msgid "load rewriting config for <command> (implies --stdin)" +msgstr "läs omskrivningsinställning för <kommando> (implicerar --stdin)" + +#: builtin/notes.c:638 msgid "too few parameters" msgstr "för fÃ¥ parametrar" -#: builtin/notes.c:656 +#: builtin/notes.c:659 #, c-format msgid "" "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite " @@ -3822,12 +6470,12 @@ msgstr "" "Kan inte kopiera anteckningar. Hittade befintliga anteckningar för objektet " "%s. Använd \"-f\" för att skriva över befintliga anteckningar" -#: builtin/notes.c:668 +#: builtin/notes.c:671 #, c-format msgid "Missing notes on source object %s. Cannot copy." msgstr "Anteckningar pÃ¥ källobjektet %s saknas. Kan inte kopiera." -#: builtin/notes.c:717 +#: builtin/notes.c:720 #, c-format msgid "" "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n" @@ -3836,36 +6484,255 @@ msgstr "" "Flaggorna -m/-F/-c/-C rekommenderas inte för underkommandot \"edit\".\n" "Använd \"git notes add -f -m/-F/-c/-C\" istället.\n" -#: builtin/notes.c:971 +#: builtin/notes.c:867 +msgid "General options" +msgstr "Allmänna flaggor" + +#: builtin/notes.c:869 +msgid "Merge options" +msgstr "Flaggor för sammanslagning" + +#: builtin/notes.c:871 +msgid "" +"resolve notes conflicts using the given strategy (manual/ours/theirs/union/" +"cat_sort_uniq)" +msgstr "" +"läs konflikter i anteckningar med angiven strategi (manual/ours/theirs/union/" +"cat_sort_uniq)" + +#: builtin/notes.c:873 +msgid "Committing unmerged notes" +msgstr "Checkar in ej sammanslagna anteckningar" + +#: builtin/notes.c:875 +msgid "finalize notes merge by committing unmerged notes" +msgstr "" +"färdigställ sammanslagning av anteckningar genom att checka in ej " +"sammanslagna anteckningar" + +#: builtin/notes.c:877 +msgid "Aborting notes merge resolution" +msgstr "Avbryt lösning av sammanslagning av anteckningar" + +#: builtin/notes.c:879 +msgid "abort notes merge" +msgstr "avbryt sammanslagning av anteckningar" + +#: builtin/notes.c:974 #, c-format msgid "Object %s has no note\n" msgstr "Objektet %s har ingen anteckning\n" -#: builtin/notes.c:1103 builtin/remote.c:1598 +#: builtin/notes.c:986 +msgid "attempt to remove non-existent note is not an error" +msgstr "försök att ta bort icke-existerande anteckningar är inte ett fel" + +#: builtin/notes.c:989 +msgid "read object names from the standard input" +msgstr "läs objektnamn frÃ¥n standard in" + +#: builtin/notes.c:1070 +msgid "notes_ref" +msgstr "anteckningar-ref" + +#: builtin/notes.c:1071 +msgid "use notes from <notes_ref>" +msgstr "använd anteckningar frÃ¥n <anteckningsref>" + +#: builtin/notes.c:1106 builtin/remote.c:1598 #, c-format msgid "Unknown subcommand: %s" msgstr "Okänt underkommando: %s" -#: builtin/pack-objects.c:2337 +#: builtin/pack-objects.c:23 +msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]" +msgstr "git pack-objects --stdout [flaggor...] [< reflista | < objektlista]" + +#: builtin/pack-objects.c:24 +msgid "git pack-objects [options...] base-name [< ref-list | < object-list]" +msgstr "git pack-objects [flaggor...] basnamn [< reflista | < objektlista]" + +#: builtin/pack-objects.c:183 builtin/pack-objects.c:186 +#, c-format +msgid "deflate error (%d)" +msgstr "fel i deflate (%d)" + +#: builtin/pack-objects.c:2397 #, c-format msgid "unsupported index version %s" msgstr "indexversionen %s stöds ej" -#: builtin/pack-objects.c:2341 +#: builtin/pack-objects.c:2401 #, c-format msgid "bad index version '%s'" msgstr "felaktig indexversion \"%s\"" -#: builtin/pack-objects.c:2364 +#: builtin/pack-objects.c:2424 #, c-format msgid "option %s does not accept negative form" msgstr "flaggan %s godtar inte negativ form" -#: builtin/pack-objects.c:2368 +#: builtin/pack-objects.c:2428 #, c-format msgid "unable to parse value '%s' for option %s" msgstr "kunde inte tolka värdet \"%s\" för flaggan %s" +#: builtin/pack-objects.c:2447 +msgid "do not show progress meter" +msgstr "visa inte förloppsindikator" + +#: builtin/pack-objects.c:2449 +msgid "show progress meter" +msgstr "visa förloppsindikator" + +#: builtin/pack-objects.c:2451 +msgid "show progress meter during object writing phase" +msgstr "visa förloppsindikator under objektskrivningsfasen" + +#: builtin/pack-objects.c:2454 +msgid "similar to --all-progress when progress meter is shown" +msgstr "som --all-progress när förloppsmätaren visas" + +#: builtin/pack-objects.c:2455 +msgid "version[,offset]" +msgstr "version[,offset]" + +#: builtin/pack-objects.c:2456 +msgid "write the pack index file in the specified idx format version" +msgstr "skriv paketindexfilen i angiven indexformatversion" + +#: builtin/pack-objects.c:2459 +msgid "maximum size of each output pack file" +msgstr "maximal storlek pÃ¥ varje utdatapaketfil" + +#: builtin/pack-objects.c:2461 +msgid "ignore borrowed objects from alternate object store" +msgstr "ignorera lÃ¥nade objekt frÃ¥n alternativa objektlager" + +#: builtin/pack-objects.c:2463 +msgid "ignore packed objects" +msgstr "ignorera packade objekt" + +#: builtin/pack-objects.c:2465 +msgid "limit pack window by objects" +msgstr "begränsa paketfönster efter objekt" + +#: builtin/pack-objects.c:2467 +msgid "limit pack window by memory in addition to object limit" +msgstr "begränsa paketfönster efter minne förutom objektgräns" + +#: builtin/pack-objects.c:2469 +msgid "maximum length of delta chain allowed in the resulting pack" +msgstr "maximal längd pÃ¥ deltakedja tillÃ¥ten i slutligt paket" + +#: builtin/pack-objects.c:2471 +msgid "reuse existing deltas" +msgstr "Ã¥teranvänd befintliga delta" + +#: builtin/pack-objects.c:2473 +msgid "reuse existing objects" +msgstr "Ã¥teranvänd befintliga objekt" + +#: builtin/pack-objects.c:2475 +msgid "use OFS_DELTA objects" +msgstr "använd OFS_DELTA-objekt" + +#: builtin/pack-objects.c:2477 +msgid "use threads when searching for best delta matches" +msgstr "använd trÃ¥dar vid sökning efter bästa deltaträffar" + +#: builtin/pack-objects.c:2479 +msgid "do not create an empty pack output" +msgstr "försök inte skapa tom paketutdata" + +#: builtin/pack-objects.c:2481 +msgid "read revision arguments from standard input" +msgstr "läs revisionsargument frÃ¥n standard in" + +#: builtin/pack-objects.c:2483 +msgid "limit the objects to those that are not yet packed" +msgstr "begränsa objekt till de som ännu inte packats" + +#: builtin/pack-objects.c:2486 +msgid "include objects reachable from any reference" +msgstr "inkludera objekt som kan nÃ¥s frÃ¥n nÃ¥gon referens" + +#: builtin/pack-objects.c:2489 +msgid "include objects referred by reflog entries" +msgstr "inkludera objekt som refereras frÃ¥n referensloggposter" + +#: builtin/pack-objects.c:2492 +msgid "output pack to stdout" +msgstr "skriv paket pÃ¥ standard ut" + +#: builtin/pack-objects.c:2494 +msgid "include tag objects that refer to objects to be packed" +msgstr "inkludera taggobjekt som refererar objekt som skall packas" + +#: builtin/pack-objects.c:2496 +msgid "keep unreachable objects" +msgstr "behÃ¥ll onÃ¥bara objekt" + +#: builtin/pack-objects.c:2497 parse-options.h:141 +msgid "time" +msgstr "tid" + +#: builtin/pack-objects.c:2498 +msgid "unpack unreachable objects newer than <time>" +msgstr "packa upp onÃ¥bara objekt nyare än <tid>" + +#: builtin/pack-objects.c:2501 +msgid "create thin packs" +msgstr "skapa tunna paket" + +#: builtin/pack-objects.c:2503 +msgid "ignore packs that have companion .keep file" +msgstr "ignorera paket som har tillhörande .keep-fil" + +#: builtin/pack-objects.c:2505 +msgid "pack compression level" +msgstr "komprimeringsgrad för paket" + +#: builtin/pack-objects.c:2507 +msgid "do not hide commits by grafts" +msgstr "göm inte incheckningar med ympningar (\"grafts\")" + +#: builtin/pack-refs.c:6 +msgid "git pack-refs [options]" +msgstr "git pack-refs [flaggor]" + +#: builtin/pack-refs.c:14 +msgid "pack everything" +msgstr "packa allt" + +#: builtin/pack-refs.c:15 +msgid "prune loose refs (default)" +msgstr "ta bort lösa referenser (standard)" + +#: builtin/prune-packed.c:7 +msgid "git prune-packed [-n|--dry-run] [-q|--quiet]" +msgstr "git prune-packed [-n|--dry-run] [-q|--quiet]" + +#: builtin/prune.c:12 +msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]" +msgstr "git prune [-n] [-v] [--expire <tid>] [--] [<huvud>...]" + +#: builtin/prune.c:132 +msgid "do not remove, show only" +msgstr "ta inte bort, bara visa" + +#: builtin/prune.c:133 +msgid "report pruned objects" +msgstr "rapportera borttagna objekt" + +#: builtin/prune.c:136 +msgid "expire objects older than <time>" +msgstr "lÃ¥t tid gÃ¥ ut för objekt äldre än <tid>" + +#: builtin/push.c:14 +msgid "git push [<options>] [<repository> [<refspec>...]]" +msgstr "git push [<flaggor>] [<arkiv> [<refspec>...]]" + #: builtin/push.c:45 msgid "tag shorthand without <tag>" msgstr "taggförkortning utan <tagg>" @@ -3952,14 +6819,48 @@ msgstr "" "aktuella grenen \"%s\", utan att tala om för mig vad som\n" "skall sändas för att uppdatera fjärrgrenen." -#: builtin/push.c:174 +#: builtin/push.c:151 +msgid "" +"push.default is unset; its implicit value is changing in\n" +"Git 2.0 from 'matching' to 'simple'. To squelch this message\n" +"and maintain the current behavior after the default changes, use:\n" +"\n" +" git config --global push.default matching\n" +"\n" +"To squelch this message and adopt the new behavior now, use:\n" +"\n" +" git config --global push.default simple\n" +"\n" +"See 'git help config' and search for 'push.default' for further " +"information.\n" +"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n" +"'current' instead of 'simple' if you sometimes use older versions of Git)" +msgstr "" +"push.default har inte ställts in; dess underförstÃ¥dda värde\n" +"ändras i Git 2.0 frÃ¥n \"matching\" till \"simple\". För att\n" +"undertrycka det här meddelandet och behÃ¥lla nuvarande beteende\n" +"efter att förvalet ändras,\n" +"skriver du:\n" +"\n" +" git config --global push.default matching\n" +"\n" +"För att undertrycka meddelandet och välja det nya beteendet nu skriver du:\n" +"\n" +" git config --global push.default simple\n" +"\n" +"Se \"git help config\" och sök efter \"push.default\" för ytterligare \n" +"information. (Läget \"simple\" introducerades i Git 1.7.11. Använd det\n" +"liknande läget \"current\" istället för \"simple\" om du ibland använder\n" +"äldre versioner av Git.)" + +#: builtin/push.c:199 msgid "" "You didn't specify any refspecs to push, and push.default is \"nothing\"." msgstr "" "Du angav inga referensspecifikationer att sända, och push.default är " "\"nothing\"." -#: builtin/push.c:181 +#: builtin/push.c:206 msgid "" "Updates were rejected because the tip of your current branch is behind\n" "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n" @@ -3971,20 +6872,21 @@ msgstr "" "innan du sänder igen.\n" "Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer." -#: builtin/push.c:187 +#: builtin/push.c:212 msgid "" "Updates were rejected because a pushed branch tip is behind its remote\n" "counterpart. If you did not intend to push that branch, you may want to\n" -"specify branches to push or set the 'push.default' configuration\n" -"variable to 'current' or 'upstream' to push only the current branch." +"specify branches to push or set the 'push.default' configuration variable\n" +"to 'simple', 'current' or 'upstream' to push only the current branch." msgstr "" "Uppdateringar avvisades dÃ¥ änden pÃ¥ en insänd gren är bakom dess\n" "fjärrmotsvarighet. Om det inte var meningen att sända in grenen, bör\n" "du specificera grenar att sända, eller ändra inställningsvariabeln\n" -"\"push-default\" till \"current\" eller \"upstream\" för att endast sända\n" -"aktuell gren." +"\"push-default\" till \"simple\", \"current\" eller \"upstream\" för att " +"endast\n" +"sända aktuell gren." -#: builtin/push.c:193 +#: builtin/push.c:218 msgid "" "Updates were rejected because a pushed branch tip is behind its remote\n" "counterpart. Check out this branch and merge the remote changes\n" @@ -3996,22 +6898,22 @@ msgstr "" "\"git pull\") innan du sänder igen.\n" "Se avsnittet \"Note about fast-forward\" i \"git push --help\" för detaljer." -#: builtin/push.c:233 +#: builtin/push.c:258 #, c-format msgid "Pushing to %s\n" msgstr "Sänder till %s\n" -#: builtin/push.c:237 +#: builtin/push.c:262 #, c-format msgid "failed to push some refs to '%s'" msgstr "misslyckades sända vissa referenser till \"%s\"" -#: builtin/push.c:269 +#: builtin/push.c:294 #, c-format msgid "bad repository '%s'" msgstr "felaktigt arkiv \"%s\"" -#: builtin/push.c:270 +#: builtin/push.c:295 msgid "" "No configured push destination.\n" "Either specify the URL from the command-line or configure a remote " @@ -4032,34 +6934,234 @@ msgstr "" "\n" " git push <namn>\n" -#: builtin/push.c:285 +#: builtin/push.c:310 msgid "--all and --tags are incompatible" msgstr "--all och --tags är inkompatibla" -#: builtin/push.c:286 +#: builtin/push.c:311 msgid "--all can't be combined with refspecs" msgstr "--all kan inte kombineras med referensspecifikationer" -#: builtin/push.c:291 +#: builtin/push.c:316 msgid "--mirror and --tags are incompatible" msgstr "--mirror och --tags är inkompatibla" -#: builtin/push.c:292 +#: builtin/push.c:317 msgid "--mirror can't be combined with refspecs" msgstr "--mirror kan inte kombineras med referensspecifikationer" -#: builtin/push.c:297 +#: builtin/push.c:322 msgid "--all and --mirror are incompatible" msgstr "--all och --mirror är inkompatibla" -#: builtin/push.c:385 +#: builtin/push.c:382 +msgid "repository" +msgstr "arkiv" + +#: builtin/push.c:383 +msgid "push all refs" +msgstr "sänd alla referenser" + +#: builtin/push.c:384 +msgid "mirror all refs" +msgstr "spegla alla referenser" + +#: builtin/push.c:386 +msgid "delete refs" +msgstr "ta bort referenser" + +#: builtin/push.c:387 +msgid "push tags (can't be used with --all or --mirror)" +msgstr "sänd taggar (kan inte användas med --all eller --mirror)" + +#: builtin/push.c:390 +msgid "force updates" +msgstr "tvinga uppdateringar" + +#: builtin/push.c:391 +msgid "check" +msgstr "kontrollera" + +#: builtin/push.c:392 +msgid "control recursive pushing of submodules" +msgstr "styr rekursiv insändning av undermoduler" + +#: builtin/push.c:394 +msgid "use thin pack" +msgstr "använd tunna paket" + +#: builtin/push.c:395 builtin/push.c:396 +msgid "receive pack program" +msgstr "program för att ta emot paket" + +#: builtin/push.c:397 +msgid "set upstream for git pull/status" +msgstr "ställ in uppström för git pull/status" + +#: builtin/push.c:400 +msgid "prune locally removed refs" +msgstr "ta bort lokalt borttagna referenser" + +#: builtin/push.c:410 msgid "--delete is incompatible with --all, --mirror and --tags" msgstr "--delete är imkompatibel med --all, --mirror och --tags" -#: builtin/push.c:387 +#: builtin/push.c:412 msgid "--delete doesn't make sense without any refs" msgstr "--delete kan inte användas utan referenser" +#: builtin/read-tree.c:36 +msgid "" +"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] " +"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--" +"index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])" +msgstr "" +"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] " +"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--" +"index-output=<fil>] (--empty | <träd-igt1> [<träd-igt2> [<träd-igt3>]])" + +#: builtin/read-tree.c:108 +msgid "write resulting index to <file>" +msgstr "skriv resulterande index till <fil>" + +#: builtin/read-tree.c:111 +msgid "only empty the index" +msgstr "töm bara indexet" + +#: builtin/read-tree.c:113 +msgid "Merging" +msgstr "Sammanslagning" + +#: builtin/read-tree.c:115 +msgid "perform a merge in addition to a read" +msgstr "utför en sammanslagning i tillägg till en läsning" + +#: builtin/read-tree.c:117 +msgid "3-way merge if no file level merging required" +msgstr "3-vägssammanslagning om sammanslagning pÃ¥ filnivÃ¥ ej krävs" + +#: builtin/read-tree.c:119 +msgid "3-way merge in presence of adds and removes" +msgstr "3-vägssammanslagning när det finns tillägg och borttagningar" + +#: builtin/read-tree.c:121 +msgid "same as -m, but discard unmerged entries" +msgstr "som -m, men kasta bort ej sammanslagna poster" + +#: builtin/read-tree.c:122 +msgid "<subdirectory>/" +msgstr "<underkatalog>/" + +#: builtin/read-tree.c:123 +msgid "read the tree into the index under <subdirectory>/" +msgstr "läs in trädet i indexet under <underkatalog>/" + +#: builtin/read-tree.c:126 +msgid "update working tree with merge result" +msgstr "uppdatera arbetskatalogen med resultatet frÃ¥n sammanslagningen" + +#: builtin/read-tree.c:128 +msgid "gitignore" +msgstr "gitignore" + +#: builtin/read-tree.c:129 +msgid "allow explicitly ignored files to be overwritten" +msgstr "tillÃ¥t explicit ignorerade filer att skrivas över" + +#: builtin/read-tree.c:132 +msgid "don't check the working tree after merging" +msgstr "kontrollera inte arbetskatalogen efter sammanslagning" + +#: builtin/read-tree.c:133 +msgid "don't update the index or the work tree" +msgstr "uppdatera inte indexet eller arbetskatalogen" + +#: builtin/read-tree.c:135 +msgid "skip applying sparse checkout filter" +msgstr "hoppa över att applicera filter för gles utcheckning" + +#: builtin/read-tree.c:137 +msgid "debug unpack-trees" +msgstr "felsök unpack-trees" + +#: builtin/remote.c:11 +msgid "git remote [-v | --verbose]" +msgstr "git remote [-v | --verbose]" + +#: builtin/remote.c:12 +msgid "" +"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--" +"mirror=<fetch|push>] <name> <url>" +msgstr "" +"git remote add [-t <gren>] [-m <master>] [-f] [--tags|--no-tags] [--" +"mirror=<fetch|push>] <namn> <url>" + +#: builtin/remote.c:13 builtin/remote.c:32 +msgid "git remote rename <old> <new>" +msgstr "git remote rename <gammal> <ny>" + +#: builtin/remote.c:14 builtin/remote.c:37 +msgid "git remote remove <name>" +msgstr "git remote remove <namn>" + +#: builtin/remote.c:15 builtin/remote.c:42 +msgid "git remote set-head <name> (-a | -d | <branch>)" +msgstr "git remote set-head <namn> (-a | -d | <gren>)" + +#: builtin/remote.c:16 +msgid "git remote [-v | --verbose] show [-n] <name>" +msgstr "git remote [-v | --verbose] show [-n] <namn>" + +#: builtin/remote.c:17 +msgid "git remote prune [-n | --dry-run] <name>" +msgstr "git remote prune [-n | --dry-run] <namn>" + +#: builtin/remote.c:18 +msgid "" +"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]" +msgstr "" +"git remote [-v | --verbose] update [-p | --prune] [(<grupp> | <fjärr>)...]" + +#: builtin/remote.c:19 +msgid "git remote set-branches [--add] <name> <branch>..." +msgstr "git remote set-branches [--add] <namn> <gren>..." + +#: builtin/remote.c:20 builtin/remote.c:68 +msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]" +msgstr "git remote set-url [--push] <namn> <nyurl> [<gammalurl>]" + +#: builtin/remote.c:21 builtin/remote.c:69 +msgid "git remote set-url --add <name> <newurl>" +msgstr "git remote set-url --add <namn> <nyurl>" + +#: builtin/remote.c:22 builtin/remote.c:70 +msgid "git remote set-url --delete <name> <url>" +msgstr "git remote set-url --delete <namn> <url>" + +#: builtin/remote.c:27 +msgid "git remote add [<options>] <name> <url>" +msgstr "git remote add [<flaggor>] <namn> <url>" + +#: builtin/remote.c:47 +msgid "git remote set-branches <name> <branch>..." +msgstr "git remote set-branches <namn> <gren>..." + +#: builtin/remote.c:48 +msgid "git remote set-branches --add <name> <branch>..." +msgstr "git remote set-branches --add <namn> <gren>..." + +#: builtin/remote.c:53 +msgid "git remote show [<options>] <name>" +msgstr "git remote show [<flaggor>] <namn>" + +#: builtin/remote.c:58 +msgid "git remote prune [<options>] <name>" +msgstr "git remote prune [<flaggor>] <namn>" + +#: builtin/remote.c:63 +msgid "git remote update [<options>] [<group> | <remote>]..." +msgstr "git remote update [<flaggor>] [<grupp> | <fjärr>]..." + #: builtin/remote.c:98 #, c-format msgid "Updating %s" @@ -4078,6 +7180,34 @@ msgstr "" msgid "unknown mirror argument: %s" msgstr "okänt argument till mirror: %s" +#: builtin/remote.c:163 +msgid "fetch the remote branches" +msgstr "hämta fjärrgrenarna" + +#: builtin/remote.c:165 +msgid "import all tags and associated objects when fetching" +msgstr "importera alla taggar och associerade objekt vid hämtning" + +#: builtin/remote.c:168 +msgid "or do not fetch any tag at all (--no-tags)" +msgstr "eller hämta inte nÃ¥gra taggar alls (--no-tags)" + +#: builtin/remote.c:170 +msgid "branch(es) to track" +msgstr "gren(ar) att spÃ¥ra" + +#: builtin/remote.c:171 +msgid "master branch" +msgstr "huvudgren" + +#: builtin/remote.c:172 +msgid "push|fetch" +msgstr "push|fetch" + +#: builtin/remote.c:173 +msgid "set up remote as a mirror to push to or fetch from" +msgstr "ställ in arkiv som spegel att sända eller ta emot frÃ¥n" + #: builtin/remote.c:185 msgid "specifying a master branch makes no sense with --mirror" msgstr "att ange en master-gren ger ingen mening med --mirror" @@ -4274,6 +7404,10 @@ msgstr " %-*s tvingar till %s" msgid " %-*s pushes to %s" msgstr " %-*s sänder till %s" +#: builtin/remote.c:1091 +msgid "do not query remotes" +msgstr "frÃ¥ga inte fjärrar" + #: builtin/remote.c:1118 #, c-format msgid "* remote %s" @@ -4332,6 +7466,14 @@ msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] " Lokal referens konfigurerad för \"git push\"%s:" msgstr[1] " Lokala referenser konfigurerade för \"git push\"%s:" +#: builtin/remote.c:1199 +msgid "set refs/remotes/<name>/HEAD according to remote" +msgstr "sätt refs/remotes/<namn>/HEAD enligt fjärren" + +#: builtin/remote.c:1201 +msgid "delete refs/remotes/<name>/HEAD" +msgstr "ta bort refs/remotes/<namn>/HEAD" + #: builtin/remote.c:1216 msgid "Cannot determine remote HEAD" msgstr "Kan inte bestämma HEAD pÃ¥ fjärren" @@ -4385,15 +7527,35 @@ msgstr " * [skulle rensa] %s" msgid " * [pruned] %s" msgstr " * [rensad] %s" +#: builtin/remote.c:1321 +msgid "prune remotes after fetching" +msgstr "rensa fjärrar efter hämtning" + #: builtin/remote.c:1387 builtin/remote.c:1461 #, c-format msgid "No such remote '%s'" msgstr "Ingen sÃ¥dan fjärr \"%s\"" +#: builtin/remote.c:1407 +msgid "add branch" +msgstr "lägg till gren" + #: builtin/remote.c:1414 msgid "no remote specified" msgstr "ingen fjärr angavs" +#: builtin/remote.c:1436 +msgid "manipulate push URLs" +msgstr "manipulera URL:ar för sändning" + +#: builtin/remote.c:1438 +msgid "add URL" +msgstr "lägg till URL" + +#: builtin/remote.c:1440 +msgid "delete URLs" +msgstr "ta bort URL:ar" + #: builtin/remote.c:1447 msgid "--add --delete doesn't make sense" msgstr "--add --delete ger ingen mening" @@ -4412,6 +7574,56 @@ msgstr "Ingen sÃ¥dan URL hittades: %s" msgid "Will not delete all non-push URLs" msgstr "Kommer inte ta bort alla icke-sänd-URL:er" +#: builtin/remote.c:1569 +msgid "be verbose; must be placed before a subcommand" +msgstr "var pratsam; mÃ¥ste skrivas före ett underkommando" + +#: builtin/replace.c:17 +msgid "git replace [-f] <object> <replacement>" +msgstr "git replace [-f] <objekt> <ersättning>" + +#: builtin/replace.c:18 +msgid "git replace -d <object>..." +msgstr "git replace -d <objekt>..." + +#: builtin/replace.c:19 +msgid "git replace -l [<pattern>]" +msgstr "git replace -l [<mönster>]" + +#: builtin/replace.c:121 +msgid "list replace refs" +msgstr "visa ersättningsreferenser" + +#: builtin/replace.c:122 +msgid "delete replace refs" +msgstr "ta bort ersättningsreferenser" + +#: builtin/replace.c:123 +msgid "replace the ref if it exists" +msgstr "ersätt referensen om den finns" + +#: builtin/rerere.c:11 +msgid "git rerere [clear | forget path... | status | remaining | diff | gc]" +msgstr "git rerere [clear | forget path... | status | remaining | diff | gc]" + +#: builtin/rerere.c:56 +msgid "register clean resolutions in index" +msgstr "registrera rena lösningar i indexet" + +#: builtin/reset.c:25 +msgid "" +"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]" +msgstr "" +"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<incheckning>]" + +#: builtin/reset.c:26 +msgid "git reset [-q] <commit> [--] <paths>..." +msgstr "git reset [-q] <incheckning> [--] <sökvägar>..." + +#: builtin/reset.c:27 +msgid "git reset --patch [<commit>] [--] [<paths>...]" +msgstr "git reset --patch [<incheckning>] [--] [<sökvägar>...]" + #: builtin/reset.c:33 msgid "mixed" msgstr "blandad" @@ -4467,53 +7679,186 @@ msgstr "Oköade ändringar efter Ã¥terställning:" msgid "Cannot do a %s reset in the middle of a merge." msgstr "Kan inte utföra en %s Ã¥terställning mitt i en sammanslagning." -#: builtin/reset.c:297 +#: builtin/reset.c:238 +msgid "be quiet, only report errors" +msgstr "var tyst, rapportera endast fel" + +#: builtin/reset.c:240 +msgid "reset HEAD and index" +msgstr "Ã¥terställ HEAD och index" + +#: builtin/reset.c:241 +msgid "reset only HEAD" +msgstr "Ã¥terställ endast HEAD" + +#: builtin/reset.c:243 builtin/reset.c:245 +msgid "reset HEAD, index and working tree" +msgstr "Ã¥terställ HEAD, index och arbetskatalog" + +#: builtin/reset.c:247 +msgid "reset HEAD but keep local changes" +msgstr "Ã¥terställ HEAD men behÃ¥ll lokala ändringar" + +#: builtin/reset.c:303 #, c-format msgid "Could not parse object '%s'." msgstr "Kan inte tolka objektet \"%s\"" -#: builtin/reset.c:302 +#: builtin/reset.c:308 msgid "--patch is incompatible with --{hard,mixed,soft}" msgstr "--patch är inkompatibel med --{hard,mixed,soft}" -#: builtin/reset.c:311 +#: builtin/reset.c:317 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." msgstr "" "--mixed rekommenderas inte med sökvägar; använd \"git reset -- <sökvägar>\"." -#: builtin/reset.c:313 +#: builtin/reset.c:319 #, c-format msgid "Cannot do %s reset with paths." msgstr "Kan inte göra %s Ã¥terställning med sökvägar." -#: builtin/reset.c:325 +#: builtin/reset.c:331 #, c-format msgid "%s reset is not allowed in a bare repository" msgstr "%s Ã¥terställning tillÃ¥ts inte i ett naket arkiv" -#: builtin/reset.c:341 +#: builtin/reset.c:347 #, c-format msgid "Could not reset index file to revision '%s'." msgstr "Kunde inte Ã¥terställa indexfilen till versionen \"%s\"." +#: builtin/rev-parse.c:339 +msgid "git rev-parse --parseopt [options] -- [<args>...]" +msgstr "git rev-parse --parseopt [options] -- [<argument>...]" + +#: builtin/rev-parse.c:344 +msgid "keep the `--` passed as an arg" +msgstr "behÃ¥ll \"--\" sänt som argument" + +#: builtin/rev-parse.c:346 +msgid "stop parsing after the first non-option argument" +msgstr "sluta tolka efter första argument som inte är flagga" + +#: builtin/rev-parse.c:464 +msgid "" +"git rev-parse --parseopt [options] -- [<args>...]\n" +" or: git rev-parse --sq-quote [<arg>...]\n" +" or: git rev-parse [options] [<arg>...]\n" +"\n" +"Run \"git rev-parse --parseopt -h\" for more information on the first usage." +msgstr "" +"git rev-parse --parseopt [flaggor] -- [<argument>...]\n" +" eller: git rev-parse --sq-quote [<argument>...]\n" +" eller: git rev-parse [flaggor] [<argument>...]\n" +"\n" +"Kör \"git rev-parse --parseopt -h\" för mer information om den första " +"varianten." + +#: builtin/revert.c:22 +msgid "git revert [options] <commit-ish>" +msgstr "git revert [flaggor] <incheckning-igt>" + +#: builtin/revert.c:23 +msgid "git revert <subcommand>" +msgstr "git revert <underkommando>" + +#: builtin/revert.c:28 +msgid "git cherry-pick [options] <commit-ish>" +msgstr "git cherry-pick [flaggor] <incheckning-igt>" + +#: builtin/revert.c:29 +msgid "git cherry-pick <subcommand>" +msgstr "git cherry-pick <underkommando>" + #: builtin/revert.c:70 builtin/revert.c:92 #, c-format msgid "%s: %s cannot be used with %s" msgstr "%s: %s kan inte användas med %s" -#: builtin/revert.c:131 +#: builtin/revert.c:103 +msgid "end revert or cherry-pick sequence" +msgstr "avsluta revert- eller cherry-pick-sekvens" + +#: builtin/revert.c:104 +msgid "resume revert or cherry-pick sequence" +msgstr "Ã¥teruppta revert- eller cherry-pick-sekvens" + +#: builtin/revert.c:105 +msgid "cancel revert or cherry-pick sequence" +msgstr "avbryt revert- eller cherry-pick-sekvens" + +#: builtin/revert.c:106 +msgid "don't automatically commit" +msgstr "checka inte in automatiskt" + +#: builtin/revert.c:107 +msgid "edit the commit message" +msgstr "redigera incheckningsmeddelandet" + +#: builtin/revert.c:110 +msgid "parent number" +msgstr "nummer pÃ¥ förälder" + +#: builtin/revert.c:112 +msgid "merge strategy" +msgstr "sammanslagninsstrategi" + +#: builtin/revert.c:113 +msgid "option" +msgstr "alternativ" + +#: builtin/revert.c:114 +msgid "option for merge strategy" +msgstr "alternativ för sammanslagningsstrategi" + +#: builtin/revert.c:125 +msgid "append commit name" +msgstr "lägg till incheckningsnamn" + +#: builtin/revert.c:126 +msgid "allow fast-forward" +msgstr "tillÃ¥t snabbspolning" + +#: builtin/revert.c:127 +msgid "preserve initially empty commits" +msgstr "behÃ¥ll incheckningar som börjar som tomma" + +#: builtin/revert.c:128 +msgid "allow commits with empty messages" +msgstr "tillÃ¥t incheckningar med tomt meddelande" + +#: builtin/revert.c:129 +msgid "keep redundant, empty commits" +msgstr "behÃ¥ll redundanta, tomma incheckningar" + +#: builtin/revert.c:133 msgid "program error" msgstr "programfel" -#: builtin/revert.c:221 +#: builtin/revert.c:223 msgid "revert failed" msgstr "\"revert\" misslyckades" -#: builtin/revert.c:236 +#: builtin/revert.c:238 msgid "cherry-pick failed" msgstr "\"cherry-pick\" misslyckades" -#: builtin/rm.c:109 +#: builtin/rm.c:15 +msgid "git rm [options] [--] <file>..." +msgstr "git rm [flaggor] [--] <fil>..." + +#: builtin/rm.c:64 builtin/rm.c:186 +#, c-format +msgid "" +"submodule '%s' (or one of its nested submodules) uses a .git directory\n" +"(use 'rm -rf' if you really want to remove it including all of its history)" +msgstr "" +"undermodulen \"%s\" (eller en av dess undermoduler) använder en .git-" +"katalog\n" +"(använd \"rm -rf\" om du verkligen vill ta bort den och all dess historik)" + +#: builtin/rm.c:174 #, c-format msgid "" "'%s' has staged content different from both the file and the HEAD\n" @@ -4522,7 +7867,7 @@ msgstr "" "\"%s\" har köat ändringar som skiljer sig bÃ¥de frÃ¥n filen och HEAD\n" "(använd -f för att tvinga borttagning)" -#: builtin/rm.c:115 +#: builtin/rm.c:180 #, c-format msgid "" "'%s' has changes staged in the index\n" @@ -4531,7 +7876,7 @@ msgstr "" "\"%s\" har köade ändringar i indexet\n" "(använd --cached för att behÃ¥lla filen eller -f för att tvinga borttagning)" -#: builtin/rm.c:119 +#: builtin/rm.c:191 #, c-format msgid "" "'%s' has local modifications\n" @@ -4540,21 +7885,241 @@ msgstr "" "\"%s\" har lokala ändringar\n" "(använd --cached för att behÃ¥lla filen eller -f för att tvinga borttagning)" -#: builtin/rm.c:194 +#: builtin/rm.c:207 +msgid "do not list removed files" +msgstr "lista inte borttagna filer" + +#: builtin/rm.c:208 +msgid "only remove from the index" +msgstr "ta bara bort frÃ¥n indexet" + +#: builtin/rm.c:209 +msgid "override the up-to-date check" +msgstr "överstyr à jour-testet" + +#: builtin/rm.c:210 +msgid "allow recursive removal" +msgstr "tillÃ¥t rekursiv borttagning" + +#: builtin/rm.c:212 +msgid "exit with a zero status even if nothing matched" +msgstr "avsluta med nollstatus även om inget träffades" + +#: builtin/rm.c:283 #, c-format msgid "not removing '%s' recursively without -r" msgstr "tar inte bort \"%s\" rekursivt utan -r" -#: builtin/rm.c:230 +#: builtin/rm.c:322 #, c-format msgid "git rm: unable to remove %s" msgstr "git rm: kan inte ta bort %s" +#: builtin/shortlog.c:13 +msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]" +msgstr "" +"git shortlog [-n] [-s] [-e] [-w] [rev-flaggor] [--] [<incheckning-id>... ]" + #: builtin/shortlog.c:157 #, c-format msgid "Missing author: %s" msgstr "Författare saknas: %s" +#: builtin/shortlog.c:253 +msgid "sort output according to the number of commits per author" +msgstr "sortera utdata enligt antal incheckningar per författare" + +#: builtin/shortlog.c:255 +msgid "Suppress commit descriptions, only provides commit count" +msgstr "Undertryck beskrivningar, visa bara antal incheckningar" + +#: builtin/shortlog.c:257 +msgid "Show the email address of each author" +msgstr "Visa e-postadress för varje författare" + +#: builtin/shortlog.c:258 +msgid "w[,i1[,i2]]" +msgstr "w[,i1[,i2]]" + +#: builtin/shortlog.c:259 +msgid "Linewrap output" +msgstr "Radbryt utdata" + +#: builtin/show-branch.c:9 +msgid "" +"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--" +"current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --" +"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | " +"<glob>)...]" +msgstr "" +"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--" +"current] [--color[=<när>] | --no-color] [--sparse] [--more=<n> | --list | --" +"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | " +"<mönster>)...]" + +#: builtin/show-branch.c:10 +msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]" +msgstr "git show-branch (-g|--reflog)[=<n>[,<bas>]] [--list] [<ref>]" + +#: builtin/show-branch.c:651 +msgid "show remote-tracking and local branches" +msgstr "visa fjärrspÃ¥rande och lokala grenar" + +#: builtin/show-branch.c:653 +msgid "show remote-tracking branches" +msgstr "visa fjärrspÃ¥rande grenar" + +#: builtin/show-branch.c:655 +msgid "color '*!+-' corresponding to the branch" +msgstr "färga \"*!+-\" enligt grenen" + +#: builtin/show-branch.c:657 +msgid "show <n> more commits after the common ancestor" +msgstr "visa <n> ytterligare incheckningar efter gemensam anfader" + +#: builtin/show-branch.c:659 +msgid "synonym to more=-1" +msgstr "synonym till more=-1" + +#: builtin/show-branch.c:660 +msgid "suppress naming strings" +msgstr "undertyck namnsträngar" + +#: builtin/show-branch.c:662 +msgid "include the current branch" +msgstr "inkludera aktuell gren" + +#: builtin/show-branch.c:664 +msgid "name commits with their object names" +msgstr "namnge incheckningar med deras objektnamn" + +#: builtin/show-branch.c:666 +msgid "show possible merge bases" +msgstr "visa möjliga sammanslaningsbaser" + +#: builtin/show-branch.c:668 +msgid "show refs unreachable from any other ref" +msgstr "visa referenser som inte kan nÃ¥s frÃ¥n nÃ¥gon annan referens" + +#: builtin/show-branch.c:670 +msgid "show commits in topological order" +msgstr "visa incheckningar i topologisk ordning" + +#: builtin/show-branch.c:672 +msgid "show only commits not on the first branch" +msgstr "visa endast incheckningar inte pÃ¥ den första grenen" + +#: builtin/show-branch.c:674 +msgid "show merges reachable from only one tip" +msgstr "visa sammanslagningar som endast kan nÃ¥s frÃ¥n en spets" + +#: builtin/show-branch.c:676 +msgid "show commits where no parent comes before its children" +msgstr "visa incheckningar där ingen förälder kommer före dess barn" + +#: builtin/show-branch.c:678 +msgid "<n>[,<base>]" +msgstr "<n>[,<bas>]" + +#: builtin/show-branch.c:679 +msgid "show <n> most recent ref-log entries starting at base" +msgstr "visa <n> nyaste refloggposter med början pÃ¥ bas" + +#: builtin/show-ref.c:10 +msgid "" +"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash" +"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] " +msgstr "" +"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash" +"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [mönster*] " + +#: builtin/show-ref.c:11 +msgid "git show-ref --exclude-existing[=pattern] < ref-list" +msgstr "git show-ref --exclude-existing[=mönster] < reflista" + +#: builtin/show-ref.c:165 +msgid "only show tags (can be combined with heads)" +msgstr "visa endast taggar (kan kombineras med huvuden)" + +#: builtin/show-ref.c:166 +msgid "only show heads (can be combined with tags)" +msgstr "visa endast huvuden (kan kombineras med taggar)" + +#: builtin/show-ref.c:167 +msgid "stricter reference checking, requires exact ref path" +msgstr "striktare referenskontroll, kräver exakt referenssökväg" + +#: builtin/show-ref.c:170 builtin/show-ref.c:172 +msgid "show the HEAD reference" +msgstr "visa HEAD-referensen" + +#: builtin/show-ref.c:174 +msgid "dereference tags into object IDs" +msgstr "avreferera taggar till objekt-id" + +#: builtin/show-ref.c:176 +msgid "only show SHA1 hash using <n> digits" +msgstr "visa SHA1-hash endast med <n> siffror" + +#: builtin/show-ref.c:180 +msgid "do not print results to stdout (useful with --verify)" +msgstr "visa inte resultat pÃ¥ standard ut (användbart med --verify)" + +#: builtin/show-ref.c:182 +msgid "show refs from stdin that aren't in local repository" +msgstr "visa referenser frÃ¥n standard in som inte finns i lokalt arkiv" + +#: builtin/symbolic-ref.c:7 +msgid "git symbolic-ref [options] name [ref]" +msgstr "git symbolic-ref [flaggor] namn [ref]" + +#: builtin/symbolic-ref.c:8 +msgid "git symbolic-ref -d [-q] name" +msgstr "git symbolic-ref -d [-q] namn" + +#: builtin/symbolic-ref.c:40 +msgid "suppress error message for non-symbolic (detached) refs" +msgstr "" +"undertryck felmeddelanden för icke-symboliska (frÃ¥nkopplade) referenser" + +#: builtin/symbolic-ref.c:41 +msgid "delete symbolic ref" +msgstr "ta bort symbolisk referens" + +#: builtin/symbolic-ref.c:42 +msgid "shorten ref output" +msgstr "förkorta ref-utdata" + +#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18 +msgid "reason" +msgstr "skäl" + +#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18 +msgid "reason of the update" +msgstr "skäl till uppdateringen" + +#: builtin/tag.c:22 +msgid "" +"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]" +msgstr "" +"git tag [-a|-s|-u <nyckel-id>] [-f] [-m <medd>|-F <fil>] <taggnamn> [<huvud>]" + +#: builtin/tag.c:23 +msgid "git tag -d <tagname>..." +msgstr "git tag -d <taggnamn>..." + +#: builtin/tag.c:24 +msgid "" +"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n" +"\t\t[<pattern>...]" +msgstr "" +"git tag -l [-n[<antal>]] [--contains <incheckning>] [--points-at <objekt>] \n" +"\t\t[<mönster>...]" + +#: builtin/tag.c:26 +msgid "git tag -v <tagname>..." +msgstr "git tag -v <taggnamn>..." + #: builtin/tag.c:60 #, c-format msgid "malformed object at '%s'" @@ -4644,6 +8209,62 @@ msgstr "flaggan \"points-at\" behöver ett object" msgid "malformed object name '%s'" msgstr "felformat objektnamn \"%s\"" +#: builtin/tag.c:447 +msgid "list tag names" +msgstr "lista taggnamn" + +#: builtin/tag.c:449 +msgid "print <n> lines of each tag message" +msgstr "visa <n> rader frÃ¥n varje taggmeddelande" + +#: builtin/tag.c:451 +msgid "delete tags" +msgstr "ta bort taggar" + +#: builtin/tag.c:452 +msgid "verify tags" +msgstr "verifiera taggar" + +#: builtin/tag.c:454 +msgid "Tag creation options" +msgstr "Alternativ för att skapa taggar" + +#: builtin/tag.c:456 +msgid "annotated tag, needs a message" +msgstr "annoterad tagg, behöver meddelande" + +#: builtin/tag.c:458 +msgid "tag message" +msgstr "taggmeddelande" + +#: builtin/tag.c:460 +msgid "annotated and GPG-signed tag" +msgstr "annoterad och GPG-signerad tagg" + +#: builtin/tag.c:464 +msgid "use another key to sign the tag" +msgstr "använd annan nyckel för att signera taggen" + +#: builtin/tag.c:465 +msgid "replace the tag if exists" +msgstr "ersätt taggen om den finns" + +#: builtin/tag.c:466 +msgid "show tag list in columns" +msgstr "lista taggar i spalter" + +#: builtin/tag.c:468 +msgid "Tag listing options" +msgstr "Alternativ för listning av taggar" + +#: builtin/tag.c:471 +msgid "print only tags that contain the commit" +msgstr "visa endast taggar som innehÃ¥ller incheckningen" + +#: builtin/tag.c:477 +msgid "print only tags of the object" +msgstr "visa endast taggar för objektet" + #: builtin/tag.c:506 msgid "--column and -n are incompatible" msgstr "--column och -n är inkompatibla" @@ -4693,27 +8314,182 @@ msgstr "%s: kan inte uppdatera referensen" msgid "Updated tag '%s' (was %s)\n" msgstr "Uppdaterad tagg \"%s\" (var %s)\n" -#: git.c:16 -msgid "See 'git help <command>' for more information on a specific command." -msgstr "" -"Se \"git help <kommando>\" för mer information om ett specifikt kommando." +#: builtin/update-index.c:401 +msgid "git update-index [options] [--] [<file>...]" +msgstr "git update-index [flaggor] [--] [<fil>...]" -#: parse-options.h:133 parse-options.h:235 -msgid "n" -msgstr "n" +#: builtin/update-index.c:718 +msgid "continue refresh even when index needs update" +msgstr "fortsätt uppdatera även när index inte är à jour" -#: parse-options.h:141 -msgid "time" -msgstr "tid" +#: builtin/update-index.c:721 +msgid "refresh: ignore submodules" +msgstr "refresh: ignorera undermoduler" -# %s är ett verb ("Untracked"/"Ignored"); lägg till ett -e. -#: parse-options.h:149 -msgid "file" -msgstr "fil" +#: builtin/update-index.c:724 +msgid "do not ignore new files" +msgstr "ignorera inte nya filer" -#: parse-options.h:151 -msgid "when" -msgstr "när" +#: builtin/update-index.c:726 +msgid "let files replace directories and vice-versa" +msgstr "lÃ¥t filer ersätta kataloger och omvänt" + +#: builtin/update-index.c:728 +msgid "notice files missing from worktree" +msgstr "lägg märke till filer som saknas i arbetskatalogen" + +#: builtin/update-index.c:730 +msgid "refresh even if index contains unmerged entries" +msgstr "uppdatera även om indexet innehÃ¥ller ej sammanslagna poster" + +#: builtin/update-index.c:733 +msgid "refresh stat information" +msgstr "uppdatera statusinformation" + +#: builtin/update-index.c:737 +msgid "like --refresh, but ignore assume-unchanged setting" +msgstr "som --refresh, men ignorera assume-unchanged-inställning" + +#: builtin/update-index.c:741 +msgid "<mode> <object> <path>" +msgstr "<läge> <objekt> <sökväg>" + +#: builtin/update-index.c:742 +msgid "add the specified entry to the index" +msgstr "lägg till angiven post i indexet" + +#: builtin/update-index.c:746 +msgid "(+/-)x" +msgstr "(+/-)x" + +#: builtin/update-index.c:747 +msgid "override the executable bit of the listed files" +msgstr "överstyr exekveringsbiten för angivna filer" + +#: builtin/update-index.c:751 +msgid "mark files as \"not changing\"" +msgstr "markera filer som \"ändras inte\"" + +#: builtin/update-index.c:754 +msgid "clear assumed-unchanged bit" +msgstr "rensa \"assume-unchanged\"-biten" + +#: builtin/update-index.c:757 +msgid "mark files as \"index-only\"" +msgstr "markera filer som \"endast index\"" + +#: builtin/update-index.c:760 +msgid "clear skip-worktree bit" +msgstr "töm \"skip-worktree\"-biten" + +#: builtin/update-index.c:763 +msgid "add to index only; do not add content to object database" +msgstr "lägg endast till indexet; lägg inte till innehÃ¥llet i objektdatabasen" + +#: builtin/update-index.c:765 +msgid "remove named paths even if present in worktree" +msgstr "ta bort namngivna sökvägar även om de finns i arbetskatalogen" + +#: builtin/update-index.c:767 +msgid "with --stdin: input lines are terminated by null bytes" +msgstr "med --stdin: indatarader termineras med null-byte" + +#: builtin/update-index.c:769 +msgid "read list of paths to be updated from standard input" +msgstr "läs lista över sökvägar att uppdatera frÃ¥n standard in" + +#: builtin/update-index.c:773 +msgid "add entries from standard input to the index" +msgstr "lägg poster frÃ¥n frÃ¥n standard in till indexet" + +#: builtin/update-index.c:777 +msgid "repopulate stages #2 and #3 for the listed paths" +msgstr "Ã¥terfyll etapp 2 och 3 frÃ¥n angivna sökvägar" + +#: builtin/update-index.c:781 +msgid "only update entries that differ from HEAD" +msgstr "uppdatera endast poster som skiljer sig frÃ¥n HEAD" + +#: builtin/update-index.c:785 +msgid "ignore files missing from worktree" +msgstr "ignorera filer som saknas i arbetskatalogen" + +#: builtin/update-index.c:788 +msgid "report actions to standard output" +msgstr "raportera Ã¥tgärder pÃ¥ standard ut" + +#: builtin/update-index.c:790 +msgid "(for porcelains) forget saved unresolved conflicts" +msgstr "(för porslin) glöm sparade olösta konflikter" + +#: builtin/update-index.c:794 +msgid "write index in this format" +msgstr "skriv index i detta format" + +#: builtin/update-ref.c:7 +msgid "git update-ref [options] -d <refname> [<oldval>]" +msgstr "git update-ref [flaggor] -d <refnamn> [<gammaltvärde>]" + +#: builtin/update-ref.c:8 +msgid "git update-ref [options] <refname> <newval> [<oldval>]" +msgstr "git update-ref [flaggor] <refnamn> <gammaltvärde> [<nyttvärde>]" + +#: builtin/update-ref.c:19 +msgid "delete the reference" +msgstr "ta bort referensen" + +#: builtin/update-ref.c:21 +msgid "update <refname> not the one it points to" +msgstr "uppdatera <refnamn> inte det den pekar pÃ¥" + +#: builtin/update-server-info.c:6 +msgid "git update-server-info [--force]" +msgstr "git update-server-info [--force]" + +#: builtin/update-server-info.c:14 +msgid "update the info files from scratch" +msgstr "uppdatera informationsfilerna frÃ¥n grunden" + +#: builtin/verify-pack.c:56 +msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..." +msgstr "git verify-pack [-v|--verbose] [-s|--stat-only] <paket>..." + +#: builtin/verify-pack.c:66 +msgid "verbose" +msgstr "pratsam" + +#: builtin/verify-pack.c:68 +msgid "show statistics only" +msgstr "visa endast statistik" + +#: builtin/verify-tag.c:17 +msgid "git verify-tag [-v|--verbose] <tag>..." +msgstr "git verify-tag [-v|--verbose] <tagg>..." + +#: builtin/verify-tag.c:73 +msgid "print tag contents" +msgstr "visa innehÃ¥ll för tag" + +#: builtin/write-tree.c:13 +msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]" +msgstr "git write-tree [--missing-ok] [--prefix=<prefix>/]" + +#: builtin/write-tree.c:26 +msgid "<prefix>/" +msgstr "<prefix>/" + +#: builtin/write-tree.c:27 +msgid "write tree object for a subdirectory <prefix>" +msgstr "visa trädobjekt för underkatalogen <prefix>" + +#: builtin/write-tree.c:30 +msgid "only useful for debugging" +msgstr "endast användbart vid felsökning" + +#: git.c:16 +msgid "See 'git help <command>' for more information on a specific command." +msgstr "" +"Se \"git help <kommando>\" för mer information om ett specifikt kommando." #: parse-options.h:156 msgid "no-op (backward compatibility)" @@ -4813,7 +8589,7 @@ msgstr "Visa status för arbetskatalogen" #: common-cmds.h:28 msgid "Create, list, delete or verify a tag object signed with GPG" -msgstr "Skapa, visa, ta bort eller verifiera ett taggobjekt signerat med GPG" +msgstr "Skapa, visa, ta bort eller verifiera GPG-signerat taggobjekt" #: git-am.sh:50 msgid "You need to set your committer info first" @@ -4830,9 +8606,9 @@ msgstr "" #: git-am.sh:105 #, sh-format msgid "" -"When you have resolved this problem run \"$cmdline --resolved\".\n" -"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n" -"To restore the original branch and stop patching run \"$cmdline --abort\"." +"When you have resolved this problem, run \"$cmdline --resolved\".\n" +"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n" +"To restore the original branch and stop patching, run \"$cmdline --abort\"." msgstr "" "När du har löst problemet kör du \"$cmdline --resolved\".\n" "Om du vill hoppa över patchen kör du istället \"$cmdline --skip\".\n" @@ -4848,6 +8624,10 @@ msgstr "" "Arkivet saknar objekt som behövs för att falla tillbaka pÃ¥ 3-" "vägssammanslagning." +#: git-am.sh:139 +msgid "Using index info to reconstruct a base tree..." +msgstr "Använder indexinfo för att Ã¥teskapa ett basträd..." + #: git-am.sh:154 msgid "" "Did you hand edit your patch?\n" @@ -4861,42 +8641,50 @@ msgid "Falling back to patching base and 3-way merge..." msgstr "" "Faller tillbaka pÃ¥ att pacha grundversionen och trevägssammanslagning..." -#: git-am.sh:275 +#: git-am.sh:179 +msgid "Failed to merge in the changes." +msgstr "Misslyckads slÃ¥ ihop ändringarna." + +#: git-am.sh:274 msgid "Only one StGIT patch series can be applied at once" msgstr "Endast en StGIT-patchserie kan tillämpas Ã¥t gÃ¥ngen" -#: git-am.sh:362 +#: git-am.sh:361 #, sh-format msgid "Patch format $patch_format is not supported." msgstr "Patchformatet $patch_format stöds inte." -#: git-am.sh:364 +#: git-am.sh:363 msgid "Patch format detection failed." msgstr "Misslyckades detektera patchformat." -#: git-am.sh:418 -msgid "-d option is no longer supported. Do not use." -msgstr "Flaggan -d stöds inte lägre. Använd inte." +#: git-am.sh:389 +msgid "" +"The -b/--binary option has been a no-op for long time, and\n" +"it will be removed. Please do not use it anymore." +msgstr "" +"Flaggan -b/--binary har varit utan funktion länge, och\n" +"kommer tas bort. Vi ber dig att inte använda den längre." -#: git-am.sh:481 +#: git-am.sh:477 #, sh-format msgid "previous rebase directory $dotest still exists but mbox given." msgstr "tidigare rebase-katalog $dotest finns fortfarande, men mbox angavs." -#: git-am.sh:486 +#: git-am.sh:482 msgid "Please make up your mind. --skip or --abort?" msgstr "Bestäm dig. --skip eller --abort?" -#: git-am.sh:513 +#: git-am.sh:509 msgid "Resolve operation not in progress, we are not resuming." msgstr "Lösningsoperation pÃ¥gÃ¥r inte, vi Ã¥terupptar inte." -#: git-am.sh:579 +#: git-am.sh:575 #, sh-format msgid "Dirty index: cannot apply patches (dirty: $files)" msgstr "Smutsigt index: kan inte tillämpa patchar (smutsiga: $files)" -#: git-am.sh:671 +#: git-am.sh:679 #, sh-format msgid "" "Patch is empty. Was it split wrong?\n" @@ -4907,32 +8695,32 @@ msgstr "" "Om du vill hoppa över patchen kör du istället \"$cmdline --skip\".\n" "För att Ã¥terställa originalgrenen och avbryta kör du \"$cmdline --abort\"." -#: git-am.sh:708 +#: git-am.sh:706 msgid "Patch does not have a valid e-mail address." msgstr "Patchen har inte nÃ¥gon giltig e-postadress." -#: git-am.sh:755 +#: git-am.sh:753 msgid "cannot be interactive without stdin connected to a terminal." msgstr "" "kan inte vara interaktiv om standard in inte är ansluten till en terminal." -#: git-am.sh:759 +#: git-am.sh:757 msgid "Commit Body is:" msgstr "Incheckningskroppen är:" #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] #. in your translation. The program will only accept English #. input at this point. -#: git-am.sh:766 +#: git-am.sh:764 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " msgstr "Tillämpa? Y=ja/N=nej/E=redigera/V=visa patch/A=godta alla " -#: git-am.sh:802 +#: git-am.sh:800 #, sh-format msgid "Applying: $FIRSTLINE" msgstr "Tillämpar: $FIRSTLINE" -#: git-am.sh:823 +#: git-am.sh:821 msgid "" "No changes - did you forget to use 'git add'?\n" "If there is nothing left to stage, chances are that something else\n" @@ -4942,7 +8730,7 @@ msgstr "" "Om det inte är nÃ¥got kvar att köa kan det hända att nÃ¥got annat redan\n" "introducerat samma ändringar; kanske du bör hoppa över patchen." -#: git-am.sh:831 +#: git-am.sh:829 msgid "" "You still have unmerged paths in your index\n" "did you forget to use 'git add'?" @@ -4950,16 +8738,25 @@ msgstr "" "Du har fortfarande sökvägar som inte slagits samman i ditt index\n" "glömde du använda \"git add\"?" -#: git-am.sh:847 +#: git-am.sh:845 msgid "No changes -- Patch already applied." msgstr "Inga ändringar -- Patchen har redan tillämpats." -#: git-am.sh:857 +#: git-am.sh:855 #, sh-format msgid "Patch failed at $msgnum $FIRSTLINE" msgstr "Patchen misslyckades vid $msgnum $FIRSTLINE" -#: git-am.sh:873 +#: git-am.sh:858 +#, sh-format +msgid "" +"The copy of the patch that failed is found in:\n" +" $dotest/patch" +msgstr "" +"En kopia av patchen som misslyckades finns i:\n" +" $dotest/patch" + +#: git-am.sh:876 msgid "applying to an empty history" msgstr "tillämpar pÃ¥ en tom historik" @@ -5143,7 +8940,7 @@ msgstr "uppdaterar en ofödd gren med ändringar som lagts till i indexet" #. The working tree and the index file is still based on the #. $orig_head commit, but we are merging into $curr_head. #. First update the working tree to match $curr_head. -#: git-pull.sh:228 +#: git-pull.sh:229 #, sh-format msgid "" "Warning: fetch updated the current branch head.\n" @@ -5154,14 +8951,138 @@ msgstr "" "Varning: snabbspolar din arbetskatalog frÃ¥n\n" "Varning: incheckningen $orig_head." -#: git-pull.sh:253 +#: git-pull.sh:254 msgid "Cannot merge multiple branches into empty head" msgstr "Kan inte slÃ¥ ihop flera grenar i ett tomt huvud." -#: git-pull.sh:257 +#: git-pull.sh:258 msgid "Cannot rebase onto multiple branches" msgstr "Kan inte utföra en \"rebase\" ovanpÃ¥ flera grenar" +#: git-rebase.sh:53 +msgid "" +"When you have resolved this problem, run \"git rebase --continue\".\n" +"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n" +"To check out the original branch and stop rebasing, run \"git rebase --abort" +"\"." +msgstr "" +"När du har löst problemet kör du \"git rebase --continue\".\n" +"Om du vill hoppa över patchen kör du istället \"git rebase --skip\".\n" +"För att Ã¥terställa originalgrenen och avbryta kör du \"git rebase --abort\"." + +#: git-rebase.sh:160 +msgid "The pre-rebase hook refused to rebase." +msgstr "Kroken pre-rebase vägrade ombaseringen." + +#: git-rebase.sh:165 +msgid "It looks like git-am is in progress. Cannot rebase." +msgstr "Det verkar som en git-am körs. Kan inte ombasera." + +#: git-rebase.sh:296 +msgid "The --exec option must be used with the --interactive option" +msgstr "Flaggan --exec mÃ¥ste användas tillsammans med flaggan --interactive" + +#: git-rebase.sh:301 +msgid "No rebase in progress?" +msgstr "Ingen ombasering pÃ¥gÃ¥r?" + +#: git-rebase.sh:312 +msgid "The --edit-todo action can only be used during interactive rebase." +msgstr "Ã…tgärden --edit-todo kan endast användas under interaktiv ombasering." + +#: git-rebase.sh:319 +msgid "Cannot read HEAD" +msgstr "Kan inte läsa HEAD" + +#: git-rebase.sh:322 +msgid "" +"You must edit all merge conflicts and then\n" +"mark them as resolved using git add" +msgstr "" +"Du mÃ¥ste redigera alla sammanslagningskonflikter och\n" +"därefter markera dem som lösta med git add" + +#: git-rebase.sh:340 +#, sh-format +msgid "Could not move back to $head_name" +msgstr "Kunde inte flytta tillbaka till $head_name" + +#: git-rebase.sh:359 +#, sh-format +msgid "" +"It seems that there is already a $state_dir_base directory, and\n" +"I wonder if you are in the middle of another rebase. If that is the\n" +"case, please try\n" +"\t$cmd_live_rebase\n" +"If that is not the case, please\n" +"\t$cmd_clear_stale_rebase\n" +"and run me again. I am stopping in case you still have something\n" +"valuable there." +msgstr "" +"Det verkar som katalogen $state_dir_base redan existerar, och\n" +"jag undrar om du redan är mitt i en annan ombasering. Om sÃ¥ är\n" +"fallet, försök\n" +"\t$cmd_live_rebase\n" +"Om sÃ¥ inte är fallet, kör\n" +"\t$cmd_clear_stale_rebase\n" +"och kör programmet igen. Jag avslutar ifall du fortfarande har\n" +"nÃ¥got av värde där." + +#: git-rebase.sh:404 +#, sh-format +msgid "invalid upstream $upstream_name" +msgstr "ogiltig uppström $upstream_name" + +#: git-rebase.sh:428 +#, sh-format +msgid "$onto_name: there are more than one merge bases" +msgstr "$onto_name: mer än en sammanslagningsbas finns" + +#: git-rebase.sh:431 git-rebase.sh:435 +#, sh-format +msgid "$onto_name: there is no merge base" +msgstr "$onto_name: ingen sammanslagningsbas finns" + +#: git-rebase.sh:440 +#, sh-format +msgid "Does not point to a valid commit: $onto_name" +msgstr "Peka pÃ¥ en giltig incheckning: $onto_name" + +#: git-rebase.sh:463 +#, sh-format +msgid "fatal: no such branch: $branch_name" +msgstr "ödesdigert: ingen sÃ¥dan gren: $branch_name" + +#: git-rebase.sh:483 +msgid "Please commit or stash them." +msgstr "Checka in eller använd \"stash\" pÃ¥ dem." + +#: git-rebase.sh:501 +#, sh-format +msgid "Current branch $branch_name is up to date." +msgstr "Aktuell gren $branch_name är à jour." + +#: git-rebase.sh:504 +#, sh-format +msgid "Current branch $branch_name is up to date, rebase forced." +msgstr "Aktuell gren $branch_name är à jour, ombasering framtvingad." + +#: git-rebase.sh:515 +#, sh-format +msgid "Changes from $mb to $onto:" +msgstr "Ändringar frÃ¥n $mb till $onto:" + +#. Detach HEAD and reset the tree +#: git-rebase.sh:524 +msgid "First, rewinding head to replay your work on top of it..." +msgstr "" +"Först, spolar tillbaka huvudet för att spela av ditt arbete ovanpÃ¥ det..." + +#: git-rebase.sh:532 +#, sh-format +msgid "Fast-forwarded $branch_name to $onto_name." +msgstr "Snabbspolade $branch_name till $onto_name." + #: git-stash.sh:51 msgid "git stash clear with parameters is unimplemented" msgstr "\"git stash clear\" med parametrar har inte implementerats" @@ -5269,60 +9190,60 @@ msgstr "Kunde inte spara indexträd" msgid "Cannot unstage modified files" msgstr "Kan inte ta bort ändrade filer ur kön" -#: git-stash.sh:474 +#: git-stash.sh:475 msgid "Index was not unstashed." msgstr "Indexet har inte tagits ur kön." -#: git-stash.sh:491 +#: git-stash.sh:492 #, sh-format msgid "Dropped ${REV} ($s)" msgstr "Kastade ${REV} ($s)" -#: git-stash.sh:492 +#: git-stash.sh:493 #, sh-format msgid "${REV}: Could not drop stash entry" msgstr "${REV}: Kunde inte kasta \"stash\"-post" -#: git-stash.sh:499 +#: git-stash.sh:500 msgid "No branch name specified" msgstr "Inget grennamn angavs" -#: git-stash.sh:570 +#: git-stash.sh:571 msgid "(To restore them type \"git stash apply\")" msgstr "(För att Ã¥terställa dem, skriv \"git stash apply\")" -#: git-submodule.sh:56 +#: git-submodule.sh:89 #, sh-format msgid "cannot strip one component off url '$remoteurl'" msgstr "kan inte ta bort en komponent frÃ¥n url:en \"$remoteurl\"" -#: git-submodule.sh:109 +#: git-submodule.sh:168 #, sh-format msgid "No submodule mapping found in .gitmodules for path '$sm_path'" msgstr "" "Hittade ingen undermodulmappning i .gitmodules för sökvägen \"$sm_path\"" -#: git-submodule.sh:150 +#: git-submodule.sh:211 #, sh-format msgid "Clone of '$url' into submodule path '$sm_path' failed" msgstr "Misslyckades klona \"$url\" till undermodulsökvägen \"$sm_path\"" -#: git-submodule.sh:160 +#: git-submodule.sh:223 #, sh-format msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa" msgstr "Gitkatalog \"$a\" ingÃ¥r i underkatalogsökvägen \"$b\" eller omvänt" -#: git-submodule.sh:249 +#: git-submodule.sh:316 #, sh-format msgid "repo URL: '$repo' must be absolute or begin with ./|../" msgstr "arkiv-URL: \"$repo\" mÃ¥ste vara absolut eller börja med ./|../" -#: git-submodule.sh:266 +#: git-submodule.sh:333 #, sh-format msgid "'$sm_path' already exists in the index" msgstr "\"$sm_path\" finns redan i indexet" -#: git-submodule.sh:270 +#: git-submodule.sh:337 #, sh-format msgid "" "The following path is ignored by one of your .gitignore files:\n" @@ -5333,64 +9254,98 @@ msgstr "" "$sm_path\n" "Använd -f om du verkligen vill lägga till den" -#: git-submodule.sh:281 +#: git-submodule.sh:355 #, sh-format msgid "Adding existing repo at '$sm_path' to the index" msgstr "Lägger till befintligt arkiv i \"$sm_path\" i indexet" -#: git-submodule.sh:283 +#: git-submodule.sh:357 #, sh-format msgid "'$sm_path' already exists and is not a valid git repo" msgstr "\"$sm_path\" finns redan och är inte ett giltigt git-arkiv" -#: git-submodule.sh:297 +#: git-submodule.sh:365 +#, sh-format +msgid "A git directory for '$sm_name' is found locally with remote(s):" +msgstr "En git-katalog för \"$sm_name\" hittades lokalt med fjärr(ar):" + +#: git-submodule.sh:367 +#, sh-format +msgid "" +"If you want to reuse this local git directory instead of cloning again from" +msgstr "" +"För att Ã¥teranvända den lokala git-katalogen istället för att pÃ¥ nytt klona " +"frÃ¥n" + +#: git-submodule.sh:369 +#, sh-format +msgid "" +"use the '--force' option. If the local git directory is not the correct repo" +msgstr "" +"använd flaggan \"--force\". Om den lokala git-katalogen inte är riktigt arkiv" + +#: git-submodule.sh:370 +#, sh-format +msgid "" +"or you are unsure what this means choose another name with the '--name' " +"option." +msgstr "" +"eller om du är osäker pÃ¥ vad det innebär, välj nytt namn med flaggan \"--name" +"\"." + +#: git-submodule.sh:372 +#, sh-format +msgid "Reactivating local git directory for submodule '$sm_name'." +msgstr "Aktiverar lokal git-katalog för undermodulen \"$sm_name\" pÃ¥ nytt." + +#: git-submodule.sh:384 #, sh-format msgid "Unable to checkout submodule '$sm_path'" msgstr "Kan inte checka ut undermodulen \"$sm_path\"" -#: git-submodule.sh:302 +#: git-submodule.sh:389 #, sh-format msgid "Failed to add submodule '$sm_path'" msgstr "Misslyckades lägga till undermodulen \"$sm_path\"" -#: git-submodule.sh:307 +#: git-submodule.sh:394 #, sh-format msgid "Failed to register submodule '$sm_path'" msgstr "Misslyckades registrera undermodulen \"$sm_path\"" -#: git-submodule.sh:349 +#: git-submodule.sh:437 #, sh-format msgid "Entering '$prefix$sm_path'" msgstr "GÃ¥r in i \"$prefix$sm_path\"" -#: git-submodule.sh:363 +#: git-submodule.sh:451 #, sh-format msgid "Stopping at '$sm_path'; script returned non-zero status." msgstr "" "Stoppar pÃ¥ \"$sm_path\"; skriptet returnerade en status skild frÃ¥n noll." -#: git-submodule.sh:406 +#: git-submodule.sh:495 #, sh-format msgid "No url found for submodule path '$sm_path' in .gitmodules" msgstr "Hittade ingen url för undermodulsökvägen \"$sm_path\" i .gitmodules" -#: git-submodule.sh:415 +#: git-submodule.sh:504 #, sh-format msgid "Failed to register url for submodule path '$sm_path'" msgstr "Misslyckades registrera url för underkatalogsökväg \"$sm_path\"" -#: git-submodule.sh:417 +#: git-submodule.sh:506 #, sh-format msgid "Submodule '$name' ($url) registered for path '$sm_path'" msgstr "Undermodulen \"$name\" ($url) registrerad för sökvägen \"$sm_path\"" -#: git-submodule.sh:425 +#: git-submodule.sh:514 #, sh-format msgid "Failed to register update mode for submodule path '$sm_path'" msgstr "" "Misslyckades registrera uppdateringsläge för undermodulsökväg \"$sm_path\"" -#: git-submodule.sh:524 +#: git-submodule.sh:614 #, sh-format msgid "" "Submodule path '$sm_path' not initialized\n" @@ -5399,96 +9354,163 @@ msgstr "" "Undermodulen \"$sm_path\" har inte initierats\n" "Kanske du vill köra \"update --init\"?" -#: git-submodule.sh:537 +#: git-submodule.sh:627 #, sh-format msgid "Unable to find current revision in submodule path '$sm_path'" msgstr "Kan inte hitta aktuell revision i undermodulsökväg \"$sm_path\"" -#: git-submodule.sh:556 +#: git-submodule.sh:646 #, sh-format msgid "Unable to fetch in submodule path '$sm_path'" msgstr "Kan inte hämta i undermodulsökväg \"$sm_path\"" -#: git-submodule.sh:570 +#: git-submodule.sh:660 #, sh-format msgid "Unable to rebase '$sha1' in submodule path '$sm_path'" msgstr "Kan inte ombasera \"$sha1\" i undermodulsökväg \"$sm_path\"" -#: git-submodule.sh:571 +#: git-submodule.sh:661 #, sh-format msgid "Submodule path '$sm_path': rebased into '$sha1'" msgstr "Undermodulsökvägen \"$sm_path\": ombaserade in i \"$sha1\"" -#: git-submodule.sh:576 +#: git-submodule.sh:666 #, sh-format msgid "Unable to merge '$sha1' in submodule path '$sm_path'" msgstr "Kan inte slÃ¥ ihop \"$sha1\" i undermodulsökvägen \"$sm_path\"" -#: git-submodule.sh:577 +#: git-submodule.sh:667 #, sh-format msgid "Submodule path '$sm_path': merged in '$sha1'" msgstr "Undermodulsökvägen \"$sm_path\": sammanslagen i \"$sha1\"" -#: git-submodule.sh:582 +#: git-submodule.sh:672 #, sh-format msgid "Unable to checkout '$sha1' in submodule path '$sm_path'" msgstr "Kan inte checka ut \"$sha1\" i undermodulsökvägen \"$sm_path\"" -#: git-submodule.sh:583 +#: git-submodule.sh:673 #, sh-format msgid "Submodule path '$sm_path': checked out '$sha1'" msgstr "Undermodulsökvägen \"$sm_path\": checkade ut \"$sha1\"" -#: git-submodule.sh:605 git-submodule.sh:928 +#: git-submodule.sh:695 git-submodule.sh:1017 #, sh-format msgid "Failed to recurse into submodule path '$sm_path'" msgstr "Misslyckades rekursera in i undermodulsökvägen \"$sm_path\"" -#: git-submodule.sh:713 -msgid "--cached cannot be used with --files" -msgstr "--cached kan inte användas med --files" +#: git-submodule.sh:803 +msgid "The --cached option cannot be used with the --files option" +msgstr "Flaggan --cached kan inte användas med flaggan --files" #. unexpected type -#: git-submodule.sh:753 +#: git-submodule.sh:843 #, sh-format msgid "unexpected mode $mod_dst" msgstr "oväntat läge $mod_dst" -#: git-submodule.sh:771 +#: git-submodule.sh:861 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_src" msgstr " Varning: $name innehÃ¥ller inte incheckning $sha1_src" -#: git-submodule.sh:774 +#: git-submodule.sh:864 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_dst" msgstr " Varning: $name innehÃ¥ller inte incheckning $sha1_dst" -#: git-submodule.sh:777 +#: git-submodule.sh:867 #, sh-format msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst" msgstr " Varning: $name innehÃ¥ller inte incheckningar $sha1_src och $sha1_dst" -#: git-submodule.sh:802 +#: git-submodule.sh:892 msgid "blob" msgstr "blob" -#: git-submodule.sh:803 -msgid "submodule" -msgstr "undermodul" - -#: git-submodule.sh:840 +#: git-submodule.sh:930 msgid "# Submodules changed but not updated:" msgstr "# Undermoduler ändrade men inte uppdaterade:" -#: git-submodule.sh:842 +#: git-submodule.sh:932 msgid "# Submodule changes to be committed:" msgstr "# Undermodulers ändringar att checka in:" -#: git-submodule.sh:974 +#: git-submodule.sh:1080 #, sh-format -msgid "Synchronizing submodule url for '$name'" -msgstr "Synkroniserar undermodul-url för \"$name\"" +msgid "Synchronizing submodule url for '$prefix$sm_path'" +msgstr "Synkroniserar undermodul-url för \"$prefix$sm_path\"" + +#~ msgid "git remote set-head <name> (-a | -d | <branch>])" +#~ msgstr "git remote set-head <namn> (-a | -d | <gren>])" + +#~ msgid " 0 files changed" +#~ msgstr " 0 filer ändrade" + +#~ msgid " %d file changed" +#~ msgid_plural " %d files changed" +#~ msgstr[0] " %d fil ändrad" +#~ msgstr[1] " %d filer ändrade" + +#~ msgid ", %d insertion(+)" +#~ msgid_plural ", %d insertions(+)" +#~ msgstr[0] ", %d tillägg(+)" +#~ msgstr[1] ", %d tillägg(+)" + +#~ msgid ", %d deletion(-)" +#~ msgid_plural ", %d deletions(-)" +#~ msgstr[0] ", %d borttagning(-)" +#~ msgstr[1] ", %d borttagningar(-)" + +#~ msgid "Auto packing the repository for optimum performance.\n" +#~ msgstr "Packar arkivet automatiskt för optimal prestanda.\n" + +#~ msgid " (use \"git add\" to track)" +#~ msgstr " (spÃ¥ra med \"git add\")" + +#~ msgid "-B cannot be used with -b" +#~ msgstr "-B kan inte användas med -b" + +#~ msgid "--patch is incompatible with all other options" +#~ msgstr "--patch är inkompatibel med alla andra flaggor" + +#~ msgid "--detach cannot be used with -b/-B/--orphan" +#~ msgstr "--detcah kan inte användas med -b/-B/--orphan" + +#~ msgid "--detach cannot be used with -t" +#~ msgstr "--detach kan inte användas med -t" + +#~ msgid "--orphan and -b|-B are mutually exclusive" +#~ msgstr "--orphan och -b|-B kan inte användas samtidigt" + +#~ msgid "--orphan cannot be used with -t" +#~ msgstr "--orphan kan inte användas med -t" + +#~ msgid "git checkout: -f and -m are incompatible" +#~ msgstr "git checkout: -f och -m är inkompatibla" + +#~ msgid "" +#~ "git checkout: updating paths is incompatible with switching branches." +#~ msgstr "" +#~ "git checkout: uppdatera sökvägar är inkompatibelt med att växla gren." + +#~ msgid "diff setup failed" +#~ msgstr "misslyckades sätta upp för diff" + +#~ msgid "merge-recursive: disk full?" +#~ msgstr "merge-recursive: disk full?" + +#~ msgid "diff_setup_done failed" +#~ msgstr "diff_setup_done misslyckades" + +#~ msgid "%s: has been deleted/renamed" +#~ msgstr "%s: har tagits bort/ändrat namn" + +#~ msgid "'%s': not a documentation directory." +#~ msgstr "\"%s\": inte en dokumentationskatalog." + +#~ msgid "-d option is no longer supported. Do not use." +#~ msgstr "Flaggan -d stöds inte lägre. Använd inte." #~ msgid "cherry-pick" #~ msgstr "cherry-pick" @@ -5502,9 +9524,6 @@ msgstr "Synkroniserar undermodul-url för \"$name\"" #~ msgid "--" #~ msgstr "--" -#~ msgid "Too many options specified" -#~ msgstr "För mÃ¥nga flaggor angavs" - #~ msgid "# Changed but not updated:" #~ msgstr "# Ändrade men inte uppdaterade:" @@ -5529,26 +9548,17 @@ msgstr "Synkroniserar undermodul-url för \"$name\"" #~ msgid "cannot mix --fixed-strings and regexp" #~ msgstr "kan inte blanda --fixed-strings och reguljära uttryck" -#~ msgid "invalid --decorate option: %s" -#~ msgstr "felaktigt värde till --decorate: %s" - #~ msgid "%s; will overwrite!" #~ msgstr "%s; kommer skriva över!" #~ msgid "Failed to write current notes tree to database" #~ msgstr "Kunde inte skriva aktuellt anteckningsträd till databasen" -#~ msgid "Failed to commit notes tree to database" -#~ msgstr "Kunde inte checka in anteckningsträd i databasen" - # FIXME: Untranslatable! # #~ msgid "Refusing to %s notes in %s (outside of refs/notes/)" #~ msgstr "Vägrar %s anteckningar i %s (utanför refs/notes/)" -#~ msgid "list" -#~ msgstr "list" - #~ msgid "add" #~ msgstr "add" @@ -2,23 +2,22 @@ # Copyright (C) 2012, Trần Ngá»c Quân. # This file is distributed under the same license as the git-core package. # First translated by Trần Ngá»c Quân <vnwildman@gmail.com>, 2012. +# Nguyá»…n Thái Ngá»c Duy <pclouds@gmail.com>, 2012. # msgid "" msgstr "" -"Project-Id-Version: git-1.7.11.rc2.2.gb694fbb\n" +"Project-Id-Version: git-v1.8.0.1-347-gf94c3\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2012-06-08 10:20+0800\n" -"PO-Revision-Date: 2012-06-09 14:08+0700\n" +"POT-Creation-Date: 2012-11-30 12:40+0800\n" +"PO-Revision-Date: 2012-11-30 13:40+0700\n" "Last-Translator: Trần Ngá»c Quân <vnwildman@gmail.com>\n" "Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n" +"Language: vi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: \n" "Plural-Forms: nplurals=2; plural=1;\n" -"X-Poedit-Language: Vietnamese\n" -"X-Poedit-Country: VIET NAM\n" -"X-Poedit-SourceCharset: utf-8\n" +"X-Poedit-SourceCharset: UTF-8\n" "X-Poedit-Basepath: ../\n" #: advice.c:40 @@ -38,41 +37,129 @@ msgid "" "or use 'git commit -a'." msgstr "" "Sá»a chúng trong cây là m việc,\n" -"và sau đó sá» dụng lệnh 'git add/rm <táºp-tin>'\n" -"dà nh riêng cho việc đánh dấu cần giải quyết và tạo lần chuyển giao,\n" -"hoặc là sá» dụng lệnh 'git commit -a'." +"và sau đó dùng lệnh “git add/rm <táºp-tin>†dà nh riêng\n" +"cho việc đánh dấu táºp tin cần giải quyết và tạo lần chuyển giao,\n" +"hoặc là dùng lệnh “git commit -aâ€." + +#: archive.c:10 +msgid "git archive [options] <tree-ish> [<path>...]" +msgstr "git archive [các-tùy-chá»n] <tree-ish> [<đưá»ng-dẫn>...]" + +#: archive.c:11 +msgid "git archive --list" +msgstr "git archive --list" + +#: archive.c:12 +msgid "" +"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]" +msgstr "" +"git archive --remote <kho> [--exec <lệnh>] [các-tùy-chá»n] <tree-ish> [<đưá»ng-" +"dẫn>...]" + +#: archive.c:13 +msgid "git archive --remote <repo> [--exec <cmd>] --list" +msgstr "git archive --remote <kho> [--exec <lệnh>] --list" + +#: archive.c:322 +msgid "fmt" +msgstr "fmt" + +#: archive.c:322 +msgid "archive format" +msgstr "định dạng lưu trữ" + +#: archive.c:323 builtin/log.c:1084 +msgid "prefix" +msgstr "tiá»n tố" + +#: archive.c:324 +msgid "prepend prefix to each pathname in the archive" +msgstr "nối thêm tiá»n tố và o từng đưá»ng dẫn táºp tin trong kho lưu" + +#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2390 +#: builtin/blame.c:2391 builtin/config.c:55 builtin/fast-export.c:642 +#: builtin/fast-export.c:644 builtin/grep.c:715 builtin/hash-object.c:77 +#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:540 +#: builtin/notes.c:697 builtin/read-tree.c:107 parse-options.h:149 +msgid "file" +msgstr "táºp-tin" + +#: archive.c:326 builtin/archive.c:92 +msgid "write the archive to this file" +msgstr "ghi kho lưu và o táºp tin nà y" + +#: archive.c:328 +msgid "read .gitattributes in working directory" +msgstr "Ä‘á»c .gitattributes trong thư mục là m việc" + +#: archive.c:329 +msgid "report archived files on stderr" +msgstr "liệt kê các táºp tin được lưu trữ và o stderr (đầu ra lá»—i chuẩn)" + +#: archive.c:330 +msgid "store only" +msgstr "chỉ lưu (không nén)" + +#: archive.c:331 +msgid "compress faster" +msgstr "nén nhanh hÆ¡n" + +#: archive.c:339 +msgid "compress better" +msgstr "nén nhá» hÆ¡n" + +#: archive.c:342 +msgid "list supported archive formats" +msgstr "liệt kê các kiểu nén được há»— trợ" + +#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85 +msgid "repo" +msgstr "kho" + +#: archive.c:345 builtin/archive.c:94 +msgid "retrieve the archive from remote repository <repo>" +msgstr "nháºn kho lưu từ kho chứa <kho> trên máy chá»§" + +#: archive.c:346 builtin/archive.c:95 builtin/notes.c:619 +msgid "command" +msgstr "lệnh" + +#: archive.c:347 builtin/archive.c:96 +msgid "path to the remote git-upload-archive command" +msgstr "đưá»ng dẫn đến lệnh git-upload-pack trên máy chá»§" + +#: attr.c:259 +msgid "" +"Negative patterns are forbidden in git attributes\n" +"Use '\\!' for literal leading exclamation." +msgstr "" +"Mấu dạng phá»§ định bị cấm chỉ dùng trong các thuá»™c tÃnh cá»§a git\n" +"Dùng '\\!' cho các chuá»—i văn bản có dấu chấm than." #: bundle.c:36 #, c-format msgid "'%s' does not look like a v2 bundle file" -msgstr "'%s' không giống như táºp tin v2 bundle (cụm)" +msgstr "“%s†không giống như táºp tin v2 bundle (định dạng dump cá»§a git)" #: bundle.c:63 #, c-format msgid "unrecognized header: %s%s (%d)" msgstr "phần đầu (header) không được thừa nháºn: %s%s (%d)" -#: bundle.c:89 -#: builtin/commit.c:696 +#: bundle.c:89 builtin/commit.c:674 #, c-format msgid "could not open '%s'" -msgstr "không thể mở '%s'" +msgstr "không thể mở “%sâ€" #: bundle.c:140 msgid "Repository lacks these prerequisite commits:" msgstr "Khó chứa thiếu những lần chuyển giao (commit) cần trước hết nà y:" -#: bundle.c:164 -#: sequencer.c:550 -#: sequencer.c:982 -#: builtin/log.c:289 -#: builtin/log.c:720 -#: builtin/log.c:1309 -#: builtin/log.c:1528 -#: builtin/merge.c:347 +#: bundle.c:164 sequencer.c:562 sequencer.c:994 builtin/log.c:290 +#: builtin/log.c:732 builtin/log.c:1319 builtin/log.c:1535 builtin/merge.c:347 #: builtin/shortlog.c:181 msgid "revision walk setup failed" -msgstr "Cà i đặt việc di chuyển qua các Ä‘iểm xét lại gặp lá»—i" +msgstr "cà i đặt việc di chuyển qua các Ä‘iểm xét lại gặp lá»—i" #: bundle.c:186 #, c-format @@ -82,67 +169,68 @@ msgstr[0] "Bundle chứa %d tham chiếu (refs)" msgstr[1] "Bundle chứa %d tham chiếu (refs)" #: bundle.c:192 +msgid "The bundle records a complete history." +msgstr "Lệnh bundle ghi lại toà n bá»™ lịch sá»." + +#: bundle.c:195 #, c-format msgid "The bundle requires this ref" msgid_plural "The bundle requires these %d refs" msgstr[0] "Lệnh bundle yêu cầu tham chiếu (refs) nà y" msgstr[1] "Lệnh bundle yêu cầu %d tham chiếu (refs) nà y" -#: bundle.c:290 +#: bundle.c:294 msgid "rev-list died" -msgstr "rev-list bị chết" +msgstr "rev-list đã chết" -#: bundle.c:296 -#: builtin/log.c:1205 -#: builtin/shortlog.c:284 +#: bundle.c:300 builtin/log.c:1215 builtin/shortlog.c:284 #, c-format msgid "unrecognized argument: %s" msgstr "đối số không được thừa nháºn: %s" -#: bundle.c:331 +#: bundle.c:335 #, c-format msgid "ref '%s' is excluded by the rev-list options" -msgstr "tham chiếu '%s' bị loại trừ bởi các tùy chá»n rev-list" +msgstr "th.chiếu “%s†bị loại trừ bởi các tùy chá»n rev-list" -#: bundle.c:376 +#: bundle.c:380 msgid "Refusing to create empty bundle." msgstr "Từ chối tạo má»™t bundle trống rá»—ng." -#: bundle.c:394 +#: bundle.c:398 msgid "Could not spawn pack-objects" msgstr "Không thể sản sinh pack-objects" -#: bundle.c:412 +#: bundle.c:416 msgid "pack-objects died" msgstr "pack-objects đã chết" -#: bundle.c:415 +#: bundle.c:419 #, c-format msgid "cannot create '%s'" -msgstr "không thể tạo '%s'" +msgstr "không thể tạo “%sâ€" -#: bundle.c:437 +#: bundle.c:441 msgid "index-pack died" msgstr "index-pack đã chết" -#: commit.c:48 +#: commit.c:50 #, c-format msgid "could not parse %s" msgstr "không thể phân tÃch %s" -#: commit.c:50 +#: commit.c:52 #, c-format msgid "%s %s is not a commit!" msgstr "%s %s không phải là má»™t lần commit!" -#: compat/obstack.c:406 -#: compat/obstack.c:408 +#: compat/obstack.c:406 compat/obstack.c:408 msgid "memory exhausted" -msgstr "cạn bá»™ nhá»›" +msgstr "hết bá»™ nhá»›" #: connected.c:39 msgid "Could not run 'git rev-list'" -msgstr "Không thể chạy 'git rev-list'" +msgstr "Không thể chạy “git rev-listâ€" #: connected.c:48 #, c-format @@ -214,59 +302,38 @@ msgid_plural "%s, %lu months ago" msgstr[0] "%s, %lu tháng trước" msgstr[1] "%s, %lu tháng trước" -#: date.c:154 -#: date.c:159 +#: date.c:154 date.c:159 #, c-format msgid "%lu year ago" msgid_plural "%lu years ago" msgstr[0] "%lu năm trước" msgstr[1] "%lu năm trước" -#: diff.c:105 +#: diff.c:111 +#, c-format +msgid " Failed to parse dirstat cut-off percentage '%s'\n" +msgstr " Gặp lá»—i khi phân tÃch dirstat cắt bá» phần trăm '%s'\n" + +#: diff.c:116 #, c-format -msgid " Failed to parse dirstat cut-off percentage '%.*s'\n" -msgstr " Gặp lá»—i khi phân tÃch dirstat cắt bá» phần trăm '%.*s'\n" +msgid " Unknown dirstat parameter '%s'\n" +msgstr " Không hiểu đối số dirstat '%s'\n" -#: diff.c:110 +#: diff.c:194 #, c-format -msgid " Unknown dirstat parameter '%.*s'\n" -msgstr " Không hiểu đối số dirstat '%.*s'\n" +msgid "Unknown value for 'diff.submodule' config variable: '%s'" +msgstr "Không hiểu giá trị cho biến cấu hình “diff.submoduleâ€: `%s'" -#: diff.c:210 +#: diff.c:237 #, c-format msgid "" "Found errors in 'diff.dirstat' config variable:\n" "%s" msgstr "" -"Tìm thấy các lá»—i trong biến cấu hình 'diff.dirstat':\n" +"Tìm thấy các lá»—i trong biến cấu hình “diff.dirstatâ€:\n" "%s" -#: diff.c:1400 -msgid " 0 files changed\n" -msgstr " 0 táºp tin nà o bị thay đổi\n" - -#: diff.c:1404 -#, c-format -msgid " %d file changed" -msgid_plural " %d files changed" -msgstr[0] " %d táºp tin đã bị thay đổi" -msgstr[1] " %d táºp tin đã bị thay đổi" - -#: diff.c:1421 -#, c-format -msgid ", %d insertion(+)" -msgid_plural ", %d insertions(+)" -msgstr[0] ", %d được thêm và o(+)" -msgstr[1] ", %d được thêm và o(+)" - -#: diff.c:1432 -#, c-format -msgid ", %d deletion(-)" -msgid_plural ", %d deletions(-)" -msgstr[0] ", %d bị xóa(-)" -msgstr[1] ", %d bị xóa(-)" - -#: diff.c:3478 +#: diff.c:3494 #, c-format msgid "" "Failed to parse --dirstat/-X option parameter:\n" @@ -275,6 +342,11 @@ msgstr "" "Gặp lá»—i khi phân tÃch đối số tùy chá»n --dirstat/-X:\n" "%s" +#: diff.c:3508 +#, c-format +msgid "Failed to parse --submodule option parameter: '%s'" +msgstr "Gặp lá»—i khi phân tÃch đối số tùy chá»n --submodule: `%s'" + #: gpg-interface.c:59 msgid "could not run gpg." msgstr "không thể chạy gpg." @@ -287,63 +359,63 @@ msgstr "gpg đã không đồng ý dữ liệu" msgid "gpg failed to sign the data" msgstr "gpg gặp lá»—i khi ký dữ liệu" -#: grep.c:1320 +#: grep.c:1622 #, c-format msgid "'%s': unable to read %s" -msgstr "'%s': không thể Ä‘á»c %s" +msgstr "“%sâ€: không thể Ä‘á»c %s" -#: grep.c:1337 +#: grep.c:1639 #, c-format msgid "'%s': %s" -msgstr "'%s': %s" +msgstr "“%sâ€: %s" -#: grep.c:1348 +#: grep.c:1650 #, c-format msgid "'%s': short read %s" -msgstr "'%s': Ä‘á»c ngắn %s" +msgstr "“%sâ€: Ä‘á»c ngắn %s" -#: help.c:207 +#: help.c:212 #, c-format msgid "available git commands in '%s'" -msgstr "các lệnh git sẵn sà ng để dùng trong '%s'" +msgstr "các lệnh git sẵn sà ng để dùng trong “%sâ€" -#: help.c:214 +#: help.c:219 msgid "git commands available from elsewhere on your $PATH" msgstr "các lệnh git sẵn sà ng để dùng từ má»™t nÆ¡i khác trong $PATH cá»§a bạn" -#: help.c:270 +#: help.c:275 #, c-format msgid "" "'%s' appears to be a git command, but we were not\n" "able to execute it. Maybe git-%s is broken?" msgstr "" -"'%s' trông như là má»™t lệnh git, nhưng chúng tôi không\n" +"“%s†trông như là má»™t lệnh git, nhưng chúng tôi không\n" "thể thá»±c thi nó. Có lẽ là lệnh git-%s đã bị há»ng?" -#: help.c:327 +#: help.c:332 msgid "Uh oh. Your system reports no Git commands at all." msgstr "á»i chà . Hệ thống cá»§a bạn báo rằng chẳng có lệnh Git nà o cả." -#: help.c:349 +#: help.c:354 #, c-format msgid "" "WARNING: You called a Git command named '%s', which does not exist.\n" "Continuing under the assumption that you meant '%s'" msgstr "" -"CẢNH BÃO: Bạn đã gá»i lệnh Git có tên '%s', mà nó lại không sẵn có.\n" -"Giả định rằng ý bạn là '%s'" +"CẢNH BÃO: Bạn đã gá»i lệnh Git có tên “%sâ€, mà nó lại không có sẵn.\n" +"Giả định rằng ý bạn là “%sâ€" -#: help.c:354 +#: help.c:359 #, c-format msgid "in %0.1f seconds automatically..." msgstr "trong %0.1f giây má»™t cách tá»± động..." -#: help.c:361 +#: help.c:366 #, c-format msgid "git: '%s' is not a git command. See 'git --help'." -msgstr "git: '%s' không phải là má»™t lệnh cá»§a git. Xem thêm 'git --help'." +msgstr "git: “%s†không phải là má»™t lệnh cá»§a git. Xem “git --helpâ€." -#: help.c:365 +#: help.c:370 msgid "" "\n" "Did you mean this?" @@ -357,42 +429,320 @@ msgstr[1] "" "\n" "Có phải ý bạn là má»™t trong số những cái nà y không?" -#: parse-options.c:493 +#: merge.c:56 +msgid "failed to read the cache" +msgstr "gặp lá»—i khi Ä‘á»c bá»™ nhá»› tạm" + +#: merge.c:110 builtin/checkout.c:333 builtin/checkout.c:534 +#: builtin/clone.c:586 +msgid "unable to write new index file" +msgstr "không thể ghi táºp tin lưu bảng mục lục má»›i" + +#: merge-recursive.c:190 +#, c-format +msgid "(bad commit)\n" +msgstr "(commit sai)\n" + +#: merge-recursive.c:206 +#, c-format +msgid "addinfo_cache failed for path '%s'" +msgstr "addinfo_cache gặp lá»—i đối vá»›i đưá»ng dẫn “%sâ€" + +#: merge-recursive.c:268 +msgid "error building trees" +msgstr "gặp lá»—i khi xây dá»±ng cây" + +#: merge-recursive.c:672 +#, c-format +msgid "failed to create path '%s'%s" +msgstr "gặp lá»—i khi tạo đưá»ng dẫn “%sâ€%s" + +#: merge-recursive.c:683 +#, c-format +msgid "Removing %s to make room for subdirectory\n" +msgstr "Gỡ bá» %s để tạo chá»— (room) cho thư mục con\n" + +#. something else exists +#. .. but not some other error (who really cares what?) +#: merge-recursive.c:697 merge-recursive.c:718 +msgid ": perhaps a D/F conflict?" +msgstr ": có lẽ là má»™t xung đột D/F?" + +#: merge-recursive.c:708 +#, c-format +msgid "refusing to lose untracked file at '%s'" +msgstr "từ chối đóng táºp tin không được theo vết tại “%sâ€" + +#: merge-recursive.c:748 +#, c-format +msgid "cannot read object %s '%s'" +msgstr "không thể Ä‘á»c đối tượng %s “%sâ€" + +#: merge-recursive.c:750 +#, c-format +msgid "blob expected for %s '%s'" +msgstr "đối tượng blob được mong đợi cho %s “%sâ€" + +#: merge-recursive.c:773 builtin/clone.c:302 +#, c-format +msgid "failed to open '%s'" +msgstr "gặp lá»—i khi mở “%sâ€" + +#: merge-recursive.c:781 +#, c-format +msgid "failed to symlink '%s'" +msgstr "gặp lá»—i khi tạo liên kết tượng trưng (symlink) “%sâ€" + +#: merge-recursive.c:784 +#, c-format +msgid "do not know what to do with %06o %s '%s'" +msgstr "không hiểu phải là m gì vá»›i %06o %s “%sâ€" + +#: merge-recursive.c:922 +msgid "Failed to execute internal merge" +msgstr "Gặp lá»—i khi thá»±c hiện trá»™n ná»™i bá»™" + +#: merge-recursive.c:926 +#, c-format +msgid "Unable to add %s to database" +msgstr "Không thể thêm %s và o cÆ¡ sở dữ liệu" + +#: merge-recursive.c:942 +msgid "unsupported object type in the tree" +msgstr "kiểu đối tượng không được há»— trợ trong cây (tree)" + +#: merge-recursive.c:1021 merge-recursive.c:1035 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree." +msgstr "" +"XUNG ÄỘT (%s/xóa): %s bị xóa trong %s và %s trong %s. Phiên bản %s cá»§a %s " +"còn lại trong cây (tree)." + +#: merge-recursive.c:1027 merge-recursive.c:1040 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree at %s." +msgstr "" +"XUNG ÄỘT (%s/xóa): %s bị xóa trong %s và %s trong %s. Phiên bản %s cá»§a %s " +"còn lại trong cây (tree) tại %s." + +#: merge-recursive.c:1081 +msgid "rename" +msgstr "đổi tên" + +#: merge-recursive.c:1081 +msgid "renamed" +msgstr "đã đổi tên" + +#: merge-recursive.c:1137 +#, c-format +msgid "%s is a directory in %s adding as %s instead" +msgstr "%s là má»™t thư mục trong %s thay và o đó thêm và o như là %s" + +#: merge-recursive.c:1159 +#, c-format +msgid "" +"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s" +"\"->\"%s\" in \"%s\"%s" +msgstr "" +"XUNG ÄỘT (đổi-tên/đổi-tên): Äổi tên \"%s\"->\"%s\" trong nhánh \"%s\" đổi " +"tên \"%s\"->\"%s\" trong \"%s\"%s" + +#: merge-recursive.c:1164 +msgid " (left unresolved)" +msgstr " (cần giải quyết)" + +#: merge-recursive.c:1218 +#, c-format +msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s" +msgstr "" +"XUNG ÄỘT (đổi-tên/đổi-tên): Äổi tên %s->%s trong %s. Äổi tên %s->%s trong %s" + +#: merge-recursive.c:1248 +#, c-format +msgid "Renaming %s to %s and %s to %s instead" +msgstr "Äang đổi tên %s thà nh %s thay vì %s thà nh %s" + +#: merge-recursive.c:1447 +#, c-format +msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s" +msgstr "" +"XUNG ÄỘT (đổi-tên/thêm): Äổi tên %s->%s trong %s. %s được thêm và o trong %s" + +#: merge-recursive.c:1457 +#, c-format +msgid "Adding merged %s" +msgstr "Thêm hòa trá»™n %s" + +#: merge-recursive.c:1462 merge-recursive.c:1660 +#, c-format +msgid "Adding as %s instead" +msgstr "Thay và o đó thêm và o %s" + +#: merge-recursive.c:1513 +#, c-format +msgid "cannot read object %s" +msgstr "không thể Ä‘á»c đối tượng %s" + +#: merge-recursive.c:1516 +#, c-format +msgid "object %s is not a blob" +msgstr "đối tượng %s không phải là má»™t blob" + +#: merge-recursive.c:1564 +msgid "modify" +msgstr "sá»a đổi" + +#: merge-recursive.c:1564 +msgid "modified" +msgstr "đã sá»a" + +#: merge-recursive.c:1574 +msgid "content" +msgstr "ná»™i dung" + +#: merge-recursive.c:1581 +msgid "add/add" +msgstr "thêm/thêm" + +#: merge-recursive.c:1615 +#, c-format +msgid "Skipped %s (merged same as existing)" +msgstr "Äã bá» qua %s (đã có sẵn lần hòa trá»™n nà y)" + +#: merge-recursive.c:1629 +#, c-format +msgid "Auto-merging %s" +msgstr "Tá»±-động-hòa-trá»™n %s" + +#: merge-recursive.c:1633 git-submodule.sh:893 +msgid "submodule" +msgstr "mô-Ä‘un-con" + +#: merge-recursive.c:1634 +#, c-format +msgid "CONFLICT (%s): Merge conflict in %s" +msgstr "XUNG ÄỘT (%s): Xung đột hòa trá»™n trong %s" + +#: merge-recursive.c:1724 +#, c-format +msgid "Removing %s" +msgstr "Äang xóa %s" + +#: merge-recursive.c:1749 +msgid "file/directory" +msgstr "táºp-tin/thư-mục" + +#: merge-recursive.c:1755 +msgid "directory/file" +msgstr "thư-mục/táºp tin" + +#: merge-recursive.c:1760 +#, c-format +msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s" +msgstr "" +"XUNG ÄỘT (%s): Ở đây không có thư mục nà o có tên %s trong %s. Thêm %s như là " +"%s" + +#: merge-recursive.c:1770 +#, c-format +msgid "Adding %s" +msgstr "Thêm \"%s\"" + +#: merge-recursive.c:1787 +msgid "Fatal merge failure, shouldn't happen." +msgstr "Việc hòa trá»™n há»ng nghiêm trá»ng, không nên để xảy ra." + +#: merge-recursive.c:1806 +msgid "Already up-to-date!" +msgstr "Äã cáºp nháºt rồi!" + +#: merge-recursive.c:1815 +#, c-format +msgid "merging of trees %s and %s failed" +msgstr "hòa trá»™n cây (tree) %s và %s gặp lá»—i" + +#: merge-recursive.c:1845 +#, c-format +msgid "Unprocessed path??? %s" +msgstr "ÄÆ°á»ng dẫn chưa được xá» lý??? %s" + +#: merge-recursive.c:1890 +msgid "Merging:" +msgstr "Äang trá»™n:" + +#: merge-recursive.c:1903 +#, c-format +msgid "found %u common ancestor:" +msgid_plural "found %u common ancestors:" +msgstr[0] "tìm thấy %u tổ tiên chung:" +msgstr[1] "tìm thấy %u tổ tiên chung:" + +#: merge-recursive.c:1940 +msgid "merge returned no commit" +msgstr "hòa trá»™n không trả vá» lần chuyển giao (commit) nà o" + +#: merge-recursive.c:1997 +#, c-format +msgid "Could not parse object '%s'" +msgstr "Không thể phân tÃch đối tượng “%sâ€" + +#: merge-recursive.c:2009 builtin/merge.c:643 +msgid "Unable to write index." +msgstr "Không thể ghi bảng mục lục" + +#: parse-options.c:494 msgid "..." msgstr "..." -#: parse-options.c:511 +#: parse-options.c:512 #, c-format msgid "usage: %s" -msgstr "cách sá» dụng: %s" +msgstr "cách dùng: %s" #. TRANSLATORS: the colon here should align with the #. one in "usage: %s" translation -#: parse-options.c:515 +#: parse-options.c:516 #, c-format msgid " or: %s" -msgstr " hoặc: %s" +msgstr " hoặc: %s" -#: parse-options.c:518 +#: parse-options.c:519 #, c-format msgid " %s" msgstr " %s" -#: remote.c:1629 +#: remote.c:1632 #, c-format msgid "Your branch is ahead of '%s' by %d commit.\n" msgid_plural "Your branch is ahead of '%s' by %d commits.\n" -msgstr[0] "Nhánh cá»§a bạn là đầu cá»§a '%s' bởi %d lần chuyển giao (commit).\n" -msgstr[1] "Nhánh cá»§a bạn là đầu cá»§a '%s' bởi %d lần chuyển giao (commit).\n" +msgstr[0] "Nhánh cá»§a bạn là đầu cá»§a “%s†bởi %d lần chuyển giao (commit).\n" +msgstr[1] "Nhánh cá»§a bạn là đầu cá»§a “%s†bởi %d lần chuyển giao (commit).\n" + +#: remote.c:1637 +msgid " (use \"git push\" to publish your local commits)\n" +msgstr " (dùng \"git push\" để xuất bản các lần chuyển giao ná»™i bá»™ cá»§a bạn)\n" -#: remote.c:1635 +#: remote.c:1640 #, c-format msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n" -msgid_plural "Your branch is behind '%s' by %d commits, and can be fast-forwarded.\n" -msgstr[0] "Nhánh cá»§a bạn thì ở đằng sau '%s' bởi %d lần chuyển giao (commit), và có thể được fast-forward.\n" -msgstr[1] "Nhánh cá»§a bạn thì ở đằng sau '%s' bởi %d lần chuyển giao (commit), và có thể được fast-forward.\n" +msgid_plural "" +"Your branch is behind '%s' by %d commits, and can be fast-forwarded.\n" +msgstr[0] "" +"Nhánh cá»§a bạn thì ở đằng sau “%s†bởi %d lần chuyển giao (commit), và có thể " +"được fast-forward.\n" +msgstr[1] "" +"Nhánh cá»§a bạn thì ở đằng sau “%s†bởi %d lần chuyển giao (commit), và có thể " +"được fast-forward.\n" -#: remote.c:1643 +#: remote.c:1647 +msgid " (use \"git pull\" to update your local branch)\n" +msgstr " (dùng \"git pull\" để cáºp nháºt nhánh ná»™i bá»™ cá»§a bạn)\n" + +#: remote.c:1650 #, c-format msgid "" "Your branch and '%s' have diverged,\n" @@ -401,561 +751,703 @@ msgid_plural "" "Your branch and '%s' have diverged,\n" "and have %d and %d different commits each, respectively.\n" msgstr[0] "" -"Nhánh cá»§a bạn và '%s' bị phân kỳ,\n" +"Nhánh cá»§a bạn và “%s†bị phân kỳ,\n" "và có %d và %d lần chuyển giao (commit) khác nhau cho từng cái,\n" "tương ứng vá»›i má»—i lần.\n" msgstr[1] "" -"Your branch and '%s' have diverged,\n" +"Your branch and “%s†have diverged,\n" "and have %d and %d different commit each, respectively.\n" -#: sequencer.c:121 -#: builtin/merge.c:865 -#: builtin/merge.c:978 -#: builtin/merge.c:1088 -#: builtin/merge.c:1098 +#: remote.c:1659 +msgid " (use \"git pull\" to merge the remote branch into yours)\n" +msgstr "" +" (dùng \"git pull\" để hòa trá»™n nhánh trên máy chá»§ và o trong nhánh cá»§a " +"bạn)\n" + +#: sequencer.c:123 builtin/merge.c:761 builtin/merge.c:874 builtin/merge.c:984 +#: builtin/merge.c:994 #, c-format msgid "Could not open '%s' for writing" -msgstr "Không thể mở %s' để ghi" +msgstr "Không thể mở “%s†để ghi" -#: sequencer.c:123 -#: builtin/merge.c:333 -#: builtin/merge.c:868 -#: builtin/merge.c:1090 -#: builtin/merge.c:1103 +#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:764 builtin/merge.c:986 +#: builtin/merge.c:999 #, c-format msgid "Could not write to '%s'" -msgstr "Không thể ghi và o '%s'" +msgstr "Không thể ghi và o “%sâ€" -#: sequencer.c:144 +#: sequencer.c:146 msgid "" "after resolving the conflicts, mark the corrected paths\n" "with 'git add <paths>' or 'git rm <paths>'" msgstr "" "sau khi giải quyết các xung đột, đánh dấu đưá»ng dẫn đã sá»a\n" -"vá»›i lệnh 'git add <đưá»ng_dẫn>' hoặc 'git rm <đưá»ng_dẫn>'" +"vá»›i lệnh “git add <đưá»ng_dẫn>†hoặc “git rm <đưá»ng_dẫn>â€" -#: sequencer.c:147 +#: sequencer.c:149 msgid "" "after resolving the conflicts, mark the corrected paths\n" "with 'git add <paths>' or 'git rm <paths>'\n" "and commit the result with 'git commit'" msgstr "" "sau khi giải quyết các xung đột, đánh dấu đưá»ng dẫn đã sá»a\n" -"vá»›i lệnh 'git add <đưá»ng_dẫn>' hoặc 'git rm <đưá»ng_dẫn>'\n" -"và chuyển giao (commit) kết quả bằng lệnh 'git commit'" +"vá»›i lệnh “git add <đưá»ng_dẫn>†hoặc “git rm <đưá»ng_dẫn>â€\n" +"và chuyển giao (commit) kết quả bằng lệnh “git commitâ€" -#: sequencer.c:160 -#: sequencer.c:758 -#: sequencer.c:841 +#: sequencer.c:162 sequencer.c:770 sequencer.c:853 #, c-format msgid "Could not write to %s" msgstr "Không thể ghi và o %s" -#: sequencer.c:163 +#: sequencer.c:165 #, c-format msgid "Error wrapping up %s" msgstr "Lá»—i bao bá»c %s" -#: sequencer.c:178 +#: sequencer.c:180 msgid "Your local changes would be overwritten by cherry-pick." msgstr "Các thay đổi ná»™i bá»™ cá»§a bạn có thể bị ghi đè bởi lệnh cherry-pick." -#: sequencer.c:180 +#: sequencer.c:182 msgid "Your local changes would be overwritten by revert." msgstr "Các thay đổi ná»™i bá»™ cá»§a bạn có thể bị ghi đè bởi lệnh revert." -#: sequencer.c:183 +#: sequencer.c:185 msgid "Commit your changes or stash them to proceed." -msgstr "Chuyển giao (commit) các thay đổi hay stash chúng để tiến hà nh." +msgstr "Chuyển giao (commit) các thay đổi cá»§a bạn hay stash chúng để xá» lý." #. TRANSLATORS: %s will be "revert" or "cherry-pick" -#: sequencer.c:233 +#: sequencer.c:235 #, c-format msgid "%s: Unable to write new index file" msgstr "%s: Không thể ghi táºp tin lưu bảng mục lục má»›i" -#: sequencer.c:261 +#: sequencer.c:266 msgid "Could not resolve HEAD commit\n" msgstr "Không thể phân giải commit (lần chuyển giao) HEAD\n" -#: sequencer.c:282 +#: sequencer.c:287 msgid "Unable to update cache tree\n" msgstr "Không thể cáºp nháºt cây bá»™ nhá»› đệm\n" -#: sequencer.c:324 +#: sequencer.c:332 #, c-format msgid "Could not parse commit %s\n" msgstr "Không thể phân tÃch commit (lần chuyển giao) %s\n" -#: sequencer.c:329 +#: sequencer.c:337 #, c-format msgid "Could not parse parent commit %s\n" msgstr "Không thể phân tÃch commit (lần chuyển giao) cha mẹ %s\n" -#: sequencer.c:395 +#: sequencer.c:403 msgid "Your index file is unmerged." msgstr "Táºp tin lưu mục lục cá»§a bạn không được hòa trá»™n." -#: sequencer.c:398 +#: sequencer.c:406 msgid "You do not have a valid HEAD" msgstr "Bạn không có HEAD nà o hợp lệ" -#: sequencer.c:413 +#: sequencer.c:421 #, c-format msgid "Commit %s is a merge but no -m option was given." -msgstr "Lần chuyển giao (commit) %s là má»™t lần hòa trá»™n nhưng không đưa ra tùy chá»n -m." +msgstr "" +"Lần chuyển giao (commit) %s là má»™t lần hòa trá»™n nhưng không đưa ra tùy chá»n -" +"m." -#: sequencer.c:421 +#: sequencer.c:429 #, c-format msgid "Commit %s does not have parent %d" msgstr "Lần chuyển giao (commit) %s không có cha mẹ %d" -#: sequencer.c:425 +#: sequencer.c:433 #, c-format msgid "Mainline was specified but commit %s is not a merge." -msgstr "Luồng chÃnh được chỉ định nhưng lần chuyển giao (commit) %s không phải là má»™t lần hòa trá»™n." +msgstr "" +"Luồng chÃnh được chỉ ra nhưng lần chuyển giao (commit) %s không phải là má»™t " +"lần hòa trá»™n." #. TRANSLATORS: The first %s will be "revert" or #. "cherry-pick", the second %s a SHA1 -#: sequencer.c:436 +#: sequencer.c:444 #, c-format msgid "%s: cannot parse parent commit %s" msgstr "%s: không thể phân tÃch lần chuyển giao mẹ cá»§a %s" -#: sequencer.c:440 +#: sequencer.c:448 #, c-format msgid "Cannot get commit message for %s" msgstr "Không thể lấy thông Ä‘iệp lần chuyển giao (commit) cho %s" -#: sequencer.c:524 +#: sequencer.c:532 #, c-format msgid "could not revert %s... %s" msgstr "không thể revert %s... %s" -#: sequencer.c:525 +#: sequencer.c:533 #, c-format msgid "could not apply %s... %s" msgstr "không thể apply (áp dụng miếng vá) %s... %s" -#: sequencer.c:553 +#: sequencer.c:565 msgid "empty commit set passed" msgstr "lần chuyển giao (commit) trống rá»—ng đặt là hợp quy cách" -#: sequencer.c:561 +#: sequencer.c:573 #, c-format msgid "git %s: failed to read the index" msgstr "git %s: gặp lá»—i Ä‘á»c bảng mục lục" -#: sequencer.c:566 +#: sequencer.c:578 #, c-format msgid "git %s: failed to refresh the index" msgstr "git %s: gặp lá»—i khi là m tươi má»›i bảng mục lục" -#: sequencer.c:624 +#: sequencer.c:636 #, c-format msgid "Cannot %s during a %s" msgstr "Không thể %s trong khi %s" -#: sequencer.c:646 +#: sequencer.c:658 #, c-format msgid "Could not parse line %d." msgstr "Không phân tÃch được dòng %d." -#: sequencer.c:651 +#: sequencer.c:663 msgid "No commits parsed." msgstr "Không có lần chuyển giao (commit) nà o được phân tÃch." -#: sequencer.c:664 +#: sequencer.c:676 #, c-format msgid "Could not open %s" msgstr "Không thể mở %s" -#: sequencer.c:668 +#: sequencer.c:680 #, c-format msgid "Could not read %s." msgstr "Không thể Ä‘á»c %s." -#: sequencer.c:675 +#: sequencer.c:687 #, c-format msgid "Unusable instruction sheet: %s" msgstr "Bảng chỉ thị không thể dùng được: %s" -#: sequencer.c:703 +#: sequencer.c:715 #, c-format msgid "Invalid key: %s" msgstr "Khóa không đúng: %s" -#: sequencer.c:706 +#: sequencer.c:718 #, c-format msgid "Invalid value for %s: %s" msgstr "Giá trị không hợp lệ %s: %s" -#: sequencer.c:718 +#: sequencer.c:730 #, c-format msgid "Malformed options sheet: %s" msgstr "Bảng tùy chá»n dị hình: %s" -#: sequencer.c:739 +#: sequencer.c:751 msgid "a cherry-pick or revert is already in progress" msgstr "má»™t thao tác cherry-pick hoặc revert Ä‘ang được thá»±c hiện" -#: sequencer.c:740 +#: sequencer.c:752 msgid "try \"git cherry-pick (--continue | --quit | --abort)\"" msgstr "hãy thá» \"git cherry-pick (--continue | --quit | --abort)\"" -#: sequencer.c:744 +#: sequencer.c:756 #, c-format msgid "Could not create sequencer directory %s" msgstr "Không thể tạo thư mục xếp dãy %s" -#: sequencer.c:760 -#: sequencer.c:845 +#: sequencer.c:772 sequencer.c:857 #, c-format msgid "Error wrapping up %s." msgstr "Lá»—i bao bá»c %s." -#: sequencer.c:779 -#: sequencer.c:913 +#: sequencer.c:791 sequencer.c:925 msgid "no cherry-pick or revert in progress" msgstr "không cherry-pick hay revert trong tiến trình" -#: sequencer.c:781 +#: sequencer.c:793 msgid "cannot resolve HEAD" msgstr "không thể phân giải HEAD" -#: sequencer.c:783 +#: sequencer.c:795 msgid "cannot abort from a branch yet to be born" msgstr "không thể há»§y bá» từ má»™t nhánh mà nó còn chưa được tạo ra" -#: sequencer.c:805 -#: builtin/apply.c:3697 +#: sequencer.c:817 builtin/apply.c:4005 #, c-format msgid "cannot open %s: %s" msgstr "không thể mở %s: %s" -#: sequencer.c:808 +#: sequencer.c:820 #, c-format msgid "cannot read %s: %s" msgstr "không thể Ä‘á»c %s: %s" -#: sequencer.c:809 +#: sequencer.c:821 msgid "unexpected end of file" msgstr "kết thúc táºp tin đột xuất" -#: sequencer.c:815 +#: sequencer.c:827 #, c-format msgid "stored pre-cherry-pick HEAD file '%s' is corrupt" -msgstr "táºp tin HEAD 'pre-cherry-pick' đã lưu '%s' bị há»ng" +msgstr "táºp tin HEAD “pre-cherry-pick†đã lưu “%s†bị há»ng" -#: sequencer.c:838 +#: sequencer.c:850 #, c-format msgid "Could not format %s." msgstr "Không thể định dạng %s." -#: sequencer.c:1000 +#: sequencer.c:1012 msgid "Can't revert as initial commit" msgstr "Không thể revert má»™t lần chuyển giao (commit) khởi tạo" -#: sequencer.c:1001 +#: sequencer.c:1013 msgid "Can't cherry-pick into empty head" msgstr "Không thể cherry-pick và o má»™t đầu (head) trống rá»—ng" -#: sha1_name.c:864 +#: sha1_name.c:1044 msgid "HEAD does not point to a branch" msgstr "HEAD không chỉ đến má»™t nhánh nà o cả" -#: sha1_name.c:867 +#: sha1_name.c:1047 #, c-format msgid "No such branch: '%s'" -msgstr "Không có nhánh nà o như thế: '%s'" +msgstr "Không có nhánh nà o như thế: “%sâ€" -#: sha1_name.c:869 +#: sha1_name.c:1049 #, c-format msgid "No upstream configured for branch '%s'" -msgstr "Không có dòng ngược (upstream) được cấu hình cho nhánh '%s'" +msgstr "Không có thượng nguồn (upstream) được cấu hình cho nhánh “%sâ€" -#: sha1_name.c:872 +#: sha1_name.c:1052 #, c-format msgid "Upstream branch '%s' not stored as a remote-tracking branch" -msgstr "Nhánh dòng ngược (upstream) '%s' không được lưu lại như là má»™t nhánh 'remote-tracking'" +msgstr "" +"Nhánh thượng nguồn (upstream) “%s†không được lưu lại như là má»™t nhánh " +"“remote-trackingâ€" + +#: wrapper.c:408 +#, c-format +msgid "unable to access '%s': %s" +msgstr "không thể truy cáºp “%sâ€: %s" -#: wrapper.c:413 +#: wrapper.c:426 #, c-format msgid "unable to look up current user in the passwd file: %s" msgstr "không tìm thấy ngưá»i dùng hiện tại trong táºp tin passwd: %s" -#: wrapper.c:414 +#: wrapper.c:427 msgid "no such user" msgstr "không có ngưá»i dùng như váºy" -#: wt-status.c:135 +#: wt-status.c:140 msgid "Unmerged paths:" msgstr "Những đưá»ng dẫn chưa được hòa trá»™n:" -#: wt-status.c:141 -#: wt-status.c:158 +#: wt-status.c:167 wt-status.c:194 #, c-format msgid " (use \"git reset %s <file>...\" to unstage)" -msgstr " (sá» dụng \"git reset %s <táºp-tin>...\" để bá» má»™t stage (trạng thái))" +msgstr " (dùng \"git reset %s <táºp-tin>...\" để bá» má»™t stage (trạng thái))" -#: wt-status.c:143 -#: wt-status.c:160 +#: wt-status.c:169 wt-status.c:196 msgid " (use \"git rm --cached <file>...\" to unstage)" -msgstr " (sá» dụng \"git rm --cached <táºp-tin>...\" để bá» trạng thái (stage))" +msgstr " (dùng \"git rm --cached <táºp-tin>...\" để bá» trạng thái (stage))" -#: wt-status.c:144 +#: wt-status.c:173 +msgid " (use \"git add <file>...\" to mark resolution)" +msgstr " (dùng \"git add <táºp-tin>...\" để đánh dấu là cần giải quyết)" + +#: wt-status.c:175 wt-status.c:179 msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" -msgstr " (sá» dụng \"git add/rm <táºp-tin>...\" như là má»™t cách thÃch hợp để đánh dấu là cần được giải quyết)" +msgstr "" +" (dùng \"git add/rm <táºp-tin>...\" như là má»™t cách thÃch hợp để đánh dấu " +"là cần được giải quyết)" -#: wt-status.c:152 +#: wt-status.c:177 +msgid " (use \"git rm <file>...\" to mark resolution)" +msgstr " (dùng \"git rm <táºp-tin>...\" để đánh dấu là cần giải quyết)" + +#: wt-status.c:188 msgid "Changes to be committed:" msgstr "Những thay đổi sẽ được chuyển giao:" -#: wt-status.c:170 +#: wt-status.c:206 msgid "Changes not staged for commit:" -msgstr "Các thay đổi không được đặt trạng thái (stage) cho lần chuyển giao (commit):" +msgstr "" +"Các thay đổi không được đặt trạng thái (stage) cho lần chuyển giao (commit):" -#: wt-status.c:174 +#: wt-status.c:210 msgid " (use \"git add <file>...\" to update what will be committed)" -msgstr " (sá» dụng \"git add <táºp-tin>...\" để cáºp nháºt những gì cần chuyển giao (commit))" +msgstr "" +" (dùng \"git add <táºp-tin>...\" để cáºp nháºt những gì cần chuyển giao " +"(commit))" -#: wt-status.c:176 +#: wt-status.c:212 msgid " (use \"git add/rm <file>...\" to update what will be committed)" -msgstr " (sá» dụng \"git add/rm <táºp_tin>...\" để cáºp nháºt những gì sẽ được chuyển giao)" +msgstr "" +" (dùng \"git add/rm <táºp-tin>...\" để cáºp nháºt những gì sẽ được chuyển giao)" -#: wt-status.c:177 -msgid " (use \"git checkout -- <file>...\" to discard changes in working directory)" -msgstr " (sá» dụng \"git checkout -- <táºp_tin>...\" để loại bá» những thay đổi trong thư mục là m việc)" +#: wt-status.c:213 +msgid "" +" (use \"git checkout -- <file>...\" to discard changes in working directory)" +msgstr "" +" (dùng \"git checkout -- <táºp-tin>...\" để bá» thay đổi trong thư mục là m " +"việc)" -#: wt-status.c:179 +#: wt-status.c:215 msgid " (commit or discard the untracked or modified content in submodules)" -msgstr " (chuyển giao (commit) hoặc là loại bá» các ná»™i dung không-bị-theo-vết hay đã bị chỉnh sá»a trong mô-Ä‘un-con)" - -#: wt-status.c:188 -#, c-format -msgid "%s files:" -msgstr "%s tệp tin:" +msgstr "" +" (chuyển giao (commit) hoặc là loại bá» các ná»™i dung không-bị-theo-vết hay " +"đã bị chỉnh sá»a trong mô-Ä‘un-con)" -#: wt-status.c:191 +#: wt-status.c:227 #, c-format msgid " (use \"git %s <file>...\" to include in what will be committed)" -msgstr " (sá» dụng \"git %s <táºp-tin>...\" để bao gồm thêm và o những gì cần chuyển giao (commit))" +msgstr "" +" (dùng \"git %s <táºp-tin>...\" để thêm và o những gì cần chuyển giao " +"(commit))" -#: wt-status.c:208 +#: wt-status.c:244 msgid "bug" msgstr "lá»—i" -#: wt-status.c:213 +#: wt-status.c:249 msgid "both deleted:" msgstr "bị xóa bởi cả hai:" -#: wt-status.c:214 +#: wt-status.c:250 msgid "added by us:" msgstr "được thêm và o bởi chúng tôi:" -#: wt-status.c:215 +#: wt-status.c:251 msgid "deleted by them:" msgstr "bị xóa Ä‘i bởi há»:" -#: wt-status.c:216 +#: wt-status.c:252 msgid "added by them:" msgstr "được thêm và o bởi há»:" -#: wt-status.c:217 +#: wt-status.c:253 msgid "deleted by us:" msgstr "bị xóa bởi chúng tôi:" -#: wt-status.c:218 +#: wt-status.c:254 msgid "both added:" msgstr "được thêm và o bởi cả hai:" -#: wt-status.c:219 +#: wt-status.c:255 msgid "both modified:" msgstr "bị sá»a bởi cả hai:" -#: wt-status.c:249 +#: wt-status.c:285 msgid "new commits, " -msgstr " lần chuyển giao (commit) má»›i, " +msgstr "lần chuyển giao (commit) má»›i, " -#: wt-status.c:251 +#: wt-status.c:287 msgid "modified content, " -msgstr "ná»™i dung được sá»a đổi," +msgstr "ná»™i dung được sá»a đổi, " -#: wt-status.c:253 +#: wt-status.c:289 msgid "untracked content, " -msgstr "ná»™i dung chưa được theo dõi" +msgstr "ná»™i dung chưa được theo dõi, " -#: wt-status.c:267 +#: wt-status.c:303 #, c-format msgid "new file: %s" msgstr "táºp tin má»›i: %s" -#: wt-status.c:270 +#: wt-status.c:306 #, c-format msgid "copied: %s -> %s" msgstr "đã sao chép: %s -> %s" -#: wt-status.c:273 +#: wt-status.c:309 #, c-format msgid "deleted: %s" -msgstr "bị xóa: %s" +msgstr "đã xóa: %s" -#: wt-status.c:276 +#: wt-status.c:312 #, c-format msgid "modified: %s" -msgstr "bị sá»a đổi: %s" +msgstr "đã sá»a đổi: %s" -#: wt-status.c:279 +#: wt-status.c:315 #, c-format msgid "renamed: %s -> %s" msgstr "đã đổi tên: %s -> %s" -#: wt-status.c:282 +#: wt-status.c:318 #, c-format msgid "typechange: %s" msgstr "đổi-kiểu: %s" -#: wt-status.c:285 +#: wt-status.c:321 #, c-format msgid "unknown: %s" -msgstr "không rõ: %s" +msgstr "không hiểu: %s" -#: wt-status.c:288 +#: wt-status.c:324 #, c-format msgid "unmerged: %s" msgstr "chưa hòa trá»™n: %s" -#: wt-status.c:291 +#: wt-status.c:327 #, c-format msgid "bug: unhandled diff status %c" msgstr "lá»—i: không lấy được trạng thái lệnh diff %c" -#: wt-status.c:737 +#: wt-status.c:785 +msgid "You have unmerged paths." +msgstr "Bạn có những đưá»ng dẫn chưa được hòa trá»™n." + +#: wt-status.c:788 wt-status.c:912 +msgid " (fix conflicts and run \"git commit\")" +msgstr " (sá»a các xung đột sau đó chạy \"git commit\")" + +#: wt-status.c:791 +msgid "All conflicts fixed but you are still merging." +msgstr "Tất cả các xung đột đã được giải quyết nhưng bạn vẫn Ä‘ang hòa trá»™n." + +#: wt-status.c:794 +msgid " (use \"git commit\" to conclude merge)" +msgstr " (dùng \"git commit\" để hoà n tất việc hòa trá»™n)" + +#: wt-status.c:804 +msgid "You are in the middle of an am session." +msgstr "Bạn Ä‘ang ở giữa cá»§a má»™t phiên “amâ€." + +#: wt-status.c:807 +msgid "The current patch is empty." +msgstr "Miếng vá hiện tại bị trống rá»—ng." + +#: wt-status.c:811 +msgid " (fix conflicts and then run \"git am --resolved\")" +msgstr " (sá»a các xung đột và sau đó chạy lệnh \"git am --resolved\")" + +#: wt-status.c:813 +msgid " (use \"git am --skip\" to skip this patch)" +msgstr " (dùng \"git am --skip\" để bá» qua lần vá nà y)" + +#: wt-status.c:815 +msgid " (use \"git am --abort\" to restore the original branch)" +msgstr " (dùng \"git am --abort\" để phục hồi lại nhánh nguyên thá»§y)" + +#: wt-status.c:873 wt-status.c:883 +msgid "You are currently rebasing." +msgstr "Bạn hiện nay Ä‘ang thá»±c hiện việc rebase (tái cấu trúc)." + +#: wt-status.c:876 +msgid " (fix conflicts and then run \"git rebase --continue\")" +msgstr " (sá»a các xung đột và sau đó chạy lệnh \"git rebase --continue\")" + +#: wt-status.c:878 +msgid " (use \"git rebase --skip\" to skip this patch)" +msgstr " (dùng \"git rebase --skip\" để bá» qua lần vá nà y)" + +#: wt-status.c:880 +msgid " (use \"git rebase --abort\" to check out the original branch)" +msgstr " (dùng \"git rebase --abort\" để check-out nhánh nguyên thá»§y)" + +#: wt-status.c:886 +msgid " (all conflicts fixed: run \"git rebase --continue\")" +msgstr "" +" (khi tất cả các xung đột đã sá»a xong: chạy lệnh \"git rebase --continue\")" + +#: wt-status.c:888 +msgid "You are currently splitting a commit during a rebase." +msgstr "" +"Bạn hiện tại Ä‘ang cắt đôi má»™t lần chuyển giao trong khi Ä‘ang thá»±c hiện việc " +"rebase." + +#: wt-status.c:891 +msgid " (Once your working directory is clean, run \"git rebase --continue\")" +msgstr "" +" (Má»™t khi thư mục là m việc cá»§a bạn đã gá»n gà ng, chạy \"git rebase --continue" +"\")" + +#: wt-status.c:893 +msgid "You are currently editing a commit during a rebase." +msgstr "Bạn hiện Ä‘ang sá»a má»™t lần chuyển giao trong khi bạn thá»±c hiện rebase." + +#: wt-status.c:896 +msgid " (use \"git commit --amend\" to amend the current commit)" +msgstr "" +" (dùng \"git commit --amend\" để tu bổ lần chuyển giao (commit) hiện tại)" + +#: wt-status.c:898 +msgid "" +" (use \"git rebase --continue\" once you are satisfied with your changes)" +msgstr "" +" (dùng \"git rebase --continue\" má»™t khi bạn cảm thấy hà i lòng vá» những " +"thay đổi cá»§a mình)" + +#: wt-status.c:908 +msgid "You are currently cherry-picking." +msgstr "Bạn hiện nay Ä‘ang thá»±c hiện việc cherry-pick." + +#: wt-status.c:915 +msgid " (all conflicts fixed: run \"git commit\")" +msgstr " (khi tất cả các xung đột đã sá»a xong: chạy lệnh \"git commit\")" + +#: wt-status.c:924 +msgid "You are currently bisecting." +msgstr "Bạn hiện tại Ä‘ang thá»±c hiện việc bisect (chia đôi)." + +#: wt-status.c:927 +msgid " (use \"git bisect reset\" to get back to the original branch)" +msgstr " (dùng \"git bisect reset\" để quay trở lại nhánh nguyên thá»§y)" + +#: wt-status.c:978 msgid "On branch " -msgstr "Trên nhánh" +msgstr "Trên nhánh " -#: wt-status.c:744 +#: wt-status.c:985 msgid "Not currently on any branch." msgstr "Hiện tại chẳng ở nhánh nà o cả." -#: wt-status.c:755 +#: wt-status.c:997 msgid "Initial commit" msgstr "Lần chuyển giao (commit) khởi đầu" -#: wt-status.c:769 -msgid "Untracked" -msgstr "Không được theo vết" +#: wt-status.c:1011 +msgid "Untracked files" +msgstr "Những táºp tin chưa được theo dõi" -#: wt-status.c:771 -msgid "Ignored" -msgstr "Bị bá» qua" +#: wt-status.c:1013 +msgid "Ignored files" +msgstr "Những táºp tin bị lá» Ä‘i" -#: wt-status.c:773 +#: wt-status.c:1015 #, c-format msgid "Untracked files not listed%s" msgstr "Những táºp tin không bị theo vết không được liệt kê ra %s" -#: wt-status.c:775 +#: wt-status.c:1017 msgid " (use -u option to show untracked files)" -msgstr " (sá» dụng tùy chá»n -u để hiển thị các táºp tin chưa được theo dõi)" +msgstr " (dùng tùy chá»n -u để hiển thị các táºp tin chưa được theo dõi)" -#: wt-status.c:781 +#: wt-status.c:1023 msgid "No changes" msgstr "Không có thay đổi nà o" -#: wt-status.c:785 +#: wt-status.c:1028 #, c-format -msgid "no changes added to commit%s\n" -msgstr "không có thay đổi nà o được thêm và o lần chuyển giao (commit)%s\n" +msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n" +msgstr "" +"không có thay đổi nà o được thêm và o commit (dùng \"git add\" và /hoặc \"git " +"commit -a\")\n" -#: wt-status.c:787 -msgid " (use \"git add\" and/or \"git commit -a\")" -msgstr " (sá» dụng \"git add\" và /hoặc \"git commit -a\")" +#: wt-status.c:1031 +#, c-format +msgid "no changes added to commit\n" +msgstr "không có thay đổi nà o được thêm và o lần chuyển giao (commit)\n" -#: wt-status.c:789 +#: wt-status.c:1034 #, c-format -msgid "nothing added to commit but untracked files present%s\n" -msgstr "không có gì được thêm và o lần chuyển giao (commit) nhưng có những táºp tin không được theo dấu vết hiện diện%s\n" +msgid "" +"nothing added to commit but untracked files present (use \"git add\" to " +"track)\n" +msgstr "" +"không có gì được thêm và o lần chuyển giao (commit) nhưng có những táºp tin " +"không được theo dấu vết hiện diện (dùng \"git add\" để đưa và o theo dõi)\n" -#: wt-status.c:791 -msgid " (use \"git add\" to track)" -msgstr " (sá» dụng \"git add\" để theo dõi dấu vết)" +#: wt-status.c:1037 +#, c-format +msgid "nothing added to commit but untracked files present\n" +msgstr "" +"không có gì được thêm và o lần chuyển giao (commit) nhưng có những táºp tin " +"không được theo dấu vết hiện diện\n" -#: wt-status.c:793 -#: wt-status.c:796 -#: wt-status.c:799 +#: wt-status.c:1040 #, c-format -msgid "nothing to commit%s\n" -msgstr "không có gì để chuyển giao (commit) %s\n" +msgid "nothing to commit (create/copy files and use \"git add\" to track)\n" +msgstr "" +" không có gì để commit (tạo/sao-chép các táºp tin và dùng \"git add\" để theo " +"dõi dấu vết)\n" -#: wt-status.c:794 -msgid " (create/copy files and use \"git add\" to track)" -msgstr " (tạo/sao-chép các táºp tin và sá» dụng \"git add\" để theo dõi dấu vết)" +#: wt-status.c:1043 wt-status.c:1048 +#, c-format +msgid "nothing to commit\n" +msgstr "không có gì để chuyển giao (commit)\n" -#: wt-status.c:797 -msgid " (use -u to show untracked files)" -msgstr " (sá» dụng tùy chá»n -u để hiển thị các táºp tin chưa được theo dõi)" +#: wt-status.c:1046 +#, c-format +msgid "nothing to commit (use -u to show untracked files)\n" +msgstr "" +"không có gì để chuyển giao (commit) (dùng -u để bá» các táºp tin cần theo dấu " +"vết)\n" -#: wt-status.c:800 -msgid " (working directory clean)" -msgstr " (thư mục là m việc sạch sẽ)" +#: wt-status.c:1050 +#, c-format +msgid "nothing to commit, working directory clean\n" +msgstr "không có gì để chuyển giao (commit), thư mục là m việc sạch sẽ\n" -#: wt-status.c:908 +#: wt-status.c:1158 msgid "HEAD (no branch)" -msgstr "HEAD (chưa có nhánh nà o)" +msgstr "HEAD (không nhánh)" -#: wt-status.c:914 +#: wt-status.c:1164 msgid "Initial commit on " -msgstr "Lần chuyển giao (commit) khởi tạo trên" +msgstr "Lần chuyển giao (commit) khởi tạo trên " -#: wt-status.c:929 +#: wt-status.c:1179 msgid "behind " -msgstr "đằng sau" +msgstr "đằng sau " -#: wt-status.c:932 -#: wt-status.c:935 +#: wt-status.c:1182 wt-status.c:1185 msgid "ahead " -msgstr "phÃa trước" +msgstr "phÃa trước " -#: wt-status.c:937 +#: wt-status.c:1187 msgid ", behind " -msgstr ", đằng sau" +msgstr ", đằng sau " + +#: compat/precompose_utf8.c:58 builtin/clone.c:341 +#, c-format +msgid "failed to unlink '%s'" +msgstr "bá» liên kết (unlink) %s không thà nh công" + +#: builtin/add.c:19 +msgid "git add [options] [--] <filepattern>..." +msgstr "git add [các-tùy-chá»n] [--] <mẫu-táºp-tin>..." #: builtin/add.c:62 #, c-format msgid "unexpected diff status %c" msgstr "trạng thái lệnh diff không như mong đợi %c" -#: builtin/add.c:67 -#: builtin/commit.c:226 +#: builtin/add.c:67 builtin/commit.c:231 msgid "updating files failed" msgstr "Cáºp nháºt táºp tin gặp lá»—i" #: builtin/add.c:77 #, c-format msgid "remove '%s'\n" -msgstr "gỡ bá» '%s'\n" +msgstr "gỡ bỠ“%sâ€\n" #: builtin/add.c:176 #, c-format msgid "Path '%s' is in submodule '%.*s'" -msgstr "ÄÆ°á»ng dẫn '%s' thì ở trong mô-Ä‘un-con '%.*s'" +msgstr "ÄÆ°á»ng dẫn “%s†thì ở trong mô-Ä‘un-con “%.*sâ€" #: builtin/add.c:192 msgid "Unstaged changes after refreshing the index:" -msgstr "Các thay đổi không được lưu trạng thái sau khi là m tươi má»›i lại bảng mục lục:" +msgstr "" +"Các thay đổi không được lưu trạng thái sau khi là m tươi má»›i lại bảng mục lục:" -#: builtin/add.c:195 -#: builtin/add.c:456 -#: builtin/rm.c:186 +#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:275 #, c-format msgid "pathspec '%s' did not match any files" -msgstr "pathspec '%s' không khá»›p vá»›i bất kỳ táºp tin nà o" +msgstr "pathspec “%s†không khá»›p vá»›i bất kỳ táºp tin nà o" #: builtin/add.c:209 #, c-format msgid "'%s' is beyond a symbolic link" -msgstr "'%s' nằm ngoà i má»™t liên kết tượng trưng" +msgstr "“%s†nằm ngoà i má»™t liên kết tượng trưng" #: builtin/add.c:276 msgid "Could not read the index" @@ -964,7 +1456,7 @@ msgstr "Không thể Ä‘á»c bảng mục lục" #: builtin/add.c:286 #, c-format msgid "Could not open '%s' for writing." -msgstr "Không thể mở '%s' để ghi" +msgstr "Không thể mở “%s†để ghi" #: builtin/add.c:290 msgid "Could not write patch" @@ -973,7 +1465,7 @@ msgstr "Không thể ghi ra miếng vá" #: builtin/add.c:295 #, c-format msgid "Could not stat '%s'" -msgstr "không thể lấy trạng thái vá» '%s'" +msgstr "không thể lấy trạng thái vỠ“%sâ€" #: builtin/add.c:297 msgid "Empty patch. Aborted." @@ -982,200 +1474,261 @@ msgstr "Miếng vá trống rá»—ng. Äã bá» qua." #: builtin/add.c:303 #, c-format msgid "Could not apply '%s'" -msgstr "Không thể apply (áp dụng miếng vá) '%s'" +msgstr "Không thể apply (áp dụng miếng vá) “%sâ€" -#: builtin/add.c:312 +#: builtin/add.c:313 msgid "The following paths are ignored by one of your .gitignore files:\n" -msgstr "Các đưá»ng dẫn theo sau đây sẽ bị lá» Ä‘i bởi má»™t trong các táºp tin .gitignore cá»§a bạn:\n" +msgstr "" +"Các đưá»ng dẫn theo sau đây sẽ bị lá» Ä‘i bởi má»™t trong các táºp tin .gitignore " +"cá»§a bạn:\n" + +#: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63 +#: builtin/prune-packed.c:76 builtin/push.c:388 builtin/remote.c:1253 +#: builtin/rm.c:206 +msgid "dry run" +msgstr "chạy thá»" + +#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1160 +#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1483 +#: builtin/mv.c:62 builtin/read-tree.c:112 +msgid "be verbose" +msgstr "chi tiết" + +#: builtin/add.c:322 +msgid "interactive picking" +msgstr "sá»a bằng cách tương tác" + +#: builtin/add.c:323 builtin/checkout.c:1031 builtin/reset.c:248 +msgid "select hunks interactively" +msgstr "chá»n “hunks†má»™t cách tương tác" + +#: builtin/add.c:324 +msgid "edit current diff and apply" +msgstr "sá»a diff hiện nay và áp dụng nó" + +#: builtin/add.c:325 +msgid "allow adding otherwise ignored files" +msgstr "cho phép thêm các táºp tin bị bá» qua khác" + +#: builtin/add.c:326 +msgid "update tracked files" +msgstr "cáºp nháºt các táºp tin được theo vết" + +#: builtin/add.c:327 +msgid "record only the fact that the path will be added later" +msgstr "chỉ ghi lại sá»± việc mà đưá»ng dẫn sẽ được thêm và o sau" + +#: builtin/add.c:328 +msgid "add changes from all tracked and untracked files" +msgstr "" +"thêm các thay đổi từ tất cả các táºp tin có cÅ©ng như không được theo dõi dấu " +"vết" + +#: builtin/add.c:329 +msgid "don't add, only refresh the index" +msgstr "không thêm, chỉ là m tươi má»›i bảng mục lục" -#: builtin/add.c:352 +#: builtin/add.c:330 +msgid "just skip files which cannot be added because of errors" +msgstr "chie bá» qua những táºp tin mà nó không thể được thêm và o bởi vì gặp lá»—i" + +#: builtin/add.c:331 +msgid "check if - even missing - files are ignored in dry run" +msgstr "" +"kiểm tra xem - tháºm chà thiếu - táºp tin bị bá» qua trong quá trình chạy thá»" + +#: builtin/add.c:353 #, c-format msgid "Use -f if you really want to add them.\n" msgstr "Sá» dụng tùy chá»n -f nếu bạn thá»±c sá»± muốn thêm chúng và o.\n" -#: builtin/add.c:353 +#: builtin/add.c:354 msgid "no files added" msgstr "chưa có táºp tin nà o được thêm và o" -#: builtin/add.c:359 +#: builtin/add.c:360 msgid "adding files failed" msgstr "thêm táºp tin gặp lá»—i" -#: builtin/add.c:391 +#: builtin/add.c:392 msgid "-A and -u are mutually incompatible" msgstr "-A và -u xung khắc nhau" -#: builtin/add.c:393 +#: builtin/add.c:394 msgid "Option --ignore-missing can only be used together with --dry-run" -msgstr "Tùy chá»n --ignore-missing chỉ có thể được sá» dụng cùng vá»›i --dry-run" +msgstr "Tùy chá»n --ignore-missing chỉ có thể được dùng cùng vá»›i --dry-run" -#: builtin/add.c:413 +#: builtin/add.c:414 #, c-format msgid "Nothing specified, nothing added.\n" msgstr "Không có gì được chỉ ra, không có gì được thêm và o.\n" -#: builtin/add.c:414 +#: builtin/add.c:415 #, c-format msgid "Maybe you wanted to say 'git add .'?\n" -msgstr "Có lẽ bạn muốn nói là 'git add .' phải không?\n" +msgstr "Có lẽ bạn muốn là “git add .†phải không?\n" -#: builtin/add.c:420 -#: builtin/clean.c:95 -#: builtin/commit.c:286 -#: builtin/mv.c:82 -#: builtin/rm.c:162 +#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:291 builtin/mv.c:82 +#: builtin/rm.c:235 msgid "index file corrupt" msgstr "táºp tin ghi bảng mục lục bị há»ng" -#: builtin/add.c:476 -#: builtin/apply.c:4108 -#: builtin/mv.c:229 -#: builtin/rm.c:260 +#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:370 msgid "Unable to write new index file" msgstr "Không thể ghi táºp tin lưu bảng mục lục má»›i" -#: builtin/apply.c:53 +#: builtin/apply.c:57 msgid "git apply [options] [<patch>...]" msgstr "git apply [các-tùy-chá»n] [<miếng-vá>...]" -#: builtin/apply.c:106 +#: builtin/apply.c:110 #, c-format msgid "unrecognized whitespace option '%s'" -msgstr "không nháºn ra tùy chá»n vá» khoảng trắng '%s'" +msgstr "không nháºn ra tùy chá»n vá» khoảng trắng “%sâ€" -#: builtin/apply.c:121 +#: builtin/apply.c:125 #, c-format msgid "unrecognized whitespace ignore option '%s'" -msgstr "không nháºn ra tùy chá»n bá» qua khoảng trắng '%s'" +msgstr "không nháºn ra tùy chá»n bá» qua khoảng trắng “%sâ€" -#: builtin/apply.c:815 +#: builtin/apply.c:823 #, c-format msgid "Cannot prepare timestamp regexp %s" -msgstr "Không thể chuẩn bị biểu thức chÃnh qui dấu vết thá»i gian (timestamp regexp) %s" +msgstr "" +"Không thể chuẩn bị biểu thức chÃnh qui dấu vết thá»i gian (timestamp regexp) " +"%s" -#: builtin/apply.c:824 +#: builtin/apply.c:832 #, c-format msgid "regexec returned %d for input: %s" msgstr "thi hà nh biểu thức chÃnh quy trả vá» %d cho kết xuất: %s" -#: builtin/apply.c:905 +#: builtin/apply.c:913 #, c-format msgid "unable to find filename in patch at line %d" msgstr "không thể tìm thấy tên táºp tin trong miếng vá tại dòng %d" -#: builtin/apply.c:937 +#: builtin/apply.c:945 #, c-format msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" msgstr "git apply: git-diff sai - mong đợi /dev/null, đã nháºn %s trên dòng %d" -#: builtin/apply.c:941 +#: builtin/apply.c:949 #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "git apply: git-diff sai - tên táºp tin má»›i mâu thuấn trên dòng %d" -#: builtin/apply.c:942 +#: builtin/apply.c:950 #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "git apply: git-diff sai - tên táºp tin cÅ© mâu thuấn trên dòng %d" -#: builtin/apply.c:949 +#: builtin/apply.c:957 #, c-format msgid "git apply: bad git-diff - expected /dev/null on line %d" msgstr "git apply: git-diff sai - mong đợi /dev/null trên dòng %d" -#: builtin/apply.c:1394 +#: builtin/apply.c:1420 #, c-format msgid "recount: unexpected line: %.*s" msgstr "chi tiết: dòng không được mong đợi: %.*s" -#: builtin/apply.c:1451 +#: builtin/apply.c:1477 #, c-format msgid "patch fragment without header at line %d: %.*s" msgstr "miếng vá phân mảnh mà không có phần đầu tại dòng %d: %.*s" -#: builtin/apply.c:1468 +#: builtin/apply.c:1494 #, c-format -msgid "git diff header lacks filename information when removing %d leading pathname component (line %d)" -msgid_plural "git diff header lacks filename information when removing %d leading pathname components (line %d)" -msgstr[0] "phần đầu diff cho git thiếu thông tin tên táºp tin khi gỡ bá» Ä‘i %d trong thà nh phần dẫn đầu tên cá»§a đưá»ng dẫn (dòng %d)" -msgstr[1] "phần đầu diff cho git thiếu thông tin tên táºp tin khi gỡ bá» Ä‘i %d trong thà nh phần dẫn đầu tên cá»§a đưá»ng dẫn (dòng %d)" +msgid "" +"git diff header lacks filename information when removing %d leading pathname " +"component (line %d)" +msgid_plural "" +"git diff header lacks filename information when removing %d leading pathname " +"components (line %d)" +msgstr[0] "" +"phần đầu diff cho git thiếu thông tin tên táºp tin khi gỡ bá» Ä‘i %d trong " +"thà nh phần dẫn đầu tên cá»§a đưá»ng dẫn (dòng %d)" +msgstr[1] "" +"phần đầu diff cho git thiếu thông tin tên táºp tin khi gỡ bá» Ä‘i %d trong " +"thà nh phần dẫn đầu tên cá»§a đưá»ng dẫn (dòng %d)" -#: builtin/apply.c:1628 +#: builtin/apply.c:1654 msgid "new file depends on old contents" msgstr "táºp tin má»›i phụ thuá»™c và o ná»™i dung cÅ©" -#: builtin/apply.c:1630 +#: builtin/apply.c:1656 msgid "deleted file still has contents" msgstr "táºp tin đã xóa vẫn còn ná»™i dung" -#: builtin/apply.c:1656 +#: builtin/apply.c:1682 #, c-format msgid "corrupt patch at line %d" msgstr "miếng vá há»ng tại dòng %d" -#: builtin/apply.c:1692 +#: builtin/apply.c:1718 #, c-format msgid "new file %s depends on old contents" msgstr "táºp tin má»›i %s phụ thuá»™c và o ná»™i dung cÅ©" -#: builtin/apply.c:1694 +#: builtin/apply.c:1720 #, c-format msgid "deleted file %s still has contents" msgstr "táºp tin đã xóa %s vẫn còn ná»™i dung" -#: builtin/apply.c:1697 +#: builtin/apply.c:1723 #, c-format msgid "** warning: file %s becomes empty but is not deleted" msgstr "** cảnh báo: táºp tin %s trở nên trống rá»—ng nhưng không bị xóa" -#: builtin/apply.c:1843 +#: builtin/apply.c:1869 #, c-format msgid "corrupt binary patch at line %d: %.*s" msgstr "miếng vá định dạng nhị phân sai há»ng tại dòng %d: %.*s" #. there has to be one hunk (forward hunk) -#: builtin/apply.c:1872 +#: builtin/apply.c:1898 #, c-format msgid "unrecognized binary patch at line %d" msgstr "miếng vá định dạng nhị phân không được nháºn ra tại dòng %d" -#: builtin/apply.c:1958 +#: builtin/apply.c:1984 #, c-format msgid "patch with only garbage at line %d" -msgstr "vá chỉ vá»›i 'garbage' tại dòng %d" +msgstr "vá chỉ vá»›i “garbage†tại dòng %d" -#: builtin/apply.c:2048 +#: builtin/apply.c:2074 #, c-format msgid "unable to read symlink %s" msgstr "không thể Ä‘á»c liên kết tượng trưng %s" -#: builtin/apply.c:2052 +#: builtin/apply.c:2078 #, c-format msgid "unable to open or read %s" msgstr "không thể mở để Ä‘á»c hay ghi %s" -#: builtin/apply.c:2123 +#: builtin/apply.c:2149 msgid "oops" msgstr "ôi?" -#: builtin/apply.c:2645 +#: builtin/apply.c:2671 #, c-format msgid "invalid start of line: '%c'" -msgstr "sai khởi đầu dòng: '%c'" +msgstr "sai khởi đầu dòng: “%câ€" -#: builtin/apply.c:2763 +#: builtin/apply.c:2789 #, c-format msgid "Hunk #%d succeeded at %d (offset %d line)." msgid_plural "Hunk #%d succeeded at %d (offset %d lines)." msgstr[0] "Khối dữ liệu #%d thà nh công tại %d (offset %d dòng)." msgstr[1] "Khối dữ liệu #%d thà nh công tại %d (offset %d dòng)." -#: builtin/apply.c:2775 +#: builtin/apply.c:2801 #, c-format msgid "Context reduced to (%ld/%ld) to apply fragment at %d" -msgstr "Ná»™i dung được giảm xuống (%ld/%ld) để áp dụng mảnh dữ liệu tại %d" +msgstr "Ná»™i dung bị giảm xuống (%ld/%ld) để áp dụng mảnh dữ liệu tại %d" -#: builtin/apply.c:2781 +#: builtin/apply.c:2807 #, c-format msgid "" "while searching for:\n" @@ -1184,320 +1737,325 @@ msgstr "" "Trong khi Ä‘ang tìm kiếm cho:\n" "%.*s" -#: builtin/apply.c:2800 +#: builtin/apply.c:2826 #, c-format msgid "missing binary patch data for '%s'" -msgstr "thiếu dữ liệu cá»§a miếng vá định dạng nhị phân cho '%s'" +msgstr "thiếu dữ liệu cá»§a miếng vá định dạng nhị phân cho “%sâ€" -#: builtin/apply.c:2903 +#: builtin/apply.c:2929 #, c-format msgid "binary patch does not apply to '%s'" -msgstr "miếng vá định dạng nhị phân không được áp dụng cho '%s'" +msgstr "miếng vá định dạng nhị phân không được áp dụng cho “%sâ€" -#: builtin/apply.c:2909 +#: builtin/apply.c:2935 #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" -msgstr "vá nhị phân cho '%s' tạo ra kết quả không chÃnh xác (Ä‘ang chá» %s, đã nháºn %s)" +msgstr "" +"vá nhị phân cho “%s†tạo ra kết quả không chÃnh xác (mong chá» %s, lại nháºn " +"%s)" -#: builtin/apply.c:2930 +#: builtin/apply.c:2956 #, c-format msgid "patch failed: %s:%ld" msgstr "vá gặp lá»—i: %s:%ld" -#: builtin/apply.c:3045 +#: builtin/apply.c:3078 #, c-format -msgid "patch %s has been renamed/deleted" -msgstr "miếng vá %s đã bị xóa/đổi tên" +msgid "cannot checkout %s" +msgstr "không thể \"checkout\" %s" -#: builtin/apply.c:3052 -#: builtin/apply.c:3069 +#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176 #, c-format msgid "read of %s failed" msgstr "Ä‘á»c %s gặp lá»—i" -#: builtin/apply.c:3084 -msgid "removal patch leaves file contents" -msgstr "loại bá» miếng vá để lại ná»™i dung táºp tin" - -#: builtin/apply.c:3105 +#: builtin/apply.c:3156 builtin/apply.c:3378 #, c-format -msgid "%s: already exists in working directory" -msgstr "%s: đã sẵn có trong thư mục Ä‘ang là m việc" +msgid "path %s has been renamed/deleted" +msgstr "đưá»ng dẫn %s đã bị xóa/đổi tên" -#: builtin/apply.c:3143 +#: builtin/apply.c:3237 builtin/apply.c:3392 #, c-format -msgid "%s: has been deleted/renamed" -msgstr "%s: đã được xóa/thay-tên" +msgid "%s: does not exist in index" +msgstr "%s: không tồn tại trong bảng mục lục" -#: builtin/apply.c:3148 -#: builtin/apply.c:3179 +#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: builtin/apply.c:3159 -#, c-format -msgid "%s: does not exist in index" -msgstr "%s: không tồn tại trong bảng mục lục" - -#: builtin/apply.c:3173 +#: builtin/apply.c:3246 builtin/apply.c:3400 #, c-format msgid "%s: does not match index" msgstr "%s: không khá»›p trong mục lục" -#: builtin/apply.c:3190 +#: builtin/apply.c:3348 +msgid "removal patch leaves file contents" +msgstr "loại bá» miếng vá để lại ná»™i dung táºp tin" + +#: builtin/apply.c:3417 #, c-format msgid "%s: wrong type" msgstr "%s: sai kiểu" -#: builtin/apply.c:3192 +#: builtin/apply.c:3419 #, c-format msgid "%s has type %o, expected %o" msgstr "%s có kiểu %o, mong chá» %o" -#: builtin/apply.c:3247 +#: builtin/apply.c:3520 #, c-format msgid "%s: already exists in index" msgstr "%s: đã có từ trước trong bảng mục lục" -#: builtin/apply.c:3267 +#: builtin/apply.c:3523 +#, c-format +msgid "%s: already exists in working directory" +msgstr "%s: đã sẵn có trong thư mục Ä‘ang là m việc" + +#: builtin/apply.c:3543 #, c-format msgid "new mode (%o) of %s does not match old mode (%o)" msgstr "chế độ má»›i (%o) cá»§a %s không khá»›p vá»›i chế độ cÅ© (%o)" -#: builtin/apply.c:3272 +#: builtin/apply.c:3548 #, c-format msgid "new mode (%o) of %s does not match old mode (%o) of %s" msgstr "chế độ má»›i (%o) cá»§a %s không khá»›p vá»›i chế độ cÅ© (%o) cá»§a %s" -#: builtin/apply.c:3280 +#: builtin/apply.c:3556 #, c-format msgid "%s: patch does not apply" msgstr "%s: miếng vá không được áp dụng" -#: builtin/apply.c:3293 +#: builtin/apply.c:3569 #, c-format msgid "Checking patch %s..." msgstr "Äang kiểm tra miếng vá %s..." -#: builtin/apply.c:3348 -#: builtin/checkout.c:212 -#: builtin/reset.c:158 +#: builtin/apply.c:3624 builtin/checkout.c:215 builtin/reset.c:158 #, c-format msgid "make_cache_entry failed for path '%s'" -msgstr "make_cache_entry gặp lá»—i đối vá»›i đưá»ng dẫn '%s'" +msgstr "make_cache_entry gặp lá»—i đối vá»›i đưá»ng dẫn “%sâ€" -#: builtin/apply.c:3491 +#: builtin/apply.c:3767 #, c-format msgid "unable to remove %s from index" msgstr "không thể gỡ bá» %s từ mục lục" -#: builtin/apply.c:3518 +#: builtin/apply.c:3795 #, c-format msgid "corrupt patch for subproject %s" msgstr "miếng vá sai há»ng cho dá»± án con (subproject) %s" -#: builtin/apply.c:3522 +#: builtin/apply.c:3799 #, c-format msgid "unable to stat newly created file '%s'" msgstr "không thể lấy trạng thái vá» táºp tin %s má»›i hÆ¡n đã được tạo" -#: builtin/apply.c:3527 +#: builtin/apply.c:3804 #, c-format msgid "unable to create backing store for newly created file %s" -msgstr "không thể tạo 'backing store' cho táºp tin được tạo má»›i hÆ¡n %s" +msgstr "không thể tạo “backing store†cho táºp tin được tạo má»›i hÆ¡n %s" -#: builtin/apply.c:3530 +#: builtin/apply.c:3807 builtin/apply.c:3915 #, c-format msgid "unable to add cache entry for %s" msgstr "không thể thêm mục nhá»› tạm cho %s" -#: builtin/apply.c:3563 +#: builtin/apply.c:3840 #, c-format msgid "closing file '%s'" -msgstr "Ä‘ang đóng táºp tin '%s'" +msgstr "Ä‘ang đóng táºp tin “%sâ€" -#: builtin/apply.c:3612 +#: builtin/apply.c:3889 #, c-format msgid "unable to write file '%s' mode %o" -msgstr "không thể ghi và o táºp tin '%s' chế độ (mode) %o" +msgstr "không thể ghi và o táºp tin “%s†chế độ (mode) %o" -#: builtin/apply.c:3668 +#: builtin/apply.c:3976 #, c-format msgid "Applied patch %s cleanly." msgstr "Äã áp dụng miếng và %s má»™t cách sạch sẽ." -#: builtin/apply.c:3676 +#: builtin/apply.c:3984 msgid "internal error" msgstr "lá»—i ná»™i bá»™" #. Say this even without --verbose -#: builtin/apply.c:3679 +#: builtin/apply.c:3987 #, c-format msgid "Applying patch %%s with %d reject..." msgid_plural "Applying patch %%s with %d rejects..." msgstr[0] "Äang áp dụng miếng vá %%s vá»›i %d lần từ chối..." msgstr[1] "Äang áp dụng miếng vá %%s vá»›i %d lần từ chối..." -#: builtin/apply.c:3689 +#: builtin/apply.c:3997 #, c-format msgid "truncating .rej filename to %.*s.rej" msgstr "Ä‘ang cắt cụt tên táºp tin .rej thà nh %.*s.rej" -#: builtin/apply.c:3710 +#: builtin/apply.c:4018 #, c-format msgid "Hunk #%d applied cleanly." msgstr "Khối nhá»› #%d được áp dụng gá»n gà ng." -#: builtin/apply.c:3713 +#: builtin/apply.c:4021 #, c-format msgid "Rejected hunk #%d." msgstr "hunk #%d bị từ chối." -#: builtin/apply.c:3844 +#: builtin/apply.c:4171 msgid "unrecognized input" msgstr "không thừa nháºn đầu và o" -#: builtin/apply.c:3855 +#: builtin/apply.c:4182 msgid "unable to read index file" msgstr "không thể Ä‘á»c táºp tin lưu bảng mục lục" -#: builtin/apply.c:3970 -#: builtin/apply.c:3973 +#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91 +#: builtin/fetch.c:63 msgid "path" msgstr "đưá»ng-dẫn" -#: builtin/apply.c:3971 +#: builtin/apply.c:4302 msgid "don't apply changes matching the given path" msgstr "không áp dụng các thay đổi khá»›p vá»›i đưá»ng dẫn đã cho" -#: builtin/apply.c:3974 +#: builtin/apply.c:4305 msgid "apply changes matching the given path" msgstr "áp dụng các thay đổi khá»›p vá»›i đưá»ng dẫn đã cho" -#: builtin/apply.c:3976 +#: builtin/apply.c:4307 msgid "num" msgstr "số" -#: builtin/apply.c:3977 +#: builtin/apply.c:4308 msgid "remove <num> leading slashes from traditional diff paths" msgstr "gỡ bá» <số> phần dẫn đầu (slashe) từ đưá»ng dẫn diff cổ Ä‘iển" -#: builtin/apply.c:3980 +#: builtin/apply.c:4311 msgid "ignore additions made by the patch" msgstr "lá» Ä‘i phần phụ thêm tạo ra bởi miếng vá" -#: builtin/apply.c:3982 +#: builtin/apply.c:4313 msgid "instead of applying the patch, output diffstat for the input" -msgstr "thay vì áp dụng má»™t miếng vá, kết xuất kết quả từ lệnh diffstat cho đầu ra" +msgstr "" +"thay vì áp dụng má»™t miếng vá, kết xuất kết quả từ lệnh diffstat cho đầu ra" -#: builtin/apply.c:3986 -msgid "shows number of added and deleted lines in decimal notation" -msgstr "hiển thị số lượng các dòng được thêm và o và xóa Ä‘i theo ký hiệu tháºp phân" +#: builtin/apply.c:4317 +msgid "show number of added and deleted lines in decimal notation" +msgstr "" +"hiển thị số lượng các dòng được thêm và o và xóa Ä‘i theo ký hiệu tháºp phân" -#: builtin/apply.c:3988 +#: builtin/apply.c:4319 msgid "instead of applying the patch, output a summary for the input" msgstr "thay vì áp dụng má»™t miếng vá, kết xuất kết quả cho đầu và o" -#: builtin/apply.c:3990 +#: builtin/apply.c:4321 msgid "instead of applying the patch, see if the patch is applicable" msgstr "thay vì áp dụng miếng vá, hãy xem xem miếng vá có thÃch hợp không" -#: builtin/apply.c:3992 +#: builtin/apply.c:4323 msgid "make sure the patch is applicable to the current index" msgstr "hãy chắc chắn là miếng vá thÃch hợp vá»›i bảng mục lục hiện hà nh" -#: builtin/apply.c:3994 +#: builtin/apply.c:4325 msgid "apply a patch without touching the working tree" msgstr "áp dụng má»™t miếng vá mà không động chạm đến cây là m việc" -#: builtin/apply.c:3996 +#: builtin/apply.c:4327 msgid "also apply the patch (use with --stat/--summary/--check)" -msgstr "đồng thá»i áp dụng miếng vá (sá» dụng vá»›i tùy chá»n --stat/--summary/--check)" +msgstr "" +"đồng thá»i áp dụng miếng vá (dùng vá»›i tùy chá»n --stat/--summary/--check)" -#: builtin/apply.c:3998 +#: builtin/apply.c:4329 +msgid "attempt three-way merge if a patch does not apply" +msgstr "thá» hòa trá»™n kiểu three-way nếu việc vá không thể thá»±c hiện được" + +#: builtin/apply.c:4331 msgid "build a temporary index based on embedded index information" -msgstr "xây dá»±ng bảng mục lục tạm thá»i trên cÆ¡ sở thông tin bảng mục lục được nhúng" +msgstr "" +"xây dá»±ng bảng mục lục tạm thá»i trên cÆ¡ sở thông tin bảng mục lục được nhúng" -#: builtin/apply.c:4000 +#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460 msgid "paths are separated with NUL character" msgstr "các đưá»ng dẫn bị ngăn cách bởi ký tá»± NULL" -#: builtin/apply.c:4003 +#: builtin/apply.c:4336 msgid "ensure at least <n> lines of context match" msgstr "đảm bảo rằng có Ãt nhất <n> dòng ná»™i dung khá»›p" -#: builtin/apply.c:4004 +#: builtin/apply.c:4337 msgid "action" msgstr "hà nh động" -#: builtin/apply.c:4005 +#: builtin/apply.c:4338 msgid "detect new or modified lines that have whitespace errors" msgstr "tìm thấy má»™t dòng má»›i hoặc bị sá»a đổi mà nó có lá»—i do khoảng trắng" -#: builtin/apply.c:4008 -#: builtin/apply.c:4011 +#: builtin/apply.c:4341 builtin/apply.c:4344 msgid "ignore changes in whitespace when finding context" msgstr "lá» Ä‘i sá»± thay đổi do khoảng trắng khi quét ná»™i dung" -#: builtin/apply.c:4014 +#: builtin/apply.c:4347 msgid "apply the patch in reverse" msgstr "áp dụng miếng vá theo chiá»u ngược" -#: builtin/apply.c:4016 +#: builtin/apply.c:4349 msgid "don't expect at least one line of context" msgstr "đừng hy vá»ng có Ãt nhất má»™t dòng ná»™i dung" -#: builtin/apply.c:4018 +#: builtin/apply.c:4351 msgid "leave the rejected hunks in corresponding *.rej files" msgstr "để lại khối dữ liệu bị từ chối trong các táºp tin *.rej tương ứng" -#: builtin/apply.c:4020 +#: builtin/apply.c:4353 msgid "allow overlapping hunks" msgstr "cho phép chồng khối nhá»›" -#: builtin/apply.c:4021 -msgid "be verbose" -msgstr "chi tiết" - -#: builtin/apply.c:4023 +#: builtin/apply.c:4356 msgid "tolerate incorrectly detected missing new-line at the end of file" -msgstr "dung sai không chÃnh xác đã tìm thấy thiếu dòng má»›i tại cuối táºp tin" +msgstr "" +"đã dò tìm thấy dung sai không chÃnh xác thiếu dòng má»›i tại cuối táºp tin" -#: builtin/apply.c:4026 +#: builtin/apply.c:4359 msgid "do not trust the line counts in the hunk headers" msgstr "không tin số lượng dòng trong phần đầu khối dữ liệu" -#: builtin/apply.c:4028 +#: builtin/apply.c:4361 msgid "root" msgstr "root" -#: builtin/apply.c:4029 +#: builtin/apply.c:4362 msgid "prepend <root> to all filenames" msgstr "treo thêm <root> và o tất cả các tên táºp tin" -#: builtin/apply.c:4050 +#: builtin/apply.c:4384 +msgid "--3way outside a repository" +msgstr "--3way ở ngoà i má»™t kho chứa" + +#: builtin/apply.c:4392 msgid "--index outside a repository" msgstr "--index ở ngoà i má»™t kho chứa" -#: builtin/apply.c:4053 +#: builtin/apply.c:4395 msgid "--cached outside a repository" msgstr "--cached ở ngoà i má»™t kho chứa" -#: builtin/apply.c:4069 +#: builtin/apply.c:4411 #, c-format msgid "can't open patch '%s'" -msgstr "không thể mở miếng vá '%s'" +msgstr "không thể mở miếng vá “%sâ€" -#: builtin/apply.c:4083 +#: builtin/apply.c:4425 #, c-format msgid "squelched %d whitespace error" msgid_plural "squelched %d whitespace errors" msgstr[0] "đã chấm dứt %d lá»—i khoảng trắng" msgstr[1] "đã chấm dứt %d lá»—i khoảng trắng" -#: builtin/apply.c:4089 -#: builtin/apply.c:4099 +#: builtin/apply.c:4431 builtin/apply.c:4441 #, c-format msgid "%d line adds whitespace errors." msgid_plural "%d lines add whitespace errors." @@ -1507,7 +2065,7 @@ msgstr[1] "%d dòng thêm khoảng trắng lá»—i." #: builtin/archive.c:17 #, c-format msgid "could not create archive file '%s'" -msgstr "không thể tạo táºp tin kho (lưu trữ, nén) '%s'" +msgstr "không thể tạo táºp tin kho (lưu trữ, nén) “%sâ€" #: builtin/archive.c:20 msgid "could not redirect output" @@ -1539,186 +2097,449 @@ msgstr "git archive: lá»—i giao thức" msgid "git archive: expected a flush" msgstr "git archive: đã mong chá» má»™t flush" -#: builtin/branch.c:144 +#: builtin/bisect--helper.c:7 +msgid "git bisect--helper --next-all [--no-checkout]" +msgstr "git bisect--helper --next-all [--no-checkout]" + +#: builtin/bisect--helper.c:17 +msgid "perform 'git bisect next'" +msgstr "thá»±c hiện “git bisect nextâ€" + +#: builtin/bisect--helper.c:19 +msgid "update BISECT_HEAD instead of checking out the current commit" +msgstr "" +"cáºp nháºt BISECT_HEAD thay vì lấy ra (checking out) lần chuyển giao (commit) " +"hiện hà nh" + +#: builtin/blame.c:25 +msgid "git blame [options] [rev-opts] [rev] [--] file" +msgstr "git blame [các-tùy-chá»n] [rev-opts] [rev] [--] táºp-tin" + +#: builtin/blame.c:30 builtin/shortlog.c:15 +msgid "[rev-opts] are documented in git-rev-list(1)" +msgstr "[rev-opts] được mô tả trong git-rev-list(1)" + +#: builtin/blame.c:2374 +msgid "Show blame entries as we find them, incrementally" +msgstr "Hiển thị các mục “blame†như là chúng ta thấy chúng, tăng dần" + +#: builtin/blame.c:2375 +msgid "Show blank SHA-1 for boundary commits (Default: off)" +msgstr "" +"Hiển thị SHA-1 trắng cho những lần chuyển giao biên giá»›i (Mặc định: off)" + +#: builtin/blame.c:2376 +msgid "Do not treat root commits as boundaries (Default: off)" +msgstr "Không coi các lần chuyển giao gốc là giá»›i hạn (Mặc định: off)" + +#: builtin/blame.c:2377 +msgid "Show work cost statistics" +msgstr "Hiển thị thống kê công sức là m việc" + +#: builtin/blame.c:2378 +msgid "Show output score for blame entries" +msgstr "Hiển thị kết xuất Ä‘iểm số có các mục tin “blameâ€" + +#: builtin/blame.c:2379 +msgid "Show original filename (Default: auto)" +msgstr "Hiển thị tên táºp tin gốc (Mặc định: auto)" + +#: builtin/blame.c:2380 +msgid "Show original linenumber (Default: off)" +msgstr "Hiển thị số dòng gốc (Mặc định: off)" + +#: builtin/blame.c:2381 +msgid "Show in a format designed for machine consumption" +msgstr "Hiển thị ở định dạng đã thiết kế cho sá»± tiêu dùng bằng máy" + +#: builtin/blame.c:2382 +msgid "Show porcelain format with per-line commit information" +msgstr "Hiển thị định dạng “porcelain†vá»›i thông tin chuyển giao má»—i dòng" + +#: builtin/blame.c:2383 +msgid "Use the same output mode as git-annotate (Default: off)" +msgstr "Dùng cùng chế độ xuất ra vóigit-annotate (Mặc định: off)" + +#: builtin/blame.c:2384 +msgid "Show raw timestamp (Default: off)" +msgstr "Hiển thị dấu vết thá»i gian dạng thô (Mặc định: off)" + +#: builtin/blame.c:2385 +msgid "Show long commit SHA1 (Default: off)" +msgstr "Hiển thị SHA1 cá»§a lần chuyển giao (commit) dạng dà i (Mặc định: off)" + +#: builtin/blame.c:2386 +msgid "Suppress author name and timestamp (Default: off)" +msgstr "Không hiển thị tên tác giả và dấu vết thá»i gian (Mặc định: off)" + +#: builtin/blame.c:2387 +msgid "Show author email instead of name (Default: off)" +msgstr "Hiển thị thư Ä‘iện tá» cá»§a tác giả thay vì tên (Mặc định: off)" + +#: builtin/blame.c:2388 +msgid "Ignore whitespace differences" +msgstr "Bá» qua các khác biệt do khoảng trắng gây ra" + +#: builtin/blame.c:2389 +msgid "Spend extra cycles to find better match" +msgstr "Tiêu thụ thêm năng tà i nguyên máy móc để tìm kiếm tốt hÆ¡n nữa" + +#: builtin/blame.c:2390 +msgid "Use revisions from <file> instead of calling git-rev-list" +msgstr "" +"Sá» dụng Ä‘iểm xét duyệt (revision) từ <táºp tin> thay vì gá»i “git-rev-listâ€" + +#: builtin/blame.c:2391 +msgid "Use <file>'s contents as the final image" +msgstr "Sá» dụng ná»™i dung cá»§a <táºp tin> như là ảnh cuối cùng" + +#: builtin/blame.c:2392 builtin/blame.c:2393 +msgid "score" +msgstr "Ä‘iểm số" + +#: builtin/blame.c:2392 +msgid "Find line copies within and across files" +msgstr "Tìm các bản sao chép dòng trong và ngang qua táºp tin" + +#: builtin/blame.c:2393 +msgid "Find line movements within and across files" +msgstr "Tìm các di chuyển dòng trong và ngang qua táºp tin" + +#: builtin/blame.c:2394 +msgid "n,m" +msgstr "n,m" + +#: builtin/blame.c:2394 +msgid "Process only line range n,m, counting from 1" +msgstr "Xá» lý chỉ dòng vùng n,m, tÃnh từ 1" + +#: builtin/branch.c:23 +msgid "git branch [options] [-r | -a] [--merged | --no-merged]" +msgstr "git branch [các-tùy-chá»n] [-r | -a] [--merged | --no-merged]" + +#: builtin/branch.c:24 +msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]" +msgstr "git branch [các-tùy-chá»n] [-l] [-f] <tên-nhánh> [<Ä‘iểm-đầu>]" + +#: builtin/branch.c:25 +msgid "git branch [options] [-r] (-d | -D) <branchname>..." +msgstr "git branch [các-tùy-chá»n] [-r] (-d | -D) <tên-nhánh> ..." + +#: builtin/branch.c:26 +msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>" +msgstr "git branch [các-tùy-chá»n] (-m | -M) [<nhánh-cÅ©>] <nhánh-má»›i>" + +#: builtin/branch.c:145 #, c-format msgid "" "deleting branch '%s' that has been merged to\n" " '%s', but not yet merged to HEAD." msgstr "" -"Ä‘ang xóa nhánh '%s' mà nó lại đã được hòa trá»™n và o\n" -" '%s', nhưng vẫn chưa được hòa trá»™n và o HEAD." +"Ä‘ang xóa nhánh “%s†mà nó lại đã được hòa trá»™n và o\n" +" “%sâ€, nhưng vẫn chưa được hòa trá»™n và o HEAD." -#: builtin/branch.c:148 +#: builtin/branch.c:149 #, c-format msgid "" "not deleting branch '%s' that is not yet merged to\n" " '%s', even though it is merged to HEAD." msgstr "" -"không xóa nhánh '%s' cái mà chưa được hòa trá»™ng và o\n" -" '%s', cho dù là nó đã được hòa trá»™n và o HEAD." +"không xóa nhánh “%s†cái mà chưa được hòa trá»™n và o\n" +" “%sâ€, cho dù là nó đã được hòa trá»™n và o HEAD." + +#: builtin/branch.c:163 +#, c-format +msgid "Couldn't look up commit object for '%s'" +msgstr "Không thể tìm kiếm đối tượng chuyển giao (commit) cho “%sâ€" + +#: builtin/branch.c:167 +#, c-format +msgid "" +"The branch '%s' is not fully merged.\n" +"If you are sure you want to delete it, run 'git branch -D %s'." +msgstr "" +"Nhánh “%s†không được trá»™n má»™t cách đầy đủ.\n" +"Nếu bạn thá»±c sá»± muốn xóa nó, thì chạy lệnh “git branch -D %sâ€." #: builtin/branch.c:180 +msgid "Update of config-file failed" +msgstr "Cáºp nháºt táºp tin cấu hình gặp lá»—i" + +#: builtin/branch.c:208 msgid "cannot use -a with -d" -msgstr "không thể sá» dụng -a vá»›i -d" +msgstr "không thể dùng tùy chá»n -a vá»›i -d" -#: builtin/branch.c:186 +#: builtin/branch.c:214 msgid "Couldn't look up commit object for HEAD" msgstr "Không thể tìm kiếm đối tượng chuyển giao (commit) cho HEAD" -#: builtin/branch.c:191 +#: builtin/branch.c:222 #, c-format msgid "Cannot delete the branch '%s' which you are currently on." -msgstr "Không thể xóa nhánh '%s' cái mà bạn hiện nay Ä‘ang ở." +msgstr "Không thể xóa nhánh “%s†cái mà bạn hiện nay Ä‘ang ở." -#: builtin/branch.c:202 +#: builtin/branch.c:235 #, c-format msgid "remote branch '%s' not found." -msgstr "nhánh máy chá»§ '%s' không tìm thấy." +msgstr "không tìm thấy nhánh máy chá»§ “%sâ€." -#: builtin/branch.c:203 +#: builtin/branch.c:236 #, c-format msgid "branch '%s' not found." -msgstr "không tìm thấy nhánh '%s'." - -#: builtin/branch.c:210 -#, c-format -msgid "Couldn't look up commit object for '%s'" -msgstr "Không thể tìm kiếm đối tượng chuyển giao (commit) cho '%s'" +msgstr "không tìm thấy nhánh “%sâ€." -#: builtin/branch.c:216 -#, c-format -msgid "" -"The branch '%s' is not fully merged.\n" -"If you are sure you want to delete it, run 'git branch -D %s'." -msgstr "" -"Nhánh '%s' không được trá»™n má»™t cách đầy đủ.\n" -"Nếu bạn thá»±c sá»± muốn xóa nó, thì chạy lệnh 'git branch -D %s'." - -#: builtin/branch.c:225 +#: builtin/branch.c:250 #, c-format msgid "Error deleting remote branch '%s'" -msgstr "Gặp lá»—i khi Ä‘ang xóa nhánh máy chá»§ '%s'" +msgstr "Gặp lá»—i khi Ä‘ang xóa nhánh máy chá»§ “%sâ€" -#: builtin/branch.c:226 +#: builtin/branch.c:251 #, c-format msgid "Error deleting branch '%s'" -msgstr "Lá»—i khi xoá bá» nhánh '%s'" +msgstr "Lá»—i khi xoá bá» nhánh “%sâ€" -#: builtin/branch.c:233 +#: builtin/branch.c:258 #, c-format msgid "Deleted remote branch %s (was %s).\n" -msgstr "Nhánh máy chá»§ đã xóa %s (trước là %s).\n" +msgstr "Nhánh máy chá»§ \"%s\" đã bị xóa (từng là %s).\n" -#: builtin/branch.c:234 +#: builtin/branch.c:259 #, c-format msgid "Deleted branch %s (was %s).\n" -msgstr "Nhánh đã bị xóa '%s' (trước là %s)\n" +msgstr "Nhánh “%s†đã bị xóa (từng là %s)\n" -#: builtin/branch.c:239 -msgid "Update of config-file failed" -msgstr "Cáºp nháºt tệp tin cấu hình gặp lá»—i" - -#: builtin/branch.c:337 +#: builtin/branch.c:361 #, c-format msgid "branch '%s' does not point at a commit" -msgstr "nhánh '%s' không chỉ đến má»™t lần chuyển giao (commit) nà o cả" +msgstr "nhánh “%s†không chỉ đến má»™t lần chuyển giao (commit) nà o cả" -#: builtin/branch.c:409 +#: builtin/branch.c:433 #, c-format msgid "[%s: behind %d]" msgstr "[%s: đằng sau %d]" -#: builtin/branch.c:411 +#: builtin/branch.c:435 #, c-format msgid "[behind %d]" msgstr "[đằng sau %d]" -#: builtin/branch.c:415 +#: builtin/branch.c:439 #, c-format msgid "[%s: ahead %d]" msgstr "[%s: phÃa trước %d]" -#: builtin/branch.c:417 +#: builtin/branch.c:441 #, c-format msgid "[ahead %d]" msgstr "[phÃa trước %d]" -#: builtin/branch.c:420 +#: builtin/branch.c:444 #, c-format msgid "[%s: ahead %d, behind %d]" -msgstr "[%s: phÃa trước %d, phÃa sau %d]" +msgstr "[%s: trước %d, sau %d]" -#: builtin/branch.c:423 +#: builtin/branch.c:447 #, c-format msgid "[ahead %d, behind %d]" -msgstr "[phÃa trước %d, phÃa sau %d]" +msgstr "[trước %d, sau %d]" -#: builtin/branch.c:535 +#: builtin/branch.c:560 msgid "(no branch)" -msgstr "(không có nhánh nà o)" +msgstr "(không nhánh)" -#: builtin/branch.c:600 +#: builtin/branch.c:625 msgid "some refs could not be read" msgstr "má»™t số tham chiếu đã không thể Ä‘á»c được" -#: builtin/branch.c:613 +#: builtin/branch.c:638 msgid "cannot rename the current branch while not on any." msgstr "không thể đổi tên nhánh hiện hà nh trong khi nó chẳng ở đâu cả." -#: builtin/branch.c:623 +#: builtin/branch.c:648 #, c-format msgid "Invalid branch name: '%s'" -msgstr "tên nhánh sai: '%s'" +msgstr "Sai tên nhánh: “%sâ€" -#: builtin/branch.c:638 +#: builtin/branch.c:663 msgid "Branch rename failed" msgstr "Äổi tên nhánh gặp lá»—i" -#: builtin/branch.c:642 +#: builtin/branch.c:667 #, c-format msgid "Renamed a misnamed branch '%s' away" -msgstr "Äã đổi tên nhánh khuyết danh '%s' Ä‘i" +msgstr "Äã đổi tên nhánh khuyết danh “%s†đi" -#: builtin/branch.c:646 +#: builtin/branch.c:671 #, c-format msgid "Branch renamed to %s, but HEAD is not updated!" msgstr "Nhánh bị đổi tên thà nh %s, nhưng HEAD lại không được cáºp nháºt!" -#: builtin/branch.c:653 +#: builtin/branch.c:678 msgid "Branch is renamed, but update of config-file failed" msgstr "Nhánh bị đổi tên, nhưng cáºp nháºt táºp tin cấu hình gặp lá»—i" -#: builtin/branch.c:668 +#: builtin/branch.c:693 #, c-format msgid "malformed object name %s" msgstr "tên đối tượng dị hình %s" -#: builtin/branch.c:692 +#: builtin/branch.c:717 #, c-format msgid "could not write branch description template: %s" msgstr "không thể ghi và o mẫu mô tả nhánh: %s" -#: builtin/branch.c:783 +#: builtin/branch.c:747 +msgid "Generic options" +msgstr "Tùy chá»n chung" + +#: builtin/branch.c:749 +msgid "show hash and subject, give twice for upstream branch" +msgstr "hiển thị mã băm và chá»§ Ä‘á», đưa ra hai lần cho nhánh thượng nguồn" + +#: builtin/branch.c:750 +msgid "suppress informational messages" +msgstr "Thu hồi các thông Ä‘iệp thông tin" + +#: builtin/branch.c:751 +msgid "set up tracking mode (see git-pull(1))" +msgstr "cà i đặt chế độ theo vết (xem git-pull(1))" + +#: builtin/branch.c:753 +msgid "change upstream info" +msgstr "thay đổi thông tin thượng nguồn (upstream)" + +#: builtin/branch.c:757 +msgid "use colored output" +msgstr "sá» dụng kết xuất có tô mà u" + +#: builtin/branch.c:758 +msgid "act on remote-tracking branches" +msgstr "thao tác trên nhánh “remote-trackingâ€" + +#: builtin/branch.c:761 builtin/branch.c:767 builtin/branch.c:788 +#: builtin/branch.c:794 builtin/commit.c:1376 builtin/commit.c:1377 +#: builtin/commit.c:1378 builtin/commit.c:1379 builtin/tag.c:470 +msgid "commit" +msgstr "commit" + +#: builtin/branch.c:762 builtin/branch.c:768 +msgid "print only branches that contain the commit" +msgstr "chỉ hiển thị những nhánh mà nó chứa lần chuyển giao" + +#: builtin/branch.c:774 +msgid "Specific git-branch actions:" +msgstr "Hà nh động git-branch:" + +#: builtin/branch.c:775 +msgid "list both remote-tracking and local branches" +msgstr "liệt kê cả nhánh “remote-tracking†và ná»™i bá»™" + +#: builtin/branch.c:777 +msgid "delete fully merged branch" +msgstr "xóa má»™t cách đầy đủ nhánh đã hòa trá»™n" + +#: builtin/branch.c:778 +msgid "delete branch (even if not merged)" +msgstr "xoá nhánh (cho dù là chưa được hòa trá»™n)" + +#: builtin/branch.c:779 +msgid "move/rename a branch and its reflog" +msgstr "di chuyển hay đổi tên má»™t nhánh và reflog cá»§a nó" + +#: builtin/branch.c:780 +msgid "move/rename a branch, even if target exists" +msgstr "di chuyển hoặc đổi tên má»™t nhánh, tháºm chà cả khi Ä‘Ãch đã có sẵn" + +#: builtin/branch.c:781 +msgid "list branch names" +msgstr "liệt kê các tên nhánh" + +#: builtin/branch.c:782 +msgid "create the branch's reflog" +msgstr "tạo reflog cá»§a nhánh" + +#: builtin/branch.c:784 +msgid "edit the description for the branch" +msgstr "sá»a mô tả cho nhánh" + +#: builtin/branch.c:785 +msgid "force creation (when already exists)" +msgstr "ép buá»™c tạo (khi đã sẵn tồn tại rồi)" + +#: builtin/branch.c:788 +msgid "print only not merged branches" +msgstr "chỉ hiển thị các nhánh chưa được hòa trá»™n" + +#: builtin/branch.c:794 +msgid "print only merged branches" +msgstr "chỉ hiển thị các nhánh được hòa trá»™n" + +#: builtin/branch.c:798 +msgid "list branches in columns" +msgstr "liệt kê các nhánh trong các cá»™t" + +#: builtin/branch.c:811 msgid "Failed to resolve HEAD as a valid ref." msgstr "Gặp lá»—i khi giải quyết HEAD như là má»™t tham chiếu (ref) hợp lệ." -#: builtin/branch.c:788 -#: builtin/clone.c:558 +#: builtin/branch.c:816 builtin/clone.c:561 msgid "HEAD not found below refs/heads!" -msgstr "HEAD không tìm thấy ở dưới refs/heads!" +msgstr "không tìm thấy HEAD ở dưới refs/heads!" -#: builtin/branch.c:808 +#: builtin/branch.c:836 msgid "--column and --verbose are incompatible" msgstr "--column và --verbose xung khắc nhau" -#: builtin/branch.c:857 +#: builtin/branch.c:887 +#, c-format +msgid "branch '%s' does not exist" +msgstr "nhánh “%s†chưa sẵn có" + +#: builtin/branch.c:899 +#, c-format +msgid "Branch '%s' has no upstream information" +msgstr "Nhánh “%s†không có thông tin thượng nguồn (upstream)" + +#: builtin/branch.c:914 msgid "-a and -r options to 'git branch' do not make sense with a branch name" -msgstr "hai tùy chá»n -a và -r áp dụng cho lệnh 'git branch' không hợp lý đối vá»›i tên nhánh" +msgstr "" +"hai tùy chá»n -a và -r áp dụng cho lệnh “git branch†không hợp lý đối vá»›i tên " +"nhánh" + +#: builtin/branch.c:917 +#, c-format +msgid "" +"The --set-upstream flag is deprecated and will be removed. Consider using --" +"track or --set-upstream-to\n" +msgstr "" +"Cá» --set-upstream bị phản đối và sẽ bị xóa bá». Nên dùng --track hoặc --set-" +"upstream-to\n" + +#: builtin/branch.c:934 +#, c-format +msgid "" +"\n" +"If you wanted to make '%s' track '%s', do this:\n" +"\n" +msgstr "" +"\n" +"Nếu bạn muốn “%s†theo dõi “%sâ€, thá»±c hiện lệnh sau:\n" +"\n" + +#: builtin/branch.c:935 +#, c-format +msgid " git branch -d %s\n" +msgstr " git branch -d %s\n" + +#: builtin/branch.c:936 +#, c-format +msgid " git branch --set-upstream-to %s\n" +msgstr " git branch --set-upstream-to %s\n" #: builtin/bundle.c:47 #, c-format msgid "%s is okay\n" -msgstr "'%s' tốt\n" +msgstr "“%s†tốt\n" #: builtin/bundle.c:56 msgid "Need a repository to create a bundle." @@ -1728,107 +2549,226 @@ msgstr "Cần má»™t kho chứa để mà tạo má»™t bundle." msgid "Need a repository to unbundle." msgstr "Cần má»™t kho chứa để mà bung má»™t bundle." -#: builtin/checkout.c:113 -#: builtin/checkout.c:146 +#: builtin/cat-file.c:247 +msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>" +msgstr "git cat-file (-t|-s|-e|-p|<kiểu>|--textconv) <đối tượng>" + +#: builtin/cat-file.c:248 +msgid "git cat-file (--batch|--batch-check) < <list_of_objects>" +msgstr "git cat-file (--batch|--batch-check) < <danh-sách-đối-tượng>" + +#: builtin/cat-file.c:266 +msgid "<type> can be one of: blob, tree, commit, tag" +msgstr "<kiểu> là má»™t trong số: blob, tree, commit, tag" + +#: builtin/cat-file.c:267 +msgid "show object type" +msgstr "hiển thị kiểu đối tượng" + +#: builtin/cat-file.c:268 +msgid "show object size" +msgstr "hiển thị kÃch thước đối tượng" + +#: builtin/cat-file.c:270 +msgid "exit with zero when there's no error" +msgstr "thoát vá»›i 0 khi không có lá»—i" + +#: builtin/cat-file.c:271 +msgid "pretty-print object's content" +msgstr "in ná»™i dung đối tượng dạng dá»… Ä‘á»c" + +#: builtin/cat-file.c:273 +msgid "for blob objects, run textconv on object's content" +msgstr "vá»›i đối tượng blob, chạy lệnh textconv trên ná»™i dung cá»§a đối tượng" + +#: builtin/cat-file.c:275 +msgid "show info and content of objects fed from the standard input" +msgstr "" +"hiển thị thông tin và ná»™i dung cá»§a các đối tượng lấy từ đầu và o tiêu chuẩn" + +#: builtin/cat-file.c:278 +msgid "show info about objects fed from the standard input" +msgstr "hiển thị các thông tin vỠđối tượng fed từ đầu và o tiêu chuẩn" + +#: builtin/check-attr.c:11 +msgid "git check-attr [-a | --all | attr...] [--] pathname..." +msgstr "git check-attr [-a | --all | attr...] [--] tên-đưá»ng-dẫn..." + +#: builtin/check-attr.c:12 +msgid "git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>" +msgstr "" +"git check-attr --stdin [-z] [-a | --all | attr...] < <danh-sách-đưá»ng-dẫn>" + +#: builtin/check-attr.c:19 +msgid "report all attributes set on file" +msgstr "báo cáo tất cả các thuá»™c tÃnh đặt trên táºp tin" + +#: builtin/check-attr.c:20 +msgid "use .gitattributes only from the index" +msgstr "chỉ sá» dụng .gitattributes từ bảng mục lục" + +#: builtin/check-attr.c:21 builtin/hash-object.c:75 +msgid "read file names from stdin" +msgstr "Ä‘á»c tên táºp tin từ đầu và o tiêu chuẩn" + +#: builtin/check-attr.c:23 +msgid "input paths are terminated by a null character" +msgstr "các đưá»ng dẫn được ngăn cách bởi ký tá»± null" + +#: builtin/checkout-index.c:126 +msgid "git checkout-index [options] [--] [<file>...]" +msgstr "git checkout-index [các-tùy-chá»n] [--] [<táºp-tin>...]" + +#: builtin/checkout-index.c:187 +msgid "check out all files in the index" +msgstr "lấy ra toà n bá»™ các táºp tin trong bảng mục lục" + +#: builtin/checkout-index.c:188 +msgid "force overwrite of existing files" +msgstr "ép buá»™c ghi đè lên táºp tin đã sẵn có từ trước" + +#: builtin/checkout-index.c:190 +msgid "no warning for existing files and files not in index" +msgstr "" +"không cảnh báo cho những táºp tin tồn tại và không có trong bảng mục lục" + +#: builtin/checkout-index.c:192 +msgid "don't checkout new files" +msgstr "không checkout các táºp tin má»›i" + +#: builtin/checkout-index.c:194 +msgid "update stat information in the index file" +msgstr "cáºp nháºt thông tin thống kê trong táºp tin lưu bảng mục lục má»›i" + +#: builtin/checkout-index.c:200 +msgid "read list of paths from the standard input" +msgstr " Ä‘á»c danh sách đưá»ng dẫn từ thiết bị nháºp chuẩn" + +#: builtin/checkout-index.c:202 +msgid "write the content to temporary files" +msgstr "ghi ná»™i dung và o táºp tin tạm" + +#: builtin/checkout-index.c:203 builtin/column.c:30 +msgid "string" +msgstr "chuá»—i" + +#: builtin/checkout-index.c:204 +msgid "when creating files, prepend <string>" +msgstr "khi tạo các táºp tin, nối thêm <chuá»—i>" + +#: builtin/checkout-index.c:207 +msgid "copy out the files from named stage" +msgstr "sao chép ra các táºp tin từ trạng thái được đặt tên" + +#: builtin/checkout.c:25 +msgid "git checkout [options] <branch>" +msgstr "git checkout [các-tùy-chá»n] <nhánh>" + +#: builtin/checkout.c:26 +msgid "git checkout [options] [<branch>] -- <file>..." +msgstr "git checkout [các-tùy-chá»n] [<nhánh>] -- <táºp-tin>..." + +#: builtin/checkout.c:116 builtin/checkout.c:149 #, c-format msgid "path '%s' does not have our version" -msgstr "đưá»ng dẫn '%s' không có các phiên bản cá»§a chúng ta" +msgstr "đưá»ng dẫn “%s†không có các phiên bản cá»§a chúng ta" -#: builtin/checkout.c:115 -#: builtin/checkout.c:148 +#: builtin/checkout.c:118 builtin/checkout.c:151 #, c-format msgid "path '%s' does not have their version" -msgstr "đưá»ng dẫn '%s' không có các phiên bản cá»§a chúng" +msgstr "đưá»ng dẫn “%s†không có các phiên bản cá»§a chúng" -#: builtin/checkout.c:131 +#: builtin/checkout.c:134 #, c-format msgid "path '%s' does not have all necessary versions" -msgstr "đưá»ng dẫn '%s' không có tất cả các phiên bản cần thiết" +msgstr "đưá»ng dẫn “%s†không có tất cả các phiên bản cần thiết" -#: builtin/checkout.c:175 +#: builtin/checkout.c:178 #, c-format msgid "path '%s' does not have necessary versions" -msgstr "đưá»ng dẫn '%s' không có các phiên bản cần thiết" +msgstr "đưá»ng dẫn “%s†không có các phiên bản cần thiết" -#: builtin/checkout.c:192 +#: builtin/checkout.c:195 #, c-format msgid "path '%s': cannot merge" -msgstr "đưá»ng dẫn '%s': không thể hòa trá»™n" +msgstr "đưá»ng dẫn “%sâ€: không thể hòa trá»™n" -#: builtin/checkout.c:209 +#: builtin/checkout.c:212 #, c-format msgid "Unable to add merge result for '%s'" -msgstr "Không thể thêm kết quả hòa trá»™n cho '%s'" +msgstr "Không thể thêm kết quả hòa trá»™n cho “%sâ€" + +#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242 +#: builtin/checkout.c:245 +#, c-format +msgid "'%s' cannot be used with updating paths" +msgstr "“%s†không thể được sá» dụng vá»›i các đưá»ng dẫn cáºp nháºt" -#: builtin/checkout.c:234 -#: builtin/checkout.c:392 +#: builtin/checkout.c:248 builtin/checkout.c:251 +#, c-format +msgid "'%s' cannot be used with %s" +msgstr "“%s†không thể được sá» dụng vá»›i %s" + +#: builtin/checkout.c:254 +#, c-format +msgid "Cannot update paths and switch to branch '%s' at the same time." +msgstr "" +"Không thể cáºp nháºt các đưá»ng dẫn và chuyển đến nhánh “%s†cùng má»™t lúc." + +#: builtin/checkout.c:265 builtin/checkout.c:426 msgid "corrupt index file" msgstr "táºp tin ghi bảng mục lục bị há»ng" -#: builtin/checkout.c:264 -#: builtin/checkout.c:271 +#: builtin/checkout.c:295 builtin/checkout.c:302 #, c-format msgid "path '%s' is unmerged" -msgstr "đưá»ng dẫn '%s' không được hòa trá»™n" - -#: builtin/checkout.c:302 -#: builtin/checkout.c:498 -#: builtin/clone.c:583 -#: builtin/merge.c:812 -msgid "unable to write new index file" -msgstr "không thể ghi táºp tin lưu bảng mục lục má»›i" +msgstr "đưá»ng dẫn “%s†không được hòa trá»™n" -#: builtin/checkout.c:319 -#: builtin/diff.c:302 -#: builtin/merge.c:408 -msgid "diff_setup_done failed" -msgstr "diff_setup_done gặp lá»—i" - -#: builtin/checkout.c:414 +#: builtin/checkout.c:448 msgid "you need to resolve your current index first" msgstr "bạn cần phải giải quyết bảng mục lục hiện tại cá»§a bạn trước đã!" -#: builtin/checkout.c:533 +#: builtin/checkout.c:569 #, c-format msgid "Can not do reflog for '%s'\n" -msgstr "Không thể thá»±c hiện reflog cho '%s'\n" +msgstr "Không thể thá»±c hiện reflog cho “%sâ€\n" -#: builtin/checkout.c:566 +#: builtin/checkout.c:602 msgid "HEAD is now at" msgstr "HEAD hiện giá» tại" -#: builtin/checkout.c:573 +#: builtin/checkout.c:609 #, c-format msgid "Reset branch '%s'\n" -msgstr "Äặt lại nhánh '%s'\n" +msgstr "Äặt lại nhánh “%sâ€\n" -#: builtin/checkout.c:576 +#: builtin/checkout.c:612 #, c-format msgid "Already on '%s'\n" -msgstr "Äã sẵn sà ng trên '%s'\n" +msgstr "Äã sẵn sà ng trên “%sâ€\n" -#: builtin/checkout.c:580 +#: builtin/checkout.c:616 #, c-format msgid "Switched to and reset branch '%s'\n" -msgstr "Äã chuyển tá»›i và reset nhánh '%s'\n" +msgstr "Äã chuyển tá»›i và reset nhánh “%sâ€\n" -#: builtin/checkout.c:582 +#: builtin/checkout.c:618 builtin/checkout.c:955 #, c-format msgid "Switched to a new branch '%s'\n" -msgstr "Äã chuyển đến nhánh má»›i '%s'\n" +msgstr "Äã chuyển đến nhánh má»›i “%sâ€\n" -#: builtin/checkout.c:584 +#: builtin/checkout.c:620 #, c-format msgid "Switched to branch '%s'\n" -msgstr "Äã chuyển đến nhánh '%s'\n" +msgstr "Äã chuyển đến nhánh “%sâ€\n" -#: builtin/checkout.c:640 +#: builtin/checkout.c:676 #, c-format msgid " ... and %d more.\n" msgstr " ... và nhiá»u hÆ¡n %d.\n" #. The singular version -#: builtin/checkout.c:646 +#: builtin/checkout.c:682 #, c-format msgid "" "Warning: you are leaving %d commit behind, not connected to\n" @@ -1841,17 +2781,19 @@ msgid_plural "" "\n" "%s\n" msgstr[0] "" -"Cảnh báo: bạn đã rá»i bở %d lần chuyển giao (commit) lại đằng sau, không được kết nối đến\n" +"Cảnh báo: bạn đã rá»i bá» %d lần chuyển giao (commit) lại đằng sau, không được " +"kết nối đến\n" "bất kỳ nhánh nà o cá»§a bạn:\n" "\n" "%s\n" msgstr[1] "" -"Cảnh báo: bạn đã rá»i bở %d lần chuyển giao (commit) lại đằng sau, không được kết nối đến\n" +"Cảnh báo: bạn đã rá»i bá» %d lần chuyển giao (commit) lại đằng sau, không được " +"kết nối đến\n" "bất kỳ nhánh nà o cá»§a bạn:\n" "\n" "%s\n" -#: builtin/checkout.c:664 +#: builtin/checkout.c:700 #, c-format msgid "" "If you want to keep them by creating a new branch, this may be a good time\n" @@ -1860,135 +2802,230 @@ msgid "" " git branch new_branch_name %s\n" "\n" msgstr "" -"Nếu bạn muốn giữ chúng bằng cách tạo ra má»™t nhánh má»›i, đây có lẽ là má»™t thá»i Ä‘iểm thÃch hợp\n" +"Nếu bạn muốn giữ chúng bằng cách tạo ra má»™t nhánh má»›i, đây có lẽ là má»™t thá»i " +"Ä‘iểm thÃch hợp\n" "để là m thế bằng lệnh:\n" "\n" " git branch tên_nhánh_má»›i %s\n" "\n" -#: builtin/checkout.c:694 +#: builtin/checkout.c:730 msgid "internal error in revision walk" msgstr "lá»—i ná»™i bá»™ trong khi di chuyển qua các Ä‘iểm xét lại" -#: builtin/checkout.c:698 +#: builtin/checkout.c:734 msgid "Previous HEAD position was" msgstr "Vị trà kế trước cá»§a HEAD là " -#: builtin/checkout.c:724 +#: builtin/checkout.c:761 builtin/checkout.c:950 msgid "You are on a branch yet to be born" msgstr "Bạn tại nhánh mà nó chưa hỠđược sinh ra" #. case (1) -#: builtin/checkout.c:855 +#: builtin/checkout.c:886 #, c-format msgid "invalid reference: %s" msgstr "tham chiếu sai: %s" #. case (1): want a tree -#: builtin/checkout.c:894 +#: builtin/checkout.c:925 #, c-format msgid "reference is not a tree: %s" -msgstr "tham chiếu không phải là cây:%s" +msgstr "tham chiếu không phải là má»™t cây (tree):%s" -#: builtin/checkout.c:974 -msgid "-B cannot be used with -b" -msgstr "-B không thể được sá» dụng vá»›i -b" +#: builtin/checkout.c:964 +msgid "paths cannot be used with switching branches" +msgstr "các đưá»ng dẫn không thể dùng cùng vá»›i các nhánh chuyển" -#: builtin/checkout.c:983 -msgid "--patch is incompatible with all other options" -msgstr "--patch xung khắc vá»›i tất cả các tùy chá»n khác" +#: builtin/checkout.c:967 builtin/checkout.c:971 +#, c-format +msgid "'%s' cannot be used with switching branches" +msgstr "“%s†không thể được sá» dụng vá»›i các nhánh chuyển" +#: builtin/checkout.c:975 builtin/checkout.c:978 builtin/checkout.c:983 #: builtin/checkout.c:986 -msgid "--detach cannot be used with -b/-B/--orphan" -msgstr "--detach không thể được sá» dụng vá»›i -b/-B/--orphan" +#, c-format +msgid "'%s' cannot be used with '%s'" +msgstr "“%s†không thể được sá» dụng vá»›i “%sâ€" -#: builtin/checkout.c:988 -msgid "--detach cannot be used with -t" -msgstr "--detach không thể được sá» dụng vá»›i tùy chá»n -t" +#: builtin/checkout.c:991 +#, c-format +msgid "Cannot switch branch to a non-commit '%s'" +msgstr "Không thể chuyển nhánh đến má»™t non-commit “%sâ€" -#: builtin/checkout.c:994 -msgid "--track needs a branch name" -msgstr "--track cần tên má»™t nhánh" +#: builtin/checkout.c:1012 builtin/gc.c:177 +msgid "suppress progress reporting" +msgstr "chặn các báo cáo tiến trình hoạt động" -#: builtin/checkout.c:1001 -msgid "Missing branch name; try -b" -msgstr "Thiếu tên nhánh; hãy thá» -b" +#: builtin/checkout.c:1013 builtin/checkout.c:1015 builtin/clone.c:89 +#: builtin/remote.c:169 builtin/remote.c:171 +msgid "branch" +msgstr "nhánh" -#: builtin/checkout.c:1007 -msgid "--orphan and -b|-B are mutually exclusive" -msgstr "Tùy chá»n --orphan và -b|-B loại từ lẫn nhau" +#: builtin/checkout.c:1014 +msgid "create and checkout a new branch" +msgstr "tạo và checkout má»™t nhánh má»›i" -#: builtin/checkout.c:1009 -msgid "--orphan cannot be used with -t" -msgstr "--orphan không thể được sá» dụng vá»›i tùy chá»n -t" +#: builtin/checkout.c:1016 +msgid "create/reset and checkout a branch" +msgstr "create/reset và checkout má»™t nhánh" + +#: builtin/checkout.c:1017 +msgid "create reflog for new branch" +msgstr "tạo reflog cho nhánh má»›i" + +#: builtin/checkout.c:1018 +msgid "detach the HEAD at named commit" +msgstr "rá»i bá» HEAD tại lần chuyển giao danh nghÄ©a" #: builtin/checkout.c:1019 -msgid "git checkout: -f and -m are incompatible" -msgstr "git checkout: -f và -m xung khắc nhau" +msgid "set upstream info for new branch" +msgstr "đặt thông tin thượng nguồn (upstream) cho nhánh má»›i" + +#: builtin/checkout.c:1021 +msgid "new branch" +msgstr "nhánh má»›i" + +#: builtin/checkout.c:1021 +msgid "new unparented branch" +msgstr "nhánh mồ côi má»›i" + +#: builtin/checkout.c:1022 +msgid "checkout our version for unmerged files" +msgstr "" +"lấy ra (checkout) phiên bản cá»§a chúng ta cho các táºp tin chưa được hòa trá»™n" + +#: builtin/checkout.c:1024 +msgid "checkout their version for unmerged files" +msgstr "" +"lấy ra (checkout) phiên bản cá»§a chúng há» cho các táºp tin chưa được hòa trá»™n" + +#: builtin/checkout.c:1026 +msgid "force checkout (throw away local modifications)" +msgstr "ép buá»™c lấy ra (checkout) (bá» Ä‘i những thay đổi ná»™i bá»™)" + +#: builtin/checkout.c:1027 +msgid "perform a 3-way merge with the new branch" +msgstr "thá»±c hiện hòa trá»™n kiểu 3-way vá»›i nhánh má»›i" + +#: builtin/checkout.c:1028 builtin/merge.c:215 +msgid "update ignored files (default)" +msgstr "cáºp nháºt các táºp tin bị bá» qua (mặc định)" + +#: builtin/checkout.c:1029 builtin/log.c:1116 parse-options.h:241 +msgid "style" +msgstr "kiểu" + +#: builtin/checkout.c:1030 +msgid "conflict style (merge or diff3)" +msgstr "xung đột kiểu (hòa trá»™n hay diff3)" + +#: builtin/checkout.c:1033 +msgid "second guess 'git checkout no-such-branch'" +msgstr "gợi ý thứ hai “git checkout không-nhánh-nà o-như-váºyâ€" + +#: builtin/checkout.c:1057 +msgid "-b, -B and --orphan are mutually exclusive" +msgstr "Tùy chá»n -b|-B và --orphan loại từ lẫn nhau" + +#: builtin/checkout.c:1074 +msgid "--track needs a branch name" +msgstr "--track cần tên má»™t nhánh" + +#: builtin/checkout.c:1081 +msgid "Missing branch name; try -b" +msgstr "Thiếu tên nhánh; hãy thá» -b" -#: builtin/checkout.c:1053 +#: builtin/checkout.c:1116 msgid "invalid path specification" msgstr "đưá»ng dẫn đã cho không hợp lệ" -#: builtin/checkout.c:1061 +#: builtin/checkout.c:1123 #, c-format msgid "" -"git checkout: updating paths is incompatible with switching branches.\n" +"Cannot update paths and switch to branch '%s' at the same time.\n" "Did you intend to checkout '%s' which can not be resolved as commit?" msgstr "" -"git checkout: việc cáºp nháºt các đưá»ng dẫn là xung khắc vá»›i việc chuyển đổi các nhánh..\n" -"Bạn đã có ý định checkout '%s' cái mà không thể được phân giải như là lần chuyển giao (commit)?" - -#: builtin/checkout.c:1063 -msgid "git checkout: updating paths is incompatible with switching branches." -msgstr "git checkout: việc cáºp nháºt các đưá»ng dẫn là xung khắc vá»›i việc chuyển đổi các nhánh." +"Không thể cáºp nháºt và chuyển thà nh nhánh “%s†cùng lúc\n" +"Bạn đã có ý định checkout “%s†cái mà không thể được phân giải như là lần " +"chuyển giao (commit)?" -#: builtin/checkout.c:1068 -msgid "git checkout: --detach does not take a path argument" -msgstr "git checkout: --detach không nháºn má»™t đối số đưá»ng dẫn" +#: builtin/checkout.c:1128 +#, c-format +msgid "git checkout: --detach does not take a path argument '%s'" +msgstr "git checkout: --detach không nháºn má»™t đối số đưá»ng dẫn “%sâ€" -#: builtin/checkout.c:1071 +#: builtin/checkout.c:1132 msgid "" "git checkout: --ours/--theirs, --force and --merge are incompatible when\n" "checking out of the index." msgstr "" "git checkout: --ours/--theirs, --force và --merge là xung khắc vá»›i nhau khi\n" -"checkout." +"checkout bảng mục lục (index)." + +#: builtin/clean.c:19 +msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..." +msgstr "git clean [-d] [-f] [-n] [-q] [-e <mẫu>] [-x | -X] [--] <đưá»ng-dẫn>..." + +#: builtin/clean.c:51 +msgid "do not print names of files removed" +msgstr "không hiển thị tên cá»§a các táºp tin đã gỡ bá»" + +#: builtin/clean.c:53 +msgid "force" +msgstr "ép buá»™c" -#: builtin/checkout.c:1090 -msgid "Cannot switch branch to a non-commit." -msgstr "Không thể chuyển đến má»™t non-commit." +#: builtin/clean.c:55 +msgid "remove whole directories" +msgstr "gỡ bá» toà n bá»™ thư mục" -#: builtin/checkout.c:1093 -msgid "--ours/--theirs is incompatible with switching branches." -msgstr "--ours/--theirs là xung khắc nhau khi chuyển đổi các nhánh." +#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:717 +#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:182 +msgid "pattern" +msgstr "mẫu" + +#: builtin/clean.c:57 +msgid "add <pattern> to ignore rules" +msgstr "thêm <mẫu> và o trong qui tắc bá» qua" + +#: builtin/clean.c:58 +msgid "remove ignored files, too" +msgstr "đồng thá»i gỡ bá» cả các táºp tin bị bá» qua" + +#: builtin/clean.c:60 +msgid "remove only ignored files" +msgstr "chỉ gỡ bá» những táºp tin bị bá» qua" #: builtin/clean.c:78 msgid "-x and -X cannot be used together" msgstr "-x và -X không thể dùng cùng má»™t lúc vá»›i nhau" #: builtin/clean.c:82 -msgid "clean.requireForce set to true and neither -n nor -f given; refusing to clean" -msgstr "clean.requireForce được đặt thà nh true và không đưa ra tùy chá»n -n mà cÅ©ng không -f; từ chối lệnh dá»n dẹp (clean)" +msgid "" +"clean.requireForce set to true and neither -n nor -f given; refusing to clean" +msgstr "" +"clean.requireForce được đặt thà nh true và không đưa ra tùy chá»n -n mà cÅ©ng " +"không -f; từ chối lệnh dá»n dẹp (clean)" #: builtin/clean.c:85 -msgid "clean.requireForce defaults to true and neither -n nor -f given; refusing to clean" -msgstr "clean.requireForce mặc định được đặt thà nh true và không đưa ra tùy chá»n -n mà cÅ©ng không -f; từ chối lệnh dá»n dẹp (clean)" +msgid "" +"clean.requireForce defaults to true and neither -n nor -f given; refusing to " +"clean" +msgstr "" +"clean.requireForce mặc định được đặt thà nh true và không đưa ra tùy chá»n -n " +"mà cÅ©ng không -f; từ chối lệnh dá»n dẹp (clean)" -#: builtin/clean.c:155 -#: builtin/clean.c:176 +#: builtin/clean.c:155 builtin/clean.c:176 #, c-format msgid "Would remove %s\n" msgstr "Có thể gỡ bá» %s\n" -#: builtin/clean.c:159 -#: builtin/clean.c:179 +#: builtin/clean.c:159 builtin/clean.c:179 #, c-format msgid "Removing %s\n" msgstr "Äang gỡ bá» %s\n" -#: builtin/clean.c:162 -#: builtin/clean.c:182 +#: builtin/clean.c:162 builtin/clean.c:182 #, c-format msgid "failed to remove %s" msgstr "gặp lá»—i khi gỡ bá» %s" @@ -2003,26 +3040,113 @@ msgstr "Không thể gỡ bá» %s\n" msgid "Not removing %s\n" msgstr "Không xóa %s\n" +#: builtin/clone.c:36 +msgid "git clone [options] [--] <repo> [<dir>]" +msgstr "git clone [các-tùy-chá»n] [--] <kho> [<t.mục>]" + +#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212 +#: builtin/push.c:399 +msgid "force progress reporting" +msgstr "ép buá»™c báo cáo tiến trình" + +#: builtin/clone.c:66 +msgid "don't create a checkout" +msgstr "không tạo má»™t checkout" + +#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488 +msgid "create a bare repository" +msgstr "tạo kho chứa bare" + +#: builtin/clone.c:72 +msgid "create a mirror repository (implies bare)" +msgstr "tạo kho bản sao (mirror) (ngụ ý là bare)" + +#: builtin/clone.c:74 +msgid "to clone from a local repository" +msgstr "để nhân bản từ kho ná»™i bá»™" + +#: builtin/clone.c:76 +msgid "don't use local hardlinks, always copy" +msgstr "không sá» dụng liên kết cứng ná»™i bá»™, luôn sao chép" + +#: builtin/clone.c:78 +msgid "setup as shared repository" +msgstr "cà i đặt đây là kho chia sẻ" + +#: builtin/clone.c:80 builtin/clone.c:82 +msgid "initialize submodules in the clone" +msgstr "khởi tạo mô-Ä‘un-con trong bản sao" + +#: builtin/clone.c:83 builtin/init-db.c:485 +msgid "template-directory" +msgstr "thư-mục-tạm" + +#: builtin/clone.c:84 builtin/init-db.c:486 +msgid "directory from which templates will be used" +msgstr "thư mục mà tại đó các mẫu sẽ được dùng" + +#: builtin/clone.c:86 +msgid "reference repository" +msgstr "kho tham chiếu" + +#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44 +msgid "name" +msgstr "tên" + +#: builtin/clone.c:88 +msgid "use <name> instead of 'origin' to track upstream" +msgstr "dùng <tên> thay vì “origin†để theo dõi thượng nguồn (uptream)" + +#: builtin/clone.c:90 +msgid "checkout <branch> instead of the remote's HEAD" +msgstr "lấy ra nhánh (checkout <nhánh>) thay vì HEAD cá»§a máy chá»§" + +#: builtin/clone.c:92 +msgid "path to git-upload-pack on the remote" +msgstr "đưá»ng dẫn đến git-upload-pack trên máy chá»§" + +#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:662 +msgid "depth" +msgstr "độ sâu" + +#: builtin/clone.c:94 +msgid "create a shallow clone of that depth" +msgstr "tạo bản sao không đầy đủ cho mức sâu đã cho" + +#: builtin/clone.c:96 +msgid "clone only one branch, HEAD or --branch" +msgstr "nhân bản (clone) chỉ má»™t nhánh, HEAD hoặc --branch" + +#: builtin/clone.c:97 builtin/init-db.c:494 +msgid "gitdir" +msgstr "gitdir" + +#: builtin/clone.c:98 builtin/init-db.c:495 +msgid "separate git dir from working tree" +msgstr "không dùng chung thư mục dà nh riêng cho git và thư mục là m việc" + +#: builtin/clone.c:99 +msgid "key=value" +msgstr "khóa=giá trị" + +#: builtin/clone.c:100 +msgid "set config inside the new repository" +msgstr "đặt cấu hình bên trong má»™t kho chứa má»›i" + #: builtin/clone.c:243 #, c-format msgid "reference repository '%s' is not a local directory." -msgstr "kho tham chiếu '%s' không phải là má»™t thư mục ná»™i bá»™." - -#: builtin/clone.c:302 -#, c-format -msgid "failed to open '%s'" -msgstr "gặp lá»—i khi mở '%s'" +msgstr "kho tham chiếu “%s†không phải là má»™t thư mục ná»™i bá»™." #: builtin/clone.c:306 #, c-format msgid "failed to create directory '%s'" msgstr "tạo thư mục \"%s\" gặp lá»—i" -#: builtin/clone.c:308 -#: builtin/diff.c:75 +#: builtin/clone.c:308 builtin/diff.c:77 #, c-format msgid "failed to stat '%s'" -msgstr "gặp lá»—i stat (lấy trạng thái vá») '%s'" +msgstr "gặp lá»—i stat (lấy trạng thái vá») “%sâ€" #: builtin/clone.c:310 #, c-format @@ -2034,107 +3158,137 @@ msgstr "%s tồn tại nhưng không phải là má»™t thư mục" msgid "failed to stat %s\n" msgstr "lá»—i stat (lấy trạng thái vá») %s\n" -#: builtin/clone.c:341 -#, c-format -msgid "failed to unlink '%s'" -msgstr "bá» liên kết (unlink) %s không thà nh công" - #: builtin/clone.c:346 #, c-format msgid "failed to create link '%s'" -msgstr "tạo được liên kết má»m tá»›i %s gặp lá»—i" +msgstr "gặp lá»—i khi tạo được liên kết má»m %s" #: builtin/clone.c:350 #, c-format msgid "failed to copy file to '%s'" -msgstr "sao chép tệp tin tá»›i '%s' gặp lá»—i" +msgstr "gặp lá»—i khi chép táºp tin tá»›i “%sâ€" #: builtin/clone.c:373 #, c-format msgid "done.\n" msgstr "hoà n tất.\n" -#: builtin/clone.c:440 +#: builtin/clone.c:443 #, c-format msgid "Could not find remote branch %s to clone." msgstr "Không tìm thấy nhánh máy chá»§ %s để nhân bản (clone)." -#: builtin/clone.c:549 +#: builtin/clone.c:552 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" msgstr "refers HEAD máy chá»§ chỉ đến ref không tồn tại, không thể checkout.\n" -#: builtin/clone.c:639 +#: builtin/clone.c:690 msgid "Too many arguments." msgstr "Có quá nhiá»u đối số." -#: builtin/clone.c:643 +#: builtin/clone.c:694 msgid "You must specify a repository to clone." msgstr "Bạn phải chỉ định má»™t kho để mà nhân bản (clone)." -#: builtin/clone.c:654 +#: builtin/clone.c:705 #, c-format msgid "--bare and --origin %s options are incompatible." msgstr "tùy chá»n --bare và --origin %s xung khắc nhau." -#: builtin/clone.c:668 +#: builtin/clone.c:719 #, c-format msgid "repository '%s' does not exist" -msgstr "kho chứa '%s' chưa tồn tại" +msgstr "kho chứa “%s†chưa tồn tại" -#: builtin/clone.c:673 +#: builtin/clone.c:724 msgid "--depth is ignored in local clones; use file:// instead." msgstr "--depth bị lá» Ä‘i khi nhân bản ná»™i bá»™; hãy sá» dụng file:// để thay thế." -#: builtin/clone.c:683 +#: builtin/clone.c:734 #, c-format msgid "destination path '%s' already exists and is not an empty directory." -msgstr "đưá»ng dẫn Ä‘Ãch '%s' đã có từ trước và không phải là má»™t thư mục rá»—ng." +msgstr "đưá»ng dẫn Ä‘Ãch “%s†đã có từ trước và không phải là má»™t thư mục rá»—ng." -#: builtin/clone.c:693 +#: builtin/clone.c:744 #, c-format msgid "working tree '%s' already exists." -msgstr "cây là m việc '%s' đã sẵn tồn tại rồi." +msgstr "cây là m việc “%s†đã sẵn tồn tại rồi." -#: builtin/clone.c:706 -#: builtin/clone.c:720 +#: builtin/clone.c:757 builtin/clone.c:771 #, c-format msgid "could not create leading directories of '%s'" -msgstr "không thể tạo các thư mục dẫn đầu cá»§a '%s'" +msgstr "không thể tạo các thư mục dẫn đầu cá»§a “%sâ€" -#: builtin/clone.c:709 +#: builtin/clone.c:760 #, c-format msgid "could not create work tree dir '%s'." -msgstr "không thể tạo cây thư mục là m việc dir '%s'." +msgstr "không thể tạo cây thư mục là m việc dir “%sâ€." -#: builtin/clone.c:728 +#: builtin/clone.c:779 #, c-format msgid "Cloning into bare repository '%s'...\n" -msgstr "Äang nhân bản thà nh kho chứa bare '%s'...\n" +msgstr "Äang nhân bản thà nh kho chứa bare “%sâ€...\n" -#: builtin/clone.c:730 +#: builtin/clone.c:781 #, c-format msgid "Cloning into '%s'...\n" -msgstr "Äang nhân bản thà nh '%s'...\n" +msgstr "Äang nhân bản thà nh “%sâ€...\n" -#: builtin/clone.c:786 +#: builtin/clone.c:823 #, c-format msgid "Don't know how to clone %s" msgstr "Không biết là m cách nà o để nhân bản (clone) %s" -#: builtin/clone.c:835 +#: builtin/clone.c:872 #, c-format msgid "Remote branch %s not found in upstream %s" -msgstr "Nhánh máy chá»§ %s không tìm thấy trong dòng ngược (upstream) %s" +msgstr "Nhánh máy chá»§ %s không tìm thấy trong thượng nguồn (upstream) %s" -#: builtin/clone.c:842 +#: builtin/clone.c:879 msgid "You appear to have cloned an empty repository." msgstr "Bạn hình như là đã nhân bản má»™t kho trống rá»—ng." +#: builtin/column.c:9 +msgid "git column [options]" +msgstr "git column [các-tùy-chá»n]" + +#: builtin/column.c:26 +msgid "lookup config vars" +msgstr "tìm kiếm biến cấu hình" + +#: builtin/column.c:27 builtin/column.c:28 +msgid "layout to use" +msgstr "bố cục để dùng" + +#: builtin/column.c:29 +msgid "Maximum width" +msgstr "Äá»™ rá»™ng tối Ä‘a" + +#: builtin/column.c:30 +msgid "Padding space on left border" +msgstr "Chèn thêm khoảng trống và o bá» bên trái" + +#: builtin/column.c:31 +msgid "Padding space on right border" +msgstr "Chèn thêm khoảng trắng và o tiếp giáp bên phải" + +#: builtin/column.c:32 +msgid "Padding space between columns" +msgstr "Chèn thêm khoảng trắng giữa các cá»™t" + #: builtin/column.c:51 msgid "--command must be the first argument" msgstr "--command phải là đối số đầu tiên" -#: builtin/commit.c:43 +#: builtin/commit.c:34 +msgid "git commit [options] [--] <filepattern>..." +msgstr "git commit [các-tùy-chá»n] [--] <mẫu-táºp-tin>..." + +#: builtin/commit.c:39 +msgid "git status [options] [--] <filepattern>..." +msgstr "git status [các-tùy-chá»n] [--] <mẫu-táºp-tin>..." + +#: builtin/commit.c:44 msgid "" "Your name and email address were configured automatically based\n" "on your username and hostname. Please check that they are accurate.\n" @@ -2147,29 +3301,35 @@ msgid "" "\n" " git commit --amend --reset-author\n" msgstr "" -"Tên và địa chỉ thư Ä‘iện tá» cá»§a bạn được cấu hình má»™t cách tá»± động trên cÆ¡ sở\n" -"tà i khoản và địa chỉ máy chá»§ cá»§a bạn. Xin hãy kiểm tra xem chúng có chÃnh xác không.\n" -"Bạn có thể chặn những thông báo kiểu nà y bằng cách cà i đặt các thông tin trên má»™t cách rõ rà ng:\n" +"Tên và địa chỉ thư Ä‘iện tá» cá»§a bạn được cấu hình má»™t cách tá»± động trên cÆ¡ " +"sở\n" +"tà i khoản và địa chỉ máy chá»§ cá»§a bạn. Xin hãy kiểm tra xem chúng có chÃnh " +"xác không.\n" +"Bạn có thể chặn những thông báo kiểu nà y bằng cách cà i đặt các thông tin " +"trên má»™t cách rõ rà ng:\n" "\n" " git config --global user.name \"Tên cá»§a bạn\"\n" " git config --global user.email you@example.com\n" "\n" -"Sau khi thá»±c hiện xong, bạn có thể sá»a chữa định danh được sá» dụng cho lần chuyển giao (commit) nà y vá»›i lệnh:\n" +"Sau khi thá»±c hiện xong, bạn có thể sá»a chữa định danh được sá» dụng cho lần " +"chuyển giao (commit) nà y vá»›i lệnh:\n" "\n" " git commit --amend --reset-author\n" -#: builtin/commit.c:55 +#: builtin/commit.c:56 msgid "" "You asked to amend the most recent commit, but doing so would make\n" "it empty. You can repeat your command with --allow-empty, or you can\n" "remove the commit entirely with \"git reset HEAD^\".\n" msgstr "" -"Bạn đã yêu cầu amend (tu bổ) phần lá»›n các lần chuyển giao (commit) gần đây, nhưng là m như thế\n" -"có thể là m cho nó trở nên trống rá»—ng. Bạn có thể lặp lại lệnh cá»§a mình bằng --allow-empty,\n" +"Bạn đã yêu cầu amend (tu bổ) phần lá»›n các lần chuyển giao (commit) gần đây, " +"nhưng là m như thế\n" +"có thể là m cho nó trở nên trống rá»—ng. Bạn có thể lặp lại lệnh cá»§a mình bằng " +"--allow-empty,\n" "hoặc là bạn gỡ bá» các lần chuyển giao má»™t cách hoà n toà n bằng lệnh:\n" "\"git reset HEAD^\".\n" -#: builtin/commit.c:60 +#: builtin/commit.c:61 msgid "" "The previous cherry-pick is now empty, possibly due to conflict resolution.\n" "If you wish to commit it anyway, use:\n" @@ -2178,106 +3338,105 @@ msgid "" "\n" "Otherwise, please use 'git reset'\n" msgstr "" -"Lần cherry-pick trước hiện nay trống rá»—ng, có lẽ là bởi vì sá»± phân giải xung đột.\n" +"Lần cherry-pick trước hiện nay trống rá»—ng, có lẽ là bởi vì sá»± phân giải xung " +"đột.\n" "Nếu bạn muốn chuyển giao nó cho dù thế nà o Ä‘i nữa, sá» dụng:\n" "\n" " git commit --allow-empty\n" "\n" -"Nếu không, hãy thá» sá» dụng 'git reset'\n" +"Nếu không, hãy thá» dùng “git resetâ€\n" -#: builtin/commit.c:253 +#: builtin/commit.c:258 msgid "failed to unpack HEAD tree object" msgstr "gặp lá»—i khi tháo dỡ HEAD đối tượng cây" -#: builtin/commit.c:295 +#: builtin/commit.c:300 msgid "unable to create temporary index" msgstr "không thể tạo bảng mục lục tạm thá»i" -#: builtin/commit.c:301 +#: builtin/commit.c:306 msgid "interactive add failed" msgstr "việc thêm tương tác gặp lá»—i" -#: builtin/commit.c:334 -#: builtin/commit.c:355 -#: builtin/commit.c:405 +#: builtin/commit.c:339 builtin/commit.c:360 builtin/commit.c:410 msgid "unable to write new_index file" msgstr "không thể ghi táºp tin lưu bảng mục lục má»›i (new_index)" -#: builtin/commit.c:386 +#: builtin/commit.c:391 msgid "cannot do a partial commit during a merge." -msgstr "không thể thá»±c hiện việc chuyển giao (commit) cục bá»™ trong khi Ä‘ang được hòa trá»™n." +msgstr "" +"không thể thá»±c hiện việc chuyển giao (commit) cục bá»™ trong khi Ä‘ang được hòa " +"trá»™n." -#: builtin/commit.c:388 +#: builtin/commit.c:393 msgid "cannot do a partial commit during a cherry-pick." -msgstr "không thể thá»±c hiện việc chuyển giao (commit) bá»™ pháºn trong khi Ä‘ang cherry-pick." +msgstr "" +"không thể thá»±c hiện việc chuyển giao (commit) bá»™ pháºn trong khi Ä‘ang cherry-" +"pick." -#: builtin/commit.c:398 +#: builtin/commit.c:403 msgid "cannot read the index" msgstr "không Ä‘á»c được bảng mục lục" -#: builtin/commit.c:418 +#: builtin/commit.c:423 msgid "unable to write temporary index file" msgstr "không thể ghi táºp tin lưu bảng mục lục tạm thá»i" -#: builtin/commit.c:493 -#: builtin/commit.c:499 +#: builtin/commit.c:511 builtin/commit.c:517 #, c-format msgid "invalid commit: %s" msgstr "lần chuyển giao (commit) không hợp lệ: %s" -#: builtin/commit.c:522 +#: builtin/commit.c:540 msgid "malformed --author parameter" msgstr "đối số --author bị dị hình" -#: builtin/commit.c:582 +#: builtin/commit.c:560 #, c-format msgid "Malformed ident string: '%s'" -msgstr "Chuá»—i thụt lỠđầu dòng dị hình: '%s'" +msgstr "Chuá»—i thụt lỠđầu dòng dị hình: “%sâ€" -#: builtin/commit.c:620 -#: builtin/commit.c:653 -#: builtin/commit.c:967 +#: builtin/commit.c:598 builtin/commit.c:631 builtin/commit.c:954 #, c-format msgid "could not lookup commit %s" msgstr "không thể tìm kiếm commit (lần chuyển giao) %s" -#: builtin/commit.c:632 -#: builtin/shortlog.c:296 +#: builtin/commit.c:610 builtin/shortlog.c:296 #, c-format msgid "(reading log message from standard input)\n" msgstr "(Ä‘ang Ä‘á»c thông Ä‘iệp nháºt ký từ đầu và o tiêu chuẩn)\n" -#: builtin/commit.c:634 +#: builtin/commit.c:612 msgid "could not read log from standard input" msgstr "không thể Ä‘á»c nháºt ký từ đầu và o tiêu chuẩn" -#: builtin/commit.c:638 +#: builtin/commit.c:616 #, c-format msgid "could not read log file '%s'" -msgstr "không Ä‘á»c được tệp nháºt ký '%s'" +msgstr "không Ä‘á»c được tệp nháºt ký “%sâ€" -#: builtin/commit.c:644 +#: builtin/commit.c:622 msgid "commit has empty message" msgstr "lần chuyển giao (commit) có ghi chú trống rá»—ng" -#: builtin/commit.c:660 +#: builtin/commit.c:638 msgid "could not read MERGE_MSG" msgstr "không thể Ä‘á»c MERGE_MSG" -#: builtin/commit.c:664 +#: builtin/commit.c:642 msgid "could not read SQUASH_MSG" msgstr "không thể Ä‘á»c SQUASH_MSG" -#: builtin/commit.c:668 +#: builtin/commit.c:646 #, c-format msgid "could not read '%s'" -msgstr "Không thể Ä‘á»c '%s'." +msgstr "Không thể Ä‘á»c “%sâ€." -#: builtin/commit.c:720 +#: builtin/commit.c:707 msgid "could not write commit template" msgstr "không thể ghi mẫu commit" -#: builtin/commit.c:731 +#: builtin/commit.c:718 #, c-format msgid "" "\n" @@ -2292,7 +3451,7 @@ msgstr "" "\t%s\n" "và thá» lại.\n" -#: builtin/commit.c:736 +#: builtin/commit.c:723 #, c-format msgid "" "\n" @@ -2307,182 +3466,393 @@ msgstr "" "\t%s\n" "và thá» lại.\n" -#: builtin/commit.c:748 +#: builtin/commit.c:735 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be ignored, and an empty message aborts the commit.\n" msgstr "" -"Hãy nháºp và o các thông tin để giải thÃch các thay đổi cá»§a bạn. Những dòng được\n" -"bắt đầu bằng '#' sẽ được bá» qua, phần chú thÃch nà y nếu rá»—ng sẽ là m há»§y bá» lần chuyển giao (commit).\n" +"Hãy nháºp và o các thông tin để giải thÃch các thay đổi cá»§a bạn. Những dòng " +"được\n" +"bắt đầu bằng “#†sẽ được bá» qua, phần chú thÃch nà y nếu rá»—ng sẽ là m há»§y bá» " +"lần chuyển giao (commit).\n" -#: builtin/commit.c:753 +#: builtin/commit.c:740 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be kept; you may remove them yourself if you want to.\n" "An empty message aborts the commit.\n" msgstr "" -"Hãy nháºp và o các thông tin để giải thÃch các thay đổi cá»§a bạn.Những dòng được\n" -"bắt đầu bằng '#' sẽ được bá» qua; bạn có thể xóa chúng Ä‘i nếu muốn.\n" +"Hãy nháºp và o các thông tin để giải thÃch các thay đổi cá»§a bạn.Những dòng " +"được\n" +"bắt đầu bằng “#†sẽ được bá» qua; bạn có thể xóa chúng Ä‘i nếu muốn.\n" "Phần chú thÃch nà y nếu rá»—ng sẽ là m há»§y bá» lần chuyển giao (commit).\n" -#: builtin/commit.c:766 +#: builtin/commit.c:753 #, c-format msgid "%sAuthor: %s" msgstr "%sTác giả: %s" -#: builtin/commit.c:773 +#: builtin/commit.c:760 #, c-format msgid "%sCommitter: %s" msgstr "%sNgưá»i chuyển giao (commit): %s" -#: builtin/commit.c:793 +#: builtin/commit.c:780 msgid "Cannot read index" msgstr "không Ä‘á»c được bảng mục lục" -#: builtin/commit.c:830 +#: builtin/commit.c:817 msgid "Error building trees" msgstr "Gặp lá»—i khi xây dá»±ng cây" -#: builtin/commit.c:845 -#: builtin/tag.c:361 +#: builtin/commit.c:832 builtin/tag.c:361 #, c-format msgid "Please supply the message using either -m or -F option.\n" msgstr "Xin hãy áp dụng thông Ä‘iệp sá» dụng hoặc là tùy chá»n -m hoặc là -F.\n" -#: builtin/commit.c:942 +#: builtin/commit.c:929 #, c-format msgid "No existing author found with '%s'" -msgstr "Không tìm thấy tác giả đã sẵn có vá»›i '%s'" +msgstr "Không tìm thấy tác giả có sẵn vá»›i “%sâ€" -#: builtin/commit.c:957 -#: builtin/commit.c:1157 +#: builtin/commit.c:944 builtin/commit.c:1148 #, c-format msgid "Invalid untracked files mode '%s'" -msgstr "Chế độ cho các táºp tin không bị theo vết không hợp lệ '%s'" +msgstr "Chế độ cho các táºp tin không bị theo vết không hợp lệ “%sâ€" -#: builtin/commit.c:997 +#: builtin/commit.c:984 msgid "Using both --reset-author and --author does not make sense" msgstr "Sá» dụng cả hai tùy chá»n --reset-author và --author không hợp lý" -#: builtin/commit.c:1008 +#: builtin/commit.c:995 msgid "You have nothing to amend." msgstr "Không có gì để amend (tu bổ) cả." -#: builtin/commit.c:1011 +#: builtin/commit.c:998 msgid "You are in the middle of a merge -- cannot amend." -msgstr "Bạn Ä‘ang ở giữa cá»§a quá trình hòa trá»™n -- không thể thá»±c hiện amend (tu bổ)." +msgstr "" +"Bạn Ä‘ang ở giữa cá»§a quá trình hòa trá»™n -- không thể thá»±c hiện amend (tu bổ)." -#: builtin/commit.c:1013 +#: builtin/commit.c:1000 msgid "You are in the middle of a cherry-pick -- cannot amend." -msgstr "Bạn Ä‘ang ở giữa cá»§a quá trình cherry-pick -- không thể thá»±c hiện amend (tu bổ)." +msgstr "" +"Bạn Ä‘ang ở giữa cá»§a quá trình cherry-pick -- không thể thá»±c hiện amend (tu " +"bổ)." -#: builtin/commit.c:1016 +#: builtin/commit.c:1003 msgid "Options --squash and --fixup cannot be used together" msgstr "Các tùy chá»n --squash và --fixup không thể sá» dụng cùng vá»›i nhau" -#: builtin/commit.c:1026 +#: builtin/commit.c:1013 msgid "Only one of -c/-C/-F/--fixup can be used." msgstr "Chỉ má»™t tùy chá»n trong số -c/-C/-F/--fixup được sá» dụng" -#: builtin/commit.c:1028 +#: builtin/commit.c:1015 msgid "Option -m cannot be combined with -c/-C/-F/--fixup." msgstr "Tùy chá»n -m không thể được tổ hợp cùng vá»›i -c/-C/-F/--fixup." -#: builtin/commit.c:1036 +#: builtin/commit.c:1023 msgid "--reset-author can be used only with -C, -c or --amend." -msgstr "--reset-author chỉ có thể được sá» dụng vá»›i tùy chá»n -C, -c hay --amend." +msgstr "" +"--reset-author chỉ có thể được sá» dụng vá»›i tùy chá»n -C, -c hay --amend." -#: builtin/commit.c:1053 +#: builtin/commit.c:1040 msgid "Only one of --include/--only/--all/--interactive/--patch can be used." -msgstr "Chỉ má»™t trong các tùy chá»n --include/--only/--all/--interactive/--patch được sá» dụng." +msgstr "" +"Chỉ má»™t trong các tùy chá»n --include/--only/--all/--interactive/--patch được " +"sá» dụng." -#: builtin/commit.c:1055 +#: builtin/commit.c:1042 msgid "No paths with --include/--only does not make sense." msgstr "Không đưá»ng dẫn vá»›i các tùy chá»n --include/--only không hợp lý." -#: builtin/commit.c:1057 +#: builtin/commit.c:1044 msgid "Clever... amending the last one with dirty index." -msgstr "Giá»i... Ä‘ang tu bổ cái cuối vá»›i bảng mục lục phi nghÄ©a." +msgstr "Giá»i... tu bổ cái cuối vá»›i bảng mục lục phi nghÄ©a." -#: builtin/commit.c:1059 +#: builtin/commit.c:1046 msgid "Explicit paths specified without -i nor -o; assuming --only paths..." -msgstr "Những đưá»ng dẫn rõ rà ng được chỉ ra không có tùy chá»n -i cÅ©ng không -o; Ä‘ang giả định --only những-đưá»ng-dẫn..." +msgstr "" +"Những đưá»ng dẫn rõ rà ng được chỉ ra không có tùy chá»n -i cÅ©ng không -o; Ä‘ang " +"giả định --only những-đưá»ng-dẫn..." -#: builtin/commit.c:1069 -#: builtin/tag.c:577 +#: builtin/commit.c:1056 builtin/tag.c:577 #, c-format msgid "Invalid cleanup mode %s" msgstr "Chế độ dá»n dẹp không hợp lệ %s" -#: builtin/commit.c:1074 +#: builtin/commit.c:1061 msgid "Paths with -a does not make sense." msgstr "Các đưá»ng dẫn vá»›i tùy chá»n -a không hợp lý." -#: builtin/commit.c:1257 +#: builtin/commit.c:1067 builtin/commit.c:1202 +msgid "--long and -z are incompatible" +msgstr "hai tùy chá»n -long và -z không tương thÃch vá»›i nhau" + +#: builtin/commit.c:1162 builtin/commit.c:1398 +msgid "show status concisely" +msgstr "hiển thị trạng thái ở dạng súc tÃch" + +#: builtin/commit.c:1164 builtin/commit.c:1400 +msgid "show branch information" +msgstr "hiển thị thông tin nhánh" + +#: builtin/commit.c:1166 builtin/commit.c:1402 builtin/push.c:389 +msgid "machine-readable output" +msgstr "kết xuất dạng máy-có-thể-Ä‘á»c" + +#: builtin/commit.c:1169 builtin/commit.c:1404 +msgid "show status in long format (default)" +msgstr "hiển thị trạng thái ở định dạng dà i (mặc định)" + +#: builtin/commit.c:1172 builtin/commit.c:1407 +msgid "terminate entries with NUL" +msgstr "chấm dứt các mục bằng NUL" + +#: builtin/commit.c:1174 builtin/commit.c:1410 builtin/fast-export.c:636 +#: builtin/fast-export.c:639 builtin/tag.c:461 +msgid "mode" +msgstr "chế độ" + +#: builtin/commit.c:1175 builtin/commit.c:1410 +msgid "show untracked files, optional modes: all, normal, no. (Default: all)" +msgstr "" +"hiển thị các táºp tin chưa được theo dõi dấu vết, các chế độ tùy chá»n: all, " +"normal, no. (Mặc định: all)" + +#: builtin/commit.c:1178 +msgid "show ignored files" +msgstr "hiển thị các táºp tin ẩn" + +#: builtin/commit.c:1179 parse-options.h:151 +msgid "when" +msgstr "khi" + +#: builtin/commit.c:1180 +msgid "" +"ignore changes to submodules, optional when: all, dirty, untracked. " +"(Default: all)" +msgstr "" +"bá» qua các thay đổi trong mô-Ä‘un con, tùy chá»n khi: all, dirty, untracked. " +"(Mặc định: all)" + +#: builtin/commit.c:1182 +msgid "list untracked files in columns" +msgstr "hiển thị danh sách các táºp-tin chưa được theo dõi trong các cá»™t" + +#: builtin/commit.c:1256 msgid "couldn't look up newly created commit" msgstr "không thể tìm thấy lần chuyển giao (commit) má»›i hÆ¡n đã được tạo" -#: builtin/commit.c:1259 +#: builtin/commit.c:1258 msgid "could not parse newly created commit" -msgstr "không thể phân tÃch cú pháp cá»§a đối tượng chuyển giao má»›i hÆ¡n đã được tạo" +msgstr "" +"không thể phân tÃch cú pháp cá»§a đối tượng chuyển giao má»›i hÆ¡n đã được tạo" -#: builtin/commit.c:1300 +#: builtin/commit.c:1299 msgid "detached HEAD" msgstr "đã rá»i khá»i HEAD" -#: builtin/commit.c:1302 +#: builtin/commit.c:1301 msgid " (root-commit)" msgstr " (root-commit)" -#: builtin/commit.c:1446 +#: builtin/commit.c:1368 +msgid "suppress summary after successful commit" +msgstr "không hiển thị tổng kết sau khi chuyển giao thà nh công" + +#: builtin/commit.c:1369 +msgid "show diff in commit message template" +msgstr "hiển thị sá»± khác biệt trong mẫu tin nhắn chuyển giao" + +#: builtin/commit.c:1371 +msgid "Commit message options" +msgstr "Các tùy chá»n ghi chú commit" + +#: builtin/commit.c:1372 builtin/tag.c:459 +msgid "read message from file" +msgstr "Ä‘á»c chú thÃch từ táºp tin" + +#: builtin/commit.c:1373 +msgid "author" +msgstr "tác giả" + +#: builtin/commit.c:1373 +msgid "override author for commit" +msgstr "ghi đè tác giả cho commit" + +#: builtin/commit.c:1374 builtin/gc.c:178 +msgid "date" +msgstr "ngà y tháng" + +#: builtin/commit.c:1374 +msgid "override date for commit" +msgstr "ghi đè ngà y tháng cho commit" + +#: builtin/commit.c:1375 builtin/merge.c:206 builtin/notes.c:537 +#: builtin/notes.c:694 builtin/tag.c:457 +msgid "message" +msgstr "thông Ä‘iệp" + +#: builtin/commit.c:1375 +msgid "commit message" +msgstr "chú thÃch cá»§a lần commit" + +#: builtin/commit.c:1376 +msgid "reuse and edit message from specified commit" +msgstr "" +"dùng lại các ghi chú từ lần chuyển giao (commit) đã cho nhưng có cho sá»a chữa" + +#: builtin/commit.c:1377 +msgid "reuse message from specified commit" +msgstr "dùng lại các ghi chú từ lần chuyển giao (commit) đã cho" + +#: builtin/commit.c:1378 +msgid "use autosquash formatted message to fixup specified commit" +msgstr "" +"dùng ghi chú có định dạng autosquash để sá»a chữa lần chuyển giao đã chỉ ra" + +#: builtin/commit.c:1379 +msgid "use autosquash formatted message to squash specified commit" +msgstr "" +"dùng lá»i nhắn có định dạng tá»± động nén để nén lại các lần chuyển giao đã chỉ " +"ra" + +#: builtin/commit.c:1380 +msgid "the commit is authored by me now (used with -C/-c/--amend)" +msgstr "" +"lần chuyển giao nháºn tôi là tác giả (được dùng vá»›i tùy chá»n -C/-c/--amend)" + +#: builtin/commit.c:1381 builtin/log.c:1073 builtin/revert.c:109 +msgid "add Signed-off-by:" +msgstr "thêm dòng Signed-off-by:" + +#: builtin/commit.c:1382 +msgid "use specified template file" +msgstr "sá» dụng táºp tin mẫu đã cho" + +#: builtin/commit.c:1383 +msgid "force edit of commit" +msgstr "ép buá»™c sá»a lần commit" + +#: builtin/commit.c:1384 +msgid "default" +msgstr "mặc định" + +#: builtin/commit.c:1384 builtin/tag.c:462 +msgid "how to strip spaces and #comments from message" +msgstr "là m thế nà o để cắt bá» khoảng trắng và #ghichú từ mẩu tin nhắn" + +#: builtin/commit.c:1385 +msgid "include status in commit message template" +msgstr "bao gồm các trạng thái ghi mẫu ghi chú chuyển giao (commit)" + +#: builtin/commit.c:1386 builtin/merge.c:213 builtin/tag.c:463 +msgid "key id" +msgstr "id khóa" + +#: builtin/commit.c:1387 builtin/merge.c:214 +msgid "GPG sign commit" +msgstr "ký lần commit dùng GPG" + +#. end commit message options +#: builtin/commit.c:1390 +msgid "Commit contents options" +msgstr "Các tùy ná»™i dung ghi chú commit" + +#: builtin/commit.c:1391 +msgid "commit all changed files" +msgstr "chuyển giao tất cả các táºp tin có thay đổi" + +#: builtin/commit.c:1392 +msgid "add specified files to index for commit" +msgstr "thêm các táºp tin đã chỉ ra và o bảng mục lục để chuyển giao (commit)" + +#: builtin/commit.c:1393 +msgid "interactively add files" +msgstr "thêm các táºp-tin bằng tương tác" + +#: builtin/commit.c:1394 +msgid "interactively add changes" +msgstr "thêm các thay đổi bằng tương tác" + +#: builtin/commit.c:1395 +msgid "commit only specified files" +msgstr "chỉ chuyển giao các táºp tin đã chỉ ra" + +#: builtin/commit.c:1396 +msgid "bypass pre-commit hook" +msgstr "vòng qua móc (hook) pre-commit" + +#: builtin/commit.c:1397 +msgid "show what would be committed" +msgstr "hiển thị xem cái gì có thể được chuyển giao" + +#: builtin/commit.c:1408 +msgid "amend previous commit" +msgstr "tu bổ (amend) lần commit trước" + +#: builtin/commit.c:1409 +msgid "bypass post-rewrite hook" +msgstr "vòng qua móc (hook) post-rewrite" + +#: builtin/commit.c:1414 +msgid "ok to record an empty change" +msgstr "ok để ghi lại má»™t thay đổi trống rá»—ng" + +#: builtin/commit.c:1417 +msgid "ok to record a change with an empty message" +msgstr "ok để ghi các thay đổi vá»›i lá»i nhắn trống rá»—ng" + +#: builtin/commit.c:1449 msgid "could not parse HEAD commit" msgstr "không thể phân tÃch commit (lần chuyển giao) HEAD" -#: builtin/commit.c:1484 -#: builtin/merge.c:509 +#: builtin/commit.c:1487 builtin/merge.c:508 #, c-format msgid "could not open '%s' for reading" -msgstr "không thể mở %s' để Ä‘á»c" +msgstr "không thể mở “%s†để Ä‘á»c" -#: builtin/commit.c:1491 +#: builtin/commit.c:1494 #, c-format msgid "Corrupt MERGE_HEAD file (%s)" msgstr "Táºp tin MERGE_HEAD sai há»ng (%s)" -#: builtin/commit.c:1498 +#: builtin/commit.c:1501 msgid "could not read MERGE_MODE" msgstr "không thể Ä‘á»c MERGE_MODE" -#: builtin/commit.c:1517 +#: builtin/commit.c:1520 #, c-format msgid "could not read commit message: %s" msgstr "không thể Ä‘á»c thông Ä‘iệp (message) commit (lần chuyển giao): %s" -#: builtin/commit.c:1531 +#: builtin/commit.c:1534 #, c-format msgid "Aborting commit; you did not edit the message.\n" -msgstr "Äang bá» qua việc chuyển giao (commit); bạn đã không biên soạn thông Ä‘iệp (message).\n" +msgstr "" +"Äang bá» qua việc chuyển giao (commit); bạn đã không biên soạn thông Ä‘iệp " +"(message).\n" -#: builtin/commit.c:1536 +#: builtin/commit.c:1539 #, c-format msgid "Aborting commit due to empty commit message.\n" -msgstr "Äang bá» qua lần chuyển giao (commit) bởi vì thông Ä‘iệp cá»§a nó trống rá»—ng.\n" +msgstr "" +"Äang bá» qua lần chuyển giao (commit) bởi vì thông Ä‘iệp cá»§a nó trống rá»—ng.\n" -#: builtin/commit.c:1551 -#: builtin/merge.c:936 -#: builtin/merge.c:961 +#: builtin/commit.c:1554 builtin/merge.c:832 builtin/merge.c:857 msgid "failed to write commit object" msgstr "gặp lá»—i khi ghi đối tượng chuyển giao (commit)" -#: builtin/commit.c:1572 +#: builtin/commit.c:1575 msgid "cannot lock HEAD ref" msgstr "không thể khóa HEAD ref (tham chiếu)" -#: builtin/commit.c:1576 +#: builtin/commit.c:1579 msgid "cannot update HEAD ref" -msgstr "không thể cáºp nháºt HEAD ref (tham chiếu)" +msgstr "không thể cáºp nháºt ref (tham chiếu) HEAD" -#: builtin/commit.c:1587 +#: builtin/commit.c:1590 msgid "" "Repository has been updated, but unable to write\n" "new_index file. Check that disk is not full or quota is\n" @@ -2490,7 +3860,136 @@ msgid "" msgstr "" "Kho chứa đã hoà n tất việc cáºp nháºt, nhưng không thể ghi và o\n" "táºp tin new_index (bảng mục lục má»›i). Hãy kiểm tra xem đĩa có bị đầy quá\n" -"hay quota (hạn nghạch đĩa cứng) bị vượt quá, và sau đó \"git reset HEAD\" để khắc phục." +"hay quota (hạn nghạch đĩa cứng) bị vượt quá, và sau đó \"git reset HEAD\" để " +"khắc phục." + +#: builtin/config.c:7 +msgid "git config [options]" +msgstr "git config [các-tùy-chá»n]" + +#: builtin/config.c:51 +msgid "Config file location" +msgstr "Vị trà táºp tin cấu hình" + +#: builtin/config.c:52 +msgid "use global config file" +msgstr "đặt táºp tin cấu hình cần toà n cục" + +#: builtin/config.c:53 +msgid "use system config file" +msgstr "sá» dụng táºp tin cấu hình hệ thống" + +#: builtin/config.c:54 +msgid "use repository config file" +msgstr "dùng táºp tin cấu hình cá»§a kho" + +#: builtin/config.c:55 +msgid "use given config file" +msgstr "sá» dụng táºp tin cấu hình đã cho" + +#: builtin/config.c:56 +msgid "Action" +msgstr "Hà nh động" + +#: builtin/config.c:57 +msgid "get value: name [value-regex]" +msgstr "lấy giá-trị: tên [value-regex]" + +#: builtin/config.c:58 +msgid "get all values: key [value-regex]" +msgstr "lấy tất cả giá-trị: khóa [value-regex]" + +#: builtin/config.c:59 +msgid "get values for regexp: name-regex [value-regex]" +msgstr "lấy giá trị cho regexp: name-regex [value-regex]" + +#: builtin/config.c:60 +msgid "replace all matching variables: name value [value_regex]" +msgstr "thay thế tất cả các biến khá»›p mẫu: tên giá-trị [value_regex]" + +#: builtin/config.c:61 +msgid "add a new variable: name value" +msgstr "thêm biến má»›i: tên giá-trị" + +#: builtin/config.c:62 +msgid "remove a variable: name [value-regex]" +msgstr "gỡ bá» biến: tên [value-regex]" + +#: builtin/config.c:63 +msgid "remove all matches: name [value-regex]" +msgstr "gỡ bá» má»i cái khá»›p: tên [value-regex]" + +#: builtin/config.c:64 +msgid "rename section: old-name new-name" +msgstr "đổi tên chương: tên-cÅ© tên-má»›i" + +#: builtin/config.c:65 +msgid "remove a section: name" +msgstr "gỡ bá» chương: tên" + +#: builtin/config.c:66 +msgid "list all" +msgstr "liệt kê tất" + +#: builtin/config.c:67 +msgid "open an editor" +msgstr "mở má»™t trình biên soạn" + +#: builtin/config.c:68 builtin/config.c:69 +msgid "slot" +msgstr "khe" + +#: builtin/config.c:68 +msgid "find the color configured: [default]" +msgstr "tìm cấu hình mà u sắc: [mặc định]" + +#: builtin/config.c:69 +msgid "find the color setting: [stdout-is-tty]" +msgstr "tìm các cà i đặt vá» mà u sắc: [stdout-là -tty]" + +#: builtin/config.c:70 +msgid "Type" +msgstr "Kiểu" + +#: builtin/config.c:71 +msgid "value is \"true\" or \"false\"" +msgstr "giá trị là \"true\" hoặc \"false\"" + +#: builtin/config.c:72 +msgid "value is decimal number" +msgstr "giá trị ở dạng số tháºp phân" + +#: builtin/config.c:73 +msgid "value is --bool or --int" +msgstr "giá trị là --bool hoặc --int" + +#: builtin/config.c:74 +msgid "value is a path (file or directory name)" +msgstr "giá trị là đưá»ng dẫn (tên táºp tin hay thư mục)" + +#: builtin/config.c:75 +msgid "Other" +msgstr "Khác" + +#: builtin/config.c:76 +msgid "terminate values with NUL byte" +msgstr "chấm dứt giá trị vá»›i byte NUL" + +#: builtin/config.c:77 +msgid "respect include directives on lookup" +msgstr "tôn trá»ng kể cà các hướng trong tìm kiếm" + +#: builtin/count-objects.c:69 +msgid "git count-objects [-v]" +msgstr "git count-objects [-v]" + +#: builtin/describe.c:15 +msgid "git describe [options] <committish>*" +msgstr "git describe [các-tùy-chá»n] <committish>*" + +#: builtin/describe.c:16 +msgid "git describe [options] --dirty" +msgstr "git describe [các-tùy-chá»n] --dirty" #: builtin/describe.c:234 #, c-format @@ -2505,7 +4004,7 @@ msgstr "thẻ được chú giải %s không có tên nhúng" #: builtin/describe.c:240 #, c-format msgid "tag '%s' is really '%s' here" -msgstr "thẻ '%s' đã thá»±c sá»± ở đây '%s' rồi" +msgstr "thẻ “%s†đã thá»±c sá»± ở đây “%s†rồi" #: builtin/describe.c:267 #, c-format @@ -2515,12 +4014,12 @@ msgstr "Không phải tên đối tượng %s hợp lệ" #: builtin/describe.c:270 #, c-format msgid "%s is not a valid '%s' object" -msgstr "%s không phải là má»™t đối tượng '%s' hợp lệ" +msgstr "%s không phải là má»™t đối tượng “%s†hợp lệ" #: builtin/describe.c:287 #, c-format msgid "no tag exactly matches '%s'" -msgstr "không có thẻ nà o khá»›p chÃnh xác vá»›i '%s'" +msgstr "không có thẻ nà o khá»›p chÃnh xác vá»›i “%sâ€" #: builtin/describe.c:289 #, c-format @@ -2538,7 +4037,7 @@ msgid "" "No annotated tags can describe '%s'.\n" "However, there were unannotated tags: try --tags." msgstr "" -"Không có thẻ được chú giải nà o được mô tả là '%s'.\n" +"Không có thẻ được chú giải nà o được mô tả là “%sâ€.\n" "Tuy nhiên, ở đây có những thẻ không được chú giải: hãy thá» --tags." #: builtin/describe.c:357 @@ -2547,7 +4046,7 @@ msgid "" "No tags can describe '%s'.\n" "Try --always, or create some tags." msgstr "" -"Không có thẻ (tag) có thể mô tả '%s'.\n" +"Không có thẻ (tag) có thể mô tả “%sâ€.\n" "Hãy thá» --always, hoặt tạo má»™t số thẻ." #: builtin/describe.c:378 @@ -2564,6 +4063,50 @@ msgstr "" "tìm thấy nhiá»u hÆ¡n %i thẻ (tag); đã liệt kê %i gần đây nhất\n" "bá» Ä‘i tìm kiếm tại %s\n" +#: builtin/describe.c:403 +msgid "find the tag that comes after the commit" +msgstr "tìm các thẻ mà nó đến trước lần chuyển giao" + +#: builtin/describe.c:404 +msgid "debug search strategy on stderr" +msgstr "chiến lược tìm kiếm trên đầu ra lá»—i chuẩn stderr" + +#: builtin/describe.c:405 +msgid "use any ref in .git/refs" +msgstr "sá» dụng bất kỳ ref nà o trong .git/refs" + +#: builtin/describe.c:406 +msgid "use any tag in .git/refs/tags" +msgstr "sá» dụng bất kỳ thẻ nà o trong .git/refs/tags" + +#: builtin/describe.c:407 +msgid "always use long format" +msgstr "luôn dùng định dạng dà i" + +#: builtin/describe.c:410 +msgid "only output exact matches" +msgstr "chỉ xuất những gì khá»›p chÃnh xác" + +#: builtin/describe.c:412 +msgid "consider <n> most recent tags (default: 10)" +msgstr "coi như <n> thẻ gần đây nhất (mặc định: 10)" + +#: builtin/describe.c:414 +msgid "only consider tags matching <pattern>" +msgstr "chỉ cân nhắc đến những thẻ khá»›p vá»›i <mẫu>" + +#: builtin/describe.c:416 builtin/name-rev.c:238 +msgid "show abbreviated commit object as fallback" +msgstr "hiển thị đối tượng chuyển giao vắn tắt như là fallback" + +#: builtin/describe.c:417 +msgid "mark" +msgstr "dấu" + +#: builtin/describe.c:418 +msgid "append <mark> on dirty working tree (default: \"-dirty\")" +msgstr "thêm <dấu> trên cây thư mục là m việc bẩn (mặc định \"-dirty\")" + #: builtin/describe.c:436 msgid "--long is incompatible with --abbrev=0" msgstr "--long là xung khắc vá»›i tùy chá»n --abbrev=0" @@ -2576,45 +4119,167 @@ msgstr "Không tìm thấy các tên, không thể mô tả gì cả." msgid "--dirty is incompatible with committishes" msgstr "--dirty là xung khắc vá»›i các tùy chá»n dà nh cho chuyển giao (commit)" -#: builtin/diff.c:77 +#: builtin/diff.c:79 #, c-format msgid "'%s': not a regular file or symlink" -msgstr "'%s': không phải táºp tin bình thưá»ng hay liên kết tượng trưng" +msgstr "“%sâ€: không phải táºp tin bình thưá»ng hay liên kết tượng trưng" -#: builtin/diff.c:220 +#: builtin/diff.c:228 #, c-format msgid "invalid option: %s" msgstr "tùy chá»n sai: %s" -#: builtin/diff.c:297 +#: builtin/diff.c:305 msgid "Not a git repository" msgstr "Không phải là kho git" -#: builtin/diff.c:347 +#: builtin/diff.c:348 #, c-format msgid "invalid object '%s' given." -msgstr "đối tượng đã cho '%s' không hợp lệ." +msgstr "đối tượng đã cho “%s†không hợp lệ." -#: builtin/diff.c:352 +#: builtin/diff.c:353 #, c-format msgid "more than %d trees given: '%s'" -msgstr "đã chỉ ra nhiá»u hÆ¡n %d cây (tree): '%s'" +msgstr "đã chỉ ra nhiá»u hÆ¡n %d cây (tree): “%sâ€" -#: builtin/diff.c:362 +#: builtin/diff.c:363 #, c-format msgid "more than two blobs given: '%s'" -msgstr "đã cho nhiá»u hÆ¡n hai đối tượng blob: '%s'" +msgstr "đã cho nhiá»u hÆ¡n hai đối tượng blob: “%sâ€" -#: builtin/diff.c:370 +#: builtin/diff.c:371 #, c-format msgid "unhandled object '%s' given." -msgstr "đã cho đối tượng không thể nắm giữ '%s'." +msgstr "đã cho đối tượng không thể nắm giữ “%sâ€." + +#: builtin/fast-export.c:22 +msgid "git fast-export [rev-list-opts]" +msgstr "git fast-export [rev-list-opts]" + +#: builtin/fast-export.c:635 +msgid "show progress after <n> objects" +msgstr "hiển thị tiến triển sau <n> đối tượng" + +#: builtin/fast-export.c:637 +msgid "select handling of signed tags" +msgstr "chá»n Ä‘iá»u khiển cá»§a thẻ đã ký" + +#: builtin/fast-export.c:640 +msgid "select handling of tags that tag filtered objects" +msgstr "chá»n sá»± xá» lý cá»§a các thẻ, cái mà đánh thẻ các đối tượng được lá»c ra" + +#: builtin/fast-export.c:643 +msgid "Dump marks to this file" +msgstr "Äổ các đánh dấu nà y và o táºp-tin" + +#: builtin/fast-export.c:645 +msgid "Import marks from this file" +msgstr "nháºp và o đánh dấu từ táºp tin nà y" + +#: builtin/fast-export.c:647 +msgid "Fake a tagger when tags lack one" +msgstr "Là m giả má»™t cái thẻ khi thẻ bị thiếu má»™t cái" + +#: builtin/fast-export.c:649 +msgid "Output full tree for each commit" +msgstr "Xuất ra toà n bá»™ cây cho má»—i lần chuyển giao" + +#: builtin/fast-export.c:651 +msgid "Use the done feature to terminate the stream" +msgstr "Sá» dụng tÃnh năng done để chấm dứt luồng dữ liệu" + +#: builtin/fast-export.c:652 +msgid "Skip output of blob data" +msgstr "Bá» qua kết xuất cá»§a dữ liệu blob" + +#: builtin/fetch.c:20 +msgid "git fetch [<options>] [<repository> [<refspec>...]]" +msgstr "git fetch [<các-tùy-chá»n>] [<kho-chứa> [<refspec>...]]" + +#: builtin/fetch.c:21 +msgid "git fetch [<options>] <group>" +msgstr "git fetch [<các-tùy-chá»n>] [<nhóm>" + +#: builtin/fetch.c:22 +msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]" +msgstr "git fetch --multiple [<các-tùy-chá»n>] [(<kho> | <nhóm>)...]" + +#: builtin/fetch.c:23 +msgid "git fetch --all [<options>]" +msgstr "git fetch --all [<các-tùy-chá»n>]" + +#: builtin/fetch.c:60 +msgid "fetch from all remotes" +msgstr "fetch từ tất cả các máy chá»§" + +#: builtin/fetch.c:62 +msgid "append to .git/FETCH_HEAD instead of overwriting" +msgstr "nối thêm và o .git/FETCH_HEAD thay vì ghi đè lên nó" + +#: builtin/fetch.c:64 +msgid "path to upload pack on remote end" +msgstr "đưá»ng dẫn đến gói (pack) tải lên trên máy chá»§ cuối" -#: builtin/fetch.c:200 +#: builtin/fetch.c:65 +msgid "force overwrite of local branch" +msgstr "ép buá»™c ghi đè lên nhánh ná»™i bá»™" + +#: builtin/fetch.c:67 +msgid "fetch from multiple remotes" +msgstr "fetch từ nhiá»u máy chá»§ cùng lúc" + +#: builtin/fetch.c:69 +msgid "fetch all tags and associated objects" +msgstr "lấy (fetch) tất cả các thẻ cùng vá»›i các đối tượng liên quan đến nó" + +#: builtin/fetch.c:71 +msgid "do not fetch all tags (--no-tags)" +msgstr "không lấy (fetch) tất cả các thẻ (--no-tags)" + +#: builtin/fetch.c:73 +msgid "prune remote-tracking branches no longer on remote" +msgstr "" +"cắt cụt (prune) các nhánh “remote-tracking†không còn tồn tại trên máy chá»§ " +"nữa" + +#: builtin/fetch.c:74 +msgid "on-demand" +msgstr "khi-cần" + +#: builtin/fetch.c:75 +msgid "control recursive fetching of submodules" +msgstr "Ä‘iá»u khiển việc lấy vá» (fetch) đệ quy trong các mô-Ä‘un-con" + +#: builtin/fetch.c:79 +msgid "keep downloaded pack" +msgstr "giữ các gói đã tải vá»" + +#: builtin/fetch.c:81 +msgid "allow updating of HEAD ref" +msgstr "cho phép cáºp nháºt ref (tham chiếu) HEAD" + +#: builtin/fetch.c:84 +msgid "deepen history of shallow clone" +msgstr "là m sâu hÆ¡n lịch sá» cá»§a bản sao" + +#: builtin/fetch.c:85 builtin/log.c:1088 +msgid "dir" +msgstr "tmục" + +#: builtin/fetch.c:86 +msgid "prepend this to submodule path output" +msgstr "soạn sẵn cái nà y cho kết xuất đưá»ng dẫn mô-Ä‘un-con" + +#: builtin/fetch.c:89 +msgid "default mode for recursion" +msgstr "chế độ mặc định cho đệ qui" + +#: builtin/fetch.c:201 msgid "Couldn't find remote ref HEAD" msgstr "Không thể tìm thấy máy chá»§ cho tham chiếu HEAD" -#: builtin/fetch.c:253 +#: builtin/fetch.c:254 #, c-format msgid "object %s not found" msgstr "Không tìm thấy đối tượng %s" @@ -2626,10 +4291,9 @@ msgstr "[đã cáºp nháºt]" #: builtin/fetch.c:273 #, c-format msgid "! %-*s %-*s -> %s (can't fetch in current branch)" -msgstr "! %-*s %-*s -> %s (không thể fetch (lấy vá») trong nhánh hiện hà nh)" +msgstr "! %-*s %-*s -> %s (không thể fetch (lấy) vá» nhánh hiện hà nh)" -#: builtin/fetch.c:274 -#: builtin/fetch.c:360 +#: builtin/fetch.c:274 builtin/fetch.c:360 msgid "[rejected]" msgstr "[Bị từ chối]" @@ -2637,9 +4301,7 @@ msgstr "[Bị từ chối]" msgid "[tag update]" msgstr "[cáºp nháºt thẻ]" -#: builtin/fetch.c:287 -#: builtin/fetch.c:322 -#: builtin/fetch.c:340 +#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340 msgid " (unable to update local ref)" msgstr " (không thể cáºp nháºt tham chiếu (ref) ná»™i bá»™)" @@ -2667,8 +4329,7 @@ msgstr "cưỡng bức cáºp nháºt" msgid "(non-fast-forward)" msgstr "(non-fast-forward)" -#: builtin/fetch.c:393 -#: builtin/fetch.c:685 +#: builtin/fetch.c:393 builtin/fetch.c:685 #, c-format msgid "cannot open %s: %s\n" msgstr "không thể mở %s: %s\n" @@ -2690,31 +4351,32 @@ msgid "" " 'git remote prune %s' to remove any old, conflicting branches" msgstr "" "má»™t số tham chiếu (refs) ná»™i bá»™ không thể được cáºp nháºt; hãy thá» chạy\n" -" 'git remote prune %s' để bá» Ä‘i những nhánh cÅ©, hay bị xung đột" +" “git remote prune %s†để bá» Ä‘i những nhánh cÅ©, hay bị xung đột" #: builtin/fetch.c:549 #, c-format msgid " (%s will become dangling)" -msgstr " (%s sẽ trở thà nh lá»§ng lẳng (không được quản lý))" +msgstr " (%s sẽ trở thà nh không đầu (không được quản lý))" #: builtin/fetch.c:550 #, c-format msgid " (%s has become dangling)" -msgstr " (%s phải trở thà nh lá»§ng lẳng (không được quản lý))" +msgstr " (%s đã trở thà nh không đầu (không được quản lý))" #: builtin/fetch.c:557 msgid "[deleted]" msgstr "[đã xóa]" -#: builtin/fetch.c:558 -#: builtin/remote.c:1055 +#: builtin/fetch.c:558 builtin/remote.c:1055 msgid "(none)" msgstr "(không)" #: builtin/fetch.c:675 #, c-format msgid "Refusing to fetch into current branch %s of non-bare repository" -msgstr "Từ chối việc lấy (fetch) và o trong nhánh hiện tại %s cá»§a má»™t kho chứa không phải kho trần (bare)" +msgstr "" +"Từ chối việc lấy (fetch) và o trong nhánh hiện tại %s cá»§a má»™t kho chứa không " +"phải kho trần (bare)" #: builtin/fetch.c:709 #, c-format @@ -2731,18 +4393,17 @@ msgstr "Tùy chá»n \"%s\" có giá trị \"%s\" là không hợp lệ cho %s" msgid "Option \"%s\" is ignored for %s\n" msgstr "Tùy chá»n \"%s\" bị bá» qua vá»›i %s\n" -#: builtin/fetch.c:888 +#: builtin/fetch.c:891 #, c-format msgid "Fetching %s\n" msgstr "Äang lấy (fetch) %s\n" -#: builtin/fetch.c:890 -#: builtin/remote.c:100 +#: builtin/fetch.c:893 builtin/remote.c:100 #, c-format msgid "Could not fetch %s" msgstr "không thể fetch (lấy) %s" -#: builtin/fetch.c:907 +#: builtin/fetch.c:912 msgid "" "No remote repository specified. Please, specify either a URL or a\n" "remote name from which new revisions should be fetched." @@ -2750,424 +4411,817 @@ msgstr "" "Chưa chỉ ra kho chứa máy chá»§. Xin hãy chỉ định hoặc là URL hoặc\n" "tên máy chá»§ từ cái mà những Ä‘iểm xét duyệt má»›i có thể được fetch (lấy vá»)." -#: builtin/fetch.c:927 +#: builtin/fetch.c:932 msgid "You need to specify a tag name." msgstr "Bạn phải định rõ tên thẻ." -#: builtin/fetch.c:979 +#: builtin/fetch.c:984 msgid "fetch --all does not take a repository argument" -msgstr "lệnh lấy vá» sá» dụng tùy chá»n --all sẽ không lấy đối số kho chứa" +msgstr "lệnh lấy vá» \"fetch --all\" không lấy đối số kho chứa" -#: builtin/fetch.c:981 +#: builtin/fetch.c:986 msgid "fetch --all does not make sense with refspecs" -msgstr "lệnh lấy vá» fetch sá» dụng tùy chá»n --all không hợp lý vá»›i refspecs" +msgstr "lệnh lấy vá» \"fetch --all\" không hợp lý vá»›i refspecs" -#: builtin/fetch.c:992 +#: builtin/fetch.c:997 #, c-format msgid "No such remote or remote group: %s" msgstr "không có nhóm máy chá»§ hay máy chá»§ như thế: %s" -#: builtin/fetch.c:1000 +#: builtin/fetch.c:1005 msgid "Fetching a group and specifying refspecs does not make sense" msgstr "Việc lấy vá» cả má»™t nhóm và chỉ định refspecs không hợp lý" +#: builtin/fmt-merge-msg.c:13 +msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]" +msgstr "" +"git fmt-merge-msg [-m <thông Ä‘iệp>] [--log[=<n>]|--no-log] [--file <táºp-tin>]" + +#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:701 +#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:175 +#: builtin/tag.c:448 parse-options.h:133 parse-options.h:235 +msgid "n" +msgstr "n" + +#: builtin/fmt-merge-msg.c:654 +msgid "populate log with at most <n> entries from shortlog" +msgstr "gắn nháºt ký vá»›i Ãt nhất <n> mục từ lệnh “shortlogâ€" + +#: builtin/fmt-merge-msg.c:657 +msgid "alias for --log (deprecated)" +msgstr "bà danh cho --log (không được dùng)" + +#: builtin/fmt-merge-msg.c:660 +msgid "text" +msgstr "văn bản" + +#: builtin/fmt-merge-msg.c:661 +msgid "use <text> as start of message" +msgstr "dùng <văn bản thưá»ng> để bắt đầu ghi chú" + +#: builtin/fmt-merge-msg.c:662 +msgid "file to read from" +msgstr "táºp tin để Ä‘á»c dữ liệu từ đó" + +#: builtin/for-each-ref.c:979 +msgid "git for-each-ref [options] [<pattern>]" +msgstr "git for-each-ref [các-tùy-chá»n] [<mẫu>]" + +#: builtin/for-each-ref.c:994 +msgid "quote placeholders suitably for shells" +msgstr "trÃch dẫn để phù hợp cho hệ vá» (shell)" + +#: builtin/for-each-ref.c:996 +msgid "quote placeholders suitably for perl" +msgstr "trÃch dẫn để phù hợp cho perl" + +#: builtin/for-each-ref.c:998 +msgid "quote placeholders suitably for python" +msgstr "trÃch dẫn để phù hợp cho python" + +#: builtin/for-each-ref.c:1000 +msgid "quote placeholders suitably for tcl" +msgstr "trÃch dẫn để phù hợp cho tcl" + +#: builtin/for-each-ref.c:1003 +msgid "show only <n> matched refs" +msgstr "hiển thị chỉ <n> tham chiếu khá»›p" + +#: builtin/for-each-ref.c:1004 +msgid "format" +msgstr "định dạng" + +#: builtin/for-each-ref.c:1004 +msgid "format to use for the output" +msgstr "định dạng sẽ dùng cho đầu ra" + +#: builtin/for-each-ref.c:1005 +msgid "key" +msgstr "khóa" + +#: builtin/for-each-ref.c:1006 +msgid "field name to sort on" +msgstr "tên trưá»ng cần sắp xếp" + +#: builtin/fsck.c:608 +msgid "git fsck [options] [<object>...]" +msgstr "git fsck [các-tùy-chá»n] [<đối-tượng>...]" + +#: builtin/fsck.c:614 +msgid "show unreachable objects" +msgstr "hiển thị các đối tượng không thể Ä‘á»c được" + +#: builtin/fsck.c:615 +msgid "show dangling objects" +msgstr "hiển thị các đối tượng không được quản lý" + +#: builtin/fsck.c:616 +msgid "report tags" +msgstr "báo cáo các thẻ" + +#: builtin/fsck.c:617 +msgid "report root nodes" +msgstr "báo cáo node gốc" + +#: builtin/fsck.c:618 +msgid "make index objects head nodes" +msgstr "tạo “ index objects head nodesâ€" + +#: builtin/fsck.c:619 +msgid "make reflogs head nodes (default)" +msgstr "tạo reflogs head nodes (mặc định)" + +#: builtin/fsck.c:620 +msgid "also consider packs and alternate objects" +msgstr "cÅ©ng cân nhắc đến các đối tượng gói và thay thế" + +#: builtin/fsck.c:621 +msgid "enable more strict checking" +msgstr "cho phép kiểm tra hạn chế hÆ¡n" + +#: builtin/fsck.c:623 +msgid "write dangling objects in .git/lost-found" +msgstr "ghi các đối tượng không được quản lý trong .git/lost-found" + +#: builtin/fsck.c:624 builtin/prune.c:134 +msgid "show progress" +msgstr "hiển thị quá trình" + +#: builtin/gc.c:22 +msgid "git gc [options]" +msgstr "git gc [các-tùy-chá»n]" + #: builtin/gc.c:63 #, c-format msgid "Invalid %s: '%s'" -msgstr "%s không hợp lệ: '%s'" +msgstr "%s không hợp lệ: “%sâ€" #: builtin/gc.c:90 #, c-format msgid "insanely long object directory %.*s" msgstr "thư mục đối tượng dà i má»™t cách Ä‘iên rồ %.*s" -#: builtin/gc.c:221 -#, c-format -msgid "Auto packing the repository for optimum performance.\n" -msgstr "Tá»± động đóng gói kho chứa để tối ưu hóa hiệu suất là m việc.\n" +#: builtin/gc.c:179 +msgid "prune unreferenced objects" +msgstr "xóa bá» các đối tượng không được tham chiếu" + +#: builtin/gc.c:181 +msgid "be more thorough (increased runtime)" +msgstr "cẩn tháºn hÆ¡n nữa (tăng thá»i gian chạy)" -#: builtin/gc.c:224 +#: builtin/gc.c:182 +msgid "enable auto-gc mode" +msgstr "báºt chế độ auto-gc" + +#: builtin/gc.c:222 #, c-format msgid "" "Auto packing the repository for optimum performance. You may also\n" "run \"git gc\" manually. See \"git help gc\" for more information.\n" msgstr "" "Tá»± động đóng gói kho chứa để tối ưu hóa hiệu suất là m việc.\n" -"chạy lệnh \"git gc\" má»™t cách thá»§ công. Hãy xem \"git help gc\" để biết thêm chi tiết.\n" +"chạy lệnh \"git gc\" má»™t cách thá»§ công. Hãy xem \"git help gc\" để biết thêm " +"chi tiết.\n" + +#: builtin/gc.c:249 +msgid "" +"There are too many unreachable loose objects; run 'git prune' to remove them." +msgstr "" +"Có quá nhiá»u đối tượng tá»± do không được dùng đến; hãy chạy lệnh “git prune†" +"để xóa bá» chúng Ä‘i." -#: builtin/gc.c:251 -msgid "There are too many unreachable loose objects; run 'git prune' to remove them." -msgstr "Có quá nhiá»u đối tượng tá»± do không được dùng đến; hãy chạy lệnh 'git prune' để xóa bá» chúng Ä‘i." +#: builtin/grep.c:22 +msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]" +msgstr "git grep [các-tùy-chá»n] [-e] <mẫu> [<rev>...] [[--] <đưá»ng-dẫn>...]" -#: builtin/grep.c:216 +#: builtin/grep.c:217 #, c-format msgid "grep: failed to create thread: %s" msgstr "grep: gặp lá»—i tạo tuyến (thread): %s" -#: builtin/grep.c:402 +#: builtin/grep.c:365 #, c-format msgid "Failed to chdir: %s" msgstr "Gặp lá»—i vá»›i lệnh chdir: %s" -#: builtin/grep.c:478 -#: builtin/grep.c:512 +#: builtin/grep.c:443 builtin/grep.c:478 #, c-format msgid "unable to read tree (%s)" msgstr "không thể Ä‘á»c cây (%s)" -#: builtin/grep.c:526 +#: builtin/grep.c:493 #, c-format msgid "unable to grep from object of type %s" msgstr "không thể thá»±c hiện lệnh grep (lá»c tìm) từ đối tượng thuá»™c kiểu %s" -#: builtin/grep.c:584 +#: builtin/grep.c:551 #, c-format msgid "switch `%c' expects a numerical value" -msgstr "chuyển đến `%c' mong chá» má»™t giá trị bằng số" +msgstr "chuyển đến `%c' cần má»™t giá trị bằng số" -#: builtin/grep.c:601 +#: builtin/grep.c:568 #, c-format msgid "cannot open '%s'" -msgstr "không mở được '%s'" +msgstr "không mở được “%sâ€" + +#: builtin/grep.c:643 +msgid "search in index instead of in the work tree" +msgstr "tìm trong bảng mục lục thay vì trong cây là m việc" + +#: builtin/grep.c:645 +msgid "find in contents not managed by git" +msgstr "tìm trong ná»™i dung không được quản lý bởi git" + +#: builtin/grep.c:647 +msgid "search in both tracked and untracked files" +msgstr "tìm kiếm các táºp tin được và chưa được theo dõi dấu vết" + +#: builtin/grep.c:649 +msgid "search also in ignored files" +msgstr "tìm cả trong các táºp tin đã bị lá» Ä‘i" + +#: builtin/grep.c:652 +msgid "show non-matching lines" +msgstr "hiển thị những dòng không khá»›p vá»›i mẫu" + +#: builtin/grep.c:654 +msgid "case insensitive matching" +msgstr "phân biệt chữ hoa/thưá»ng" + +#: builtin/grep.c:656 +msgid "match patterns only at word boundaries" +msgstr "chỉ khá»›p mẫu tại đưá»ng ranh giá»›i từ" + +#: builtin/grep.c:658 +msgid "process binary files as text" +msgstr "xá» lý táºp tin nhị phân như là dạng văn bản thưá»ng" + +#: builtin/grep.c:660 +msgid "don't match patterns in binary files" +msgstr "không khá»›p mẫu trong các táºp tin nhị phân" + +#: builtin/grep.c:663 +msgid "descend at most <depth> levels" +msgstr "giảm xuống Ãt nhất mức <sâu>" + +#: builtin/grep.c:667 +msgid "use extended POSIX regular expressions" +msgstr "dùng biểu thức chÃnh qui POSIX có mở rá»™ng" + +#: builtin/grep.c:670 +msgid "use basic POSIX regular expressions (default)" +msgstr "sá» dụng biểu thức chÃnh quy kiểu POSIX (mặc định)" + +#: builtin/grep.c:673 +msgid "interpret patterns as fixed strings" +msgstr "diá»…n dịch các mẫu như là chuá»—i cố định" + +#: builtin/grep.c:676 +msgid "use Perl-compatible regular expressions" +msgstr "sá» dụng biểu thức chÃnh quy tương thÃch Perl" + +#: builtin/grep.c:679 +msgid "show line numbers" +msgstr "hiển thị số cá»§a dòng" + +#: builtin/grep.c:680 +msgid "don't show filenames" +msgstr "không hiển thị tên táºp tin" -#: builtin/grep.c:885 +#: builtin/grep.c:681 +msgid "show filenames" +msgstr "hiển thị các tên táºp tin" + +#: builtin/grep.c:683 +msgid "show filenames relative to top directory" +msgstr "hiển thị tên táºp tin tương đối vá»›i thư mục đỉnh (top)" + +#: builtin/grep.c:685 +msgid "show only filenames instead of matching lines" +msgstr "chỉ hiển thị tên táºp tin thay vì những dòng khá»›p vá»›i mẫu" + +#: builtin/grep.c:687 +msgid "synonym for --files-with-matches" +msgstr "đồng nghÄ©a vá»›i --files-with-matches" + +#: builtin/grep.c:690 +msgid "show only the names of files without match" +msgstr "chỉ hiển thị tên cho những táºp tin không khá»›p vá»›i mẫu" + +#: builtin/grep.c:692 +msgid "print NUL after filenames" +msgstr "thêm NUL và o sau tên táºp tin" + +#: builtin/grep.c:694 +msgid "show the number of matches instead of matching lines" +msgstr "hiển thị số lượng khá»›p thay vì những dòng khá»›p vá»›i mẫu" + +#: builtin/grep.c:695 +msgid "highlight matches" +msgstr "tô sáng cái khá»›p" + +#: builtin/grep.c:697 +msgid "print empty line between matches from different files" +msgstr "hiển thị dòng trống giữa các lần khá»›p từ các táºp tin khác biệt" + +#: builtin/grep.c:699 +msgid "show filename only once above matches from same file" +msgstr "" +"hiển thị tên táºp tin má»™t lần phÃa trên các lần khá»›p từ cùng má»™t táºp tin" + +#: builtin/grep.c:702 +msgid "show <n> context lines before and after matches" +msgstr "hiển thị <n> dòng ná»™i dung phÃa trước và sau các lần khá»›p" + +#: builtin/grep.c:705 +msgid "show <n> context lines before matches" +msgstr "hiển thị <n> dòng ná»™i dung trước khá»›p" + +#: builtin/grep.c:707 +msgid "show <n> context lines after matches" +msgstr "hiển thị <n> dòng ná»™i dung sau khá»›p" + +#: builtin/grep.c:708 +msgid "shortcut for -C NUM" +msgstr "Dạng tắt cho -C Sá»" + +#: builtin/grep.c:711 +msgid "show a line with the function name before matches" +msgstr "hiển thị dòng vói tên hà m trước các lần khá»›p" + +#: builtin/grep.c:713 +msgid "show the surrounding function" +msgstr "hiển thị hà m bao quanh" + +#: builtin/grep.c:716 +msgid "read patterns from file" +msgstr "Ä‘á»c mẫu từ táºp-tin" + +#: builtin/grep.c:718 +msgid "match <pattern>" +msgstr "match <mẫu>" + +#: builtin/grep.c:720 +msgid "combine patterns specified with -e" +msgstr "tổ hợp mẫu được chỉ ra vá»›i tùy chá»n -e" + +#: builtin/grep.c:732 +msgid "indicate hit with exit status without output" +msgstr "đưa ra gợi ý vá»›i trạng thái thoát mà không có kết xuất" + +#: builtin/grep.c:734 +msgid "show only matches from files that match all patterns" +msgstr "chỉ hiển thị những cái khá»›p từ táºp tin mà nó khá»›p toà n bá»™ các mẫu" + +#: builtin/grep.c:736 +msgid "show parse tree for grep expression" +msgstr "hiển thị cây phân tÃch cú pháp cho biểu thức “grep†(tìm kiếm)" + +#: builtin/grep.c:740 +msgid "pager" +msgstr "trang giấy" + +#: builtin/grep.c:740 +msgid "show matching files in the pager" +msgstr "hiển thị các táºp tin khá»›p trong trang giấy" + +#: builtin/grep.c:743 +msgid "allow calling of grep(1) (ignored by this build)" +msgstr "cho phép gá»i grep(1) (bị bá» qua bởi lần dịch nà y)" + +#: builtin/grep.c:744 builtin/show-ref.c:184 +msgid "show usage" +msgstr "hiển thị cách dùng" + +#: builtin/grep.c:811 msgid "no pattern given." msgstr "chưa chỉ ra mẫu." -#: builtin/grep.c:899 +#: builtin/grep.c:825 #, c-format msgid "bad object %s" msgstr "đối tượng sai %s" -#: builtin/grep.c:940 +#: builtin/grep.c:866 msgid "--open-files-in-pager only works on the worktree" msgstr "--open-files-in-pager chỉ là m việc trên cây-là m-việc" -#: builtin/grep.c:963 +#: builtin/grep.c:889 msgid "--cached or --untracked cannot be used with --no-index." msgstr "--cached hay --untracked không được sá» dụng vá»›i --no-index." -#: builtin/grep.c:968 +#: builtin/grep.c:894 msgid "--no-index or --untracked cannot be used with revs." -msgstr "--no-index hay --untracked không được sá» dụng cùng vá»›i các tùy chá»n liên quan đến revs." +msgstr "" +"--no-index hay --untracked không được sá» dụng cùng vá»›i các tùy chá»n liên " +"quan đến revs." -#: builtin/grep.c:971 +#: builtin/grep.c:897 msgid "--[no-]exclude-standard cannot be used for tracked contents." msgstr "--[no-]exclude-standard không thể sá» dụng cho ná»™i dung lưu dấu vết." -#: builtin/grep.c:979 +#: builtin/grep.c:905 msgid "both --cached and trees are given." msgstr "cả hai --cached và các cây phải được chỉ ra." -#: builtin/help.c:59 +#: builtin/hash-object.c:60 +msgid "" +"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] " +"<file>..." +msgstr "" +"git hash-object [-t <kiểu>] [-w] [--path=<táºp-tin>|--no-filters] [--stdin] " +"[--] <táºp-tin>..." + +#: builtin/hash-object.c:61 +msgid "git hash-object --stdin-paths < <list-of-paths>" +msgstr "git hash-object --stdin-paths < <danh-sách-đưá»ng-dẫn>" + +#: builtin/hash-object.c:72 +msgid "type" +msgstr "kiểu" + +#: builtin/hash-object.c:72 +msgid "object type" +msgstr "kiểu đối tượng" + +#: builtin/hash-object.c:73 +msgid "write the object into the object database" +msgstr "ghi đối tượng và o dữ liệu đối tượng" + +#: builtin/hash-object.c:74 +msgid "read the object from stdin" +msgstr "Ä‘á»c đối tượng từ đầu và o tiêu chuẩn stdin" + +#: builtin/hash-object.c:76 +msgid "store file as is without filters" +msgstr "lưu các táºp tin mà nó không có các bá»™ lá»c" + +#: builtin/hash-object.c:77 +msgid "process file as it were from this path" +msgstr "xá» lý táºp tin như là nó Ä‘ang ở thư mục nà y" + +#: builtin/help.c:43 +msgid "print all available commands" +msgstr "hiển thị danh sách các câu lệnh ngưá»i dùng có thể sá» dụng" + +#: builtin/help.c:44 +msgid "show man page" +msgstr "hiển thị trang man" + +#: builtin/help.c:45 +msgid "show manual in web browser" +msgstr "hiển thị hướng dẫn sá» dụng trong trình duyệt web" + +#: builtin/help.c:47 +msgid "show info page" +msgstr "hiện trang info" + +#: builtin/help.c:53 +msgid "git help [--all] [--man|--web|--info] [command]" +msgstr "git help [--all] [--man|--web|--info] [lệnh]" + +#: builtin/help.c:65 #, c-format msgid "unrecognized help format '%s'" -msgstr "không nháºn ra định dạng trợ giúp '%s'" +msgstr "không nháºn ra định dạng trợ giúp “%sâ€" -#: builtin/help.c:87 +#: builtin/help.c:93 msgid "Failed to start emacsclient." msgstr "Lá»—i khởi chạy emacsclient." -#: builtin/help.c:100 +#: builtin/help.c:106 msgid "Failed to parse emacsclient version." msgstr "Gặp lá»—i khi phân tÃch phiên bản emacsclient." -#: builtin/help.c:108 +#: builtin/help.c:114 #, c-format msgid "emacsclient version '%d' too old (< 22)." -msgstr "phiên bản cá»§a emacsclient '%d' quá cÅ© (< 22)." +msgstr "phiên bản cá»§a emacsclient “%d†quá cÅ© (< 22)." -#: builtin/help.c:126 -#: builtin/help.c:154 -#: builtin/help.c:163 -#: builtin/help.c:171 +#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177 #, c-format msgid "failed to exec '%s': %s" -msgstr "gặp lá»—i khi thá»±c thi '%s': %s" +msgstr "gặp lá»—i khi thá»±c thi “%sâ€: %s" -#: builtin/help.c:211 +#: builtin/help.c:217 #, c-format msgid "" "'%s': path for unsupported man viewer.\n" "Please consider using 'man.<tool>.cmd' instead." msgstr "" -"'%s': đưá»ng dẫn không há»— trợ bá»™ trình chiếu man.\n" -"Hãy cân nhắc đến việc sá» dụng 'man.<tool>.cmd' để thay thế." +"“%sâ€: đưá»ng dẫn không há»— trợ bá»™ trình chiếu man.\n" +"Hãy cân nhắc đến việc sá» dụng “man.<tool>.cmd†để thay thế." -#: builtin/help.c:223 +#: builtin/help.c:229 #, c-format msgid "" "'%s': cmd for supported man viewer.\n" "Please consider using 'man.<tool>.path' instead." msgstr "" -"'%s': cmd (lệnh) há»— trợ bá»™ trình chiếu man.\n" -"Hãy cân nhắc đến việc sá» dụng 'man.<tool>.path' để thay thế." +"“%sâ€: cmd (lệnh) há»— trợ bá»™ trình chiếu man.\n" +"Hãy cân nhắc đến việc sá» dụng “man.<tool>.path†để thay thế." -#: builtin/help.c:287 +#: builtin/help.c:299 msgid "The most commonly used git commands are:" msgstr "Những lệnh git hay được sá» dụng nhất là :" -#: builtin/help.c:355 +#: builtin/help.c:367 #, c-format msgid "'%s': unknown man viewer." -msgstr "'%s': không rõ chương trình xem man." +msgstr "“%sâ€: không rõ chương trình xem man." -#: builtin/help.c:372 +#: builtin/help.c:384 msgid "no man viewer handled the request" msgstr "không có trình xem trợ giúp dạng manpage tiếp hợp vá»›i yêu cầu" -#: builtin/help.c:380 +#: builtin/help.c:392 msgid "no info viewer handled the request" msgstr "không có trình xem trợ giúp dạng info tiếp hợp vá»›i yêu cầu" -#: builtin/help.c:391 -#, c-format -msgid "'%s': not a documentation directory." -msgstr "'%s': không phải là má»™t thư mục tà i liệu." - -#: builtin/help.c:432 -#: builtin/help.c:439 +#: builtin/help.c:447 builtin/help.c:454 #, c-format msgid "usage: %s%s" msgstr "cách sá» dụng: %s%s" -#: builtin/help.c:453 +#: builtin/help.c:470 #, c-format msgid "`git %s' is aliased to `%s'" msgstr "`git %s' được đặt bà danh thà nh `%s'" -#: builtin/index-pack.c:169 +#: builtin/index-pack.c:170 #, c-format msgid "object type mismatch at %s" msgstr "kiểu đối tượng không khá»›p tại %s" -#: builtin/index-pack.c:189 +#: builtin/index-pack.c:190 msgid "object of unexpected type" msgstr "đối tượng cá»§a kiểu không mong đợi" -#: builtin/index-pack.c:226 +#: builtin/index-pack.c:227 #, c-format msgid "cannot fill %d byte" msgid_plural "cannot fill %d bytes" msgstr[0] "không thể Ä‘iá»n và o %d byte" msgstr[1] "không thể Ä‘iá»n và o %d byte" -#: builtin/index-pack.c:236 +#: builtin/index-pack.c:237 msgid "early EOF" msgstr "vừa đúng lúc EOF" -#: builtin/index-pack.c:237 +#: builtin/index-pack.c:238 msgid "read error on input" msgstr "lá»—i Ä‘á»c ở đầu và o" -#: builtin/index-pack.c:249 +#: builtin/index-pack.c:250 msgid "used more bytes than were available" msgstr "sá» dụng nhiá»u hÆ¡n số lượng byte mà nó sẵn có" -#: builtin/index-pack.c:256 +#: builtin/index-pack.c:257 msgid "pack too large for current definition of off_t" msgstr "pack quá lá»›n so vá»›i định nghÄ©a hiện tại cá»§a kiểu off_t" -#: builtin/index-pack.c:272 +#: builtin/index-pack.c:273 #, c-format msgid "unable to create '%s'" -msgstr "không thể tạo '%s'" +msgstr "không thể tạo “%sâ€" -#: builtin/index-pack.c:277 +#: builtin/index-pack.c:278 #, c-format msgid "cannot open packfile '%s'" -msgstr "không thể mở packfile '%s'" +msgstr "không thể mở packfile “%sâ€" -#: builtin/index-pack.c:291 +#: builtin/index-pack.c:292 msgid "pack signature mismatch" msgstr "chữ ký cho pack không khá»›p" -#: builtin/index-pack.c:311 +#: builtin/index-pack.c:294 +#, c-format +msgid "pack version %<PRIu32> unsupported" +msgstr "không há»— trợ phiên bản pack %<PRIu32>" + +#: builtin/index-pack.c:312 #, c-format msgid "pack has bad object at offset %lu: %s" msgstr "pack có đối tượng sai khoảng bù (offset) %lu: %s" -#: builtin/index-pack.c:405 +#: builtin/index-pack.c:434 #, c-format msgid "inflate returned %d" msgstr "xả nén trả vá» %d" -#: builtin/index-pack.c:450 +#: builtin/index-pack.c:483 msgid "offset value overflow for delta base object" msgstr "trà n giá trị khoảng bù cho đối tượng delta cÆ¡ sở" -#: builtin/index-pack.c:458 +#: builtin/index-pack.c:491 msgid "delta base offset is out of bound" msgstr "khoảng bù cÆ¡ sở cho delta nằm ngoà i phạm vi" -#: builtin/index-pack.c:466 +#: builtin/index-pack.c:499 #, c-format msgid "unknown object type %d" msgstr "không hiểu kiểu đối tượng %d" -#: builtin/index-pack.c:495 +#: builtin/index-pack.c:530 msgid "cannot pread pack file" msgstr "không thể chạy hà m pread cho táºp tin pack" -#: builtin/index-pack.c:497 +#: builtin/index-pack.c:532 #, c-format msgid "premature end of pack file, %lu byte missing" msgid_plural "premature end of pack file, %lu bytes missing" msgstr[0] "táºp tin pack bị kết thúc sá»›m, %lu byte bị thiếu" msgstr[1] "táºp tin pack bị kết thúc sá»›m, %lu byte bị thiếu" -#: builtin/index-pack.c:510 +#: builtin/index-pack.c:558 msgid "serious inflate inconsistency" msgstr "sá»± mâu thuẫn xả nén nghiêm trá»ng" -#: builtin/index-pack.c:583 -#, c-format -msgid "cannot read existing object %s" -msgstr "không thể Ä‘á»c đối tượng đã tồn tại %s" - -#: builtin/index-pack.c:586 +#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678 +#: builtin/index-pack.c:712 builtin/index-pack.c:721 #, c-format msgid "SHA1 COLLISION FOUND WITH %s !" msgstr "Sá»° VA CHẠM SHA1 Äà XẢY RA VỚI %s!" -#: builtin/index-pack.c:598 +#: builtin/index-pack.c:652 builtin/pack-objects.c:170 +#: builtin/pack-objects.c:262 +#, c-format +msgid "unable to read %s" +msgstr "không thể Ä‘á»c %s" + +#: builtin/index-pack.c:718 +#, c-format +msgid "cannot read existing object %s" +msgstr "không thể Ä‘á»c đối tượng đã tồn tại %s" + +#: builtin/index-pack.c:732 #, c-format msgid "invalid blob object %s" msgstr "đối tượng blob không hợp lệ %s" -#: builtin/index-pack.c:610 +#: builtin/index-pack.c:747 #, c-format msgid "invalid %s" msgstr "%s không hợp lệ" -#: builtin/index-pack.c:612 +#: builtin/index-pack.c:749 msgid "Error in object" msgstr "Lá»—i trong đối tượng" -#: builtin/index-pack.c:614 +#: builtin/index-pack.c:751 #, c-format msgid "Not all child objects of %s are reachable" msgstr "Không phải tất cả các đối tượng con cá»§a %s là có thể vá»›i tá»›i được" -#: builtin/index-pack.c:687 -#: builtin/index-pack.c:713 +#: builtin/index-pack.c:821 builtin/index-pack.c:847 msgid "failed to apply delta" msgstr "gặp lá»—i khi áp dụng delta" -#: builtin/index-pack.c:850 +#: builtin/index-pack.c:986 msgid "Receiving objects" msgstr "Äang nháºn vá» các đối tượng" -#: builtin/index-pack.c:850 +#: builtin/index-pack.c:986 msgid "Indexing objects" msgstr "Các đối tượng bảng mục lục" -#: builtin/index-pack.c:872 +#: builtin/index-pack.c:1012 msgid "pack is corrupted (SHA1 mismatch)" msgstr "pack bị sai há»ng (SHA1 không khá»›p)" -#: builtin/index-pack.c:877 +#: builtin/index-pack.c:1017 msgid "cannot fstat packfile" msgstr "không thể fstat packfile" -#: builtin/index-pack.c:880 +#: builtin/index-pack.c:1020 msgid "pack has junk at the end" msgstr "pack có phần thừa ở cuối" -#: builtin/index-pack.c:903 +#: builtin/index-pack.c:1031 +msgid "confusion beyond insanity in parse_pack_objects()" +msgstr "lá»™n xá»™n hÆ¡n cả Ä‘iên rồ khi chạy hà m parse_pack_objects()" + +#: builtin/index-pack.c:1054 msgid "Resolving deltas" msgstr "Äang phân giải các delta" -#: builtin/index-pack.c:954 +#: builtin/index-pack.c:1064 +#, c-format +msgid "unable to create thread: %s" +msgstr "không thể tạo tuyến: %s" + +#: builtin/index-pack.c:1106 msgid "confusion beyond insanity" msgstr "lá»™n xá»™n hÆ¡n cả Ä‘iên rồ" -#: builtin/index-pack.c:973 +#: builtin/index-pack.c:1112 +#, c-format +msgid "completed with %d local objects" +msgstr "đầy đủ vá»›i %d đối tượng ná»™i bá»™" + +#: builtin/index-pack.c:1121 +#, c-format +msgid "Unexpected tail checksum for %s (disk corruption?)" +msgstr "Tổng kiểm tra tail không như mong đợi cho %s (đĩa há»ng?)" + +#: builtin/index-pack.c:1125 #, c-format msgid "pack has %d unresolved delta" msgid_plural "pack has %d unresolved deltas" msgstr[0] "pack có %d delta chưa được giải quyết" msgstr[1] "pack có %d delta chưa được giải quyết" -#: builtin/index-pack.c:998 +#: builtin/index-pack.c:1150 #, c-format msgid "unable to deflate appended object (%d)" msgstr "không thể xả đối tượng nối thêm (%d)" -#: builtin/index-pack.c:1077 +#: builtin/index-pack.c:1229 #, c-format msgid "local object %s is corrupt" msgstr "đối tượng ná»™i bá»™ %s bị há»ng" -#: builtin/index-pack.c:1101 +#: builtin/index-pack.c:1253 msgid "error while closing pack file" msgstr "gặp lá»—i trong khi đóng táºp tin pack" -#: builtin/index-pack.c:1114 +#: builtin/index-pack.c:1266 #, c-format msgid "cannot write keep file '%s'" -msgstr "không thể ghi táºp tin giữ lại '%s'" +msgstr "không thể ghi táºp tin giữ lại “%sâ€" -#: builtin/index-pack.c:1122 +#: builtin/index-pack.c:1274 #, c-format msgid "cannot close written keep file '%s'" -msgstr "không thể đóng táºp tin giữ lại đã được ghi '%s'" +msgstr "không thể đóng táºp tin giữ lại đã được ghi “%sâ€" -#: builtin/index-pack.c:1135 +#: builtin/index-pack.c:1287 msgid "cannot store pack file" msgstr "không thể lưu táºp tin pack" -#: builtin/index-pack.c:1146 +#: builtin/index-pack.c:1298 msgid "cannot store index file" msgstr "không thể lưu trữ táºp tin ghi mục lục" -#: builtin/index-pack.c:1247 +#: builtin/index-pack.c:1331 +#, c-format +msgid "bad pack.indexversion=%<PRIu32>" +msgstr "sai pack.indexversion=%<PRIu32>" + +#: builtin/index-pack.c:1337 +#, c-format +msgid "invalid number of threads specified (%d)" +msgstr "số tuyến chỉ ra không hợp lệ (%d)" + +#: builtin/index-pack.c:1341 builtin/index-pack.c:1514 +#, c-format +msgid "no threads support, ignoring %s" +msgstr "không há»— trợ Ä‘a tuyến, bá» qua %s" + +#: builtin/index-pack.c:1399 #, c-format msgid "Cannot open existing pack file '%s'" -msgstr "Không thể mở táºp tin pack đã sẵn có '%s' " +msgstr "Không thể mở táºp tin pack đã sẵn có “%sâ€" -#: builtin/index-pack.c:1249 +#: builtin/index-pack.c:1401 #, c-format msgid "Cannot open existing pack idx file for '%s'" -msgstr "Không thể mở táºp tin 'pack idx' cho '%s'" +msgstr "Không thể mở táºp tin “pack idx†cho “%sâ€" -#: builtin/index-pack.c:1296 +#: builtin/index-pack.c:1448 #, c-format msgid "non delta: %d object" msgid_plural "non delta: %d objects" msgstr[0] "không delta: %d đối tượng" msgstr[1] "không delta: %d đối tượng" -#: builtin/index-pack.c:1303 +#: builtin/index-pack.c:1455 #, c-format msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" msgstr[0] "chiá»u dà i xÃch = %d: %lu đối tượng" msgstr[1] "chiá»u dà i xÃch = %d: %lu đối tượng" -#: builtin/index-pack.c:1330 +#: builtin/index-pack.c:1482 msgid "Cannot come back to cwd" msgstr "Không thể quay lại cwd" -#: builtin/index-pack.c:1374 -#: builtin/index-pack.c:1377 -#: builtin/index-pack.c:1389 -#: builtin/index-pack.c:1393 +#: builtin/index-pack.c:1526 builtin/index-pack.c:1529 +#: builtin/index-pack.c:1541 builtin/index-pack.c:1545 #, c-format msgid "bad %s" msgstr "%s sai" -#: builtin/index-pack.c:1407 +#: builtin/index-pack.c:1559 msgid "--fix-thin cannot be used without --stdin" msgstr "--fix-thin không thể được dùng mà không có --stdin" -#: builtin/index-pack.c:1411 -#: builtin/index-pack.c:1421 +#: builtin/index-pack.c:1563 builtin/index-pack.c:1573 #, c-format msgid "packfile name '%s' does not end with '.pack'" -msgstr "tên táºp tin packfile '%s' không được kết thúc bằng Ä‘uôi '.pack'" +msgstr "tên táºp tin packfile “%s†không được kết thúc bằng Ä‘uôi “.packâ€" -#: builtin/index-pack.c:1430 +#: builtin/index-pack.c:1582 msgid "--verify with no packfile name given" msgstr "dùng tùy chá»n --verify mà không đưa ra tên packfile" @@ -3184,22 +5238,22 @@ msgstr "tên mẫu dà i má»™t cách Ä‘iên rồ %s" #: builtin/init-db.c:67 #, c-format msgid "cannot stat '%s'" -msgstr "không thể lấy trạng thái (stat) vá» '%s'" +msgstr "không thể lấy trạng thái (stat) vỠ“%sâ€" #: builtin/init-db.c:73 #, c-format msgid "cannot stat template '%s'" -msgstr "không thể stat (lấy trạng thái vá») mẫu '%s'" +msgstr "không thể stat (lấy trạng thái vá») mẫu “%sâ€" #: builtin/init-db.c:80 #, c-format msgid "cannot opendir '%s'" -msgstr "không thể opendir '%s'" +msgstr "không thể opendir “%sâ€" #: builtin/init-db.c:97 #, c-format msgid "cannot readlink '%s'" -msgstr "không thể readlink '%s'" +msgstr "không thể readlink “%sâ€" #: builtin/init-db.c:99 #, c-format @@ -3209,7 +5263,7 @@ msgstr "liên kết tượng trưng dà i má»™t cách Ä‘iên rồ %s" #: builtin/init-db.c:102 #, c-format msgid "cannot symlink '%s' '%s'" -msgstr "không thể tạo liên kết tượng trưng (symlink) '%s' '%s'" +msgstr "không thể tạo liên kết tượng trưng (symlink) “%s†“%sâ€" #: builtin/init-db.c:106 #, c-format @@ -3234,185 +5288,494 @@ msgstr "các mẫu không được tìm thấy %s" #: builtin/init-db.c:154 #, c-format msgid "not copying templates of a wrong format version %d from '%s'" -msgstr "không sao chép các mẫu cá»§a phiên bản sai định dạng %d từ '%s'" +msgstr "không sao chép các mẫu cá»§a phiên bản sai định dạng %d từ “%sâ€" #: builtin/init-db.c:192 #, c-format msgid "insane git directory %s" msgstr "thư mục git Ä‘iên rồ %s" -#: builtin/init-db.c:322 -#: builtin/init-db.c:325 +#: builtin/init-db.c:323 builtin/init-db.c:326 #, c-format msgid "%s already exists" -msgstr "%s đã tồn tại rồi" +msgstr "%s đã có từ trước rồi" -#: builtin/init-db.c:354 +#: builtin/init-db.c:355 #, c-format msgid "unable to handle file type %d" -msgstr "không thể handle tệp tin kiểu %d" +msgstr "không thể nắm (handle) táºp tin kiểu %d" -#: builtin/init-db.c:357 +#: builtin/init-db.c:358 #, c-format msgid "unable to move %s to %s" msgstr "không di chuyển được %s và o %s" -#: builtin/init-db.c:362 +#: builtin/init-db.c:363 #, c-format msgid "Could not create git link %s" -msgstr "Không thể tạo liên kết git '%s'" +msgstr "Không thể tạo liên kết git “%sâ€" #. #. * TRANSLATORS: The first '%s' is either "Reinitialized #. * existing" or "Initialized empty", the second " shared" or #. * "", and the last '%s%s' is the verbatim directory name. #. -#: builtin/init-db.c:419 +#: builtin/init-db.c:420 #, c-format msgid "%s%s Git repository in %s%s\n" msgstr "%s%s kho Git trong %s%s\n" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Reinitialized existing" msgstr "Khởi tạo lại đã sẵn có rồi" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Initialized empty" msgstr "Khởi tạo trống rá»—ng" -#: builtin/init-db.c:421 +#: builtin/init-db.c:422 msgid " shared" msgstr " đã chia sẻ" -#: builtin/init-db.c:440 +#: builtin/init-db.c:441 msgid "cannot tell cwd" msgstr "không nói chuyện được vá»›i lệnh cwd" -#: builtin/init-db.c:521 -#: builtin/init-db.c:528 +#: builtin/init-db.c:467 +msgid "" +"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared" +"[=<permissions>]] [directory]" +msgstr "" +"git init [-q | --quiet] [--bare] [--template=<thư-mục-tạm>] [--shared[=<các-" +"quyá»n>]] [thư-mục]" + +#: builtin/init-db.c:490 +msgid "permissions" +msgstr "các quyá»n" + +#: builtin/init-db.c:491 +msgid "specify that the git repository is to be shared amongst several users" +msgstr "chỉ ra cái mà kho git được chia sẻ giữa nhiá»u ngưá»i dùng" + +#: builtin/init-db.c:493 builtin/prune-packed.c:77 +msgid "be quiet" +msgstr "im lặng" + +#: builtin/init-db.c:522 builtin/init-db.c:529 #, c-format msgid "cannot mkdir %s" msgstr "không thể mkdir (tạo thư mục): %s" -#: builtin/init-db.c:532 +#: builtin/init-db.c:533 #, c-format msgid "cannot chdir to %s" msgstr "không thể chdir (chuyển đổi thư mục) sang %s" -#: builtin/init-db.c:554 +#: builtin/init-db.c:555 #, c-format -msgid "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-dir=<directory>)" -msgstr "%s (hoặc --work-tree=<thư-mục>) không cho phép không chỉ định %s (hoặc --git-dir=<thư-mục>)" +msgid "" +"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" +"dir=<directory>)" +msgstr "" +"%s (hoặc --work-tree=<thư-mục>) không cho phép không chỉ định %s (hoặc --git-" +"dir=<thư-mục>)" -#: builtin/init-db.c:578 +#: builtin/init-db.c:579 msgid "Cannot access current working directory" msgstr "Không thể truy cáºp thư mục là m việc hiện hà nh" -#: builtin/init-db.c:585 +#: builtin/init-db.c:586 #, c-format msgid "Cannot access work tree '%s'" -msgstr "không thể truy cáºp cây (tree) là m việc '%s'" +msgstr "không thể truy cáºp cây (tree) là m việc “%sâ€" + +#: builtin/log.c:37 +msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n" +msgstr "git log [<các-tùy-chá»n>] [<kể-từ>..<cho-đến>] [[--] <đưá»ng-dẫn>...]\n" + +#: builtin/log.c:38 +msgid " or: git show [options] <object>..." +msgstr " or: git show [các-tùy-chá»n] <đối-tượng>..." -#: builtin/log.c:188 +#: builtin/log.c:100 +msgid "suppress diff output" +msgstr "chặn má»i kết xuất từ diff" + +#: builtin/log.c:101 +msgid "show source" +msgstr "hiển thị mã nguồn" + +#: builtin/log.c:102 +msgid "decorate options" +msgstr "các tùy chá»n trang trÃ" + +#: builtin/log.c:189 #, c-format msgid "Final output: %d %s\n" msgstr "Kết xuất cuối cùng: %d %s\n" -#: builtin/log.c:401 -#: builtin/log.c:489 +#: builtin/log.c:405 builtin/log.c:497 #, c-format msgid "Could not read object %s" msgstr "Không thể Ä‘á»c đối tượng %s" -#: builtin/log.c:513 +#: builtin/log.c:521 #, c-format msgid "Unknown type: %d" msgstr "Không nháºn ra kiểu: %d" -#: builtin/log.c:602 +#: builtin/log.c:613 msgid "format.headers without value" msgstr "format.headers không có giá trị cụ thể" -#: builtin/log.c:676 +#: builtin/log.c:687 msgid "name of output directory is too long" msgstr "tên cá»§a thư mục kết xuất quá dà i" -#: builtin/log.c:687 +#: builtin/log.c:698 #, c-format msgid "Cannot open patch file %s" msgstr "Không thể mở táºp tin miếng vá: %s" -#: builtin/log.c:701 +#: builtin/log.c:712 msgid "Need exactly one range." msgstr "Cần chÃnh xác má»™t vùng." -#: builtin/log.c:709 +#: builtin/log.c:720 msgid "Not a range." msgstr "Không phải là má»™t vùng." -#: builtin/log.c:786 +#: builtin/log.c:794 msgid "Cover letter needs email format" -msgstr "'Cover letter' cần cho định dạng thư" +msgstr "â€Cover letter†cần cho định dạng thư" -#: builtin/log.c:859 +#: builtin/log.c:867 #, c-format msgid "insane in-reply-to: %s" msgstr "in-reply-to Ä‘iên rồ: %s" -#: builtin/log.c:932 +#: builtin/log.c:895 +msgid "git format-patch [options] [<since> | <revision range>]" +msgstr "git format-patch [các-tùy-chá»n] [<kể-từ> | <vùng-xem-xét>]" + +#: builtin/log.c:940 msgid "Two output directories?" msgstr "Hai thư mục kết xuất?" -#: builtin/log.c:1153 +#: builtin/log.c:1068 +msgid "use [PATCH n/m] even with a single patch" +msgstr "dùng [PATCH n/m] ngay cả vá»›i miếng vá đơn" + +#: builtin/log.c:1071 +msgid "use [PATCH] even with multiple patches" +msgstr "dùng [VÃ] ngay cả vá»›i các miếng vá phức tạp" + +#: builtin/log.c:1075 +msgid "print patches to standard out" +msgstr "hiển thị miếng vá ra đầu ra chuẩn" + +#: builtin/log.c:1077 +msgid "generate a cover letter" +msgstr "tạo bì thư" + +#: builtin/log.c:1079 +msgid "use simple number sequence for output file names" +msgstr "sá» dụng chá»—i dãy số dạng đơn giản cho tên táºp-tin xuất ra" + +#: builtin/log.c:1080 +msgid "sfx" +msgstr "sfx" + +#: builtin/log.c:1081 +msgid "use <sfx> instead of '.patch'" +msgstr "sá» dụng <sfx> thay cho “.patchâ€" + +#: builtin/log.c:1083 +msgid "start numbering patches at <n> instead of 1" +msgstr "bắt đầu đánh số miếng vá từ <n> thay vì 1" + +#: builtin/log.c:1085 +msgid "Use [<prefix>] instead of [PATCH]" +msgstr "Dùng [<tiá»n-tố>] thay cho [VÃ]" + +#: builtin/log.c:1088 +msgid "store resulting files in <dir>" +msgstr "lưu các táºp tin kết quả trong <t.mục>" + +#: builtin/log.c:1091 +msgid "don't strip/add [PATCH]" +msgstr "không strip/add [VÃ]" + +#: builtin/log.c:1094 +msgid "don't output binary diffs" +msgstr "không kết xuất diff (những khác biệt) nhị phân" + +#: builtin/log.c:1096 +msgid "don't include a patch matching a commit upstream" +msgstr "không bao gồm miếng vá khá»›p vá»›i má»™t lần chuyển giao thượng nguồn" + +#: builtin/log.c:1098 +msgid "show patch format instead of default (patch + stat)" +msgstr "hiển thị định dạng miếng vá thay vì mặc định (miếng vá + thống kê)" + +#: builtin/log.c:1100 +msgid "Messaging" +msgstr "Lá»i nhắn" + +#: builtin/log.c:1101 +msgid "header" +msgstr "đầu đỠthư" + +#: builtin/log.c:1102 +msgid "add email header" +msgstr "thêm đầu đỠthư" + +#: builtin/log.c:1103 builtin/log.c:1105 +msgid "email" +msgstr "thư Ä‘iện tá»" + +#: builtin/log.c:1103 +msgid "add To: header" +msgstr "thêm To: đầu đỠthư" + +#: builtin/log.c:1105 +msgid "add Cc: header" +msgstr "thêm Cc: đầu đỠthư" + +#: builtin/log.c:1107 +msgid "message-id" +msgstr "message-id" + +#: builtin/log.c:1108 +msgid "make first mail a reply to <message-id>" +msgstr "dùng thư đầu tiên để trả lá»i <message-id>" + +#: builtin/log.c:1109 builtin/log.c:1112 +msgid "boundary" +msgstr "ranh giá»›i" + +#: builtin/log.c:1110 +msgid "attach the patch" +msgstr "Ä‘Ãnh kèm miếng vá" + +#: builtin/log.c:1113 +msgid "inline the patch" +msgstr "dùng miếng vá là m ná»™i dung" + +#: builtin/log.c:1117 +msgid "enable message threading, styles: shallow, deep" +msgstr "cho phép luồng lá»i nhắn, kiểu: “shallowâ€, “deepâ€" + +#: builtin/log.c:1119 +msgid "signature" +msgstr "chữ ký" + +#: builtin/log.c:1120 +msgid "add a signature" +msgstr "thêm chữ ký" + +#: builtin/log.c:1122 +msgid "don't print the patch filenames" +msgstr "không hiển thị các tên táºp tin cá»§a miếng vá" + +#: builtin/log.c:1163 #, c-format msgid "bogus committer info %s" msgstr "thông tin ngưá»i chuyển giao không có thá»±c %s" -#: builtin/log.c:1198 +#: builtin/log.c:1208 msgid "-n and -k are mutually exclusive." msgstr "-n và -k loại từ lẫn nhau." -#: builtin/log.c:1200 +#: builtin/log.c:1210 msgid "--subject-prefix and -k are mutually exclusive." msgstr "--subject-prefix và -k xung khắc nhau." -#: builtin/log.c:1208 +#: builtin/log.c:1218 msgid "--name-only does not make sense" msgstr "--name-only không hợp lý" -#: builtin/log.c:1210 +#: builtin/log.c:1220 msgid "--name-status does not make sense" msgstr "--name-status không hợp lý" -#: builtin/log.c:1212 +#: builtin/log.c:1222 msgid "--check does not make sense" msgstr "--check không hợp lý" -#: builtin/log.c:1235 +#: builtin/log.c:1245 msgid "standard output, or directory, which one?" msgstr "đầu ra chuẩn, hay thư mục, chá»n cái nà o?" -#: builtin/log.c:1237 +#: builtin/log.c:1247 #, c-format msgid "Could not create directory '%s'" -msgstr "Không thể tạo thư mục '%s'" +msgstr "Không thể tạo thư mục “%sâ€" -#: builtin/log.c:1390 +#: builtin/log.c:1400 msgid "Failed to create output files" msgstr "Gặp lá»—i khi tạo các táºp tin kết xuất" -#: builtin/log.c:1494 +#: builtin/log.c:1449 +msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]" +msgstr "git cherry [-v] [<thượng-nguồn> [<head> [<giá»›i-hạn>]]]" + +#: builtin/log.c:1504 #, c-format -msgid "Could not find a tracked remote branch, please specify <upstream> manually.\n" -msgstr "Không tìm thấy nhánh mạng bị theo vết, hãy chỉ định <dòng-ngược> má»™t cách thá»§ công.\n" +msgid "" +"Could not find a tracked remote branch, please specify <upstream> manually.\n" +msgstr "" +"Không tìm thấy nhánh mạng bị theo vết, hãy chỉ định <thượng-nguồn> má»™t cách " +"thá»§ công.\n" -#: builtin/log.c:1510 -#: builtin/log.c:1512 -#: builtin/log.c:1524 +#: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531 #, c-format msgid "Unknown commit %s" msgstr "Không hiểu lần chuyển giao (commit) %s" +#: builtin/ls-files.c:408 +msgid "git ls-files [options] [<file>...]" +msgstr "git ls-files [các-tùy-chá»n] [<táºp-tin>...]" + +#: builtin/ls-files.c:463 +msgid "identify the file status with tags" +msgstr "nháºn dạng các trạng thái táºp tin vá»›i thẻ" + +#: builtin/ls-files.c:465 +msgid "use lowercase letters for 'assume unchanged' files" +msgstr "" +"dùng chữ cái viết thưá»ng cho các táºp tin “assume unchanged†(giả định không " +"thay đổi)" + +#: builtin/ls-files.c:467 +msgid "show cached files in the output (default)" +msgstr "hiển thị các táºp tin được nhá»› tạm và o đầu ra (mặc định)" + +#: builtin/ls-files.c:469 +msgid "show deleted files in the output" +msgstr "hiển thị các táºp tin đã xóa trong kết xuất" + +#: builtin/ls-files.c:471 +msgid "show modified files in the output" +msgstr "hiển thị các táºp tin đã bị sá»a đổi ra kết xuất" + +#: builtin/ls-files.c:473 +msgid "show other files in the output" +msgstr "hiển thị các táºp tin khác trong kết xuất" + +#: builtin/ls-files.c:475 +msgid "show ignored files in the output" +msgstr "hiển thị các táºp tin bị bá» qua trong kết xuất" + +#: builtin/ls-files.c:478 +msgid "show staged contents' object name in the output" +msgstr "hiển thị tên đối tượng cá»§a ná»™i dung được lưu trạng thái ở kết xuất" + +#: builtin/ls-files.c:480 +msgid "show files on the filesystem that need to be removed" +msgstr "hiển thị các táºp tin trên hệ thống táºp tin mà nó cần được gỡ bá»" + +#: builtin/ls-files.c:482 +msgid "show 'other' directories' name only" +msgstr "chỉ hiển thị tên cá»§a các thư mục “khácâ€" + +#: builtin/ls-files.c:485 +msgid "don't show empty directories" +msgstr "không hiển thị thư mục rá»—ng" + +#: builtin/ls-files.c:488 +msgid "show unmerged files in the output" +msgstr "hiển thị các táºp tin chưa hòa trá»™n trong kết xuất" + +#: builtin/ls-files.c:490 +msgid "show resolve-undo information" +msgstr "hiển thị thông tin resolve-undo" + +#: builtin/ls-files.c:492 +msgid "skip files matching pattern" +msgstr "bá» qua những táºp tin khá»›p vá»›i má»™t mẫu" + +#: builtin/ls-files.c:495 +msgid "exclude patterns are read from <file>" +msgstr "mẫu loại trừ được Ä‘á»c từ <táºp tin>" + +#: builtin/ls-files.c:498 +msgid "read additional per-directory exclude patterns in <file>" +msgstr "Ä‘á»c thêm các mẫu ngoại trừ má»—i thư mục trong <táºp tin>" + +#: builtin/ls-files.c:500 +msgid "add the standard git exclusions" +msgstr "thêm loại trừ tiêu chuẩn kiểu git" + +#: builtin/ls-files.c:503 +msgid "make the output relative to the project top directory" +msgstr "là m cho kết xuất liên quan đến thư mục ở mức cao nhất (gốc) cá»§a dá»± án" + +#: builtin/ls-files.c:506 +msgid "if any <file> is not in the index, treat this as an error" +msgstr "nếu <táºp tin> bất kỳ không ở trong bảng mục lục, xá» lý nó như má»™t lá»—i" + +#: builtin/ls-files.c:507 +msgid "tree-ish" +msgstr "tree-ish" + +#: builtin/ls-files.c:508 +msgid "pretend that paths removed since <tree-ish> are still present" +msgstr "" +"giả định rằng các đưá»ng dẫn đã bị gỡ bá» kể từ <tree-ish> nay vẫn hiện diện" + +#: builtin/ls-files.c:510 +msgid "show debugging data" +msgstr "hiển thị dữ liệu gỡ lá»—i" + +#: builtin/ls-tree.c:27 +msgid "git ls-tree [<options>] <tree-ish> [<path>...]" +msgstr "git ls-tree [<các-tùy-chá»n>] <tree-ish> [<đưá»ng-dẫn>...]" + +#: builtin/ls-tree.c:125 +msgid "only show trees" +msgstr "chỉ hiển thị các tree" + +#: builtin/ls-tree.c:127 +msgid "recurse into subtrees" +msgstr "đệ quy và o các thư mục con" + +#: builtin/ls-tree.c:129 +msgid "show trees when recursing" +msgstr "hiển thị cây khi đệ quy" + +#: builtin/ls-tree.c:132 +msgid "terminate entries with NUL byte" +msgstr "chấm dứt mục tin vá»›i byte NUL" + +#: builtin/ls-tree.c:133 +msgid "include object size" +msgstr "gồm cả kÃch thước đối tượng" + +#: builtin/ls-tree.c:135 builtin/ls-tree.c:137 +msgid "list only filenames" +msgstr "chỉ liệt kê tên táºp tin" + +#: builtin/ls-tree.c:140 +msgid "use full path names" +msgstr "dùng tên đưá»ng dẫn đầy đủ" + +#: builtin/ls-tree.c:142 +msgid "list entire tree; not just current directory (implies --full-name)" +msgstr "liệt kê cây mục tin; không chỉ thư mục hiện hà nh (ngụ ý --full-name)" + +#: builtin/merge.c:43 +msgid "git merge [options] [<commit>...]" +msgstr "git merge [các-tùy-chá»n] [<commit>...]" + +#: builtin/merge.c:44 +msgid "git merge [options] <msg> HEAD <commit>" +msgstr "git merge [các-tùy-chá»n] <tin-nhắn> HEAD <commit>" + +#: builtin/merge.c:45 +msgid "git merge --abort" +msgstr "git merge --abort" + #: builtin/merge.c:90 msgid "switch `m' requires a value" msgstr "switch `m' yêu cầu má»™t giá trị" @@ -3420,7 +5783,7 @@ msgstr "switch `m' yêu cầu má»™t giá trị" #: builtin/merge.c:127 #, c-format msgid "Could not find merge strategy '%s'.\n" -msgstr "Không tìm thấy chiến lược hòa trá»™n '%s'.\n" +msgstr "Không tìm thấy chiến lược hòa trá»™n “%sâ€.\n" #: builtin/merge.c:128 #, c-format @@ -3432,6 +5795,67 @@ msgstr "Các chiến lược sẵn sà ng là :" msgid "Available custom strategies are:" msgstr "Các chiến lược tùy chỉnh sẵn sà ng là :" +#: builtin/merge.c:183 +msgid "do not show a diffstat at the end of the merge" +msgstr "không hiển thị thống kê khác biệt tại cuối cá»§a lần hòa trá»™n" + +#: builtin/merge.c:186 +msgid "show a diffstat at the end of the merge" +msgstr "hiển thị thống kê khác biệt tại cuối cá»§a hòa trá»™n" + +#: builtin/merge.c:187 +msgid "(synonym to --stat)" +msgstr "(đồng nghÄ©a vá»›i --stat)" + +#: builtin/merge.c:189 +msgid "add (at most <n>) entries from shortlog to merge commit message" +msgstr "thêm (Ãt nhất <n>) mục từ shortlog cho ghi chú chuyển giao hòa trá»™n" + +#: builtin/merge.c:192 +msgid "create a single commit instead of doing a merge" +msgstr "tạo má»™t lần chuyển giao (commit) đưon thay vì thá»±c hiện việc hòa trá»™n" + +#: builtin/merge.c:194 +msgid "perform a commit if the merge succeeds (default)" +msgstr "thá»±c hiện chuyển giao nếu hòa trá»™n thà nh công (mặc định)" + +#: builtin/merge.c:196 +msgid "edit message before committing" +msgstr "sá»a chú thÃch trước khi chuyển giao (commit)" + +#: builtin/merge.c:198 +msgid "allow fast-forward (default)" +msgstr "cho phép fast-forward (mặc định)" + +#: builtin/merge.c:200 +msgid "abort if fast-forward is not possible" +msgstr "bá» qua nếu fast-forward không thể được" + +#: builtin/merge.c:202 builtin/notes.c:870 builtin/revert.c:112 +msgid "strategy" +msgstr "chiến lược" + +#: builtin/merge.c:203 +msgid "merge strategy to use" +msgstr "chiến lược hòa trá»™n sẽ dùng" + +#: builtin/merge.c:204 +msgid "option=value" +msgstr "tùy_chá»n=giá_trị" + +#: builtin/merge.c:205 +msgid "option for selected merge strategy" +msgstr "tùy chá»n cho chiến lược hòa trá»™n đã chá»n" + +#: builtin/merge.c:207 +msgid "merge commit message (for a non-fast-forward merge)" +msgstr "" +"hòa trá»™n ghi chú cá»§a lần chuyển giao (dà nh cho hòa trá»™n non-fast-forward)" + +#: builtin/merge.c:211 +msgid "abort the current in-progress merge" +msgstr "bãi bá» quá trình hòa trá»™n hiện tại Ä‘ang thá»±c hiện" + #: builtin/merge.c:240 msgid "could not run stash." msgstr "không thể chạy stash." @@ -3445,14 +5869,13 @@ msgstr "stash gặp lá»—i" msgid "not a valid object: %s" msgstr "không phải là má»™t đối tượng hợp lệ: %s" -#: builtin/merge.c:269 -#: builtin/merge.c:286 +#: builtin/merge.c:269 builtin/merge.c:286 msgid "read-tree failed" msgstr "read-tree gặp lá»—i" #: builtin/merge.c:316 msgid " (nothing to squash)" -msgstr " (không có ghì để squash)" +msgstr " (không có gì để squash)" #: builtin/merge.c:329 #, c-format @@ -3472,53 +5895,47 @@ msgstr "Hoà n thà nh SQUASH_MSG" msgid "No merge message -- not updating HEAD\n" msgstr "Không thông Ä‘iệp hòa trá»™n -- không cáºp nháºt HEAD\n" -#: builtin/merge.c:437 +#: builtin/merge.c:436 #, c-format msgid "'%s' does not point to a commit" -msgstr "'%s' không chỉ đến má»™t lần chuyển giao (commit) nà o cả" +msgstr "“%s†không chỉ đến má»™t lần chuyển giao (commit) nà o cả" -#: builtin/merge.c:536 +#: builtin/merge.c:535 #, c-format msgid "Bad branch.%s.mergeoptions string: %s" msgstr "Chuá»—i branch.%s.mergeoptions sai: %s" -#: builtin/merge.c:629 +#: builtin/merge.c:628 msgid "git write-tree failed to write a tree" msgstr "lệnh git write-tree gặp lá»—i khi ghi má»™t cây" -#: builtin/merge.c:679 -msgid "failed to read the cache" -msgstr "gặp lá»—i khi Ä‘á»c bá»™ nhá»› tạm" - -#: builtin/merge.c:697 -msgid "Unable to write index." -msgstr "Không thể ghi bảng mục lục" - -#: builtin/merge.c:710 +#: builtin/merge.c:656 msgid "Not handling anything other than two heads merge." msgstr "Không cầm nắm gì ngoà i hai head hòa trá»™n" -#: builtin/merge.c:724 +#: builtin/merge.c:670 #, c-format msgid "Unknown option for merge-recursive: -X%s" msgstr "Không hiểu tùy chá»n cho merge-recursive: -X%s" -#: builtin/merge.c:738 +#: builtin/merge.c:684 #, c-format msgid "unable to write %s" -msgstr "không ghi được %s" +msgstr "không thể ghi %s" -#: builtin/merge.c:877 +#: builtin/merge.c:773 #, c-format msgid "Could not read from '%s'" -msgstr "Không thể Ä‘á»c từ '%s'" +msgstr "Không thể Ä‘á»c từ “%sâ€" -#: builtin/merge.c:886 +#: builtin/merge.c:782 #, c-format msgid "Not committing merge; use 'git commit' to complete the merge.\n" -msgstr "Vẫn chưa hòa trá»™n các lần chuyển giao (commit); sá» dụng lệnh 'git commit' để hoà n tất việc hòa trá»™n.\n" +msgstr "" +"Vẫn chưa hòa trá»™n các lần chuyển giao (commit); sá» dụng lệnh “git commit†để " +"hoà n tất việc hòa trá»™n.\n" -#: builtin/merge.c:892 +#: builtin/merge.c:788 msgid "" "Please enter a commit message to explain why this merge is necessary,\n" "especially if it merges an updated upstream into a topic branch.\n" @@ -3526,60 +5943,64 @@ msgid "" "Lines starting with '#' will be ignored, and an empty message aborts\n" "the commit.\n" msgstr "" -"Hãy nháºp và o các thông tin để giải thÃch tại sao sá»± hòa trá»™n nà y là cần thiết,\n" -"đặc biệt là khi nó hòa trá»™n dòng ngược đã cáºp nháºt và o trong má»™t nhánh topic.\n" +"Hãy nháºp và o các thông tin để giải thÃch tại sao sá»± hòa trá»™n nà y là cần " +"thiết,\n" +"đặc biệt là khi nó hòa trá»™n thượng nguồn đã cáºp nháºt và o trong má»™t nhánh " +"topic.\n" "\n" -"Những dòng được bắt đầu bằng '#' sẽ được bá» qua, và phần chú thÃch nà y nếu rá»—ng\n" +"Những dòng được bắt đầu bằng “#†sẽ được bá» qua, và phần chú thÃch nà y nếu " +"rá»—ng\n" "sẽ là m há»§y bá» lần chuyển giao (commit).\n" -#: builtin/merge.c:916 +#: builtin/merge.c:812 msgid "Empty commit message." msgstr "Chú thÃch cá»§a lần commit (chuyển giao) bị trống rá»—ng." -#: builtin/merge.c:928 +#: builtin/merge.c:824 #, c-format msgid "Wonderful.\n" msgstr "Thần kỳ.\n" -#: builtin/merge.c:993 +#: builtin/merge.c:889 #, c-format msgid "Automatic merge failed; fix conflicts and then commit the result.\n" -msgstr "Việc tá»± động hòa trá»™n gặp lá»—i; hãy sá»a các xung đột sau đó chuyển giao (commit) kết quả.\n" +msgstr "" +"Việc tá»± động hòa trá»™n gặp lá»—i; hãy sá»a các xung đột sau đó chuyển giao " +"(commit) kết quả.\n" -#: builtin/merge.c:1009 +#: builtin/merge.c:905 #, c-format msgid "'%s' is not a commit" msgstr "%s không phải là má»™t lần commit (chuyển giao)" -#: builtin/merge.c:1050 +#: builtin/merge.c:946 msgid "No current branch." msgstr "không phải nhánh hiện hà nh" -#: builtin/merge.c:1052 +#: builtin/merge.c:948 msgid "No remote for the current branch." msgstr "Không có máy chá»§ cho nhánh hiện hà nh." -#: builtin/merge.c:1054 +#: builtin/merge.c:950 msgid "No default upstream defined for the current branch." -msgstr "Không có dòng ngược mặc định được định nghÄ©a cho nhánh hiện hà nh." +msgstr "Không có thượng nguồn mặc định được định nghÄ©a cho nhánh hiện hà nh." -#: builtin/merge.c:1059 +#: builtin/merge.c:955 #, c-format msgid "No remote tracking branch for %s from %s" msgstr "Không nhánh mạng theo vết cho %s từ %s" -#: builtin/merge.c:1146 -#: builtin/merge.c:1303 +#: builtin/merge.c:1042 builtin/merge.c:1199 #, c-format msgid "%s - not something we can merge" msgstr "%s - không phải là má»™t số thứ chúng tôi có thể hòa trá»™n" -#: builtin/merge.c:1214 +#: builtin/merge.c:1110 msgid "There is no merge to abort (MERGE_HEAD missing)." -msgstr "Ở đây không có lần hòa trá»™n nà o được há»§y bá» giữa chừng cả (không thấy MERGE_HEAD)." +msgstr "" +"Ở đây không có lần hòa trá»™n nà o được há»§y bá» giữa chừng cả (thiếu MERGE_HEAD)." -#: builtin/merge.c:1230 -#: git-pull.sh:31 +#: builtin/merge.c:1126 git-pull.sh:31 msgid "" "You have not concluded your merge (MERGE_HEAD exists).\n" "Please, commit your changes before you can merge." @@ -3587,12 +6008,11 @@ msgstr "" "Bạn chưa kết thúc việc hòa trá»™ng (MERGE_HEAD vẫn tồn tại).\n" "Hãy chuyển giao (commit) các thay đổi trước khi bạn có thể hòa trá»™n." -#: builtin/merge.c:1233 -#: git-pull.sh:34 +#: builtin/merge.c:1129 git-pull.sh:34 msgid "You have not concluded your merge (MERGE_HEAD exists)." msgstr "Bạn chưa kết thúc việc hòa trá»™ng (MERGE_HEAD vẫn tồn tại)." -#: builtin/merge.c:1237 +#: builtin/merge.c:1133 msgid "" "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" "Please, commit your changes before you can merge." @@ -3600,88 +6020,195 @@ msgstr "" "Bạn chưa kết thúc việc cherry-pick (CHERRY_PICK_HEAD vẫn tồn tại).\n" "Hãy chuyển giao (commit) các thay đổi trước khi bạn có thể hòa trá»™n." -#: builtin/merge.c:1240 +#: builtin/merge.c:1136 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)." msgstr "Bạn chưa kết thúc việc cherry-pick (CHERRY_PICK_HEAD vẫn tồn tại)." -#: builtin/merge.c:1249 +#: builtin/merge.c:1145 msgid "You cannot combine --squash with --no-ff." -msgstr "Bạn không thể tổ hợp --squash vá»›i --no-ff." +msgstr "Bạn không thể kết hợp --squash vá»›i --no-ff." -#: builtin/merge.c:1254 +#: builtin/merge.c:1150 msgid "You cannot combine --no-ff with --ff-only." -msgstr "Bạn không thể tổ hợp --no-ff vá»›i --ff-only." +msgstr "Bạn không thể kết hợp --no-ff vá»›i --ff-only." -#: builtin/merge.c:1261 +#: builtin/merge.c:1157 msgid "No commit specified and merge.defaultToUpstream not set." -msgstr "Không chỉ ra lần chuyển giao (commit) và merge.defaultToUpstream chưa được đặt." +msgstr "" +"Không chỉ ra lần chuyển giao (commit) và merge.defaultToUpstream chưa được " +"đặt." -#: builtin/merge.c:1293 +#: builtin/merge.c:1189 msgid "Can merge only exactly one commit into empty head" -msgstr "Không thể hòa trá»™n má»™t cách đúng đắn má»™t lần chuyển giao (commit) và o má»™t head rá»—ng" +msgstr "" +"Không thể hòa trá»™n má»™t cách đúng đắn má»™t lần chuyển giao (commit) và o má»™t " +"head rá»—ng" -#: builtin/merge.c:1296 +#: builtin/merge.c:1192 msgid "Squash commit into empty head not supported yet" msgstr "Squash commit và o má»™t head trống rá»—ng vẫn chưa được há»— trợ" -#: builtin/merge.c:1298 +#: builtin/merge.c:1194 msgid "Non-fast-forward commit does not make sense into an empty head" -msgstr "Chuyển giao (commit) không-fast-forward không hợp lý ở trong má»™t head trống rá»—ng" +msgstr "" +"Chuyển giao (commit) không-fast-forward không hợp lý ở trong má»™t head trống " +"rá»—ng" -#: builtin/merge.c:1413 +#: builtin/merge.c:1309 #, c-format msgid "Updating %s..%s\n" msgstr "Äang cáºp nháºt %s..%s\n" -#: builtin/merge.c:1451 +#: builtin/merge.c:1348 #, c-format msgid "Trying really trivial in-index merge...\n" -msgstr "Äang thá» hòa trá»™n kiểu 'trivial in-index'...\n" +msgstr "Äang thá» hòa trá»™n kiểu “trivial in-indexâ€...\n" -#: builtin/merge.c:1458 +#: builtin/merge.c:1355 #, c-format msgid "Nope.\n" msgstr "Không.\n" -#: builtin/merge.c:1490 +#: builtin/merge.c:1387 msgid "Not possible to fast-forward, aborting." msgstr "Thá»±c hiện lệnh fast-forward là không thể được, Ä‘ang bá» qua." -#: builtin/merge.c:1513 -#: builtin/merge.c:1592 +#: builtin/merge.c:1410 builtin/merge.c:1489 #, c-format msgid "Rewinding the tree to pristine...\n" msgstr "Äang tua lại cây thà nh thá»i xa xưa...\n" -#: builtin/merge.c:1517 +#: builtin/merge.c:1414 #, c-format msgid "Trying merge strategy %s...\n" msgstr "Äang thá» chiến lược hòa trá»™n %s...\n" -#: builtin/merge.c:1583 +#: builtin/merge.c:1480 #, c-format msgid "No merge strategy handled the merge.\n" msgstr "Không có chiến lược hòa trá»™n nà o được nắm giữ (handle) sá»± hòa trá»™n.\n" -#: builtin/merge.c:1585 +#: builtin/merge.c:1482 #, c-format msgid "Merge with strategy %s failed.\n" msgstr "Hòa trá»™n vá»›i chiến lược %s gặp lá»—i.\n" -#: builtin/merge.c:1594 +#: builtin/merge.c:1491 #, c-format msgid "Using the %s to prepare resolving by hand.\n" msgstr "Sá» dụng %s để chuẩn bị giải quyết bằng tay.\n" -#: builtin/merge.c:1606 +#: builtin/merge.c:1503 #, c-format msgid "Automatic merge went well; stopped before committing as requested\n" -msgstr "Hòa trá»™n tá»± động đã trở nên tốt; bị dừng trước khi việc chuyển giao được yêu cầu\n" +msgstr "" +"Hòa trá»™n tá»± động đã trở nên tốt; bị dừng trước khi việc chuyển giao được yêu " +"cầu\n" + +#: builtin/merge-base.c:26 +msgid "git merge-base [-a|--all] <commit> <commit>..." +msgstr "git merge-base [-a|--all] <commit> <commit>..." + +#: builtin/merge-base.c:27 +msgid "git merge-base [-a|--all] --octopus <commit>..." +msgstr "git merge-base [-a|--all] --octopus <lần commit>..." + +#: builtin/merge-base.c:28 +msgid "git merge-base --independent <commit>..." +msgstr "git merge-base --independent <lần commit>..." + +#: builtin/merge-base.c:29 +msgid "git merge-base --is-ancestor <commit> <commit>" +msgstr "git merge-base --is-ancestor <commit> <commit>" + +#: builtin/merge-base.c:98 +msgid "output all common ancestors" +msgstr "xuất ra tất cả các ông bà , tổ tiên chung" + +#: builtin/merge-base.c:99 +msgid "find ancestors for a single n-way merge" +msgstr "tìm tổ tiên cá»§a hòa trá»™n n-way đơn" + +#: builtin/merge-base.c:100 +msgid "list revs not reachable from others" +msgstr "liệt kê các “rev†mà nó không thể Ä‘á»c được từ cái khác" + +#: builtin/merge-base.c:102 +msgid "is the first one ancestor of the other?" +msgstr "là cha mẹ đầu tiên cá»§a cái khác?" + +#: builtin/merge-file.c:8 +msgid "" +"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file " +"file2" +msgstr "" +"git merge-file [các-tùy-chá»n] [-L tên1 [-L gốc [-L tên2]]] táºp-tin1 táºp-tin-" +"gốc táºp-tin2" + +#: builtin/merge-file.c:33 +msgid "send results to standard output" +msgstr "gá»i kết quả và o đầu ra tiêu chuẩn" + +#: builtin/merge-file.c:34 +msgid "use a diff3 based merge" +msgstr "dùng kiểu hòa dá»±a trên diff3" + +#: builtin/merge-file.c:35 +msgid "for conflicts, use our version" +msgstr "để tránh xung đột, sá» dụng phiên bản cá»§a chúng ta" + +#: builtin/merge-file.c:37 +msgid "for conflicts, use their version" +msgstr "để tránh xung đột, sá» dụng phiên bản cá»§a há»" + +#: builtin/merge-file.c:39 +msgid "for conflicts, use a union version" +msgstr "để tránh xung đột, sá» dụng phiên bản kết hợp" + +#: builtin/merge-file.c:42 +msgid "for conflicts, use this marker size" +msgstr "để tránh xung đột, hãy sá» dụng kÃch thước bá»™ tạo nà y" + +#: builtin/merge-file.c:43 +msgid "do not warn about conflicts" +msgstr "không cảnh báo vá» các xung đột xảy ra" + +#: builtin/merge-file.c:45 +msgid "set labels for file1/orig_file/file2" +msgstr "đặt nhãn cho táºp-tin-1/táºp-tin-gốc/táºp-tin-2" + +#: builtin/mktree.c:67 +msgid "git mktree [-z] [--missing] [--batch]" +msgstr "git mktree [-z] [--missing] [--batch]" + +#: builtin/mktree.c:153 +msgid "input is NUL terminated" +msgstr "đầu và o được chấm dứt bởi NUL" + +#: builtin/mktree.c:154 builtin/write-tree.c:24 +msgid "allow missing objects" +msgstr "cho phép thiếu đối tượng" + +#: builtin/mktree.c:155 +msgid "allow creation of more than one tree" +msgstr "cho phép tạo nhiá»u hÆ¡n má»™t cây" + +#: builtin/mv.c:14 +msgid "git mv [options] <source>... <destination>" +msgstr "git mv [các-tùy-chá»n] <nguồn>... <Ä‘Ãch>" + +#: builtin/mv.c:64 +msgid "force move/rename even if target exists" +msgstr "ép buá»™c di chuyển hay đổi tên tháºm chà cả khi Ä‘Ãch đã tồn tại" + +#: builtin/mv.c:65 +msgid "skip move/rename errors" +msgstr "bá» qua các lá»—i liên quan đến di chuyển, đổi tên" #: builtin/mv.c:108 #, c-format msgid "Checking rename of '%s' to '%s'\n" -msgstr "Äang kiểm tra việc đổi tên cá»§a '%s' thà nh '%s'\n" +msgstr "Äang kiểm tra việc đổi tên cá»§a “%s†thà nh “%sâ€\n" #: builtin/mv.c:112 msgid "bad source" @@ -3715,11 +6242,11 @@ msgstr "Ä‘Ãch đã tồn tại sẵn rồi" #: builtin/mv.c:181 #, c-format msgid "overwriting '%s'" -msgstr "Ä‘ang ghi đè lên '%s'" +msgstr "Ä‘ang ghi đè lên “%sâ€" #: builtin/mv.c:184 msgid "Cannot overwrite" -msgstr "Không thể ghi chèn" +msgstr "Không thể ghi đè" #: builtin/mv.c:187 msgid "multiple sources for the same target" @@ -3733,202 +6260,597 @@ msgstr "%s, nguồn=%s, Ä‘Ãch=%s" #: builtin/mv.c:212 #, c-format msgid "Renaming %s to %s\n" -msgstr "Äang thay đổi tên %s thà nh %s\n" +msgstr "Äổi tên %s thà nh %s\n" -#: builtin/mv.c:215 -#: builtin/remote.c:731 +#: builtin/mv.c:215 builtin/remote.c:731 #, c-format msgid "renaming '%s' failed" msgstr "đổi tên %s gặp lá»—i" -#: builtin/notes.c:139 +#: builtin/name-rev.c:175 +msgid "git name-rev [options] <commit>..." +msgstr "git name-rev [các-tùy-chá»n] <commit>..." + +#: builtin/name-rev.c:176 +msgid "git name-rev [options] --all" +msgstr "git name-rev [các-tùy-chá»n] --all" + +#: builtin/name-rev.c:177 +msgid "git name-rev [options] --stdin" +msgstr "git name-rev [các-tùy-chá»n] --stdin" + +#: builtin/name-rev.c:229 +msgid "print only names (no SHA-1)" +msgstr "chỉ hiển thị tên (không SHA-1)" + +#: builtin/name-rev.c:230 +msgid "only use tags to name the commits" +msgstr "chỉ dùng các thẻ để đặt tên cho các lần chuyển giao" + +#: builtin/name-rev.c:232 +msgid "only use refs matching <pattern>" +msgstr "chỉ sá» dụng các tham chiếu (refs) khá»›p vá»›i <mẫu>" + +#: builtin/name-rev.c:234 +msgid "list all commits reachable from all refs" +msgstr "" +"liệt kê tất cả các lần chuyển giao có thể Ä‘á»c được từ tất cả các tham chiếu" + +#: builtin/name-rev.c:235 +msgid "read from stdin" +msgstr "Ä‘á»c từ đầu và o tiêu chuẩn" + +#: builtin/name-rev.c:236 +msgid "allow to print `undefined` names" +msgstr "cho phép hiển thị các tên `chưa định nghÄ©a`" + +#: builtin/notes.c:26 +msgid "git notes [--ref <notes_ref>] [list [<object>]]" +msgstr "git notes [--ref <notes_ref>] [list [<đối-tượng>]]" + +#: builtin/notes.c:27 +msgid "" +"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) " +"<object>] [<object>]" +msgstr "" +"git notes [--ref <notes_ref>] add [-f] [-m <lá»i-nhắn> | -F <táºp-tin> | (-c | " +"-C) <đối-tượng>] [<đối-tượng>]" + +#: builtin/notes.c:28 +msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>" +msgstr "git notes [--ref <notes_ref>] copy [-f] <từ-đối-tượng> <đến-đối-tượng>" + +#: builtin/notes.c:29 +msgid "" +"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) " +"<object>] [<object>]" +msgstr "" +"git notes [--ref <notes_ref>] append [-m <lá»i-nhắn> | -F <táºp-tin> | (-c | -" +"C) <đối-tượng>] [<đối-tượng>]" + +#: builtin/notes.c:30 +msgid "git notes [--ref <notes_ref>] edit [<object>]" +msgstr "git notes [--ref <notes_ref>] edit [<đối-tượng>]" + +#: builtin/notes.c:31 +msgid "git notes [--ref <notes_ref>] show [<object>]" +msgstr "git notes [--ref <notes_ref>] show [<đối-tượng>]" + +#: builtin/notes.c:32 +msgid "" +"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>" +msgstr "" +"git notes [--ref <notes_ref>] merge [-v | -q] [-s <chiến-lược> ] <notes_ref>" + +#: builtin/notes.c:33 +msgid "git notes merge --commit [-v | -q]" +msgstr "git notes merge --commit [-v | -q]" + +#: builtin/notes.c:34 +msgid "git notes merge --abort [-v | -q]" +msgstr "git notes merge --abort [-v | -q]" + +#: builtin/notes.c:35 +msgid "git notes [--ref <notes_ref>] remove [<object>...]" +msgstr "git notes [--ref <notes_ref>] remove [<đối-tượng>...]" + +#: builtin/notes.c:36 +msgid "git notes [--ref <notes_ref>] prune [-n | -v]" +msgstr "git notes [--ref <notes_ref>] prune [-n | -v]" + +#: builtin/notes.c:37 +msgid "git notes [--ref <notes_ref>] get-ref" +msgstr "git notes [--ref <notes_ref>] get-ref" + +#: builtin/notes.c:42 +msgid "git notes [list [<object>]]" +msgstr "git notes [list [<đối tượng>]]" + +#: builtin/notes.c:47 +msgid "git notes add [<options>] [<object>]" +msgstr "git notes add [<các-tùy-chá»n>] [<đối-tượng>]" + +#: builtin/notes.c:52 +msgid "git notes copy [<options>] <from-object> <to-object>" +msgstr "git notes copy [<các-tùy-chá»n>] <từ-đối-tượng> <đến-đối-tượng>" + +#: builtin/notes.c:53 +msgid "git notes copy --stdin [<from-object> <to-object>]..." +msgstr "git notes copy --stdin [<từ-đối-tượng> <đến-đối-tượng>]..." + +#: builtin/notes.c:58 +msgid "git notes append [<options>] [<object>]" +msgstr "git notes append [<các-tùy-chá»n>] [<đối-tượng>]" + +#: builtin/notes.c:63 +msgid "git notes edit [<object>]" +msgstr "git notes edit [<đối tượng>]" + +#: builtin/notes.c:68 +msgid "git notes show [<object>]" +msgstr "git notes show [<đối tượng>]" + +#: builtin/notes.c:73 +msgid "git notes merge [<options>] <notes_ref>" +msgstr "git notes merge [<các-tùy-chá»n>] <notes_ref>" + +#: builtin/notes.c:74 +msgid "git notes merge --commit [<options>]" +msgstr "git notes merge --commit [<các-tùy-chá»n>]" + +#: builtin/notes.c:75 +msgid "git notes merge --abort [<options>]" +msgstr "git notes merge --abort [<các-tùy-chá»n>]" + +#: builtin/notes.c:80 +msgid "git notes remove [<object>]" +msgstr "git notes remove [<đối tượng>]" + +#: builtin/notes.c:85 +msgid "git notes prune [<options>]" +msgstr "git notes prune [<các-tùy-chá»n>]" + +#: builtin/notes.c:90 +msgid "git notes get-ref" +msgstr "git notes get-ref" + +#: builtin/notes.c:142 #, c-format msgid "unable to start 'show' for object '%s'" -msgstr "không thể khởi chạy 'show' cho đối tượng '%s'" +msgstr "không thể khởi chạy “show†cho đối tượng “%sâ€" -#: builtin/notes.c:145 +#: builtin/notes.c:148 msgid "can't fdopen 'show' output fd" -msgstr "không thể fdopen 'show' (lệnh hiển thị) mô tả táºp tin (fd) kết xuất" +msgstr "không thể fdopen “show†(lệnh hiển thị) mô tả táºp tin (fd) kết xuất" -#: builtin/notes.c:155 +#: builtin/notes.c:158 #, c-format msgid "failed to close pipe to 'show' for object '%s'" -msgstr "gặp lá»—i khi đóng đưá»ng ống cho lệnh 'show' cho đối tượng '%s'" +msgstr "gặp lá»—i khi đóng đưá»ng ống cho lệnh “show†cho đối tượng “%sâ€" -#: builtin/notes.c:158 +#: builtin/notes.c:161 #, c-format msgid "failed to finish 'show' for object '%s'" -msgstr "gặp lá»—i khi hoà n thà nh 'show' cho đối tượng '%s'" +msgstr "gặp lá»—i khi hoà n thà nh “show†cho đối tượng “%sâ€" -#: builtin/notes.c:175 -#: builtin/tag.c:347 +#: builtin/notes.c:178 builtin/tag.c:347 #, c-format msgid "could not create file '%s'" -msgstr "không thể tạo táºp tin '%s'" +msgstr "không thể tạo táºp tin “%sâ€" -#: builtin/notes.c:189 +#: builtin/notes.c:192 msgid "Please supply the note contents using either -m or -F option" -msgstr "Xin hãy áp dụng ná»™i dung cá»§a ghi chú sá» dụng hoặc là tùy chá»n -m hoặc là -F" +msgstr "" +"Xin hãy áp dụng ná»™i dung cá»§a ghi chú sá» dụng hoặc là tùy chá»n -m hoặc là -F" -#: builtin/notes.c:210 -#: builtin/notes.c:973 +#: builtin/notes.c:213 builtin/notes.c:976 #, c-format msgid "Removing note for object %s\n" msgstr "Äang gỡ bá» ghi chú (note) cho đối tượng %s\n" -#: builtin/notes.c:215 +#: builtin/notes.c:218 msgid "unable to write note object" msgstr "không thể ghi đối tượng ghi chú (note)" -#: builtin/notes.c:217 +#: builtin/notes.c:220 #, c-format msgid "The note contents has been left in %s" msgstr "Ná»™i dung ghi chú còn lại %s" -#: builtin/notes.c:251 -#: builtin/tag.c:542 +#: builtin/notes.c:254 builtin/tag.c:542 #, c-format msgid "cannot read '%s'" -msgstr "không thể Ä‘á»c '%s'" +msgstr "không thể Ä‘á»c “%sâ€" -#: builtin/notes.c:253 -#: builtin/tag.c:545 +#: builtin/notes.c:256 builtin/tag.c:545 #, c-format msgid "could not open or read '%s'" -msgstr "không thể mở để Ä‘á»c hay ghi '%s'" - -#: builtin/notes.c:272 -#: builtin/notes.c:445 -#: builtin/notes.c:447 -#: builtin/notes.c:507 -#: builtin/notes.c:561 -#: builtin/notes.c:644 -#: builtin/notes.c:649 -#: builtin/notes.c:724 -#: builtin/notes.c:766 -#: builtin/notes.c:968 -#: builtin/reset.c:293 -#: builtin/tag.c:558 +msgstr "không thể mở để Ä‘á»c hay ghi “%sâ€" + +#: builtin/notes.c:275 builtin/notes.c:448 builtin/notes.c:450 +#: builtin/notes.c:510 builtin/notes.c:564 builtin/notes.c:647 +#: builtin/notes.c:652 builtin/notes.c:727 builtin/notes.c:769 +#: builtin/notes.c:971 builtin/reset.c:293 builtin/tag.c:558 #, c-format msgid "Failed to resolve '%s' as a valid ref." -msgstr "Gặp lá»—i khi giải quyết '%s' như là má»™t tham chiếu (ref) hợp lệ." +msgstr "Gặp lá»—i khi giải quyết “%s†như là má»™t tham chiếu (ref) hợp lệ." -#: builtin/notes.c:275 +#: builtin/notes.c:278 #, c-format msgid "Failed to read object '%s'." -msgstr "Gặp lá»—i khi Ä‘á»c đối tượng '%s'." +msgstr "Gặp lá»—i khi Ä‘á»c đối tượng “%sâ€." -#: builtin/notes.c:299 +#: builtin/notes.c:302 msgid "Cannot commit uninitialized/unreferenced notes tree" -msgstr "Không thể chuyển giao (commit) chưa được khởi tạo hoặc không được tham chiếu cây ghi chú" +msgstr "" +"Không thể chuyển giao (commit) chưa được khởi tạo hoặc không được tham chiếu " +"cây ghi chú" -#: builtin/notes.c:340 +#: builtin/notes.c:343 #, c-format msgid "Bad notes.rewriteMode value: '%s'" -msgstr "Giá trị notes.rewriteMode sai: '%s'" +msgstr "Giá trị notes.rewriteMode sai: “%sâ€" -#: builtin/notes.c:350 +#: builtin/notes.c:353 #, c-format msgid "Refusing to rewrite notes in %s (outside of refs/notes/)" msgstr "Từ chối ghi đè ghi chú trong %s (nằm ngoà i cá»§a refs/notes/)" #. TRANSLATORS: The first %s is the name of the #. environment variable, the second %s is its value -#: builtin/notes.c:377 +#: builtin/notes.c:380 #, c-format msgid "Bad %s value: '%s'" -msgstr "Giá trị %s sai: '%s'" +msgstr "Giá trị %s sai: “%sâ€" -#: builtin/notes.c:441 +#: builtin/notes.c:444 #, c-format msgid "Malformed input line: '%s'." -msgstr "Dòng nháºp và o dị hình: '%s'." +msgstr "Dòng nháºp và o dị hình: “%sâ€." -#: builtin/notes.c:456 +#: builtin/notes.c:459 #, c-format msgid "Failed to copy notes from '%s' to '%s'" -msgstr "Gặp lá»—i khi sao chép ghi chú (note) từ '%s' tá»›i '%s'" - -#: builtin/notes.c:500 -#: builtin/notes.c:554 -#: builtin/notes.c:627 -#: builtin/notes.c:639 -#: builtin/notes.c:712 -#: builtin/notes.c:759 -#: builtin/notes.c:1033 +msgstr "Gặp lá»—i khi sao chép ghi chú (note) từ “%s†tá»›i “%sâ€" + +#: builtin/notes.c:503 builtin/notes.c:557 builtin/notes.c:630 +#: builtin/notes.c:642 builtin/notes.c:715 builtin/notes.c:762 +#: builtin/notes.c:1036 msgid "too many parameters" msgstr "quá nhiá»u đối số" -#: builtin/notes.c:513 -#: builtin/notes.c:772 +#: builtin/notes.c:516 builtin/notes.c:775 #, c-format msgid "No note found for object %s." -msgstr "không ghi chú được tìm thấy cho đối tượng %s." +msgstr "không tìm thấy ghi chú cho đối tượng %s." + +#: builtin/notes.c:538 builtin/notes.c:695 +msgid "note contents as a string" +msgstr "ná»™i dung ghi chú (note) nằm trong má»™t chuá»—i" + +#: builtin/notes.c:541 builtin/notes.c:698 +msgid "note contents in a file" +msgstr "ná»™i dung ghi chú (note) nằm trong má»™t táºp tin" + +#: builtin/notes.c:543 builtin/notes.c:546 builtin/notes.c:700 +#: builtin/notes.c:703 builtin/tag.c:476 +msgid "object" +msgstr "đối tượng" + +#: builtin/notes.c:544 builtin/notes.c:701 +msgid "reuse and edit specified note object" +msgstr "dùng lại nhưng có sá»a chữa đối tượng note đã chỉ ra" + +#: builtin/notes.c:547 builtin/notes.c:704 +msgid "reuse specified note object" +msgstr "dùng lại đối tượng ghi chú (note) đã chỉ ra" + +#: builtin/notes.c:549 builtin/notes.c:617 +msgid "replace existing notes" +msgstr "thay thế ghi chú trước" -#: builtin/notes.c:580 +#: builtin/notes.c:583 #, c-format -msgid "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite existing notes" -msgstr "Không thể thêm các ghi chú. Äã tìm thấy các ghi chú đã sẵn có cho đối tượng %s. Sá» dụng tùy chá»n '-f' để ghi đè lên các ghi chú cÅ©" +msgid "" +"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite " +"existing notes" +msgstr "" +"Không thể thêm các ghi chú. Äã tìm thấy các ghi chú đã có sẵn cho đối tượng " +"%s. Sá» dụng tùy chá»n “-f†để ghi đè lên các ghi chú cÅ©" -#: builtin/notes.c:585 -#: builtin/notes.c:662 +#: builtin/notes.c:588 builtin/notes.c:665 #, c-format msgid "Overwriting existing notes for object %s\n" msgstr "Äang ghi đè lên ghi chú cÅ© cho đối tượng %s\n" -#: builtin/notes.c:635 +#: builtin/notes.c:618 +msgid "read objects from stdin" +msgstr "Ä‘á»c các đối tượng từ đầu và o tiêu chuẩn" + +#: builtin/notes.c:620 +msgid "load rewriting config for <command> (implies --stdin)" +msgstr "tải cấu hình chép lại cho <lệnh> (ngầm định là --stdin)" + +#: builtin/notes.c:638 msgid "too few parameters" msgstr "quá Ãt đối số" -#: builtin/notes.c:656 +#: builtin/notes.c:659 #, c-format -msgid "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite existing notes" -msgstr "Không thể sao chép các ghi chú. Äã tìm thấy các ghi chú đã sẵn có cho đối tượng %s. Sá» dụng tùy chá»n '-f' để ghi đè lên các ghi chú cÅ©" +msgid "" +"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite " +"existing notes" +msgstr "" +"Không thể sao chép các ghi chú. Äã tìm thấy các ghi chú đã có sẵn cho đối " +"tượng %s. Sá» dụng tùy chá»n “-f†để ghi đè lên các ghi chú cÅ©" -#: builtin/notes.c:668 +#: builtin/notes.c:671 #, c-format msgid "Missing notes on source object %s. Cannot copy." msgstr "Thiếu ghi chú trên đối tượng nguốn %s. Không thể sao chép." -#: builtin/notes.c:717 +#: builtin/notes.c:720 #, c-format msgid "" "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n" "Please use 'git notes add -f -m/-F/-c/-C' instead.\n" msgstr "" -"Các tùy chá»n -m/-F/-c/-C đã cổ không còn dùng nữa cho lệnh con 'edit'.\n" -"Xin hãy sá» dụng lệnh sau để thay thế: 'git notes add -f -m/-F/-c/-C'.\n" +"Các tùy chá»n -m/-F/-c/-C đã cổ không còn dùng nữa cho lệnh con “editâ€.\n" +"Xin hãy sá» dụng lệnh sau để thay thế: “git notes add -f -m/-F/-c/-Câ€.\n" + +#: builtin/notes.c:867 +msgid "General options" +msgstr "Tùy chá»n chung" + +#: builtin/notes.c:869 +msgid "Merge options" +msgstr "Tùy chá»n vá» hòa trá»™n" + +#: builtin/notes.c:871 +msgid "" +"resolve notes conflicts using the given strategy (manual/ours/theirs/union/" +"cat_sort_uniq)" +msgstr "" +"phân giải các xung đột “notes†sá» dụng chiến lược đã đưa ra (manual/ours/" +"theirs/union/cat_sort_uniq)" + +#: builtin/notes.c:873 +msgid "Committing unmerged notes" +msgstr "Chuyển giao các note chưa được hòa trá»™n" -#: builtin/notes.c:971 +#: builtin/notes.c:875 +msgid "finalize notes merge by committing unmerged notes" +msgstr "" +"các note cuối cùng được hòa trá»™n bởi các note chưa hòa trá»™n cá»§a lần chuyển " +"giao" + +#: builtin/notes.c:877 +msgid "Aborting notes merge resolution" +msgstr "Há»§y bá» phân giải ghi chú (note) hòa trá»™n" + +#: builtin/notes.c:879 +msgid "abort notes merge" +msgstr "bá» qua hòa trá»™n các ghi chú (note)" + +#: builtin/notes.c:974 #, c-format msgid "Object %s has no note\n" msgstr "Äối tượng %s không có ghi chú (note)\n" -#: builtin/notes.c:1103 -#: builtin/remote.c:1598 +#: builtin/notes.c:986 +msgid "attempt to remove non-existent note is not an error" +msgstr "cố gắng gỡ bá» má»™t note chưa từng tồn tại không phải là má»™t lá»—i" + +#: builtin/notes.c:989 +msgid "read object names from the standard input" +msgstr "Ä‘á»c tên đối tượng từ thiết bị nháºp chuẩn" + +#: builtin/notes.c:1070 +msgid "notes_ref" +msgstr "notes_ref" + +#: builtin/notes.c:1071 +msgid "use notes from <notes_ref>" +msgstr "dùng “notes†từ <notes_ref>" + +#: builtin/notes.c:1106 builtin/remote.c:1598 #, c-format msgid "Unknown subcommand: %s" msgstr "Không hiểu câu lệnh con: %s" -#: builtin/pack-objects.c:2337 +#: builtin/pack-objects.c:23 +msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]" +msgstr "" +"git pack-objects --stdout [các-tùy-chá»n...] [< danh-sách-ref | < danh-sách-" +"đối-tượng]" + +#: builtin/pack-objects.c:24 +msgid "git pack-objects [options...] base-name [< ref-list | < object-list]" +msgstr "" +"git pack-objects [các-tùy-chá»n...] base-name [< danh-sách-ref | < danh-sách-" +"đối-tượng]" + +#: builtin/pack-objects.c:183 builtin/pack-objects.c:186 +#, c-format +msgid "deflate error (%d)" +msgstr "lá»—i giải nén (%d)" + +#: builtin/pack-objects.c:2397 #, c-format msgid "unsupported index version %s" msgstr "phiên bản mục lục không được há»— trợ %s" -#: builtin/pack-objects.c:2341 +#: builtin/pack-objects.c:2401 #, c-format msgid "bad index version '%s'" -msgstr "phiên bản mục lục sai '%s'" +msgstr "phiên bản mục lục sai “%sâ€" -#: builtin/pack-objects.c:2364 +#: builtin/pack-objects.c:2424 #, c-format msgid "option %s does not accept negative form" msgstr "tùy chá»n %s không chấp nháºn dạng thức âm" -#: builtin/pack-objects.c:2368 +#: builtin/pack-objects.c:2428 #, c-format msgid "unable to parse value '%s' for option %s" -msgstr "không thể phân tÃch giá trị '%s' cho tùy chá»n %s" +msgstr "không thể phân tÃch giá trị “%s†cho tùy chá»n %s" + +#: builtin/pack-objects.c:2447 +msgid "do not show progress meter" +msgstr "không hiển thị bá»™ Ä‘o tiến trình" + +#: builtin/pack-objects.c:2449 +msgid "show progress meter" +msgstr "hiển thị bá»™ Ä‘o tiến trình" + +#: builtin/pack-objects.c:2451 +msgid "show progress meter during object writing phase" +msgstr "hiển thị bá»™ Ä‘o tiến triển trong suốt pha ghi đối tượng" + +#: builtin/pack-objects.c:2454 +msgid "similar to --all-progress when progress meter is shown" +msgstr "tương tá»± --all-progress khi bá»™ Ä‘o tiến trình được xuất hiện" + +#: builtin/pack-objects.c:2455 +msgid "version[,offset]" +msgstr "phiên bản[,offset]" + +#: builtin/pack-objects.c:2456 +msgid "write the pack index file in the specified idx format version" +msgstr "ghi táºp tin bảng mục lục gói (pack) ở phiên bản định dạng idx đã cho" + +#: builtin/pack-objects.c:2459 +msgid "maximum size of each output pack file" +msgstr "kcÃh thước tối Ä‘a cho táºp tin gói được tạo" + +#: builtin/pack-objects.c:2461 +msgid "ignore borrowed objects from alternate object store" +msgstr "bá» qua các đối tượng vay mượn từ kho đối tượng thay thế" + +#: builtin/pack-objects.c:2463 +msgid "ignore packed objects" +msgstr "bá» qua các đối tượng đóng gói" + +#: builtin/pack-objects.c:2465 +msgid "limit pack window by objects" +msgstr "giá»›i hạn cá»a sổ đóng gói theo đối tượng" + +#: builtin/pack-objects.c:2467 +msgid "limit pack window by memory in addition to object limit" +msgstr "giá»›i hạn cá»a sổ đóng gói theo bá»™ nhá»› cá»™ng thêm vá»›i giá»›i hạn đối tượng" + +#: builtin/pack-objects.c:2469 +msgid "maximum length of delta chain allowed in the resulting pack" +msgstr "độ dà i tối Ä‘a cá»§a chuá»—i móc xÃch “delta†được phép trong gói kết quả" + +#: builtin/pack-objects.c:2471 +msgid "reuse existing deltas" +msgstr "dùng lại các delta sẵn có" + +#: builtin/pack-objects.c:2473 +msgid "reuse existing objects" +msgstr "dùng lại các đối tượng sẵn có" + +#: builtin/pack-objects.c:2475 +msgid "use OFS_DELTA objects" +msgstr "dùng các đối tượng OFS_DELTA" + +#: builtin/pack-objects.c:2477 +msgid "use threads when searching for best delta matches" +msgstr "sá» dụng các tuyến trình khi tìm kiếm cho các mẫu khá»›p delta tốt nhất" + +#: builtin/pack-objects.c:2479 +msgid "do not create an empty pack output" +msgstr "không thể tạo kết xuất gói (pack) trống rá»—ng" + +#: builtin/pack-objects.c:2481 +msgid "read revision arguments from standard input" +msgstr " Ä‘á»c tham số “revision†từ thiết bị nháºp chuẩn" + +#: builtin/pack-objects.c:2483 +msgid "limit the objects to those that are not yet packed" +msgstr "giá»›i hạn các đối tượng thà nh những cái mà chúng vẫn chưa được đóng gói" + +#: builtin/pack-objects.c:2486 +msgid "include objects reachable from any reference" +msgstr "bao gồm các đối tượng có thể Ä‘á»c được từ bất kỳ tham chiếu nà o" + +#: builtin/pack-objects.c:2489 +msgid "include objects referred by reflog entries" +msgstr "bao gồm các đối tượng được tham chiếu bởi các mục reflog" + +#: builtin/pack-objects.c:2492 +msgid "output pack to stdout" +msgstr "xuất gói ra đầu ra tiêu chuẩn" + +#: builtin/pack-objects.c:2494 +msgid "include tag objects that refer to objects to be packed" +msgstr "bao gồm các đối tượng tham chiếu đến các đối tượng được đóng gói" + +#: builtin/pack-objects.c:2496 +msgid "keep unreachable objects" +msgstr "giữ lại các đối tượng không thể Ä‘á»c được" + +#: builtin/pack-objects.c:2497 parse-options.h:141 +msgid "time" +msgstr "thá»i-gian" + +#: builtin/pack-objects.c:2498 +msgid "unpack unreachable objects newer than <time>" +msgstr "" +"xả nén (gỡ khá»i gói) các đối tượng không thể Ä‘á»c được má»›i hÆ¡n <thá»i-gian>" + +#: builtin/pack-objects.c:2501 +msgid "create thin packs" +msgstr "tạo gói nhẹ" + +#: builtin/pack-objects.c:2503 +msgid "ignore packs that have companion .keep file" +msgstr "bá» qua các gói mà nó có táºp tin .keep Ä‘i kèm" + +#: builtin/pack-objects.c:2505 +msgid "pack compression level" +msgstr "mức nén gói" + +#: builtin/pack-objects.c:2507 +msgid "do not hide commits by grafts" +msgstr "không ẩn các lần chuyển giao bởi “graftsâ€" + +#: builtin/pack-refs.c:6 +msgid "git pack-refs [options]" +msgstr "git pack-refs [các-tùy-chá»n]" + +#: builtin/pack-refs.c:14 +msgid "pack everything" +msgstr "đóng gói má»i thứ" + +#: builtin/pack-refs.c:15 +msgid "prune loose refs (default)" +msgstr "prune (cắt cụt) những tham chiếu (refs) bị mất (mặc định)" + +#: builtin/prune-packed.c:7 +msgid "git prune-packed [-n|--dry-run] [-q|--quiet]" +msgstr "git prune-packed [-n|--dry-run] [-q|--quiet]" + +#: builtin/prune.c:12 +msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]" +msgstr "git prune [-n] [-v] [--expire <thá»i-gian>] [--] [<head>...]" + +#: builtin/prune.c:132 +msgid "do not remove, show only" +msgstr "không gỡ bá», chỉ hiển thị" + +#: builtin/prune.c:133 +msgid "report pruned objects" +msgstr "báo cáo các đối tượng đã prune" + +#: builtin/prune.c:136 +msgid "expire objects older than <time>" +msgstr "các đối tượng hết hạn cÅ© hÆ¡n khoảng <thá»i gian>" + +#: builtin/push.c:14 +msgid "git push [<options>] [<repository> [<refspec>...]]" +msgstr "git push [<các-tùy-chá»n>] [<kho-chứa> [<refspec>...]]" #: builtin/push.c:45 msgid "tag shorthand without <tag>" @@ -3944,7 +6866,8 @@ msgid "" "To choose either option permanently, see push.default in 'git help config'." msgstr "" "\n" -"Äể chá»n má»—i tùy chá»n má»™t cách cố định, xem push.default trong 'git help config'." +"Äể chá»n má»—i tùy chá»n má»™t cách cố định, xem push.default trong “git help " +"configâ€." #: builtin/push.c:102 #, c-format @@ -3960,8 +6883,8 @@ msgid "" " git push %s %s\n" "%s" msgstr "" -"Nhánh dòng ngược (upstream) cá»§a nhánh hiện tại cá»§a bạn không khá»›p\n" -"vá»›i tên cá»§a nhánh hiện tại cá»§a bạn. Äể push đến nhánh dòng ngược\n" +"Nhánh thượng nguồn (upstream) cá»§a nhánh hiện tại cá»§a bạn không khá»›p\n" +"vá»›i tên cá»§a nhánh hiện tại cá»§a bạn. Äể push đến nhánh thượng nguồn\n" "trên máy chá»§, sá» dụng\n" "\n" " git push %s HEAD:%s\n" @@ -3994,15 +6917,16 @@ msgid "" "\n" " git push --set-upstream %s %s\n" msgstr "" -"Nhánh hiện tại %s không có nhánh dòng ngược (upstream) nà o.\n" -"Äể push (đẩy lên) nhánh hiện tại và đặt máy chá»§ như là dòng ngược (upstream), sá» dụng\n" +"Nhánh hiện tại %s không có nhánh thượng nguồn (upstream) nà o.\n" +"Äể push (đẩy lên) nhánh hiện tại và đặt máy chá»§ như là thượng nguồn " +"(upstream), sá» dụng\n" "\n" " git push --set-upstream %s %s\n" #: builtin/push.c:136 #, c-format msgid "The current branch %s has multiple upstream branches, refusing to push." -msgstr "Nhánh hiện tại %s có Ä‘a nhánh dòng ngược (upstream), từ chối push." +msgstr "Nhánh hiện tại %s có Ä‘a nhánh thượng nguồn (upstream), từ chối push." #: builtin/push.c:139 #, c-format @@ -4011,15 +6935,52 @@ msgid "" "your current branch '%s', without telling me what to push\n" "to update which remote branch." msgstr "" -"Bạn Ä‘ang push (đẩy lên) máy chá»§ '%s', mà nó không phải là dòng ngược (upstream) cá»§a\n" -"nhánh hiện tại '%s' cá»§a bạn, mà không báo cho tôi biết là cái gì được push\n" +"Bạn Ä‘ang push (đẩy lên) máy chá»§ “%sâ€, mà nó không phải là thượng nguồn " +"(upstream) cá»§a\n" +"nhánh hiện tại “%s†cá»§a bạn, mà không báo cho tôi biết là cái gì được push\n" "để cáºp nháºt nhánh máy chá»§ nà o." -#: builtin/push.c:174 -msgid "You didn't specify any refspecs to push, and push.default is \"nothing\"." -msgstr "Bạn đã không chỉ ra má»™t refspecs nà o để push, và push.default là \"không là gì cả\"." +#: builtin/push.c:151 +msgid "" +"push.default is unset; its implicit value is changing in\n" +"Git 2.0 from 'matching' to 'simple'. To squelch this message\n" +"and maintain the current behavior after the default changes, use:\n" +"\n" +" git config --global push.default matching\n" +"\n" +"To squelch this message and adopt the new behavior now, use:\n" +"\n" +" git config --global push.default simple\n" +"\n" +"See 'git help config' and search for 'push.default' for further " +"information.\n" +"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n" +"'current' instead of 'simple' if you sometimes use older versions of Git)" +msgstr "" +"biến push.default chưa được đặt; giá trị ngầm định cá»§a nó\n" +"đã được thay đổi trong Git 2.0 từ “matching†thà nh “simpleâ€.\n" +"Äể không hiển thị nhắc nhở nà y và duy trì cách xá» lý sau\n" +"những thay đổi mặc định nà y, hãy chạy lệnh:\n" +"\n" +" git config --global push.default matching\n" +"\n" +"Äể không hiển thị nhắc nhở nà y và áp dụng cách xá» lý má»›i, hãy chạy lệnh:\n" +"\n" +" git config --global push.default simple\n" +"\n" +"Xem “git help config†và tìm đến “push.default†để có thêm thông tin.\n" +"(chế độ “simple†được bắt đầu sá» dụng từ Git 1.7.11. Sá» dụng chế độ tương " +"tá»±\n" +"“current†thay vì “simple†nếu bạn thỉnh thoảng phải sá» dụng bản Git cÅ©)" + +#: builtin/push.c:199 +msgid "" +"You didn't specify any refspecs to push, and push.default is \"nothing\"." +msgstr "" +"Bạn đã không chỉ ra má»™t refspecs nà o để push, và push.default là \"không là " +"gì cả\"." -#: builtin/push.c:181 +#: builtin/push.c:206 msgid "" "Updates were rejected because the tip of your current branch is behind\n" "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n" @@ -4027,23 +6988,28 @@ msgid "" "See the 'Note about fast-forwards' in 'git push --help' for details." msgstr "" "Việc cáºp nháºt bị từ chối bởi vì đầu mút cá»§a nhánh được push nằm đằng sau bá»™\n" -"pháºn tương ứng cá»§a máy chá»§. Hòa trá»™n vá»›i các thay đổi từ máy chá»§ (v.d. 'git pull')\n" +"pháºn tương ứng cá»§a máy chá»§. Hòa trá»™n vá»›i các thay đổi từ máy chá»§ (v.d. “git " +"pullâ€)\n" "trước khi lại push lần nữa.\n" -"Xem trong phần 'Note about fast-forwards' trong ná»™i dung từ lệnh 'git push --help'." +"Xem trong phần “Note about fast-forwards†từ lệnh “git push --help†để có " +"thông tin chi tiết." -#: builtin/push.c:187 +#: builtin/push.c:212 msgid "" "Updates were rejected because a pushed branch tip is behind its remote\n" "counterpart. If you did not intend to push that branch, you may want to\n" -"specify branches to push or set the 'push.default' configuration\n" -"variable to 'current' or 'upstream' to push only the current branch." +"specify branches to push or set the 'push.default' configuration variable\n" +"to 'simple', 'current' or 'upstream' to push only the current branch." msgstr "" "Việc cáºp nháºt bị từ chối bởi vì đầu mút cá»§a nhánh được push nằm đằng sau bá»™\n" -"pháºn tương ứng cá»§a máy chá»§. Nếu bạn không có ý định push nhánh đó, bạn có lẽ muốn\n" -"chỉ định các nhánh để push hoặt là đặt ná»™i dung cho biến cấu hình 'push.default'\n" -"thà nh 'current' hoặc 'upstream' để push chỉ nhánh hiện hà nh mà thôi." - -#: builtin/push.c:193 +"pháºn tương ứng cá»§a máy chá»§. Nếu bạn không có ý định push nhánh đó, bạn có lẽ " +"muốn\n" +"chỉ định các nhánh để push hoặt là đặt ná»™i dung cho biến cấu hình “push." +"defaultâ€\n" +"thà nh “simpleâ€, “current†hoặc “upstream†để chỉ push nhánh hiện hà nh mà " +"thôi." + +#: builtin/push.c:218 msgid "" "Updates were rejected because a pushed branch tip is behind its remote\n" "counterpart. Check out this branch and merge the remote changes\n" @@ -4051,29 +7017,32 @@ msgid "" "See the 'Note about fast-forwards' in 'git push --help' for details." msgstr "" "Việc cáºp nháºt bị từ chối bởi vì đầu mút cá»§a nhánh được push nằm đằng sau bá»™\n" -"pháºn tương ứng cá»§a máy chá»§. Checkou nhánh nà y và hòa trá»™n vá»›i các thay đổi từ máy chá»§\n" -"(v.d. 'git pull') trước khi lại push lần nữa.\n" -"Xem trong phần 'Note about fast-forwards' trong ná»™i dung từ lệnh 'git push --help'." +"pháºn tương ứng cá»§a máy chá»§. Checkou nhánh nà y và hòa trá»™n vá»›i các thay đổi " +"từ máy chá»§\n" +"(v.d. “git pullâ€) trước khi lại push lần nữa.\n" +"Xem trong phần “Note about fast-forwards†từ lệnh “git push --help†để có " +"thông tin chi tiết." -#: builtin/push.c:233 +#: builtin/push.c:258 #, c-format msgid "Pushing to %s\n" msgstr "Äang push (đẩy) lên %s\n" -#: builtin/push.c:237 +#: builtin/push.c:262 #, c-format msgid "failed to push some refs to '%s'" -msgstr "gặp lá»—i khi push (đẩy lên) má»™t số tham chiếu (ref) đến '%s'" +msgstr "gặp lá»—i khi push (đẩy lên) má»™t số tham chiếu (ref) đến “%sâ€" -#: builtin/push.c:269 +#: builtin/push.c:294 #, c-format msgid "bad repository '%s'" -msgstr "repository (kho) sai '%s'" +msgstr "repository (kho) sai “%sâ€" -#: builtin/push.c:270 +#: builtin/push.c:295 msgid "" "No configured push destination.\n" -"Either specify the URL from the command-line or configure a remote repository using\n" +"Either specify the URL from the command-line or configure a remote " +"repository using\n" "\n" " git remote add <name> <url>\n" "\n" @@ -4090,34 +7059,237 @@ msgstr "" "\n" " git push <tên>\n" -#: builtin/push.c:285 +#: builtin/push.c:310 msgid "--all and --tags are incompatible" msgstr "--all và --tags xung khắc nhau" -#: builtin/push.c:286 +#: builtin/push.c:311 msgid "--all can't be combined with refspecs" msgstr "--all không thể được tổ hợp cùng vá»›i refspecs" -#: builtin/push.c:291 +#: builtin/push.c:316 msgid "--mirror and --tags are incompatible" msgstr "--mirror và --tags xung khắc nhau" -#: builtin/push.c:292 +#: builtin/push.c:317 msgid "--mirror can't be combined with refspecs" msgstr "--mirror không thể được tổ hợp cùng vá»›i refspecs" -#: builtin/push.c:297 +#: builtin/push.c:322 msgid "--all and --mirror are incompatible" msgstr "--all và --mirror xung khắc nhau" -#: builtin/push.c:385 +#: builtin/push.c:382 +msgid "repository" +msgstr "kho" + +#: builtin/push.c:383 +msgid "push all refs" +msgstr "push tất cả refs" + +#: builtin/push.c:384 +msgid "mirror all refs" +msgstr "mirror tất cả refs" + +#: builtin/push.c:386 +msgid "delete refs" +msgstr "xóa refs" + +#: builtin/push.c:387 +msgid "push tags (can't be used with --all or --mirror)" +msgstr "" +"các thẻ push (không thể sá» dụng cùng vá»›i các tùy chá»n --all hay --mirror)" + +#: builtin/push.c:390 +msgid "force updates" +msgstr "ép buá»™c cáºp nháºt" + +#: builtin/push.c:391 +msgid "check" +msgstr "kiểm tra" + +#: builtin/push.c:392 +msgid "control recursive pushing of submodules" +msgstr "Ä‘iá»u khiển việc đẩy lên (push) đệ qui cá»§a mô-Ä‘un-con" + +#: builtin/push.c:394 +msgid "use thin pack" +msgstr "tạo gói nhẹ" + +#: builtin/push.c:395 builtin/push.c:396 +msgid "receive pack program" +msgstr "nháºn vá» chương trình pack" + +#: builtin/push.c:397 +msgid "set upstream for git pull/status" +msgstr "đặt thượng nguồn (upstream) cho git pull/status" + +#: builtin/push.c:400 +msgid "prune locally removed refs" +msgstr "prune (cắt cụt) những tham chiếu (refs) bị gỡ bá»" + +#: builtin/push.c:410 msgid "--delete is incompatible with --all, --mirror and --tags" msgstr "--delete là xung khắc vá»›i các tùy chá»n --all, --mirror và --tags" -#: builtin/push.c:387 +#: builtin/push.c:412 msgid "--delete doesn't make sense without any refs" msgstr "--delete không hợp lý nếu không có bất kỳ tham chiếu (refs) nà o" +#: builtin/read-tree.c:36 +msgid "" +"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] " +"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--" +"index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])" +msgstr "" +"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<tiá»n-" +"tố>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] " +"[--index-output=<táºp-tin>] (--empty | <tree-ish1> [<tree-ish2> [<tree-" +"ish3>]])" + +#: builtin/read-tree.c:108 +msgid "write resulting index to <file>" +msgstr "ghi mục lục kết quả và o <táºp-tin>" + +#: builtin/read-tree.c:111 +msgid "only empty the index" +msgstr "chỉ vá»›i bảng mục lục trống rá»—ng" + +#: builtin/read-tree.c:113 +msgid "Merging" +msgstr "Hòa trá»™n" + +#: builtin/read-tree.c:115 +msgid "perform a merge in addition to a read" +msgstr "thá»±c hiện má»™t hòa trá»™n thêm và o việc Ä‘á»c" + +#: builtin/read-tree.c:117 +msgid "3-way merge if no file level merging required" +msgstr "" +"hòa trá»™n kiểu “3-way†nếu không có táºp tin mức hòa trá»™n nà o được yêu cầu " + +#: builtin/read-tree.c:119 +msgid "3-way merge in presence of adds and removes" +msgstr "hòa trá»™n 3-way trong sá»± hiện diện cá»§a “adds†và “removesâ€" + +#: builtin/read-tree.c:121 +msgid "same as -m, but discard unmerged entries" +msgstr "giống vá»›i -m, nhưng bá» qua các mục chưa được hòa trá»™n" + +#: builtin/read-tree.c:122 +msgid "<subdirectory>/" +msgstr "<thư-mục-con>/" + +#: builtin/read-tree.c:123 +msgid "read the tree into the index under <subdirectory>/" +msgstr "Ä‘á»c cây và o trong bảng mục lục dưới <thư_mục_con>/" + +#: builtin/read-tree.c:126 +msgid "update working tree with merge result" +msgstr "cáºp nháºt cây là m việc vá»›i kết quả hòa trá»™n" + +#: builtin/read-tree.c:128 +msgid "gitignore" +msgstr "gitignore" + +#: builtin/read-tree.c:129 +msgid "allow explicitly ignored files to be overwritten" +msgstr "cho phép các táºp tin rõ rà ng bị lá» Ä‘i được ghi đè" + +#: builtin/read-tree.c:132 +msgid "don't check the working tree after merging" +msgstr "không kiểm tra cây là m việc sau hòa trá»™n" + +#: builtin/read-tree.c:133 +msgid "don't update the index or the work tree" +msgstr "không cáºp nháºt bảng mục lục hay cây là m việc" + +#: builtin/read-tree.c:135 +msgid "skip applying sparse checkout filter" +msgstr "bá» qua áp dụng bá»™ lá»c lấy ra (checkout) thưa thá»›t" + +#: builtin/read-tree.c:137 +msgid "debug unpack-trees" +msgstr "gỡ lá»—i unpack-trees" + +#: builtin/remote.c:11 +msgid "git remote [-v | --verbose]" +msgstr "git remote [-v | --verbose]" + +#: builtin/remote.c:12 +msgid "" +"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--" +"mirror=<fetch|push>] <name> <url>" +msgstr "" +"git remote add [-t <nhánh>] [-m <master>] [-f] [--tags|--no-tags] [--" +"mirror=<fetch|push>] <tên> <url>" + +#: builtin/remote.c:13 builtin/remote.c:32 +msgid "git remote rename <old> <new>" +msgstr "git remote rename <tên-cÅ©> <tên-má»›i>" + +#: builtin/remote.c:14 builtin/remote.c:37 +msgid "git remote remove <name>" +msgstr "git remote remove <tên>" + +#: builtin/remote.c:15 builtin/remote.c:42 +msgid "git remote set-head <name> (-a | -d | <branch>)" +msgstr "git remote set-head <tên> (-a | -d | <nhánh>)" + +#: builtin/remote.c:16 +msgid "git remote [-v | --verbose] show [-n] <name>" +msgstr "git remote [-v | --verbose] show [-n] <tên>" + +#: builtin/remote.c:17 +msgid "git remote prune [-n | --dry-run] <name>" +msgstr "git remote prune [-n | --dry-run] <tên>" + +#: builtin/remote.c:18 +msgid "" +"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]" +msgstr "" +"git remote [-v | --verbose] update [-p | --prune] [(<nhóm> | <máy-chá»§>)...]" + +#: builtin/remote.c:19 +msgid "git remote set-branches [--add] <name> <branch>..." +msgstr "git remote set-branches [--add] <tên> <nhánh>..." + +#: builtin/remote.c:20 builtin/remote.c:68 +msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]" +msgstr "git remote set-url [--push] <tên> <url-má»›i> [<url-cÅ©>]" + +#: builtin/remote.c:21 builtin/remote.c:69 +msgid "git remote set-url --add <name> <newurl>" +msgstr "git remote set-url --add <tên> <url-má»›i>" + +#: builtin/remote.c:22 builtin/remote.c:70 +msgid "git remote set-url --delete <name> <url>" +msgstr "git remote set-url --delete <tên> <url>" + +#: builtin/remote.c:27 +msgid "git remote add [<options>] <name> <url>" +msgstr "git remote add [<các-tùy-chá»n>] <tên> <url>" + +#: builtin/remote.c:47 +msgid "git remote set-branches <name> <branch>..." +msgstr "git remote set-branches <tên> <nhánh>..." + +#: builtin/remote.c:48 +msgid "git remote set-branches --add <name> <branch>..." +msgstr "git remote set-branches --add <tên> <nhánh>..." + +#: builtin/remote.c:53 +msgid "git remote show [<options>] <name>" +msgstr "git remote show [<các-tùy-chá»n>] <tên>" + +#: builtin/remote.c:58 +msgid "git remote prune [<options>] <name>" +msgstr "git remote prune [<các-tùy-chá»n>] <tên>" + +#: builtin/remote.c:63 +msgid "git remote update [<options>] [<group> | <remote>]..." +msgstr "git remote update [<các-tùy-chá»n>] [<nhóm> | <máy-chá»§>]..." + #: builtin/remote.c:98 #, c-format msgid "Updating %s" @@ -4136,30 +7308,57 @@ msgstr "" msgid "unknown mirror argument: %s" msgstr "không hiểu tham số máy bản sao (mirror): %s" +#: builtin/remote.c:163 +msgid "fetch the remote branches" +msgstr "lấy vá» (fetch) các nhánh từ máy chá»§" + +#: builtin/remote.c:165 +msgid "import all tags and associated objects when fetching" +msgstr "" +"nháºp và o tất cả các đối tượng thẻ và thà nh phần liên quan khi lấy vá» (fetch)" + +#: builtin/remote.c:168 +msgid "or do not fetch any tag at all (--no-tags)" +msgstr "hoặc không lấy vá» (fetch) bất kỳ thẻ nà o (--no-tags)" + +#: builtin/remote.c:170 +msgid "branch(es) to track" +msgstr "các nhánh theo vết" + +#: builtin/remote.c:171 +msgid "master branch" +msgstr "nhánh master" + +#: builtin/remote.c:172 +msgid "push|fetch" +msgstr "push|fetch" + +#: builtin/remote.c:173 +msgid "set up remote as a mirror to push to or fetch from" +msgstr "đặt máy chá»§ (remote) như là má»™t máy bản sao để push hay fetch từ đó" + #: builtin/remote.c:185 msgid "specifying a master branch makes no sense with --mirror" -msgstr "Ä‘ang chỉ định má»™t nhánh master không phân biệt HOA/thưá»ng vá»›i tùy chá»n --mirror" +msgstr "Ä‘ang chỉ định má»™t nhánh master không hợp lý vá»›i tùy chá»n --mirror" #: builtin/remote.c:187 msgid "specifying branches to track makes sense only with fetch mirrors" -msgstr "chỉ định những nhánh để theo vết chỉ hợp lý vá»›i các 'fetch mirror'" +msgstr "chỉ định những nhánh để theo vết chỉ hợp lý vá»›i các “fetch mirrorâ€" -#: builtin/remote.c:195 -#: builtin/remote.c:646 +#: builtin/remote.c:195 builtin/remote.c:646 #, c-format msgid "remote %s already exists." msgstr "máy chá»§ %s đã tồn tại rồi." -#: builtin/remote.c:199 -#: builtin/remote.c:650 +#: builtin/remote.c:199 builtin/remote.c:650 #, c-format msgid "'%s' is not a valid remote name" -msgstr "'%s' không phải tên máy chá»§ hợp lệ" +msgstr "“%s†không phải tên máy chá»§ hợp lệ" #: builtin/remote.c:243 #, c-format msgid "Could not setup master '%s'" -msgstr "Không thể cà i đặt nhánh master '%s'" +msgstr "Không thể cà i đặt nhánh master “%sâ€" #: builtin/remote.c:299 #, c-format @@ -4171,8 +7370,7 @@ msgstr "nhiá»u hÆ¡n má»™t %s" msgid "Could not get fetch map for refspec %s" msgstr "Không thể lấy ánh xạ (map) fetch cho refspec %s" -#: builtin/remote.c:440 -#: builtin/remote.c:448 +#: builtin/remote.c:440 builtin/remote.c:448 msgid "(matching)" msgstr "(mẫu)" @@ -4180,16 +7378,12 @@ msgstr "(mẫu)" msgid "(delete)" msgstr "(xoá)" -#: builtin/remote.c:595 -#: builtin/remote.c:601 -#: builtin/remote.c:607 +#: builtin/remote.c:595 builtin/remote.c:601 builtin/remote.c:607 #, c-format msgid "Could not append '%s' to '%s'" -msgstr "Không thể nối thêm '%s' và o '%s'" +msgstr "Không thể nối thêm “%s†và o “%sâ€" -#: builtin/remote.c:639 -#: builtin/remote.c:792 -#: builtin/remote.c:890 +#: builtin/remote.c:639 builtin/remote.c:792 builtin/remote.c:890 #, c-format msgid "No such remote: %s" msgstr "Không có máy chá»§ nà o như thế: %s" @@ -4197,13 +7391,12 @@ msgstr "Không có máy chá»§ nà o như thế: %s" #: builtin/remote.c:656 #, c-format msgid "Could not rename config section '%s' to '%s'" -msgstr "Không thể đổi tên chương (section) cấu hình từ '%s' thà nh '%s'" +msgstr "Không thể đổi tên chương (section) cấu hình từ “%s†thà nh “%sâ€" -#: builtin/remote.c:662 -#: builtin/remote.c:799 +#: builtin/remote.c:662 builtin/remote.c:799 #, c-format msgid "Could not remove config section '%s'" -msgstr "Không thể gỡ bá» chương (section) cấu hình '%s'" +msgstr "Không thể gỡ bá» chương (section) cấu hình “%sâ€" #: builtin/remote.c:677 #, c-format @@ -4212,19 +7405,19 @@ msgid "" "\t%s\n" "\tPlease update the configuration manually if necessary." msgstr "" -"Không cáºp nháºt 'non-default fetch respec'\n" +"Không cáºp nháºt “non-default fetch respecâ€\n" "\t%s\n" "\tXin hãy cáºp nháºt phần cấu hình má»™t cách thá»§ công nếu thấy cần thiết." #: builtin/remote.c:683 #, c-format msgid "Could not append '%s'" -msgstr "Không thể nối thêm '%s'" +msgstr "Không thể nối thêm “%sâ€" #: builtin/remote.c:694 #, c-format msgid "Could not set '%s'" -msgstr "Không thể đặt '%s'" +msgstr "Không thể đặt “%sâ€" #: builtin/remote.c:716 #, c-format @@ -4239,7 +7432,7 @@ msgstr "tạo %s gặp lá»—i" #: builtin/remote.c:764 #, c-format msgid "Could not remove branch %s" -msgstr "Không thể gỡ nhánh %s" +msgstr "Không thể gỡ bá» nhánh %s" #: builtin/remote.c:834 msgid "" @@ -4252,7 +7445,8 @@ msgstr[0] "" "Chú ý: Má»™t nhánh nằm ngoà i hệ thống refs/remotes/ đã không được gỡ bá» Ä‘i;\n" "để xóa Ä‘i, sá» dụng:" msgstr[1] "" -"Chú ý: Má»™t số nhánh nằm ngoà i hệ thống refs/remotes/ đã không được gỡ bá» Ä‘i;\n" +"Chú ý: Má»™t số nhánh nằm ngoà i hệ thống refs/remotes/ đã không được gỡ bá» " +"Ä‘i;\n" "để xóa Ä‘i, sá» dụng:" #: builtin/remote.c:943 @@ -4262,11 +7456,11 @@ msgstr " má»›i (lần lấy vá» tiếp theo sẽ lưu trong remotes/%s)" #: builtin/remote.c:946 msgid " tracked" -msgstr " bị theo vết" +msgstr " được theo vết" #: builtin/remote.c:948 msgid " stale (use 'git remote prune' to remove)" -msgstr " cÅ© (sá» dụng 'git remote prune' để gỡ bá»)" +msgstr " cÅ© (dùng “git remote prune†để gỡ bá»)" #: builtin/remote.c:950 msgid " ???" @@ -4294,7 +7488,7 @@ msgstr " và vá»›i máy chá»§" #: builtin/remote.c:1004 #, c-format msgid "merges with remote %s" -msgstr "hòa trá»™n vá»›i máy chá»§ %s" +msgstr "hòa trá»™n vá»›i máy chá»§ %s" #: builtin/remote.c:1005 msgid " and with remote" @@ -4340,6 +7534,10 @@ msgstr " %-*s ép buá»™c thà nh %s" msgid " %-*s pushes to %s" msgstr " %-*s push tá»›i %s" +#: builtin/remote.c:1091 +msgid "do not query remotes" +msgstr "không truy vấn các máy chá»§" + #: builtin/remote.c:1118 #, c-format msgid "* remote %s" @@ -4350,28 +7548,25 @@ msgstr "* máy chá»§ %s" msgid " Fetch URL: %s" msgstr " URL để lấy vá» (fetch): %s" -#: builtin/remote.c:1120 -#: builtin/remote.c:1285 +#: builtin/remote.c:1120 builtin/remote.c:1285 msgid "(no URL)" -msgstr "(không có URL nà o)" +msgstr "(không có URL)" -#: builtin/remote.c:1129 -#: builtin/remote.c:1131 +#: builtin/remote.c:1129 builtin/remote.c:1131 #, c-format msgid " Push URL: %s" -msgstr " URL để đẩy lên (push) : %s" +msgstr " URL để đẩy lên (push): %s" -#: builtin/remote.c:1133 -#: builtin/remote.c:1135 -#: builtin/remote.c:1137 +#: builtin/remote.c:1133 builtin/remote.c:1135 builtin/remote.c:1137 #, c-format msgid " HEAD branch: %s" msgstr " Nhánh HEAD: %s" #: builtin/remote.c:1139 #, c-format -msgid " HEAD branch (remote HEAD is ambiguous, may be one of the following):\n" -msgstr " nhánh HEAD (HEAD máy chá»§ là không rõ rà ng, có lẽ là má»™t trong số sau):\n" +msgid "" +" HEAD branch (remote HEAD is ambiguous, may be one of the following):\n" +msgstr " nhánh HEAD (HEAD máy chá»§ chưa rõ rà ng, có lẽ là má»™t trong số sau):\n" #: builtin/remote.c:1151 #, c-format @@ -4380,27 +7575,34 @@ msgid_plural " Remote branches:%s" msgstr[0] " Nhánh trên máy chá»§:%s" msgstr[1] " Những nhánh trên máy chá»§:%s" -#: builtin/remote.c:1154 -#: builtin/remote.c:1181 +#: builtin/remote.c:1154 builtin/remote.c:1181 msgid " (status not queried)" msgstr " (trạng thái không được yêu cầu)" #: builtin/remote.c:1163 msgid " Local branch configured for 'git pull':" msgid_plural " Local branches configured for 'git pull':" -msgstr[0] " Nhánh ná»™i bá»™ đã được cấu hình cho lệnh 'git pull':" -msgstr[1] " Những nhánh ná»™i bá»™ đã được cấu hình cho lệnh 'git pull':" +msgstr[0] " Nhánh ná»™i bá»™ đã được cấu hình cho lệnh “git pullâ€:" +msgstr[1] " Những nhánh ná»™i bá»™ đã được cấu hình cho lệnh “git pullâ€:" #: builtin/remote.c:1171 msgid " Local refs will be mirrored by 'git push'" -msgstr " refs ná»™i bá»™ sẽ được phản chiếu bởi lệnh 'git push'" +msgstr " refs ná»™i bá»™ sẽ được phản chiếu bởi lệnh “git pushâ€" #: builtin/remote.c:1178 #, c-format msgid " Local ref configured for 'git push'%s:" msgid_plural " Local refs configured for 'git push'%s:" -msgstr[0] " Tham chiếu ná»™i bá»™ được cấu hình cho lệnh 'git push'%s:" -msgstr[1] " Những tham chiếu ná»™i bá»™ được cấu hình cho lệnh 'git push'%s:" +msgstr[0] " Tham chiếu ná»™i bá»™ được cấu hình cho lệnh “git pushâ€%s:" +msgstr[1] " Những tham chiếu ná»™i bá»™ được cấu hình cho lệnh “git pushâ€%s:" + +#: builtin/remote.c:1199 +msgid "set refs/remotes/<name>/HEAD according to remote" +msgstr "đặt refs/remotes/<tên>/HEAD cho phù hợp vá»›i máy chá»§" + +#: builtin/remote.c:1201 +msgid "delete refs/remotes/<name>/HEAD" +msgstr "xóa refs/remotes/<tên>/HEAD" #: builtin/remote.c:1216 msgid "Cannot determine remote HEAD" @@ -4428,12 +7630,12 @@ msgstr "Không thể cà i đặt %s" #: builtin/remote.c:1274 #, c-format msgid " %s will become dangling!" -msgstr " %s sẽ trở thà nh lá»§ng lẳng (không được quản lý)!" +msgstr " %s sẽ trở thà nh không đầu (không được quản lý)!" #: builtin/remote.c:1275 #, c-format msgid " %s has become dangling!" -msgstr " %s phải trở thà nh lá»§ng lẳng (không được quản lý)!" +msgstr " %s đã trở thà nh không đầu (không được quản lý)!" #: builtin/remote.c:1281 #, c-format @@ -4455,16 +7657,35 @@ msgstr " * [nên xén bá»›t] %s" msgid " * [pruned] %s" msgstr " *[đã xén bá»›] %s" -#: builtin/remote.c:1387 -#: builtin/remote.c:1461 +#: builtin/remote.c:1321 +msgid "prune remotes after fetching" +msgstr "cắt máy chá»§ sau khi lấy vá»" + +#: builtin/remote.c:1387 builtin/remote.c:1461 #, c-format msgid "No such remote '%s'" -msgstr "Không có máy chá»§ nà o có tên '%s'" +msgstr "Không có máy chá»§ nà o có tên “%sâ€" + +#: builtin/remote.c:1407 +msgid "add branch" +msgstr "thêm nhánh" #: builtin/remote.c:1414 msgid "no remote specified" msgstr "chưa chỉ ra máy chá»§ nà o" +#: builtin/remote.c:1436 +msgid "manipulate push URLs" +msgstr "đẩy các “URL†bằng tay" + +#: builtin/remote.c:1438 +msgid "add URL" +msgstr "thêm URL" + +#: builtin/remote.c:1440 +msgid "delete URLs" +msgstr "xóa URLs" + #: builtin/remote.c:1447 msgid "--add --delete doesn't make sense" msgstr "--add --delete không hợp lý" @@ -4483,6 +7704,56 @@ msgstr "Không tìm thấy URL như váºy: %s" msgid "Will not delete all non-push URLs" msgstr "Sẽ không xóa những địa chỉ URL không-push" +#: builtin/remote.c:1569 +msgid "be verbose; must be placed before a subcommand" +msgstr "chi tiết; phải được đặt trước má»™t lệnh-con" + +#: builtin/replace.c:17 +msgid "git replace [-f] <object> <replacement>" +msgstr "git replace [-f] <đối-tượng> <thay-thế>" + +#: builtin/replace.c:18 +msgid "git replace -d <object>..." +msgstr "git replace -d <đối tượng>..." + +#: builtin/replace.c:19 +msgid "git replace -l [<pattern>]" +msgstr "git replace -l [<mẫu>]" + +#: builtin/replace.c:121 +msgid "list replace refs" +msgstr "liệt kê các refs thay thế" + +#: builtin/replace.c:122 +msgid "delete replace refs" +msgstr "xóa tham chiếu (refs) thay thế" + +#: builtin/replace.c:123 +msgid "replace the ref if it exists" +msgstr "thay thế tham chiếu (ref) nếu nó đã sẵn có" + +#: builtin/rerere.c:11 +msgid "git rerere [clear | forget path... | status | remaining | diff | gc]" +msgstr "git rerere [clear | forget path... | status | remaining | diff | gc]" + +#: builtin/rerere.c:56 +msgid "register clean resolutions in index" +msgstr "sổ ghi dá»n sạch các phân giải trong bản mục lục" + +#: builtin/reset.c:25 +msgid "" +"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]" +msgstr "" +"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]" + +#: builtin/reset.c:26 +msgid "git reset [-q] <commit> [--] <paths>..." +msgstr "git reset [-q] <commit> [--] <các-đưá»ng-dẫn>..." + +#: builtin/reset.c:27 +msgid "git reset --patch [<commit>] [--] [<paths>...]" +msgstr "git reset --patch [<commit>] [--] [<các-đưá»ng-dẫn>...]" + #: builtin/reset.c:33 msgid "mixed" msgstr "pha trá»™n" @@ -4538,98 +7809,455 @@ msgstr "Những thay đổi bị bá» trạng thái (stage) sau khi reset:" msgid "Cannot do a %s reset in the middle of a merge." msgstr "Không thể thá»±c hiện má»™t %s reset ở giữa cá»§a quá trình hòa trá»™n." -#: builtin/reset.c:297 +#: builtin/reset.c:238 +msgid "be quiet, only report errors" +msgstr "là m việc ở chế độ im lặng, chỉ hiển thị khi có lá»—i" + +#: builtin/reset.c:240 +msgid "reset HEAD and index" +msgstr "đặt lại (reset) HEAD và bảng mục lục" + +#: builtin/reset.c:241 +msgid "reset only HEAD" +msgstr "chỉ đặt lại (reset) HEAD" + +#: builtin/reset.c:243 builtin/reset.c:245 +msgid "reset HEAD, index and working tree" +msgstr "đặt lại HEAD, bảng mục lục và cây là m việc" + +#: builtin/reset.c:247 +msgid "reset HEAD but keep local changes" +msgstr "đặt lại HEAD nhưng giữ lại các thay đổi ná»™i bá»™" + +#: builtin/reset.c:303 #, c-format msgid "Could not parse object '%s'." -msgstr "không thể phân tÃch đối tượng '%s'." +msgstr "không thể phân tÃch đối tượng “%sâ€." -#: builtin/reset.c:302 +#: builtin/reset.c:308 msgid "--patch is incompatible with --{hard,mixed,soft}" msgstr "--patch xung khắc vá»›i --{hard,mixed,soft}" -#: builtin/reset.c:311 +#: builtin/reset.c:317 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." -msgstr "--mixed vá»›i các đưá»ng dẫn không còn dùng nữa; hãy thay thế bằng lệnh 'git reset -- <đưá»ng_dẫn>'." +msgstr "" +"--mixed vá»›i các đưá»ng dẫn không còn dùng nữa; hãy thay thế bằng lệnh “git " +"reset -- <đưá»ng_dẫn>â€." -#: builtin/reset.c:313 +#: builtin/reset.c:319 #, c-format msgid "Cannot do %s reset with paths." msgstr "Không thể thá»±c hiện lệnh %s reset vá»›i các đưá»ng dẫn." -#: builtin/reset.c:325 +#: builtin/reset.c:331 #, c-format msgid "%s reset is not allowed in a bare repository" msgstr "%s reset không được phép trên kho bare (trên máy chá»§)" -#: builtin/reset.c:341 +#: builtin/reset.c:347 #, c-format msgid "Could not reset index file to revision '%s'." -msgstr "Không thể đặt lại (reset) bảng mục lục thà nh Ä‘iểm xét lại '%s'." +msgstr "Không thể đặt lại (reset) bảng mục lục thà nh Ä‘iểm xét lại “%sâ€." + +#: builtin/rev-parse.c:339 +msgid "git rev-parse --parseopt [options] -- [<args>...]" +msgstr "git rev-parse --parseopt [các-tùy-chá»n] -- [<th.số>...]" + +#: builtin/rev-parse.c:344 +msgid "keep the `--` passed as an arg" +msgstr "giữ `--` chuyển qua là m tham số" + +#: builtin/rev-parse.c:346 +msgid "stop parsing after the first non-option argument" +msgstr "dừng phân tÃch sau đối số đầu tiên không có tùy chá»n" + +#: builtin/rev-parse.c:464 +msgid "" +"git rev-parse --parseopt [options] -- [<args>...]\n" +" or: git rev-parse --sq-quote [<arg>...]\n" +" or: git rev-parse [options] [<arg>...]\n" +"\n" +"Run \"git rev-parse --parseopt -h\" for more information on the first usage." +msgstr "" +"git rev-parse --parseopt [các-tùy-chá»n] -- [<Ä‘.số>...]\n" +" or: git rev-parse --sq-quote [<Ä‘.số>...]\n" +" or: git rev-parse [các-tùy-chá»n] [<Ä‘.số>...]\n" +"\n" +"Chạy lệnh \"git rev-parse --parseopt -h\" để có thêm thông tin vá» cách dùng." -#: builtin/revert.c:70 -#: builtin/revert.c:92 +#: builtin/revert.c:22 +msgid "git revert [options] <commit-ish>" +msgstr "git revert [các-tùy-chá»n] <commit-ish>" + +#: builtin/revert.c:23 +msgid "git revert <subcommand>" +msgstr "git revert <lệnh-con>" + +#: builtin/revert.c:28 +msgid "git cherry-pick [options] <commit-ish>" +msgstr "git cherry-pick [các-tùy-chá»n] <commit-ish>" + +#: builtin/revert.c:29 +msgid "git cherry-pick <subcommand>" +msgstr "git cherry-pick <lệnh-con>" + +#: builtin/revert.c:70 builtin/revert.c:92 #, c-format msgid "%s: %s cannot be used with %s" msgstr "%s: %s không thể được sá» dụng vá»›i %s" -#: builtin/revert.c:131 +#: builtin/revert.c:103 +msgid "end revert or cherry-pick sequence" +msgstr "kết thúc cherry-pick hay revert liên tiếp nhau" + +#: builtin/revert.c:104 +msgid "resume revert or cherry-pick sequence" +msgstr "phục hồi lại cherry-pick hay revert liên tiếp nhau" + +#: builtin/revert.c:105 +msgid "cancel revert or cherry-pick sequence" +msgstr "không cherry-pick hay revert liên tiếp nhau" + +#: builtin/revert.c:106 +msgid "don't automatically commit" +msgstr "không commit má»™t cách tá»± động." + +#: builtin/revert.c:107 +msgid "edit the commit message" +msgstr "sá»a lại chú thÃch cho commit" + +#: builtin/revert.c:110 +msgid "parent number" +msgstr "số cá»§a cha mẹ" + +#: builtin/revert.c:112 +msgid "merge strategy" +msgstr "chiến lược hòa trá»™n" + +#: builtin/revert.c:113 +msgid "option" +msgstr "tùy chá»n" + +#: builtin/revert.c:114 +msgid "option for merge strategy" +msgstr "tùy chá»n cho chiến lược hòa trá»™n" + +#: builtin/revert.c:125 +msgid "append commit name" +msgstr "nối thêm tên lần chuyển giao (commit)" + +#: builtin/revert.c:126 +msgid "allow fast-forward" +msgstr "cho phép fast-forward" + +#: builtin/revert.c:127 +msgid "preserve initially empty commits" +msgstr "cấm khởi tạo lần chuyển giao trống rá»—ng" + +#: builtin/revert.c:128 +msgid "allow commits with empty messages" +msgstr "chấp nháºn chuyển giao (commit) mà không ghi chú gì" + +#: builtin/revert.c:129 +msgid "keep redundant, empty commits" +msgstr "giữ lại các lần chuyển giao dư thừa, rá»—ng" + +#: builtin/revert.c:133 msgid "program error" msgstr "lá»—i chương trình" -#: builtin/revert.c:221 +#: builtin/revert.c:223 msgid "revert failed" msgstr "revert gặp lá»—i" -#: builtin/revert.c:236 +#: builtin/revert.c:238 msgid "cherry-pick failed" msgstr "cherry-pick gặp lá»—i" -#: builtin/rm.c:109 +#: builtin/rm.c:15 +msgid "git rm [options] [--] <file>..." +msgstr "git rm [các-tùy-chá»n] [--] <táºp-tin>..." + +#: builtin/rm.c:64 builtin/rm.c:186 +#, c-format +msgid "" +"submodule '%s' (or one of its nested submodules) uses a .git directory\n" +"(use 'rm -rf' if you really want to remove it including all of its history)" +msgstr "" +"mô-Ä‘un-con '%s' (hoặc cái nằm trong các mô-Ä‘un-con) dùng thư mục .git\n" +"(dùng 'rm -rf' nếu bạn thá»±c sá»± muốn gỡ bá» nó cùng vá»›i tất cả lịch sá» cá»§a " +"chúng)" + +#: builtin/rm.c:174 #, c-format msgid "" "'%s' has staged content different from both the file and the HEAD\n" "(use -f to force removal)" msgstr "" -"'%s' có ná»™i dung được lưu trạng thái khác biệt từ cả táºp tin và cả HEAD\n" -"(sá» dụng -f để ép buá»™c gỡ bá»)" +"“%s†có ná»™i dung được lưu trạng thái khác biệt từ cả táºp tin và cả HEAD\n" +"(dùng tùy chá»n -f để ép buá»™c gỡ bá»)" -#: builtin/rm.c:115 +#: builtin/rm.c:180 #, c-format msgid "" "'%s' has changes staged in the index\n" "(use --cached to keep the file, or -f to force removal)" msgstr "" -"'%s' có các thay đổi được lưu trạng thái trong bảng mục lục\n" -"(sá» dụng --cached để giữ táºp tin, hoặc -f để ép buá»™c gỡ bá»)" +"“%s†có các thay đổi được lưu trạng thái trong bảng mục lục\n" +"(dùng tùy chá»n --cached để giữ táºp tin, hoặc -f để ép buá»™c gỡ bá»)" -#: builtin/rm.c:119 +#: builtin/rm.c:191 #, c-format msgid "" "'%s' has local modifications\n" "(use --cached to keep the file, or -f to force removal)" msgstr "" -"'%s' có các thay đổi ná»™i bá»™\n" -"(sá» dụng --cached để giữ táºp tin, hoặc -f để ép buá»™c gỡ bá»)" +"“%s†có các thay đổi ná»™i bá»™\n" +"(dùng tùy chá»n --cached để giữ táºp tin, hoặc -f để ép buá»™c gỡ bá»)" -#: builtin/rm.c:194 +#: builtin/rm.c:207 +msgid "do not list removed files" +msgstr "không liệt kê các táºp tin đã gỡ bá»" + +#: builtin/rm.c:208 +msgid "only remove from the index" +msgstr "chỉ gỡ bá» từ mục lục" + +#: builtin/rm.c:209 +msgid "override the up-to-date check" +msgstr "ghi đè lên kiểm tra cáºp nháºt" + +#: builtin/rm.c:210 +msgid "allow recursive removal" +msgstr "cho phép gỡ bỠđệ qui" + +#: builtin/rm.c:212 +msgid "exit with a zero status even if nothing matched" +msgstr "thoát ra vá»›i trạng thái khác không tháºm chà nếu không có gì khá»›p" + +#: builtin/rm.c:283 #, c-format msgid "not removing '%s' recursively without -r" -msgstr "không thể gỡ bá» '%s' má»™t cách đệ qui mà không có tùy chá»n -r" +msgstr "không thể gỡ bỠ“%s†má»™t cách đệ qui mà không có tùy chá»n -r" -#: builtin/rm.c:230 +#: builtin/rm.c:322 #, c-format msgid "git rm: unable to remove %s" msgstr "git rm: không thể gỡ bá» %s" +#: builtin/shortlog.c:13 +msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]" +msgstr "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]" + #: builtin/shortlog.c:157 #, c-format msgid "Missing author: %s" msgstr "Thiếu tên tác giả: %s" +#: builtin/shortlog.c:253 +msgid "sort output according to the number of commits per author" +msgstr "sắp xếp kết xuất tuân theo số lượng chuyển giao trên má»—i tác giả" + +#: builtin/shortlog.c:255 +msgid "Suppress commit descriptions, only provides commit count" +msgstr "Chặn má»i mô tả lần chuyển giao, chỉ đưa ra số lượng lần chuyển giao" + +#: builtin/shortlog.c:257 +msgid "Show the email address of each author" +msgstr "Hiển thị thư Ä‘iện tá» cho từng tác giả" + +#: builtin/shortlog.c:258 +msgid "w[,i1[,i2]]" +msgstr "w[,i1[,i2]]" + +#: builtin/shortlog.c:259 +msgid "Linewrap output" +msgstr "Ngắt dòng khi quá dà i" + +#: builtin/show-branch.c:9 +msgid "" +"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--" +"current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --" +"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | " +"<glob>)...]" +msgstr "" +"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--" +"current] [--color[=<khi>] | --no-color] [--sparse] [--more=<n> | --list | --" +"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | " +"<glob>)...]" + +#: builtin/show-branch.c:10 +msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]" +msgstr "git show-branch (-g|--reflog)[=<n>[,<ná»n>]] [--list] [<ref>]" + +#: builtin/show-branch.c:651 +msgid "show remote-tracking and local branches" +msgstr "hiển thị các nhánh remote-tracking và ná»™i bá»™" + +#: builtin/show-branch.c:653 +msgid "show remote-tracking branches" +msgstr "hiển thị các nhánh remote-tracking" + +#: builtin/show-branch.c:655 +msgid "color '*!+-' corresponding to the branch" +msgstr "mà u “*!+-†tương ứng vá»›i nhánh" + +#: builtin/show-branch.c:657 +msgid "show <n> more commits after the common ancestor" +msgstr "hiển thị thêm <n> lần chuyển giao sau cha mẹ chung" + +#: builtin/show-branch.c:659 +msgid "synonym to more=-1" +msgstr "đồng nghÄ©a vá»›i more=-1" + +#: builtin/show-branch.c:660 +msgid "suppress naming strings" +msgstr "chặn các chuá»—i đặt tên" + +#: builtin/show-branch.c:662 +msgid "include the current branch" +msgstr "bao gồm nhánh hiện hà nh" + +#: builtin/show-branch.c:664 +msgid "name commits with their object names" +msgstr "đặt tên các lần chuyển giao bằng các tên cá»§a đối tượng cá»§a chúng" + +#: builtin/show-branch.c:666 +msgid "show possible merge bases" +msgstr "hiển thị má»i cÆ¡ sở có thể dùng để hòa trá»™n" + +#: builtin/show-branch.c:668 +msgid "show refs unreachable from any other ref" +msgstr "hiển thị các tham chiếu không thể được Ä‘á»c bởi bất kỳ tham chiếu khác" + +#: builtin/show-branch.c:670 +msgid "show commits in topological order" +msgstr "hiển thị các lần chuyển giao theo thứ tá»± tôpô" + +#: builtin/show-branch.c:672 +msgid "show only commits not on the first branch" +msgstr "chỉ hiển thị các lần chuyển giao không nằm trên nhánh đầu tiên" + +#: builtin/show-branch.c:674 +msgid "show merges reachable from only one tip" +msgstr "hiển thị các lần hòa trá»™n có thể Ä‘á»c được chỉ từ má»™t đầu mút" + +#: builtin/show-branch.c:676 +msgid "show commits where no parent comes before its children" +msgstr "hiển thị các lần chuyển giao nÆ¡i mà cha mẹ đến trước con cá»§a nó" + +#: builtin/show-branch.c:678 +msgid "<n>[,<base>]" +msgstr "<n>[,<cÆ¡ sở>]" + +#: builtin/show-branch.c:679 +msgid "show <n> most recent ref-log entries starting at base" +msgstr "hiển thị <n> các mục “ref-log†gần nhất kể từ ná»n (base)" + +#: builtin/show-ref.c:10 +msgid "" +"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash" +"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] " +msgstr "" +"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash" +"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [mẫu*] " + +#: builtin/show-ref.c:11 +msgid "git show-ref --exclude-existing[=pattern] < ref-list" +msgstr "git show-ref --exclude-existing[=mẫu] < ref-list" + +#: builtin/show-ref.c:165 +msgid "only show tags (can be combined with heads)" +msgstr "chỉ hiển thị thẻ (có thể tổ hợp cùng vá»›i đầu)" + +#: builtin/show-ref.c:166 +msgid "only show heads (can be combined with tags)" +msgstr "chỉ hiển thị đầu (có thể tổ hợp cùng vá»›i thẻ)" + +#: builtin/show-ref.c:167 +msgid "stricter reference checking, requires exact ref path" +msgstr "" +"việc kiểm tra tham chiếu chÃnh xác, đòi há»i chÃnh xác đưá»ng dẫn tham chiếu " +"(ref)" + +#: builtin/show-ref.c:170 builtin/show-ref.c:172 +msgid "show the HEAD reference" +msgstr "hiển thị tham chiếu cá»§a HEAD" + +#: builtin/show-ref.c:174 +msgid "dereference tags into object IDs" +msgstr "bãi bá» tham chiếu các thẻ thà nh ra các ID đối tượng" + +#: builtin/show-ref.c:176 +msgid "only show SHA1 hash using <n> digits" +msgstr "chỉ hiển thị mã băm SHA1 sá» dụng <n> chữ số" + +#: builtin/show-ref.c:180 +msgid "do not print results to stdout (useful with --verify)" +msgstr "" +"không hiển thị kết quả ra đầu ra chuẩn (stdout) (chỉ hữu dụng vá»›i --verify)" + +#: builtin/show-ref.c:182 +msgid "show refs from stdin that aren't in local repository" +msgstr "" +"hiển thị các tham chiếu (refs) từ đầu và o tiêu chuẩn (stdin) cái mà không ở " +"kho ná»™i bá»™" + +#: builtin/symbolic-ref.c:7 +msgid "git symbolic-ref [options] name [ref]" +msgstr "git symbolic-ref [các-tùy-chá»n] tên [t.chiếu]" + +#: builtin/symbolic-ref.c:8 +msgid "git symbolic-ref -d [-q] name" +msgstr "git symbolic-ref -d [-q] tên" + +#: builtin/symbolic-ref.c:40 +msgid "suppress error message for non-symbolic (detached) refs" +msgstr "" +"chặn các thông tin lá»—i cho các tham chiếu (refs) “non-symbolic†(bị tách ra)" + +#: builtin/symbolic-ref.c:41 +msgid "delete symbolic ref" +msgstr "xóa tham chiếu (ref) tượng trưng" + +#: builtin/symbolic-ref.c:42 +msgid "shorten ref output" +msgstr "là m ngắn kết xuất ref (tham chiếu)" + +#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18 +msgid "reason" +msgstr "lý do" + +#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18 +msgid "reason of the update" +msgstr "lý do cáºp nháºt" + +#: builtin/tag.c:22 +msgid "" +"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]" +msgstr "" +"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <táºp-tin>] <tên-thẻ> [<head>]" + +#: builtin/tag.c:23 +msgid "git tag -d <tagname>..." +msgstr "git tag -d <tên-thẻ>..." + +#: builtin/tag.c:24 +msgid "" +"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n" +"\t\t[<pattern>...]" +msgstr "" +"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <đối-tượng>] \n" +"\t\t[<mẫu>...]" + +#: builtin/tag.c:26 +msgid "git tag -v <tagname>..." +msgstr "git tag -v <tên-thẻ>..." + #: builtin/tag.c:60 #, c-format msgid "malformed object at '%s'" -msgstr "đối tượng dị hình tại '%s'" +msgstr "đối tượng dị hình tại “%sâ€" #: builtin/tag.c:207 #, c-format @@ -4639,17 +8267,17 @@ msgstr "tên thẻ quá dà i: %.*s..." #: builtin/tag.c:212 #, c-format msgid "tag '%s' not found." -msgstr "không tìm thấy tìm thấy thẻ '%s'." +msgstr "không tìm thấy tìm thấy thẻ “%sâ€." #: builtin/tag.c:227 #, c-format msgid "Deleted tag '%s' (was %s)\n" -msgstr "Thẻ đã bị xóa '%s' (trước là %s)\n" +msgstr "Thẻ đã bị xóa “%s†(trước là %s)\n" #: builtin/tag.c:239 #, c-format msgid "could not verify the tag '%s'" -msgstr "không thể thẩm tra thẻ '%s'" +msgstr "không thể thẩm tra thẻ “%sâ€" #: builtin/tag.c:249 msgid "" @@ -4662,7 +8290,7 @@ msgstr "" "\n" "#\n" "# Viết các ghi chú cho (thẻ) tag\n" -"# Những dòng được bắt đầu bằng '#' sẽ được bá» qua.\n" +"# Những dòng được bắt đầu bằng “#†sẽ được bá» qua.\n" "#\n" #: builtin/tag.c:256 @@ -4670,13 +8298,15 @@ msgid "" "\n" "#\n" "# Write a tag message\n" -"# Lines starting with '#' will be kept; you may remove them yourself if you want to.\n" +"# Lines starting with '#' will be kept; you may remove them yourself if you " +"want to.\n" "#\n" msgstr "" "\n" "#\n" "# Viết các ghi chú cho (thẻ) tag\n" -"# Những dòng được bắt đầu bằng '#' sẽ được bá» qua; bạn có thể xóa chúng Ä‘i nếu muốn.\n" +"# Những dòng được bắt đầu bằng “#†sẽ được bá» qua; bạn có thể xóa chúng Ä‘i " +"nếu muốn.\n" "#\n" #: builtin/tag.c:298 @@ -4706,12 +8336,68 @@ msgstr "Ná»™i dung ghi chú còn lại %s\n" #: builtin/tag.c:425 msgid "switch 'points-at' requires an object" -msgstr "chuyển đến 'points-at' yêu cần má»™t đối tượng" +msgstr "chuyển đến “points-at†yêu cần má»™t đối tượng" #: builtin/tag.c:427 #, c-format msgid "malformed object name '%s'" -msgstr "tên đối tượng dị hình '%s'" +msgstr "tên đối tượng dị hình “%sâ€" + +#: builtin/tag.c:447 +msgid "list tag names" +msgstr "chỉ liệt kê tên các thẻ" + +#: builtin/tag.c:449 +msgid "print <n> lines of each tag message" +msgstr "hiển thị <n> dòng cho má»—i ghi chú" + +#: builtin/tag.c:451 +msgid "delete tags" +msgstr "xóa thẻ" + +#: builtin/tag.c:452 +msgid "verify tags" +msgstr "thẩm tra thẻ" + +#: builtin/tag.c:454 +msgid "Tag creation options" +msgstr "Tùy chá»n tạo tag" + +#: builtin/tag.c:456 +msgid "annotated tag, needs a message" +msgstr "để chú giải cho thẻ, cần má»™t lá»i ghi chú" + +#: builtin/tag.c:458 +msgid "tag message" +msgstr "tin nhắn cho thẻ (tag)" + +#: builtin/tag.c:460 +msgid "annotated and GPG-signed tag" +msgstr "thẻ chú giải và ký kiểu GPG" + +#: builtin/tag.c:464 +msgid "use another key to sign the tag" +msgstr "dùng kháo khác để ký thẻ" + +#: builtin/tag.c:465 +msgid "replace the tag if exists" +msgstr "thay thế nếu tag đó đã có trước" + +#: builtin/tag.c:466 +msgid "show tag list in columns" +msgstr "hiển thị danh sách thẻ trong các cá»™t" + +#: builtin/tag.c:468 +msgid "Tag listing options" +msgstr "Các tùy chá»n liệt kê thẻ" + +#: builtin/tag.c:471 +msgid "print only tags that contain the commit" +msgstr "chỉ hiển thị những nhánh mà nó chứa lần chuyển giao" + +#: builtin/tag.c:477 +msgid "print only tags of the object" +msgstr "chỉ hiển thị các thẻ cá»§a đối tượng" #: builtin/tag.c:506 msgid "--column and -n are incompatible" @@ -4740,12 +8426,12 @@ msgstr "quá nhiá»u đối số" #: builtin/tag.c:561 #, c-format msgid "'%s' is not a valid tag name." -msgstr "'%s' không phải thẻ hợp lệ." +msgstr "“%s†không phải thẻ hợp lệ." #: builtin/tag.c:566 #, c-format msgid "tag '%s' already exists" -msgstr "Thẻ '%s' đã tồn tại rồi" +msgstr "Thẻ “%s†đã tồn tại rồi" #: builtin/tag.c:584 #, c-format @@ -4760,28 +8446,188 @@ msgstr "%s: không thể cáºp nháºt ref (tham chiếu)" #: builtin/tag.c:588 #, c-format msgid "Updated tag '%s' (was %s)\n" -msgstr "Thẻ đã cáºp nháºt '%s' (cÅ© là %s)\n" +msgstr "Äã cáºp nháºt thẻ “%s†(trước là %s)\n" -#: git.c:16 -msgid "See 'git help <command>' for more information on a specific command." -msgstr "Chạy lệnh 'git help <tên-lệnh>' để có thêm thông tin vá» lệnh được chỉ ra." +#: builtin/update-index.c:401 +msgid "git update-index [options] [--] [<file>...]" +msgstr "git update-index [các-tùy-chá»n] [<táºp-tin>...]" -#: parse-options.h:133 -#: parse-options.h:235 -msgid "n" -msgstr "n" +#: builtin/update-index.c:718 +msgid "continue refresh even when index needs update" +msgstr "tiếp tục là m má»›i ngay cả khi bảng mục lục cần được cáºp nháºt" -#: parse-options.h:141 -msgid "time" -msgstr "thá»i-gian" +#: builtin/update-index.c:721 +msgid "refresh: ignore submodules" +msgstr "refresh: lá» Ä‘i mô-Ä‘un-con" -#: parse-options.h:149 -msgid "file" -msgstr "táºp-tin" +#: builtin/update-index.c:724 +msgid "do not ignore new files" +msgstr "không bá» qua các táºp tin má»›i tạo" -#: parse-options.h:151 -msgid "when" -msgstr "khi" +#: builtin/update-index.c:726 +msgid "let files replace directories and vice-versa" +msgstr "để các táºp tin thay thế các thư mục và “vice-versaâ€" + +#: builtin/update-index.c:728 +msgid "notice files missing from worktree" +msgstr "thông báo các táºp-tin thiếu trong thư-mục là m việc" + +#: builtin/update-index.c:730 +msgid "refresh even if index contains unmerged entries" +msgstr "" +"là m tươi má»›i tháºm chà khi bảng mục lục chứa các mục tin chưa được hòa trá»™n" + +#: builtin/update-index.c:733 +msgid "refresh stat information" +msgstr "lấy lại thông tin thống kê" + +#: builtin/update-index.c:737 +msgid "like --refresh, but ignore assume-unchanged setting" +msgstr "giống --refresh, nhưng bá» qua các cà i đặt “assume-unchangedâ€" + +#: builtin/update-index.c:741 +msgid "<mode> <object> <path>" +msgstr "<mode> <đối tượng> <đưá»ng dẫn>" + +#: builtin/update-index.c:742 +msgid "add the specified entry to the index" +msgstr "thêm các táºp tin đã chỉ ra và o bảng mục lục" + +#: builtin/update-index.c:746 +msgid "(+/-)x" +msgstr "(+/-)x" + +#: builtin/update-index.c:747 +msgid "override the executable bit of the listed files" +msgstr "ghi đè lên bÃt thi hà nh cá»§a các táºp tin được liệt kê" + +#: builtin/update-index.c:751 +msgid "mark files as \"not changing\"" +msgstr "Äánh dấu các táºp tin là \"không thay đổi\"" + +#: builtin/update-index.c:754 +msgid "clear assumed-unchanged bit" +msgstr "xóa bÃt assumed-unchanged" + +#: builtin/update-index.c:757 +msgid "mark files as \"index-only\"" +msgstr "đánh dấu các táºp tin là “chỉ-Ä‘á»câ€" + +#: builtin/update-index.c:760 +msgid "clear skip-worktree bit" +msgstr "xóa bÃt skip-worktree" + +#: builtin/update-index.c:763 +msgid "add to index only; do not add content to object database" +msgstr "" +"chỉ thêm và o bảng mục lục; không thêm ná»™i dung và o cÆ¡ sở dữ liệu đối tượng" + +#: builtin/update-index.c:765 +msgid "remove named paths even if present in worktree" +msgstr "" +"gỡ bá» các đưá»ng dẫn được đặt tên tháºm chà cả khi nó hiện diện trong thư mục " +"là m việc" + +#: builtin/update-index.c:767 +msgid "with --stdin: input lines are terminated by null bytes" +msgstr "vá»›i tùy chá»n --stdin: các dòng đầu và o được chấm dứt bởi ký tá»± null" + +#: builtin/update-index.c:769 +msgid "read list of paths to be updated from standard input" +msgstr "Ä‘á»c danh sách đưá»ng dẫn cần cáºp nháºt từ đầu và o tiêu chuẩn" + +#: builtin/update-index.c:773 +msgid "add entries from standard input to the index" +msgstr "không thể Ä‘á»c các mục từ đầu và o tiêu chuẩn và o bảng mục lục" + +#: builtin/update-index.c:777 +msgid "repopulate stages #2 and #3 for the listed paths" +msgstr "phục hồi các trạng thái #2 và #3 cho các đưá»ng dẫn được liệt kê" + +#: builtin/update-index.c:781 +msgid "only update entries that differ from HEAD" +msgstr "chỉ cáºp nháºt các mục tin mà nó khác biệt so vá»›i HEAD" + +#: builtin/update-index.c:785 +msgid "ignore files missing from worktree" +msgstr "bá» qua các táºp-tin thiếu trong thư-mục là m việc" + +#: builtin/update-index.c:788 +msgid "report actions to standard output" +msgstr "báo cáo các thao tác ra thiết bị xuất chuẩn" + +#: builtin/update-index.c:790 +msgid "(for porcelains) forget saved unresolved conflicts" +msgstr "(cho “porcelainsâ€) quên các xung đột chưa được giải quyết đã ghi" + +#: builtin/update-index.c:794 +msgid "write index in this format" +msgstr "ghi mục lục ở định dạng nà y" + +#: builtin/update-ref.c:7 +msgid "git update-ref [options] -d <refname> [<oldval>]" +msgstr "git update-ref [các-tùy-chá»n] -d <refname> [<biến-cÅ©>]" + +#: builtin/update-ref.c:8 +msgid "git update-ref [options] <refname> <newval> [<oldval>]" +msgstr "git update-ref [các-tùy-chá»n] <refname> <biến-má»›i> [<biến-cÅ©>]" + +#: builtin/update-ref.c:19 +msgid "delete the reference" +msgstr "xóa tham chiếu" + +#: builtin/update-ref.c:21 +msgid "update <refname> not the one it points to" +msgstr "cáºp nháºt <tên-tham-chiếu> không phải cái nó chỉ tá»›i" + +#: builtin/update-server-info.c:6 +msgid "git update-server-info [--force]" +msgstr "git update-server-info [--force]" + +#: builtin/update-server-info.c:14 +msgid "update the info files from scratch" +msgstr "cáºp nháºt các táºp tin thông tin từ Ä‘iểm xuất phát" + +#: builtin/verify-pack.c:56 +msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..." +msgstr "git verify-pack [-v|--verbose] [-s|--stat-only] <gói>..." + +#: builtin/verify-pack.c:66 +msgid "verbose" +msgstr "chi tiết" + +#: builtin/verify-pack.c:68 +msgid "show statistics only" +msgstr "chỉ hiển thị thống kê" + +#: builtin/verify-tag.c:17 +msgid "git verify-tag [-v|--verbose] <tag>..." +msgstr "git verify-tag [-v|--verbose] <thẻ>..." + +#: builtin/verify-tag.c:73 +msgid "print tag contents" +msgstr "hiển thị ná»™i dung cá»§a thẻ" + +#: builtin/write-tree.c:13 +msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]" +msgstr "git write-tree [--missing-ok] [--prefix=<tiá»n-tố>/]" + +#: builtin/write-tree.c:26 +msgid "<prefix>/" +msgstr "<iá»n tố>/" + +#: builtin/write-tree.c:27 +msgid "write tree object for a subdirectory <prefix>" +msgstr "ghi đối tượng cây (tree) cho <tiá»n tố> thư mục con" + +#: builtin/write-tree.c:30 +msgid "only useful for debugging" +msgstr "chỉ hữu Ãch khi cần gỡ lá»—i" + +#: git.c:16 +msgid "See 'git help <command>' for more information on a specific command." +msgstr "" +"Chạy lệnh “git help <tên-lệnh>†để có thêm thông tin vá» lệnh được chỉ ra." #: parse-options.h:156 msgid "no-op (backward compatibility)" @@ -4813,7 +8659,7 @@ msgstr "Liệt kê, tạo hay là xóa các nhánh" #: common-cmds.h:11 msgid "Checkout a branch or paths to the working tree" -msgstr "Checkout má»™t nhánh hay các đưá»ng dẫn tá»i cây là m việc" +msgstr "Lấy ra (checkout) má»™t nhánh hay các đưá»ng dẫn tá»›i cây là m việc" #: common-cmds.h:12 msgid "Clone a repository into a new directory" @@ -4825,7 +8671,9 @@ msgstr "Ghi các thay đổi và o kho chứa" #: common-cmds.h:14 msgid "Show changes between commits, commit and working tree, etc" -msgstr "Hiển thị các thay đổi giữa những lần chuyển giao (commit), commit và cây là m việc, v.v.." +msgstr "" +"Hiển thị các thay đổi giữa những lần chuyển giao (commit), commit và cây là m " +"việc, v.v.." #: common-cmds.h:15 msgid "Download objects and refs from another repository" @@ -4837,15 +8685,18 @@ msgstr "In ra những dòng khá»›p vá»›i má»™t mẫu" #: common-cmds.h:17 msgid "Create an empty git repository or reinitialize an existing one" -msgstr "Tạo má»™t kho git trống rá»—ng hay khởi tạo lại má»™t kho đã tồn tại từ trước" +msgstr "" +"Tạo má»™t kho git trống rá»—ng hay khởi tạo lại má»™t kho đã tồn tại từ trước" #: common-cmds.h:18 msgid "Show commit logs" -msgstr "hiển thị nháºt ký các lần commit (chuyển giao)" +msgstr "Hiển thị nháºt ký các lần chuyển giao (commit)" #: common-cmds.h:19 msgid "Join two or more development histories together" -msgstr "Hợp nhất hai hay nhiá»u hÆ¡n lịch sá» cá»§a các nhà phát triển phần má»m lại vá»›i nhau" +msgstr "" +"Hợp nhất hai hay nhiá»u hÆ¡n lịch sá» cá»§a các nhà phát triển phần má»m lại vá»›i " +"nhau" #: common-cmds.h:20 msgid "Move or rename a file, a directory, or a symlink" @@ -4853,15 +8704,17 @@ msgstr "Di chuyển, đổi tên má»™t táºp tin, thư mục hay liên kết tư #: common-cmds.h:21 msgid "Fetch from and merge with another repository or a local branch" -msgstr "Fetch (lấy vá») và hòa trá»™ng vá»›i kho khác hay nhánh ná»™i bá»™" +msgstr "Lấy vá» (fetch) và hòa trá»™n vá»›i kho khác hay nhánh ná»™i bá»™" #: common-cmds.h:22 msgid "Update remote refs along with associated objects" -msgstr "Cáºp nháºt tham chiếu (refs) máy chá»§ cùng vá»›i các đối tượng liên quan đến nó" +msgstr "" +"Cáºp nháºt tham chiếu (refs) máy chá»§ cùng vá»›i các đối tượng liên quan đến nó" #: common-cmds.h:23 msgid "Forward-port local commits to the updated upstream head" -msgstr "Forward-port những lần chuyển giao ná»™i bá»™ tá»›i head dòng ngược đã cáºp nháºt" +msgstr "" +"Forward-port những lần chuyển giao ná»™i bá»™ tá»›i head thượng nguồn đã cáºp nháºt" #: common-cmds.h:24 msgid "Reset current HEAD to the specified state" @@ -4881,7 +8734,9 @@ msgstr "Hiển thị trạng thái cây là m việc" #: common-cmds.h:28 msgid "Create, list, delete or verify a tag object signed with GPG" -msgstr "Tạo, liệt kê, xóa hay xác thá»±c má»™t đối tượng thẻ (tag) mà nó được ký sá» dụng GPG" +msgstr "" +"Tạo, liệt kê, xóa hay xác thá»±c má»™t đối tượng thẻ (tag) mà nó được ký sá» dụng " +"GPG" #: git-am.sh:50 msgid "You need to set your committer info first" @@ -4892,27 +8747,34 @@ msgid "" "You seem to have moved HEAD since the last 'am' failure.\n" "Not rewinding to ORIG_HEAD" msgstr "" -"Bạn có lẽ đã có HEAD đã bị di chuyển Ä‘i kể từ lần 'am' thất bại cuối cùng.\n" +"Bạn có lẽ đã có HEAD đã bị di chuyển Ä‘i kể từ lần “am†thất bại cuối cùng.\n" "Không thể chuyển tá»›i ORIG_HEAD" #: git-am.sh:105 #, sh-format msgid "" -"When you have resolved this problem run \"$cmdline --resolved\".\n" -"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n" -"To restore the original branch and stop patching run \"$cmdline --abort\"." +"When you have resolved this problem, run \"$cmdline --resolved\".\n" +"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n" +"To restore the original branch and stop patching, run \"$cmdline --abort\"." msgstr "" "Khi bạn cần giải quyết vấn đỠnà y hãy chạy lệnh \"$cmdline --resolved\".\n" -"Nếu bạn có ý định bá» qua miếng vá, thay và o đó bạn chạy \"$cmdline --skip\".\n" -"Äể phục hồi lại thà nh nhánh nguyên bản và dừng việc vá lại thì chạy \"$cmdline --abort\"." +"Nếu bạn có ý định bá» qua miếng vá, thay và o đó bạn chạy \"$cmdline --skip" +"\".\n" +"Äể phục hồi lại thà nh nhánh nguyên thá»§y và dừng việc vá lại thì chạy " +"\"$cmdline --abort\"." #: git-am.sh:121 msgid "Cannot fall back to three-way merge." -msgstr "Äang trở lại để hòa trá»™n kiểu 'three-way'." +msgstr "Äang trở lại để hòa trá»™n kiểu “three-wayâ€." #: git-am.sh:137 msgid "Repository lacks necessary blobs to fall back on 3-way merge." -msgstr "Kho thiếu đối tượng blob cần thiết để trở vá» trên '3-way merge'." +msgstr "Kho thiếu đối tượng blob cần thiết để trở vá» trên “3-way mergeâ€." + +#: git-am.sh:139 +msgid "Using index info to reconstruct a base tree..." +msgstr "" +"Sá» dụng thông tin trong bảng mục lục để cấu trúc lại má»™t cây (tree) cÆ¡ sở..." #: git-am.sh:154 msgid "" @@ -4924,44 +8786,53 @@ msgstr "" #: git-am.sh:163 msgid "Falling back to patching base and 3-way merge..." -msgstr "Äang trở lại để vá cÆ¡ sở và '3-way merge'..." +msgstr "Äang trở lại để vá cÆ¡ sở và “3-way mergeâ€..." + +#: git-am.sh:179 +msgid "Failed to merge in the changes." +msgstr "Gặp lá»—i khi trá»™n và o các thay đổi." -#: git-am.sh:275 +#: git-am.sh:274 msgid "Only one StGIT patch series can be applied at once" msgstr "Chỉ có má»™t sê-ri miếng vá StGIT được áp dụng má»™t lúc" -#: git-am.sh:362 +#: git-am.sh:361 #, sh-format msgid "Patch format $patch_format is not supported." msgstr "Äịnh dạng miếng vá $patch_format không được há»— trợ." -#: git-am.sh:364 +#: git-am.sh:363 msgid "Patch format detection failed." msgstr "Dò tìm định dạng miếng vá gặp lá»—i." -#: git-am.sh:418 -msgid "-d option is no longer supported. Do not use." -msgstr "Tùy chá»n -d không còn được há»— trợ nữa. Xin đừng sá» dụng." +#: git-am.sh:389 +msgid "" +"The -b/--binary option has been a no-op for long time, and\n" +"it will be removed. Please do not use it anymore." +msgstr "" +"Tùy chá»n -b/--binary đã không dùng từ lâu rồi, và \n" +"nó sẽ được bá» Ä‘i. Xin đừng sá» dụng nó thêm nữa." -#: git-am.sh:481 +#: git-am.sh:477 #, sh-format msgid "previous rebase directory $dotest still exists but mbox given." msgstr "thư mục rebase trước $dotest vẫn chưa sẵn sà ng nhưng mbox được đưa ra." -#: git-am.sh:486 +#: git-am.sh:482 msgid "Please make up your mind. --skip or --abort?" msgstr "Xin hãy rõ rà ng. --skip hay --abort?" -#: git-am.sh:513 +#: git-am.sh:509 msgid "Resolve operation not in progress, we are not resuming." -msgstr "Thao tác phân giải không Ä‘ang được tiến hà nh, chúng ta không phục hồi lại." +msgstr "" +"Thao tác phân giải không Ä‘ang được tiến hà nh, chúng ta không phục hồi lại." -#: git-am.sh:579 +#: git-am.sh:575 #, sh-format msgid "Dirty index: cannot apply patches (dirty: $files)" msgstr "Bảng mục lục sai: không thể áp dụng các miếng vá (sai: $files)" -#: git-am.sh:671 +#: git-am.sh:679 #, sh-format msgid "" "Patch is empty. Was it split wrong?\n" @@ -4969,61 +8840,76 @@ msgid "" "To restore the original branch and stop patching run \"$cmdline --abort\"." msgstr "" "Miếng vá trống rá»—ng. Nó đã bị chia cắt sai phải không?\n" -"Nếu bạn thÃch bá» qua miếng vá nà y, hãy chạy lệnh sau để thay thế \"$cmdline --skip\".\n" -"Äể phục hồi lại nhánh nguyên bản và dừng vá lại hãy chạy lệnh \"$cmdline --abort\"." +"Nếu bạn thÃch bá» qua miếng vá nà y, hãy chạy lệnh sau để thay thế \"$cmdline " +"--skip\".\n" +"Äể phục hồi lại nhánh nguyên thá»§y và dừng vá lại hãy chạy lệnh \"$cmdline --" +"abort\"." -#: git-am.sh:708 +#: git-am.sh:706 msgid "Patch does not have a valid e-mail address." msgstr "Miếng vá không có địa chỉ e-mail hợp lệ." -#: git-am.sh:755 +#: git-am.sh:753 msgid "cannot be interactive without stdin connected to a terminal." -msgstr "không thể được tương tác mà không có stdin kết nối vá»›i má»™t thiết bị cuối" +msgstr "" +"không thể được tương tác mà không có stdin kết nối vá»›i má»™t thiết bị cuối" -#: git-am.sh:759 +#: git-am.sh:757 msgid "Commit Body is:" msgstr "Thân cá»§a lần chuyển giao (commit) là :" #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] #. in your translation. The program will only accept English #. input at this point. -#: git-am.sh:766 +#: git-am.sh:764 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " -msgstr "Ãp dụng? đồng ý [y]/không [n]/chỉnh sá»a [e]/hiển thị miếng [v]á/đồng ý tất cả [a]" +msgstr "" +"Ãp dụng? đồng ý [y]/không [n]/chỉnh sá»a [e]/hiển thị miếng [v]á/đồng ý tất " +"cả [a] " -#: git-am.sh:802 +#: git-am.sh:800 #, sh-format msgid "Applying: $FIRSTLINE" msgstr "Äang áp dụng (miếng vá): $FIRSTLINE" -#: git-am.sh:823 +#: git-am.sh:821 msgid "" "No changes - did you forget to use 'git add'?\n" "If there is nothing left to stage, chances are that something else\n" "already introduced the same changes; you might want to skip this patch." msgstr "" -"Không có thay đổi nà o - bạn đã quên sá» dụng lệnh 'git add' à ?\n" +"Không có thay đổi nà o - bạn đã quên sá» dụng lệnh “git add†à ?\n" "Nếu ở đây không có gì còn lại stage, tình cá» là có má»™t số thứ khác\n" -"đã sẵn được đưa và o vá»›i cùng ná»™i dung thay đổi; bạn có lẽ muốn bá» qua miếng vá nà y." +"đã sẵn được đưa và o vá»›i cùng ná»™i dung thay đổi; bạn có lẽ muốn bá» qua miếng " +"vá nà y." -#: git-am.sh:831 +#: git-am.sh:829 msgid "" "You still have unmerged paths in your index\n" "did you forget to use 'git add'?" msgstr "" "Bạn vẫn có những đưá»ng dẫn chưa được hòa trá»™n trong bảng mục lục cá»§a mình\n" -"bạn đã quên sá» dụng lệnh 'git add' à ?" +"bạn đã quên sá» dụng lệnh “git add†à ?" -#: git-am.sh:847 +#: git-am.sh:845 msgid "No changes -- Patch already applied." msgstr "Không thay đổi gì cả -- Miếng vá đã được áp dụng rồi." -#: git-am.sh:857 +#: git-am.sh:855 #, sh-format msgid "Patch failed at $msgnum $FIRSTLINE" msgstr "Vá gặp lá»—i tại $msgnum $FIRSTLINE" -#: git-am.sh:873 +#: git-am.sh:858 +#, sh-format +msgid "" +"The copy of the patch that failed is found in:\n" +" $dotest/patch" +msgstr "" +"Bản sao chép cá»§a miếng vá mà nó gặp lá»—i thì được tìm thấy trong:\n" +" $dotest/patch" + +#: git-am.sh:876 msgid "applying to an empty history" msgstr "áp dụng và o má»™t lịch sá» trống rá»—ng" @@ -5041,12 +8927,12 @@ msgstr "Bạn có muốn tôi thá»±c hiện Ä‘iá»u nà y cho bạn không [Y/n]? #: git-bisect.sh:95 #, sh-format msgid "unrecognised option: '$arg'" -msgstr "không công nháºn tùy chá»n: '$arg'" +msgstr "không công nháºn tùy chá»n: “$argâ€" #: git-bisect.sh:99 #, sh-format msgid "'$arg' does not appear to be a valid revision" -msgstr "'$arg' không có vẻ như là má»™t sá»± xét lại hợp lệ" +msgstr "â€$arg†không có vẻ như là má»™t sá»± xét lại hợp lệ" #: git-bisect.sh:117 msgid "Bad HEAD - I need a HEAD" @@ -5054,8 +8940,11 @@ msgstr "HEAD sai - Tôi cần má»™t HEAD" #: git-bisect.sh:130 #, sh-format -msgid "Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'." -msgstr "Việc checkout '$start_head' gặp lá»—i. Hãy thá» 'git bisect reset <nhánh_hợp_lệ>'." +msgid "" +"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'." +msgstr "" +"Việc checkout “$start_head†gặp lá»—i. Hãy thỠ“git bisect reset " +"<nhánh_hợp_lệ>â€." #: git-bisect.sh:140 msgid "won't bisect on seeked tree" @@ -5077,7 +8966,7 @@ msgstr "Äầu và o rev sai: $arg" #: git-bisect.sh:232 msgid "Please call 'bisect_state' with at least one argument." -msgstr "Hãy gá»i lệnhl 'bisect_state' vá»›i Ãt nhất má»™t đối số." +msgstr "Hãy gá»i lệnhl “bisect_state†vá»›i Ãt nhất má»™t đối số." #: git-bisect.sh:244 #, sh-format @@ -5086,20 +8975,21 @@ msgstr "Äầu và o rev sai: $rev" #: git-bisect.sh:250 msgid "'git bisect bad' can take only one argument." -msgstr "'git bisect bad' có thể lấy chỉ má»™t đối số." +msgstr "“git bisect bad†có thể lấy chỉ má»™t đối số." #. have bad but not good. we could bisect although #. this is less optimum. #: git-bisect.sh:273 msgid "Warning: bisecting only with a bad commit." -msgstr "Cảnh báo: chỉ thá»±c hiện việc bisect vá»›i má»™t lần chuyển giao (commit) sai." +msgstr "" +"Cảnh báo: chỉ thá»±c hiện việc bisect vá»›i má»™t lần chuyển giao (commit) sai." #. TRANSLATORS: Make sure to include [Y] and [n] in your #. translation. The program will only accept English input #. at this point. #: git-bisect.sh:279 msgid "Are you sure [Y/n]? " -msgstr "Bạn có chắc chắn chưa [Y/n]?" +msgstr "Bạn có chắc chắn chưa [Y/n]? " #: git-bisect.sh:289 msgid "" @@ -5116,18 +9006,18 @@ msgid "" "(You can use \"git bisect bad\" and \"git bisect good\" for that.)" msgstr "" "Bạn cần bắt đầu bằng lệnh \"git bisect start\".\n" -"Bạn sau đó cần phải chỉ cho tôi Ãt nhất má»™t Ä‘iểm xét duyệt đúng và má»™t Ä‘iểm sai.\n" +"Bạn sau đó cần phải chỉ cho tôi Ãt nhất má»™t Ä‘iểm xét duyệt đúng và má»™t Ä‘iểm " +"sai.\n" "(Bạn có thể sá» dụng \"git bisect bad\" và \"git bisect good\" cho chúng.)" -#: git-bisect.sh:347 -#: git-bisect.sh:474 +#: git-bisect.sh:347 git-bisect.sh:474 msgid "We are not bisecting." msgstr "Chúng tôi không bisect." #: git-bisect.sh:354 #, sh-format msgid "'$invalid' is not a valid commit" -msgstr "'$invalid' không phải là lần chuyển giao (commit) hợp lệ" +msgstr "â€$invalid†không phải là lần chuyển giao (commit) hợp lệ" #: git-bisect.sh:363 #, sh-format @@ -5135,8 +9025,8 @@ msgid "" "Could not check out original HEAD '$branch'.\n" "Try 'git bisect reset <commit>'." msgstr "" -"Không thể check out original HEAD '$branch'.\n" -"Hãy thá» 'git bisect reset <commit>'." +"Không thể check-out HEAD nguyên thá»§y cá»§a “$branchâ€.\n" +"Hãy thỠ“git bisect reset <lần-chuyển-giao>â€." #: git-bisect.sh:390 msgid "No logfile given" @@ -5163,7 +9053,7 @@ msgid "" "exit code $res from '$command' is < 0 or >= 128" msgstr "" "chạy bisect gặp lá»—i:\n" -"mã trả vá» $res từ lệnh '$command' là < 0 hoặc >= 128" +"mã trả vá» $res từ lệnh “$command†là < 0 hoặc >= 128" #: git-bisect.sh:453 msgid "bisect run cannot continue any more" @@ -5176,7 +9066,7 @@ msgid "" "'bisect_state $state' exited with error code $res" msgstr "" "chạy bisect gặp lá»—i:\n" -"'bisect_state $state' đã thoát ra vá»›i mã lá»—i $res" +"â€bisect_state $state†đã thoát ra vá»›i mã lá»—i $res" #: git-bisect.sh:466 msgid "bisect run success" @@ -5189,22 +9079,26 @@ msgid "" "as appropriate to mark resolution, or use 'git commit -a'." msgstr "" "Pull là không thể được bởi vì bạn có những táºp tin chưa được hòa trá»™n.\n" -"Xin hãy sá»a chữa chúng trước, và sau đó sá» dụng lệnh 'git add/rm <táºp-tin>'\n" -"để phê chuẩn việc đánh dấu đây cần được giải quyết, hoặc là sá» dụng 'git commit -a'." +"Xin hãy sá»a chữa chúng trước, và sau đó sá» dụng lệnh “git add/rm <táºp-tin>â€\n" +"để phê chuẩn việc đánh dấu đây cần được giải quyết, hoặc là sá» dụng “git " +"commit -aâ€." #: git-pull.sh:25 msgid "Pull is not possible because you have unmerged files." -msgstr "Full là không thể thá»±c hiện bởi vì bạn có những táºp tin chưa được hòa trá»™n." +msgstr "" +"Full là không thể thá»±c hiện bởi vì bạn có những táºp tin chưa được hòa trá»™n." #: git-pull.sh:197 msgid "updating an unborn branch with changes added to the index" -msgstr "Ä‘ang cáºp nháºt má»™t nhánh chưa được sinh ra vá»›i các thay đổi được thêm và o bảng mục lục" +msgstr "" +"Ä‘ang cáºp nháºt má»™t nhánh chưa được sinh ra vá»›i các thay đổi được thêm và o " +"bảng mục lục" #. The fetch involved updating the current branch. #. The working tree and the index file is still based on the #. $orig_head commit, but we are merging into $curr_head. #. First update the working tree to match $curr_head. -#: git-pull.sh:228 +#: git-pull.sh:229 #, sh-format msgid "" "Warning: fetch updated the current branch head.\n" @@ -5215,17 +9109,150 @@ msgstr "" "Cảnh báo: Ä‘ang fast-forward cây là m việc cá»§a bạn từ\n" "Cảnh báo: commit $orig_head." -#: git-pull.sh:253 +#: git-pull.sh:254 msgid "Cannot merge multiple branches into empty head" msgstr "Không thể hòa trá»™n nhiá»u nhánh và trong má»™t head trống rá»—ng" -#: git-pull.sh:257 +#: git-pull.sh:258 msgid "Cannot rebase onto multiple branches" msgstr "Không thể thá»±c hiện lệnh rebase (cÆ¡ cấu lại) trên nhiá»u nhánh" +#: git-rebase.sh:53 +msgid "" +"When you have resolved this problem, run \"git rebase --continue\".\n" +"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n" +"To check out the original branch and stop rebasing, run \"git rebase --abort" +"\"." +msgstr "" +"Khi bạn cần giải quyết vấn đỠnà y hãy chạy lệnh \"git rebase --continue\".\n" +"Nếu bạn có ý định bá» qua miếng vá, thay và o đó bạn chạy \"git rebase --skip" +"\".\n" +"Äể phục hồi lại thà nh nhánh nguyên thá»§y và dừng việc vá lại thì chạy \"git " +"rebase --abort\"." + +#: git-rebase.sh:160 +msgid "The pre-rebase hook refused to rebase." +msgstr "Móc (hook) pre-rebase từ chối rebase." + +#: git-rebase.sh:165 +msgid "It looks like git-am is in progress. Cannot rebase." +msgstr "" +"Hình như Ä‘ang trong quá trình thá»±c hiện lệnh git-am. Không thể chạy lệnh " +"rebase." + +#: git-rebase.sh:296 +msgid "The --exec option must be used with the --interactive option" +msgstr "Tùy chá»n --exec phải được sá» dụng cùng vá»›i tùy chá»n --interactive" + +#: git-rebase.sh:301 +msgid "No rebase in progress?" +msgstr "Không có tiến trình rebase nà o phải không?" + +#: git-rebase.sh:312 +msgid "The --edit-todo action can only be used during interactive rebase." +msgstr "" +"Hà nh động “--edit-todo†chỉ có thể dùng trong quá trình “rebase†(sá»a lịch " +"sá») tương tác." + +#: git-rebase.sh:319 +msgid "Cannot read HEAD" +msgstr "Không thể Ä‘á»c HEAD" + +#: git-rebase.sh:322 +msgid "" +"You must edit all merge conflicts and then\n" +"mark them as resolved using git add" +msgstr "" +"Bạn phải sá»a tất cả các lần hòa trá»™n xung đột và sau\n" +"đó đánh dấu chúng là cần xá» lý sá» dụng lệnh git add" + +#: git-rebase.sh:340 +#, sh-format +msgid "Could not move back to $head_name" +msgstr "Không thể quay trở lại $head_name" + +#: git-rebase.sh:359 +#, sh-format +msgid "" +"It seems that there is already a $state_dir_base directory, and\n" +"I wonder if you are in the middle of another rebase. If that is the\n" +"case, please try\n" +"\t$cmd_live_rebase\n" +"If that is not the case, please\n" +"\t$cmd_clear_stale_rebase\n" +"and run me again. I am stopping in case you still have something\n" +"valuable there." +msgstr "" +"Hình như là ở đây sẵn có má»™t thư mục $state_dir_base directory, và \n" +"Tôi tá»± há»i có phải bạn Ä‘ang ở giữa má»™t lệnh rebase khác. Nếu đúng là \n" +"như váºy, xin hãy thá»\n" +"\t$cmd_live_rebase\n" +"Nếu không phải thế, hãy thá»\n" +"\t$cmd_clear_stale_rebase\n" +"và chạy TÔI lần nữa. TÔI dừng lại trong trưá»ng hợp bạn vẫn\n" +"có má»™t số thứ quý giá ở đây.\n" +"\n" +"TÔI: là lệnh bạn vừa gá»i!" + +#: git-rebase.sh:404 +#, sh-format +msgid "invalid upstream $upstream_name" +msgstr "thượng nguồn không hợp lệ $upstream_name" + +#: git-rebase.sh:428 +#, sh-format +msgid "$onto_name: there are more than one merge bases" +msgstr "$onto_name: ở đây có nhiá»u hÆ¡n má»™t ná»n móng hòa trá»™n" + +#: git-rebase.sh:431 git-rebase.sh:435 +#, sh-format +msgid "$onto_name: there is no merge base" +msgstr "$onto_name: ở đây không có ná»n móng hòa trá»™n nà o" + +#: git-rebase.sh:440 +#, sh-format +msgid "Does not point to a valid commit: $onto_name" +msgstr "Không chỉ đến má»™t lần chuyển giao (commit) không hợp lệ: $onto_name" + +#: git-rebase.sh:463 +#, sh-format +msgid "fatal: no such branch: $branch_name" +msgstr "nghiêm trá»ng: không có nhánh như thế: $branch_name" + +#: git-rebase.sh:483 +msgid "Please commit or stash them." +msgstr "Xin hãy commit hoặc tạm cất (stash) chúng." + +#: git-rebase.sh:501 +#, sh-format +msgid "Current branch $branch_name is up to date." +msgstr "Nhánh hiện tại $branch_name đã được cáºp nháºt rồi." + +#: git-rebase.sh:504 +#, sh-format +msgid "Current branch $branch_name is up to date, rebase forced." +msgstr "Nhánh hiện tại $branch_name đã được cáºp nháºt rồi, lệnh rebase ép buá»™c." + +#: git-rebase.sh:515 +#, sh-format +msgid "Changes from $mb to $onto:" +msgstr "Thay đổi từ $mb thà nh $onto:" + +#. Detach HEAD and reset the tree +#: git-rebase.sh:524 +msgid "First, rewinding head to replay your work on top of it..." +msgstr "" +"Trước tiên, di chuyển head để xem lại các công việc trên đỉnh cá»§a nó..." + +#: git-rebase.sh:532 +#, sh-format +msgid "Fast-forwarded $branch_name to $onto_name." +msgstr "Fast-forward $branch_name thà nh $onto_name." + #: git-stash.sh:51 msgid "git stash clear with parameters is unimplemented" -msgstr "git stash clear vá»›i các tham số là chưa được thá»±c hiện (không nháºn đối số)" +msgstr "" +"git stash clear vá»›i các tham số là chưa được thá»±c hiện (không nháºn đối số)" #: git-stash.sh:74 msgid "You do not have the initial commit yet" @@ -5235,8 +9262,7 @@ msgstr "Bạn chưa còn có lần chuyển giao (commit) khởi tạo" msgid "Cannot save the current index state" msgstr "Không thể ghi lại trạng thái bảng mục lục hiện hà nh" -#: git-stash.sh:123 -#: git-stash.sh:136 +#: git-stash.sh:123 git-stash.sh:136 msgid "Cannot save the current worktree state" msgstr "Không thể ghi lại trạng thái cây-là m-việc hiện hà nh" @@ -5268,8 +9294,8 @@ msgid "" "error: unknown option for 'stash save': $option\n" " To provide a message, use git stash save -- '$option'" msgstr "" -"lá»—i: không hiểu tùy chá»n cho 'stash save': $option\n" -" Äể cung cấp má»™t thông Ä‘iệp, sá» dụng git stash save -- '$option'" +"lá»—i: không hiểu tùy chá»n cho “stash saveâ€: $option\n" +" Äể cung cấp má»™t thông Ä‘iệp, sá» dụng git stash save -- “$optionâ€" #: git-stash.sh:223 msgid "No local changes to save" @@ -5289,7 +9315,7 @@ msgstr "Không thể gỡ bá» các thay đổi cây-là m-việc" #: git-stash.sh:352 msgid "No stash found." -msgstr "Không tìm thấy stast nà o." +msgstr "Không tìm thấy stash nà o." #: git-stash.sh:359 #, sh-format @@ -5304,12 +9330,12 @@ msgstr "$reference không phải là tham chiếu hợp lệ" #: git-stash.sh:393 #, sh-format msgid "'$args' is not a stash-like commit" -msgstr "'$args' không phải là lần chuyển giao (commit) giống-stash" +msgstr "â€$args†không phải là lần chuyển giao (commit) giống-stash" #: git-stash.sh:404 #, sh-format msgid "'$args' is not a stash reference" -msgstr "'$args' không phải tham chiếu đến stash" +msgstr "â€$args†không phải tham chiếu đến stash" #: git-stash.sh:412 msgid "unable to refresh index" @@ -5331,224 +9357,336 @@ msgstr "Không thể ghi lại cây chỉ mục" msgid "Cannot unstage modified files" msgstr "Không thể bá» trạng thÃa cá»§a các táºp tin đã được sá»a chữa" -#: git-stash.sh:474 +#: git-stash.sh:475 msgid "Index was not unstashed." msgstr "Bảng mục lục đã không được bá» stash." -#: git-stash.sh:491 +#: git-stash.sh:492 #, sh-format msgid "Dropped ${REV} ($s)" msgstr "Äã hạ xuống ${REV} ($s)" -#: git-stash.sh:492 +#: git-stash.sh:493 #, sh-format msgid "${REV}: Could not drop stash entry" msgstr "${REV}: Không thể xóa bá» mục stash" -#: git-stash.sh:499 +#: git-stash.sh:500 msgid "No branch name specified" msgstr "Chưa chỉ ra tên cá»§a nhánh" -#: git-stash.sh:570 +#: git-stash.sh:571 msgid "(To restore them type \"git stash apply\")" msgstr "(Äể phục hồi lại chúng hãy gõ \"git stash apply\")" -#: git-submodule.sh:56 +#: git-submodule.sh:89 #, sh-format msgid "cannot strip one component off url '$remoteurl'" -msgstr "không thể tháo bá» má»™t thà nh phần ra khá»i url '$remoteurl'" +msgstr "không thể tháo bá» má»™t thà nh phần ra khá»i “$remoteurl†url" -#: git-submodule.sh:109 +#: git-submodule.sh:168 #, sh-format msgid "No submodule mapping found in .gitmodules for path '$sm_path'" -msgstr "Không tìm thấy ánh xạ (mapping) mô-Ä‘un-con trong .gitmodules cho đưá»ng dẫn '$sm_path'" +msgstr "" +"Không tìm thấy ánh xạ (mapping) mô-Ä‘un-con trong .gitmodules cho đưá»ng dẫn " +"“$sm_pathâ€" -#: git-submodule.sh:150 +#: git-submodule.sh:211 #, sh-format msgid "Clone of '$url' into submodule path '$sm_path' failed" -msgstr "Nhân bản '$url' và o đưá»ng dẫn mô-Ä‘un-con '$sm_path' gặp lá»—i" +msgstr "Nhân bản “$url†và o đưá»ng dẫn mô-Ä‘un-con “$sm_path†gặp lá»—i" -#: git-submodule.sh:160 +#: git-submodule.sh:223 #, sh-format msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa" -msgstr "Gitdir '$a' là bá»™ pháºn cá»§a đưá»ng dẫn mô-Ä‘un-con '$b' hoặc \"vice versa\"" +msgstr "" +"Gitdir “$a†là bá»™ pháºn cá»§a đưá»ng dẫn mô-Ä‘un-con “$b†hoặc \"vice versa\"" -#: git-submodule.sh:249 +#: git-submodule.sh:316 #, sh-format msgid "repo URL: '$repo' must be absolute or begin with ./|../" -msgstr "repo URL: '$repo' phải là đưá»ng dẫn tuyệt đối hoặc là bắt đầu bằng ./|../" +msgstr "" +"repo URL: “$repo†phải là đưá»ng dẫn tuyệt đối hoặc là bắt đầu bằng ./|../" -#: git-submodule.sh:266 +#: git-submodule.sh:333 #, sh-format msgid "'$sm_path' already exists in the index" -msgstr "'$sm_path' thá»±c sá»± đã tồn tại ở bảng mục lục rồi" +msgstr "â€$sm_path†thá»±c sá»± đã tồn tại ở bảng mục lục rồi" -#: git-submodule.sh:270 +#: git-submodule.sh:337 #, sh-format msgid "" "The following path is ignored by one of your .gitignore files:\n" "$sm_path\n" "Use -f if you really want to add it." msgstr "" -"Các đưá»ng dẫn theo sau đây sẽ bị lá» Ä‘i bởi má»™t trong các táºp tin .gitignore cá»§a bạn:\n" +"Các đưá»ng dẫn theo sau đây sẽ bị lá» Ä‘i bởi má»™t trong các táºp tin .gitignore " +"cá»§a bạn:\n" "$sm_path\n" "Sá» dụng -f nếu bạn thá»±c sá»± muốn thêm nó và o." -#: git-submodule.sh:281 +#: git-submodule.sh:355 #, sh-format msgid "Adding existing repo at '$sm_path' to the index" -msgstr "Äang thêm repo có sẵn tại '$sm_path' và o bảng mục lục" +msgstr "Äang thêm repo có sẵn tại “$sm_path†và o bảng mục lục" -#: git-submodule.sh:283 +#: git-submodule.sh:357 #, sh-format msgid "'$sm_path' already exists and is not a valid git repo" -msgstr "'$sm_path' đã tồn tại từ trước và không phải là má»™t kho git hợp lệ" +msgstr "â€$sm_path†đã tồn tại từ trước và không phải là má»™t kho git hợp lệ" + +#: git-submodule.sh:365 +#, sh-format +msgid "A git directory for '$sm_name' is found locally with remote(s):" +msgstr "" +"Thư mục git cho '$sm_name' được tìm thấy má»™t cách cục bá»™ vá»›i các máy chá»§:" + +#: git-submodule.sh:367 +#, sh-format +msgid "" +"If you want to reuse this local git directory instead of cloning again from" +msgstr "Nếu bạn muốn dùng lại thư mục git ná»™i bá»™ nà y thay vì nhân bản từ nó" + +#: git-submodule.sh:369 +#, sh-format +msgid "" +"use the '--force' option. If the local git directory is not the correct repo" +msgstr "" +"dùng tùy chá»n '--force'. Nếu thư mục git ná»™i bá»™ không phải là repo (kho) đúng" -#: git-submodule.sh:297 +#: git-submodule.sh:370 +#, sh-format +msgid "" +"or you are unsure what this means choose another name with the '--name' " +"option." +msgstr "" +"hay bạn không chắc chắn Ä‘iá»u đó có nghÄ©a gì chá»n tên khác vá»›i tùy chá»n '--" +"name'." + +#: git-submodule.sh:372 +#, sh-format +msgid "Reactivating local git directory for submodule '$sm_name'." +msgstr "" +"Phục hồi sá»± hoạt động cá»§a thư mục git ná»™i bá»™ cho mô-Ä‘un-con '$sm_name'." + +#: git-submodule.sh:384 #, sh-format msgid "Unable to checkout submodule '$sm_path'" -msgstr "Không thể checkout mô-Ä‘un con '$sm_path'" +msgstr "Không thể checkout mô-Ä‘un con “$sm_pathâ€" -#: git-submodule.sh:302 +#: git-submodule.sh:389 #, sh-format msgid "Failed to add submodule '$sm_path'" -msgstr "Gặp lá»—i khi thêm mô-Ä‘un con '$sm_path'" +msgstr "Gặp lá»—i khi thêm mô-Ä‘un con “$sm_pathâ€" -#: git-submodule.sh:307 +#: git-submodule.sh:394 #, sh-format msgid "Failed to register submodule '$sm_path'" -msgstr "Gặp lá»—i khi đăng ký vá»›i hệ thống mô-Ä‘un con '$sm_path'" +msgstr "Gặp lá»—i khi đăng ký vá»›i hệ thống mô-Ä‘un con “$sm_pathâ€" -#: git-submodule.sh:349 +#: git-submodule.sh:437 #, sh-format msgid "Entering '$prefix$sm_path'" -msgstr "Äang nháºp '$prefix$sm_path'" +msgstr "Äang nháºp “$prefix$sm_pathâ€" -#: git-submodule.sh:363 +#: git-submodule.sh:451 #, sh-format msgid "Stopping at '$sm_path'; script returned non-zero status." -msgstr "Dừng lại tại '$sm_path'; script trả vá» trạng thái khác không." +msgstr "Dừng lại tại “$sm_pathâ€; script trả vá» trạng thái khác không." -#: git-submodule.sh:406 +#: git-submodule.sh:495 #, sh-format msgid "No url found for submodule path '$sm_path' in .gitmodules" -msgstr "Không tìm thấy url cho đưá»ng dẫn mô-Ä‘un-con '$sm_path' trong .gitmodules" +msgstr "" +"Không tìm thấy url cho đưá»ng dẫn mô-Ä‘un-con “$sm_path†trong .gitmodules" -#: git-submodule.sh:415 +#: git-submodule.sh:504 #, sh-format msgid "Failed to register url for submodule path '$sm_path'" -msgstr "Gặp lá»—i khi đăng ký url cho đưá»ng dẫn mô-Ä‘un-con '$sm_path'" +msgstr "Gặp lá»—i khi đăng ký url cho đưá»ng dẫn mô-Ä‘un-con “$sm_pathâ€" -#: git-submodule.sh:417 +#: git-submodule.sh:506 #, sh-format msgid "Submodule '$name' ($url) registered for path '$sm_path'" -msgstr "Mô-Ä‘un-con '$name' ($url) được đăng ký cho đưá»ng dẫn '$sm_path'" +msgstr "Mô-Ä‘un-con “$name†($url) được đăng ký cho đưá»ng dẫn “$sm_pathâ€" -#: git-submodule.sh:425 +#: git-submodule.sh:514 #, sh-format msgid "Failed to register update mode for submodule path '$sm_path'" -msgstr "Gặp lá»—i khi đăng ký chế độ cáºp nháºt cho đưá»ng dẫn mô-Ä‘un-con '$sm_path'" +msgstr "" +"Gặp lá»—i khi đăng ký chế độ cáºp nháºt cho đưá»ng dẫn mô-Ä‘un-con “$sm_pathâ€" -#: git-submodule.sh:524 +#: git-submodule.sh:614 #, sh-format msgid "" "Submodule path '$sm_path' not initialized\n" "Maybe you want to use 'update --init'?" msgstr "" -"ÄÆ°á»ng dẫn mô-Ä‘un-con '$sm_path' chưa được khởi tạo\n" -"Có lẽ bạn muốn sá» dụng lệnh 'update --init'?" +"ÄÆ°á»ng dẫn mô-Ä‘un-con “$sm_path†chưa được khởi tạo\n" +"Có lẽ bạn muốn sá» dụng lệnh “update --initâ€?" -#: git-submodule.sh:537 +#: git-submodule.sh:627 #, sh-format msgid "Unable to find current revision in submodule path '$sm_path'" -msgstr "Không tìm thấy Ä‘iểm xét lại hiện hà nh trong đưá»ng dẫn mô-Ä‘un-con '$sm_path'" +msgstr "" +"Không tìm thấy Ä‘iểm xét lại hiện hà nh trong đưá»ng dẫn mô-Ä‘un-con “$sm_pathâ€" -#: git-submodule.sh:556 +#: git-submodule.sh:646 #, sh-format msgid "Unable to fetch in submodule path '$sm_path'" -msgstr "Không thể lấy vá» (fetch) trong đưá»ng dẫn mô-Ä‘un-con '$sm_path'" +msgstr "Không thể lấy vá» (fetch) trong đưá»ng dẫn mô-Ä‘un-con “$sm_pathâ€" -#: git-submodule.sh:570 +#: git-submodule.sh:660 #, sh-format msgid "Unable to rebase '$sha1' in submodule path '$sm_path'" -msgstr "Không thể rebase '$sha1' trong đưá»ng dẫn mô-Ä‘un-con '$sm_path'" +msgstr "Không thể rebase “$sha1†trong đưá»ng dẫn mô-Ä‘un-con “$sm_pathâ€" -#: git-submodule.sh:571 +#: git-submodule.sh:661 #, sh-format msgid "Submodule path '$sm_path': rebased into '$sha1'" -msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con '$sm_path': được rebase và o trong '$sha1'" +msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “$sm_pathâ€: được rebase và o trong “$sha1â€" -#: git-submodule.sh:576 +#: git-submodule.sh:666 #, sh-format msgid "Unable to merge '$sha1' in submodule path '$sm_path'" -msgstr "Không thể hòa trá»™n (merge) '$sha1' trong đưá»ng dẫn mô-Ä‘un-con '$sm_path'" +msgstr "" +"Không thể hòa trá»™n (merge) “$sha1†trong đưá»ng dẫn mô-Ä‘un-con “$sm_pathâ€" -#: git-submodule.sh:577 +#: git-submodule.sh:667 #, sh-format msgid "Submodule path '$sm_path': merged in '$sha1'" -msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con '$sm_path': được hòa trá»™n và o '$sha1'" +msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “$sm_pathâ€: được hòa trá»™n và o “$sha1â€" -#: git-submodule.sh:582 +#: git-submodule.sh:672 #, sh-format msgid "Unable to checkout '$sha1' in submodule path '$sm_path'" -msgstr "Không thể checkout '$sha1' trong đưá»ng dẫn mô-Ä‘un-con '$sm_path'" +msgstr "Không thể checkout “$sha1†trong đưá»ng dẫn mô-Ä‘un-con “$sm_pathâ€" -#: git-submodule.sh:583 +#: git-submodule.sh:673 #, sh-format msgid "Submodule path '$sm_path': checked out '$sha1'" -msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con '$sm_path': được checkout '$sha1'" +msgstr "ÄÆ°á»ng dẫn mô-Ä‘un-con “$sm_pathâ€: được checkout “$sha1â€" -#: git-submodule.sh:605 -#: git-submodule.sh:928 +#: git-submodule.sh:695 git-submodule.sh:1017 #, sh-format msgid "Failed to recurse into submodule path '$sm_path'" -msgstr "Gặp lá»—i khi đệ quy và o trong đưá»ng dẫn mô-Ä‘un-con '$sm_path'" +msgstr "Gặp lá»—i khi đệ quy và o trong đưá»ng dẫn mô-Ä‘un-con “$sm_pathâ€" -#: git-submodule.sh:713 -msgid "--cached cannot be used with --files" -msgstr "--cached không thể được sá» dụng cùng vá»›i --files" +#: git-submodule.sh:803 +msgid "The --cached option cannot be used with the --files option" +msgstr "Tùy chá»n --cached không thể dùng cùng vá»›i tùy chá»n --files" #. unexpected type -#: git-submodule.sh:753 +#: git-submodule.sh:843 #, sh-format msgid "unexpected mode $mod_dst" msgstr "chế độ không như mong chá» $mod_dst" -#: git-submodule.sh:771 +#: git-submodule.sh:861 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_src" msgstr " Cảnh báo: $name không chứa lần chuyển giao (commit) $sha1_src" -#: git-submodule.sh:774 +#: git-submodule.sh:864 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_dst" msgstr " Cảnh báo: $name không chứa lần chuyển giao (commit) $sha1_dst" -#: git-submodule.sh:777 +#: git-submodule.sh:867 #, sh-format msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst" -msgstr " Cảnh báo: $name không chứa những lần chuyển giao (commit) $sha1_src và $sha1_dst" +msgstr "" +" Cảnh báo: $name không chứa những lần chuyển giao (commit) $sha1_src và " +"$sha1_dst" -#: git-submodule.sh:802 +#: git-submodule.sh:892 msgid "blob" msgstr "blob" -#: git-submodule.sh:803 -msgid "submodule" -msgstr "mô-Ä‘un con" - -#: git-submodule.sh:840 +#: git-submodule.sh:930 msgid "# Submodules changed but not updated:" -msgstr "# Những mô-Ä‘un-con đã bị thay đổi nhưng chưa được cáºp nháºt:" +msgstr "# Các mô-Ä‘un-con đã bị thay đổi nhưng chưa được cáºp nháºt:" -#: git-submodule.sh:842 +#: git-submodule.sh:932 msgid "# Submodule changes to be committed:" msgstr "# Những thay đổi mô-Ä‘un-con được chuyển giao (commit):" -#: git-submodule.sh:974 +#: git-submodule.sh:1080 #, sh-format -msgid "Synchronizing submodule url for '$name'" -msgstr "Äang đồng bá»™ hóa url mô-Ä‘un-con cho '$name'" +msgid "Synchronizing submodule url for '$prefix$sm_path'" +msgstr "Url Mô-Ä‘un-con đồng bá»™ hóa cho '$prefix$sm_path'" + +#~ msgid "git remote set-head <name> (-a | -d | <branch>])" +#~ msgstr "git remote set-head <tên> (-a | -d | <nhánh>])" + +#~ msgid " 0 files changed" +#~ msgstr " 0 có táºp tin nà o thay đổi cả" + +#~ msgid " %d file changed" +#~ msgid_plural " %d files changed" +#~ msgstr[0] " %d táºp tin thay đổi" +#~ msgstr[1] " %d táºp tin thay đổi" + +#~ msgid ", %d insertion(+)" +#~ msgid_plural ", %d insertions(+)" +#~ msgstr[0] ", %d thêm(+)" +#~ msgstr[1] ", %d thêm(+)" + +#~ msgid ", %d deletion(-)" +#~ msgid_plural ", %d deletions(-)" +#~ msgstr[0] ", %d xóa(-)" +#~ msgstr[1] ", %d xóa(-)" + +#~ msgid "Auto packing the repository for optimum performance.\n" +#~ msgstr "Tá»± động đóng gói kho chứa để tối ưu hóa hiệu suất là m việc.\n" + +#~ msgid " (use \"git add\" to track)" +#~ msgstr " (dùng \"git add\" để theo dõi dấu vết)" + +#~ msgid "-B cannot be used with -b" +#~ msgstr "tùy chá»n -B không thể dùng -b" + +#~ msgid "--patch is incompatible with all other options" +#~ msgstr "--patch xung khắc vá»›i tất cả các tùy chá»n khác" + +#~ msgid "--detach cannot be used with -b/-B/--orphan" +#~ msgstr "--detach không thể được sá» dụng vá»›i tùy chá»n -b/-B/--orphan" + +#~ msgid "--detach cannot be used with -t" +#~ msgstr "--detach không thể được sá» dụng vá»›i tùy chá»n -t" + +#~ msgid "--orphan and -b|-B are mutually exclusive" +#~ msgstr "Tùy chá»n --orphan và -b|-B loại từ lẫn nhau" + +#~ msgid "--orphan cannot be used with -t" +#~ msgstr "--orphan không thể được sá» dụng vá»›i tùy chá»n -t" + +#~ msgid "git checkout: -f and -m are incompatible" +#~ msgstr "git checkout: hai tùy chá»n -f và -m xung khắc nhau" + +#~ msgid "" +#~ "git checkout: updating paths is incompatible with switching branches." +#~ msgstr "" +#~ "git checkout: việc cáºp nháºt các đưá»ng dẫn là xung khắc vá»›i việc chuyển " +#~ "đổi các nhánh." + +#~ msgid "diff setup failed" +#~ msgstr "cà i đặt diff gặp lá»—i" + +#~ msgid "merge-recursive: disk full?" +#~ msgstr "merge-recursive: đĩa bị đầy?" + +#~ msgid "diff_setup_done failed" +#~ msgstr "diff_setup_done gặp lá»—i" + +#~ msgid "-d option is no longer supported. Do not use." +#~ msgstr "Tùy chá»n -d không còn được há»— trợ nữa. Xin đừng sá» dụng." + +#~ msgid "%s: has been deleted/renamed" +#~ msgstr "%s: đã được xóa/thay-tên" + +#~ msgid "'%s': not a documentation directory." +#~ msgstr "â€%sâ€: không phải là má»™t thư mục tà i liệu." #~ msgid "--" #~ msgstr "--" @@ -5557,14 +9695,5 @@ msgstr "Äang đồng bá»™ hóa url mô-Ä‘un-con cho '$name'" #~ msgstr "" #~ "Không thể rút trÃch địa chỉ thư Ä‘iện tá» từ định danh ngưá»i chuyển giao" -#, fuzzy #~ msgid "could not parse commit %s\n" -#~ msgstr "Không thể phân tÃch commit (lần chuyển giao) %s\n" - -#, fuzzy -#~ msgid "cherry-pick" -#~ msgstr "< Chá»n D-Mod" - -#, fuzzy -#~ msgid "Too many options specified" -#~ msgstr "đã ghi rõ quá nhiá»u kÃch cỡ" +#~ msgstr "không thể phân tÃch commit (lần chuyển giao) %s\n" diff --git a/po/zh_CN.po b/po/zh_CN.po index b46b53e6d..46d158ffd 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: Git\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2012-06-08 10:20+0800\n" -"PO-Revision-Date: 2012-06-08 12:24+0800\n" +"POT-Creation-Date: 2012-09-15 10:21+0800\n" +"PO-Revision-Date: 2012-09-07 17:56+0800\n" "Last-Translator: Jiang Xin <worldhello.net@gmail.com>\n" "Language-Team: GitHub <https://github.com/gotgit/git/>\n" "Language: zh_CN\n" @@ -42,6 +42,95 @@ msgstr "" "'git add/rm <file>' æ ‡è®°è§£å†³æ–¹æ¡ˆï¼Œ\n" "或使用 'git commit -a'。" +#: archive.c:10 +#, fuzzy +msgid "git archive [options] <tree-ish> [<path>...]" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: archive.c:11 +#, fuzzy +msgid "git archive --list" +msgstr "git archive:NACK %s" + +#: archive.c:12 +msgid "" +"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]" +msgstr "" + +#: archive.c:13 +msgid "git archive --remote <repo> [--exec <cmd>] --list" +msgstr "" + +#: archive.c:322 +msgid "fmt" +msgstr "" + +#: archive.c:322 +msgid "archive format" +msgstr "" + +#: archive.c:323 builtin/log.c:1079 +msgid "prefix" +msgstr "" + +#: archive.c:324 +msgid "prepend prefix to each pathname in the archive" +msgstr "" + +#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2332 +#: builtin/blame.c:2333 builtin/config.c:56 builtin/fast-export.c:642 +#: builtin/fast-export.c:644 builtin/grep.c:800 builtin/hash-object.c:77 +#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:537 +#: builtin/notes.c:694 builtin/read-tree.c:107 parse-options.h:149 +msgid "file" +msgstr "文件" + +#: archive.c:326 builtin/archive.c:92 +msgid "write the archive to this file" +msgstr "" + +#: archive.c:328 +#, fuzzy +msgid "read .gitattributes in working directory" +msgstr "%s:已ç»å˜åœ¨äºŽå·¥ä½œåŒºä¸" + +#: archive.c:329 +msgid "report archived files on stderr" +msgstr "" + +#: archive.c:330 +msgid "store only" +msgstr "" + +#: archive.c:331 +msgid "compress faster" +msgstr "" + +#: archive.c:339 +msgid "compress better" +msgstr "" + +#: archive.c:342 +msgid "list supported archive formats" +msgstr "" + +#: archive.c:344 builtin/archive.c:93 builtin/clone.c:85 +msgid "repo" +msgstr "" + +#: archive.c:345 builtin/archive.c:94 +msgid "retrieve the archive from remote repository <repo>" +msgstr "" + +#: archive.c:346 builtin/archive.c:95 builtin/notes.c:616 +#, fuzzy +msgid "command" +msgstr "è¿è¡Œ $command" + +#: archive.c:347 builtin/archive.c:96 +msgid "path to the remote git-upload-archive command" +msgstr "" + #: bundle.c:36 #, c-format msgid "'%s' does not look like a v2 bundle file" @@ -52,7 +141,7 @@ msgstr "'%s' ä¸åƒæ˜¯ä¸€ä¸ª v2 版本的包文件" msgid "unrecognized header: %s%s (%d)" msgstr "未能识别的包头:%s%s (%d)" -#: bundle.c:89 builtin/commit.c:696 +#: bundle.c:89 builtin/commit.c:714 #, c-format msgid "could not open '%s'" msgstr "ä¸èƒ½æ‰“å¼€ '%s'" @@ -61,8 +150,8 @@ msgstr "ä¸èƒ½æ‰“å¼€ '%s'" msgid "Repository lacks these prerequisite commits:" msgstr "版本库缺少这些必备的æäº¤ï¼š" -#: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:289 -#: builtin/log.c:720 builtin/log.c:1309 builtin/log.c:1528 builtin/merge.c:347 +#: bundle.c:164 sequencer.c:557 sequencer.c:989 builtin/log.c:290 +#: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347 #: builtin/shortlog.c:181 msgid "revision walk setup failed" msgstr "版本é历设置失败" @@ -75,44 +164,48 @@ msgstr[0] "这个包ä¸å«æœ‰ %d 个引用" msgstr[1] "这个包ä¸å«æœ‰ %d 个引用" #: bundle.c:192 +msgid "The bundle records a complete history." +msgstr "这个包记录一个完整历å²ã€‚" + +#: bundle.c:195 #, c-format msgid "The bundle requires this ref" msgid_plural "The bundle requires these %d refs" msgstr[0] "这个包需è¦è¿™ä¸ªå¼•用" msgstr[1] "è¿™ä¸ªåŒ…éœ€è¦ %d 个这些引用" -#: bundle.c:290 +#: bundle.c:294 msgid "rev-list died" msgstr "rev-list 终æ¢" -#: bundle.c:296 builtin/log.c:1205 builtin/shortlog.c:284 +#: bundle.c:300 builtin/log.c:1209 builtin/shortlog.c:284 #, c-format msgid "unrecognized argument: %s" msgstr "æœªèƒ½è¯†åˆ«çš„å‚æ•°ï¼š%s" -#: bundle.c:331 +#: bundle.c:335 #, c-format msgid "ref '%s' is excluded by the rev-list options" msgstr "引用 '%s' 被 rev-list 选项排除" -#: bundle.c:376 +#: bundle.c:380 msgid "Refusing to create empty bundle." msgstr "ä¸èƒ½åˆ›å»ºç©ºåŒ…。" -#: bundle.c:394 +#: bundle.c:398 msgid "Could not spawn pack-objects" msgstr "ä¸èƒ½ç”Ÿæˆ pack-objects 进程" -#: bundle.c:412 +#: bundle.c:416 msgid "pack-objects died" msgstr "pack-objects 终æ¢" -#: bundle.c:415 +#: bundle.c:419 #, c-format msgid "cannot create '%s'" msgstr "ä¸èƒ½åˆ›å»º '%s'" -#: bundle.c:437 +#: bundle.c:441 msgid "index-pack died" msgstr "index-pack 终æ¢" @@ -232,32 +325,32 @@ msgstr "" "å‘现é…ç½®å˜é‡ 'diff.dirstat' ä¸çš„错误:\n" "%s" -#: diff.c:1400 -msgid " 0 files changed\n" -msgstr " 0 个文件被修改\n" +#: diff.c:1401 +msgid " 0 files changed" +msgstr " 0 个文件被修改" -#: diff.c:1404 +#: diff.c:1405 #, c-format msgid " %d file changed" msgid_plural " %d files changed" msgstr[0] " %d 个文件被修改" msgstr[1] " %d 个文件被修改" -#: diff.c:1421 +#: diff.c:1422 #, c-format msgid ", %d insertion(+)" msgid_plural ", %d insertions(+)" msgstr[0] ",æ’å…¥ %d 行(+)" msgstr[1] ",æ’å…¥ %d 行(+)" -#: diff.c:1432 +#: diff.c:1433 #, c-format msgid ", %d deletion(-)" msgid_plural ", %d deletions(-)" msgstr[0] "ï¼Œåˆ é™¤ %d 行(-)" msgstr[1] "ï¼Œåˆ é™¤ %d 行(-)" -#: diff.c:3478 +#: diff.c:3460 #, c-format msgid "" "Failed to parse --dirstat/-X option parameter:\n" @@ -293,16 +386,16 @@ msgstr "'%s':%s" msgid "'%s': short read %s" msgstr "'%s':读å–ä¸å®Œæ•´ %s" -#: help.c:207 +#: help.c:212 #, c-format msgid "available git commands in '%s'" msgstr "在 '%s' 下å¯ç”¨çš„ git 命令" -#: help.c:214 +#: help.c:219 msgid "git commands available from elsewhere on your $PATH" msgstr "在 $PATH 路径ä¸çš„其他地方å¯ç”¨çš„ git 命令" -#: help.c:270 +#: help.c:275 #, c-format msgid "" "'%s' appears to be a git command, but we were not\n" @@ -311,11 +404,11 @@ msgstr "" "'%s' åƒæ˜¯ä¸€ä¸ª git å‘½ä»¤ï¼Œä½†å´æ— 法è¿è¡Œã€‚\n" "å¯èƒ½æ˜¯ git-%s å—æŸï¼Ÿ" -#: help.c:327 +#: help.c:332 msgid "Uh oh. Your system reports no Git commands at all." msgstr "å”‰å‘€ï¼Œæ‚¨çš„ç³»ç»Ÿä¸æœªå‘现 Git 命令。" -#: help.c:349 +#: help.c:354 #, c-format msgid "" "WARNING: You called a Git command named '%s', which does not exist.\n" @@ -324,17 +417,17 @@ msgstr "" "è¦å‘Šï¼šæ‚¨è¿è¡Œä¸€ä¸ªä¸å˜åœ¨çš„ Git 命令 '%s'ã€‚ç»§ç»æ‰§è¡Œå‡å®šæ‚¨è¦è¦è¿è¡Œçš„\n" "是 '%s'" -#: help.c:354 +#: help.c:359 #, c-format msgid "in %0.1f seconds automatically..." msgstr "在 %0.1f ç§’é’ŸåŽè‡ªåЍè¿è¡Œ..." -#: help.c:361 +#: help.c:366 #, c-format msgid "git: '%s' is not a git command. See 'git --help'." msgstr "git:'%s' 䏿˜¯ä¸€ä¸ª git 命令。å‚è§ 'git --help'。" -#: help.c:365 +#: help.c:370 msgid "" "\n" "Did you mean this?" @@ -346,38 +439,292 @@ msgstr[0] "" "您指的是这个么?" msgstr[1] "" "\n" -"您指的是这些其ä¸ä¸€ä¸ªä¹ˆï¼Ÿ" +"您指的是这其ä¸çš„æŸä¸€ä¸ªä¹ˆï¼Ÿ" + +#: merge-recursive.c:190 +#, c-format +msgid "(bad commit)\n" +msgstr "(åæäº¤ï¼‰\n" + +#: merge-recursive.c:206 +#, c-format +msgid "addinfo_cache failed for path '%s'" +msgstr "为路径 '%s' addinfo_cache 失败" + +#: merge-recursive.c:268 +msgid "error building trees" +msgstr "æ— æ³•åˆ›å»ºæ ‘" + +#: merge-recursive.c:672 +#, c-format +msgid "failed to create path '%s'%s" +msgstr "æ— æ³•åˆ›å»ºè·¯å¾„ '%s'%s" + +#: merge-recursive.c:683 +#, c-format +msgid "Removing %s to make room for subdirectory\n" +msgstr "åˆ é™¤ %s 以便为å目录留出空间\n" + +#. something else exists +#. .. but not some other error (who really cares what?) +#: merge-recursive.c:697 merge-recursive.c:718 +msgid ": perhaps a D/F conflict?" +msgstr ":å¯èƒ½æ˜¯ä¸€ä¸ªç›®å½•/文件冲çªï¼Ÿ" + +#: merge-recursive.c:708 +#, c-format +msgid "refusing to lose untracked file at '%s'" +msgstr "æ‹’ç»ä¸¢å¼ƒ '%s' ä¸çš„æœªè·Ÿè¸ªæ–‡ä»¶" + +#: merge-recursive.c:748 +#, c-format +msgid "cannot read object %s '%s'" +msgstr "ä¸èƒ½è¯»å–对象 %s '%s'" + +#: merge-recursive.c:750 +#, c-format +msgid "blob expected for %s '%s'" +msgstr "%s '%s' 应为二进制对象(blob)" + +#: merge-recursive.c:773 builtin/clone.c:302 +#, c-format +msgid "failed to open '%s'" +msgstr "æ— æ³•æ‰“å¼€ '%s'" + +#: merge-recursive.c:781 +#, c-format +msgid "failed to symlink '%s'" +msgstr "æ— æ³•åˆ›å»ºç¬¦å·é“¾æŽ¥ '%s'" + +#: merge-recursive.c:784 +#, c-format +msgid "do not know what to do with %06o %s '%s'" +msgstr "ä¸çŸ¥é“å¦‚ä½•å¤„ç† %06o %s '%s'" + +#: merge-recursive.c:922 +msgid "Failed to execute internal merge" +msgstr "æ— æ³•æ‰§è¡Œå†…éƒ¨åˆå¹¶" + +#: merge-recursive.c:926 +#, c-format +msgid "Unable to add %s to database" +msgstr "ä¸èƒ½æ·»åŠ %s 至对象库" + +#: merge-recursive.c:942 +msgid "unsupported object type in the tree" +msgstr "åœ¨æ ‘ä¸æœ‰ä¸æ”¯æŒçš„对象类型" + +#: merge-recursive.c:1021 merge-recursive.c:1035 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree." +msgstr "" +"冲çªï¼ˆ%1$s/åˆ é™¤ï¼‰ï¼š%2$s 在 %3$s ä¸è¢«åˆ 除,在 %5$s ä¸è¢« %4$s。%7$s 在 %6$s ä¸" +"的版本被ä¿ç•™ã€‚" + +#: merge-recursive.c:1027 merge-recursive.c:1040 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree at %s." +msgstr "" +"冲çªï¼ˆ%1$s/åˆ é™¤ï¼‰ï¼š%2$s 在 %3$s ä¸è¢«åˆ 除,在 %5$s ä¸è¢« %4$s。%7$s 在 %6$s ä¸" +"的版本ä¿ç•™äºŽ %8$s ä¸ã€‚" + +#: merge-recursive.c:1081 +msgid "rename" +msgstr "é‡å‘½å" + +#: merge-recursive.c:1081 +msgid "renamed" +msgstr "é‡å‘½å" + +#: merge-recursive.c:1137 +#, c-format +msgid "%s is a directory in %s adding as %s instead" +msgstr "%s 是 %s ä¸çš„一个目录而以 %s 为åè¢«æ·»åŠ " + +#: merge-recursive.c:1159 +#, c-format +msgid "" +"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s" +"\"->\"%s\" in \"%s\"%s" +msgstr "" +"冲çªï¼ˆé‡å‘½å/é‡å‘½å):在分支 \"%3$s\" ä¸é‡å‘½å \"%1$s\"->\"%2$s\",在分支 " +"\"%6$s\" ä¸é‡å‘½å \"%4$s\"->\"%5$s\"%7$s" + +#: merge-recursive.c:1164 +msgid " (left unresolved)" +msgstr "(留下未解决)" + +#: merge-recursive.c:1218 +#, c-format +msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s" +msgstr "" +"冲çªï¼ˆé‡å‘½å/é‡å‘½å):在 %3$s ä¸é‡å‘½å %1$s->%2$s,在 %6$s ä¸é‡å‘½å %4$s->" +"%5$s" + +#: merge-recursive.c:1248 +#, c-format +msgid "Renaming %s to %s and %s to %s instead" +msgstr "而是é‡å‘½å %s 至 %s ä»¥åŠ %s 至 %s" + +#: merge-recursive.c:1447 +#, c-format +msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s" +msgstr "冲çªï¼ˆé‡å‘½å/æ·»åŠ ï¼‰ï¼šåœ¨ %3$s ä¸é‡å‘½å %1$s->%2$s。在 %5$s 䏿·»åŠ %4$s" + +#: merge-recursive.c:1457 +#, c-format +msgid "Adding merged %s" +msgstr "æ·»åŠ åˆå¹¶åŽçš„ %s" + +#: merge-recursive.c:1462 merge-recursive.c:1660 +#, c-format +msgid "Adding as %s instead" +msgstr "而是以 %s ä¸ºåæ·»åŠ " + +#: merge-recursive.c:1513 +#, c-format +msgid "cannot read object %s" +msgstr "ä¸èƒ½è¯»å–对象 %s" + +#: merge-recursive.c:1516 +#, c-format +msgid "object %s is not a blob" +msgstr "对象 %s 䏿˜¯ä¸€ä¸ªäºŒè¿›åˆ¶å¯¹è±¡ï¼ˆblob)" + +#: merge-recursive.c:1564 +msgid "modify" +msgstr "修改" + +#: merge-recursive.c:1564 +msgid "modified" +msgstr "修改" + +#: merge-recursive.c:1574 +msgid "content" +msgstr "内容" + +#: merge-recursive.c:1581 +msgid "add/add" +msgstr "æ·»åŠ /æ·»åŠ " + +#: merge-recursive.c:1615 +#, c-format +msgid "Skipped %s (merged same as existing)" +msgstr "略过 %s(已ç»åšè¿‡ç›¸åŒåˆå¹¶ï¼‰" + +#: merge-recursive.c:1629 +#, c-format +msgid "Auto-merging %s" +msgstr "自动åˆå¹¶ %s" + +#: merge-recursive.c:1633 git-submodule.sh:869 +msgid "submodule" +msgstr "忍¡ç»„" + +#: merge-recursive.c:1634 +#, c-format +msgid "CONFLICT (%s): Merge conflict in %s" +msgstr "冲çªï¼ˆ%s):åˆå¹¶å†²çªäºŽ %s" + +#: merge-recursive.c:1724 +#, c-format +msgid "Removing %s" +msgstr "åˆ é™¤ %s" + +#: merge-recursive.c:1749 +msgid "file/directory" +msgstr "文件/目录" + +#: merge-recursive.c:1755 +msgid "directory/file" +msgstr "目录/文件" + +#: merge-recursive.c:1760 +#, c-format +msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s" +msgstr "冲çªï¼ˆ%1$s):在 %3$s 䏿œ‰ä¸€ä¸ªå为 %2$s 的目录。以 %5$s ä¸ºåæ·»åŠ %4$s" + +#: merge-recursive.c:1770 +#, c-format +msgid "Adding %s" +msgstr "æ·»åŠ %s" -#: parse-options.c:493 +#: merge-recursive.c:1787 +msgid "Fatal merge failure, shouldn't happen." +msgstr "严é‡çš„åˆå¹¶é”™è¯¯ï¼Œä¸åº”å‘生。" + +#: merge-recursive.c:1806 +msgid "Already up-to-date!" +msgstr "å·²ç»æ˜¯æœ€æ–°çš„ï¼" + +#: merge-recursive.c:1815 +#, c-format +msgid "merging of trees %s and %s failed" +msgstr "æ— æ³•åˆå¹¶æ ‘ %s å’Œ %s" + +#: merge-recursive.c:1845 +#, c-format +msgid "Unprocessed path??? %s" +msgstr "未处ç†çš„路径??? %s" + +#: merge-recursive.c:1890 +msgid "Merging:" +msgstr "åˆå¹¶ï¼š" + +#: merge-recursive.c:1903 +#, c-format +msgid "found %u common ancestor:" +msgid_plural "found %u common ancestors:" +msgstr[0] "å‘现 %u 个共åŒç¥–先:" +msgstr[1] "å‘现 %u 个共åŒç¥–先:" + +#: merge-recursive.c:1940 +msgid "merge returned no commit" +msgstr "åˆå¹¶æœªè¿”回æäº¤" + +#: merge-recursive.c:1997 +#, c-format +msgid "Could not parse object '%s'" +msgstr "ä¸èƒ½è§£æžå¯¹è±¡ '%s'" + +#: merge-recursive.c:2009 builtin/merge.c:696 +msgid "Unable to write index." +msgstr "ä¸èƒ½å†™å…¥ç´¢å¼•。" + +#: parse-options.c:494 msgid "..." msgstr "..." -#: parse-options.c:511 +#: parse-options.c:512 #, c-format msgid "usage: %s" msgstr "用法:%s" #. TRANSLATORS: the colon here should align with the #. one in "usage: %s" translation -#: parse-options.c:515 +#: parse-options.c:516 #, c-format msgid " or: %s" msgstr " 或:%s" # 译者:为ä¿è¯åœ¨è¾“出ä¸å¯¹é½ï¼Œæ³¨æ„调整å¥ä¸ç©ºæ ¼ï¼ -#: parse-options.c:518 +#: parse-options.c:519 #, c-format msgid " %s" msgstr " %s" -#: remote.c:1629 +#: remote.c:1632 #, c-format msgid "Your branch is ahead of '%s' by %d commit.\n" msgid_plural "Your branch is ahead of '%s' by %d commits.\n" msgstr[0] "您的分支领先 '%s' å…± %d 个æäº¤ã€‚\n" msgstr[1] "您的分支领先 '%s' å…± %d 个æäº¤ã€‚\n" -#: remote.c:1635 +#: remote.c:1638 #, c-format msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n" msgid_plural "" @@ -385,7 +732,7 @@ msgid_plural "" msgstr[0] "您的分支è½åŽ '%s' å…± %d 个æäº¤ï¼Œå¹¶ä¸”å¯ä»¥å¿«è¿›ã€‚\n" msgstr[1] "您的分支è½åŽ '%s' å…± %d 个æäº¤ï¼Œå¹¶ä¸”å¯ä»¥å¿«è¿›ã€‚\n" -#: remote.c:1643 +#: remote.c:1646 #, c-format msgid "" "Your branch and '%s' have diverged,\n" @@ -395,19 +742,19 @@ msgid_plural "" "and have %d and %d different commits each, respectively.\n" msgstr[0] "" "您的分支和 '%s' 出现了å离,\n" -"并且å„自分别有 %d å’Œ %d 处ä¸åŒçš„æäº¤ã€‚\n" +"并且分别有 %d å’Œ %d 处ä¸åŒçš„æäº¤ã€‚\n" msgstr[1] "" "您的分支和 '%s' 出现了å离,\n" -"并且å„自分别有 %d å’Œ %d 处ä¸åŒçš„æäº¤ã€‚\n" +"并且分别有 %d å’Œ %d 处ä¸åŒçš„æäº¤ã€‚\n" -#: sequencer.c:121 builtin/merge.c:865 builtin/merge.c:978 -#: builtin/merge.c:1088 builtin/merge.c:1098 +#: sequencer.c:121 builtin/merge.c:864 builtin/merge.c:977 +#: builtin/merge.c:1087 builtin/merge.c:1097 #, c-format msgid "Could not open '%s' for writing" msgstr "ä¸èƒ½ä¸ºå†™å…¥æ‰“å¼€ '%s'" -#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:868 -#: builtin/merge.c:1090 builtin/merge.c:1103 +#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:867 +#: builtin/merge.c:1089 builtin/merge.c:1102 #, c-format msgid "Could not write to '%s'" msgstr "ä¸èƒ½å†™å…¥ '%s'" @@ -429,7 +776,7 @@ msgstr "" "冲çªè§£å†³å®Œæ¯•åŽï¼Œç”¨ 'git add <paths>' 或 'git rm <paths>'\n" "对修æ£åŽçš„æ–‡ä»¶åšæ ‡è®°ï¼Œç„¶åŽç”¨ 'git commit' æäº¤" -#: sequencer.c:160 sequencer.c:758 sequencer.c:841 +#: sequencer.c:160 sequencer.c:765 sequencer.c:848 #, c-format msgid "Could not write to %s" msgstr "ä¸èƒ½å†™å…¥ %s" @@ -465,473 +812,608 @@ msgstr "ä¸èƒ½è§£æž HEAD æäº¤\n" msgid "Unable to update cache tree\n" msgstr "ä¸èƒ½æ›´æ–°ç¼“å˜\n" -#: sequencer.c:324 +#: sequencer.c:327 #, c-format msgid "Could not parse commit %s\n" msgstr "ä¸èƒ½è§£æžæäº¤ %s\n" -#: sequencer.c:329 +#: sequencer.c:332 #, c-format msgid "Could not parse parent commit %s\n" msgstr "ä¸èƒ½è§£æžçˆ¶æäº¤ %s\n" -#: sequencer.c:395 +#: sequencer.c:398 msgid "Your index file is unmerged." msgstr "您的索引文件未完æˆåˆå¹¶ã€‚" -#: sequencer.c:398 +#: sequencer.c:401 msgid "You do not have a valid HEAD" msgstr "您没有一个有效的 HEAD" -#: sequencer.c:413 +#: sequencer.c:416 #, c-format msgid "Commit %s is a merge but no -m option was given." msgstr "æäº¤ %s 是一个åˆå¹¶æäº¤ä½†æœªæä¾› -m 选项。" -#: sequencer.c:421 +#: sequencer.c:424 #, c-format msgid "Commit %s does not have parent %d" msgstr "æäº¤ %s 没有父æäº¤ %d" -#: sequencer.c:425 +#: sequencer.c:428 #, c-format msgid "Mainline was specified but commit %s is not a merge." msgstr "指定了主线但æäº¤ %s 䏿˜¯ä¸€ä¸ªåˆå¹¶ã€‚" #. TRANSLATORS: The first %s will be "revert" or #. "cherry-pick", the second %s a SHA1 -#: sequencer.c:436 +#: sequencer.c:439 #, c-format msgid "%s: cannot parse parent commit %s" msgstr "%s:ä¸èƒ½è§£æžçˆ¶æäº¤ %s" -#: sequencer.c:440 +#: sequencer.c:443 #, c-format msgid "Cannot get commit message for %s" msgstr "ä¸èƒ½å¾—到 %s çš„æäº¤è¯´æ˜Ž" -#: sequencer.c:524 +#: sequencer.c:527 #, c-format msgid "could not revert %s... %s" msgstr "ä¸èƒ½è¿˜åŽŸ %s... %s" -#: sequencer.c:525 +#: sequencer.c:528 #, c-format msgid "could not apply %s... %s" msgstr "ä¸èƒ½åº”用 %s... %s" -#: sequencer.c:553 +#: sequencer.c:560 msgid "empty commit set passed" msgstr "æä¾›äº†ç©ºçš„æäº¤é›†" -#: sequencer.c:561 +#: sequencer.c:568 #, c-format msgid "git %s: failed to read the index" msgstr "git %sï¼šæ— æ³•è¯»å–索引" -#: sequencer.c:566 +#: sequencer.c:573 #, c-format msgid "git %s: failed to refresh the index" msgstr "git %sï¼šæ— æ³•åˆ·æ–°ç´¢å¼•" -#: sequencer.c:624 +#: sequencer.c:631 #, c-format msgid "Cannot %s during a %s" msgstr "æ— æ³• %s 在一个 %s 过程ä¸" -#: sequencer.c:646 +#: sequencer.c:653 #, c-format msgid "Could not parse line %d." msgstr "ä¸èƒ½è§£æžç¬¬ %d 行。" -#: sequencer.c:651 +#: sequencer.c:658 msgid "No commits parsed." msgstr "没有æäº¤è¢«è§£æžã€‚" -#: sequencer.c:664 +#: sequencer.c:671 #, c-format msgid "Could not open %s" msgstr "ä¸èƒ½æ‰“å¼€ %s" -#: sequencer.c:668 +#: sequencer.c:675 #, c-format msgid "Could not read %s." msgstr "ä¸èƒ½è¯»å– %s。" -#: sequencer.c:675 +#: sequencer.c:682 #, c-format msgid "Unusable instruction sheet: %s" msgstr "æ— ç”¨çš„æŒ‡ä»¤è¡¨å•:%s" -#: sequencer.c:703 +#: sequencer.c:710 #, c-format msgid "Invalid key: %s" msgstr "æ— æ•ˆé”®å:%s" -#: sequencer.c:706 +#: sequencer.c:713 #, c-format msgid "Invalid value for %s: %s" msgstr "%s çš„å€¼æ— æ•ˆï¼š%s" -#: sequencer.c:718 +#: sequencer.c:725 #, c-format msgid "Malformed options sheet: %s" msgstr "éžæ³•的选项表å•:%s" -#: sequencer.c:739 +#: sequencer.c:746 msgid "a cherry-pick or revert is already in progress" msgstr "一个拣选或还原æ“作已在进行" -#: sequencer.c:740 +#: sequencer.c:747 msgid "try \"git cherry-pick (--continue | --quit | --abort)\"" msgstr "å°è¯• \"git cherry-pick (--continue | --quit | --abort)\"" -#: sequencer.c:744 +#: sequencer.c:751 #, c-format msgid "Could not create sequencer directory %s" msgstr "ä¸èƒ½åˆ›å»ºåºåˆ—目录 %s" -#: sequencer.c:760 sequencer.c:845 +#: sequencer.c:767 sequencer.c:852 #, c-format msgid "Error wrapping up %s." msgstr "错误收尾 %s。" -#: sequencer.c:779 sequencer.c:913 +#: sequencer.c:786 sequencer.c:920 msgid "no cherry-pick or revert in progress" -msgstr "没有拣选或还原æ“作在进行" +msgstr "拣选或还原æ“作并未进行" -#: sequencer.c:781 +#: sequencer.c:788 msgid "cannot resolve HEAD" msgstr "ä¸èƒ½è§£æž HEAD" -#: sequencer.c:783 +#: sequencer.c:790 msgid "cannot abort from a branch yet to be born" msgstr "ä¸èƒ½ä»Žå°šæœªå»ºç«‹çš„分支终æ¢" -#: sequencer.c:805 builtin/apply.c:3697 +#: sequencer.c:812 builtin/apply.c:4005 #, c-format msgid "cannot open %s: %s" msgstr "ä¸èƒ½æ‰“å¼€ %s:%s" -#: sequencer.c:808 +#: sequencer.c:815 #, c-format msgid "cannot read %s: %s" msgstr "ä¸èƒ½è¯»å– %s:%s" -#: sequencer.c:809 +#: sequencer.c:816 msgid "unexpected end of file" -msgstr "未预期的文件结æŸ" +msgstr "æ„外的文件结æŸ" -#: sequencer.c:815 +#: sequencer.c:822 #, c-format msgid "stored pre-cherry-pick HEAD file '%s' is corrupt" msgstr "ä¿å˜æ‹£é€‰æäº¤å‰çš„ HEAD 文件 '%s' æŸå" -#: sequencer.c:838 +#: sequencer.c:845 #, c-format msgid "Could not format %s." msgstr "ä¸èƒ½æ ¼å¼åŒ– %s。" -#: sequencer.c:1000 +#: sequencer.c:1007 msgid "Can't revert as initial commit" msgstr "ä¸èƒ½ä½œä¸ºåˆå§‹æäº¤è¿˜åŽŸ" -#: sequencer.c:1001 +#: sequencer.c:1008 msgid "Can't cherry-pick into empty head" msgstr "ä¸èƒ½æ‹£é€‰åˆ°ç©ºåˆ†æ”¯" -#: sha1_name.c:864 +#: sha1_name.c:1044 msgid "HEAD does not point to a branch" msgstr "HEAD 没有指å‘一个分支" -#: sha1_name.c:867 +#: sha1_name.c:1047 #, c-format msgid "No such branch: '%s'" msgstr "没有æ¤åˆ†æ”¯ï¼š'%s'" -#: sha1_name.c:869 +#: sha1_name.c:1049 #, c-format msgid "No upstream configured for branch '%s'" msgstr "尚未给分支 '%s' 设置上游" -#: sha1_name.c:872 +#: sha1_name.c:1052 #, c-format msgid "Upstream branch '%s' not stored as a remote-tracking branch" msgstr "上游分支 '%s' 没有å˜å‚¨ä¸ºä¸€ä¸ªè¿œç¨‹è·Ÿè¸ªåˆ†æ”¯" -#: wrapper.c:413 +#: wrapper.c:408 +#, fuzzy, c-format +msgid "unable to access '%s': %s" +msgstr "ä¸èƒ½åˆ›å»º '%s'" + +#: wrapper.c:426 #, c-format msgid "unable to look up current user in the passwd file: %s" -msgstr "æ— æ³•åœ¨ passwd æ–‡ä»¶ä¸æŸ¥è¯¢åˆ°å½“å‰ç”¨æˆ·ï¼š%s" +msgstr "æ— æ³•åœ¨ passwd æ–‡ä»¶ä¸æŸ¥è¯¢åˆ°è¯¥ç”¨æˆ·ï¼š%s" -#: wrapper.c:414 +#: wrapper.c:427 msgid "no such user" msgstr "æ— æ¤ç”¨æˆ·" -#: wt-status.c:135 +#: wt-status.c:140 msgid "Unmerged paths:" msgstr "未åˆå¹¶çš„路径:" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: wt-status.c:141 wt-status.c:158 +#: wt-status.c:167 wt-status.c:194 #, c-format msgid " (use \"git reset %s <file>...\" to unstage)" msgstr " (使用 \"git reset %s <file>...\" 撤出暂å˜åŒºï¼‰" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: wt-status.c:143 wt-status.c:160 +#: wt-status.c:169 wt-status.c:196 msgid " (use \"git rm --cached <file>...\" to unstage)" msgstr " (使用 \"git rm --cached <file>...\" 撤出暂å˜åŒºï¼‰" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: wt-status.c:144 +#: wt-status.c:173 +msgid " (use \"git add <file>...\" to mark resolution)" +msgstr " (使用 \"git add <file>...\" æ ‡è®°è§£å†³æ–¹æ¡ˆï¼‰" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:175 wt-status.c:179 msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" msgstr " (酌情使用 \"git add/rm <file>...\" æ ‡è®°è§£å†³æ–¹æ¡ˆï¼‰" -#: wt-status.c:152 +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:177 +msgid " (use \"git rm <file>...\" to mark resolution)" +msgstr " (使用 \"git rm <file>...\" æ ‡è®°è§£å†³æ–¹æ¡ˆï¼‰" + +#: wt-status.c:188 msgid "Changes to be committed:" msgstr "è¦æäº¤çš„å˜æ›´ï¼š" -#: wt-status.c:170 +#: wt-status.c:206 msgid "Changes not staged for commit:" msgstr "尚未暂å˜ä»¥å¤‡æäº¤çš„å˜æ›´ï¼š" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: wt-status.c:174 +#: wt-status.c:210 msgid " (use \"git add <file>...\" to update what will be committed)" msgstr " (使用 \"git add <file>...\" æ›´æ–°è¦æäº¤çš„å†…å®¹ï¼‰" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: wt-status.c:176 +#: wt-status.c:212 msgid " (use \"git add/rm <file>...\" to update what will be committed)" msgstr " (使用 \"git add/rm <file>...\" æ›´æ–°è¦æäº¤çš„å†…å®¹ï¼‰" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: wt-status.c:177 +#: wt-status.c:213 msgid "" " (use \"git checkout -- <file>...\" to discard changes in working directory)" msgstr " (使用 \"git checkout -- <file>...\" 丢弃工作区的改动)" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: wt-status.c:179 +#: wt-status.c:215 msgid " (commit or discard the untracked or modified content in submodules)" msgstr " (æäº¤æˆ–ä¸¢å¼ƒåæ¨¡ç»„䏿œªè·Ÿè¸ªæˆ–修改的内容)" -#: wt-status.c:188 -#, c-format -msgid "%s files:" -msgstr "%s文件:" - # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: wt-status.c:191 +#: wt-status.c:227 #, c-format msgid " (use \"git %s <file>...\" to include in what will be committed)" msgstr " (使用 \"git %s <file>...\" 以包å«è¦æäº¤çš„内容)" -#: wt-status.c:208 +#: wt-status.c:244 msgid "bug" msgstr "bug" -#: wt-status.c:213 +#: wt-status.c:249 msgid "both deleted:" msgstr "åŒæ–¹åˆ 除:" -#: wt-status.c:214 +#: wt-status.c:250 msgid "added by us:" msgstr "ç”±æˆ‘ä»¬æ·»åŠ ï¼š" -#: wt-status.c:215 +#: wt-status.c:251 msgid "deleted by them:" msgstr "ç”±ä»–ä»¬åˆ é™¤ï¼š" -#: wt-status.c:216 +#: wt-status.c:252 msgid "added by them:" msgstr "ç”±ä»–ä»¬æ·»åŠ ï¼š" -#: wt-status.c:217 +#: wt-status.c:253 msgid "deleted by us:" msgstr "ç”±æˆ‘ä»¬åˆ é™¤ï¼š" -#: wt-status.c:218 +#: wt-status.c:254 msgid "both added:" msgstr "åŒæ–¹æ·»åŠ ï¼š" -#: wt-status.c:219 +#: wt-status.c:255 msgid "both modified:" msgstr "åŒæ–¹ä¿®æ”¹ï¼š" # 译者:末尾两个å—节å¯èƒ½è¢«åˆ å‡ï¼Œå¦‚æžœç¿»è¯‘ä¸ºä¸æ–‡æ ‡ç‚¹ä¼šå‡ºçްåŠä¸ªæ±‰å— -#: wt-status.c:249 +#: wt-status.c:285 msgid "new commits, " msgstr "æ–°æäº¤, " # 译者:末尾两个å—节å¯èƒ½è¢«åˆ å‡ï¼Œå¦‚æžœç¿»è¯‘ä¸ºä¸æ–‡æ ‡ç‚¹ä¼šå‡ºçްåŠä¸ªæ±‰å— -#: wt-status.c:251 +#: wt-status.c:287 msgid "modified content, " msgstr "修改的内容, " # 译者:末尾两个å—节å¯èƒ½è¢«åˆ å‡ï¼Œå¦‚æžœç¿»è¯‘ä¸ºä¸æ–‡æ ‡ç‚¹ä¼šå‡ºçްåŠä¸ªæ±‰å— -#: wt-status.c:253 +#: wt-status.c:289 msgid "untracked content, " msgstr "未跟踪的内容, " # 译者:为ä¿è¯åœ¨è¾“出ä¸å¯¹é½ï¼Œæ³¨æ„调整å¥ä¸ç©ºæ ¼ï¼ -#: wt-status.c:267 +#: wt-status.c:303 #, c-format msgid "new file: %s" msgstr "新文件: %s" # 译者:为ä¿è¯åœ¨è¾“出ä¸å¯¹é½ï¼Œæ³¨æ„调整å¥ä¸ç©ºæ ¼ï¼ -#: wt-status.c:270 +#: wt-status.c:306 #, c-format msgid "copied: %s -> %s" msgstr "æ‹·è´ï¼š %s -> %s" # 译者:为ä¿è¯åœ¨è¾“出ä¸å¯¹é½ï¼Œæ³¨æ„调整å¥ä¸ç©ºæ ¼ï¼ -#: wt-status.c:273 +#: wt-status.c:309 #, c-format msgid "deleted: %s" msgstr "åˆ é™¤ï¼š %s" # 译者:为ä¿è¯åœ¨è¾“出ä¸å¯¹é½ï¼Œæ³¨æ„调整å¥ä¸ç©ºæ ¼ï¼ -#: wt-status.c:276 +#: wt-status.c:312 #, c-format msgid "modified: %s" msgstr "修改: %s" # 译者:为ä¿è¯åœ¨è¾“出ä¸å¯¹é½ï¼Œæ³¨æ„调整å¥ä¸ç©ºæ ¼ï¼ -#: wt-status.c:279 +#: wt-status.c:315 #, c-format msgid "renamed: %s -> %s" msgstr "é‡å‘½å: %s -> %s" # 译者:为ä¿è¯åœ¨è¾“出ä¸å¯¹é½ï¼Œæ³¨æ„调整å¥ä¸ç©ºæ ¼ï¼ -#: wt-status.c:282 +#: wt-status.c:318 #, c-format msgid "typechange: %s" msgstr "ç±»åž‹å˜æ›´ï¼š %s" # 译者:为ä¿è¯åœ¨è¾“出ä¸å¯¹é½ï¼Œæ³¨æ„调整å¥ä¸ç©ºæ ¼ï¼ -#: wt-status.c:285 +#: wt-status.c:321 #, c-format msgid "unknown: %s" msgstr "未知: %s" # 译者:为ä¿è¯åœ¨è¾“出ä¸å¯¹é½ï¼Œæ³¨æ„调整å¥ä¸ç©ºæ ¼ï¼ -#: wt-status.c:288 +#: wt-status.c:324 #, c-format msgid "unmerged: %s" msgstr "未åˆå¹¶ï¼š %s" -#: wt-status.c:291 +#: wt-status.c:327 #, c-format msgid "bug: unhandled diff status %c" msgstr "bug:未处ç†çš„å·®å¼‚çŠ¶æ€ %c" -#: wt-status.c:737 +#: wt-status.c:785 +msgid "You have unmerged paths." +msgstr "您有尚未åˆå¹¶çš„路径。" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:788 wt-status.c:912 +msgid " (fix conflicts and run \"git commit\")" +msgstr " (解决冲çªå¹¶è¿è¡Œ \"git commit\")" + +#: wt-status.c:791 +msgid "All conflicts fixed but you are still merging." +msgstr "所有冲çªå·²è§£å†³ä½†æ‚¨ä»å¤„于åˆå¹¶ä¸ã€‚" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:794 +msgid " (use \"git commit\" to conclude merge)" +msgstr " (使用 \"git commit\" 结æŸåˆå¹¶ï¼‰" + +#: wt-status.c:804 +msgid "You are in the middle of an am session." +msgstr "您æ£å¤„于一个 am 过程ä¸ã€‚" + +#: wt-status.c:807 +msgid "The current patch is empty." +msgstr "当å‰çš„è¡¥ä¸ä¸ºç©ºã€‚" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:811 +msgid " (fix conflicts and then run \"git am --resolved\")" +msgstr " (解决冲çªï¼Œç„¶åŽè¿è¡Œ \"git am --resolved\")" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:813 +msgid " (use \"git am --skip\" to skip this patch)" +msgstr " (使用 \"git am --skip\" 跳过æ¤è¡¥ä¸ï¼‰" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:815 +msgid " (use \"git am --abort\" to restore the original branch)" +msgstr " (使用 \"git am --abort\" æ¢å¤åŽŸæœ‰åˆ†æ”¯ï¼‰" + +#: wt-status.c:873 wt-status.c:883 +msgid "You are currently rebasing." +msgstr "您æ£åœ¨å˜åŸºã€‚" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:876 +msgid " (fix conflicts and then run \"git rebase --continue\")" +msgstr " (解决冲çªï¼Œç„¶åŽè¿è¡Œ \"git rebase --continue\")" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:878 +msgid " (use \"git rebase --skip\" to skip this patch)" +msgstr " (使用 \"git rebase --skip\" 跳过æ¤è¡¥ä¸ï¼‰" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:880 +msgid " (use \"git rebase --abort\" to check out the original branch)" +msgstr " (使用 \"git rebase --abort\" 以检出原有分支)" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:886 +msgid " (all conflicts fixed: run \"git rebase --continue\")" +msgstr " (所有冲çªå·²è§£å†³ï¼šè¿è¡Œ \"git rebase --continue\")" + +#: wt-status.c:888 +msgid "You are currently splitting a commit during a rebase." +msgstr "您æ£åœ¨å˜åŸºè¿‡ç¨‹ä¸æ‹†åˆ†ä¸€ä¸ªæäº¤ã€‚" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:891 +msgid " (Once your working directory is clean, run \"git rebase --continue\")" +msgstr " (一旦您工作目录æäº¤å¹²å‡€åŽï¼Œè¿è¡Œ \"git rebase --continue\")" + +#: wt-status.c:893 +msgid "You are currently editing a commit during a rebase." +msgstr "您æ£åœ¨å˜åŸºè¿‡ç¨‹ä¸ç¼–辑一个æäº¤ã€‚" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:896 +msgid " (use \"git commit --amend\" to amend the current commit)" +msgstr " (使用 \"git commit --amend\" ä¿®è¡¥å½“å‰æäº¤ï¼‰" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:898 +msgid "" +" (use \"git rebase --continue\" once you are satisfied with your changes)" +msgstr " (当您对您的修改满æ„åŽæ‰§è¡Œ \"git rebase --continue\")" + +#: wt-status.c:908 +msgid "You are currently cherry-picking." +msgstr "您æ£åœ¨å𿋣选æ“作。" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:915 +msgid " (all conflicts fixed: run \"git commit\")" +msgstr " (解决所有冲çªåŽï¼Œæ‰§è¡Œ \"git commit\")" + +#: wt-status.c:924 +msgid "You are currently bisecting." +msgstr "您æ£åœ¨åšäºŒåˆ†æŸ¥æ‰¾ã€‚" + +# 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ +#: wt-status.c:927 +msgid " (use \"git bisect reset\" to get back to the original branch)" +msgstr " (使用 \"git bisect reset\" 以回到原有分支)" + +#: wt-status.c:978 msgid "On branch " msgstr "ä½äºŽåˆ†æ”¯ " -#: wt-status.c:744 +#: wt-status.c:985 msgid "Not currently on any branch." msgstr "当å‰ä¸åœ¨ä»»ä½•分支上。" -#: wt-status.c:755 +#: wt-status.c:997 msgid "Initial commit" msgstr "åˆå§‹æäº¤" -#: wt-status.c:769 -msgid "Untracked" +#: wt-status.c:1011 +#, fuzzy +msgid "Untracked files" msgstr "未跟踪的" -#: wt-status.c:771 -msgid "Ignored" +#: wt-status.c:1013 +#, fuzzy +msgid "Ignored files" msgstr "忽略的" -#: wt-status.c:773 +#: wt-status.c:1015 #, c-format msgid "Untracked files not listed%s" msgstr "未跟踪的文件没有列出%s" # è¯‘è€…ï¼šä¸æ–‡å—符串拼接,å¯åˆ 除å‰å¯¼ç©ºæ ¼ -#: wt-status.c:775 +#: wt-status.c:1017 msgid " (use -u option to show untracked files)" msgstr "(使用 -u 傿•°æ˜¾ç¤ºæœªè·Ÿè¸ªçš„æ–‡ä»¶ï¼‰" -#: wt-status.c:781 +#: wt-status.c:1023 msgid "No changes" msgstr "没有修改" -#: wt-status.c:785 -#, c-format -msgid "no changes added to commit%s\n" -msgstr "ä¿®æ”¹å°šæœªåŠ å…¥æäº¤%s\n" - # è¯‘è€…ï¼šä¸æ–‡å—符串拼接,å¯åˆ 除å‰å¯¼ç©ºæ ¼ -#: wt-status.c:787 -msgid " (use \"git add\" and/or \"git commit -a\")" +#: wt-status.c:1028 +#, fuzzy, c-format +msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n" msgstr "(使用 \"git add\" å’Œ/或 \"git commit -a\")" -#: wt-status.c:789 -#, c-format -msgid "nothing added to commit but untracked files present%s\n" -msgstr "空æäº¤ä½†å˜åœ¨æœªè·Ÿè¸ªæ–‡ä»¶%s\n" +#: wt-status.c:1031 +#, fuzzy, c-format +msgid "no changes added to commit\n" +msgstr "ä¿®æ”¹å°šæœªåŠ å…¥æäº¤%s\n" -# è¯‘è€…ï¼šä¸æ–‡å—符串拼接,å¯åˆ 除å‰å¯¼ç©ºæ ¼ -#: wt-status.c:791 -msgid " (use \"git add\" to track)" -msgstr "(使用 \"git add\" 建立跟踪)" +#: wt-status.c:1034 +#, fuzzy, c-format +msgid "" +"nothing added to commit but untracked files present (use \"git add\" to " +"track)\n" +msgstr "空æäº¤ä½†å˜åœ¨æœªè·Ÿè¸ªæ–‡ä»¶%s\n" -#: wt-status.c:793 wt-status.c:796 wt-status.c:799 -#, c-format -msgid "nothing to commit%s\n" -msgstr "æ— é¡»æäº¤%s\n" +#: wt-status.c:1037 +#, fuzzy, c-format +msgid "nothing added to commit but untracked files present\n" +msgstr "空æäº¤ä½†å˜åœ¨æœªè·Ÿè¸ªæ–‡ä»¶%s\n" # è¯‘è€…ï¼šä¸æ–‡å—符串拼接,å¯åˆ 除å‰å¯¼ç©ºæ ¼ -#: wt-status.c:794 -msgid " (create/copy files and use \"git add\" to track)" +#: wt-status.c:1040 +#, fuzzy, c-format +msgid "nothing to commit (create/copy files and use \"git add\" to track)\n" msgstr "(新建/æ‹·è´çš„æ–‡ä»¶ä½¿ç”¨ \"git add\" 建立跟踪)" +#: wt-status.c:1043 wt-status.c:1048 +#, fuzzy, c-format +msgid "nothing to commit\n" +msgstr "æ— é¡»æäº¤%s\n" + # è¯‘è€…ï¼šä¸æ–‡å—符串拼接,å¯åˆ 除å‰å¯¼ç©ºæ ¼ -#: wt-status.c:797 -msgid " (use -u to show untracked files)" +#: wt-status.c:1046 +#, fuzzy, c-format +msgid "nothing to commit (use -u to show untracked files)\n" msgstr "(使用 -u 显示未跟踪文件)" # è¯‘è€…ï¼šä¸æ–‡å—符串拼接,å¯åˆ 除å‰å¯¼ç©ºæ ¼ -#: wt-status.c:800 -msgid " (working directory clean)" +#: wt-status.c:1050 +#, fuzzy, c-format +msgid "nothing to commit, working directory clean\n" msgstr "(干净的工作区)" -#: wt-status.c:908 +#: wt-status.c:1158 msgid "HEAD (no branch)" msgstr "HEAD(éžåˆ†æ”¯ï¼‰" # 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼ -#: wt-status.c:914 +#: wt-status.c:1164 msgid "Initial commit on " msgstr "åˆå§‹æäº¤äºŽ " # 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼ -#: wt-status.c:929 +#: wt-status.c:1179 msgid "behind " msgstr "è½åŽ " # 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼ -#: wt-status.c:932 wt-status.c:935 +#: wt-status.c:1182 wt-status.c:1185 msgid "ahead " msgstr "领先 " # 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼ -#: wt-status.c:937 +#: wt-status.c:1187 msgid ", behind " msgstr ",è½åŽ " +#: compat/precompose_utf8.c:58 builtin/clone.c:341 +#, c-format +msgid "failed to unlink '%s'" +msgstr "æ— æ³•åˆ é™¤ '%s'" + +#: builtin/add.c:19 +#, fuzzy +msgid "git add [options] [--] <filepattern>..." +msgstr "git apply [选项] [<è¡¥ä¸>...]" + #: builtin/add.c:62 #, c-format msgid "unexpected diff status %c" msgstr "æ„å¤–çš„å·®å¼‚çŠ¶æ€ %c" -#: builtin/add.c:67 builtin/commit.c:226 +#: builtin/add.c:67 builtin/commit.c:229 msgid "updating files failed" msgstr "更新文件失败" @@ -949,7 +1431,7 @@ msgstr "路径 '%s' 属于模组 '%.*s'" msgid "Unstaged changes after refreshing the index:" msgstr "刷新索引之åŽå°šæœªè¢«æš‚å˜çš„å˜æ›´ï¼š" -#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186 +#: builtin/add.c:195 builtin/add.c:460 builtin/rm.c:186 #, c-format msgid "pathspec '%s' did not match any files" msgstr "路径 '%s' 未匹é…任何文件" @@ -966,11 +1448,11 @@ msgstr "ä¸èƒ½è¯»å–索引" #: builtin/add.c:286 #, c-format msgid "Could not open '%s' for writing." -msgstr "ä¸èƒ½ä¸ºå†™å…¥æ‰“å¼€ '%s'。" +msgstr "ä¸èƒ½æ‰“å¼€ '%s' 以写入。" #: builtin/add.c:290 msgid "Could not write patch" -msgstr "ä¸èƒ½å†™è¡¥ä¸" +msgstr "ä¸èƒ½ç”Ÿæˆè¡¥ä¸" #: builtin/add.c:295 #, c-format @@ -986,110 +1468,165 @@ msgstr "空补ä¸ã€‚异常终æ¢ã€‚" msgid "Could not apply '%s'" msgstr "ä¸èƒ½åº”用 '%s'" -#: builtin/add.c:312 +#: builtin/add.c:313 msgid "The following paths are ignored by one of your .gitignore files:\n" -msgstr "下列路径被您的一个 .gitignore 文件所忽略:\n" +msgstr "ä¸‹åˆ—è·¯å¾„æ ¹æ®æ‚¨çš„一个 .gitignore 文件而被忽略:\n" + +#: builtin/add.c:319 builtin/clean.c:52 builtin/fetch.c:78 builtin/mv.c:63 +#: builtin/prune-packed.c:76 builtin/push.c:388 builtin/remote.c:1253 +#: builtin/rm.c:133 +msgid "dry run" +msgstr "" + +#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1187 +#: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1477 +#: builtin/mv.c:62 builtin/read-tree.c:112 +msgid "be verbose" +msgstr "冗长输出" + +#: builtin/add.c:322 +#, fuzzy +msgid "interactive picking" +msgstr "äº¤äº’å¼æ·»åŠ å¤±è´¥" + +#: builtin/add.c:323 builtin/checkout.c:1028 builtin/reset.c:248 +msgid "select hunks interactively" +msgstr "" + +#: builtin/add.c:324 +msgid "edit current diff and apply" +msgstr "" + +#: builtin/add.c:325 +msgid "allow adding otherwise ignored files" +msgstr "" + +#: builtin/add.c:326 +#, fuzzy +msgid "update tracked files" +msgstr "æ— æ³•å˜å‚¨åŒ…文件" -#: builtin/add.c:352 +#: builtin/add.c:327 +msgid "record only the fact that the path will be added later" +msgstr "" + +#: builtin/add.c:328 +msgid "add changes from all tracked and untracked files" +msgstr "" + +#: builtin/add.c:329 +#, fuzzy +msgid "don't add, only refresh the index" +msgstr "git %sï¼šæ— æ³•åˆ·æ–°ç´¢å¼•" + +#: builtin/add.c:330 +msgid "just skip files which cannot be added because of errors" +msgstr "" + +#: builtin/add.c:331 +msgid "check if - even missing - files are ignored in dry run" +msgstr "" + +#: builtin/add.c:353 #, c-format msgid "Use -f if you really want to add them.\n" msgstr "使用 -f 傿•°å¦‚æžœæ‚¨ç¡®å®žè¦æ·»åŠ å®ƒä»¬ã€‚\n" -#: builtin/add.c:353 +#: builtin/add.c:354 msgid "no files added" msgstr "æ²¡æœ‰æ–‡ä»¶è¢«æ·»åŠ " -#: builtin/add.c:359 +#: builtin/add.c:360 msgid "adding files failed" msgstr "æ·»åŠ æ–‡ä»¶å¤±è´¥" -#: builtin/add.c:391 +#: builtin/add.c:392 msgid "-A and -u are mutually incompatible" msgstr "-A å’Œ -u 选项互斥" -#: builtin/add.c:393 +#: builtin/add.c:394 msgid "Option --ignore-missing can only be used together with --dry-run" -msgstr "选项 --ignore-missing åªèƒ½å’Œ --dry-run 共用" +msgstr "选项 --ignore-missing åªèƒ½å’Œ --dry-run åŒæ—¶ä½¿ç”¨" -#: builtin/add.c:413 +#: builtin/add.c:414 #, c-format msgid "Nothing specified, nothing added.\n" msgstr "æ²¡æœ‰æŒ‡å®šæ–‡ä»¶ï¼Œä¹Ÿæ²¡æœ‰æ–‡ä»¶è¢«æ·»åŠ ã€‚\n" -#: builtin/add.c:414 +#: builtin/add.c:415 #, c-format msgid "Maybe you wanted to say 'git add .'?\n" msgstr "ä¹Ÿè®¸æ‚¨æƒ³è¦æ‰§è¡Œ 'git add .'?\n" -#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82 +#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82 #: builtin/rm.c:162 msgid "index file corrupt" msgstr "索引文件æŸå" -#: builtin/add.c:476 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260 +#: builtin/add.c:481 builtin/apply.c:4450 builtin/mv.c:229 builtin/rm.c:260 msgid "Unable to write new index file" msgstr "æ— æ³•å†™å…¥æ–°ç´¢å¼•æ–‡ä»¶" -#: builtin/apply.c:53 +#: builtin/apply.c:57 msgid "git apply [options] [<patch>...]" msgstr "git apply [选项] [<è¡¥ä¸>...]" -#: builtin/apply.c:106 +#: builtin/apply.c:110 #, c-format msgid "unrecognized whitespace option '%s'" msgstr "未能识别的空白å—符选项 '%s'" -#: builtin/apply.c:121 +#: builtin/apply.c:125 #, c-format msgid "unrecognized whitespace ignore option '%s'" msgstr "未能识别的空白å—符忽略选项 '%s'" -#: builtin/apply.c:815 +#: builtin/apply.c:823 #, c-format msgid "Cannot prepare timestamp regexp %s" msgstr "æ— æ³•å‡†å¤‡æ—¶é—´æˆ³æ£åˆ™è¡¨è¾¾å¼ %s" -#: builtin/apply.c:824 +#: builtin/apply.c:832 #, c-format msgid "regexec returned %d for input: %s" msgstr "regexec 返回 %d,输入为:%s" -#: builtin/apply.c:905 +#: builtin/apply.c:913 #, c-format msgid "unable to find filename in patch at line %d" msgstr "ä¸èƒ½åœ¨è¡¥ä¸çš„第 %d 行找到文件å" -#: builtin/apply.c:937 +#: builtin/apply.c:945 #, c-format msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" -msgstr "git apply:错误的 git-diff - 期望 /dev/null,但在第 %2$d 行得到 %1$s" +msgstr "git apply:错误的 git-diff - 应为 /dev/null,但在第 %2$d 行得到 %1$s" -#: builtin/apply.c:941 +#: builtin/apply.c:949 #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "git apply:错误的 git-diff - 第 %d 行上新文件åä¸ä¸€è‡´" -#: builtin/apply.c:942 +#: builtin/apply.c:950 #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "git apply:错误的 git-diff - 第 %d 行上旧文件åä¸ä¸€è‡´" -#: builtin/apply.c:949 +#: builtin/apply.c:957 #, c-format msgid "git apply: bad git-diff - expected /dev/null on line %d" -msgstr "git apply:错误的 git-diff - 期望 /dev/null 于第 %d 行" +msgstr "git apply:错误的 git-diff - 第 %d 行处应为 /dev/null" -#: builtin/apply.c:1394 +#: builtin/apply.c:1420 #, c-format msgid "recount: unexpected line: %.*s" msgstr "recount:æ„外的行:%.*s" -#: builtin/apply.c:1451 +#: builtin/apply.c:1477 #, c-format msgid "patch fragment without header at line %d: %.*s" msgstr "第 %d 行的补ä¸ç‰‡æ®µæ²¡æœ‰å¤´ä¿¡æ¯ï¼š%.*s" -#: builtin/apply.c:1468 +#: builtin/apply.c:1494 #, c-format msgid "" "git diff header lacks filename information when removing %d leading pathname " @@ -1100,82 +1637,82 @@ msgid_plural "" msgstr[0] "当移除 %d 个å‰å¯¼è·¯å¾„åŽ git diff å¤´ç¼ºä¹æ–‡ä»¶åä¿¡æ¯ï¼ˆç¬¬ %d 行)" msgstr[1] "当移除 %d 个å‰å¯¼è·¯å¾„åŽ git diff å¤´ç¼ºä¹æ–‡ä»¶åä¿¡æ¯ï¼ˆç¬¬ %d 行)" -#: builtin/apply.c:1628 +#: builtin/apply.c:1654 msgid "new file depends on old contents" msgstr "新文件ä¾èµ–旧内容" -#: builtin/apply.c:1630 +#: builtin/apply.c:1656 msgid "deleted file still has contents" msgstr "åˆ é™¤çš„æ–‡ä»¶ä»æœ‰å†…容" -#: builtin/apply.c:1656 +#: builtin/apply.c:1682 #, c-format msgid "corrupt patch at line %d" -msgstr "è¡¥ä¸æŸåä½äºŽç¬¬ %d 行" +msgstr "è¡¥ä¸åœ¨ç¬¬ %d 行æŸå" -#: builtin/apply.c:1692 +#: builtin/apply.c:1718 #, c-format msgid "new file %s depends on old contents" msgstr "新文件 %s ä¾èµ–旧内容" -#: builtin/apply.c:1694 +#: builtin/apply.c:1720 #, c-format msgid "deleted file %s still has contents" msgstr "åˆ é™¤çš„æ–‡ä»¶ %s 仿œ‰å†…容" -#: builtin/apply.c:1697 +#: builtin/apply.c:1723 #, c-format msgid "** warning: file %s becomes empty but is not deleted" msgstr "** è¦å‘Šï¼šæ–‡ä»¶ %s æˆä¸ºç©ºæ–‡ä»¶ä½†å¹¶æœªåˆ 除" -#: builtin/apply.c:1843 +#: builtin/apply.c:1869 #, c-format msgid "corrupt binary patch at line %d: %.*s" msgstr "二进制补ä¸åœ¨ç¬¬ %d 行æŸå:%.*s" #. there has to be one hunk (forward hunk) -#: builtin/apply.c:1872 +#: builtin/apply.c:1898 #, c-format msgid "unrecognized binary patch at line %d" msgstr "未能识别的二进制补ä¸ä½äºŽç¬¬ %d 行" -#: builtin/apply.c:1958 +#: builtin/apply.c:1984 #, c-format msgid "patch with only garbage at line %d" msgstr "è¡¥ä¸æ–‡ä»¶çš„第 %d è¡Œåªæœ‰åžƒåœ¾æ•°æ®" -#: builtin/apply.c:2048 +#: builtin/apply.c:2074 #, c-format msgid "unable to read symlink %s" msgstr "æ— æ³•è¯»å–符å·é“¾æŽ¥ %s" -#: builtin/apply.c:2052 +#: builtin/apply.c:2078 #, c-format msgid "unable to open or read %s" msgstr "ä¸èƒ½æ‰“å¼€æˆ–è¯»å– %s" -#: builtin/apply.c:2123 +#: builtin/apply.c:2149 msgid "oops" msgstr "哎哟" -#: builtin/apply.c:2645 +#: builtin/apply.c:2671 #, c-format msgid "invalid start of line: '%c'" msgstr "æ— æ•ˆçš„è¡Œé¦–å—符:'%c'" -#: builtin/apply.c:2763 +#: builtin/apply.c:2789 #, c-format msgid "Hunk #%d succeeded at %d (offset %d line)." msgid_plural "Hunk #%d succeeded at %d (offset %d lines)." msgstr[0] "å— #%d æˆåŠŸåº”ç”¨äºŽ %d (åç§» %d 行)" msgstr[1] "å— #%d æˆåŠŸåº”ç”¨äºŽ %d (åç§» %d 行)" -#: builtin/apply.c:2775 +#: builtin/apply.c:2801 #, c-format msgid "Context reduced to (%ld/%ld) to apply fragment at %d" msgstr "上下文å‡å°‘到(%ld/%ld)以在第 %d 行应用补ä¸ç‰‡æ®µ" -#: builtin/apply.c:2781 +#: builtin/apply.c:2807 #, c-format msgid "" "while searching for:\n" @@ -1184,313 +1721,319 @@ msgstr "" "当查询:\n" "%.*s" -#: builtin/apply.c:2800 +#: builtin/apply.c:2826 #, c-format msgid "missing binary patch data for '%s'" msgstr "缺失 '%s' çš„äºŒè¿›åˆ¶è¡¥ä¸æ•°æ®" -#: builtin/apply.c:2903 +#: builtin/apply.c:2929 #, c-format msgid "binary patch does not apply to '%s'" msgstr "äºŒè¿›åˆ¶è¡¥ä¸æœªåº”用到 '%s'" -#: builtin/apply.c:2909 +#: builtin/apply.c:2935 #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" -msgstr "到 '%s' 的二进制补ä¸äº§ç”Ÿäº†ä¸æ£ç¡®çš„结果(预期 %s,得到 %s)" +msgstr "到 '%s' 的二进制补ä¸äº§ç”Ÿäº†ä¸æ£ç¡®çš„结果(应为 %s,å´ä¸º %s)" -#: builtin/apply.c:2930 +#: builtin/apply.c:2956 #, c-format msgid "patch failed: %s:%ld" msgstr "打补ä¸å¤±è´¥ï¼š%s:%ld" -#: builtin/apply.c:3045 +#: builtin/apply.c:3078 #, c-format -msgid "patch %s has been renamed/deleted" -msgstr "è¡¥ä¸ %s å·²ç»è¢«é‡å‘½å/åˆ é™¤" +msgid "cannot checkout %s" +msgstr "ä¸èƒ½æ£€å‡º %s" -#: builtin/apply.c:3052 builtin/apply.c:3069 +#: builtin/apply.c:3123 builtin/apply.c:3132 builtin/apply.c:3176 #, c-format msgid "read of %s failed" msgstr "è¯»å– %s 失败" -#: builtin/apply.c:3084 -msgid "removal patch leaves file contents" -msgstr "移除补ä¸ä»ç•™ä¸‹äº†æ–‡ä»¶å†…容" - -#: builtin/apply.c:3105 +#: builtin/apply.c:3156 builtin/apply.c:3378 #, c-format -msgid "%s: already exists in working directory" -msgstr "%s:已ç»å˜åœ¨äºŽå·¥ä½œåŒºä¸" +msgid "path %s has been renamed/deleted" +msgstr "路径 %s å·²ç»è¢«é‡å‘½å/åˆ é™¤" -#: builtin/apply.c:3143 +#: builtin/apply.c:3237 builtin/apply.c:3392 #, c-format -msgid "%s: has been deleted/renamed" -msgstr "%s:已ç»è¢«åˆ 除/é‡å‘½å" +msgid "%s: does not exist in index" +msgstr "%s:ä¸å˜åœ¨äºŽç´¢å¼•ä¸" -#: builtin/apply.c:3148 builtin/apply.c:3179 +#: builtin/apply.c:3241 builtin/apply.c:3384 builtin/apply.c:3406 #, c-format msgid "%s: %s" msgstr "%s:%s" -#: builtin/apply.c:3159 -#, c-format -msgid "%s: does not exist in index" -msgstr "%s:ä¸å˜åœ¨äºŽç´¢å¼•ä¸" - -#: builtin/apply.c:3173 +#: builtin/apply.c:3246 builtin/apply.c:3400 #, c-format msgid "%s: does not match index" msgstr "%s:和索引ä¸åŒ¹é…" -#: builtin/apply.c:3190 +#: builtin/apply.c:3348 +msgid "removal patch leaves file contents" +msgstr "移除补ä¸ä»ç•™ä¸‹äº†æ–‡ä»¶å†…容" + +#: builtin/apply.c:3417 #, c-format msgid "%s: wrong type" msgstr "%s:错误类型" -#: builtin/apply.c:3192 +#: builtin/apply.c:3419 #, c-format msgid "%s has type %o, expected %o" -msgstr "%s 的类型是 %o,预期是 %o" +msgstr "%s 的类型是 %o,应为 %o" -#: builtin/apply.c:3247 +#: builtin/apply.c:3520 #, c-format msgid "%s: already exists in index" msgstr "%s:已ç»å˜åœ¨äºŽç´¢å¼•ä¸" -#: builtin/apply.c:3267 +#: builtin/apply.c:3523 +#, c-format +msgid "%s: already exists in working directory" +msgstr "%s:已ç»å˜åœ¨äºŽå·¥ä½œåŒºä¸" + +#: builtin/apply.c:3543 #, c-format msgid "new mode (%o) of %s does not match old mode (%o)" msgstr "%2$s 的新模å¼ï¼ˆ%1$o)和旧模å¼ï¼ˆ%3$o)ä¸åŒ¹é…" -#: builtin/apply.c:3272 +#: builtin/apply.c:3548 #, c-format msgid "new mode (%o) of %s does not match old mode (%o) of %s" msgstr "%2$s 的新模å¼ï¼ˆ%1$o)和 %4$s 的旧模å¼ï¼ˆ%3$o)ä¸åŒ¹é…" -#: builtin/apply.c:3280 +#: builtin/apply.c:3556 #, c-format msgid "%s: patch does not apply" msgstr "%sï¼šè¡¥ä¸æœªåº”用" -#: builtin/apply.c:3293 +#: builtin/apply.c:3569 #, c-format msgid "Checking patch %s..." msgstr "æ£€æŸ¥è¡¥ä¸ %s..." -#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158 +#: builtin/apply.c:3624 builtin/checkout.c:215 builtin/reset.c:158 #, c-format msgid "make_cache_entry failed for path '%s'" msgstr "对路径 '%s' çš„ make_cache_entry æ“作失败" -#: builtin/apply.c:3491 +#: builtin/apply.c:3767 #, c-format msgid "unable to remove %s from index" msgstr "ä¸èƒ½ä»Žç´¢å¼•ä¸ç§»é™¤ %s" -#: builtin/apply.c:3518 +#: builtin/apply.c:3795 #, c-format msgid "corrupt patch for subproject %s" msgstr "å项目 %s æŸå的补ä¸" -#: builtin/apply.c:3522 +#: builtin/apply.c:3799 #, c-format msgid "unable to stat newly created file '%s'" msgstr "ä¸èƒ½æžšä¸¾æ–°å»ºæ–‡ä»¶ '%s' 的状æ€" -#: builtin/apply.c:3527 +#: builtin/apply.c:3804 #, c-format msgid "unable to create backing store for newly created file %s" msgstr "ä¸èƒ½ä¸ºæ–°å»ºæ–‡ä»¶ %s 创建åŽç«¯å˜å‚¨" -#: builtin/apply.c:3530 +#: builtin/apply.c:3807 builtin/apply.c:3915 #, c-format msgid "unable to add cache entry for %s" msgstr "æ— æ³•ä¸º %s æ·»åŠ ç¼“å˜æ¡ç›®" -#: builtin/apply.c:3563 +#: builtin/apply.c:3840 #, c-format msgid "closing file '%s'" msgstr "关闿–‡ä»¶ '%s'" -#: builtin/apply.c:3612 +#: builtin/apply.c:3889 #, c-format msgid "unable to write file '%s' mode %o" msgstr "ä¸èƒ½å†™æ–‡ä»¶ '%s' æƒé™ %o" -#: builtin/apply.c:3668 +#: builtin/apply.c:3976 #, c-format msgid "Applied patch %s cleanly." msgstr "æˆåŠŸåº”ç”¨è¡¥ä¸ %s。" -#: builtin/apply.c:3676 +#: builtin/apply.c:3984 msgid "internal error" msgstr "内部错误" #. Say this even without --verbose -#: builtin/apply.c:3679 +#: builtin/apply.c:3987 #, c-format msgid "Applying patch %%s with %d reject..." msgid_plural "Applying patch %%s with %d rejects..." -msgstr[0] "åº”ç”¨è¡¥ä¸ %%s æ—¶ %d 个被拒ç»..." -msgstr[1] "åº”ç”¨è¡¥ä¸ %%s æ—¶ %d 个被拒ç»..." +msgstr[0] "应用 %%s 个补ä¸ï¼Œå…¶ä¸ %d 个被拒ç»..." +msgstr[1] "应用 %%s 个补ä¸ï¼Œå…¶ä¸ %d 个被拒ç»..." -#: builtin/apply.c:3689 +#: builtin/apply.c:3997 #, c-format msgid "truncating .rej filename to %.*s.rej" msgstr "æˆªçŸ .rej 文件å为 %.*s.rej" -#: builtin/apply.c:3710 +#: builtin/apply.c:4018 #, c-format msgid "Hunk #%d applied cleanly." msgstr "第 #%d 个片段æˆåŠŸåº”ç”¨ã€‚" -#: builtin/apply.c:3713 +#: builtin/apply.c:4021 #, c-format msgid "Rejected hunk #%d." msgstr "æ‹’ç»ç¬¬ #%d 个片段。" -#: builtin/apply.c:3844 +#: builtin/apply.c:4171 msgid "unrecognized input" msgstr "未能识别的输入" -#: builtin/apply.c:3855 +#: builtin/apply.c:4182 msgid "unable to read index file" msgstr "æ— æ³•è¯»å–索引文件" -#: builtin/apply.c:3970 builtin/apply.c:3973 +#: builtin/apply.c:4301 builtin/apply.c:4304 builtin/clone.c:91 +#: builtin/fetch.c:63 msgid "path" msgstr "路径" -#: builtin/apply.c:3971 +#: builtin/apply.c:4302 msgid "don't apply changes matching the given path" msgstr "ä¸è¦åº”用与给出路径å‘匹é…çš„å˜æ›´" -#: builtin/apply.c:3974 +#: builtin/apply.c:4305 msgid "apply changes matching the given path" msgstr "应用与给出路径å‘匹é…çš„å˜æ›´" -#: builtin/apply.c:3976 +#: builtin/apply.c:4307 msgid "num" msgstr "æ•°å—" -#: builtin/apply.c:3977 +#: builtin/apply.c:4308 msgid "remove <num> leading slashes from traditional diff paths" msgstr "ä»Žä¼ ç»Ÿçš„ diff 路径ä¸ç§»é™¤ <æ•°å—> 个å‰å¯¼è·¯å¾„" -#: builtin/apply.c:3980 +#: builtin/apply.c:4311 msgid "ignore additions made by the patch" msgstr "忽略补ä¸ä¸çš„æ·»åŠ çš„æ–‡ä»¶" -#: builtin/apply.c:3982 +#: builtin/apply.c:4313 msgid "instead of applying the patch, output diffstat for the input" msgstr "ä¸åº”用补ä¸ï¼Œè€Œæ˜¯æ˜¾ç¤ºè¾“入的差异统计(diffstat)" -#: builtin/apply.c:3986 -msgid "shows number of added and deleted lines in decimal notation" +#: builtin/apply.c:4317 +#, fuzzy +msgid "show number of added and deleted lines in decimal notation" msgstr "ä»¥æ•°å—æ–¹å¼æ˜¾ç¤ºæ·»åŠ æˆ–åˆ é™¤è¡Œçš„æ•°é‡" -#: builtin/apply.c:3988 +#: builtin/apply.c:4319 msgid "instead of applying the patch, output a summary for the input" msgstr "ä¸åº”用补ä¸ï¼Œè€Œæ˜¯æ˜¾ç¤ºè¾“入的概è¦" -#: builtin/apply.c:3990 +#: builtin/apply.c:4321 msgid "instead of applying the patch, see if the patch is applicable" msgstr "ä¸åº”用补ä¸ï¼Œè€Œæ˜¯æŸ¥çœ‹è¡¥ä¸æ˜¯å¦å¯åº”用" -#: builtin/apply.c:3992 +#: builtin/apply.c:4323 msgid "make sure the patch is applicable to the current index" msgstr "确认补ä¸å¯ä»¥åº”用到当å‰ç´¢å¼•" -#: builtin/apply.c:3994 +#: builtin/apply.c:4325 msgid "apply a patch without touching the working tree" msgstr "应用补ä¸è€Œä¸ä¿®æ”¹å·¥ä½œåŒº" -#: builtin/apply.c:3996 +#: builtin/apply.c:4327 msgid "also apply the patch (use with --stat/--summary/--check)" -msgstr "åŒæ—¶åº”用æ¤è¡¥ä¸ï¼ˆå’Œ --stat/--summary/--check 共用)" +msgstr "还应用æ¤è¡¥ä¸ï¼ˆä¸Ž --stat/--summary/--check é€‰é¡¹åŒæ—¶ä½¿ç”¨ï¼‰" -#: builtin/apply.c:3998 +#: builtin/apply.c:4329 +msgid "attempt three-way merge if a patch does not apply" +msgstr "如果一个补ä¸ä¸èƒ½åº”用则å°è¯•三路åˆå¹¶" + +#: builtin/apply.c:4331 msgid "build a temporary index based on embedded index information" msgstr "创建一个临时索引基于嵌入的索引信æ¯" -#: builtin/apply.c:4000 +#: builtin/apply.c:4333 builtin/checkout-index.c:197 builtin/ls-files.c:460 msgid "paths are separated with NUL character" msgstr "路径以 NUL å—符分隔" -#: builtin/apply.c:4003 +#: builtin/apply.c:4336 msgid "ensure at least <n> lines of context match" msgstr "ç¡®ä¿è‡³å°‘åŒ¹é… <n> 行上下文" -#: builtin/apply.c:4004 +#: builtin/apply.c:4337 msgid "action" msgstr "动作" -#: builtin/apply.c:4005 +#: builtin/apply.c:4338 msgid "detect new or modified lines that have whitespace errors" msgstr "检查新增和修改的行ä¸é—´çš„空白å—符滥用" -#: builtin/apply.c:4008 builtin/apply.c:4011 +#: builtin/apply.c:4341 builtin/apply.c:4344 msgid "ignore changes in whitespace when finding context" msgstr "查找上下文时忽略空白å—ç¬¦çš„å˜æ›´" -#: builtin/apply.c:4014 +#: builtin/apply.c:4347 msgid "apply the patch in reverse" msgstr "åå‘应用补ä¸" -#: builtin/apply.c:4016 +#: builtin/apply.c:4349 msgid "don't expect at least one line of context" msgstr "æ— éœ€è‡³å°‘ä¸€è¡Œä¸Šä¸‹æ–‡" -#: builtin/apply.c:4018 +#: builtin/apply.c:4351 msgid "leave the rejected hunks in corresponding *.rej files" msgstr "将拒ç»çš„è¡¥ä¸ç‰‡æ®µä¿å˜åœ¨å¯¹åº”çš„ *.rej 文件ä¸" -#: builtin/apply.c:4020 +#: builtin/apply.c:4353 msgid "allow overlapping hunks" msgstr "å…许é‡å 的补ä¸ç‰‡æ®µ" -#: builtin/apply.c:4021 -msgid "be verbose" -msgstr "冗长输出" - -#: builtin/apply.c:4023 +#: builtin/apply.c:4356 msgid "tolerate incorrectly detected missing new-line at the end of file" -msgstr "宽容䏿£ç¡®çš„æ–‡ä»¶æœ«å°¾æ¢è¡Œç¬¦" +msgstr "å…è®¸ä¸æ£ç¡®çš„æ–‡ä»¶æœ«å°¾æ¢è¡Œç¬¦" -#: builtin/apply.c:4026 +#: builtin/apply.c:4359 msgid "do not trust the line counts in the hunk headers" msgstr "ä¸ä¿¡ä»»è¡¥ä¸ç‰‡æ®µçš„头信æ¯ä¸çš„行å·" -#: builtin/apply.c:4028 +#: builtin/apply.c:4361 msgid "root" msgstr "æ ¹ç›®å½•" -#: builtin/apply.c:4029 +#: builtin/apply.c:4362 msgid "prepend <root> to all filenames" msgstr "为所有文件å剿·»åŠ <æ ¹ç›®å½•>" -#: builtin/apply.c:4050 +#: builtin/apply.c:4384 +msgid "--3way outside a repository" +msgstr "--3way 在一个版本库之外" + +#: builtin/apply.c:4392 msgid "--index outside a repository" msgstr "--index 在一个版本库之外" -#: builtin/apply.c:4053 +#: builtin/apply.c:4395 msgid "--cached outside a repository" msgstr "--cached 在一个版本库之外" -#: builtin/apply.c:4069 +#: builtin/apply.c:4411 #, c-format msgid "can't open patch '%s'" msgstr "ä¸èƒ½æ‰“å¼€è¡¥ä¸ '%s'" -#: builtin/apply.c:4083 +#: builtin/apply.c:4425 #, c-format msgid "squelched %d whitespace error" msgid_plural "squelched %d whitespace errors" msgstr[0] "æŠ‘åˆ¶ä¸‹ä»æœ‰ %d 个空白å—符误用" msgstr[1] "æŠ‘åˆ¶ä¸‹ä»æœ‰ %d 个空白å—符误用" -#: builtin/apply.c:4089 builtin/apply.c:4099 +#: builtin/apply.c:4431 builtin/apply.c:4441 #, c-format msgid "%d line adds whitespace errors." msgid_plural "%d lines add whitespace errors." @@ -1504,7 +2047,7 @@ msgstr "ä¸èƒ½åˆ›å»ºå½’档文件 '%s'" #: builtin/archive.c:20 msgid "could not redirect output" -msgstr "ä¸èƒ½è¾“出é‡å®šå‘" +msgstr "ä¸èƒ½é‡å®šå‘输出" #: builtin/archive.c:37 msgid "git archive: Remote with no URL" @@ -1512,7 +2055,7 @@ msgstr "git archive:未æä¾›è¿œç¨‹URL" #: builtin/archive.c:58 msgid "git archive: expected ACK/NAK, got EOF" -msgstr "git archive:期待ACK/NACK,å´å¾—到EOF" +msgstr "git archive:应为ACK/NACK,å´å¾—到EOF" #: builtin/archive.c:63 #, c-format @@ -1530,10 +2073,142 @@ msgstr "git archive:å议错误" #: builtin/archive.c:71 msgid "git archive: expected a flush" -msgstr "git archive:预期一个刷新" +msgstr "git archive:应为刷新" + +#: builtin/bisect--helper.c:7 +msgid "git bisect--helper --next-all [--no-checkout]" +msgstr "" + +#: builtin/bisect--helper.c:17 +msgid "perform 'git bisect next'" +msgstr "" + +#: builtin/bisect--helper.c:19 +msgid "update BISECT_HEAD instead of checking out the current commit" +msgstr "" + +#: builtin/blame.c:25 +msgid "git blame [options] [rev-opts] [rev] [--] file" +msgstr "" + +#: builtin/blame.c:30 builtin/shortlog.c:15 +msgid "[rev-opts] are documented in git-rev-list(1)" +msgstr "" + +#: builtin/blame.c:2316 +msgid "Show blame entries as we find them, incrementally" +msgstr "" + +#: builtin/blame.c:2317 +msgid "Show blank SHA-1 for boundary commits (Default: off)" +msgstr "" + +#: builtin/blame.c:2318 +msgid "Do not treat root commits as boundaries (Default: off)" +msgstr "" + +#: builtin/blame.c:2319 +#, fuzzy +msgid "Show work cost statistics" +msgstr "显示工作区状æ€" + +#: builtin/blame.c:2320 +msgid "Show output score for blame entries" +msgstr "" + +#: builtin/blame.c:2321 +msgid "Show original filename (Default: auto)" +msgstr "" + +#: builtin/blame.c:2322 +msgid "Show original linenumber (Default: off)" +msgstr "" + +#: builtin/blame.c:2323 +msgid "Show in a format designed for machine consumption" +msgstr "" + +#: builtin/blame.c:2324 +msgid "Show porcelain format with per-line commit information" +msgstr "" + +#: builtin/blame.c:2325 +msgid "Use the same output mode as git-annotate (Default: off)" +msgstr "" + +#: builtin/blame.c:2326 +msgid "Show raw timestamp (Default: off)" +msgstr "" + +#: builtin/blame.c:2327 +msgid "Show long commit SHA1 (Default: off)" +msgstr "" + +#: builtin/blame.c:2328 +msgid "Suppress author name and timestamp (Default: off)" +msgstr "" + +#: builtin/blame.c:2329 +msgid "Show author email instead of name (Default: off)" +msgstr "" + +#: builtin/blame.c:2330 +msgid "Ignore whitespace differences" +msgstr "" + +#: builtin/blame.c:2331 +msgid "Spend extra cycles to find better match" +msgstr "" + +#: builtin/blame.c:2332 +msgid "Use revisions from <file> instead of calling git-rev-list" +msgstr "" + +#: builtin/blame.c:2333 +#, fuzzy +msgid "Use <file>'s contents as the final image" +msgstr "æ·»åŠ æ–‡ä»¶å†…å®¹è‡³ç´¢å¼•" + +#: builtin/blame.c:2334 builtin/blame.c:2335 +msgid "score" +msgstr "" + +#: builtin/blame.c:2334 +msgid "Find line copies within and across files" +msgstr "" + +#: builtin/blame.c:2335 +msgid "Find line movements within and across files" +msgstr "" + +#: builtin/blame.c:2336 +#, fuzzy +msgid "n,m" +msgstr "æ•°å—" + +#: builtin/blame.c:2336 +msgid "Process only line range n,m, counting from 1" +msgstr "" + +#: builtin/branch.c:23 +msgid "git branch [options] [-r | -a] [--merged | --no-merged]" +msgstr "" + +#: builtin/branch.c:24 +msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]" +msgstr "" + +#: builtin/branch.c:25 +#, fuzzy +msgid "git branch [options] [-r] (-d | -D) <branchname>..." +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/branch.c:26 +msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>" +msgstr "" # è¯‘è€…ï¼šä¿æŒåŽŸæ¢è¡Œæ ¼å¼ï¼Œåœ¨è¾“出时 %s 的替代内容会让å—符串å˜é•¿ -#: builtin/branch.c:144 +#: builtin/branch.c:145 #, c-format msgid "" "deleting branch '%s' that has been merged to\n" @@ -1543,7 +2218,7 @@ msgstr "" " '%s',但未åˆå¹¶åˆ° HEAD。" # è¯‘è€…ï¼šä¿æŒåŽŸæ¢è¡Œæ ¼å¼ï¼Œåœ¨è¾“出时 %s 的替代内容会让å—符串å˜é•¿ -#: builtin/branch.c:148 +#: builtin/branch.c:149 #, c-format msgid "" "not deleting branch '%s' that is not yet merged to\n" @@ -1552,35 +2227,35 @@ msgstr "" "å¹¶æœªåˆ é™¤åˆ†æ”¯ '%s', 虽然它已ç»åˆå¹¶åˆ° HEAD,\n" " 然而å´å°šæœªè¢«åˆå¹¶åˆ°åˆ†æ”¯ '%s' 。" -#: builtin/branch.c:180 +#: builtin/branch.c:181 msgid "cannot use -a with -d" -msgstr "ä¸èƒ½å°† -a å’Œ -d 共用" +msgstr "ä¸èƒ½å°† -a å’Œ -d åŒæ—¶ä½¿ç”¨" -#: builtin/branch.c:186 +#: builtin/branch.c:187 msgid "Couldn't look up commit object for HEAD" msgstr "æ— æ³•æŸ¥è¯¢ HEAD 指å‘çš„æäº¤å¯¹è±¡" -#: builtin/branch.c:191 +#: builtin/branch.c:192 #, c-format msgid "Cannot delete the branch '%s' which you are currently on." msgstr "æ— æ³•åˆ é™¤æ‚¨å½“å‰æ‰€åœ¨çš„分支 '%s'。" -#: builtin/branch.c:202 +#: builtin/branch.c:203 #, c-format msgid "remote branch '%s' not found." msgstr "远程分支 '%s' 未å‘现。" -#: builtin/branch.c:203 +#: builtin/branch.c:204 #, c-format msgid "branch '%s' not found." msgstr "分支 '%s' 未å‘现。" -#: builtin/branch.c:210 +#: builtin/branch.c:211 #, c-format msgid "Couldn't look up commit object for '%s'" msgstr "æ— æ³•æŸ¥è¯¢ '%s' 指å‘çš„æäº¤å¯¹è±¡" -#: builtin/branch.c:216 +#: builtin/branch.c:217 #, c-format msgid "" "The branch '%s' is not fully merged.\n" @@ -1589,126 +2264,258 @@ msgstr "" "分支 '%s' 没有完全åˆå¹¶ã€‚\n" "如果您确认è¦åˆ 除它,执行 'git branch -D %s'。" -#: builtin/branch.c:225 +#: builtin/branch.c:226 #, c-format msgid "Error deleting remote branch '%s'" msgstr "åˆ é™¤è¿œç¨‹åˆ†æ”¯ '%s' 时出错" -#: builtin/branch.c:226 +#: builtin/branch.c:227 #, c-format msgid "Error deleting branch '%s'" msgstr "åˆ é™¤åˆ†æ”¯ '%s' 时出错" -#: builtin/branch.c:233 +#: builtin/branch.c:234 #, c-format msgid "Deleted remote branch %s (was %s).\n" msgstr "å·²åˆ é™¤è¿œç¨‹åˆ†æ”¯ %s(曾为 %s)。\n" -#: builtin/branch.c:234 +#: builtin/branch.c:235 #, c-format msgid "Deleted branch %s (was %s).\n" msgstr "å·²åˆ é™¤åˆ†æ”¯ %s(曾为 %s)。\n" -#: builtin/branch.c:239 +#: builtin/branch.c:240 msgid "Update of config-file failed" msgstr "æ— æ³•æ›´æ–° config 文件" -#: builtin/branch.c:337 +#: builtin/branch.c:338 #, c-format msgid "branch '%s' does not point at a commit" msgstr "分支 '%s' 未指å‘一个æäº¤" -#: builtin/branch.c:409 +#: builtin/branch.c:410 #, c-format msgid "[%s: behind %d]" msgstr "[%s:è½åŽ %d]" -#: builtin/branch.c:411 +#: builtin/branch.c:412 #, c-format msgid "[behind %d]" msgstr "[è½åŽ %d]" -#: builtin/branch.c:415 +#: builtin/branch.c:416 #, c-format msgid "[%s: ahead %d]" msgstr "[%s:领先 %d]" -#: builtin/branch.c:417 +#: builtin/branch.c:418 #, c-format msgid "[ahead %d]" msgstr "[领先 %d]" -#: builtin/branch.c:420 +#: builtin/branch.c:421 #, c-format msgid "[%s: ahead %d, behind %d]" msgstr "[%s:领先 %d,è½åŽ %d]" -#: builtin/branch.c:423 +#: builtin/branch.c:424 #, c-format msgid "[ahead %d, behind %d]" msgstr "[领先 %d,è½åŽ %d]" -#: builtin/branch.c:535 +#: builtin/branch.c:537 msgid "(no branch)" msgstr "(éžåˆ†æ”¯ï¼‰" -#: builtin/branch.c:600 +#: builtin/branch.c:602 msgid "some refs could not be read" msgstr "一些引用ä¸èƒ½è¯»å–" -#: builtin/branch.c:613 +#: builtin/branch.c:615 msgid "cannot rename the current branch while not on any." msgstr "æ— æ³•é‡å‘½å当å‰åˆ†æ”¯å› 为ä¸å¤„于任何分支上。" -#: builtin/branch.c:623 +#: builtin/branch.c:625 #, c-format msgid "Invalid branch name: '%s'" msgstr "æ— æ•ˆçš„åˆ†æ”¯å:'%s'" -#: builtin/branch.c:638 +#: builtin/branch.c:640 msgid "Branch rename failed" msgstr "分支é‡å‘½å失败" -#: builtin/branch.c:642 +#: builtin/branch.c:644 #, c-format msgid "Renamed a misnamed branch '%s' away" msgstr "é‡å‘½å掉一个错误命å的旧分支 '%s'" -#: builtin/branch.c:646 +#: builtin/branch.c:648 #, c-format msgid "Branch renamed to %s, but HEAD is not updated!" msgstr "分支é‡å‘½å为 %s,但 HEAD 没有更新ï¼" -#: builtin/branch.c:653 +#: builtin/branch.c:655 msgid "Branch is renamed, but update of config-file failed" msgstr "分支被é‡å‘½å,但更新 config 文件失败" -#: builtin/branch.c:668 +#: builtin/branch.c:670 #, c-format msgid "malformed object name %s" msgstr "éžæ³•的对象å %s" -#: builtin/branch.c:692 +#: builtin/branch.c:694 #, c-format msgid "could not write branch description template: %s" msgstr "ä¸èƒ½å†™åˆ†æ”¯æè¿°æ¨¡ç‰ˆï¼š%s" -#: builtin/branch.c:783 +#: builtin/branch.c:724 +#, fuzzy +msgid "Generic options" +msgstr "æ— æ•ˆé€‰é¡¹ï¼š%s" + +#: builtin/branch.c:726 +msgid "show hash and subject, give twice for upstream branch" +msgstr "" + +#: builtin/branch.c:727 +msgid "suppress informational messages" +msgstr "" + +#: builtin/branch.c:728 +msgid "set up tracking mode (see git-pull(1))" +msgstr "" + +#: builtin/branch.c:730 +msgid "change upstream info" +msgstr "" + +#: builtin/branch.c:734 +#, fuzzy +msgid "use colored output" +msgstr "ä¸èƒ½è¾“出é‡å®šå‘" + +#: builtin/branch.c:735 +#, fuzzy +msgid "act on remote-tracking branches" +msgstr "%s 没有æ¥è‡ª %s 的远程跟踪分支" + +#: builtin/branch.c:738 builtin/branch.c:744 builtin/branch.c:765 +#: builtin/branch.c:771 builtin/commit.c:1395 builtin/commit.c:1396 +#: builtin/commit.c:1397 builtin/commit.c:1398 builtin/tag.c:470 +#, fuzzy +msgid "commit" +msgstr "(åæäº¤ï¼‰\n" + +#: builtin/branch.c:739 builtin/branch.c:745 +msgid "print only branches that contain the commit" +msgstr "" + +#: builtin/branch.c:751 +msgid "Specific git-branch actions:" +msgstr "" + +#: builtin/branch.c:752 +msgid "list both remote-tracking and local branches" +msgstr "" + +#: builtin/branch.c:754 +msgid "delete fully merged branch" +msgstr "" + +#: builtin/branch.c:755 +msgid "delete branch (even if not merged)" +msgstr "" + +#: builtin/branch.c:756 +msgid "move/rename a branch and its reflog" +msgstr "" + +#: builtin/branch.c:757 +msgid "move/rename a branch, even if target exists" +msgstr "" + +#: builtin/branch.c:758 +#, fuzzy +msgid "list branch names" +msgstr "æ— æ•ˆçš„åˆ†æ”¯å:'%s'" + +#: builtin/branch.c:759 +msgid "create the branch's reflog" +msgstr "" + +#: builtin/branch.c:761 +msgid "edit the description for the branch" +msgstr "" + +#: builtin/branch.c:762 +#, fuzzy +msgid "force creation (when already exists)" +msgstr "远程 %s å·²ç»å˜åœ¨ã€‚" + +#: builtin/branch.c:765 +#, fuzzy +msgid "print only not merged branches" +msgstr "æ— æ³•ç§»é™¤åˆ†æ”¯ %s" + +#: builtin/branch.c:771 +msgid "print only merged branches" +msgstr "" + +#: builtin/branch.c:775 +msgid "list branches in columns" +msgstr "" + +#: builtin/branch.c:788 msgid "Failed to resolve HEAD as a valid ref." msgstr "æ— æ³•å°† HEAD è§£æžä¸ºæœ‰æ•ˆå¼•用。" -#: builtin/branch.c:788 builtin/clone.c:558 +#: builtin/branch.c:793 builtin/clone.c:561 msgid "HEAD not found below refs/heads!" msgstr "HEAD 没有ä½äºŽ /refs/heads 之下ï¼" -#: builtin/branch.c:808 +#: builtin/branch.c:813 msgid "--column and --verbose are incompatible" msgstr "--column å’Œ --verbose ä¸å…¼å®¹" -#: builtin/branch.c:857 +#: builtin/branch.c:864 +#, fuzzy, c-format +msgid "branch '%s' does not exist" +msgstr "版本库 '%s' ä¸å˜åœ¨" + +#: builtin/branch.c:876 +#, c-format +msgid "Branch '%s' has no upstream information" +msgstr "" + +#: builtin/branch.c:891 msgid "-a and -r options to 'git branch' do not make sense with a branch name" msgstr "'git branch' çš„ -a å’Œ -r 选项带一个分支å傿•°æ²¡æœ‰æ„义" +#: builtin/branch.c:894 +#, c-format +msgid "" +"The --set-upstream flag is deprecated and will be removed. Consider using --" +"track or --set-upstream-to\n" +msgstr "" + +#: builtin/branch.c:911 +#, c-format +msgid "" +"\n" +"If you wanted to make '%s' track '%s', do this:\n" +"\n" +msgstr "" + +#: builtin/branch.c:912 +#, fuzzy, c-format +msgid " git branch -d %s\n" +msgstr " HEAD分支:%s" + +#: builtin/branch.c:913 +#, c-format +msgid " git branch --set-upstream-to %s\n" +msgstr "" + #: builtin/bundle.c:47 #, c-format msgid "%s is okay\n" @@ -1722,100 +2529,238 @@ msgstr "需è¦ä¸€ä¸ªç‰ˆæœ¬åº“æ¥åˆ›å»ºåŒ…。" msgid "Need a repository to unbundle." msgstr "需è¦ä¸€ä¸ªç‰ˆæœ¬åº“æ¥è§£åŒ…。" -#: builtin/checkout.c:113 builtin/checkout.c:146 +#: builtin/cat-file.c:247 +msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>" +msgstr "" + +#: builtin/cat-file.c:248 +msgid "git cat-file (--batch|--batch-check) < <list_of_objects>" +msgstr "" + +#: builtin/cat-file.c:266 +msgid "<type> can be one of: blob, tree, commit, tag" +msgstr "" + +#: builtin/cat-file.c:267 +#, fuzzy +msgid "show object type" +msgstr "å的对象类型。" + +#: builtin/cat-file.c:268 +#, fuzzy +msgid "show object size" +msgstr "å对象 %s" + +#: builtin/cat-file.c:270 +msgid "exit with zero when there's no error" +msgstr "" + +#: builtin/cat-file.c:271 +msgid "pretty-print object's content" +msgstr "" + +#: builtin/cat-file.c:273 +msgid "for blob objects, run textconv on object's content" +msgstr "" + +#: builtin/cat-file.c:275 +msgid "show info and content of objects fed from the standard input" +msgstr "" + +#: builtin/cat-file.c:278 +#, fuzzy +msgid "show info about objects fed from the standard input" +msgstr "ä¸èƒ½ä»Žæ ‡å‡†è¾“å…¥ä¸è¯»å–日志信æ¯" + +#: builtin/check-attr.c:11 +msgid "git check-attr [-a | --all | attr...] [--] pathname..." +msgstr "" + +#: builtin/check-attr.c:12 +msgid "git check-attr --stdin [-a | --all | attr...] < <list-of-paths>" +msgstr "" + +#: builtin/check-attr.c:19 +msgid "report all attributes set on file" +msgstr "" + +#: builtin/check-attr.c:20 +msgid "use .gitattributes only from the index" +msgstr "" + +#: builtin/check-attr.c:21 builtin/hash-object.c:75 +#, fuzzy +msgid "read file names from stdin" +msgstr "(æ£ä»Žæ ‡å‡†è¾“å…¥ä¸è¯»å–日志信æ¯ï¼‰\n" + +#: builtin/check-attr.c:23 +#, fuzzy +msgid "input paths are terminated by a null character" +msgstr "路径以 NUL å—符分隔" + +#: builtin/checkout-index.c:126 +msgid "git checkout-index [options] [--] [<file>...]" +msgstr "" + +#: builtin/checkout-index.c:187 +msgid "check out all files in the index" +msgstr "" + +#: builtin/checkout-index.c:188 +msgid "force overwrite of existing files" +msgstr "" + +#: builtin/checkout-index.c:190 +msgid "no warning for existing files and files not in index" +msgstr "" + +#: builtin/checkout-index.c:192 +#, fuzzy +msgid "don't checkout new files" +msgstr "ä¸èƒ½æ£€å‡º %s" + +#: builtin/checkout-index.c:194 +#, fuzzy +msgid "update stat information in the index file" +msgstr "æ— æ³•å†™æ–°çš„ç´¢å¼•æ–‡ä»¶" + +#: builtin/checkout-index.c:200 +#, fuzzy +msgid "read list of paths from the standard input" +msgstr "(æ£ä»Žæ ‡å‡†è¾“å…¥ä¸è¯»å–日志信æ¯ï¼‰\n" + +#: builtin/checkout-index.c:202 +msgid "write the content to temporary files" +msgstr "" + +#: builtin/checkout-index.c:203 builtin/column.c:30 +msgid "string" +msgstr "" + +#: builtin/checkout-index.c:204 +msgid "when creating files, prepend <string>" +msgstr "" + +#: builtin/checkout-index.c:207 +msgid "copy out the files from named stage" +msgstr "" + +#: builtin/checkout.c:25 +#, fuzzy +msgid "git checkout [options] <branch>" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/checkout.c:26 +#, fuzzy +msgid "git checkout [options] [<branch>] -- <file>..." +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/checkout.c:116 builtin/checkout.c:149 #, c-format msgid "path '%s' does not have our version" msgstr "路径 '%s' 没有我们的版本" -#: builtin/checkout.c:115 builtin/checkout.c:148 +#: builtin/checkout.c:118 builtin/checkout.c:151 #, c-format msgid "path '%s' does not have their version" msgstr "路径 '%s' 没有他们的版本" -#: builtin/checkout.c:131 +#: builtin/checkout.c:134 #, c-format msgid "path '%s' does not have all necessary versions" msgstr "路径 '%s' 没有全部必须的版本" -#: builtin/checkout.c:175 +#: builtin/checkout.c:178 #, c-format msgid "path '%s' does not have necessary versions" msgstr "路径 '%s' 没有必须的版本" -#: builtin/checkout.c:192 +#: builtin/checkout.c:195 #, c-format msgid "path '%s': cannot merge" msgstr "path '%s'ï¼šæ— æ³•åˆå¹¶" -#: builtin/checkout.c:209 +#: builtin/checkout.c:212 #, c-format msgid "Unable to add merge result for '%s'" msgstr "æ— æ³•ä¸º '%s' æ·»åŠ åˆå¹¶ç»“æžœ" -#: builtin/checkout.c:234 builtin/checkout.c:392 +#: builtin/checkout.c:236 builtin/checkout.c:239 builtin/checkout.c:242 +#: builtin/checkout.c:245 +#, fuzzy, c-format +msgid "'%s' cannot be used with updating paths" +msgstr "%s:%s ä¸èƒ½å’Œ %s åŒæ—¶ä½¿ç”¨" + +#: builtin/checkout.c:248 builtin/checkout.c:251 +#, fuzzy, c-format +msgid "'%s' cannot be used with %s" +msgstr "%s:%s ä¸èƒ½å’Œ %s åŒæ—¶ä½¿ç”¨" + +#: builtin/checkout.c:254 +#, c-format +msgid "Cannot update paths and switch to branch '%s' at the same time." +msgstr "" + +#: builtin/checkout.c:265 builtin/checkout.c:426 msgid "corrupt index file" msgstr "æŸå的索引文件" -#: builtin/checkout.c:264 builtin/checkout.c:271 +#: builtin/checkout.c:295 builtin/checkout.c:302 #, c-format msgid "path '%s' is unmerged" msgstr "路径 '%s' 未åˆå¹¶" -#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583 -#: builtin/merge.c:812 +#: builtin/checkout.c:333 builtin/checkout.c:534 builtin/clone.c:586 +#: builtin/merge.c:811 msgid "unable to write new index file" msgstr "æ— æ³•å†™æ–°çš„ç´¢å¼•æ–‡ä»¶" -#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408 -msgid "diff_setup_done failed" -msgstr "diff_setup_done 失败" - -#: builtin/checkout.c:414 +#: builtin/checkout.c:448 msgid "you need to resolve your current index first" msgstr "您需è¦å…ˆè§£å†³å½“å‰ç´¢å¼•的冲çª" -#: builtin/checkout.c:533 +#: builtin/checkout.c:569 #, c-format msgid "Can not do reflog for '%s'\n" msgstr "ä¸èƒ½å¯¹ '%s' 执行 reflog æ“作\n" -#: builtin/checkout.c:566 +#: builtin/checkout.c:602 msgid "HEAD is now at" msgstr "HEAD ç›®å‰ä½äºŽ" -#: builtin/checkout.c:573 +#: builtin/checkout.c:609 #, c-format msgid "Reset branch '%s'\n" msgstr "é‡ç½®åˆ†æ”¯ '%s'\n" -#: builtin/checkout.c:576 +#: builtin/checkout.c:612 #, c-format msgid "Already on '%s'\n" msgstr "å·²ç»ä½äºŽ '%s'\n" -#: builtin/checkout.c:580 +#: builtin/checkout.c:616 #, c-format msgid "Switched to and reset branch '%s'\n" msgstr "切æ¢å¹¶é‡ç½®åˆ†æ”¯ '%s'\n" -#: builtin/checkout.c:582 +#: builtin/checkout.c:618 #, c-format msgid "Switched to a new branch '%s'\n" msgstr "切æ¢åˆ°ä¸€ä¸ªæ–°åˆ†æ”¯ '%s'\n" -#: builtin/checkout.c:584 +#: builtin/checkout.c:620 #, c-format msgid "Switched to branch '%s'\n" msgstr "切æ¢åˆ°åˆ†æ”¯ '%s'\n" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: builtin/checkout.c:640 +#: builtin/checkout.c:676 #, c-format msgid " ... and %d more.\n" msgstr " ... åŠå…¶å®ƒ %d 个。\n" #. The singular version -#: builtin/checkout.c:646 +#: builtin/checkout.c:682 #, c-format msgid "" "Warning: you are leaving %d commit behind, not connected to\n" @@ -1836,7 +2781,7 @@ msgstr[1] "" "\n" "%s\n" -#: builtin/checkout.c:664 +#: builtin/checkout.c:700 #, c-format msgid "" "If you want to keep them by creating a new branch, this may be a good time\n" @@ -1851,105 +2796,201 @@ msgstr "" " git branch new_branch_name %s\n" "\n" -#: builtin/checkout.c:694 +#: builtin/checkout.c:730 msgid "internal error in revision walk" msgstr "在版本é历时é‡åˆ°å†…部错误" -#: builtin/checkout.c:698 +#: builtin/checkout.c:734 msgid "Previous HEAD position was" msgstr "之å‰çš„ HEAD ä½ç½®æ˜¯" -#: builtin/checkout.c:724 +#: builtin/checkout.c:761 builtin/checkout.c:950 msgid "You are on a branch yet to be born" msgstr "您ä½äºŽä¸€ä¸ªå°šæœªåˆå§‹åŒ–的分支" #. case (1) -#: builtin/checkout.c:855 +#: builtin/checkout.c:886 #, c-format msgid "invalid reference: %s" msgstr "æ— æ•ˆå¼•ç”¨ï¼š%s" #. case (1): want a tree -#: builtin/checkout.c:894 +#: builtin/checkout.c:925 #, c-format msgid "reference is not a tree: %s" msgstr "å¼•ç”¨ä¸æ˜¯ä¸€ä¸ªæ ‘:%s" -#: builtin/checkout.c:974 -msgid "-B cannot be used with -b" -msgstr "-B ä¸èƒ½å’Œ -b 共用" +#: builtin/checkout.c:961 +#, fuzzy +msgid "paths cannot be used with switching branches" +msgstr "--ours/--theirs 和切æ¢åˆ†æ”¯ä¸å…¼å®¹ã€‚" -#: builtin/checkout.c:983 -msgid "--patch is incompatible with all other options" -msgstr "--patch 选项和其他选项ä¸å…¼å®¹" +#: builtin/checkout.c:964 builtin/checkout.c:968 +#, fuzzy, c-format +msgid "'%s' cannot be used with switching branches" +msgstr "%s:%s ä¸èƒ½å’Œ %s åŒæ—¶ä½¿ç”¨" -#: builtin/checkout.c:986 -msgid "--detach cannot be used with -b/-B/--orphan" -msgstr "--detach ä¸èƒ½å’Œ -b/-B/--orphan 共用" +#: builtin/checkout.c:972 builtin/checkout.c:975 builtin/checkout.c:980 +#: builtin/checkout.c:983 +#, fuzzy, c-format +msgid "'%s' cannot be used with '%s'" +msgstr "%s:%s ä¸èƒ½å’Œ %s åŒæ—¶ä½¿ç”¨" #: builtin/checkout.c:988 -msgid "--detach cannot be used with -t" -msgstr "--detach ä¸èƒ½å’Œ -t 共用" +#, fuzzy, c-format +msgid "Cannot switch branch to a non-commit '%s'" +msgstr "æ— æ³•åˆ‡æ¢åˆ†æ”¯åˆ°ä¸€ä¸ªéžæäº¤ã€‚" -#: builtin/checkout.c:994 -msgid "--track needs a branch name" -msgstr "--track 需è¦ä¸€ä¸ªåˆ†æ”¯å" +#: builtin/checkout.c:1009 builtin/gc.c:177 +msgid "suppress progress reporting" +msgstr "" -#: builtin/checkout.c:1001 -msgid "Missing branch name; try -b" -msgstr "缺少分支åï¼›å°è¯• -b" +#: builtin/checkout.c:1010 builtin/checkout.c:1012 builtin/clone.c:89 +#: builtin/remote.c:169 builtin/remote.c:171 +#, fuzzy +msgid "branch" +msgstr "ä½äºŽåˆ†æ”¯ " + +#: builtin/checkout.c:1011 +msgid "create and checkout a new branch" +msgstr "" + +#: builtin/checkout.c:1013 +msgid "create/reset and checkout a branch" +msgstr "" + +#: builtin/checkout.c:1014 +#, fuzzy +msgid "create reflog for new branch" +msgstr "列出ã€åˆ›å»ºæˆ–åˆ é™¤åˆ†æ”¯" + +#: builtin/checkout.c:1015 +msgid "detach the HEAD at named commit" +msgstr "" + +#: builtin/checkout.c:1016 +#, fuzzy +msgid "set upstream info for new branch" +msgstr "尚未给分支 '%s' 设置上游" -#: builtin/checkout.c:1007 -msgid "--orphan and -b|-B are mutually exclusive" -msgstr "--orphan å’Œ -b|-B 互斥" +#: builtin/checkout.c:1018 +#, fuzzy +msgid "new branch" +msgstr "[新分支]" -#: builtin/checkout.c:1009 -msgid "--orphan cannot be used with -t" -msgstr "--orphan ä¸èƒ½å’Œ -t 共用" +#: builtin/checkout.c:1018 +#, fuzzy +msgid "new unparented branch" +msgstr "没有当å‰åˆ†æ”¯ã€‚" #: builtin/checkout.c:1019 -msgid "git checkout: -f and -m are incompatible" -msgstr "git checkout:-f å’Œ -m ä¸å…¼å®¹" +msgid "checkout our version for unmerged files" +msgstr "" + +#: builtin/checkout.c:1021 +msgid "checkout their version for unmerged files" +msgstr "" + +#: builtin/checkout.c:1023 +msgid "force checkout (throw away local modifications)" +msgstr "" + +#: builtin/checkout.c:1024 +msgid "perform a 3-way merge with the new branch" +msgstr "" + +#: builtin/checkout.c:1025 builtin/merge.c:215 +#, fuzzy +msgid "update ignored files (default)" +msgstr "更新文件失败" + +#: builtin/checkout.c:1026 builtin/log.c:1111 parse-options.h:241 +msgid "style" +msgstr "" + +#: builtin/checkout.c:1027 +msgid "conflict style (merge or diff3)" +msgstr "" + +#: builtin/checkout.c:1030 +msgid "second guess 'git checkout no-such-branch'" +msgstr "" + +#: builtin/checkout.c:1054 +#, fuzzy +msgid "-b, -B and --orphan are mutually exclusive" +msgstr "-n å’Œ -k 互斥。" + +#: builtin/checkout.c:1071 +msgid "--track needs a branch name" +msgstr "--track 需è¦ä¸€ä¸ªåˆ†æ”¯å" + +#: builtin/checkout.c:1078 +msgid "Missing branch name; try -b" +msgstr "缺少分支åï¼›å°è¯• -b" -#: builtin/checkout.c:1053 +#: builtin/checkout.c:1113 msgid "invalid path specification" msgstr "æ— æ•ˆçš„è·¯å¾„è§„æ ¼" -#: builtin/checkout.c:1061 -#, c-format +#: builtin/checkout.c:1120 +#, fuzzy, c-format msgid "" -"git checkout: updating paths is incompatible with switching branches.\n" +"Cannot update paths and switch to branch '%s' at the same time.\n" "Did you intend to checkout '%s' which can not be resolved as commit?" msgstr "" "git checkout:更新路径和切æ¢åˆ†æ”¯ä¸å…¼å®¹ã€‚\n" "æ‚¨æ˜¯æƒ³è¦æ£€å‡º '%s' 但未能将其解æžä¸ºæäº¤ä¹ˆï¼Ÿ" -#: builtin/checkout.c:1063 -msgid "git checkout: updating paths is incompatible with switching branches." -msgstr "git checkout:更新路径和切æ¢åˆ†æ”¯ä¸å…¼å®¹ã€‚" - -#: builtin/checkout.c:1068 -msgid "git checkout: --detach does not take a path argument" +#: builtin/checkout.c:1125 +#, fuzzy, c-format +msgid "git checkout: --detach does not take a path argument '%s'" msgstr "git checkout:--detach ä¸è·Ÿè·¯å¾„傿•°" -#: builtin/checkout.c:1071 +#: builtin/checkout.c:1129 msgid "" "git checkout: --ours/--theirs, --force and --merge are incompatible when\n" "checking out of the index." msgstr "" "git checkout:在从索引检出时,--ours/--theirsã€--force å’Œ --merge ä¸å…¼å®¹ã€‚" -#: builtin/checkout.c:1090 -msgid "Cannot switch branch to a non-commit." -msgstr "æ— æ³•åˆ‡æ¢åˆ†æ”¯åˆ°ä¸€ä¸ªéžæäº¤ã€‚" +#: builtin/clean.c:19 +msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..." +msgstr "" -#: builtin/checkout.c:1093 -msgid "--ours/--theirs is incompatible with switching branches." -msgstr "--ours/--theirs 和切æ¢åˆ†æ”¯ä¸å…¼å®¹ã€‚" +#: builtin/clean.c:51 +msgid "do not print names of files removed" +msgstr "" + +#: builtin/clean.c:53 +msgid "force" +msgstr "" + +#: builtin/clean.c:55 +#, fuzzy +msgid "remove whole directories" +msgstr "两个输出目录?" + +#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:802 +#: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:199 +msgid "pattern" +msgstr "" + +#: builtin/clean.c:57 +msgid "add <pattern> to ignore rules" +msgstr "" + +#: builtin/clean.c:58 +msgid "remove ignored files, too" +msgstr "" + +#: builtin/clean.c:60 +msgid "remove only ignored files" +msgstr "" #: builtin/clean.c:78 msgid "-x and -X cannot be used together" -msgstr "-x å’Œ -X ä¸èƒ½å…±ç”¨" +msgstr "-x å’Œ -X ä¸èƒ½åŒæ—¶ä½¿ç”¨" #: builtin/clean.c:82 msgid "" @@ -1989,22 +3030,115 @@ msgstr "ä¸ä¼šåˆ 除 %s\n" msgid "Not removing %s\n" msgstr "æœªåˆ é™¤ %s\n" +#: builtin/clone.c:36 +msgid "git clone [options] [--] <repo> [<dir>]" +msgstr "" + +#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:212 +#: builtin/push.c:399 +msgid "force progress reporting" +msgstr "" + +#: builtin/clone.c:66 +msgid "don't create a checkout" +msgstr "" + +#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488 +#, fuzzy +msgid "create a bare repository" +msgstr "䏿˜¯ä¸€ä¸ª git 版本库" + +#: builtin/clone.c:72 +msgid "create a mirror repository (implies bare)" +msgstr "" + +#: builtin/clone.c:74 +msgid "to clone from a local repository" +msgstr "" + +#: builtin/clone.c:76 +msgid "don't use local hardlinks, always copy" +msgstr "" + +#: builtin/clone.c:78 +#, fuzzy +msgid "setup as shared repository" +msgstr "䏿˜¯ä¸€ä¸ª git 版本库" + +#: builtin/clone.c:80 builtin/clone.c:82 +msgid "initialize submodules in the clone" +msgstr "" + +#: builtin/clone.c:83 builtin/init-db.c:485 +#, fuzzy +msgid "template-directory" +msgstr "文件/目录" + +#: builtin/clone.c:84 builtin/init-db.c:486 +msgid "directory from which templates will be used" +msgstr "" + +#: builtin/clone.c:86 +msgid "reference repository" +msgstr "" + +#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44 +#, fuzzy +msgid "name" +msgstr "é‡å‘½å" + +#: builtin/clone.c:88 +msgid "use <name> instead of 'origin' to track upstream" +msgstr "" + +#: builtin/clone.c:90 +msgid "checkout <branch> instead of the remote's HEAD" +msgstr "" + +#: builtin/clone.c:92 +msgid "path to git-upload-pack on the remote" +msgstr "" + +#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:747 +msgid "depth" +msgstr "" + +#: builtin/clone.c:94 +msgid "create a shallow clone of that depth" +msgstr "" + +#: builtin/clone.c:96 +msgid "clone only one branch, HEAD or --branch" +msgstr "" + +#: builtin/clone.c:97 builtin/init-db.c:494 +msgid "gitdir" +msgstr "" + +#: builtin/clone.c:98 builtin/init-db.c:495 +msgid "separate git dir from working tree" +msgstr "" + +#: builtin/clone.c:99 +msgid "key=value" +msgstr "" + +#: builtin/clone.c:100 +#, fuzzy +msgid "set config inside the new repository" +msgstr "è®°å½•å˜æ›´åˆ°ç‰ˆæœ¬åº“" + #: builtin/clone.c:243 #, c-format msgid "reference repository '%s' is not a local directory." msgstr "引用版本库 '%s' 䏿˜¯ä¸€ä¸ªæœ¬åœ°ç›®å½•。" -#: builtin/clone.c:302 -#, c-format -msgid "failed to open '%s'" -msgstr "æ— æ³•æ‰“å¼€ '%s'" - #: builtin/clone.c:306 #, c-format msgid "failed to create directory '%s'" msgstr "æ— æ³•åˆ›å»ºç›®å½• '%s'" -#: builtin/clone.c:308 builtin/diff.c:75 +#: builtin/clone.c:308 builtin/diff.c:77 #, c-format msgid "failed to stat '%s'" msgstr "æ— æ³•æžšä¸¾ '%s' 状æ€" @@ -2019,11 +3153,6 @@ msgstr "%s å˜åœ¨ä¸”䏿˜¯ä¸€ä¸ªç›®å½•" msgid "failed to stat %s\n" msgstr "æ— æ³•æžšä¸¾ %s 状æ€\n" -#: builtin/clone.c:341 -#, c-format -msgid "failed to unlink '%s'" -msgstr "æ— æ³•åˆ é™¤ '%s'" - #: builtin/clone.c:346 #, c-format msgid "failed to create link '%s'" @@ -2039,85 +3168,124 @@ msgstr "æ— æ³•æ‹·è´æ–‡ä»¶è‡³ '%s'" msgid "done.\n" msgstr "完æˆã€‚\n" -#: builtin/clone.c:440 +#: builtin/clone.c:443 #, c-format msgid "Could not find remote branch %s to clone." msgstr "ä¸èƒ½å‘现è¦å…‹éš†çš„远程分支 %s。" -#: builtin/clone.c:549 +#: builtin/clone.c:552 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" msgstr "远程 HEAD 指å‘一个ä¸å˜åœ¨çš„å¼•ç”¨ï¼Œæ— æ³•æ£€å‡ºã€‚\n" -#: builtin/clone.c:639 +#: builtin/clone.c:642 msgid "Too many arguments." msgstr "å¤ªå¤šå‚æ•°ã€‚" -#: builtin/clone.c:643 +#: builtin/clone.c:646 msgid "You must specify a repository to clone." msgstr "您必须指定一个版本库æ¥å…‹éš†ã€‚" -#: builtin/clone.c:654 +#: builtin/clone.c:657 #, c-format msgid "--bare and --origin %s options are incompatible." msgstr "--bare å’Œ --origin %s 选项ä¸å…¼å®¹ã€‚" -#: builtin/clone.c:668 +#: builtin/clone.c:671 #, c-format msgid "repository '%s' does not exist" msgstr "版本库 '%s' ä¸å˜åœ¨" -#: builtin/clone.c:673 +#: builtin/clone.c:676 msgid "--depth is ignored in local clones; use file:// instead." msgstr "--depth 在本地克隆被忽略,改为 file:// å议试试。" -#: builtin/clone.c:683 +#: builtin/clone.c:686 #, c-format msgid "destination path '%s' already exists and is not an empty directory." msgstr "ç›®æ ‡è·¯å¾„ '%s' å·²ç»å˜åœ¨ï¼Œå¹¶ä¸”䏿˜¯ä¸€ä¸ªç©ºç›®å½•。" -#: builtin/clone.c:693 +#: builtin/clone.c:696 #, c-format msgid "working tree '%s' already exists." msgstr "工作区 '%s' å·²ç»å˜åœ¨ã€‚" -#: builtin/clone.c:706 builtin/clone.c:720 +#: builtin/clone.c:709 builtin/clone.c:723 #, c-format msgid "could not create leading directories of '%s'" msgstr "ä¸èƒ½ä¸º '%s' 创建先导目录" -#: builtin/clone.c:709 +#: builtin/clone.c:712 #, c-format msgid "could not create work tree dir '%s'." msgstr "ä¸èƒ½ä¸º '%s' 创建工作区目录。" -#: builtin/clone.c:728 +#: builtin/clone.c:731 #, c-format msgid "Cloning into bare repository '%s'...\n" msgstr "克隆到裸版本库 '%s'...\n" -#: builtin/clone.c:730 +#: builtin/clone.c:733 #, c-format msgid "Cloning into '%s'...\n" msgstr "æ£å…‹éš†åˆ° '%s'...\n" -#: builtin/clone.c:786 +#: builtin/clone.c:789 #, c-format msgid "Don't know how to clone %s" msgstr "ä¸çŸ¥é“如何克隆 %s" -#: builtin/clone.c:835 +#: builtin/clone.c:838 #, c-format msgid "Remote branch %s not found in upstream %s" msgstr "远程分支 %s 在上游 %s 未å‘现" -#: builtin/clone.c:842 +#: builtin/clone.c:845 msgid "You appear to have cloned an empty repository." msgstr "您似乎克隆了一个空版本库。" +#: builtin/column.c:9 +msgid "git column [options]" +msgstr "" + +#: builtin/column.c:26 +msgid "lookup config vars" +msgstr "" + +#: builtin/column.c:27 builtin/column.c:28 +#, fuzzy +msgid "layout to use" +msgstr "本地已过时" + +#: builtin/column.c:29 +msgid "Maximum width" +msgstr "" + +#: builtin/column.c:30 +msgid "Padding space on left border" +msgstr "" + +#: builtin/column.c:31 +msgid "Padding space on right border" +msgstr "" + +#: builtin/column.c:32 +msgid "Padding space between columns" +msgstr "" + #: builtin/column.c:51 msgid "--command must be the first argument" msgstr "--command å¿…é¡»æ˜¯ç¬¬ä¸€ä¸ªå‚æ•°" +#: builtin/commit.c:33 +#, fuzzy +msgid "git commit [options] [--] <filepattern>..." +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/commit.c:38 +#, fuzzy +msgid "git status [options] [--] <filepattern>..." +msgstr "git apply [选项] [<è¡¥ä¸>...]" + #: builtin/commit.c:43 msgid "" "Your name and email address were configured automatically based\n" @@ -2166,93 +3334,93 @@ msgstr "" "\n" "å¦åˆ™ï¼Œè¯·ä½¿ç”¨å‘½ä»¤ 'git reset'\n" -#: builtin/commit.c:253 +#: builtin/commit.c:256 msgid "failed to unpack HEAD tree object" msgstr "æ— æ³•è§£åŒ… HEAD æ ‘å¯¹è±¡" -#: builtin/commit.c:295 +#: builtin/commit.c:298 msgid "unable to create temporary index" msgstr "ä¸èƒ½åˆ›å»ºä¸´æ—¶ç´¢å¼•" -#: builtin/commit.c:301 +#: builtin/commit.c:304 msgid "interactive add failed" msgstr "äº¤äº’å¼æ·»åŠ å¤±è´¥" -#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405 +#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408 msgid "unable to write new_index file" msgstr "æ— æ³•å†™ new_index 文件" -#: builtin/commit.c:386 +#: builtin/commit.c:389 msgid "cannot do a partial commit during a merge." msgstr "在åˆå¹¶è¿‡ç¨‹ä¸ä¸èƒ½åšéƒ¨åˆ†æäº¤ã€‚" -#: builtin/commit.c:388 +#: builtin/commit.c:391 msgid "cannot do a partial commit during a cherry-pick." msgstr "在拣选过程ä¸ä¸èƒ½åšéƒ¨åˆ†æäº¤ã€‚" -#: builtin/commit.c:398 +#: builtin/commit.c:401 msgid "cannot read the index" msgstr "æ— æ³•è¯»å–索引" -#: builtin/commit.c:418 +#: builtin/commit.c:421 msgid "unable to write temporary index file" msgstr "æ— æ³•å†™ä¸´æ—¶ç´¢å¼•æ–‡ä»¶" -#: builtin/commit.c:493 builtin/commit.c:499 +#: builtin/commit.c:510 builtin/commit.c:516 #, c-format msgid "invalid commit: %s" msgstr "æ— æ•ˆçš„æäº¤ï¼š%s" -#: builtin/commit.c:522 +#: builtin/commit.c:539 msgid "malformed --author parameter" msgstr "éžæ³•çš„ --author 傿•°" -#: builtin/commit.c:582 +#: builtin/commit.c:600 #, c-format msgid "Malformed ident string: '%s'" msgstr "éžæ³•的身份å—符串:'%s'" -#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967 +#: builtin/commit.c:638 builtin/commit.c:671 builtin/commit.c:985 #, c-format msgid "could not lookup commit %s" msgstr "ä¸èƒ½æŸ¥è¯¢æäº¤ %s" -#: builtin/commit.c:632 builtin/shortlog.c:296 +#: builtin/commit.c:650 builtin/shortlog.c:296 #, c-format msgid "(reading log message from standard input)\n" msgstr "(æ£ä»Žæ ‡å‡†è¾“å…¥ä¸è¯»å–日志信æ¯ï¼‰\n" -#: builtin/commit.c:634 +#: builtin/commit.c:652 msgid "could not read log from standard input" msgstr "ä¸èƒ½ä»Žæ ‡å‡†è¾“å…¥ä¸è¯»å–日志信æ¯" -#: builtin/commit.c:638 +#: builtin/commit.c:656 #, c-format msgid "could not read log file '%s'" msgstr "ä¸èƒ½è¯»å–日志文件 '%s'" -#: builtin/commit.c:644 +#: builtin/commit.c:662 msgid "commit has empty message" msgstr "æäº¤è¯´æ˜Žä¸ºç©º" -#: builtin/commit.c:660 +#: builtin/commit.c:678 msgid "could not read MERGE_MSG" msgstr "ä¸èƒ½è¯»å– MERGE_MSG" -#: builtin/commit.c:664 +#: builtin/commit.c:682 msgid "could not read SQUASH_MSG" msgstr "ä¸èƒ½è¯»å– SQUASH_MSG" -#: builtin/commit.c:668 +#: builtin/commit.c:686 #, c-format msgid "could not read '%s'" msgstr "ä¸èƒ½è¯»å– '%s'" -#: builtin/commit.c:720 +#: builtin/commit.c:738 msgid "could not write commit template" msgstr "ä¸èƒ½å†™æäº¤æ¨¡ç‰ˆ" -#: builtin/commit.c:731 +#: builtin/commit.c:749 #, c-format msgid "" "\n" @@ -2262,11 +3430,11 @@ msgid "" "and try again.\n" msgstr "" "\n" -"çœ‹èµ·æ¥æ‚¨æ£åœ¨åšä¸€ä¸ªåˆå¹¶æäº¤ã€‚如果ä¸å¯¹ï¼Œè¯·åˆ 除文件\n" +"似乎您æ£åœ¨åšä¸€ä¸ªåˆå¹¶æäº¤ã€‚如果ä¸å¯¹ï¼Œè¯·åˆ 除文件\n" "\t%s\n" "ç„¶åŽé‡è¯•。\n" -#: builtin/commit.c:736 +#: builtin/commit.c:754 #, c-format msgid "" "\n" @@ -2276,11 +3444,11 @@ msgid "" "and try again.\n" msgstr "" "\n" -"çœ‹èµ·æ¥æ‚¨æ£åœ¨åšä¸€ä¸ªæ‹£é€‰æäº¤ã€‚如果ä¸å¯¹ï¼Œè¯·åˆ 除文件\n" +"似乎您æ£åœ¨åšä¸€ä¸ªæ‹£é€‰æäº¤ã€‚如果ä¸å¯¹ï¼Œè¯·åˆ 除文件\n" "\t%s\n" "ç„¶åŽé‡è¯•。\n" -#: builtin/commit.c:748 +#: builtin/commit.c:766 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be ignored, and an empty message aborts the commit.\n" @@ -2288,7 +3456,7 @@ msgstr "" "è¯·ä¸ºæ‚¨çš„å˜æ›´è¾“å…¥æäº¤è¯´æ˜Žã€‚以 '#' 开始的行将被忽略,而一个空的æäº¤\n" "è¯´æ˜Žå°†ä¼šç»ˆæ¢æäº¤ã€‚\n" -#: builtin/commit.c:753 +#: builtin/commit.c:771 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be kept; you may remove them yourself if you want to.\n" @@ -2298,160 +3466,357 @@ msgstr "" "å¦‚æžœæ‚¨æƒ³è¿™æ ·åšçš„è¯ã€‚而一个空的æäº¤è¯´æ˜Žå°†ä¼šç»ˆæ¢æäº¤ã€‚\n" # 译者:为ä¿è¯åœ¨è¾“出ä¸å¯¹é½ï¼Œæ³¨æ„调整å¥ä¸ç©ºæ ¼ï¼ -#: builtin/commit.c:766 +#: builtin/commit.c:784 #, c-format msgid "%sAuthor: %s" msgstr "%s作者: %s" # 译者:为ä¿è¯åœ¨è¾“出ä¸å¯¹é½ï¼Œæ³¨æ„调整å¥ä¸ç©ºæ ¼ï¼ -#: builtin/commit.c:773 +#: builtin/commit.c:791 #, c-format msgid "%sCommitter: %s" msgstr "%sæäº¤è€…: %s" -#: builtin/commit.c:793 +#: builtin/commit.c:811 msgid "Cannot read index" msgstr "æ— æ³•è¯»å–索引" -#: builtin/commit.c:830 +#: builtin/commit.c:848 msgid "Error building trees" msgstr "æ— æ³•åˆ›å»ºæ ‘å¯¹è±¡" -#: builtin/commit.c:845 builtin/tag.c:361 +#: builtin/commit.c:863 builtin/tag.c:361 #, c-format msgid "Please supply the message using either -m or -F option.\n" msgstr "请使用 -m 或者 -F 选项æä¾›æäº¤è¯´æ˜Žã€‚\n" -#: builtin/commit.c:942 +#: builtin/commit.c:960 #, c-format msgid "No existing author found with '%s'" msgstr "æ²¡æœ‰æ‰¾åˆ°åŒ¹é… '%s' 的作者" -#: builtin/commit.c:957 builtin/commit.c:1157 +#: builtin/commit.c:975 builtin/commit.c:1175 #, c-format msgid "Invalid untracked files mode '%s'" msgstr "æ— æ•ˆçš„æœªè¿½è¸ªæ–‡ä»¶å‚æ•° '%s'" -#: builtin/commit.c:997 +#: builtin/commit.c:1015 msgid "Using both --reset-author and --author does not make sense" msgstr "åŒæ—¶ä½¿ç”¨ --reset-author å’Œ --author 没有æ„义" -#: builtin/commit.c:1008 +#: builtin/commit.c:1026 msgid "You have nothing to amend." msgstr "您没有å¯ä¿®è¡¥çš„æäº¤ã€‚" -#: builtin/commit.c:1011 +#: builtin/commit.c:1029 msgid "You are in the middle of a merge -- cannot amend." msgstr "您æ£å¤„于一个åˆå¹¶è¿‡ç¨‹ä¸ -- æ— æ³•ä¿®è¡¥æäº¤ã€‚" -#: builtin/commit.c:1013 +#: builtin/commit.c:1031 msgid "You are in the middle of a cherry-pick -- cannot amend." msgstr "您æ£å¤„äºŽä¸€ä¸ªæ‹£é€‰è¿‡ç¨‹ä¸ -- æ— æ³•ä¿®è¡¥æäº¤ã€‚" -#: builtin/commit.c:1016 +#: builtin/commit.c:1034 msgid "Options --squash and --fixup cannot be used together" -msgstr "选项 --squash å’Œ --fixup ä¸èƒ½å…±ç”¨" +msgstr "选项 --squash å’Œ --fixup ä¸èƒ½åŒæ—¶ä½¿ç”¨" -#: builtin/commit.c:1026 +#: builtin/commit.c:1044 msgid "Only one of -c/-C/-F/--fixup can be used." msgstr "åªèƒ½ç”¨ä¸€ä¸ª -c/-C/-F/--fixup 选项。" -#: builtin/commit.c:1028 +#: builtin/commit.c:1046 msgid "Option -m cannot be combined with -c/-C/-F/--fixup." -msgstr "选项 -m ä¸èƒ½å’Œ -c/-C/-F/--fixup 共用。" +msgstr "选项 -m ä¸èƒ½å’Œ -c/-C/-F/--fixup åŒæ—¶ä½¿ç”¨ã€‚" -#: builtin/commit.c:1036 +#: builtin/commit.c:1054 msgid "--reset-author can be used only with -C, -c or --amend." -msgstr "--reset-author åªèƒ½å’Œ -Cã€-c 或 --amend 共用。" +msgstr "--reset-author åªèƒ½å’Œ -Cã€-c 或 --amend åŒæ—¶ä½¿ç”¨ã€‚" -#: builtin/commit.c:1053 +#: builtin/commit.c:1071 msgid "Only one of --include/--only/--all/--interactive/--patch can be used." msgstr "åªèƒ½ç”¨ä¸€ä¸ª --include/--only/--all/--interactive/--patch 选项。" -#: builtin/commit.c:1055 +#: builtin/commit.c:1073 msgid "No paths with --include/--only does not make sense." msgstr "傿•° --include/--only ä¸è·Ÿè·¯å¾„没有æ„义。" -#: builtin/commit.c:1057 +#: builtin/commit.c:1075 msgid "Clever... amending the last one with dirty index." msgstr "èªæ˜Ž... 在索引ä¸å¹²å‡€ä¸‹ä¿®è¡¥æœ€åŽçš„æäº¤ã€‚" -#: builtin/commit.c:1059 +#: builtin/commit.c:1077 msgid "Explicit paths specified without -i nor -o; assuming --only paths..." msgstr "指定了明确的路径而没有使用 -i 或 -o 选项;认为是 --only paths..." -#: builtin/commit.c:1069 builtin/tag.c:577 +#: builtin/commit.c:1087 builtin/tag.c:577 #, c-format msgid "Invalid cleanup mode %s" msgstr "æ— æ•ˆçš„æ¸…ç†æ¨¡å¼ %s" -#: builtin/commit.c:1074 +#: builtin/commit.c:1092 msgid "Paths with -a does not make sense." -msgstr "路径和 -a 选项共用没有æ„义。" +msgstr "路径和 -a é€‰é¡¹åŒæ—¶ä½¿ç”¨æ²¡æœ‰æ„义。" + +#: builtin/commit.c:1189 builtin/commit.c:1417 +msgid "show status concisely" +msgstr "" + +#: builtin/commit.c:1191 builtin/commit.c:1419 +msgid "show branch information" +msgstr "" + +#: builtin/commit.c:1193 builtin/commit.c:1421 builtin/push.c:389 +msgid "machine-readable output" +msgstr "" + +#: builtin/commit.c:1196 builtin/commit.c:1423 +msgid "terminate entries with NUL" +msgstr "" + +#: builtin/commit.c:1198 builtin/commit.c:1426 builtin/fast-export.c:636 +#: builtin/fast-export.c:639 builtin/tag.c:461 +msgid "mode" +msgstr "" + +#: builtin/commit.c:1199 builtin/commit.c:1426 +msgid "show untracked files, optional modes: all, normal, no. (Default: all)" +msgstr "" + +#: builtin/commit.c:1202 +msgid "show ignored files" +msgstr "" + +#: builtin/commit.c:1203 parse-options.h:151 +msgid "when" +msgstr "何时" + +#: builtin/commit.c:1204 +msgid "" +"ignore changes to submodules, optional when: all, dirty, untracked. " +"(Default: all)" +msgstr "" + +#: builtin/commit.c:1206 +#, fuzzy +msgid "list untracked files in columns" +msgstr "æ— æ•ˆçš„æœªè¿½è¸ªæ–‡ä»¶å‚æ•° '%s'" -#: builtin/commit.c:1257 +#: builtin/commit.c:1275 msgid "couldn't look up newly created commit" msgstr "æ— æ³•æ‰¾åˆ°æ–°åˆ›å»ºçš„æäº¤" -#: builtin/commit.c:1259 +#: builtin/commit.c:1277 msgid "could not parse newly created commit" msgstr "ä¸èƒ½è§£æžæ–°åˆ›å»ºçš„æäº¤" -#: builtin/commit.c:1300 +#: builtin/commit.c:1318 msgid "detached HEAD" msgstr "分离头指针" # è¯‘è€…ï¼šä¸æ–‡å—符串拼接,å¯åˆ 除å‰å¯¼ç©ºæ ¼ -#: builtin/commit.c:1302 +#: builtin/commit.c:1320 msgid " (root-commit)" msgstr "ï¼ˆæ ¹æäº¤ï¼‰" -#: builtin/commit.c:1446 +#: builtin/commit.c:1387 +msgid "suppress summary after successful commit" +msgstr "" + +#: builtin/commit.c:1388 +msgid "show diff in commit message template" +msgstr "" + +#: builtin/commit.c:1390 +#, fuzzy +msgid "Commit message options" +msgstr "ä¸èƒ½å¾—到 %s çš„æäº¤è¯´æ˜Ž" + +#: builtin/commit.c:1391 builtin/tag.c:459 +msgid "read message from file" +msgstr "" + +#: builtin/commit.c:1392 +msgid "author" +msgstr "" + +#: builtin/commit.c:1392 +#, fuzzy +msgid "override author for commit" +msgstr "åˆå¹¶æœªè¿”回æäº¤" + +#: builtin/commit.c:1393 builtin/gc.c:178 +msgid "date" +msgstr "" + +#: builtin/commit.c:1393 +#, fuzzy +msgid "override date for commit" +msgstr "åˆå¹¶æœªè¿”回æäº¤" + +#: builtin/commit.c:1394 builtin/merge.c:206 builtin/notes.c:534 +#: builtin/notes.c:691 builtin/tag.c:457 +#, fuzzy +msgid "message" +msgstr "æ— tag 说明?" + +#: builtin/commit.c:1394 +#, fuzzy +msgid "commit message" +msgstr "空æäº¤ä¿¡æ¯ã€‚" + +#: builtin/commit.c:1395 +msgid "reuse and edit message from specified commit" +msgstr "" + +#: builtin/commit.c:1396 +msgid "reuse message from specified commit" +msgstr "" + +#: builtin/commit.c:1397 +msgid "use autosquash formatted message to fixup specified commit" +msgstr "" + +#: builtin/commit.c:1398 +msgid "use autosquash formatted message to squash specified commit" +msgstr "" + +#: builtin/commit.c:1399 +msgid "the commit is authored by me now (used with -C/-c/--amend)" +msgstr "" + +#: builtin/commit.c:1400 builtin/log.c:1068 builtin/revert.c:109 +msgid "add Signed-off-by:" +msgstr "" + +#: builtin/commit.c:1401 +msgid "use specified template file" +msgstr "" + +#: builtin/commit.c:1402 +#, fuzzy +msgid "force edit of commit" +msgstr "åˆå¹¶æœªè¿”回æäº¤" + +#: builtin/commit.c:1403 +msgid "default" +msgstr "" + +#: builtin/commit.c:1403 builtin/tag.c:462 +msgid "how to strip spaces and #comments from message" +msgstr "" + +#: builtin/commit.c:1404 +#, fuzzy +msgid "include status in commit message template" +msgstr "ä¸èƒ½å†™æäº¤æ¨¡ç‰ˆ" + +#: builtin/commit.c:1405 builtin/merge.c:213 builtin/tag.c:463 +msgid "key id" +msgstr "" + +#: builtin/commit.c:1406 builtin/merge.c:214 +msgid "GPG sign commit" +msgstr "" + +#. end commit message options +#: builtin/commit.c:1409 +msgid "Commit contents options" +msgstr "" + +#: builtin/commit.c:1410 +msgid "commit all changed files" +msgstr "" + +#: builtin/commit.c:1411 +msgid "add specified files to index for commit" +msgstr "" + +#: builtin/commit.c:1412 +#, fuzzy +msgid "interactively add files" +msgstr "äº¤äº’å¼æ·»åŠ å¤±è´¥" + +#: builtin/commit.c:1413 +#, fuzzy +msgid "interactively add changes" +msgstr "äº¤äº’å¼æ·»åŠ å¤±è´¥" + +#: builtin/commit.c:1414 +#, fuzzy +msgid "commit only specified files" +msgstr "æ— æ³•è¿˜åŽŸä¿®æ”¹çš„æ–‡ä»¶" + +#: builtin/commit.c:1415 +msgid "bypass pre-commit hook" +msgstr "" + +#: builtin/commit.c:1416 +#, fuzzy +msgid "show what would be committed" +msgstr "è¦æäº¤çš„å˜æ›´ï¼š" + +#: builtin/commit.c:1424 +msgid "amend previous commit" +msgstr "" + +#: builtin/commit.c:1425 +msgid "bypass post-rewrite hook" +msgstr "" + +#: builtin/commit.c:1430 +msgid "ok to record an empty change" +msgstr "" + +#: builtin/commit.c:1433 +msgid "ok to record a change with an empty message" +msgstr "" + +#: builtin/commit.c:1464 msgid "could not parse HEAD commit" msgstr "ä¸èƒ½è§£æž HEAD æäº¤" -#: builtin/commit.c:1484 builtin/merge.c:509 +#: builtin/commit.c:1502 builtin/merge.c:508 #, c-format msgid "could not open '%s' for reading" msgstr "ä¸èƒ½ä¸ºè¯»å…¥æ‰“å¼€ '%s'" -#: builtin/commit.c:1491 +#: builtin/commit.c:1509 #, c-format msgid "Corrupt MERGE_HEAD file (%s)" msgstr "æŸåçš„ MERGE_HEAD 文件(%s)" -#: builtin/commit.c:1498 +#: builtin/commit.c:1516 msgid "could not read MERGE_MODE" msgstr "ä¸èƒ½è¯»å– MERGE_MODE" -#: builtin/commit.c:1517 +#: builtin/commit.c:1535 #, c-format msgid "could not read commit message: %s" msgstr "ä¸èƒ½è¯»å–æäº¤è¯´æ˜Žï¼š%s" -#: builtin/commit.c:1531 +#: builtin/commit.c:1549 #, c-format msgid "Aborting commit; you did not edit the message.\n" msgstr "ç»ˆæ¢æäº¤ï¼›æ‚¨æœªæ›´æ”¹æ¥è‡ªæ¨¡ç‰ˆçš„æäº¤è¯´æ˜Žã€‚\n" -#: builtin/commit.c:1536 +#: builtin/commit.c:1554 #, c-format msgid "Aborting commit due to empty commit message.\n" msgstr "ç»ˆæ¢æäº¤å› ä¸ºæäº¤è¯´æ˜Žä¸ºç©ºã€‚\n" -#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961 +#: builtin/commit.c:1569 builtin/merge.c:935 builtin/merge.c:960 msgid "failed to write commit object" msgstr "æ— æ³•å†™æäº¤å¯¹è±¡" -#: builtin/commit.c:1572 +#: builtin/commit.c:1590 msgid "cannot lock HEAD ref" msgstr "æ— æ³•é”定 HEAD 引用" -#: builtin/commit.c:1576 +#: builtin/commit.c:1594 msgid "cannot update HEAD ref" msgstr "æ— æ³•æ›´æ–° HEAD 引用" -#: builtin/commit.c:1587 +#: builtin/commit.c:1605 msgid "" "Repository has been updated, but unable to write\n" "new_index file. Check that disk is not full or quota is\n" @@ -2460,6 +3825,138 @@ msgstr "" "ç‰ˆæœ¬åº“å·²æ›´æ–°ï¼Œä½†æ— æ³•å†™ new_index 文件。检查是å¦ç£ç›˜å·²æ»¡\n" "或ç£ç›˜é…é¢å·²è€—å°½ï¼Œç„¶åŽæ‰§è¡Œ \"git reset HEAD\" æ¢å¤ã€‚" +#: builtin/config.c:7 +msgid "git config [options]" +msgstr "" + +#: builtin/config.c:52 +msgid "Config file location" +msgstr "" + +#: builtin/config.c:53 +#, fuzzy +msgid "use global config file" +msgstr "æ— æ³•æ›´æ–° config 文件" + +#: builtin/config.c:54 +msgid "use system config file" +msgstr "" + +#: builtin/config.c:55 +#, fuzzy +msgid "use repository config file" +msgstr "需è¦ä¸€ä¸ªç‰ˆæœ¬åº“æ¥è§£åŒ…。" + +#: builtin/config.c:56 +#, fuzzy +msgid "use given config file" +msgstr "未预期的文件结æŸ" + +#: builtin/config.c:57 +#, fuzzy +msgid "Action" +msgstr "动作" + +#: builtin/config.c:58 +msgid "get value: name [value-regex]" +msgstr "" + +#: builtin/config.c:59 +msgid "get all values: key [value-regex]" +msgstr "" + +#: builtin/config.c:60 +msgid "get values for regexp: name-regex [value-regex]" +msgstr "" + +#: builtin/config.c:61 +msgid "replace all matching variables: name value [value_regex]" +msgstr "" + +#: builtin/config.c:62 +msgid "add a new variable: name value" +msgstr "" + +#: builtin/config.c:63 +msgid "remove a variable: name [value-regex]" +msgstr "" + +#: builtin/config.c:64 +msgid "remove all matches: name [value-regex]" +msgstr "" + +#: builtin/config.c:65 +msgid "rename section: old-name new-name" +msgstr "" + +#: builtin/config.c:66 +msgid "remove a section: name" +msgstr "" + +#: builtin/config.c:67 +msgid "list all" +msgstr "" + +#: builtin/config.c:68 +msgid "open an editor" +msgstr "" + +#: builtin/config.c:69 builtin/config.c:70 +msgid "slot" +msgstr "" + +#: builtin/config.c:69 +msgid "find the color configured: [default]" +msgstr "" + +#: builtin/config.c:70 +msgid "find the color setting: [stdout-is-tty]" +msgstr "" + +#: builtin/config.c:71 +msgid "Type" +msgstr "" + +#: builtin/config.c:72 +msgid "value is \"true\" or \"false\"" +msgstr "" + +#: builtin/config.c:73 +msgid "value is decimal number" +msgstr "" + +#: builtin/config.c:74 +msgid "value is --bool or --int" +msgstr "" + +#: builtin/config.c:75 +msgid "value is a path (file or directory name)" +msgstr "" + +#: builtin/config.c:76 +msgid "Other" +msgstr "" + +#: builtin/config.c:77 +msgid "terminate values with NUL byte" +msgstr "" + +#: builtin/config.c:78 +msgid "respect include directives on lookup" +msgstr "" + +#: builtin/count-objects.c:69 +msgid "git count-objects [-v]" +msgstr "" + +#: builtin/describe.c:15 +msgid "git describe [options] <committish>*" +msgstr "" + +#: builtin/describe.c:16 +msgid "git describe [options] --dirty" +msgstr "" + #: builtin/describe.c:234 #, c-format msgid "annotated tag %s not available" @@ -2532,6 +4029,52 @@ msgstr "" "å‘现多于 %i 个 tag,列出最近的 %i 个\n" "在 %s 放弃æœç´¢\n" +#: builtin/describe.c:403 +msgid "find the tag that comes after the commit" +msgstr "" + +#: builtin/describe.c:404 +msgid "debug search strategy on stderr" +msgstr "" + +#: builtin/describe.c:405 +msgid "use any ref in .git/refs" +msgstr "" + +#: builtin/describe.c:406 +msgid "use any tag in .git/refs/tags" +msgstr "" + +#: builtin/describe.c:407 +msgid "always use long format" +msgstr "" + +#: builtin/describe.c:410 +#, fuzzy +msgid "only output exact matches" +msgstr "没有 tag å‡†ç¡®åŒ¹é… '%s'" + +#: builtin/describe.c:412 +msgid "consider <n> most recent tags (default: 10)" +msgstr "" + +#: builtin/describe.c:414 +#, fuzzy +msgid "only consider tags matching <pattern>" +msgstr "输出和模å¼åŒ¹é…的行" + +#: builtin/describe.c:416 builtin/name-rev.c:238 +msgid "show abbreviated commit object as fallback" +msgstr "" + +#: builtin/describe.c:417 +msgid "mark" +msgstr "" + +#: builtin/describe.c:418 +msgid "append <mark> on dirty working tree (default: \"-dirty\")" +msgstr "" + #: builtin/describe.c:436 msgid "--long is incompatible with --abbrev=0" msgstr "--long 与 --abbrev=0 ä¸å…¼å®¹" @@ -2542,113 +4085,239 @@ msgstr "没有å‘现åç§°ï¼Œæ— æ³•æè¿°ä»»ä½•东西。" #: builtin/describe.c:482 msgid "--dirty is incompatible with committishes" -msgstr "--dirty ä¸èƒ½ä¸Žæäº¤å…±ç”¨" +msgstr "--dirty ä¸èƒ½ä¸Žæäº¤åŒæ—¶ä½¿ç”¨" -#: builtin/diff.c:77 +#: builtin/diff.c:79 #, c-format msgid "'%s': not a regular file or symlink" msgstr "'%s'ï¼šä¸æ˜¯ä¸€ä¸ªæ£è§„文件或符å·é“¾æŽ¥" -#: builtin/diff.c:220 +#: builtin/diff.c:224 #, c-format msgid "invalid option: %s" msgstr "æ— æ•ˆé€‰é¡¹ï¼š%s" -#: builtin/diff.c:297 +#: builtin/diff.c:301 msgid "Not a git repository" msgstr "䏿˜¯ä¸€ä¸ª git 版本库" -#: builtin/diff.c:347 +#: builtin/diff.c:344 #, c-format msgid "invalid object '%s' given." msgstr "æä¾›äº†æ— 效对象 '%s'。" -#: builtin/diff.c:352 +#: builtin/diff.c:349 #, c-format msgid "more than %d trees given: '%s'" msgstr "æä¾›äº†è¶…过 %d ä¸ªæ ‘å¯¹è±¡ï¼š'%s'" -#: builtin/diff.c:362 +#: builtin/diff.c:359 #, c-format msgid "more than two blobs given: '%s'" -msgstr "æä¾›äº†è¶…过两个 blob 对象:'%s'" +msgstr "æä¾›äº†è¶…过两个二进制对象(blob):'%s'" -#: builtin/diff.c:370 +#: builtin/diff.c:367 #, c-format msgid "unhandled object '%s' given." msgstr "æä¾›äº†æ— 法处ç†çš„对象 '%s'。" -#: builtin/fetch.c:200 +#: builtin/fast-export.c:22 +msgid "git fast-export [rev-list-opts]" +msgstr "" + +#: builtin/fast-export.c:635 +#, fuzzy +msgid "show progress after <n> objects" +msgstr "显示å„ç§ç±»åž‹çš„对象" + +#: builtin/fast-export.c:637 +msgid "select handling of signed tags" +msgstr "" + +#: builtin/fast-export.c:640 +msgid "select handling of tags that tag filtered objects" +msgstr "" + +#: builtin/fast-export.c:643 +msgid "Dump marks to this file" +msgstr "" + +#: builtin/fast-export.c:645 +msgid "Import marks from this file" +msgstr "" + +#: builtin/fast-export.c:647 +msgid "Fake a tagger when tags lack one" +msgstr "" + +#: builtin/fast-export.c:649 +msgid "Output full tree for each commit" +msgstr "" + +#: builtin/fast-export.c:651 +msgid "Use the done feature to terminate the stream" +msgstr "" + +#: builtin/fast-export.c:652 +msgid "Skip output of blob data" +msgstr "" + +#: builtin/fetch.c:20 +#, fuzzy +msgid "git fetch [<options>] [<repository> [<refspec>...]]" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/fetch.c:21 +msgid "git fetch [<options>] <group>" +msgstr "" + +#: builtin/fetch.c:22 +msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]" +msgstr "" + +#: builtin/fetch.c:23 +msgid "git fetch --all [<options>]" +msgstr "" + +#: builtin/fetch.c:60 +msgid "fetch from all remotes" +msgstr "" + +#: builtin/fetch.c:62 +msgid "append to .git/FETCH_HEAD instead of overwriting" +msgstr "" + +#: builtin/fetch.c:64 +msgid "path to upload pack on remote end" +msgstr "" + +#: builtin/fetch.c:65 +msgid "force overwrite of local branch" +msgstr "" + +#: builtin/fetch.c:67 +msgid "fetch from multiple remotes" +msgstr "" + +#: builtin/fetch.c:69 +#, fuzzy +msgid "fetch all tags and associated objects" +msgstr "更新远程引用和相关的对象" + +#: builtin/fetch.c:71 +msgid "do not fetch all tags (--no-tags)" +msgstr "" + +#: builtin/fetch.c:73 +#, fuzzy +msgid "prune remote-tracking branches no longer on remote" +msgstr "%s 没有æ¥è‡ª %s 的远程跟踪分支" + +#: builtin/fetch.c:74 +msgid "on-demand" +msgstr "" + +#: builtin/fetch.c:75 +msgid "control recursive fetching of submodules" +msgstr "" + +#: builtin/fetch.c:79 +msgid "keep downloaded pack" +msgstr "" + +#: builtin/fetch.c:81 +#, fuzzy +msgid "allow updating of HEAD ref" +msgstr "æ— æ³•æ›´æ–° HEAD 引用" + +#: builtin/fetch.c:84 +msgid "deepen history of shallow clone" +msgstr "" + +#: builtin/fetch.c:85 builtin/log.c:1083 +msgid "dir" +msgstr "" + +#: builtin/fetch.c:86 +#, fuzzy +msgid "prepend this to submodule path output" +msgstr "æ— æ³•é€’å½’è¿›åæ¨¡ç»„路径 '$sm_path'" + +#: builtin/fetch.c:89 +msgid "default mode for recursion" +msgstr "" + +#: builtin/fetch.c:201 msgid "Couldn't find remote ref HEAD" msgstr "æ— æ³•å‘现远程 HEAD 引用" -#: builtin/fetch.c:253 +#: builtin/fetch.c:254 #, c-format msgid "object %s not found" msgstr "对象 %s 未å‘现" -#: builtin/fetch.c:259 +#: builtin/fetch.c:260 msgid "[up to date]" msgstr "[最新]" -#: builtin/fetch.c:273 +#: builtin/fetch.c:274 #, c-format msgid "! %-*s %-*s -> %s (can't fetch in current branch)" msgstr "! %-*s %-*s -> %s (在当å‰åˆ†æ”¯ä¸‹ä¸èƒ½èŽ·å–)" -#: builtin/fetch.c:274 builtin/fetch.c:360 +#: builtin/fetch.c:275 builtin/fetch.c:361 msgid "[rejected]" msgstr "[已拒ç»]" -#: builtin/fetch.c:285 +#: builtin/fetch.c:286 msgid "[tag update]" msgstr "[tagæ›´æ–°]" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340 +#: builtin/fetch.c:288 builtin/fetch.c:323 builtin/fetch.c:341 msgid " (unable to update local ref)" msgstr " (ä¸èƒ½æ›´æ–°æœ¬åœ°å¼•用)" -#: builtin/fetch.c:305 +#: builtin/fetch.c:306 msgid "[new tag]" msgstr "[æ–°tag]" -#: builtin/fetch.c:308 +#: builtin/fetch.c:309 msgid "[new branch]" msgstr "[新分支]" -#: builtin/fetch.c:311 +#: builtin/fetch.c:312 msgid "[new ref]" msgstr "[新引用]" -#: builtin/fetch.c:356 +#: builtin/fetch.c:357 msgid "unable to update local ref" msgstr "ä¸èƒ½æ›´æ–°æœ¬åœ°å¼•用" -#: builtin/fetch.c:356 +#: builtin/fetch.c:357 msgid "forced update" msgstr "强制更新" -#: builtin/fetch.c:362 +#: builtin/fetch.c:363 msgid "(non-fast-forward)" msgstr "(éžå¿«è¿›å¼ï¼‰" -#: builtin/fetch.c:393 builtin/fetch.c:685 +#: builtin/fetch.c:394 builtin/fetch.c:686 #, c-format msgid "cannot open %s: %s\n" msgstr "æ— æ³•æ‰“å¼€ %s:%s\n" -#: builtin/fetch.c:402 +#: builtin/fetch.c:403 #, c-format msgid "%s did not send all necessary objects\n" msgstr "%s 未å‘逿‰€æœ‰å¿…须的对象\n" -#: builtin/fetch.c:488 +#: builtin/fetch.c:489 #, c-format msgid "From %.*s\n" msgstr "æ¥è‡ª %.*s\n" -#: builtin/fetch.c:499 +#: builtin/fetch.c:500 #, c-format msgid "" "some local refs could not be updated; try running\n" @@ -2658,82 +4327,204 @@ msgstr "" " 'git remote prune %s' æ¥åˆ é™¤æ—§çš„ã€æœ‰å†²çªçš„分支" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: builtin/fetch.c:549 +#: builtin/fetch.c:550 #, c-format msgid " (%s will become dangling)" msgstr " (%s å°†æˆä¸ºæ‚¬ç©ºçжæ€ï¼‰" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: builtin/fetch.c:550 +#: builtin/fetch.c:551 #, c-format msgid " (%s has become dangling)" msgstr " (%s å·²æˆä¸ºæ‚¬ç©ºçжæ€ï¼‰" -#: builtin/fetch.c:557 +#: builtin/fetch.c:558 msgid "[deleted]" msgstr "[å·²åˆ é™¤]" -#: builtin/fetch.c:558 builtin/remote.c:1055 +#: builtin/fetch.c:559 builtin/remote.c:1055 msgid "(none)" msgstr "ï¼ˆæ— ï¼‰" -#: builtin/fetch.c:675 +#: builtin/fetch.c:676 #, c-format msgid "Refusing to fetch into current branch %s of non-bare repository" msgstr "æ‹’ç»èŽ·å–到éžè£¸ç‰ˆæœ¬åº“的当å‰åˆ†æ”¯ %s" -#: builtin/fetch.c:709 +#: builtin/fetch.c:710 #, c-format msgid "Don't know how to fetch from %s" msgstr "ä¸çŸ¥é“如何从 %s 获å–" -#: builtin/fetch.c:786 +#: builtin/fetch.c:787 #, c-format msgid "Option \"%s\" value \"%s\" is not valid for %s" msgstr "选项 \"%s\" 的值 \"%s\" 对于 %s æ˜¯æ— æ•ˆçš„" -#: builtin/fetch.c:789 +#: builtin/fetch.c:790 #, c-format msgid "Option \"%s\" is ignored for %s\n" msgstr "选项 \"%s\" 为 %s 所忽略\n" -#: builtin/fetch.c:888 +#: builtin/fetch.c:892 #, c-format msgid "Fetching %s\n" msgstr "æ£åœ¨èŽ·å– %s\n" -#: builtin/fetch.c:890 builtin/remote.c:100 +#: builtin/fetch.c:894 builtin/remote.c:100 #, c-format msgid "Could not fetch %s" msgstr "ä¸èƒ½èŽ·å– %s" -#: builtin/fetch.c:907 +#: builtin/fetch.c:913 msgid "" "No remote repository specified. Please, specify either a URL or a\n" "remote name from which new revisions should be fetched." msgstr "未指定远程版本库。请通过一个URLæˆ–è¿œç¨‹ç‰ˆæœ¬åº“åæŒ‡å®šï¼Œç”¨ä»¥èŽ·å–æ–°æäº¤ã€‚" -#: builtin/fetch.c:927 +#: builtin/fetch.c:933 msgid "You need to specify a tag name." msgstr "æ‚¨éœ€è¦æŒ‡å®šä¸€ä¸ª tag å称。" -#: builtin/fetch.c:979 +#: builtin/fetch.c:985 msgid "fetch --all does not take a repository argument" msgstr "fetch --all ä¸èƒ½å¸¦ä¸€ä¸ªç‰ˆæœ¬åº“傿•°" -#: builtin/fetch.c:981 +#: builtin/fetch.c:987 msgid "fetch --all does not make sense with refspecs" msgstr "fetch --all å¸¦å¼•ç”¨è¡¨è¾¾å¼æ²¡æœ‰ä»»ä½•æ„义" -#: builtin/fetch.c:992 +#: builtin/fetch.c:998 #, c-format msgid "No such remote or remote group: %s" msgstr "æ²¡æœ‰è¿™æ ·çš„è¿œç¨‹æˆ–è¿œç¨‹ç»„ï¼š%s" -#: builtin/fetch.c:1000 +#: builtin/fetch.c:1006 msgid "Fetching a group and specifying refspecs does not make sense" msgstr "获å–ç»„å¹¶æŒ‡å®šå¼•ç”¨è¡¨è¾¾å¼æ²¡æœ‰æ„义" +#: builtin/fmt-merge-msg.c:13 +msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]" +msgstr "" + +#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:786 +#: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:192 +#: builtin/tag.c:448 parse-options.h:133 parse-options.h:235 +msgid "n" +msgstr "æ•°å—" + +#: builtin/fmt-merge-msg.c:654 +msgid "populate log with at most <n> entries from shortlog" +msgstr "" + +#: builtin/fmt-merge-msg.c:657 +msgid "alias for --log (deprecated)" +msgstr "" + +#: builtin/fmt-merge-msg.c:660 +msgid "text" +msgstr "" + +#: builtin/fmt-merge-msg.c:661 +msgid "use <text> as start of message" +msgstr "" + +#: builtin/fmt-merge-msg.c:662 +#, fuzzy +msgid "file to read from" +msgstr "ä¸èƒ½è¯» %s" + +#: builtin/for-each-ref.c:979 +#, fuzzy +msgid "git for-each-ref [options] [<pattern>]" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/for-each-ref.c:994 +msgid "quote placeholders suitably for shells" +msgstr "" + +#: builtin/for-each-ref.c:996 +msgid "quote placeholders suitably for perl" +msgstr "" + +#: builtin/for-each-ref.c:998 +msgid "quote placeholders suitably for python" +msgstr "" + +#: builtin/for-each-ref.c:1000 +msgid "quote placeholders suitably for tcl" +msgstr "" + +#: builtin/for-each-ref.c:1003 +msgid "show only <n> matched refs" +msgstr "" + +#: builtin/for-each-ref.c:1004 +msgid "format" +msgstr "" + +#: builtin/for-each-ref.c:1004 +msgid "format to use for the output" +msgstr "" + +#: builtin/for-each-ref.c:1005 +msgid "key" +msgstr "" + +#: builtin/for-each-ref.c:1006 +msgid "field name to sort on" +msgstr "" + +#: builtin/fsck.c:608 +#, fuzzy +msgid "git fsck [options] [<object>...]" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/fsck.c:614 +msgid "show unreachable objects" +msgstr "" + +#: builtin/fsck.c:615 +#, fuzzy +msgid "show dangling objects" +msgstr "索引对象ä¸" + +#: builtin/fsck.c:616 +msgid "report tags" +msgstr "" + +#: builtin/fsck.c:617 +msgid "report root nodes" +msgstr "" + +#: builtin/fsck.c:618 +msgid "make index objects head nodes" +msgstr "" + +#: builtin/fsck.c:619 +msgid "make reflogs head nodes (default)" +msgstr "" + +#: builtin/fsck.c:620 +msgid "also consider packs and alternate objects" +msgstr "" + +#: builtin/fsck.c:621 +msgid "enable more strict checking" +msgstr "" + +#: builtin/fsck.c:623 +msgid "write dangling objects in .git/lost-found" +msgstr "" + +#: builtin/fsck.c:624 builtin/prune.c:134 +msgid "show progress" +msgstr "" + +#: builtin/gc.c:22 +msgid "git gc [options]" +msgstr "" + #: builtin/gc.c:63 #, c-format msgid "Invalid %s: '%s'" @@ -2744,6 +4535,18 @@ msgstr "æ— æ•ˆçš„ %s:'%s'" msgid "insanely long object directory %.*s" msgstr "䏿£å¸¸çš„长对象目录 %.*s" +#: builtin/gc.c:179 +msgid "prune unreferenced objects" +msgstr "" + +#: builtin/gc.c:181 +msgid "be more thorough (increased runtime)" +msgstr "" + +#: builtin/gc.c:182 +msgid "enable auto-gc mode" +msgstr "" + #: builtin/gc.c:221 #, c-format msgid "Auto packing the repository for optimum performance.\n" @@ -2763,89 +4566,317 @@ msgid "" "There are too many unreachable loose objects; run 'git prune' to remove them." msgstr "有太多ä¸å¯è¾¾çš„æ¾æ•£å¯¹è±¡ï¼Œè¿è¡Œ 'git prune' åˆ é™¤å®ƒä»¬ã€‚" +#: builtin/grep.c:22 +msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]" +msgstr "" + #: builtin/grep.c:216 #, c-format msgid "grep: failed to create thread: %s" msgstr "grepï¼šæ— æ³•åˆ›å»ºçº¿ç¨‹ï¼š%s" -#: builtin/grep.c:402 +#: builtin/grep.c:454 #, c-format msgid "Failed to chdir: %s" msgstr "æ— æ³•åˆ‡æ¢ç›®å½•:%s" -#: builtin/grep.c:478 builtin/grep.c:512 +#: builtin/grep.c:530 builtin/grep.c:564 #, c-format msgid "unable to read tree (%s)" msgstr "æ— æ³•è¯»å–æ ‘(%s)" -#: builtin/grep.c:526 +#: builtin/grep.c:578 #, c-format msgid "unable to grep from object of type %s" msgstr "æ— æ³•æŠ“å–æ¥è‡ªäºŽ %s 类型的对象" -#: builtin/grep.c:584 +#: builtin/grep.c:636 #, c-format msgid "switch `%c' expects a numerical value" msgstr "开关 `%c' 期望一个数å—值" -#: builtin/grep.c:601 +#: builtin/grep.c:653 #, c-format msgid "cannot open '%s'" msgstr "ä¸èƒ½æ‰“å¼€ '%s'" -#: builtin/grep.c:885 +#: builtin/grep.c:728 +msgid "search in index instead of in the work tree" +msgstr "" + +#: builtin/grep.c:730 +msgid "find in contents not managed by git" +msgstr "" + +# è¯‘è€…ï¼šä¸æ–‡å—符串拼接,å¯åˆ 除å‰å¯¼ç©ºæ ¼ +#: builtin/grep.c:732 +#, fuzzy +msgid "search in both tracked and untracked files" +msgstr "(使用 -u 傿•°æ˜¾ç¤ºæœªè·Ÿè¸ªçš„æ–‡ä»¶ï¼‰" + +#: builtin/grep.c:734 +msgid "search also in ignored files" +msgstr "" + +#: builtin/grep.c:737 +msgid "show non-matching lines" +msgstr "" + +#: builtin/grep.c:739 +msgid "case insensitive matching" +msgstr "" + +#: builtin/grep.c:741 +msgid "match patterns only at word boundaries" +msgstr "" + +#: builtin/grep.c:743 +msgid "process binary files as text" +msgstr "" + +#: builtin/grep.c:745 +msgid "don't match patterns in binary files" +msgstr "" + +#: builtin/grep.c:748 +msgid "descend at most <depth> levels" +msgstr "" + +#: builtin/grep.c:752 +msgid "use extended POSIX regular expressions" +msgstr "" + +#: builtin/grep.c:755 +msgid "use basic POSIX regular expressions (default)" +msgstr "" + +#: builtin/grep.c:758 +msgid "interpret patterns as fixed strings" +msgstr "" + +#: builtin/grep.c:761 +msgid "use Perl-compatible regular expressions" +msgstr "" + +#: builtin/grep.c:764 +msgid "show line numbers" +msgstr "" + +#: builtin/grep.c:765 +msgid "don't show filenames" +msgstr "" + +#: builtin/grep.c:766 +#, fuzzy +msgid "show filenames" +msgstr "%s文件:" + +#: builtin/grep.c:768 +msgid "show filenames relative to top directory" +msgstr "" + +#: builtin/grep.c:770 +msgid "show only filenames instead of matching lines" +msgstr "" + +#: builtin/grep.c:772 +msgid "synonym for --files-with-matches" +msgstr "" + +#: builtin/grep.c:775 +msgid "show only the names of files without match" +msgstr "" + +#: builtin/grep.c:777 +#, fuzzy +msgid "print NUL after filenames" +msgstr "为所有文件å剿·»åŠ <æ ¹ç›®å½•>" + +#: builtin/grep.c:779 +msgid "show the number of matches instead of matching lines" +msgstr "" + +#: builtin/grep.c:780 +msgid "highlight matches" +msgstr "" + +#: builtin/grep.c:782 +msgid "print empty line between matches from different files" +msgstr "" + +#: builtin/grep.c:784 +msgid "show filename only once above matches from same file" +msgstr "" + +#: builtin/grep.c:787 +msgid "show <n> context lines before and after matches" +msgstr "" + +#: builtin/grep.c:790 +msgid "show <n> context lines before matches" +msgstr "" + +#: builtin/grep.c:792 +msgid "show <n> context lines after matches" +msgstr "" + +#: builtin/grep.c:793 +msgid "shortcut for -C NUM" +msgstr "" + +#: builtin/grep.c:796 +msgid "show a line with the function name before matches" +msgstr "" + +#: builtin/grep.c:798 +msgid "show the surrounding function" +msgstr "" + +#: builtin/grep.c:801 +msgid "read patterns from file" +msgstr "" + +#: builtin/grep.c:803 +msgid "match <pattern>" +msgstr "" + +#: builtin/grep.c:805 +msgid "combine patterns specified with -e" +msgstr "" + +#: builtin/grep.c:817 +msgid "indicate hit with exit status without output" +msgstr "" + +#: builtin/grep.c:819 +msgid "show only matches from files that match all patterns" +msgstr "" + +#: builtin/grep.c:822 +msgid "pager" +msgstr "" + +#: builtin/grep.c:822 +msgid "show matching files in the pager" +msgstr "" + +#: builtin/grep.c:825 +msgid "allow calling of grep(1) (ignored by this build)" +msgstr "" + +#: builtin/grep.c:826 builtin/show-ref.c:201 +msgid "show usage" +msgstr "" + +#: builtin/grep.c:917 msgid "no pattern given." msgstr "未æä¾›æ¨¡å¼åŒ¹é…。" -#: builtin/grep.c:899 +#: builtin/grep.c:931 #, c-format msgid "bad object %s" msgstr "å对象 %s" -#: builtin/grep.c:940 +#: builtin/grep.c:972 msgid "--open-files-in-pager only works on the worktree" msgstr "--open-files-in-pager 仅用于工作区" -#: builtin/grep.c:963 +#: builtin/grep.c:995 msgid "--cached or --untracked cannot be used with --no-index." -msgstr "--cached 或 --untracked ä¸èƒ½ä¸Ž --no-index 共用。" +msgstr "--cached 或 --untracked ä¸èƒ½ä¸Ž --no-index åŒæ—¶ä½¿ç”¨ã€‚" -#: builtin/grep.c:968 +#: builtin/grep.c:1000 msgid "--no-index or --untracked cannot be used with revs." -msgstr "--no-index 或 --untracked ä¸èƒ½å’Œç‰ˆæœ¬å…±ç”¨ã€‚" +msgstr "--no-index 或 --untracked ä¸èƒ½å’Œç‰ˆæœ¬åŒæ—¶ä½¿ç”¨ã€‚" -#: builtin/grep.c:971 +#: builtin/grep.c:1003 msgid "--[no-]exclude-standard cannot be used for tracked contents." msgstr "--[no-]exclude-standard ä¸èƒ½ç”¨äºŽå·²è·Ÿè¸ªå†…容。" -#: builtin/grep.c:979 +#: builtin/grep.c:1011 msgid "both --cached and trees are given." msgstr "åŒæ—¶ç»™å‡ºäº† --cached å’Œæ ‘å¯¹è±¡ã€‚" -#: builtin/help.c:59 +#: builtin/hash-object.c:60 +msgid "" +"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] " +"<file>..." +msgstr "" + +#: builtin/hash-object.c:61 +msgid "git hash-object --stdin-paths < <list-of-paths>" +msgstr "" + +#: builtin/hash-object.c:72 +msgid "type" +msgstr "" + +#: builtin/hash-object.c:72 +#, fuzzy +msgid "object type" +msgstr "å的对象类型。" + +#: builtin/hash-object.c:73 +msgid "write the object into the object database" +msgstr "" + +#: builtin/hash-object.c:74 +msgid "read the object from stdin" +msgstr "" + +#: builtin/hash-object.c:76 +msgid "store file as is without filters" +msgstr "" + +#: builtin/hash-object.c:77 +msgid "process file as it were from this path" +msgstr "" + +#: builtin/help.c:43 +#, fuzzy +msgid "print all available commands" +msgstr "在 '%s' 下å¯ç”¨çš„ git 命令" + +#: builtin/help.c:44 +msgid "show man page" +msgstr "" + +#: builtin/help.c:45 +msgid "show manual in web browser" +msgstr "" + +#: builtin/help.c:47 +msgid "show info page" +msgstr "" + +#: builtin/help.c:53 +msgid "git help [--all] [--man|--web|--info] [command]" +msgstr "" + +#: builtin/help.c:65 #, c-format msgid "unrecognized help format '%s'" msgstr "æœªèƒ½è¯†åˆ«çš„å¸®åŠ©æ ¼å¼ '%s'" -#: builtin/help.c:87 +#: builtin/help.c:93 msgid "Failed to start emacsclient." msgstr "æ— æ³•å¯åЍ emacsclient。" -#: builtin/help.c:100 +#: builtin/help.c:106 msgid "Failed to parse emacsclient version." msgstr "æ— æ³•è§£æž emacsclient 版本。" -#: builtin/help.c:108 +#: builtin/help.c:114 #, c-format msgid "emacsclient version '%d' too old (< 22)." msgstr "emacsclient 版本 '%d' å¤ªè€ (< 22)。" -#: builtin/help.c:126 builtin/help.c:154 builtin/help.c:163 builtin/help.c:171 +#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177 #, c-format msgid "failed to exec '%s': %s" msgstr "æ— æ³•æ‰§è¡Œ '%s':%s" -#: builtin/help.c:211 +#: builtin/help.c:217 #, c-format msgid "" "'%s': path for unsupported man viewer.\n" @@ -2854,7 +4885,7 @@ msgstr "" "'%s'ï¼šä¸æ”¯æŒçš„ man 手册查看器的路径。\n" "请使用 'man.<tool>.cmd'。" -#: builtin/help.c:223 +#: builtin/help.c:229 #, c-format msgid "" "'%s': cmd for supported man viewer.\n" @@ -2863,266 +4894,307 @@ msgstr "" "'%s': 支æŒçš„ man 手册查看器命令。\n" "请使用 'man.<tool>.path'。" -#: builtin/help.c:287 +#: builtin/help.c:299 msgid "The most commonly used git commands are:" msgstr "最常用的 git 命令有:" -#: builtin/help.c:355 +#: builtin/help.c:367 #, c-format msgid "'%s': unknown man viewer." msgstr "'%s':未知的 man 查看器。" -#: builtin/help.c:372 +#: builtin/help.c:384 msgid "no man viewer handled the request" msgstr "没有 man æŸ¥çœ‹å™¨å¤„ç†æ¤è¯·æ±‚" -#: builtin/help.c:380 +#: builtin/help.c:392 msgid "no info viewer handled the request" msgstr "没有 info æŸ¥çœ‹å™¨å¤„ç†æ¤è¯·æ±‚" -#: builtin/help.c:391 -#, c-format -msgid "'%s': not a documentation directory." -msgstr "'%s'ï¼šä¸æ˜¯ä¸€ä¸ªæ–‡æ¡£ç›®å½•。" - -#: builtin/help.c:432 builtin/help.c:439 +#: builtin/help.c:447 builtin/help.c:454 #, c-format msgid "usage: %s%s" msgstr "用法:%s%s" -#: builtin/help.c:453 +#: builtin/help.c:470 #, c-format msgid "`git %s' is aliased to `%s'" msgstr "`git %s' 是 `%s' 的别å" -#: builtin/index-pack.c:169 +#: builtin/index-pack.c:170 #, c-format msgid "object type mismatch at %s" msgstr "%s 的对象类型ä¸åŒ¹é…" -#: builtin/index-pack.c:189 +#: builtin/index-pack.c:190 msgid "object of unexpected type" msgstr "æ„外的类型的对象" -#: builtin/index-pack.c:226 +#: builtin/index-pack.c:227 #, c-format msgid "cannot fill %d byte" msgid_plural "cannot fill %d bytes" msgstr[0] "æ— æ³•å¡«å…… %d å—节" msgstr[1] "æ— æ³•å¡«å…… %d å—节" -#: builtin/index-pack.c:236 +#: builtin/index-pack.c:237 msgid "early EOF" msgstr "过早的文件结æŸç¬¦ï¼ˆEOF)" -#: builtin/index-pack.c:237 +#: builtin/index-pack.c:238 msgid "read error on input" msgstr "输入上的读错误" -#: builtin/index-pack.c:249 +#: builtin/index-pack.c:250 msgid "used more bytes than were available" msgstr "用掉了超过å¯ç”¨çš„å—节" -#: builtin/index-pack.c:256 +#: builtin/index-pack.c:257 msgid "pack too large for current definition of off_t" msgstr "åŒ…å¤ªå¤§è¶…è¿‡äº†å½“å‰ off_t 的定义" -#: builtin/index-pack.c:272 +#: builtin/index-pack.c:273 #, c-format msgid "unable to create '%s'" msgstr "ä¸èƒ½åˆ›å»º '%s'" -#: builtin/index-pack.c:277 +#: builtin/index-pack.c:278 #, c-format msgid "cannot open packfile '%s'" msgstr "æ— æ³•æ‰“å¼€åŒ…æ–‡ä»¶ '%s'" -#: builtin/index-pack.c:291 +#: builtin/index-pack.c:292 msgid "pack signature mismatch" msgstr "包ç¾åä¸åŒ¹é…" -#: builtin/index-pack.c:311 +#: builtin/index-pack.c:294 +#, c-format +msgid "pack version %<PRIu32> unsupported" +msgstr "" + +#: builtin/index-pack.c:312 #, c-format msgid "pack has bad object at offset %lu: %s" msgstr "åŒ…ä¸æœ‰é”™è¯¯çš„对象ä½äºŽ %lu:%s" -#: builtin/index-pack.c:405 +#: builtin/index-pack.c:434 #, c-format msgid "inflate returned %d" msgstr "解压缩返回 %d" -#: builtin/index-pack.c:450 +#: builtin/index-pack.c:483 msgid "offset value overflow for delta base object" msgstr "å移值覆盖了 delta 基准对象" -#: builtin/index-pack.c:458 +#: builtin/index-pack.c:491 msgid "delta base offset is out of bound" msgstr "delta 基准å移越界" -#: builtin/index-pack.c:466 +#: builtin/index-pack.c:499 #, c-format msgid "unknown object type %d" msgstr "未知对象类型 %d" -#: builtin/index-pack.c:495 +#: builtin/index-pack.c:530 msgid "cannot pread pack file" msgstr "æ— æ³•è¯»å–包文件" -#: builtin/index-pack.c:497 +#: builtin/index-pack.c:532 #, c-format msgid "premature end of pack file, %lu byte missing" msgid_plural "premature end of pack file, %lu bytes missing" msgstr[0] "包文件过早结æŸï¼Œç¼ºå°‘ %lu å—节" msgstr[1] "包文件过早结æŸï¼Œç¼ºå°‘ %lu å—节" -#: builtin/index-pack.c:510 +#: builtin/index-pack.c:558 msgid "serious inflate inconsistency" msgstr "解压缩严é‡çš„ä¸ä¸€è‡´" -#: builtin/index-pack.c:583 -#, c-format -msgid "cannot read existing object %s" -msgstr "ä¸èƒ½è¯»å–现å˜å¯¹è±¡ %s" - -#: builtin/index-pack.c:586 +#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678 +#: builtin/index-pack.c:712 builtin/index-pack.c:721 #, c-format msgid "SHA1 COLLISION FOUND WITH %s !" msgstr "å‘现 %s 出现 SHA1 冲çªï¼" -#: builtin/index-pack.c:598 +#: builtin/index-pack.c:652 builtin/pack-objects.c:170 +#: builtin/pack-objects.c:262 +#, c-format +msgid "unable to read %s" +msgstr "ä¸èƒ½è¯» %s" + +#: builtin/index-pack.c:718 +#, c-format +msgid "cannot read existing object %s" +msgstr "ä¸èƒ½è¯»å–现å˜å¯¹è±¡ %s" + +#: builtin/index-pack.c:732 #, c-format msgid "invalid blob object %s" -msgstr "æ— æ•ˆçš„ blob 对象 %s" +msgstr "æ— æ•ˆçš„äºŒè¿›åˆ¶å¯¹è±¡ï¼ˆblob)%s" -#: builtin/index-pack.c:610 +#: builtin/index-pack.c:747 #, c-format msgid "invalid %s" msgstr "æ— æ•ˆçš„ %s" -#: builtin/index-pack.c:612 +#: builtin/index-pack.c:749 msgid "Error in object" msgstr "对象ä¸å‡ºé”™" -#: builtin/index-pack.c:614 +#: builtin/index-pack.c:751 #, c-format msgid "Not all child objects of %s are reachable" msgstr "%s 的所有å对象并éžéƒ½å¯è¾¾" -#: builtin/index-pack.c:687 builtin/index-pack.c:713 +#: builtin/index-pack.c:821 builtin/index-pack.c:847 msgid "failed to apply delta" msgstr "æ— æ³•åº”ç”¨ delta" -#: builtin/index-pack.c:850 +#: builtin/index-pack.c:986 msgid "Receiving objects" msgstr "接收对象ä¸" -#: builtin/index-pack.c:850 +#: builtin/index-pack.c:986 msgid "Indexing objects" msgstr "索引对象ä¸" -#: builtin/index-pack.c:872 +#: builtin/index-pack.c:1012 msgid "pack is corrupted (SHA1 mismatch)" msgstr "包冲çªï¼ˆSHA1 ä¸åŒ¹é…)" -#: builtin/index-pack.c:877 +#: builtin/index-pack.c:1017 msgid "cannot fstat packfile" msgstr "ä¸èƒ½æžšä¸¾åŒ…文件状æ€" -#: builtin/index-pack.c:880 +#: builtin/index-pack.c:1020 msgid "pack has junk at the end" msgstr "包的结尾有垃圾数æ®" -#: builtin/index-pack.c:903 +#: builtin/index-pack.c:1031 +msgid "confusion beyond insanity in parse_pack_objects()" +msgstr "parse_pack_objects() ä¸é‡åˆ°ä¸å¯ç†å–»çš„问题" + +#: builtin/index-pack.c:1054 msgid "Resolving deltas" msgstr "å¤„ç† delta ä¸" -#: builtin/index-pack.c:954 +#: builtin/index-pack.c:1064 +#, fuzzy, c-format +msgid "unable to create thread: %s" +msgstr "grepï¼šæ— æ³•åˆ›å»ºçº¿ç¨‹ï¼š%s" + +#: builtin/index-pack.c:1106 msgid "confusion beyond insanity" msgstr "ä¸å¯ç†å–»" -#: builtin/index-pack.c:973 +#: builtin/index-pack.c:1112 +#, c-format +msgid "completed with %d local objects" +msgstr "" + +#: builtin/index-pack.c:1121 +#, c-format +msgid "Unexpected tail checksum for %s (disk corruption?)" +msgstr "" + +#: builtin/index-pack.c:1125 #, c-format msgid "pack has %d unresolved delta" msgid_plural "pack has %d unresolved deltas" msgstr[0] "包有 %d 个未解决的 delta" msgstr[1] "包有 %d 个未解决的 delta" -#: builtin/index-pack.c:998 +#: builtin/index-pack.c:1150 #, c-format msgid "unable to deflate appended object (%d)" msgstr "ä¸èƒ½ç¼©å°é™„åŠ å¯¹è±¡ï¼ˆ%d)" -#: builtin/index-pack.c:1077 +#: builtin/index-pack.c:1229 #, c-format msgid "local object %s is corrupt" msgstr "本地对象 %s å·²æŸå" -#: builtin/index-pack.c:1101 +#: builtin/index-pack.c:1253 msgid "error while closing pack file" msgstr "å…³é—包文件时出错" -#: builtin/index-pack.c:1114 +#: builtin/index-pack.c:1266 #, c-format msgid "cannot write keep file '%s'" msgstr "æ— æ³•å†™ä¿ç•™æ–‡ä»¶ '%s'" -#: builtin/index-pack.c:1122 +#: builtin/index-pack.c:1274 #, c-format msgid "cannot close written keep file '%s'" msgstr "æ— æ³•å…³é—ä¿ç•™æ–‡ä»¶ '%s'" -#: builtin/index-pack.c:1135 +#: builtin/index-pack.c:1287 msgid "cannot store pack file" msgstr "æ— æ³•å˜å‚¨åŒ…文件" -#: builtin/index-pack.c:1146 +#: builtin/index-pack.c:1298 msgid "cannot store index file" msgstr "æ— æ³•å˜å‚¨ç´¢å¼•文件" -#: builtin/index-pack.c:1247 +#: builtin/index-pack.c:1331 +#, fuzzy, c-format +msgid "bad pack.indexversion=%<PRIu32>" +msgstr "å的索引版本 '%s'" + +#: builtin/index-pack.c:1337 +#, c-format +msgid "invalid number of threads specified (%d)" +msgstr "" + +#: builtin/index-pack.c:1341 builtin/index-pack.c:1514 +#, c-format +msgid "no threads support, ignoring %s" +msgstr "" + +#: builtin/index-pack.c:1399 #, c-format msgid "Cannot open existing pack file '%s'" msgstr "æ— æ³•æ‰“å¼€çŽ°å˜åŒ…文件 '%s'" -#: builtin/index-pack.c:1249 +#: builtin/index-pack.c:1401 #, c-format msgid "Cannot open existing pack idx file for '%s'" msgstr "æ— æ³•ä¸º %s 打开包索引文件" -#: builtin/index-pack.c:1296 +#: builtin/index-pack.c:1448 #, c-format msgid "non delta: %d object" msgid_plural "non delta: %d objects" msgstr[0] "éž delta:%d 个对象" msgstr[1] "éž delta:%d 个对象" -#: builtin/index-pack.c:1303 +#: builtin/index-pack.c:1455 #, c-format msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" msgstr[0] "链长 = %d: %lu 对象" msgstr[1] "链长 = %d: %lu 对象" -#: builtin/index-pack.c:1330 +#: builtin/index-pack.c:1482 msgid "Cannot come back to cwd" msgstr "æ— æ³•è¿”å›žå½“å‰å·¥ä½œç›®å½•" -#: builtin/index-pack.c:1374 builtin/index-pack.c:1377 -#: builtin/index-pack.c:1389 builtin/index-pack.c:1393 +#: builtin/index-pack.c:1526 builtin/index-pack.c:1529 +#: builtin/index-pack.c:1541 builtin/index-pack.c:1545 #, c-format msgid "bad %s" msgstr "错误选项 %s" -#: builtin/index-pack.c:1407 +#: builtin/index-pack.c:1559 msgid "--fix-thin cannot be used without --stdin" -msgstr "--fix-thin ä¸èƒ½å’Œ --stdin 共用" +msgstr "--fix-thin ä¸èƒ½å’Œ --stdin åŒæ—¶ä½¿ç”¨" -#: builtin/index-pack.c:1411 builtin/index-pack.c:1421 +#: builtin/index-pack.c:1563 builtin/index-pack.c:1573 #, c-format msgid "packfile name '%s' does not end with '.pack'" msgstr "包å '%s' 没有以 '.pack' 结尾" -#: builtin/index-pack.c:1430 +#: builtin/index-pack.c:1582 msgid "--verify with no packfile name given" msgstr "--verify 没有æä¾›åŒ…å傿•°" @@ -3196,22 +5268,22 @@ msgstr "没有从 '%2$s' å¤åˆ¶å¸¦æœ‰é”™è¯¯ç‰ˆæœ¬ %1$d 的模版" msgid "insane git directory %s" msgstr "䏿£å¸¸çš„ git 目录 %s" -#: builtin/init-db.c:322 builtin/init-db.c:325 +#: builtin/init-db.c:323 builtin/init-db.c:326 #, c-format msgid "%s already exists" msgstr "%s å·²ç»å˜åœ¨" -#: builtin/init-db.c:354 +#: builtin/init-db.c:355 #, c-format msgid "unable to handle file type %d" msgstr "ä¸èƒ½å¤„ç† %d 类型的文件" -#: builtin/init-db.c:357 +#: builtin/init-db.c:358 #, c-format msgid "unable to move %s to %s" msgstr "ä¸èƒ½ç§»åЍ %s 至 %s" -#: builtin/init-db.c:362 +#: builtin/init-db.c:363 #, c-format msgid "Could not create git link %s" msgstr "ä¸èƒ½åˆ›å»º git link %s" @@ -3221,39 +5293,58 @@ msgstr "ä¸èƒ½åˆ›å»º git link %s" #. * existing" or "Initialized empty", the second " shared" or #. * "", and the last '%s%s' is the verbatim directory name. #. -#: builtin/init-db.c:419 +#: builtin/init-db.c:420 #, c-format msgid "%s%s Git repository in %s%s\n" msgstr "%s%s Git 版本库于 %s%s\n" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Reinitialized existing" msgstr "釿–°åˆå§‹åŒ–现å˜çš„" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Initialized empty" msgstr "åˆå§‹åŒ–空的" # è¯‘è€…ï¼šä¸æ–‡å—符串拼接,å¯åˆ 除å‰å¯¼ç©ºæ ¼ -#: builtin/init-db.c:421 +#: builtin/init-db.c:422 msgid " shared" msgstr "共享" -#: builtin/init-db.c:440 +#: builtin/init-db.c:441 msgid "cannot tell cwd" msgstr "æ— æ³•èŽ·çŸ¥å½“å‰è·¯å¾„" -#: builtin/init-db.c:521 builtin/init-db.c:528 +#: builtin/init-db.c:467 +msgid "" +"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared" +"[=<permissions>]] [directory]" +msgstr "" + +#: builtin/init-db.c:490 +msgid "permissions" +msgstr "" + +#: builtin/init-db.c:491 +msgid "specify that the git repository is to be shared amongst several users" +msgstr "" + +#: builtin/init-db.c:493 builtin/prune-packed.c:77 +#, fuzzy +msgid "be quiet" +msgstr "æ›´åŠ å®‰é™" + +#: builtin/init-db.c:522 builtin/init-db.c:529 #, c-format msgid "cannot mkdir %s" msgstr "ä¸èƒ½åˆ›å»ºç›®å½• %s" -#: builtin/init-db.c:532 +#: builtin/init-db.c:533 #, c-format msgid "cannot chdir to %s" msgstr "ä¸èƒ½åˆ‡æ¢ç›®å½•到 %s" -#: builtin/init-db.c:554 +#: builtin/init-db.c:555 #, c-format msgid "" "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" @@ -3262,113 +5353,413 @@ msgstr "" "ä¸å…许 %s(或 --work-tree=<directory>)而没有指定 %s(或 --git-" "dir=<directory>)" -#: builtin/init-db.c:578 +#: builtin/init-db.c:579 msgid "Cannot access current working directory" msgstr "ä¸èƒ½è®¿é—®å½“å‰å·¥ä½œç›®å½•" -#: builtin/init-db.c:585 +#: builtin/init-db.c:586 #, c-format msgid "Cannot access work tree '%s'" msgstr "ä¸èƒ½è®¿é—®å·¥ä½œåŒº '%s'" -#: builtin/log.c:188 +#: builtin/log.c:37 +#, fuzzy +msgid "git log [<options>] [<since>..<until>] [[--] <path>...]\n" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/log.c:38 +#, fuzzy +msgid " or: git show [options] <object>..." +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/log.c:100 +msgid "suppress diff output" +msgstr "" + +#: builtin/log.c:101 +#, fuzzy +msgid "show source" +msgstr "åçš„æº" + +#: builtin/log.c:102 +msgid "decorate options" +msgstr "" + +#: builtin/log.c:189 #, c-format msgid "Final output: %d %s\n" msgstr "最终输出:%d %s\n" -#: builtin/log.c:401 builtin/log.c:489 +#: builtin/log.c:403 builtin/log.c:494 #, c-format msgid "Could not read object %s" msgstr "ä¸èƒ½è¯»å–对象 %s" -#: builtin/log.c:513 +#: builtin/log.c:518 #, c-format msgid "Unknown type: %d" msgstr "未知类型:%d" -#: builtin/log.c:602 +#: builtin/log.c:608 msgid "format.headers without value" msgstr "format.headers 没有值" -#: builtin/log.c:676 +#: builtin/log.c:682 msgid "name of output directory is too long" msgstr "输出目录å太长" -#: builtin/log.c:687 +#: builtin/log.c:693 #, c-format msgid "Cannot open patch file %s" msgstr "æ— æ³•æ‰“å¼€è¡¥ä¸æ–‡ä»¶ %s" -#: builtin/log.c:701 +#: builtin/log.c:707 msgid "Need exactly one range." msgstr "åªéœ€è¦ä¸€ä¸ªèŒƒå›´ã€‚" -#: builtin/log.c:709 +#: builtin/log.c:715 msgid "Not a range." msgstr "䏿˜¯ä¸€ä¸ªèŒƒå›´ã€‚" -#: builtin/log.c:786 +#: builtin/log.c:789 msgid "Cover letter needs email format" msgstr "ä¿¡å°éœ€è¦é‚®ä»¶åœ°å€æ ¼å¼" -#: builtin/log.c:859 +#: builtin/log.c:862 #, c-format msgid "insane in-reply-to: %s" msgstr "䏿£å¸¸çš„ in-reply-to:%s" -#: builtin/log.c:932 +#: builtin/log.c:890 +msgid "git format-patch [options] [<since> | <revision range>]" +msgstr "" + +#: builtin/log.c:935 msgid "Two output directories?" msgstr "两个输出目录?" -#: builtin/log.c:1153 +#: builtin/log.c:1063 +msgid "use [PATCH n/m] even with a single patch" +msgstr "" + +#: builtin/log.c:1066 +msgid "use [PATCH] even with multiple patches" +msgstr "" + +#: builtin/log.c:1070 +msgid "print patches to standard out" +msgstr "" + +#: builtin/log.c:1072 +msgid "generate a cover letter" +msgstr "" + +#: builtin/log.c:1074 +msgid "use simple number sequence for output file names" +msgstr "" + +#: builtin/log.c:1075 +msgid "sfx" +msgstr "" + +#: builtin/log.c:1076 +msgid "use <sfx> instead of '.patch'" +msgstr "" + +#: builtin/log.c:1078 +msgid "start numbering patches at <n> instead of 1" +msgstr "" + +#: builtin/log.c:1080 +msgid "Use [<prefix>] instead of [PATCH]" +msgstr "" + +#: builtin/log.c:1083 +msgid "store resulting files in <dir>" +msgstr "" + +#: builtin/log.c:1086 +msgid "don't strip/add [PATCH]" +msgstr "" + +#: builtin/log.c:1089 +msgid "don't output binary diffs" +msgstr "" + +#: builtin/log.c:1091 +msgid "don't include a patch matching a commit upstream" +msgstr "" + +#: builtin/log.c:1093 +msgid "show patch format instead of default (patch + stat)" +msgstr "" + +#: builtin/log.c:1095 +#, fuzzy +msgid "Messaging" +msgstr "åˆå¹¶ï¼š" + +# 译者:注æ„ä¿æŒå¥å°¾ç©ºæ ¼ +#: builtin/log.c:1096 +#, fuzzy +msgid "header" +msgstr "领先 " + +#: builtin/log.c:1097 +msgid "add email header" +msgstr "" + +#: builtin/log.c:1098 builtin/log.c:1100 +msgid "email" +msgstr "" + +#: builtin/log.c:1098 +msgid "add To: header" +msgstr "" + +#: builtin/log.c:1100 +msgid "add Cc: header" +msgstr "" + +#: builtin/log.c:1102 +msgid "message-id" +msgstr "" + +#: builtin/log.c:1103 +msgid "make first mail a reply to <message-id>" +msgstr "" + +#: builtin/log.c:1104 builtin/log.c:1107 +msgid "boundary" +msgstr "" + +#: builtin/log.c:1105 +msgid "attach the patch" +msgstr "" + +#: builtin/log.c:1108 +#, fuzzy +msgid "inline the patch" +msgstr "忽略补ä¸ä¸çš„æ·»åŠ çš„æ–‡ä»¶" + +#: builtin/log.c:1112 +msgid "enable message threading, styles: shallow, deep" +msgstr "" + +#: builtin/log.c:1114 +msgid "signature" +msgstr "" + +#: builtin/log.c:1115 +msgid "add a signature" +msgstr "" + +#: builtin/log.c:1117 +#, fuzzy +msgid "don't print the patch filenames" +msgstr "æ— æ³•æ‰“å¼€è¡¥ä¸æ–‡ä»¶ %s" + +#: builtin/log.c:1157 #, c-format msgid "bogus committer info %s" msgstr "虚å‡çš„æäº¤è€…ä¿¡æ¯ %s" -#: builtin/log.c:1198 +#: builtin/log.c:1202 msgid "-n and -k are mutually exclusive." msgstr "-n å’Œ -k 互斥。" -#: builtin/log.c:1200 +#: builtin/log.c:1204 msgid "--subject-prefix and -k are mutually exclusive." msgstr "--subject-prefix å’Œ -k 互斥。" -#: builtin/log.c:1208 +#: builtin/log.c:1212 msgid "--name-only does not make sense" msgstr "--name-only æ— æ„义" -#: builtin/log.c:1210 +#: builtin/log.c:1214 msgid "--name-status does not make sense" msgstr "--name-status æ— æ„义" -#: builtin/log.c:1212 +#: builtin/log.c:1216 msgid "--check does not make sense" msgstr "--check æ— æ„义" -#: builtin/log.c:1235 +#: builtin/log.c:1239 msgid "standard output, or directory, which one?" msgstr "æ ‡å‡†è¾“å‡ºæˆ–ç›®å½•ï¼Œå“ªä¸€ä¸ªï¼Ÿ" -#: builtin/log.c:1237 +#: builtin/log.c:1241 #, c-format msgid "Could not create directory '%s'" msgstr "ä¸èƒ½åˆ›å»ºç›®å½• '%s'" -#: builtin/log.c:1390 +#: builtin/log.c:1394 msgid "Failed to create output files" msgstr "æ— æ³•åˆ›å»ºè¾“å‡ºæ–‡ä»¶" -#: builtin/log.c:1494 +#: builtin/log.c:1443 +msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]" +msgstr "" + +#: builtin/log.c:1498 #, c-format msgid "" "Could not find a tracked remote branch, please specify <upstream> manually.\n" msgstr "ä¸èƒ½æ‰¾åˆ°è·Ÿè¸ªçš„远程分支,请手工指定 <upstream>。\n" -#: builtin/log.c:1510 builtin/log.c:1512 builtin/log.c:1524 +#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525 #, c-format msgid "Unknown commit %s" msgstr "未知æäº¤ %s" +#: builtin/ls-files.c:408 +#, fuzzy +msgid "git ls-files [options] [<file>...]" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/ls-files.c:463 +msgid "identify the file status with tags" +msgstr "" + +#: builtin/ls-files.c:465 +msgid "use lowercase letters for 'assume unchanged' files" +msgstr "" + +#: builtin/ls-files.c:467 +msgid "show cached files in the output (default)" +msgstr "" + +#: builtin/ls-files.c:469 +#, fuzzy +msgid "show deleted files in the output" +msgstr "åˆ é™¤çš„æ–‡ä»¶ %s 仿œ‰å†…容" + +#: builtin/ls-files.c:471 +msgid "show modified files in the output" +msgstr "" + +#: builtin/ls-files.c:473 +msgid "show other files in the output" +msgstr "" + +#: builtin/ls-files.c:475 +msgid "show ignored files in the output" +msgstr "" + +#: builtin/ls-files.c:478 +msgid "show staged contents' object name in the output" +msgstr "" + +#: builtin/ls-files.c:480 +msgid "show files on the filesystem that need to be removed" +msgstr "" + +#: builtin/ls-files.c:482 +msgid "show 'other' directories' name only" +msgstr "" + +#: builtin/ls-files.c:485 +#, fuzzy +msgid "don't show empty directories" +msgstr "两个输出目录?" + +#: builtin/ls-files.c:488 +msgid "show unmerged files in the output" +msgstr "" + +#: builtin/ls-files.c:490 +msgid "show resolve-undo information" +msgstr "" + +#: builtin/ls-files.c:492 +#, fuzzy +msgid "skip files matching pattern" +msgstr "输出和模å¼åŒ¹é…的行" + +#: builtin/ls-files.c:495 +msgid "exclude patterns are read from <file>" +msgstr "" + +#: builtin/ls-files.c:498 +msgid "read additional per-directory exclude patterns in <file>" +msgstr "" + +#: builtin/ls-files.c:500 +msgid "add the standard git exclusions" +msgstr "" + +#: builtin/ls-files.c:503 +msgid "make the output relative to the project top directory" +msgstr "" + +#: builtin/ls-files.c:506 +msgid "if any <file> is not in the index, treat this as an error" +msgstr "" + +#: builtin/ls-files.c:507 +msgid "tree-ish" +msgstr "" + +#: builtin/ls-files.c:508 +msgid "pretend that paths removed since <tree-ish> are still present" +msgstr "" + +#: builtin/ls-files.c:510 +msgid "show debugging data" +msgstr "" + +#: builtin/ls-tree.c:27 +#, fuzzy +msgid "git ls-tree [<options>] <tree-ish> [<path>...]" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/ls-tree.c:125 +msgid "only show trees" +msgstr "" + +#: builtin/ls-tree.c:127 +#, fuzzy +msgid "recurse into subtrees" +msgstr "å˜åŸºåˆ°è¿œç¨‹ %s" + +#: builtin/ls-tree.c:129 +msgid "show trees when recursing" +msgstr "" + +#: builtin/ls-tree.c:132 +msgid "terminate entries with NUL byte" +msgstr "" + +#: builtin/ls-tree.c:133 +#, fuzzy +msgid "include object size" +msgstr "æä¾›äº†æ— 效对象 '%s'。" + +#: builtin/ls-tree.c:135 builtin/ls-tree.c:137 +msgid "list only filenames" +msgstr "" + +#: builtin/ls-tree.c:140 +msgid "use full path names" +msgstr "" + +#: builtin/ls-tree.c:142 +msgid "list entire tree; not just current directory (implies --full-name)" +msgstr "" + +#: builtin/merge.c:43 +#, fuzzy +msgid "git merge [options] [<commit>...]" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/merge.c:44 +msgid "git merge [options] <msg> HEAD <commit>" +msgstr "" + +#: builtin/merge.c:45 +msgid "git merge --abort" +msgstr "" + #: builtin/merge.c:90 msgid "switch `m' requires a value" msgstr "开关 `m' 需è¦ä¸€ä¸ªå€¼" @@ -3388,6 +5779,71 @@ msgstr "å¯ç”¨çš„ç–略有:" msgid "Available custom strategies are:" msgstr "å¯ç”¨çš„自定义ç–略有:" +#: builtin/merge.c:183 +msgid "do not show a diffstat at the end of the merge" +msgstr "" + +#: builtin/merge.c:186 +msgid "show a diffstat at the end of the merge" +msgstr "" + +#: builtin/merge.c:187 +msgid "(synonym to --stat)" +msgstr "" + +#: builtin/merge.c:189 +msgid "add (at most <n>) entries from shortlog to merge commit message" +msgstr "" + +#: builtin/merge.c:192 +#, fuzzy +msgid "create a single commit instead of doing a merge" +msgstr "在åˆå¹¶è¿‡ç¨‹ä¸ä¸èƒ½åšéƒ¨åˆ†æäº¤ã€‚" + +#: builtin/merge.c:194 +msgid "perform a commit if the merge succeeds (default)" +msgstr "" + +#: builtin/merge.c:196 +#, fuzzy +msgid "edit message before committing" +msgstr "尚未暂å˜ä»¥å¤‡æäº¤çš„å˜æ›´ï¼š" + +#: builtin/merge.c:198 +#, fuzzy +msgid "allow fast-forward (default)" +msgstr "å¯å¿«è¿›" + +#: builtin/merge.c:200 +msgid "abort if fast-forward is not possible" +msgstr "" + +#: builtin/merge.c:202 builtin/notes.c:867 builtin/revert.c:112 +msgid "strategy" +msgstr "" + +#: builtin/merge.c:203 +#, fuzzy +msgid "merge strategy to use" +msgstr "å°è¯•åˆå¹¶ç–ç•¥ %s...\n" + +#: builtin/merge.c:204 +msgid "option=value" +msgstr "" + +#: builtin/merge.c:205 +msgid "option for selected merge strategy" +msgstr "" + +#: builtin/merge.c:207 +msgid "merge commit message (for a non-fast-forward merge)" +msgstr "" + +#: builtin/merge.c:211 +#, fuzzy +msgid "abort the current in-progress merge" +msgstr "æ— æ³•ä¿å˜å½“å‰ç´¢å¼•状æ€" + #: builtin/merge.c:240 msgid "could not run stash." msgstr "ä¸èƒ½è¿›è¡Œè¿›åº¦ä¿å˜ã€‚" @@ -3428,53 +5884,49 @@ msgstr "å®Œæˆ SQUASH_MSG" msgid "No merge message -- not updating HEAD\n" msgstr "æ— åˆå¹¶ä¿¡æ¯ -- 未更新 HEAD\n" -#: builtin/merge.c:437 +#: builtin/merge.c:436 #, c-format msgid "'%s' does not point to a commit" msgstr "'%s' 没有指å‘一个æäº¤" -#: builtin/merge.c:536 +#: builtin/merge.c:535 #, c-format msgid "Bad branch.%s.mergeoptions string: %s" msgstr "åçš„ branch.%s.mergeoptions å—符串:%s" -#: builtin/merge.c:629 +#: builtin/merge.c:628 msgid "git write-tree failed to write a tree" msgstr "git write-tree æ— æ³•å†™å…¥ä¸€æ ‘å¯¹è±¡" -#: builtin/merge.c:679 +#: builtin/merge.c:678 msgid "failed to read the cache" msgstr "æ— æ³•è¯»å–缓å˜" -#: builtin/merge.c:697 -msgid "Unable to write index." -msgstr "ä¸èƒ½å†™ç´¢å¼•。" - -#: builtin/merge.c:710 +#: builtin/merge.c:709 msgid "Not handling anything other than two heads merge." msgstr "ä¸èƒ½å¤„ç†ä¸¤ä¸ªå¤´åˆå¹¶ä¹‹å¤–的任何æ“作。" -#: builtin/merge.c:724 +#: builtin/merge.c:723 #, c-format msgid "Unknown option for merge-recursive: -X%s" msgstr "merge-recursive 的未知选项:-X%s" -#: builtin/merge.c:738 +#: builtin/merge.c:737 #, c-format msgid "unable to write %s" msgstr "ä¸èƒ½å†™ %s" -#: builtin/merge.c:877 +#: builtin/merge.c:876 #, c-format msgid "Could not read from '%s'" msgstr "ä¸èƒ½ä»Ž '%s' 读å–" -#: builtin/merge.c:886 +#: builtin/merge.c:885 #, c-format msgid "Not committing merge; use 'git commit' to complete the merge.\n" msgstr "未æäº¤åˆå¹¶ï¼Œä½¿ç”¨ 'git commit' å®Œæˆæ¤æ¬¡åˆå¹¶ã€‚\n" -#: builtin/merge.c:892 +#: builtin/merge.c:891 msgid "" "Please enter a commit message to explain why this merge is necessary,\n" "especially if it merges an updated upstream into a topic branch.\n" @@ -3487,52 +5939,52 @@ msgstr "" "\n" "以 '#' 开头的行将被忽略,而且空æäº¤è¯´æ˜Žå°†ä¼šç»ˆæ¢æäº¤ã€‚\n" -#: builtin/merge.c:916 +#: builtin/merge.c:915 msgid "Empty commit message." msgstr "空æäº¤ä¿¡æ¯ã€‚" -#: builtin/merge.c:928 +#: builtin/merge.c:927 #, c-format msgid "Wonderful.\n" msgstr "太棒了。\n" -#: builtin/merge.c:993 +#: builtin/merge.c:992 #, c-format msgid "Automatic merge failed; fix conflicts and then commit the result.\n" msgstr "自动åˆå¹¶å¤±è´¥ï¼Œä¿®æ£å†²çªç„¶åŽæäº¤ä¿®æ£çš„结果。\n" -#: builtin/merge.c:1009 +#: builtin/merge.c:1008 #, c-format msgid "'%s' is not a commit" msgstr "'%s' 䏿˜¯ä¸€ä¸ªæäº¤" -#: builtin/merge.c:1050 +#: builtin/merge.c:1049 msgid "No current branch." msgstr "没有当å‰åˆ†æ”¯ã€‚" -#: builtin/merge.c:1052 +#: builtin/merge.c:1051 msgid "No remote for the current branch." msgstr "当å‰åˆ†æ”¯æ²¡æœ‰å¯¹åº”的远程版本库。" -#: builtin/merge.c:1054 +#: builtin/merge.c:1053 msgid "No default upstream defined for the current branch." msgstr "当å‰åˆ†æ”¯æ²¡æœ‰å®šä¹‰é»˜è®¤çš„上游分支。" -#: builtin/merge.c:1059 +#: builtin/merge.c:1058 #, c-format msgid "No remote tracking branch for %s from %s" msgstr "%s 没有æ¥è‡ª %s 的远程跟踪分支" -#: builtin/merge.c:1146 builtin/merge.c:1303 +#: builtin/merge.c:1145 builtin/merge.c:1302 #, c-format msgid "%s - not something we can merge" msgstr "%s - ä¸èƒ½è¢«åˆå¹¶" -#: builtin/merge.c:1214 +#: builtin/merge.c:1213 msgid "There is no merge to abort (MERGE_HEAD missing)." msgstr "没有è¦ç»ˆæ¢çš„åˆå¹¶ï¼ˆMERGE_HEAD 丢失)。" -#: builtin/merge.c:1230 git-pull.sh:31 +#: builtin/merge.c:1229 git-pull.sh:31 msgid "" "You have not concluded your merge (MERGE_HEAD exists).\n" "Please, commit your changes before you can merge." @@ -3540,11 +5992,11 @@ msgstr "" "æ‚¨å°šæœªç»“æŸæ‚¨çš„åˆå¹¶ï¼ˆå˜åœ¨ MERGE_HEAD)。\n" "请在åˆå¹¶å‰å…ˆæäº¤æ‚¨çš„修改。" -#: builtin/merge.c:1233 git-pull.sh:34 +#: builtin/merge.c:1232 git-pull.sh:34 msgid "You have not concluded your merge (MERGE_HEAD exists)." msgstr "æ‚¨å°šæœªç»“æŸæ‚¨çš„åˆå¹¶ï¼ˆå˜åœ¨ MERGE_HEAD)。" -#: builtin/merge.c:1237 +#: builtin/merge.c:1236 msgid "" "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" "Please, commit your changes before you can merge." @@ -3552,83 +6004,184 @@ msgstr "" "æ‚¨å°šæœªç»“æŸæ‚¨çš„æ‹£é€‰ï¼ˆå˜åœ¨ CHERRY_PICK_HEAD)。\n" "请在åˆå¹¶å‰å…ˆæäº¤æ‚¨çš„修改。" -#: builtin/merge.c:1240 +#: builtin/merge.c:1239 msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)." msgstr "æ‚¨å°šæœªç»“æŸæ‚¨çš„æ‹£é€‰ï¼ˆå˜åœ¨ CHERRY_PICK_HEAD)。" -#: builtin/merge.c:1249 +#: builtin/merge.c:1248 msgid "You cannot combine --squash with --no-ff." -msgstr "您ä¸èƒ½å°† --squash 与 --no-ff 共用。" +msgstr "您ä¸èƒ½å°† --squash 与 --no-ff åŒæ—¶ä½¿ç”¨ã€‚" -#: builtin/merge.c:1254 +#: builtin/merge.c:1253 msgid "You cannot combine --no-ff with --ff-only." -msgstr "您ä¸èƒ½å°† --no-ff 与 --ff-only 共用。" +msgstr "您ä¸èƒ½å°† --no-ff 与 --ff-only åŒæ—¶ä½¿ç”¨ã€‚" -#: builtin/merge.c:1261 +#: builtin/merge.c:1260 msgid "No commit specified and merge.defaultToUpstream not set." msgstr "未指定æäº¤å¹¶ä¸” merge.defaultToUpstream 未设置。" -#: builtin/merge.c:1293 +#: builtin/merge.c:1292 msgid "Can merge only exactly one commit into empty head" msgstr "åªèƒ½å°†ä¸€ä¸ªæäº¤åˆå¹¶åˆ°ç©ºåˆ†æ”¯ä¸Š" -#: builtin/merge.c:1296 +#: builtin/merge.c:1295 msgid "Squash commit into empty head not supported yet" msgstr "å°šä¸æ”¯æŒåˆ°ç©ºåˆ†æ”¯çš„压缩æäº¤" -#: builtin/merge.c:1298 +#: builtin/merge.c:1297 msgid "Non-fast-forward commit does not make sense into an empty head" msgstr "到空分支的éžå¿«è¿›å¼æäº¤æ²¡æœ‰æ„义" -#: builtin/merge.c:1413 +#: builtin/merge.c:1412 #, c-format msgid "Updating %s..%s\n" msgstr "æ›´æ–° %s..%s\n" -#: builtin/merge.c:1451 +#: builtin/merge.c:1450 #, c-format msgid "Trying really trivial in-index merge...\n" msgstr "å°è¯•éžå¸¸å°çš„索引内åˆå¹¶...\n" -#: builtin/merge.c:1458 +#: builtin/merge.c:1457 #, c-format msgid "Nope.\n" msgstr "æ— ã€‚\n" -#: builtin/merge.c:1490 +#: builtin/merge.c:1489 msgid "Not possible to fast-forward, aborting." msgstr "æ— æ³•å¿«è¿›ï¼Œç»ˆæ¢ã€‚" -#: builtin/merge.c:1513 builtin/merge.c:1592 +#: builtin/merge.c:1512 builtin/merge.c:1591 #, c-format msgid "Rewinding the tree to pristine...\n" msgstr "å°†æ ‘å›žæ»šè‡³åŽŸå§‹çŠ¶æ€...\n" -#: builtin/merge.c:1517 +#: builtin/merge.c:1516 #, c-format msgid "Trying merge strategy %s...\n" msgstr "å°è¯•åˆå¹¶ç–ç•¥ %s...\n" -#: builtin/merge.c:1583 +#: builtin/merge.c:1582 #, c-format msgid "No merge strategy handled the merge.\n" msgstr "没有åˆå¹¶ç–ç•¥å¤„ç†æ¤åˆå¹¶ã€‚\n" -#: builtin/merge.c:1585 +#: builtin/merge.c:1584 #, c-format msgid "Merge with strategy %s failed.\n" msgstr "使用ç–ç•¥ %s åˆå¹¶å¤±è´¥ã€‚\n" -#: builtin/merge.c:1594 +#: builtin/merge.c:1593 #, c-format msgid "Using the %s to prepare resolving by hand.\n" msgstr "使用 %s 以准备手工解决。\n" -#: builtin/merge.c:1606 +#: builtin/merge.c:1605 #, c-format msgid "Automatic merge went well; stopped before committing as requested\n" msgstr "自动åˆå¹¶è¿›å±•é¡ºåˆ©ï¼ŒæŒ‰è¦æ±‚在æäº¤å‰åœæ¢\n" +#: builtin/merge-base.c:26 +msgid "git merge-base [-a|--all] <commit> <commit>..." +msgstr "" + +#: builtin/merge-base.c:27 +msgid "git merge-base [-a|--all] --octopus <commit>..." +msgstr "" + +#: builtin/merge-base.c:28 +msgid "git merge-base --independent <commit>..." +msgstr "" + +#: builtin/merge-base.c:29 +msgid "git merge-base --is-ancestor <commit> <commit>" +msgstr "" + +#: builtin/merge-base.c:98 +#, fuzzy +msgid "output all common ancestors" +msgstr "å‘现 %u 个共åŒç¥–先:" + +#: builtin/merge-base.c:99 +msgid "find ancestors for a single n-way merge" +msgstr "" + +#: builtin/merge-base.c:100 +msgid "list revs not reachable from others" +msgstr "" + +#: builtin/merge-base.c:102 +msgid "is the first one ancestor of the other?" +msgstr "" + +#: builtin/merge-file.c:8 +msgid "" +"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file " +"file2" +msgstr "" + +#: builtin/merge-file.c:33 +msgid "send results to standard output" +msgstr "" + +#: builtin/merge-file.c:34 +msgid "use a diff3 based merge" +msgstr "" + +#: builtin/merge-file.c:35 +msgid "for conflicts, use our version" +msgstr "" + +#: builtin/merge-file.c:37 +msgid "for conflicts, use their version" +msgstr "" + +#: builtin/merge-file.c:39 +msgid "for conflicts, use a union version" +msgstr "" + +#: builtin/merge-file.c:42 +msgid "for conflicts, use this marker size" +msgstr "" + +#: builtin/merge-file.c:43 +msgid "do not warn about conflicts" +msgstr "" + +#: builtin/merge-file.c:45 +msgid "set labels for file1/orig_file/file2" +msgstr "" + +#: builtin/mktree.c:67 +msgid "git mktree [-z] [--missing] [--batch]" +msgstr "" + +#: builtin/mktree.c:153 +msgid "input is NUL terminated" +msgstr "" + +#: builtin/mktree.c:154 builtin/write-tree.c:24 +#, fuzzy +msgid "allow missing objects" +msgstr "接收对象ä¸" + +#: builtin/mktree.c:155 +msgid "allow creation of more than one tree" +msgstr "" + +#: builtin/mv.c:14 +msgid "git mv [options] <source>... <destination>" +msgstr "" + +#: builtin/mv.c:64 +msgid "force move/rename even if target exists" +msgstr "" + +#: builtin/mv.c:65 +#, fuzzy +msgid "skip move/rename errors" +msgstr "程åºé”™è¯¯" + #: builtin/mv.c:108 #, c-format msgid "Checking rename of '%s' to '%s'\n" @@ -3691,6 +6244,151 @@ msgstr "é‡å‘½å %s 至 %s\n" msgid "renaming '%s' failed" msgstr "é‡å‘½å '%s' 失败" +#: builtin/name-rev.c:175 +#, fuzzy +msgid "git name-rev [options] <commit>..." +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/name-rev.c:176 +msgid "git name-rev [options] --all" +msgstr "" + +#: builtin/name-rev.c:177 +msgid "git name-rev [options] --stdin" +msgstr "" + +#: builtin/name-rev.c:229 +msgid "print only names (no SHA-1)" +msgstr "" + +#: builtin/name-rev.c:230 +msgid "only use tags to name the commits" +msgstr "" + +#: builtin/name-rev.c:232 +#, fuzzy +msgid "only use refs matching <pattern>" +msgstr "输出和模å¼åŒ¹é…的行" + +#: builtin/name-rev.c:234 +msgid "list all commits reachable from all refs" +msgstr "" + +#: builtin/name-rev.c:235 +msgid "read from stdin" +msgstr "" + +#: builtin/name-rev.c:236 +msgid "allow to print `undefined` names" +msgstr "" + +#: builtin/notes.c:23 +msgid "git notes [--ref <notes_ref>] [list [<object>]]" +msgstr "" + +#: builtin/notes.c:24 +msgid "" +"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) " +"<object>] [<object>]" +msgstr "" + +#: builtin/notes.c:25 +msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>" +msgstr "" + +#: builtin/notes.c:26 +msgid "" +"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) " +"<object>] [<object>]" +msgstr "" + +#: builtin/notes.c:27 +msgid "git notes [--ref <notes_ref>] edit [<object>]" +msgstr "" + +#: builtin/notes.c:28 +msgid "git notes [--ref <notes_ref>] show [<object>]" +msgstr "" + +#: builtin/notes.c:29 +msgid "" +"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>" +msgstr "" + +#: builtin/notes.c:30 +msgid "git notes merge --commit [-v | -q]" +msgstr "" + +#: builtin/notes.c:31 +msgid "git notes merge --abort [-v | -q]" +msgstr "" + +#: builtin/notes.c:32 +msgid "git notes [--ref <notes_ref>] remove [<object>...]" +msgstr "" + +#: builtin/notes.c:33 +msgid "git notes [--ref <notes_ref>] prune [-n | -v]" +msgstr "" + +#: builtin/notes.c:34 +msgid "git notes [--ref <notes_ref>] get-ref" +msgstr "" + +#: builtin/notes.c:39 +msgid "git notes [list [<object>]]" +msgstr "" + +#: builtin/notes.c:44 +#, fuzzy +msgid "git notes add [<options>] [<object>]" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/notes.c:49 +msgid "git notes copy [<options>] <from-object> <to-object>" +msgstr "" + +#: builtin/notes.c:50 +msgid "git notes copy --stdin [<from-object> <to-object>]..." +msgstr "" + +#: builtin/notes.c:55 +#, fuzzy +msgid "git notes append [<options>] [<object>]" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/notes.c:60 +msgid "git notes edit [<object>]" +msgstr "" + +#: builtin/notes.c:65 +msgid "git notes show [<object>]" +msgstr "" + +#: builtin/notes.c:70 +msgid "git notes merge [<options>] <notes_ref>" +msgstr "" + +#: builtin/notes.c:71 +msgid "git notes merge --commit [<options>]" +msgstr "" + +#: builtin/notes.c:72 +msgid "git notes merge --abort [<options>]" +msgstr "" + +#: builtin/notes.c:77 +msgid "git notes remove [<object>]" +msgstr "" + +#: builtin/notes.c:82 +msgid "git notes prune [<options>]" +msgstr "" + +#: builtin/notes.c:87 +msgid "git notes get-ref" +msgstr "" + #: builtin/notes.c:139 #, c-format msgid "unable to start 'show' for object '%s'" @@ -3798,6 +6496,37 @@ msgstr "傿•°å¤ªå¤š" msgid "No note found for object %s." msgstr "未å‘现对象 %s 的注解。" +#: builtin/notes.c:535 builtin/notes.c:692 +#, fuzzy +msgid "note contents as a string" +msgstr "注解内容被留在文件 %s ä¸" + +#: builtin/notes.c:538 builtin/notes.c:695 +#, fuzzy +msgid "note contents in a file" +msgstr "æ— æ³•å˜å‚¨ç´¢å¼•文件" + +#: builtin/notes.c:540 builtin/notes.c:543 builtin/notes.c:697 +#: builtin/notes.c:700 builtin/tag.c:476 +#, fuzzy +msgid "object" +msgstr "å对象 %s" + +#: builtin/notes.c:541 builtin/notes.c:698 +#, fuzzy +msgid "reuse and edit specified note object" +msgstr "ä¸èƒ½å†™æ³¨è§£å¯¹è±¡" + +#: builtin/notes.c:544 builtin/notes.c:701 +#, fuzzy +msgid "reuse specified note object" +msgstr "ä¸èƒ½å†™æ³¨è§£å¯¹è±¡" + +#: builtin/notes.c:546 builtin/notes.c:614 +#, fuzzy +msgid "replace existing notes" +msgstr "ä¸èƒ½è¯»å–现å˜å¯¹è±¡ %s" + #: builtin/notes.c:580 #, c-format msgid "" @@ -3810,6 +6539,15 @@ msgstr "ä¸èƒ½æ·»åŠ æ³¨è§£ã€‚å‘现对象 %s å·²å˜åœ¨æ³¨è§£ã€‚使用 '-f' è¦†ç› msgid "Overwriting existing notes for object %s\n" msgstr "覆盖对象 %s çŽ°å˜æ³¨è§£\n" +#: builtin/notes.c:615 +#, fuzzy +msgid "read objects from stdin" +msgstr "å对象 %s" + +#: builtin/notes.c:617 +msgid "load rewriting config for <command> (implies --stdin)" +msgstr "" + #: builtin/notes.c:635 msgid "too few parameters" msgstr "傿•°å¤ªå°‘" @@ -3835,36 +6573,263 @@ msgstr "" "å命令 'edit' 的选项 -m/-F/-c/-C 已弃用。\n" "请æ¢ç”¨ 'git notes add -f -m/-F/-c/-C'。\n" +#: builtin/notes.c:864 +#, fuzzy +msgid "General options" +msgstr "æ— æ•ˆé€‰é¡¹ï¼š%s" + +#: builtin/notes.c:866 +msgid "Merge options" +msgstr "" + +#: builtin/notes.c:868 +msgid "" +"resolve notes conflicts using the given strategy (manual/ours/theirs/union/" +"cat_sort_uniq)" +msgstr "" + +#: builtin/notes.c:870 +msgid "Committing unmerged notes" +msgstr "" + +#: builtin/notes.c:872 +msgid "finalize notes merge by committing unmerged notes" +msgstr "" + +#: builtin/notes.c:874 +msgid "Aborting notes merge resolution" +msgstr "" + +#: builtin/notes.c:876 +#, fuzzy +msgid "abort notes merge" +msgstr "path '%s'ï¼šæ— æ³•åˆå¹¶" + #: builtin/notes.c:971 #, c-format msgid "Object %s has no note\n" msgstr "对象 %s 没有注解\n" +#: builtin/notes.c:983 +msgid "attempt to remove non-existent note is not an error" +msgstr "" + +#: builtin/notes.c:986 +#, fuzzy +msgid "read object names from the standard input" +msgstr "(æ£ä»Žæ ‡å‡†è¾“å…¥ä¸è¯»å–日志信æ¯ï¼‰\n" + +#: builtin/notes.c:1067 +msgid "notes_ref" +msgstr "" + +#: builtin/notes.c:1068 +msgid "use notes from <notes_ref>" +msgstr "" + #: builtin/notes.c:1103 builtin/remote.c:1598 #, c-format msgid "Unknown subcommand: %s" msgstr "未知å命令:%s" -#: builtin/pack-objects.c:2337 +#: builtin/pack-objects.c:23 +msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]" +msgstr "" + +#: builtin/pack-objects.c:24 +msgid "git pack-objects [options...] base-name [< ref-list | < object-list]" +msgstr "" + +#: builtin/pack-objects.c:183 builtin/pack-objects.c:186 +#, c-format +msgid "deflate error (%d)" +msgstr "压缩错误 (%d)" + +#: builtin/pack-objects.c:2398 #, c-format msgid "unsupported index version %s" msgstr "䏿”¯æŒçš„索引版本 %s" -#: builtin/pack-objects.c:2341 +#: builtin/pack-objects.c:2402 #, c-format msgid "bad index version '%s'" msgstr "å的索引版本 '%s'" -#: builtin/pack-objects.c:2364 +#: builtin/pack-objects.c:2425 #, c-format msgid "option %s does not accept negative form" msgstr "选项 %s 䏿ޥå—å¦å®šæ ¼å¼" -#: builtin/pack-objects.c:2368 +#: builtin/pack-objects.c:2429 #, c-format msgid "unable to parse value '%s' for option %s" msgstr "ä¸èƒ½è§£æžé€‰é¡¹ %1$s 的值 '%2$s'" +#: builtin/pack-objects.c:2448 +msgid "do not show progress meter" +msgstr "" + +#: builtin/pack-objects.c:2450 +msgid "show progress meter" +msgstr "" + +#: builtin/pack-objects.c:2452 +msgid "show progress meter during object writing phase" +msgstr "" + +#: builtin/pack-objects.c:2455 +msgid "similar to --all-progress when progress meter is shown" +msgstr "" + +#: builtin/pack-objects.c:2456 +msgid "version[,offset]" +msgstr "" + +#: builtin/pack-objects.c:2457 +msgid "write the pack index file in the specified idx format version" +msgstr "" + +#: builtin/pack-objects.c:2460 +#, fuzzy +msgid "maximum size of each output pack file" +msgstr "æ— æ³•åˆ›å»ºè¾“å‡ºæ–‡ä»¶" + +#: builtin/pack-objects.c:2462 +msgid "ignore borrowed objects from alternate object store" +msgstr "" + +#: builtin/pack-objects.c:2464 +#, fuzzy +msgid "ignore packed objects" +msgstr "ä¸èƒ½è¯»å–对象 %s" + +#: builtin/pack-objects.c:2466 +msgid "limit pack window by objects" +msgstr "" + +#: builtin/pack-objects.c:2468 +msgid "limit pack window by memory in addition to object limit" +msgstr "" + +#: builtin/pack-objects.c:2470 +msgid "maximum length of delta chain allowed in the resulting pack" +msgstr "" + +#: builtin/pack-objects.c:2472 +#, fuzzy +msgid "reuse existing deltas" +msgstr "å¤„ç† delta ä¸" + +#: builtin/pack-objects.c:2474 +#, fuzzy +msgid "reuse existing objects" +msgstr "ä¸èƒ½è¯»å–现å˜å¯¹è±¡ %s" + +#: builtin/pack-objects.c:2476 +msgid "use OFS_DELTA objects" +msgstr "" + +#: builtin/pack-objects.c:2478 +msgid "use threads when searching for best delta matches" +msgstr "" + +#: builtin/pack-objects.c:2480 +msgid "do not create an empty pack output" +msgstr "" + +#: builtin/pack-objects.c:2482 +#, fuzzy +msgid "read revision arguments from standard input" +msgstr "(æ£ä»Žæ ‡å‡†è¾“å…¥ä¸è¯»å–日志信æ¯ï¼‰\n" + +#: builtin/pack-objects.c:2484 +msgid "limit the objects to those that are not yet packed" +msgstr "" + +#: builtin/pack-objects.c:2487 +msgid "include objects reachable from any reference" +msgstr "" + +#: builtin/pack-objects.c:2490 +msgid "include objects referred by reflog entries" +msgstr "" + +#: builtin/pack-objects.c:2493 +msgid "output pack to stdout" +msgstr "" + +#: builtin/pack-objects.c:2495 +msgid "include tag objects that refer to objects to be packed" +msgstr "" + +#: builtin/pack-objects.c:2497 +msgid "keep unreachable objects" +msgstr "" + +#: builtin/pack-objects.c:2498 parse-options.h:141 +msgid "time" +msgstr "æ—¶é—´" + +#: builtin/pack-objects.c:2499 +msgid "unpack unreachable objects newer than <time>" +msgstr "" + +#: builtin/pack-objects.c:2502 +msgid "create thin packs" +msgstr "" + +#: builtin/pack-objects.c:2504 +msgid "ignore packs that have companion .keep file" +msgstr "" + +#: builtin/pack-objects.c:2506 +msgid "pack compression level" +msgstr "" + +#: builtin/pack-objects.c:2508 +#, fuzzy +msgid "do not hide commits by grafts" +msgstr "ä¸èƒ½å†™æäº¤æ¨¡ç‰ˆ" + +#: builtin/pack-refs.c:6 +msgid "git pack-refs [options]" +msgstr "" + +#: builtin/pack-refs.c:14 +msgid "pack everything" +msgstr "" + +#: builtin/pack-refs.c:15 +msgid "prune loose refs (default)" +msgstr "" + +#: builtin/prune-packed.c:7 +msgid "git prune-packed [-n|--dry-run] [-q|--quiet]" +msgstr "" + +#: builtin/prune.c:12 +msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]" +msgstr "" + +#: builtin/prune.c:132 +#, fuzzy +msgid "do not remove, show only" +msgstr "ä¸ä¼šåˆ 除 %s\n" + +#: builtin/prune.c:133 +#, fuzzy +msgid "report pruned objects" +msgstr "ä¸èƒ½è¯»å–对象 %s" + +#: builtin/prune.c:136 +msgid "expire objects older than <time>" +msgstr "" + +#: builtin/push.c:14 +#, fuzzy +msgid "git push [<options>] [<repository> [<refspec>...]]" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + #: builtin/push.c:45 msgid "tag shorthand without <tag>" msgstr "tag 简写没有跟 <tag> 傿•°" @@ -3947,12 +6912,44 @@ msgstr "" "æ‚¨æ£æŽ¨é€è‡³è¿œç¨‹ '%s'(其并éžå½“å‰åˆ†æ”¯ '%s' 的上游),\n" "è€Œæ²¡æœ‰å‘Šè¯‰æˆ‘è¦æŽ¨é€ä»€ä¹ˆã€æ›´æ–°å“ªä¸ªè¿œç¨‹åˆ†æ”¯ã€‚" -#: builtin/push.c:174 +# 译者:å—ç¬¦ä¸²é¦–è¡Œè¡Œé¦–è¦æ·»åŠ â€œwarning: â€å—串,故æ¤é¦–行è¦è¾ƒå…¶ä½™è¡ŒçŸ +#: builtin/push.c:151 +msgid "" +"push.default is unset; its implicit value is changing in\n" +"Git 2.0 from 'matching' to 'simple'. To squelch this message\n" +"and maintain the current behavior after the default changes, use:\n" +"\n" +" git config --global push.default matching\n" +"\n" +"To squelch this message and adopt the new behavior now, use:\n" +"\n" +" git config --global push.default simple\n" +"\n" +"See 'git help config' and search for 'push.default' for further " +"information.\n" +"(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n" +"'current' instead of 'simple' if you sometimes use older versions of Git)" +msgstr "" +"push.default 未设置,它的默认值将会在 Git 2.0 ç”± 'matching'\n" +"修改为 'simple'。若è¦ä¸å†æ˜¾ç¤ºæœ¬ä¿¡æ¯å¹¶åœ¨å…¶é»˜è®¤å€¼æ”¹å˜åŽç»´æŒå½“å‰ä½¿ç”¨ä¹ 惯,\n" +"进行如下设置:\n" +"\n" +" git config --global push.default matching\n" +"\n" +"è‹¥è¦ä¸å†æ˜¾ç¤ºæœ¬ä¿¡æ¯å¹¶ä»ŽçŽ°åœ¨å¼€å§‹é‡‡ç”¨æ–°çš„ä½¿ç”¨ä¹ æƒ¯ï¼Œè®¾ç½®ï¼š\n" +"\n" +" git config --global push.default simple\n" +"\n" +"å‚è§ 'git help config' 并查找 'push.default' ä»¥èŽ·å–æ›´å¤šä¿¡æ¯ã€‚\n" +"('simple' 模å¼ç”± Git 1.7.11 版本引入。如果您有时è¦ä½¿ç”¨è€ç‰ˆæœ¬çš„ Git,\n" +"ä¸ºä¿æŒå…¼å®¹ï¼Œè¯·ç”¨ 'current' 代替 'simple' 模å¼ï¼‰" + +#: builtin/push.c:199 msgid "" "You didn't specify any refspecs to push, and push.default is \"nothing\"." msgstr "æ‚¨æ²¡æœ‰ä¸ºæŽ¨é€æŒ‡å®šä»»ä½•引用表达å¼ï¼Œå¹¶ä¸” push.default 为 \"nothing\"。" -#: builtin/push.c:181 +#: builtin/push.c:206 msgid "" "Updates were rejected because the tip of your current branch is behind\n" "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n" @@ -3963,18 +6960,19 @@ msgstr "" "冿¬¡æŽ¨é€å‰ï¼Œå…ˆä¸Žè¿œç¨‹å˜æ›´åˆå¹¶ï¼ˆå¦‚ 'git pull')。详è§\n" "'git push --help' ä¸çš„ 'Note about fast-forwards' å°èŠ‚ã€‚" -#: builtin/push.c:187 +#: builtin/push.c:212 msgid "" "Updates were rejected because a pushed branch tip is behind its remote\n" "counterpart. If you did not intend to push that branch, you may want to\n" -"specify branches to push or set the 'push.default' configuration\n" -"variable to 'current' or 'upstream' to push only the current branch." +"specify branches to push or set the 'push.default' configuration variable\n" +"to 'simple', 'current' or 'upstream' to push only the current branch." msgstr "" "更新被拒ç»ï¼Œå› 为推é€çš„一个分支的最新æäº¤è½åŽäºŽå…¶å¯¹åº”的远程分支。\n" "å¦‚æžœæ‚¨å¹¶éžæœ‰æ„推é€è¯¥åˆ†æ”¯ï¼Œæ‚¨å¯ä»¥åœ¨æŽ¨é€æ—¶æŒ‡å®šè¦æŽ¨é€çš„分支,或者将\n" -"é…ç½®å˜é‡ 'push.default' 设置为 'current' 或 'upstream' ä»¥ä¾¿åªæŽ¨é€å½“å‰åˆ†æ”¯ã€‚" +"é…ç½®å˜é‡ 'push.default' 设置为 'simple'ã€'current' 或 'upstream'\n" +"ä»¥ä¾¿åªæŽ¨é€å½“å‰åˆ†æ”¯ã€‚" -#: builtin/push.c:193 +#: builtin/push.c:218 msgid "" "Updates were rejected because a pushed branch tip is behind its remote\n" "counterpart. Check out this branch and merge the remote changes\n" @@ -3985,22 +6983,22 @@ msgstr "" "æ£€å‡ºè¯¥åˆ†æ”¯å¹¶ä¸Žè¿œç¨‹å˜æ›´åˆå¹¶ï¼ˆå¦‚ 'git pull'),然åŽå†æŽ¨é€ã€‚详è§\n" "'git push --help' ä¸çš„ 'Note about fast-forwards' å°èŠ‚ã€‚" -#: builtin/push.c:233 +#: builtin/push.c:258 #, c-format msgid "Pushing to %s\n" msgstr "推é€åˆ° %s\n" -#: builtin/push.c:237 +#: builtin/push.c:262 #, c-format msgid "failed to push some refs to '%s'" msgstr "æ— æ³•æŽ¨é€ä¸€äº›å¼•用到 '%s'" -#: builtin/push.c:269 +#: builtin/push.c:294 #, c-format msgid "bad repository '%s'" msgstr "å的版本库 '%s'" -#: builtin/push.c:270 +#: builtin/push.c:295 msgid "" "No configured push destination.\n" "Either specify the URL from the command-line or configure a remote " @@ -4021,34 +7019,241 @@ msgstr "" "\n" " git push <name>\n" -#: builtin/push.c:285 +#: builtin/push.c:310 msgid "--all and --tags are incompatible" msgstr "--all å’Œ --tags ä¸å…¼å®¹" -#: builtin/push.c:286 +#: builtin/push.c:311 msgid "--all can't be combined with refspecs" -msgstr "--all ä¸èƒ½å’Œå¼•用表达å¼å…±ç”¨" +msgstr "--all ä¸èƒ½å’Œå¼•用表达å¼åŒæ—¶ä½¿ç”¨" -#: builtin/push.c:291 +#: builtin/push.c:316 msgid "--mirror and --tags are incompatible" msgstr "--mirror å’Œ --tags ä¸å…¼å®¹" -#: builtin/push.c:292 +#: builtin/push.c:317 msgid "--mirror can't be combined with refspecs" -msgstr "--mirror ä¸èƒ½å’Œå¼•用表达å¼å…±ç”¨" +msgstr "--mirror ä¸èƒ½å’Œå¼•用表达å¼åŒæ—¶ä½¿ç”¨" -#: builtin/push.c:297 +#: builtin/push.c:322 msgid "--all and --mirror are incompatible" msgstr "--all å’Œ --mirror ä¸å…¼å®¹" -#: builtin/push.c:385 +#: builtin/push.c:382 +#, fuzzy +msgid "repository" +msgstr "å的版本库 '%s'" + +#: builtin/push.c:383 +msgid "push all refs" +msgstr "" + +#: builtin/push.c:384 +msgid "mirror all refs" +msgstr "" + +#: builtin/push.c:386 +#, fuzzy +msgid "delete refs" +msgstr "åˆ é™¤" + +#: builtin/push.c:387 +msgid "push tags (can't be used with --all or --mirror)" +msgstr "" + +#: builtin/push.c:390 +#, fuzzy +msgid "force updates" +msgstr "强制更新" + +#: builtin/push.c:391 +msgid "check" +msgstr "" + +#: builtin/push.c:392 +msgid "control recursive pushing of submodules" +msgstr "" + +#: builtin/push.c:394 +msgid "use thin pack" +msgstr "" + +#: builtin/push.c:395 builtin/push.c:396 +msgid "receive pack program" +msgstr "" + +#: builtin/push.c:397 +msgid "set upstream for git pull/status" +msgstr "" + +#: builtin/push.c:400 +msgid "prune locally removed refs" +msgstr "" + +#: builtin/push.c:410 msgid "--delete is incompatible with --all, --mirror and --tags" msgstr "--delete 与 --allã€--mirror åŠ --tags ä¸å…¼å®¹" -#: builtin/push.c:387 +#: builtin/push.c:412 msgid "--delete doesn't make sense without any refs" msgstr "--delete 未接任何引用没有æ„义" +#: builtin/read-tree.c:36 +msgid "" +"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] " +"[-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--" +"index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])" +msgstr "" + +#: builtin/read-tree.c:108 +#, fuzzy +msgid "write resulting index to <file>" +msgstr "æŸå的索引文件" + +#: builtin/read-tree.c:111 +#, fuzzy +msgid "only empty the index" +msgstr "ä¸èƒ½è¯»å–索引" + +#: builtin/read-tree.c:113 +#, fuzzy +msgid "Merging" +msgstr "åˆå¹¶ï¼š" + +#: builtin/read-tree.c:115 +msgid "perform a merge in addition to a read" +msgstr "" + +#: builtin/read-tree.c:117 +msgid "3-way merge if no file level merging required" +msgstr "" + +#: builtin/read-tree.c:119 +msgid "3-way merge in presence of adds and removes" +msgstr "" + +#: builtin/read-tree.c:121 +msgid "same as -m, but discard unmerged entries" +msgstr "" + +#: builtin/read-tree.c:122 +#, fuzzy +msgid "<subdirectory>/" +msgstr "目录/文件" + +#: builtin/read-tree.c:123 +msgid "read the tree into the index under <subdirectory>/" +msgstr "" + +#: builtin/read-tree.c:126 +msgid "update working tree with merge result" +msgstr "" + +#: builtin/read-tree.c:128 +#, fuzzy +msgid "gitignore" +msgstr "忽略的" + +#: builtin/read-tree.c:129 +msgid "allow explicitly ignored files to be overwritten" +msgstr "" + +#: builtin/read-tree.c:132 +#, fuzzy +msgid "don't check the working tree after merging" +msgstr "显示工作区状æ€" + +#: builtin/read-tree.c:133 +msgid "don't update the index or the work tree" +msgstr "" + +#: builtin/read-tree.c:135 +msgid "skip applying sparse checkout filter" +msgstr "" + +#: builtin/read-tree.c:137 +msgid "debug unpack-trees" +msgstr "" + +#: builtin/remote.c:11 +msgid "git remote [-v | --verbose]" +msgstr "" + +#: builtin/remote.c:12 +msgid "" +"git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--" +"mirror=<fetch|push>] <name> <url>" +msgstr "" + +#: builtin/remote.c:13 builtin/remote.c:32 +msgid "git remote rename <old> <new>" +msgstr "" + +#: builtin/remote.c:14 builtin/remote.c:37 +msgid "git remote remove <name>" +msgstr "" + +#: builtin/remote.c:15 +msgid "git remote set-head <name> (-a | -d | <branch>)" +msgstr "" + +#: builtin/remote.c:16 +msgid "git remote [-v | --verbose] show [-n] <name>" +msgstr "" + +#: builtin/remote.c:17 +msgid "git remote prune [-n | --dry-run] <name>" +msgstr "" + +#: builtin/remote.c:18 +msgid "" +"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]" +msgstr "" + +#: builtin/remote.c:19 +msgid "git remote set-branches [--add] <name> <branch>..." +msgstr "" + +#: builtin/remote.c:20 builtin/remote.c:68 +msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]" +msgstr "" + +#: builtin/remote.c:21 builtin/remote.c:69 +msgid "git remote set-url --add <name> <newurl>" +msgstr "" + +#: builtin/remote.c:22 builtin/remote.c:70 +msgid "git remote set-url --delete <name> <url>" +msgstr "" + +#: builtin/remote.c:27 +msgid "git remote add [<options>] <name> <url>" +msgstr "" + +#: builtin/remote.c:42 +msgid "git remote set-head <name> (-a | -d | <branch>])" +msgstr "" + +#: builtin/remote.c:47 +msgid "git remote set-branches <name> <branch>..." +msgstr "" + +#: builtin/remote.c:48 +msgid "git remote set-branches --add <name> <branch>..." +msgstr "" + +#: builtin/remote.c:53 +msgid "git remote show [<options>] <name>" +msgstr "" + +#: builtin/remote.c:58 +msgid "git remote prune [<options>] <name>" +msgstr "" + +#: builtin/remote.c:63 +msgid "git remote update [<options>] [<group> | <remote>]..." +msgstr "" + #: builtin/remote.c:98 #, c-format msgid "Updating %s" @@ -4067,13 +7272,43 @@ msgstr "" msgid "unknown mirror argument: %s" msgstr "未知的镜åƒå‚数:%s" +#: builtin/remote.c:163 +#, fuzzy +msgid "fetch the remote branches" +msgstr " 远程分支:%s" + +#: builtin/remote.c:165 +msgid "import all tags and associated objects when fetching" +msgstr "" + +#: builtin/remote.c:168 +msgid "or do not fetch any tag at all (--no-tags)" +msgstr "" + +#: builtin/remote.c:170 +msgid "branch(es) to track" +msgstr "" + +#: builtin/remote.c:171 +#, fuzzy +msgid "master branch" +msgstr " 远程分支:%s" + +#: builtin/remote.c:172 +msgid "push|fetch" +msgstr "" + +#: builtin/remote.c:173 +msgid "set up remote as a mirror to push to or fetch from" +msgstr "" + #: builtin/remote.c:185 msgid "specifying a master branch makes no sense with --mirror" msgstr "指定一个 master 分支并使用 --mirror 选项没有æ„义" #: builtin/remote.c:187 msgid "specifying branches to track makes sense only with fetch mirrors" -msgstr "指定è¦è·Ÿè¸ªçš„分支åªåœ¨ä¸ŽèŽ·å–镜åƒå…±ç”¨æ‰æœ‰æ„义" +msgstr "指定è¦è·Ÿè¸ªçš„分支åªåœ¨ä¸ŽèŽ·å–镜åƒåŒæ—¶ä½¿ç”¨æ‰æœ‰æ„义" #: builtin/remote.c:195 builtin/remote.c:646 #, c-format @@ -4259,6 +7494,11 @@ msgstr " %-*s 强制推é€è‡³ %s" msgid " %-*s pushes to %s" msgstr " %-*s 推é€è‡³ %s" +#: builtin/remote.c:1091 +#, fuzzy +msgid "do not query remotes" +msgstr "ä¸ä¼šåˆ 除 %s\n" + #: builtin/remote.c:1118 #, c-format msgid "* remote %s" @@ -4318,6 +7558,14 @@ msgid_plural " Local refs configured for 'git push'%s:" msgstr[0] " 为 'git push' é…置的本地引用%s:" msgstr[1] " 为 'git push' é…置的本地引用%s:" +#: builtin/remote.c:1199 +msgid "set refs/remotes/<name>/HEAD according to remote" +msgstr "" + +#: builtin/remote.c:1201 +msgid "delete refs/remotes/<name>/HEAD" +msgstr "" + #: builtin/remote.c:1216 msgid "Cannot determine remote HEAD" msgstr "æ— æ³•ç¡®å®šè¿œç¨‹ HEAD" @@ -4373,15 +7621,37 @@ msgstr " * [å°†åˆ é™¤] %s" msgid " * [pruned] %s" msgstr " * [å·²åˆ é™¤] %s" +#: builtin/remote.c:1321 +msgid "prune remotes after fetching" +msgstr "" + #: builtin/remote.c:1387 builtin/remote.c:1461 #, c-format msgid "No such remote '%s'" msgstr "没有æ¤è¿œç¨‹ '%s'" +#: builtin/remote.c:1407 +#, fuzzy +msgid "add branch" +msgstr "ä½äºŽåˆ†æ”¯ " + #: builtin/remote.c:1414 msgid "no remote specified" msgstr "未指定远程" +#: builtin/remote.c:1436 +msgid "manipulate push URLs" +msgstr "" + +#: builtin/remote.c:1438 +msgid "add URL" +msgstr "" + +#: builtin/remote.c:1440 +#, fuzzy +msgid "delete URLs" +msgstr "åˆ é™¤" + #: builtin/remote.c:1447 msgid "--add --delete doesn't make sense" msgstr "--add --delete æ— æ„义" @@ -4400,6 +7670,56 @@ msgstr "未找到æ¤URL:%s" msgid "Will not delete all non-push URLs" msgstr "å°†ä¸ä¼šåˆ é™¤æ‰€æœ‰éžæŽ¨é€URL地å€" +#: builtin/remote.c:1569 +msgid "be verbose; must be placed before a subcommand" +msgstr "" + +#: builtin/replace.c:17 +msgid "git replace [-f] <object> <replacement>" +msgstr "" + +#: builtin/replace.c:18 +msgid "git replace -d <object>..." +msgstr "" + +#: builtin/replace.c:19 +msgid "git replace -l [<pattern>]" +msgstr "" + +#: builtin/replace.c:118 +msgid "list replace refs" +msgstr "" + +#: builtin/replace.c:119 +msgid "delete replace refs" +msgstr "" + +#: builtin/replace.c:120 +msgid "replace the ref if it exists" +msgstr "" + +#: builtin/rerere.c:11 +msgid "git rerere [clear | forget path... | status | remaining | diff | gc]" +msgstr "" + +#: builtin/rerere.c:56 +#, fuzzy +msgid "register clean resolutions in index" +msgstr "%s:已ç»å˜åœ¨äºŽç´¢å¼•ä¸" + +#: builtin/reset.c:25 +msgid "" +"git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]" +msgstr "" + +#: builtin/reset.c:26 +msgid "git reset [-q] <commit> [--] <paths>..." +msgstr "" + +#: builtin/reset.c:27 +msgid "git reset --patch [<commit>] [--] [<paths>...]" +msgstr "" + #: builtin/reset.c:33 msgid "mixed" msgstr "æ··æ‚" @@ -4456,53 +7776,182 @@ msgstr "é‡ç½®åŽæ’¤å‡ºæš‚å˜åŒºçš„å˜æ›´ï¼š" msgid "Cannot do a %s reset in the middle of a merge." msgstr "在åˆå¹¶è¿‡ç¨‹ä¸ä¸èƒ½åš%sé‡ç½®æ“作。" -#: builtin/reset.c:297 +#: builtin/reset.c:238 +msgid "be quiet, only report errors" +msgstr "" + +#: builtin/reset.c:240 +msgid "reset HEAD and index" +msgstr "" + +#: builtin/reset.c:241 +msgid "reset only HEAD" +msgstr "" + +#: builtin/reset.c:243 builtin/reset.c:245 +msgid "reset HEAD, index and working tree" +msgstr "" + +#: builtin/reset.c:247 +msgid "reset HEAD but keep local changes" +msgstr "" + +#: builtin/reset.c:303 #, c-format msgid "Could not parse object '%s'." msgstr "ä¸èƒ½è§£æžå¯¹è±¡ '%s'。" -#: builtin/reset.c:302 +#: builtin/reset.c:308 msgid "--patch is incompatible with --{hard,mixed,soft}" msgstr "--patch 与 --{hard,mixed,soft} ä¸å…¼å®¹" -#: builtin/reset.c:311 +#: builtin/reset.c:317 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." -msgstr "--mixed 带路径已弃用,代之以 'git reset -- <paths>'。" +msgstr "--mixed 带路径已弃用,而是用 'git reset -- <paths>'。" # 译者:汉å—ä¹‹é—´æ— ç©ºæ ¼ï¼Œæ•…åˆ é™¤%så‰åŽç©ºæ ¼ -#: builtin/reset.c:313 +#: builtin/reset.c:319 #, c-format msgid "Cannot do %s reset with paths." msgstr "ä¸èƒ½å¸¦è·¯å¾„进行%sé‡ç½®ã€‚" # 译者:汉å—ä¹‹é—´æ— ç©ºæ ¼ï¼Œæ•…åˆ é™¤%så‰åŽç©ºæ ¼ -#: builtin/reset.c:325 +#: builtin/reset.c:331 #, c-format msgid "%s reset is not allowed in a bare repository" msgstr "ä¸èƒ½å¯¹è£¸ç‰ˆæœ¬åº“进行%sé‡ç½®" -#: builtin/reset.c:341 +#: builtin/reset.c:347 #, c-format msgid "Could not reset index file to revision '%s'." msgstr "ä¸èƒ½é‡ç½®ç´¢å¼•文件至版本 '%s'。" +#: builtin/rev-parse.c:339 +#, fuzzy +msgid "git rev-parse --parseopt [options] -- [<args>...]" +msgstr "git apply [选项] [<è¡¥ä¸>...]" + +#: builtin/rev-parse.c:344 +msgid "keep the `--` passed as an arg" +msgstr "" + +#: builtin/rev-parse.c:346 +msgid "stop parsing after the first non-option argument" +msgstr "" + +#: builtin/rev-parse.c:464 +msgid "" +"git rev-parse --parseopt [options] -- [<args>...]\n" +" or: git rev-parse --sq-quote [<arg>...]\n" +" or: git rev-parse [options] [<arg>...]\n" +"\n" +"Run \"git rev-parse --parseopt -h\" for more information on the first usage." +msgstr "" + +#: builtin/revert.c:22 +msgid "git revert [options] <commit-ish>" +msgstr "" + +#: builtin/revert.c:23 +msgid "git revert <subcommand>" +msgstr "" + +#: builtin/revert.c:28 +msgid "git cherry-pick [options] <commit-ish>" +msgstr "" + +#: builtin/revert.c:29 +#, fuzzy +msgid "git cherry-pick <subcommand>" +msgstr "拣选失败" + #: builtin/revert.c:70 builtin/revert.c:92 #, c-format msgid "%s: %s cannot be used with %s" -msgstr "%s:%s ä¸èƒ½å’Œ %s 共用" +msgstr "%s:%s ä¸èƒ½å’Œ %s åŒæ—¶ä½¿ç”¨" + +#: builtin/revert.c:103 +msgid "end revert or cherry-pick sequence" +msgstr "" -#: builtin/revert.c:131 +#: builtin/revert.c:104 +msgid "resume revert or cherry-pick sequence" +msgstr "" + +#: builtin/revert.c:105 +msgid "cancel revert or cherry-pick sequence" +msgstr "" + +#: builtin/revert.c:106 +#, fuzzy +msgid "don't automatically commit" +msgstr "ä¸èƒ½ä½œä¸ºåˆå§‹æäº¤è¿˜åŽŸ" + +#: builtin/revert.c:107 +#, fuzzy +msgid "edit the commit message" +msgstr "空æäº¤ä¿¡æ¯ã€‚" + +#: builtin/revert.c:110 +msgid "parent number" +msgstr "" + +#: builtin/revert.c:112 +#, fuzzy +msgid "merge strategy" +msgstr "å°è¯•åˆå¹¶ç–ç•¥ %s...\n" + +#: builtin/revert.c:113 +#, fuzzy +msgid "option" +msgstr "动作" + +#: builtin/revert.c:114 +#, fuzzy +msgid "option for merge strategy" +msgstr "å°è¯•åˆå¹¶ç–ç•¥ %s...\n" + +#: builtin/revert.c:125 +msgid "append commit name" +msgstr "" + +#: builtin/revert.c:126 +#, fuzzy +msgid "allow fast-forward" +msgstr "(éžå¿«è¿›å¼ï¼‰" + +#: builtin/revert.c:127 +#, fuzzy +msgid "preserve initially empty commits" +msgstr "ä¸èƒ½ä½œä¸ºåˆå§‹æäº¤è¿˜åŽŸ" + +#: builtin/revert.c:128 +#, fuzzy +msgid "allow commits with empty messages" +msgstr "æäº¤è¯´æ˜Žä¸ºç©º" + +#: builtin/revert.c:129 +#, fuzzy +msgid "keep redundant, empty commits" +msgstr "åˆå¹¶æœªè¿”回æäº¤" + +#: builtin/revert.c:133 msgid "program error" msgstr "程åºé”™è¯¯" -#: builtin/revert.c:221 +#: builtin/revert.c:223 msgid "revert failed" msgstr "还原失败" -#: builtin/revert.c:236 +#: builtin/revert.c:238 msgid "cherry-pick failed" msgstr "拣选失败" +#: builtin/rm.c:14 +#, fuzzy +msgid "git rm [options] [--] <file>..." +msgstr "git apply [选项] [<è¡¥ä¸>...]" + #: builtin/rm.c:109 #, c-format msgid "" @@ -4530,6 +7979,28 @@ msgstr "" "'%s' 有本地修改\n" "(使用 --cached ä¿å˜æ–‡ä»¶ï¼Œæˆ–用 -f å¼ºåˆ¶åˆ é™¤ï¼‰" +#: builtin/rm.c:134 +#, fuzzy +msgid "do not list removed files" +msgstr "æ— æ³•è¿˜åŽŸä¿®æ”¹çš„æ–‡ä»¶" + +#: builtin/rm.c:135 +#, fuzzy +msgid "only remove from the index" +msgstr "ä¸èƒ½ä»Žç´¢å¼•ä¸ç§»é™¤ %s" + +#: builtin/rm.c:136 +msgid "override the up-to-date check" +msgstr "" + +#: builtin/rm.c:137 +msgid "allow recursive removal" +msgstr "" + +#: builtin/rm.c:139 +msgid "exit with a zero status even if nothing matched" +msgstr "" + #: builtin/rm.c:194 #, c-format msgid "not removing '%s' recursively without -r" @@ -4540,11 +8011,199 @@ msgstr "未æä¾› -r 选项ä¸ä¼šé€’å½’åˆ é™¤ '%s'" msgid "git rm: unable to remove %s" msgstr "git rm:ä¸èƒ½åˆ 除 %s" +#: builtin/shortlog.c:13 +msgid "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]" +msgstr "" + #: builtin/shortlog.c:157 #, c-format msgid "Missing author: %s" msgstr "缺少作者:%s" +#: builtin/shortlog.c:253 +msgid "sort output according to the number of commits per author" +msgstr "" + +#: builtin/shortlog.c:255 +msgid "Suppress commit descriptions, only provides commit count" +msgstr "" + +#: builtin/shortlog.c:257 +msgid "Show the email address of each author" +msgstr "" + +#: builtin/shortlog.c:258 +msgid "w[,i1[,i2]]" +msgstr "" + +#: builtin/shortlog.c:259 +msgid "Linewrap output" +msgstr "" + +#: builtin/show-branch.c:9 +msgid "" +"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--" +"current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --" +"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | " +"<glob>)...]" +msgstr "" + +#: builtin/show-branch.c:10 +msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]" +msgstr "" + +#: builtin/show-branch.c:651 +#, fuzzy +msgid "show remote-tracking and local branches" +msgstr "%s 没有æ¥è‡ª %s 的远程跟踪分支" + +#: builtin/show-branch.c:653 +#, fuzzy +msgid "show remote-tracking branches" +msgstr "%s 没有æ¥è‡ª %s 的远程跟踪分支" + +#: builtin/show-branch.c:655 +msgid "color '*!+-' corresponding to the branch" +msgstr "" + +#: builtin/show-branch.c:657 +msgid "show <n> more commits after the common ancestor" +msgstr "" + +#: builtin/show-branch.c:659 +msgid "synonym to more=-1" +msgstr "" + +#: builtin/show-branch.c:660 +msgid "suppress naming strings" +msgstr "" + +#: builtin/show-branch.c:662 +#, fuzzy +msgid "include the current branch" +msgstr "没有当å‰åˆ†æ”¯ã€‚" + +#: builtin/show-branch.c:664 +#, fuzzy +msgid "name commits with their object names" +msgstr "ä¸èƒ½å†™æ³¨è§£å¯¹è±¡" + +#: builtin/show-branch.c:666 +msgid "show possible merge bases" +msgstr "" + +#: builtin/show-branch.c:668 +msgid "show refs unreachable from any other ref" +msgstr "" + +#: builtin/show-branch.c:670 +msgid "show commits in topological order" +msgstr "" + +#: builtin/show-branch.c:672 +msgid "show only commits not on the first branch" +msgstr "" + +#: builtin/show-branch.c:674 +msgid "show merges reachable from only one tip" +msgstr "" + +#: builtin/show-branch.c:676 +msgid "show commits where no parent comes before its children" +msgstr "" + +#: builtin/show-branch.c:678 +msgid "<n>[,<base>]" +msgstr "" + +#: builtin/show-branch.c:679 +msgid "show <n> most recent ref-log entries starting at base" +msgstr "" + +#: builtin/show-ref.c:10 +msgid "" +"git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash" +"[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] " +msgstr "" + +#: builtin/show-ref.c:11 +msgid "git show-ref --exclude-existing[=pattern] < ref-list" +msgstr "" + +#: builtin/show-ref.c:182 +#, fuzzy +msgid "only show tags (can be combined with heads)" +msgstr "--all ä¸èƒ½å’Œå¼•用表达å¼åŒæ—¶ä½¿ç”¨" + +#: builtin/show-ref.c:183 +#, fuzzy +msgid "only show heads (can be combined with tags)" +msgstr "--all ä¸èƒ½å’Œå¼•用表达å¼åŒæ—¶ä½¿ç”¨" + +#: builtin/show-ref.c:184 +msgid "stricter reference checking, requires exact ref path" +msgstr "" + +#: builtin/show-ref.c:187 builtin/show-ref.c:189 +msgid "show the HEAD reference" +msgstr "" + +#: builtin/show-ref.c:191 +#, fuzzy +msgid "dereference tags into object IDs" +msgstr "å¼•ç”¨ä¸æ˜¯ä¸€ä¸ªæ ‘:%s" + +#: builtin/show-ref.c:193 +msgid "only show SHA1 hash using <n> digits" +msgstr "" + +#: builtin/show-ref.c:197 +msgid "do not print results to stdout (useful with --verify)" +msgstr "" + +#: builtin/show-ref.c:199 +msgid "show refs from stdin that aren't in local repository" +msgstr "" + +#: builtin/symbolic-ref.c:7 +msgid "git symbolic-ref [options] name [ref]" +msgstr "" + +#: builtin/symbolic-ref.c:38 +msgid "suppress error message for non-symbolic (detached) refs" +msgstr "" + +#: builtin/symbolic-ref.c:39 +msgid "shorten ref output" +msgstr "" + +#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18 +msgid "reason" +msgstr "" + +#: builtin/symbolic-ref.c:40 builtin/update-ref.c:18 +msgid "reason of the update" +msgstr "" + +#: builtin/tag.c:22 +msgid "" +"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]" +msgstr "" + +#: builtin/tag.c:23 +msgid "git tag -d <tagname>..." +msgstr "" + +#: builtin/tag.c:24 +msgid "" +"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] \n" +"\t\t[<pattern>...]" +msgstr "" + +#: builtin/tag.c:26 +msgid "git tag -v <tagname>..." +msgstr "" + #: builtin/tag.c:60 #, c-format msgid "malformed object at '%s'" @@ -4633,21 +8292,81 @@ msgstr "开关 'points-at' 需è¦ä¸€ä¸ªå¯¹è±¡" msgid "malformed object name '%s'" msgstr "éžæ³•的对象å '%s'" +#: builtin/tag.c:447 +msgid "list tag names" +msgstr "" + +#: builtin/tag.c:449 +msgid "print <n> lines of each tag message" +msgstr "" + +#: builtin/tag.c:451 +#, fuzzy +msgid "delete tags" +msgstr "åˆ é™¤" + +#: builtin/tag.c:452 +msgid "verify tags" +msgstr "" + +#: builtin/tag.c:454 +msgid "Tag creation options" +msgstr "" + +#: builtin/tag.c:456 +#, fuzzy +msgid "annotated tag, needs a message" +msgstr "注释 tag %s 没有嵌入åç§°" + +#: builtin/tag.c:458 +#, fuzzy +msgid "tag message" +msgstr "æ— tag 说明?" + +#: builtin/tag.c:460 +msgid "annotated and GPG-signed tag" +msgstr "" + +#: builtin/tag.c:464 +#, fuzzy +msgid "use another key to sign the tag" +msgstr "æ— æ³•ç¾ç½² tag" + +#: builtin/tag.c:465 +msgid "replace the tag if exists" +msgstr "" + +#: builtin/tag.c:466 +msgid "show tag list in columns" +msgstr "" + +#: builtin/tag.c:468 +msgid "Tag listing options" +msgstr "" + +#: builtin/tag.c:471 +msgid "print only tags that contain the commit" +msgstr "" + +#: builtin/tag.c:477 +msgid "print only tags of the object" +msgstr "" + #: builtin/tag.c:506 msgid "--column and -n are incompatible" msgstr "--column å’Œ -n ä¸å…¼å®¹" #: builtin/tag.c:523 msgid "-n option is only allowed with -l." -msgstr "-n 选项åªå…许和 -l 共用。" +msgstr "-n 选项åªå…许和 -l åŒæ—¶ä½¿ç”¨ã€‚" #: builtin/tag.c:525 msgid "--contains option is only allowed with -l." -msgstr "--contains 选项åªå…许和 -l 共用。" +msgstr "--contains 选项åªå…许和 -l åŒæ—¶ä½¿ç”¨ã€‚" #: builtin/tag.c:527 msgid "--points-at option is only allowed with -l." -msgstr "--points-at 选项åªå…许和 -l 共用。" +msgstr "--points-at 选项åªå…许和 -l åŒæ—¶ä½¿ç”¨ã€‚" #: builtin/tag.c:535 msgid "only one -F or -m option is allowed." @@ -4682,25 +8401,187 @@ msgstr "%s:ä¸èƒ½æ›´æ–°å¼•用" msgid "Updated tag '%s' (was %s)\n" msgstr "已更新tag '%s'(曾为 %s)\n" -#: git.c:16 -msgid "See 'git help <command>' for more information on a specific command." -msgstr "å‚è§ 'git help <command>' 以获得该特定命令的详细信æ¯ã€‚" +#: builtin/update-index.c:401 +#, fuzzy +msgid "git update-index [options] [--] [<file>...]" +msgstr "git apply [选项] [<è¡¥ä¸>...]" -#: parse-options.h:133 parse-options.h:235 -msgid "n" -msgstr "æ•°å—" +#: builtin/update-index.c:717 +msgid "continue refresh even when index needs update" +msgstr "" -#: parse-options.h:141 -msgid "time" -msgstr "æ—¶é—´" +#: builtin/update-index.c:720 +msgid "refresh: ignore submodules" +msgstr "" -#: parse-options.h:149 -msgid "file" -msgstr "文件" +#: builtin/update-index.c:723 +#, fuzzy +msgid "do not ignore new files" +msgstr "æ— æ³•å˜å‚¨ç´¢å¼•文件" -#: parse-options.h:151 -msgid "when" -msgstr "何时" +#: builtin/update-index.c:725 +msgid "let files replace directories and vice-versa" +msgstr "" + +#: builtin/update-index.c:727 +msgid "notice files missing from worktree" +msgstr "" + +#: builtin/update-index.c:729 +msgid "refresh even if index contains unmerged entries" +msgstr "" + +#: builtin/update-index.c:732 +msgid "refresh stat information" +msgstr "" + +#: builtin/update-index.c:736 +msgid "like --refresh, but ignore assume-unchanged setting" +msgstr "" + +#: builtin/update-index.c:740 +msgid "<mode> <object> <path>" +msgstr "" + +#: builtin/update-index.c:741 +#, fuzzy +msgid "add the specified entry to the index" +msgstr "æ·»åŠ æ–‡ä»¶å†…å®¹è‡³ç´¢å¼•" + +#: builtin/update-index.c:745 +msgid "(+/-)x" +msgstr "" + +#: builtin/update-index.c:746 +msgid "override the executable bit of the listed files" +msgstr "" + +#: builtin/update-index.c:750 +msgid "mark files as \"not changing\"" +msgstr "" + +#: builtin/update-index.c:753 +msgid "clear assumed-unchanged bit" +msgstr "" + +#: builtin/update-index.c:756 +msgid "mark files as \"index-only\"" +msgstr "" + +#: builtin/update-index.c:759 +msgid "clear skip-worktree bit" +msgstr "" + +#: builtin/update-index.c:762 +msgid "add to index only; do not add content to object database" +msgstr "" + +#: builtin/update-index.c:764 +msgid "remove named paths even if present in worktree" +msgstr "" + +#: builtin/update-index.c:766 +msgid "with --stdin: input lines are terminated by null bytes" +msgstr "" + +#: builtin/update-index.c:768 +#, fuzzy +msgid "read list of paths to be updated from standard input" +msgstr "(æ£ä»Žæ ‡å‡†è¾“å…¥ä¸è¯»å–日志信æ¯ï¼‰\n" + +#: builtin/update-index.c:772 +#, fuzzy +msgid "add entries from standard input to the index" +msgstr "ä¸èƒ½ä»Žæ ‡å‡†è¾“å…¥ä¸è¯»å–日志信æ¯" + +#: builtin/update-index.c:776 +msgid "repopulate stages #2 and #3 for the listed paths" +msgstr "" + +#: builtin/update-index.c:780 +msgid "only update entries that differ from HEAD" +msgstr "" + +#: builtin/update-index.c:784 +msgid "ignore files missing from worktree" +msgstr "" + +#: builtin/update-index.c:787 +msgid "report actions to standard output" +msgstr "" + +#: builtin/update-index.c:789 +msgid "(for porcelains) forget saved unresolved conflicts" +msgstr "" + +#: builtin/update-index.c:793 +msgid "write index in this format" +msgstr "" + +#: builtin/update-ref.c:7 +msgid "git update-ref [options] -d <refname> [<oldval>]" +msgstr "" + +#: builtin/update-ref.c:8 +msgid "git update-ref [options] <refname> <newval> [<oldval>]" +msgstr "" + +#: builtin/update-ref.c:19 +msgid "delete the reference" +msgstr "" + +#: builtin/update-ref.c:21 +msgid "update <refname> not the one it points to" +msgstr "" + +#: builtin/update-server-info.c:6 +msgid "git update-server-info [--force]" +msgstr "" + +#: builtin/update-server-info.c:14 +msgid "update the info files from scratch" +msgstr "" + +#: builtin/verify-pack.c:56 +msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..." +msgstr "" + +#: builtin/verify-pack.c:66 +#, fuzzy +msgid "verbose" +msgstr "冗长输出" + +#: builtin/verify-pack.c:68 +msgid "show statistics only" +msgstr "" + +#: builtin/verify-tag.c:17 +msgid "git verify-tag [-v|--verbose] <tag>..." +msgstr "" + +#: builtin/verify-tag.c:73 +msgid "print tag contents" +msgstr "" + +#: builtin/write-tree.c:13 +msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]" +msgstr "" + +#: builtin/write-tree.c:26 +msgid "<prefix>/" +msgstr "" + +#: builtin/write-tree.c:27 +msgid "write tree object for a subdirectory <prefix>" +msgstr "" + +#: builtin/write-tree.c:30 +msgid "only useful for debugging" +msgstr "" + +#: git.c:16 +msgid "See 'git help <command>' for more information on a specific command." +msgstr "å‚è§ 'git help <command>' 以获得该特定命令的详细信æ¯ã€‚" #: parse-options.h:156 msgid "no-op (backward compatibility)" @@ -4810,15 +8691,14 @@ msgstr "您需è¦å…ˆè®¾ç½®ä½ çš„æäº¤è€…ä¿¡æ¯" msgid "" "You seem to have moved HEAD since the last 'am' failure.\n" "Not rewinding to ORIG_HEAD" -msgstr "" -"您好åƒåœ¨ä¸Šä¸€æ¬¡ 'am' 失败åŽç§»åŠ¨äº† HEAD。未回退至 ORIG_HEAD" +msgstr "您好åƒåœ¨ä¸Šä¸€æ¬¡ 'am' 失败åŽç§»åŠ¨äº† HEAD。未回退至 ORIG_HEAD" #: git-am.sh:105 #, sh-format msgid "" -"When you have resolved this problem run \"$cmdline --resolved\".\n" -"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n" -"To restore the original branch and stop patching run \"$cmdline --abort\"." +"When you have resolved this problem, run \"$cmdline --resolved\".\n" +"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n" +"To restore the original branch and stop patching, run \"$cmdline --abort\"." msgstr "" "当您解决了æ¤é—®é¢˜åŽï¼Œæ‰§è¡Œ \"$cmdline --resolved\"。\n" "如果您想跳过æ¤è¡¥ä¸ï¼Œåˆ™æ‰§è¡Œ \"$cmdline --skip\"。\n" @@ -4830,7 +8710,11 @@ msgstr "æ— æ³•æ±‚åŠ©äºŽä¸‰è·¯åˆå¹¶ã€‚" #: git-am.sh:137 msgid "Repository lacks necessary blobs to fall back on 3-way merge." -msgstr "版本库缺ä¹å¿…è¦çš„ blob æ•°æ®ä»¥è¿›è¡Œä¸‰è·¯åˆå¹¶ã€‚" +msgstr "版本库缺ä¹å¿…è¦çš„二进制对象(blob)以进行三路åˆå¹¶ã€‚" + +#: git-am.sh:139 +msgid "Using index info to reconstruct a base tree..." +msgstr "更新索引信æ¯ä»¥é‡å»ºåŸºæ ‘..." #: git-am.sh:154 msgid "" @@ -4838,48 +8722,56 @@ msgid "" "It does not apply to blobs recorded in its index." msgstr "" "æ‚¨æ˜¯å¦æ›¾æ‰‹åŠ¨ç¼–è¾‘è¿‡æ‚¨çš„è¡¥ä¸ï¼Ÿ\n" -"æ— æ³•åº”ç”¨è¡¥ä¸åˆ°ç´¢å¼•ä¸çš„æ•°æ®ä¸Šã€‚" +"æ— æ³•åº”ç”¨è¡¥ä¸åˆ°ç´¢å¼•ä¸çš„二进制对象(blob)上。" #: git-am.sh:163 msgid "Falling back to patching base and 3-way merge..." msgstr "转而在基础版本上打补ä¸åŠè¿›è¡Œä¸‰è·¯åˆå¹¶..." -#: git-am.sh:275 +#: git-am.sh:179 +msgid "Failed to merge in the changes." +msgstr "æ— æ³•åˆå¹¶å˜æ›´ã€‚" + +#: git-am.sh:274 msgid "Only one StGIT patch series can be applied at once" msgstr "一次åªèƒ½æœ‰ä¸€ä¸ª StGIT è¡¥ä¸é˜Ÿåˆ—被应用" -#: git-am.sh:362 +#: git-am.sh:361 #, sh-format msgid "Patch format $patch_format is not supported." msgstr "䏿”¯æŒ $patch_format è¡¥ä¸æ ¼å¼ã€‚" -#: git-am.sh:364 +#: git-am.sh:363 msgid "Patch format detection failed." msgstr "è¡¥ä¸æ ¼å¼æ£€æµ‹å¤±è´¥ã€‚" -#: git-am.sh:418 -msgid "-d option is no longer supported. Do not use." -msgstr "ä¸å†æ”¯æŒ -d 选项。ä¸è¦ä½¿ç”¨ã€‚" +#: git-am.sh:389 +msgid "" +"The -b/--binary option has been a no-op for long time, and\n" +"it will be removed. Please do not use it anymore." +msgstr "" +"傿•° -b/--binary å·²ç»å¾ˆé•¿æ—¶é—´ä¸åšä»»ä½•实质æ“ä½œäº†ï¼Œå¹¶ä¸”å°†è¢«åˆ é™¤ã€‚\n" +"请ä¸è¦å†ä½¿ç”¨å®ƒäº†ã€‚" -#: git-am.sh:481 +#: git-am.sh:477 #, sh-format msgid "previous rebase directory $dotest still exists but mbox given." msgstr "之å‰çš„å˜åŸºç›®å½• $dotest ä»ç„¶å˜åœ¨ä½†ç»™å‡ºäº†mbox。" -#: git-am.sh:486 +#: git-am.sh:482 msgid "Please make up your mind. --skip or --abort?" msgstr "请下决心。--skip 或是 --abort ?" -#: git-am.sh:513 +#: git-am.sh:509 msgid "Resolve operation not in progress, we are not resuming." msgstr "解决æ“作未进行,我们ä¸ä¼šç»§ç»ã€‚" -#: git-am.sh:579 +#: git-am.sh:575 #, sh-format msgid "Dirty index: cannot apply patches (dirty: $files)" msgstr "è„的索引:ä¸èƒ½åº”用补ä¸ï¼ˆè„文件:$files)" -#: git-am.sh:671 +#: git-am.sh:679 #, sh-format msgid "" "Patch is empty. Was it split wrong?\n" @@ -4890,15 +8782,15 @@ msgstr "" "如果您想è¦è·³è¿‡è¿™ä¸ªè¡¥ä¸ï¼Œæ‰§è¡Œ \"$cmdline --skip\"。\n" "è¦æ¢å¤åŽŸåˆ†æ”¯å¹¶åœæ¢æ‰“è¡¥ä¸ï¼Œæ‰§è¡Œ \"$cmdline --abort\"。" -#: git-am.sh:708 +#: git-am.sh:706 msgid "Patch does not have a valid e-mail address." msgstr "è¡¥ä¸ä¸æ²¡æœ‰ä¸€ä¸ªæœ‰æ•ˆçš„邮件地å€ã€‚" -#: git-am.sh:755 +#: git-am.sh:753 msgid "cannot be interactive without stdin connected to a terminal." msgstr "æ ‡å‡†è¾“å…¥æ²¡æœ‰å’Œç»ˆç«¯å…³è”,ä¸èƒ½è¿›è¡Œäº¤äº’弿“作。" -#: git-am.sh:759 +#: git-am.sh:757 msgid "Commit Body is:" msgstr "æäº¤å†…容为:" @@ -4906,16 +8798,16 @@ msgstr "æäº¤å†…容为:" #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] #. in your translation. The program will only accept English #. input at this point. -#: git-am.sh:766 +#: git-am.sh:764 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " msgstr "应用?[y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " -#: git-am.sh:802 +#: git-am.sh:800 #, sh-format msgid "Applying: $FIRSTLINE" msgstr "æ£åº”用:$FIRSTLINE" -#: git-am.sh:823 +#: git-am.sh:821 msgid "" "No changes - did you forget to use 'git add'?\n" "If there is nothing left to stage, chances are that something else\n" @@ -4925,23 +8817,29 @@ msgstr "" "å¦‚æžœæ²¡æœ‰ä»€ä¹ˆè¦æ·»åŠ åˆ°æš‚å˜åŒºçš„,则很å¯èƒ½æ˜¯å…¶å®ƒæäº¤å·²ç»å¼•入了相åŒçš„å˜æ›´ã€‚\n" "您也许想è¦è·³è¿‡è¿™ä¸ªè¡¥ä¸ã€‚" -#: git-am.sh:831 +#: git-am.sh:829 msgid "" "You still have unmerged paths in your index\n" "did you forget to use 'git add'?" -msgstr "" -"您的索引ä¸ä»æœ‰æœªåˆå¹¶çš„路径。您是å¦å¿˜äº†æ‰§è¡Œ 'git add'?" +msgstr "您的索引ä¸ä»æœ‰æœªåˆå¹¶çš„路径。您是å¦å¿˜äº†æ‰§è¡Œ 'git add'?" -#: git-am.sh:847 +#: git-am.sh:845 msgid "No changes -- Patch already applied." msgstr "æ²¡æœ‰å˜æ›´ -- è¡¥ä¸å·²ç»åº”用过。" -#: git-am.sh:857 +#: git-am.sh:855 #, sh-format msgid "Patch failed at $msgnum $FIRSTLINE" msgstr "è¡¥ä¸å¤±è´¥äºŽ $msgnum $FIRSTLINE" -#: git-am.sh:873 +#: git-am.sh:858 +#, sh-format +msgid "" +"The copy of the patch that failed is found in:\n" +" $dotest/patch" +msgstr "" + +#: git-am.sh:876 msgid "applying to an empty history" msgstr "æ£åº”用到一个空历å²ä¸Š" @@ -5142,6 +9040,123 @@ msgstr "æ— æ³•å°†å¤šä¸ªåˆ†æ”¯åˆå¹¶åˆ°ç©ºåˆ†æ”¯" msgid "Cannot rebase onto multiple branches" msgstr "æ— æ³•å˜åŸºåˆ°å¤šä¸ªåˆ†æ”¯" +#: git-rebase.sh:52 +msgid "" +"When you have resolved this problem, run \"git rebase --continue\".\n" +"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n" +"To check out the original branch and stop rebasing, run \"git rebase --abort" +"\"." +msgstr "" +"当您解决了æ¤é—®é¢˜åŽï¼Œæ‰§è¡Œ \"git rebase --continue\"。\n" +"如果您想跳过æ¤è¡¥ä¸ï¼Œåˆ™æ‰§è¡Œ \"git rebase --skip\"。\n" +"è¦æ¢å¤åŽŸåˆ†æ”¯å¹¶åœæ¢å˜åŸºï¼Œæ‰§è¡Œ \"git rebase --abort\"。" + +#: git-rebase.sh:159 +msgid "The pre-rebase hook refused to rebase." +msgstr "é’©å pre-rebase æ‹’ç»å˜åŸºã€‚" + +#: git-rebase.sh:164 +msgid "It looks like git-am is in progress. Cannot rebase." +msgstr "似乎æ£å¤„于在 git-am 的执行过程ä¸ã€‚æ— æ³•å˜åŸºã€‚" + +#: git-rebase.sh:295 +msgid "The --exec option must be used with the --interactive option" +msgstr "选项 --exec 必须和选项 --interactive åŒæ—¶ä½¿ç”¨" + +#: git-rebase.sh:300 +msgid "No rebase in progress?" +msgstr "没有æ£åœ¨è¿›è¡Œçš„å˜åŸºï¼Ÿ" + +#: git-rebase.sh:313 +msgid "Cannot read HEAD" +msgstr "ä¸èƒ½è¯»å– HEAD" + +#: git-rebase.sh:316 +msgid "" +"You must edit all merge conflicts and then\n" +"mark them as resolved using git add" +msgstr "" +"您必须编辑所有的åˆå¹¶å†²çªï¼Œç„¶åŽé€šè¿‡ git add\n" +"å‘½ä»¤å°†å®ƒä»¬æ ‡è®°ä¸ºå·²è§£å†³" + +#: git-rebase.sh:334 +#, sh-format +msgid "Could not move back to $head_name" +msgstr "æ— æ³•ç§»å›ž $head_name" + +#: git-rebase.sh:350 +#, sh-format +msgid "" +"It seems that there is already a $state_dir_base directory, and\n" +"I wonder if you are in the middle of another rebase. If that is the\n" +"case, please try\n" +"\t$cmd_live_rebase\n" +"If that is not the case, please\n" +"\t$cmd_clear_stale_rebase\n" +"and run me again. I am stopping in case you still have something\n" +"valuable there." +msgstr "" +"好åƒå·²æœ‰ä¸€ä¸ª $state_dir_base 目录,我怀疑您æ£å¤„于å¦å¤–一个å˜åŸºè¿‡ç¨‹ä¸ã€‚\n" +"å¦‚æžœæ˜¯è¿™æ ·ï¼Œè¯·å°è¯•执行\n" +"\t$cmd_live_rebase\n" +"å¦‚æžœä¸æ˜¯è¿™æ ·ï¼Œè¯·æ‰§è¡Œ\n" +"\t$cmd_clear_stale_rebase\n" +"ç„¶åŽå†é‡æ–°æ‰§è¡Œå˜åŸºã€‚为é¿å…您丢失é‡è¦æ•°æ®ï¼Œæˆ‘å·²ç»åœæ¢å½“剿“作。" + +#: git-rebase.sh:395 +#, sh-format +msgid "invalid upstream $upstream_name" +msgstr "æ— æ•ˆçš„ä¸Šæ¸¸ $upstream_name" + +#: git-rebase.sh:419 +#, sh-format +msgid "$onto_name: there are more than one merge bases" +msgstr "$onto_name: 有一个以上的åˆå¹¶åŸºå‡†" + +#: git-rebase.sh:422 git-rebase.sh:426 +#, sh-format +msgid "$onto_name: there is no merge base" +msgstr "$onto_name: 没有åˆå¹¶åŸºå‡†" + +#: git-rebase.sh:431 +#, sh-format +msgid "Does not point to a valid commit: $onto_name" +msgstr "没有指å‘一个有效的æäº¤ï¼š$onto_name" + +#: git-rebase.sh:454 +#, sh-format +msgid "fatal: no such branch: $branch_name" +msgstr "严é‡é”™è¯¯ï¼šæ— æ¤åˆ†æ”¯ï¼š$branch_name" + +#: git-rebase.sh:474 +msgid "Please commit or stash them." +msgstr "请æäº¤æˆ–为它们ä¿å˜è¿›åº¦ã€‚" + +#: git-rebase.sh:492 +#, sh-format +msgid "Current branch $branch_name is up to date." +msgstr "当å‰åˆ†æ”¯ $branch_name 是最新的。" + +#: git-rebase.sh:495 +#, sh-format +msgid "Current branch $branch_name is up to date, rebase forced." +msgstr "当å‰åˆ†æ”¯ $branch_name 是最新的,强制å˜åŸºã€‚" + +#: git-rebase.sh:506 +#, sh-format +msgid "Changes from $mb to $onto:" +msgstr "å˜æ›´ä»Ž $mb 到 $onto:" + +#. Detach HEAD and reset the tree +#: git-rebase.sh:515 +msgid "First, rewinding head to replay your work on top of it..." +msgstr "首先,é‡ç½®å¤´æŒ‡é’ˆä»¥ä¾¿åœ¨ä¸Šé¢é‡æ”¾æ‚¨çš„工作..." + +#: git-rebase.sh:523 +#, sh-format +msgid "Fast-forwarded $branch_name to $onto_name." +msgstr "å¿«è¿› $branch_name 至 $onto_name。" + #: git-stash.sh:51 msgid "git stash clear with parameters is unimplemented" msgstr "git stash clear 䏿”¯æŒå‚æ•°" @@ -5249,59 +9264,59 @@ msgstr "ä¸èƒ½ä¿å˜ç´¢å¼•æ ‘" msgid "Cannot unstage modified files" msgstr "æ— æ³•è¿˜åŽŸä¿®æ”¹çš„æ–‡ä»¶" -#: git-stash.sh:474 +#: git-stash.sh:475 msgid "Index was not unstashed." msgstr "索引的进度没有被æ¢å¤ã€‚" -#: git-stash.sh:491 +#: git-stash.sh:492 #, sh-format msgid "Dropped ${REV} ($s)" msgstr "丢弃了 ${REV} ($s)" -#: git-stash.sh:492 +#: git-stash.sh:493 #, sh-format msgid "${REV}: Could not drop stash entry" msgstr "${REV}:ä¸èƒ½ä¸¢å¼ƒè¿›åº¦æ¡ç›®" -#: git-stash.sh:499 +#: git-stash.sh:500 msgid "No branch name specified" msgstr "未指定分支å" -#: git-stash.sh:570 +#: git-stash.sh:571 msgid "(To restore them type \"git stash apply\")" msgstr "(为æ¢å¤æ•°æ®è¾“å…¥ \"git stash apply\")" -#: git-submodule.sh:56 +#: git-submodule.sh:88 #, sh-format msgid "cannot strip one component off url '$remoteurl'" msgstr "æ— æ³•ä»Ž url '$remoteurl' 剥离一个组件" -#: git-submodule.sh:109 +#: git-submodule.sh:167 #, sh-format msgid "No submodule mapping found in .gitmodules for path '$sm_path'" msgstr "未在 .gitmodules ä¸å‘现路径 '$sm_path' çš„åæ¨¡ç»„æ˜ å°„" -#: git-submodule.sh:150 +#: git-submodule.sh:211 #, sh-format msgid "Clone of '$url' into submodule path '$sm_path' failed" msgstr "æ— æ³•å…‹éš† '$url' åˆ°åæ¨¡ç»„路径 '$sm_path'" -#: git-submodule.sh:160 +#: git-submodule.sh:223 #, sh-format msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa" msgstr "Gitdir '$a' åœ¨åæ¨¡ç»„路径 '$b' 之下或者相å" -#: git-submodule.sh:249 +#: git-submodule.sh:312 #, sh-format msgid "repo URL: '$repo' must be absolute or begin with ./|../" msgstr "版本库URL:'$repo' 必须是ç»å¯¹è·¯å¾„或以 ./|../ èµ·å§‹" -#: git-submodule.sh:266 +#: git-submodule.sh:329 #, sh-format msgid "'$sm_path' already exists in the index" msgstr "'$sm_path' å·²ç»å˜åœ¨äºŽç´¢å¼•ä¸" -#: git-submodule.sh:270 +#: git-submodule.sh:333 #, sh-format msgid "" "The following path is ignored by one of your .gitignore files:\n" @@ -5312,62 +9327,62 @@ msgstr "" "$sm_path\n" "å¦‚æžœæ‚¨ç¡®å®žæƒ³æ·»åŠ å®ƒï¼Œä½¿ç”¨ -f 傿•°ã€‚" -#: git-submodule.sh:281 +#: git-submodule.sh:344 #, sh-format msgid "Adding existing repo at '$sm_path' to the index" msgstr "æ·»åŠ ä½äºŽ '$sm_path' 的现å˜ç‰ˆæœ¬åº“到索引" -#: git-submodule.sh:283 +#: git-submodule.sh:346 #, sh-format msgid "'$sm_path' already exists and is not a valid git repo" msgstr "'$sm_path' å·²å˜åœ¨ä¸”䏿˜¯ä¸€ä¸ªæœ‰æ•ˆçš„ git 版本库" -#: git-submodule.sh:297 +#: git-submodule.sh:360 #, sh-format msgid "Unable to checkout submodule '$sm_path'" msgstr "ä¸èƒ½æ£€å‡ºå模组 '$sm_path'" -#: git-submodule.sh:302 +#: git-submodule.sh:365 #, sh-format msgid "Failed to add submodule '$sm_path'" msgstr "æ— æ³•æ·»åŠ åæ¨¡ç»„ '$sm_path'" -#: git-submodule.sh:307 +#: git-submodule.sh:370 #, sh-format msgid "Failed to register submodule '$sm_path'" msgstr "æ— æ³•æ³¨å†Œåæ¨¡ç»„ '$sm_path'" -#: git-submodule.sh:349 +#: git-submodule.sh:413 #, sh-format msgid "Entering '$prefix$sm_path'" msgstr "æ£åœ¨è¿›å…¥ '$prefix$sm_path'" -#: git-submodule.sh:363 +#: git-submodule.sh:427 #, sh-format msgid "Stopping at '$sm_path'; script returned non-zero status." msgstr "åœæ¢äºŽ '$sm_path',脚本返回éžé›¶å€¼ã€‚" -#: git-submodule.sh:406 +#: git-submodule.sh:471 #, sh-format msgid "No url found for submodule path '$sm_path' in .gitmodules" msgstr "在 .gitmodules 䏿œªæ‰¾åˆ°å模组路径 '$sm_path' çš„ url" -#: git-submodule.sh:415 +#: git-submodule.sh:480 #, sh-format msgid "Failed to register url for submodule path '$sm_path'" msgstr "æ— æ³•ä¸ºåæ¨¡ç»„路径 '$sm_path' 注册 url" -#: git-submodule.sh:417 +#: git-submodule.sh:482 #, sh-format msgid "Submodule '$name' ($url) registered for path '$sm_path'" msgstr "忍¡ç»„ '$name' ($url) 已为路径 '$sm_path' 注册" -#: git-submodule.sh:425 +#: git-submodule.sh:490 #, sh-format msgid "Failed to register update mode for submodule path '$sm_path'" msgstr "æ— æ³•ä¸ºåæ¨¡ç»„路径 '$sm_path' 注册更新模å¼" -#: git-submodule.sh:524 +#: git-submodule.sh:590 #, sh-format msgid "" "Submodule path '$sm_path' not initialized\n" @@ -5376,96 +9391,130 @@ msgstr "" "忍¡ç»„路径 '$sm_path' 没有åˆå§‹åŒ–\n" "也许您想用 'update --init'?" -#: git-submodule.sh:537 +#: git-submodule.sh:603 #, sh-format msgid "Unable to find current revision in submodule path '$sm_path'" msgstr "æ— æ³•åœ¨åæ¨¡ç»„路径 '$sm_path' 䏿‰¾åˆ°å½“å‰ç‰ˆæœ¬" -#: git-submodule.sh:556 +#: git-submodule.sh:622 #, sh-format msgid "Unable to fetch in submodule path '$sm_path'" msgstr "æ— æ³•åœ¨åæ¨¡ç»„路径 '$sm_path' ä¸èŽ·å–" -#: git-submodule.sh:570 +#: git-submodule.sh:636 #, sh-format msgid "Unable to rebase '$sha1' in submodule path '$sm_path'" msgstr "æ— æ³•åœ¨åæ¨¡ç»„路径 '$sm_path' ä¸å˜åŸº '$sha1'" -#: git-submodule.sh:571 +#: git-submodule.sh:637 #, sh-format msgid "Submodule path '$sm_path': rebased into '$sha1'" msgstr "忍¡ç»„路径 '$sm_path':å˜åŸºè‡³ '$sha1'" -#: git-submodule.sh:576 +#: git-submodule.sh:642 #, sh-format msgid "Unable to merge '$sha1' in submodule path '$sm_path'" msgstr "æ— æ³•åˆå¹¶ '$sha1' åˆ°åæ¨¡ç»„路径 '$sm_path' ä¸" -#: git-submodule.sh:577 +#: git-submodule.sh:643 #, sh-format msgid "Submodule path '$sm_path': merged in '$sha1'" msgstr "忍¡ç»„路径 '$sm_path':已åˆå¹¶å…¥ '$sha1'" -#: git-submodule.sh:582 +#: git-submodule.sh:648 #, sh-format msgid "Unable to checkout '$sha1' in submodule path '$sm_path'" msgstr "æ— æ³•åœ¨åæ¨¡ç»„路径 '$sm_path' 䏿£€å‡º '$sha1'" -#: git-submodule.sh:583 +#: git-submodule.sh:649 #, sh-format msgid "Submodule path '$sm_path': checked out '$sha1'" msgstr "忍¡ç»„路径 '$sm_path':检出 '$sha1'" -#: git-submodule.sh:605 git-submodule.sh:928 +#: git-submodule.sh:671 git-submodule.sh:995 #, sh-format msgid "Failed to recurse into submodule path '$sm_path'" msgstr "æ— æ³•é€’å½’è¿›åæ¨¡ç»„路径 '$sm_path'" -#: git-submodule.sh:713 -msgid "--cached cannot be used with --files" -msgstr "--cached ä¸èƒ½å’Œ --files 共用" +#: git-submodule.sh:779 +msgid "The --cached option cannot be used with the --files option" +msgstr "选项 --cached ä¸èƒ½å’Œé€‰é¡¹ --files åŒæ—¶ä½¿ç”¨" #. unexpected type -#: git-submodule.sh:753 +#: git-submodule.sh:819 #, sh-format msgid "unexpected mode $mod_dst" msgstr "æ„å¤–çš„æ¨¡å¼ $mod_dst" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: git-submodule.sh:771 +#: git-submodule.sh:837 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_src" msgstr " è¦å‘Šï¼š$name æœªåŒ…å«æäº¤ $sha1_src" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: git-submodule.sh:774 +#: git-submodule.sh:840 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_dst" msgstr " è¦å‘Šï¼š$name æœªåŒ…å«æäº¤ $sha1_dst" # 译者:注æ„ä¿æŒå‰å¯¼ç©ºæ ¼ -#: git-submodule.sh:777 +#: git-submodule.sh:843 #, sh-format msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst" msgstr " è¦å‘Šï¼š$name æœªåŒ…å«æäº¤ $sha1_src å’Œ $sha1_dst" -#: git-submodule.sh:802 +#: git-submodule.sh:868 msgid "blob" -msgstr "blob" +msgstr "二进制对象" -#: git-submodule.sh:803 -msgid "submodule" -msgstr "忍¡ç»„" - -#: git-submodule.sh:840 +#: git-submodule.sh:906 msgid "# Submodules changed but not updated:" msgstr "# 忍¡ç»„已修改但尚未更新:" -#: git-submodule.sh:842 +#: git-submodule.sh:908 msgid "# Submodule changes to be committed:" msgstr "è¦æäº¤çš„åæ¨¡ç»„å˜æ›´ï¼š" -#: git-submodule.sh:974 +#: git-submodule.sh:1054 #, sh-format msgid "Synchronizing submodule url for '$name'" msgstr "为 '$name' åŒæ¥å模组 url" + +# è¯‘è€…ï¼šä¸æ–‡å—符串拼接,å¯åˆ 除å‰å¯¼ç©ºæ ¼ +#~ msgid " (use \"git add\" to track)" +#~ msgstr "(使用 \"git add\" 建立跟踪)" + +#~ msgid "-B cannot be used with -b" +#~ msgstr "-B ä¸èƒ½å’Œ -b åŒæ—¶ä½¿ç”¨" + +#~ msgid "--patch is incompatible with all other options" +#~ msgstr "--patch 选项和其他选项ä¸å…¼å®¹" + +#~ msgid "--detach cannot be used with -b/-B/--orphan" +#~ msgstr "--detach ä¸èƒ½å’Œ -b/-B/--orphan åŒæ—¶ä½¿ç”¨" + +#~ msgid "--detach cannot be used with -t" +#~ msgstr "--detach ä¸èƒ½å’Œ -t åŒæ—¶ä½¿ç”¨" + +#~ msgid "--orphan and -b|-B are mutually exclusive" +#~ msgstr "--orphan å’Œ -b|-B 互斥" + +#~ msgid "--orphan cannot be used with -t" +#~ msgstr "--orphan ä¸èƒ½å’Œ -t åŒæ—¶ä½¿ç”¨" + +#~ msgid "git checkout: -f and -m are incompatible" +#~ msgstr "git checkout:-f å’Œ -m ä¸å…¼å®¹" + +#~ msgid "" +#~ "git checkout: updating paths is incompatible with switching branches." +#~ msgstr "git checkout:更新路径和切æ¢åˆ†æ”¯ä¸å…¼å®¹ã€‚" + +#~ msgid "diff setup failed" +#~ msgstr "diff 设置失败" + +#~ msgid "merge-recursive: disk full?" +#~ msgstr "merge-recursive:ç£ç›˜å·²æ»¡ï¼Ÿ" + +#~ msgid "diff_setup_done failed" +#~ msgstr "diff_setup_done 失败" @@ -231,7 +231,7 @@ static int is_rfc822_special(char ch) } } -static int has_rfc822_specials(const char *s, int len) +static int needs_rfc822_quoting(const char *s, int len) { int i; for (i = 0; i < len; i++) @@ -240,6 +240,17 @@ static int has_rfc822_specials(const char *s, int len) return 0; } +static int last_line_length(struct strbuf *sb) +{ + int i; + + /* How many bytes are already used on the last line? */ + for (i = sb->len - 1; i >= 0; i--) + if (sb->buf[i] == '\n') + break; + return sb->len - (i + 1); +} + static void add_rfc822_quoted(struct strbuf *out, const char *s, int len) { int i; @@ -261,57 +272,110 @@ static void add_rfc822_quoted(struct strbuf *out, const char *s, int len) strbuf_addch(out, '"'); } -static int is_rfc2047_special(char ch) +enum rfc2047_type { + RFC2047_SUBJECT, + RFC2047_ADDRESS, +}; + +static int is_rfc2047_special(char ch, enum rfc2047_type type) { - return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_')); + /* + * rfc2047, section 4.2: + * + * 8-bit values which correspond to printable ASCII characters other + * than "=", "?", and "_" (underscore), MAY be represented as those + * characters. (But see section 5 for restrictions.) In + * particular, SPACE and TAB MUST NOT be represented as themselves + * within encoded words. + */ + + /* + * rule out non-ASCII characters and non-printable characters (the + * non-ASCII check should be redundant as isprint() is not localized + * and only knows about ASCII, but be defensive about that) + */ + if (non_ascii(ch) || !isprint(ch)) + return 1; + + /* + * rule out special printable characters (' ' should be the only + * whitespace character considered printable, but be defensive and use + * isspace()) + */ + if (isspace(ch) || ch == '=' || ch == '?' || ch == '_') + return 1; + + /* + * rfc2047, section 5.3: + * + * As a replacement for a 'word' entity within a 'phrase', for example, + * one that precedes an address in a From, To, or Cc header. The ABNF + * definition for 'phrase' from RFC 822 thus becomes: + * + * phrase = 1*( encoded-word / word ) + * + * In this case the set of characters that may be used in a "Q"-encoded + * 'encoded-word' is restricted to: <upper and lower case ASCII + * letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_" + * (underscore, ASCII 95.)>. An 'encoded-word' that appears within a + * 'phrase' MUST be separated from any adjacent 'word', 'text' or + * 'special' by 'linear-white-space'. + */ + + if (type != RFC2047_ADDRESS) + return 0; + + /* '=' and '_' are special cases and have been checked above */ + return !(isalnum(ch) || ch == '!' || ch == '*' || ch == '+' || ch == '-' || ch == '/'); } -static void add_rfc2047(struct strbuf *sb, const char *line, int len, - const char *encoding) +static int needs_rfc2047_encoding(const char *line, int len, + enum rfc2047_type type) { - static const int max_length = 78; /* per rfc2822 */ int i; - int line_len; - - /* How many bytes are already used on the current line? */ - for (i = sb->len - 1; i >= 0; i--) - if (sb->buf[i] == '\n') - break; - line_len = sb->len - (i+1); for (i = 0; i < len; i++) { int ch = line[i]; if (non_ascii(ch) || ch == '\n') - goto needquote; + return 1; if ((i + 1 < len) && (ch == '=' && line[i+1] == '?')) - goto needquote; + return 1; } - strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len); - return; -needquote: + return 0; +} + +static void add_rfc2047(struct strbuf *sb, const char *line, int len, + const char *encoding, enum rfc2047_type type) +{ + static const int max_encoded_length = 76; /* per rfc2047 */ + int i; + int line_len = last_line_length(sb); + strbuf_grow(sb, len * 3 + strlen(encoding) + 100); strbuf_addf(sb, "=?%s?q?", encoding); line_len += strlen(encoding) + 5; /* 5 for =??q? */ for (i = 0; i < len; i++) { unsigned ch = line[i] & 0xFF; + int is_special = is_rfc2047_special(ch, type); + + /* + * According to RFC 2047, we could encode the special character + * ' ' (space) with '_' (underscore) for readability. But many + * programs do not understand this and just leave the + * underscore in place. Thus, we do nothing special here, which + * causes ' ' to be encoded as '=20', avoiding this problem. + */ - if (line_len >= max_length - 2) { + if (line_len + 2 + (is_special ? 3 : 1) > max_encoded_length) { strbuf_addf(sb, "?=\n =?%s?q?", encoding); line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */ } - /* - * We encode ' ' using '=20' even though rfc2047 - * allows using '_' for readability. Unfortunately, - * many programs do not understand this and just - * leave the underscore in place. - */ - if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') { + if (is_special) { strbuf_addf(sb, "=%02X", ch); line_len += 3; - } - else { + } else { strbuf_addch(sb, ch); line_len++; } @@ -323,6 +387,7 @@ void pp_user_info(const struct pretty_print_context *pp, const char *what, struct strbuf *sb, const char *line, const char *encoding) { + int max_length = 78; /* per rfc2822 */ char *date; int namelen; unsigned long time; @@ -340,25 +405,27 @@ void pp_user_info(const struct pretty_print_context *pp, if (pp->fmt == CMIT_FMT_EMAIL) { char *name_tail = strchr(line, '<'); int display_name_length; - int final_line; if (!name_tail) return; while (line < name_tail && isspace(name_tail[-1])) name_tail--; display_name_length = name_tail - line; strbuf_addstr(sb, "From: "); - if (!has_rfc822_specials(line, display_name_length)) { - add_rfc2047(sb, line, display_name_length, encoding); - } else { + if (needs_rfc2047_encoding(line, display_name_length, RFC2047_ADDRESS)) { + add_rfc2047(sb, line, display_name_length, + encoding, RFC2047_ADDRESS); + max_length = 76; /* per rfc2047 */ + } else if (needs_rfc822_quoting(line, display_name_length)) { struct strbuf quoted = STRBUF_INIT; add_rfc822_quoted("ed, line, display_name_length); - add_rfc2047(sb, quoted.buf, quoted.len, encoding); + strbuf_add_wrapped_bytes(sb, quoted.buf, quoted.len, + -6, 1, max_length); strbuf_release("ed); + } else { + strbuf_add_wrapped_bytes(sb, line, display_name_length, + -6, 1, max_length); } - for (final_line = 0; final_line < sb->len; final_line++) - if (sb->buf[sb->len - final_line - 1] == '\n') - break; - if (namelen - display_name_length + final_line > 78) { + if (namelen - display_name_length + last_line_length(sb) > max_length) { strbuf_addch(sb, '\n'); if (!isspace(name_tail[0])) strbuf_addch(sb, ' '); @@ -500,11 +567,11 @@ char *logmsg_reencode(const struct commit *commit, char *encoding; char *out; - if (!*output_encoding) + if (!output_encoding || !*output_encoding) return NULL; encoding = get_header(commit, "encoding"); use_encoding = encoding ? encoding : utf8; - if (!strcmp(use_encoding, output_encoding)) + if (same_encoding(use_encoding, output_encoding)) if (encoding) /* we'll strip encoding header later */ out = xstrdup(commit->buffer); else @@ -1033,9 +1100,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder, } return 0; /* unknown %g placeholder */ case 'N': - if (c->pretty_ctx->show_notes) { - format_display_notes(commit->object.sha1, sb, - get_log_output_encoding(), 0); + if (c->pretty_ctx->notes_message) { + strbuf_addstr(sb, c->pretty_ctx->notes_message); return 1; } return 0; @@ -1184,23 +1250,15 @@ void format_commit_message(const struct commit *commit, const struct pretty_print_context *pretty_ctx) { struct format_commit_context context; - static const char utf8[] = "UTF-8"; const char *output_enc = pretty_ctx->output_encoding; memset(&context, 0, sizeof(context)); context.commit = commit; context.pretty_ctx = pretty_ctx; context.wrap_start = sb->len; - context.message = commit->buffer; - if (output_enc) { - char *enc = get_header(commit, "encoding"); - if (strcmp(enc ? enc : utf8, output_enc)) { - context.message = logmsg_reencode(commit, output_enc); - if (!context.message) - context.message = commit->buffer; - } - free(enc); - } + context.message = logmsg_reencode(commit, output_enc); + if (!context.message) + context.message = commit->buffer; strbuf_expand(sb, format, format_commit_item, &context); rewrap_message_tail(sb, &context, 0, 0, 0); @@ -1278,6 +1336,7 @@ void pp_title_line(const struct pretty_print_context *pp, const char *encoding, int need_8bit_cte) { + static const int max_length = 78; /* per rfc2047 */ struct strbuf title; strbuf_init(&title, 80); @@ -1287,7 +1346,12 @@ void pp_title_line(const struct pretty_print_context *pp, strbuf_grow(sb, title.len + 1024); if (pp->subject) { strbuf_addstr(sb, pp->subject); - add_rfc2047(sb, title.buf, title.len, encoding); + if (needs_rfc2047_encoding(title.buf, title.len, RFC2047_SUBJECT)) + add_rfc2047(sb, title.buf, title.len, + encoding, RFC2047_SUBJECT); + else + strbuf_add_wrapped_bytes(sb, title.buf, title.len, + -last_line_length(sb), 1, max_length); } else { strbuf_addbuf(sb, &title); } @@ -1341,16 +1405,6 @@ void pp_remainder(const struct pretty_print_context *pp, } } -char *reencode_commit_message(const struct commit *commit, const char **encoding_p) -{ - const char *encoding; - - encoding = get_log_output_encoding(); - if (encoding_p) - *encoding_p = encoding; - return logmsg_reencode(commit, encoding); -} - void pretty_print_commit(const struct pretty_print_context *pp, const struct commit *commit, struct strbuf *sb) @@ -1367,7 +1421,8 @@ void pretty_print_commit(const struct pretty_print_context *pp, return; } - reencoded = reencode_commit_message(commit, &encoding); + encoding = get_log_output_encoding(); + reencoded = logmsg_reencode(commit, encoding); if (reencoded) { msg = reencoded; } @@ -1427,10 +1482,6 @@ void pretty_print_commit(const struct pretty_print_context *pp, if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) strbuf_addch(sb, '\n'); - if (pp->show_notes) - format_display_notes(commit->object.sha1, sb, encoding, - NOTES_SHOW_HEADER | NOTES_INDENT); - free(reencoded); } diff --git a/read-cache.c b/read-cache.c index d8543e4d4..fda78bc35 100644 --- a/read-cache.c +++ b/read-cache.c @@ -17,6 +17,10 @@ static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really); +/* Mask for the name length in ce_flags in the on-disk index */ + +#define CE_NAMEMASK (0x0fff) + /* Index extensions. * * The first letter should be 'A'..'Z' for extensions that are not @@ -54,8 +58,8 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n new = xmalloc(cache_entry_size(namelen)); copy_cache_entry(new, old); - new->ce_flags &= ~(CE_STATE_MASK | CE_NAMEMASK); - new->ce_flags |= (namelen >= CE_NAMEMASK ? CE_NAMEMASK : namelen); + new->ce_flags &= ~CE_STATE_MASK; + new->ce_namelen = namelen; memcpy(new->name, new_name, namelen + 1); cache_tree_invalidate_path(istate->cache_tree, old->name); @@ -395,17 +399,10 @@ int df_name_compare(const char *name1, int len1, int mode1, return c1 - c2; } -int cache_name_compare(const char *name1, int flags1, const char *name2, int flags2) +int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2) { - int len1, len2, len, cmp; - - len1 = flags1 & CE_NAMEMASK; - if (CE_NAMEMASK <= len1) - len1 = strlen(name1 + CE_NAMEMASK) + CE_NAMEMASK; - len2 = flags2 & CE_NAMEMASK; - if (CE_NAMEMASK <= len2) - len2 = strlen(name2 + CE_NAMEMASK) + CE_NAMEMASK; - len = len1 < len2 ? len1 : len2; + int len = len1 < len2 ? len1 : len2; + int cmp; cmp = memcmp(name1, name2, len); if (cmp) @@ -415,18 +412,19 @@ int cache_name_compare(const char *name1, int flags1, const char *name2, int fla if (len1 > len2) return 1; - /* Compare stages */ - flags1 &= CE_STAGEMASK; - flags2 &= CE_STAGEMASK; - - if (flags1 < flags2) + if (stage1 < stage2) return -1; - if (flags1 > flags2) + if (stage1 > stage2) return 1; return 0; } -int index_name_pos(const struct index_state *istate, const char *name, int namelen) +int cache_name_compare(const char *name1, int len1, const char *name2, int len2) +{ + return cache_name_stage_compare(name1, len1, 0, name2, len2, 0); +} + +static int index_name_stage_pos(const struct index_state *istate, const char *name, int namelen, int stage) { int first, last; @@ -435,7 +433,7 @@ int index_name_pos(const struct index_state *istate, const char *name, int namel while (last > first) { int next = (last + first) >> 1; struct cache_entry *ce = istate->cache[next]; - int cmp = cache_name_compare(name, namelen, ce->name, ce->ce_flags); + int cmp = cache_name_stage_compare(name, namelen, stage, ce->name, ce_namelen(ce), ce_stage(ce)); if (!cmp) return next; if (cmp < 0) { @@ -447,6 +445,11 @@ int index_name_pos(const struct index_state *istate, const char *name, int namel return -first-1; } +int index_name_pos(const struct index_state *istate, const char *name, int namelen) +{ + return index_name_stage_pos(istate, name, namelen, 0); +} + /* Remove entry, return true if there are more entries to go.. */ int remove_index_entry_at(struct index_state *istate, int pos) { @@ -586,7 +589,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, size = cache_entry_size(namelen); ce = xcalloc(1, size); memcpy(ce->name, path, namelen); - ce->ce_flags = namelen; + ce->ce_namelen = namelen; if (!intent_only) fill_stat_cache_info(ce, st); else @@ -688,7 +691,8 @@ struct cache_entry *make_cache_entry(unsigned int mode, hashcpy(ce->sha1, sha1); memcpy(ce->name, path, len); - ce->ce_flags = create_ce_flags(len, stage); + ce->ce_flags = create_ce_flags(stage); + ce->ce_namelen = len; ce->ce_mode = create_ce_mode(mode); if (refresh) @@ -825,7 +829,7 @@ static int has_dir_name(struct index_state *istate, } len = slash - name; - pos = index_name_pos(istate, name, create_ce_flags(len, stage)); + pos = index_name_stage_pos(istate, name, len, stage); if (pos >= 0) { /* * Found one, but not so fast. This could @@ -915,7 +919,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e int new_only = option & ADD_CACHE_NEW_ONLY; cache_tree_invalidate_path(istate->cache_tree, ce->name); - pos = index_name_pos(istate, ce->name, ce->ce_flags); + pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce)); /* existing match? Just replace it. */ if (pos >= 0) { @@ -947,7 +951,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e if (!ok_to_replace) return error("'%s' appears as both a file and as a directory", ce->name); - pos = index_name_pos(istate, ce->name, ce->ce_flags); + pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce)); pos = -pos-1; } return pos + 1; @@ -1124,7 +1128,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p continue; if (pathspec && - !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen)) + !match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen)) filtered = 1; if (ce_stage(ce)) { @@ -1324,7 +1328,8 @@ static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *on ce->ce_uid = ntoh_l(ondisk->uid); ce->ce_gid = ntoh_l(ondisk->gid); ce->ce_size = ntoh_l(ondisk->size); - ce->ce_flags = flags; + ce->ce_flags = flags & ~CE_NAMEMASK; + ce->ce_namelen = len; hashcpy(ce->sha1, ondisk->sha1); memcpy(ce->name, name, len); ce->name[len] = '\0'; @@ -1647,6 +1652,8 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce) static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk, struct cache_entry *ce) { + short flags; + ondisk->ctime.sec = htonl(ce->ce_ctime.sec); ondisk->mtime.sec = htonl(ce->ce_mtime.sec); ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec); @@ -1658,7 +1665,10 @@ static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk, ondisk->gid = htonl(ce->ce_gid); ondisk->size = htonl(ce->ce_size); hashcpy(ondisk->sha1, ce->sha1); - ondisk->flags = htons(ce->ce_flags); + + flags = ce->ce_flags; + flags |= (ce_namelen(ce) >= CE_NAMEMASK ? CE_NAMEMASK : ce_namelen(ce)); + ondisk->flags = htons(flags); if (ce->ce_flags & CE_EXTENDED) { struct ondisk_cache_entry_extended *ondisk2; ondisk2 = (struct ondisk_cache_entry_extended *)ondisk; @@ -1844,11 +1854,12 @@ int read_index_unmerged(struct index_state *istate) if (!ce_stage(ce)) continue; unmerged = 1; - len = strlen(ce->name); + len = ce_namelen(ce); size = cache_entry_size(len); new_ce = xcalloc(1, size); memcpy(new_ce->name, ce->name, len); - new_ce->ce_flags = create_ce_flags(len, 0) | CE_CONFLICTED; + new_ce->ce_flags = create_ce_flags(0) | CE_CONFLICTED; + new_ce->ce_namelen = len; new_ce->ce_mode = ce->ce_mode; if (add_index_entry(istate, new_ce, 0)) return error("%s: cannot drop to stage #0", @@ -1202,6 +1202,8 @@ int peel_ref(const char *refname, unsigned char *sha1) if (current_ref && (current_ref->name == refname || !strcmp(current_ref->name, refname))) { if (current_ref->flag & REF_KNOWS_PEELED) { + if (is_null_sha1(current_ref->u.value.peeled)) + return -1; hashcpy(sha1, current_ref->u.value.peeled); return 0; } @@ -1223,9 +1225,16 @@ int peel_ref(const char *refname, unsigned char *sha1) } fallback: - o = parse_object(base); - if (o && o->type == OBJ_TAG) { - o = deref_tag(o, refname, 0); + o = lookup_unknown_object(base); + if (o->type == OBJ_NONE) { + int type = sha1_object_info(base, NULL); + if (type < 0) + return -1; + o->type = type; + } + + if (o->type == OBJ_TAG) { + o = deref_tag_noverify(o); if (o) { hashcpy(sha1, o->sha1); return 0; @@ -1735,7 +1744,8 @@ static struct lock_file packlock; static int repack_without_ref(const char *refname) { struct repack_without_ref_sb data; - struct ref_dir *packed = get_packed_refs(get_ref_cache(NULL)); + struct ref_cache *refs = get_ref_cache(NULL); + struct ref_dir *packed = get_packed_refs(refs); if (find_ref(packed, refname) == NULL) return 0; data.refname = refname; @@ -1744,6 +1754,8 @@ static int repack_without_ref(const char *refname) unable_to_lock_error(git_path("packed-refs"), errno); return error("cannot delete '%s' from packed refs", refname); } + clear_packed_ref_cache(refs); + packed = get_packed_refs(refs); do_for_each_ref_in_dir(packed, 0, "", repack_without_ref_fn, 0, 0, &data); return commit_lock_file(&packlock); } @@ -1753,32 +1765,24 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt) struct ref_lock *lock; int err, i = 0, ret = 0, flag = 0; - lock = lock_ref_sha1_basic(refname, sha1, 0, &flag); + lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag); if (!lock) return 1; if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) { /* loose */ - const char *path; - - if (!(delopt & REF_NODEREF)) { - i = strlen(lock->lk->filename) - 5; /* .lock */ - lock->lk->filename[i] = 0; - path = lock->lk->filename; - } else { - path = git_path("%s", refname); - } - err = unlink_or_warn(path); + i = strlen(lock->lk->filename) - 5; /* .lock */ + lock->lk->filename[i] = 0; + err = unlink_or_warn(lock->lk->filename); if (err && errno != ENOENT) ret = 1; - if (!(delopt & REF_NODEREF)) - lock->lk->filename[i] = '.'; + lock->lk->filename[i] = '.'; } /* removing the loose one could have resurrected an earlier * packed one. Also, if it was not loose we need to repack * without it. */ - ret |= repack_without_ref(refname); + ret |= repack_without_ref(lock->ref_name); unlink_or_warn(git_path("logs/%s", lock->ref_name)); invalidate_ref_cache(NULL); diff --git a/remote-curl.c b/remote-curl.c index 3ec474fc6..9a8b12350 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -95,15 +95,16 @@ static struct discovery* discover_refs(const char *service) struct strbuf buffer = STRBUF_INIT; struct discovery *last = last_discovery; char *refs_url; - int http_ret, is_http = 0, proto_git_candidate = 1; + int http_ret, maybe_smart = 0; if (last && !strcmp(service, last->service)) return last; free_discovery(last); strbuf_addf(&buffer, "%sinfo/refs", url); - if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) { - is_http = 1; + if ((!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) && + git_env_bool("GIT_SMART_HTTP", 1)) { + maybe_smart = 1; if (!strchr(url, '?')) strbuf_addch(&buffer, '?'); else @@ -113,19 +114,6 @@ static struct discovery* discover_refs(const char *service) refs_url = strbuf_detach(&buffer, NULL); http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE); - - /* try again with "plain" url (no ? or & appended) */ - if (http_ret != HTTP_OK && http_ret != HTTP_NOAUTH) { - free(refs_url); - strbuf_reset(&buffer); - - proto_git_candidate = 0; - strbuf_addf(&buffer, "%sinfo/refs", url); - refs_url = strbuf_detach(&buffer, NULL); - - http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE); - } - switch (http_ret) { case HTTP_OK: break; @@ -144,8 +132,7 @@ static struct discovery* discover_refs(const char *service) last->buf_alloc = strbuf_detach(&buffer, &last->len); last->buf = last->buf_alloc; - if (is_http && proto_git_candidate - && 5 <= last->len && last->buf[4] == '#') { + if (maybe_smart && 5 <= last->len && last->buf[4] == '#') { /* smart HTTP response; validate that the service * pkt-line matches our request. */ @@ -369,7 +356,7 @@ static int run_slot(struct active_request_slot *slot) slot->curl_result = curl_easy_perform(slot->curl); finish_active_slot(slot); - err = handle_curl_result(slot); + err = handle_curl_result(&results); if (err != HTTP_OK && err != HTTP_REAUTH) { error("RPC failed; result=%d, HTTP code = %ld", results.curl_result, results.http_code); @@ -393,7 +380,7 @@ static int probe_rpc(struct rpc_state *rpc) curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0); curl_easy_setopt(slot->curl, CURLOPT_POST, 1); curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url); - curl_easy_setopt(slot->curl, CURLOPT_ENCODING, ""); + curl_easy_setopt(slot->curl, CURLOPT_ENCODING, NULL); curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, "0000"); curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, 4); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers); @@ -413,6 +400,7 @@ static int post_rpc(struct rpc_state *rpc) struct curl_slist *headers = NULL; int use_gzip = rpc->gzip_request; char *gzip_body = NULL; + size_t gzip_size = 0; int err, large_request = 0; /* Try to load the entire request, if we can fit it into the @@ -444,16 +432,17 @@ static int post_rpc(struct rpc_state *rpc) return -1; } + headers = curl_slist_append(headers, rpc->hdr_content_type); + headers = curl_slist_append(headers, rpc->hdr_accept); + headers = curl_slist_append(headers, "Expect:"); + +retry: slot = get_active_slot(); curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0); curl_easy_setopt(slot->curl, CURLOPT_POST, 1); curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url); - curl_easy_setopt(slot->curl, CURLOPT_ENCODING, ""); - - headers = curl_slist_append(headers, rpc->hdr_content_type); - headers = curl_slist_append(headers, rpc->hdr_accept); - headers = curl_slist_append(headers, "Expect:"); + curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "gzip"); if (large_request) { /* The request body is large and the size cannot be predicted. @@ -472,24 +461,32 @@ static int post_rpc(struct rpc_state *rpc) fflush(stderr); } + } else if (gzip_body) { + /* + * If we are looping to retry authentication, then the previous + * run will have set up the headers and gzip buffer already, + * and we just need to send it. + */ + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body); + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size); + } else if (use_gzip && 1024 < rpc->len) { /* The client backend isn't giving us compressed data so * we can try to deflate it ourselves, this may save on. * the transfer time. */ - size_t size; git_zstream stream; int ret; memset(&stream, 0, sizeof(stream)); git_deflate_init_gzip(&stream, Z_BEST_COMPRESSION); - size = git_deflate_bound(&stream, rpc->len); - gzip_body = xmalloc(size); + gzip_size = git_deflate_bound(&stream, rpc->len); + gzip_body = xmalloc(gzip_size); stream.next_in = (unsigned char *)rpc->buf; stream.avail_in = rpc->len; stream.next_out = (unsigned char *)gzip_body; - stream.avail_out = size; + stream.avail_out = gzip_size; ret = git_deflate(&stream, Z_FINISH); if (ret != Z_STREAM_END) @@ -499,16 +496,16 @@ static int post_rpc(struct rpc_state *rpc) if (ret != Z_OK) die("cannot deflate request; zlib end error %d", ret); - size = stream.total_out; + gzip_size = stream.total_out; headers = curl_slist_append(headers, "Content-Encoding: gzip"); curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, gzip_body); - curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, size); + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, gzip_size); if (options.verbosity > 1) { fprintf(stderr, "POST %s (gzip %lu to %lu bytes)\n", rpc->service_name, - (unsigned long)rpc->len, (unsigned long)size); + (unsigned long)rpc->len, (unsigned long)gzip_size); fflush(stderr); } } else { @@ -528,9 +525,9 @@ static int post_rpc(struct rpc_state *rpc) curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in); curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc); - do { - err = run_slot(slot); - } while (err == HTTP_REAUTH && !large_request && !use_gzip); + err = run_slot(slot); + if (err == HTTP_REAUTH && !large_request) + goto retry; if (err != HTTP_OK) err = -1; diff --git a/remote-testsvn.c b/remote-testsvn.c new file mode 100644 index 000000000..5ddf11cc6 --- /dev/null +++ b/remote-testsvn.c @@ -0,0 +1,344 @@ +#include "cache.h" +#include "remote.h" +#include "strbuf.h" +#include "url.h" +#include "exec_cmd.h" +#include "run-command.h" +#include "vcs-svn/svndump.h" +#include "notes.h" +#include "argv-array.h" + +static const char *url; +static int dump_from_file; +static const char *private_ref; +static const char *remote_ref = "refs/heads/master"; +static const char *marksfilename, *notes_ref; +struct rev_note { unsigned int rev_nr; }; + +static int cmd_capabilities(const char *line); +static int cmd_import(const char *line); +static int cmd_list(const char *line); + +typedef int (*input_command_handler)(const char *); +struct input_command_entry { + const char *name; + input_command_handler fn; + unsigned char batchable; /* whether the command starts or is part of a batch */ +}; + +static const struct input_command_entry input_command_list[] = { + { "capabilities", cmd_capabilities, 0 }, + { "import", cmd_import, 1 }, + { "list", cmd_list, 0 }, + { NULL, NULL } +}; + +static int cmd_capabilities(const char *line) +{ + printf("import\n"); + printf("bidi-import\n"); + printf("refspec %s:%s\n\n", remote_ref, private_ref); + fflush(stdout); + return 0; +} + +static void terminate_batch(void) +{ + /* terminate a current batch's fast-import stream */ + printf("done\n"); + fflush(stdout); +} + +/* NOTE: 'ref' refers to a git reference, while 'rev' refers to a svn revision. */ +static char *read_ref_note(const unsigned char sha1[20]) +{ + const unsigned char *note_sha1; + char *msg = NULL; + unsigned long msglen; + enum object_type type; + + init_notes(NULL, notes_ref, NULL, 0); + if (!(note_sha1 = get_note(NULL, sha1))) + return NULL; /* note tree not found */ + if (!(msg = read_sha1_file(note_sha1, &type, &msglen))) + error("Empty notes tree. %s", notes_ref); + else if (!msglen || type != OBJ_BLOB) { + error("Note contains unusable content. " + "Is something else using this notes tree? %s", notes_ref); + free(msg); + msg = NULL; + } + free_notes(NULL); + return msg; +} + +static int parse_rev_note(const char *msg, struct rev_note *res) +{ + const char *key, *value, *end; + size_t len; + + while (*msg) { + end = strchr(msg, '\n'); + len = end ? end - msg : strlen(msg); + + key = "Revision-number: "; + if (!prefixcmp(msg, key)) { + long i; + char *end; + value = msg + strlen(key); + i = strtol(value, &end, 0); + if (end == value || i < 0 || i > UINT32_MAX) + return -1; + res->rev_nr = i; + return 0; + } + msg += len + 1; + } + /* didn't find it */ + return -1; +} + +static int note2mark_cb(const unsigned char *object_sha1, + const unsigned char *note_sha1, char *note_path, + void *cb_data) +{ + FILE *file = (FILE *)cb_data; + char *msg; + unsigned long msglen; + enum object_type type; + struct rev_note note; + + if (!(msg = read_sha1_file(note_sha1, &type, &msglen)) || + !msglen || type != OBJ_BLOB) { + free(msg); + return 1; + } + if (parse_rev_note(msg, ¬e)) + return 2; + if (fprintf(file, ":%d %s\n", note.rev_nr, sha1_to_hex(object_sha1)) < 1) + return 3; + return 0; +} + +static void regenerate_marks(void) +{ + int ret; + FILE *marksfile = fopen(marksfilename, "w+"); + + if (!marksfile) + die_errno("Couldn't create mark file %s.", marksfilename); + ret = for_each_note(NULL, 0, note2mark_cb, marksfile); + if (ret) + die("Regeneration of marks failed, returned %d.", ret); + fclose(marksfile); +} + +static void check_or_regenerate_marks(int latestrev) +{ + FILE *marksfile; + struct strbuf sb = STRBUF_INIT; + struct strbuf line = STRBUF_INIT; + int found = 0; + + if (latestrev < 1) + return; + + init_notes(NULL, notes_ref, NULL, 0); + marksfile = fopen(marksfilename, "r"); + if (!marksfile) { + regenerate_marks(); + marksfile = fopen(marksfilename, "r"); + if (!marksfile) + die_errno("cannot read marks file %s!", marksfilename); + fclose(marksfile); + } else { + strbuf_addf(&sb, ":%d ", latestrev); + while (strbuf_getline(&line, marksfile, '\n') != EOF) { + if (!prefixcmp(line.buf, sb.buf)) { + found++; + break; + } + } + fclose(marksfile); + if (!found) + regenerate_marks(); + } + free_notes(NULL); + strbuf_release(&sb); + strbuf_release(&line); +} + +static int cmd_import(const char *line) +{ + int code; + int dumpin_fd; + char *note_msg; + unsigned char head_sha1[20]; + unsigned int startrev; + struct argv_array svndump_argv = ARGV_ARRAY_INIT; + struct child_process svndump_proc; + + if (read_ref(private_ref, head_sha1)) + startrev = 0; + else { + note_msg = read_ref_note(head_sha1); + if(note_msg == NULL) { + warning("No note found for %s.", private_ref); + startrev = 0; + } else { + struct rev_note note = { 0 }; + if (parse_rev_note(note_msg, ¬e)) + die("Revision number couldn't be parsed from note."); + startrev = note.rev_nr + 1; + free(note_msg); + } + } + check_or_regenerate_marks(startrev - 1); + + if (dump_from_file) { + dumpin_fd = open(url, O_RDONLY); + if(dumpin_fd < 0) + die_errno("Couldn't open svn dump file %s.", url); + } else { + memset(&svndump_proc, 0, sizeof(struct child_process)); + svndump_proc.out = -1; + argv_array_push(&svndump_argv, "svnrdump"); + argv_array_push(&svndump_argv, "dump"); + argv_array_push(&svndump_argv, url); + argv_array_pushf(&svndump_argv, "-r%u:HEAD", startrev); + svndump_proc.argv = svndump_argv.argv; + + code = start_command(&svndump_proc); + if (code) + die("Unable to start %s, code %d", svndump_proc.argv[0], code); + dumpin_fd = svndump_proc.out; + } + /* setup marks file import/export */ + printf("feature import-marks-if-exists=%s\n" + "feature export-marks=%s\n", marksfilename, marksfilename); + + svndump_init_fd(dumpin_fd, STDIN_FILENO); + svndump_read(url, private_ref, notes_ref); + svndump_deinit(); + svndump_reset(); + + close(dumpin_fd); + if (!dump_from_file) { + code = finish_command(&svndump_proc); + if (code) + warning("%s, returned %d", svndump_proc.argv[0], code); + argv_array_clear(&svndump_argv); + } + + return 0; +} + +static int cmd_list(const char *line) +{ + printf("? %s\n\n", remote_ref); + fflush(stdout); + return 0; +} + +static int do_command(struct strbuf *line) +{ + const struct input_command_entry *p = input_command_list; + static struct string_list batchlines = STRING_LIST_INIT_DUP; + static const struct input_command_entry *batch_cmd; + /* + * commands can be grouped together in a batch. + * Batches are ended by \n. If no batch is active the program ends. + * During a batch all lines are buffered and passed to the handler function + * when the batch is terminated. + */ + if (line->len == 0) { + if (batch_cmd) { + struct string_list_item *item; + for_each_string_list_item(item, &batchlines) + batch_cmd->fn(item->string); + terminate_batch(); + batch_cmd = NULL; + string_list_clear(&batchlines, 0); + return 0; /* end of the batch, continue reading other commands. */ + } + return 1; /* end of command stream, quit */ + } + if (batch_cmd) { + if (prefixcmp(batch_cmd->name, line->buf)) + die("Active %s batch interrupted by %s", batch_cmd->name, line->buf); + /* buffer batch lines */ + string_list_append(&batchlines, line->buf); + return 0; + } + + for (p = input_command_list; p->name; p++) { + if (!prefixcmp(line->buf, p->name) && (strlen(p->name) == line->len || + line->buf[strlen(p->name)] == ' ')) { + if (p->batchable) { + batch_cmd = p; + string_list_append(&batchlines, line->buf); + return 0; + } + return p->fn(line->buf); + } + } + die("Unknown command '%s'\n", line->buf); + return 0; +} + +int main(int argc, const char **argv) +{ + struct strbuf buf = STRBUF_INIT, url_sb = STRBUF_INIT, + private_ref_sb = STRBUF_INIT, marksfilename_sb = STRBUF_INIT, + notes_ref_sb = STRBUF_INIT; + static struct remote *remote; + const char *url_in; + + git_extract_argv0_path(argv[0]); + setup_git_directory(); + if (argc < 2 || argc > 3) { + usage("git-remote-svn <remote-name> [<url>]"); + return 1; + } + + remote = remote_get(argv[1]); + url_in = (argc == 3) ? argv[2] : remote->url[0]; + + if (!prefixcmp(url_in, "file://")) { + dump_from_file = 1; + url = url_decode(url_in + sizeof("file://")-1); + } else { + dump_from_file = 0; + end_url_with_slash(&url_sb, url_in); + url = url_sb.buf; + } + + strbuf_addf(&private_ref_sb, "refs/svn/%s/master", remote->name); + private_ref = private_ref_sb.buf; + + strbuf_addf(¬es_ref_sb, "refs/notes/%s/revs", remote->name); + notes_ref = notes_ref_sb.buf; + + strbuf_addf(&marksfilename_sb, "%s/info/fast-import/remote-svn/%s.marks", + get_git_dir(), remote->name); + marksfilename = marksfilename_sb.buf; + + while (1) { + if (strbuf_getline(&buf, stdin, '\n') == EOF) { + if (ferror(stdin)) + die("Error reading command stream"); + else + die("Unexpected end of command stream"); + } + if (do_command(&buf)) + break; + strbuf_reset(&buf); + } + + strbuf_release(&buf); + strbuf_release(&url_sb); + strbuf_release(&private_ref_sb); + strbuf_release(¬es_ref_sb); + strbuf_release(&marksfilename_sb); + return 0; +} @@ -1370,6 +1370,16 @@ int branch_merge_matches(struct branch *branch, return refname_match(branch->merge[i]->src, refname, ref_fetch_rules); } +static int ignore_symref_update(const char *refname) +{ + unsigned char sha1[20]; + int flag; + + if (!resolve_ref_unsafe(refname, sha1, 0, &flag)) + return 0; /* non-existing refs are OK */ + return (flag & REF_ISSYMREF); +} + static struct ref *get_expanded_map(const struct ref *remote_refs, const struct refspec *refspec) { @@ -1383,7 +1393,8 @@ static struct ref *get_expanded_map(const struct ref *remote_refs, if (strchr(ref->name, '^')) continue; /* a dereference item */ if (match_name_with_pattern(refspec->src, ref->name, - refspec->dst, &expn_name)) { + refspec->dst, &expn_name) && + !ignore_symref_update(expn_name)) { struct ref *cpy = copy_ref(ref); cpy->peer_ref = alloc_ref(expn_name); @@ -1458,8 +1469,8 @@ int get_fetch_map(const struct ref *remote_refs, for (rmp = &ref_map; *rmp; ) { if ((*rmp)->peer_ref) { - if (check_refname_format((*rmp)->peer_ref->name + 5, - REFNAME_ALLOW_ONELEVEL)) { + if (prefixcmp((*rmp)->peer_ref->name, "refs/") || + check_refname_format((*rmp)->peer_ref->name, 0)) { struct ref *ignore = *rmp; error("* Ignoring funny ref '%s' locally", (*rmp)->peer_ref->name); @@ -1627,13 +1638,16 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) base = branch->merge[0]->dst; base = shorten_unambiguous_ref(base, 0); - if (!num_theirs) + if (!num_theirs) { strbuf_addf(sb, Q_("Your branch is ahead of '%s' by %d commit.\n", "Your branch is ahead of '%s' by %d commits.\n", num_ours), base, num_ours); - else if (!num_ours) + if (advice_status_hints) + strbuf_addf(sb, + _(" (use \"git push\" to publish your local commits)\n")); + } else if (!num_ours) { strbuf_addf(sb, Q_("Your branch is behind '%s' by %d commit, " "and can be fast-forwarded.\n", @@ -1641,7 +1655,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) "and can be fast-forwarded.\n", num_theirs), base, num_theirs); - else + if (advice_status_hints) + strbuf_addf(sb, + _(" (use \"git pull\" to update your local branch)\n")); + } else { strbuf_addf(sb, Q_("Your branch and '%s' have diverged,\n" "and have %d and %d different commit each, " @@ -1651,6 +1668,10 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) "respectively.\n", num_theirs), base, num_ours, num_theirs); + if (advice_status_hints) + strbuf_addf(sb, + _(" (use \"git pull\" to merge the remote branch into yours)\n")); + } return 1; } @@ -25,7 +25,7 @@ const char *rerere_path(const char *hex, const char *file) return git_path("rr-cache/%s/%s", hex, file); } -int has_rerere_resolution(const char *hex) +static int has_rerere_resolution(const char *hex) { struct stat st; return !stat(rerere_path(hex, "postimage"), &st); @@ -544,13 +544,13 @@ static int do_plain_rerere(struct string_list *rr, int fd) if (has_rerere_resolution(name)) { if (!merge(name, path)) { - if (rerere_autoupdate) + const char *msg; + if (rerere_autoupdate) { string_list_insert(&update, path); - fprintf(stderr, - "%s '%s' using previous resolution.\n", - rerere_autoupdate - ? "Staged" : "Resolved", - path); + msg = "Staged '%s' using previous resolution.\n"; + } else + msg = "Resolved '%s' using previous resolution.\n"; + fprintf(stderr, msg, path); goto mark_resolved; } } @@ -16,7 +16,6 @@ extern void *RERERE_RESOLVED; extern int setup_rerere(struct string_list *, int); extern int rerere(int); extern const char *rerere_path(const char *hex, const char *file); -extern int has_rerere_resolution(const char *hex); extern int rerere_forget(const char **); extern int rerere_remaining(struct string_list *); extern void rerere_clear(struct string_list *); diff --git a/revision.c b/revision.c index 72104962d..95d21e647 100644 --- a/revision.c +++ b/revision.c @@ -1002,7 +1002,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags) flags ^= UNINTERESTING; arg++; } - if (get_sha1(arg, sha1)) + if (get_sha1_committish(arg, sha1)) return 0; while (1) { it = get_reference(revs, arg, sha1, 0); @@ -1048,9 +1048,9 @@ void init_revisions(struct rev_info *revs, const char *prefix) revs->commit_format = CMIT_FMT_DEFAULT; + init_grep_defaults(); + grep_init(&revs->grep_filter, prefix); revs->grep_filter.status_only = 1; - revs->grep_filter.pattern_tail = &(revs->grep_filter.pattern_list); - revs->grep_filter.header_tail = &(revs->grep_filter.header_list); revs->grep_filter.regflags = REG_NEWLINE; diff_setup(&revs->diffopt); @@ -1116,16 +1116,16 @@ static void prepare_show_merge(struct rev_info *revs) revs->limited = 1; } -int handle_revision_arg(const char *arg_, struct rev_info *revs, - int flags, - int cant_be_filename) +int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt) { - unsigned mode; + struct object_context oc; char *dotdot; struct object *object; unsigned char sha1[20]; int local_flags; const char *arg = arg_; + int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME; + unsigned get_sha1_flags = 0; dotdot = strstr(arg, ".."); if (dotdot) { @@ -1155,8 +1155,8 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, return -1; } } - if (!get_sha1(this, from_sha1) && - !get_sha1(next, sha1)) { + if (!get_sha1_committish(this, from_sha1) && + !get_sha1_committish(next, sha1)) { struct commit *a, *b; struct commit_list *exclude; @@ -1215,13 +1215,17 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, local_flags = UNINTERESTING; arg++; } - if (get_sha1_with_mode(arg, sha1, &mode)) + + if (revarg_opt & REVARG_COMMITTISH) + get_sha1_flags = GET_SHA1_COMMITTISH; + + if (get_sha1_with_context(arg, get_sha1_flags, sha1, &oc)) return revs->ignore_missing ? 0 : -1; if (!cant_be_filename) verify_non_filename(revs->prefix, arg); object = get_reference(revs, arg, sha1, flags ^ local_flags); add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags); - add_pending_object_with_mode(revs, object, arg, mode); + add_pending_object_with_mode(revs, object, arg, oc.mode); return 0; } @@ -1271,7 +1275,7 @@ static void read_revisions_from_stdin(struct rev_info *revs, } die("options not supported in --stdin mode"); } - if (handle_revision_arg(sb.buf, revs, 0, 1)) + if (handle_revision_arg(sb.buf, revs, 0, REVARG_CANNOT_BE_FILENAME)) die("bad revision '%s'", sb.buf); } if (seen_dashdash) @@ -1308,7 +1312,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg !strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") || !strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") || !prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") || - !prefixcmp(arg, "--remotes=")) + !prefixcmp(arg, "--remotes=") || !prefixcmp(arg, "--no-walk=")) { unkv[(*unkc)++] = arg; return 1; @@ -1591,16 +1595,25 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if ((argcount = parse_long_opt("committer", argv, &optarg))) { add_header_grep(revs, GREP_HEADER_COMMITTER, optarg); return argcount; + } else if ((argcount = parse_long_opt("grep-reflog", argv, &optarg))) { + add_header_grep(revs, GREP_HEADER_REFLOG, optarg); + return argcount; } else if ((argcount = parse_long_opt("grep", argv, &optarg))) { add_message_grep(revs, optarg); return argcount; + } else if (!strcmp(arg, "--grep-debug")) { + revs->grep_filter.debug = 1; + } else if (!strcmp(arg, "--basic-regexp")) { + grep_set_pattern_type_option(GREP_PATTERN_TYPE_BRE, &revs->grep_filter); } else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) { - revs->grep_filter.regflags |= REG_EXTENDED; + grep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, &revs->grep_filter); } else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) { revs->grep_filter.regflags |= REG_ICASE; DIFF_OPT_SET(&revs->diffopt, PICKAXE_IGNORE_CASE); } else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) { - revs->grep_filter.fixed = 1; + grep_set_pattern_type_option(GREP_PATTERN_TYPE_FIXED, &revs->grep_filter); + } else if (!strcmp(arg, "--perl-regexp")) { + grep_set_pattern_type_option(GREP_PATTERN_TYPE_PCRE, &revs->grep_filter); } else if (!strcmp(arg, "--all-match")) { revs->grep_filter.all_match = 1; } else if ((argcount = parse_long_opt("encoding", argv, &optarg))) { @@ -1703,7 +1716,18 @@ static int handle_revision_pseudo_opt(const char *submodule, } else if (!strcmp(arg, "--not")) { *flags ^= UNINTERESTING; } else if (!strcmp(arg, "--no-walk")) { - revs->no_walk = 1; + revs->no_walk = REVISION_WALK_NO_WALK_SORTED; + } else if (!prefixcmp(arg, "--no-walk=")) { + /* + * Detached form ("--no-walk X" as opposed to "--no-walk=X") + * not allowed, since the argument is optional. + */ + if (!strcmp(arg + 10, "sorted")) + revs->no_walk = REVISION_WALK_NO_WALK_SORTED; + else if (!strcmp(arg + 10, "unsorted")) + revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED; + else + return error("invalid argument to --no-walk"); } else if (!strcmp(arg, "--do-walk")) { revs->no_walk = 0; } else { @@ -1722,7 +1746,7 @@ static int handle_revision_pseudo_opt(const char *submodule, */ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt) { - int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0; + int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0, revarg_opt; struct cmdline_pathspec prune_data; const char *submodule = NULL; @@ -1750,6 +1774,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s /* Second, deal with arguments and options */ flags = 0; + revarg_opt = opt ? opt->revarg_opt : 0; + if (seen_dashdash) + revarg_opt |= REVARG_CANNOT_BE_FILENAME; read_from_stdin = 0; for (left = i = 1; i < argc; i++) { const char *arg = argv[i]; @@ -1785,7 +1812,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s continue; } - if (handle_revision_arg(arg, revs, flags, seen_dashdash)) { + + if (handle_revision_arg(arg, revs, flags, revarg_opt)) { int j; if (seen_dashdash || *arg == '^') die("bad revision '%s'", arg); @@ -1836,11 +1864,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (revs->def && !revs->pending.nr && !got_rev_arg) { unsigned char sha1[20]; struct object *object; - unsigned mode; - if (get_sha1_with_mode(revs->def, sha1, &mode)) + struct object_context oc; + if (get_sha1_with_context(revs->def, 0, sha1, &oc)) die("bad default revision '%s'", revs->def); object = get_reference(revs, revs->def, sha1, 0); - add_pending_object_with_mode(revs, object, revs->def, mode); + add_pending_object_with_mode(revs, object, revs->def, oc.mode); } /* Did the user ask for any diff output? Run the diff! */ @@ -1869,6 +1897,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s revs->diffopt.abbrev = revs->abbrev; diff_setup_done(&revs->diffopt); + grep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED, + &revs->grep_filter); compile_grep_patterns(&revs->grep_filter); if (revs->reverse && revs->reflog_info) @@ -1884,6 +1914,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (revs->reflog_info && revs->graph) die("cannot combine --walk-reflogs with --graph"); + if (!revs->reflog_info && revs->grep_filter.use_reflog_filter) + die("cannot use --grep-reflog without --walk-reflogs"); return left; } @@ -2121,10 +2153,11 @@ int prepare_revision_walk(struct rev_info *revs) } e++; } - commit_list_sort_by_date(&revs->commits); if (!revs->leak_pending) free(list); + if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED) + commit_list_sort_by_date(&revs->commits); if (revs->no_walk) return 0; if (revs->limited) @@ -2188,10 +2221,38 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit) static int commit_match(struct commit *commit, struct rev_info *opt) { + int retval; + struct strbuf buf = STRBUF_INIT; if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list) return 1; - return grep_buffer(&opt->grep_filter, - commit->buffer, strlen(commit->buffer)); + + /* Prepend "fake" headers as needed */ + if (opt->grep_filter.use_reflog_filter) { + strbuf_addstr(&buf, "reflog "); + get_reflog_message(&buf, opt->reflog_info); + strbuf_addch(&buf, '\n'); + } + + /* Copy the commit to temporary if we are using "fake" headers */ + if (buf.len) + strbuf_addstr(&buf, commit->buffer); + + /* Append "fake" message parts as needed */ + if (opt->show_notes) { + if (!buf.len) + strbuf_addstr(&buf, commit->buffer); + format_display_notes(commit->object.sha1, &buf, + get_log_output_encoding(), 1); + } + + /* Find either in the commit object, or in the temporary */ + if (buf.len) + retval = grep_buffer(&opt->grep_filter, buf.buf, buf.len); + else + retval = grep_buffer(&opt->grep_filter, + commit->buffer, strlen(commit->buffer)); + strbuf_release(&buf); + return retval; } static inline int want_ancestry(struct rev_info *revs) @@ -2374,29 +2435,28 @@ static struct commit *get_revision_internal(struct rev_info *revs) } /* - * Now pick up what they want to give us + * If our max_count counter has reached zero, then we are done. We + * don't simply return NULL because we still might need to show + * boundary commits. But we want to avoid calling get_revision_1, which + * might do a considerable amount of work finding the next commit only + * for us to throw it away. + * + * If it is non-zero, then either we don't have a max_count at all + * (-1), or it is still counting, in which case we decrement. */ - c = get_revision_1(revs); - if (c) { - while (0 < revs->skip_count) { - revs->skip_count--; - c = get_revision_1(revs); - if (!c) - break; + if (revs->max_count) { + c = get_revision_1(revs); + if (c) { + while (0 < revs->skip_count) { + revs->skip_count--; + c = get_revision_1(revs); + if (!c) + break; + } } - } - /* - * Check the max_count. - */ - switch (revs->max_count) { - case -1: - break; - case 0: - c = NULL; - break; - default: - revs->max_count--; + if (revs->max_count > 0) + revs->max_count--; } if (c) diff --git a/revision.h b/revision.h index 863f4f645..059bfff81 100644 --- a/revision.h +++ b/revision.h @@ -41,6 +41,10 @@ struct rev_cmdline_info { } *rev; }; +#define REVISION_WALK_WALK 0 +#define REVISION_WALK_NO_WALK_SORTED 1 +#define REVISION_WALK_NO_WALK_UNSORTED 2 + struct rev_info { /* Starting list */ struct commit_list *commits; @@ -62,7 +66,7 @@ struct rev_info { /* Traversal flags */ unsigned int dense:1, prune:1, - no_walk:1, + no_walk:2, show_all:1, remove_empty_trees:1, simplify_history:1, @@ -107,6 +111,7 @@ struct rev_info { /* Format info */ unsigned int shown_one:1, + shown_dashes:1, show_merge:1, show_notes:1, show_notes_given:1, @@ -184,6 +189,7 @@ struct setup_revision_opt { void (*tweak)(struct rev_info *, struct setup_revision_opt *); const char *submodule; int assume_dashdash; + unsigned revarg_opt; }; extern void init_revisions(struct rev_info *revs, const char *prefix); @@ -191,7 +197,9 @@ extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, s extern void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx, const struct option *options, const char * const usagestr[]); -extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,int cant_be_filename); +#define REVARG_CANNOT_BE_FILENAME 01 +#define REVARG_COMMITTISH 02 +extern int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, unsigned revarg_opt); extern void reset_revision_walk(void); extern int prepare_revision_walk(struct rev_info *revs); diff --git a/run-command.c b/run-command.c index f9922b9ec..24eaad5c6 100644 --- a/run-command.c +++ b/run-command.c @@ -53,13 +53,14 @@ static void mark_child_for_cleanup(pid_t pid) static void clear_child_for_cleanup(pid_t pid) { - struct child_to_clean **last, *p; + struct child_to_clean **pp; - last = &children_to_clean; - for (p = children_to_clean; p; p = p->next) { - if (p->pid == pid) { - *last = p->next; - free(p); + for (pp = &children_to_clean; *pp; pp = &(*pp)->next) { + struct child_to_clean *clean_me = *pp; + + if (clean_me->pid == pid) { + *pp = clean_me->next; + free(clean_me); return; } } @@ -225,7 +226,7 @@ static inline void set_cloexec(int fd) fcntl(fd, F_SETFD, flags | FD_CLOEXEC); } -static int wait_or_whine(pid_t pid, const char *argv0, int silent_exec_failure) +static int wait_or_whine(pid_t pid, const char *argv0) { int status, code = -1; pid_t waiting; @@ -241,7 +242,8 @@ static int wait_or_whine(pid_t pid, const char *argv0, int silent_exec_failure) error("waitpid is confused (%s)", argv0); } else if (WIFSIGNALED(status)) { code = WTERMSIG(status); - error("%s died of signal %d", argv0, code); + if (code != SIGINT && code != SIGQUIT) + error("%s died of signal %d", argv0, code); /* * This return value is chosen so that code & 0xff * mimics the exit code that a POSIX shell would report for @@ -396,16 +398,6 @@ fail_pipe: unsetenv(*cmd->env); } } - if (cmd->preexec_cb) { - /* - * We cannot predict what the pre-exec callback does. - * Forgo parent notification. - */ - close(child_notifier); - child_notifier = -1; - - cmd->preexec_cb(); - } if (cmd->git_cmd) { execv_git_cmd(cmd->argv); } else if (cmd->use_shell) { @@ -441,8 +433,7 @@ fail_pipe: * At this point we know that fork() succeeded, but execvp() * failed. Errors have been reported to our stderr. */ - wait_or_whine(cmd->pid, cmd->argv[0], - cmd->silent_exec_failure); + wait_or_whine(cmd->pid, cmd->argv[0]); failed_errno = errno; cmd->pid = -1; } @@ -547,7 +538,7 @@ fail_pipe: int finish_command(struct child_process *cmd) { - return wait_or_whine(cmd->pid, cmd->argv[0], cmd->silent_exec_failure); + return wait_or_whine(cmd->pid, cmd->argv[0]); } int run_command(struct child_process *cmd) @@ -734,7 +725,7 @@ error: int finish_async(struct async *async) { #ifdef NO_PTHREADS - return wait_or_whine(async->pid, "child process", 0); + return wait_or_whine(async->pid, "child process"); #else void *ret = (void *)(intptr_t)(-1); diff --git a/run-command.h b/run-command.h index 44f7d2bd4..850c638f1 100644 --- a/run-command.h +++ b/run-command.h @@ -39,7 +39,6 @@ struct child_process { unsigned stdout_to_stderr:1; unsigned use_shell:1; unsigned clean_on_exit:1; - void (*preexec_cb)(void); }; int start_command(struct child_process *); diff --git a/send-pack.c b/send-pack.c new file mode 100644 index 000000000..f50dfd9f4 --- /dev/null +++ b/send-pack.c @@ -0,0 +1,344 @@ +#include "builtin.h" +#include "commit.h" +#include "refs.h" +#include "pkt-line.h" +#include "sideband.h" +#include "run-command.h" +#include "remote.h" +#include "send-pack.h" +#include "quote.h" +#include "transport.h" +#include "version.h" + +static int feed_object(const unsigned char *sha1, int fd, int negative) +{ + char buf[42]; + + if (negative && !has_sha1_file(sha1)) + return 1; + + memcpy(buf + negative, sha1_to_hex(sha1), 40); + if (negative) + buf[0] = '^'; + buf[40 + negative] = '\n'; + return write_or_whine(fd, buf, 41 + negative, "send-pack: send refs"); +} + +/* + * Make a pack stream and spit it out into file descriptor fd + */ +static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args) +{ + /* + * The child becomes pack-objects --revs; we feed + * the revision parameters to it via its stdin and + * let its stdout go back to the other end. + */ + const char *argv[] = { + "pack-objects", + "--all-progress-implied", + "--revs", + "--stdout", + NULL, + NULL, + NULL, + NULL, + NULL, + }; + struct child_process po; + int i; + + i = 4; + if (args->use_thin_pack) + argv[i++] = "--thin"; + if (args->use_ofs_delta) + argv[i++] = "--delta-base-offset"; + if (args->quiet || !args->progress) + argv[i++] = "-q"; + if (args->progress) + argv[i++] = "--progress"; + memset(&po, 0, sizeof(po)); + po.argv = argv; + po.in = -1; + po.out = args->stateless_rpc ? -1 : fd; + po.git_cmd = 1; + if (start_command(&po)) + die_errno("git pack-objects failed"); + + /* + * We feed the pack-objects we just spawned with revision + * parameters by writing to the pipe. + */ + for (i = 0; i < extra->nr; i++) + if (!feed_object(extra->array[i], po.in, 1)) + break; + + while (refs) { + if (!is_null_sha1(refs->old_sha1) && + !feed_object(refs->old_sha1, po.in, 1)) + break; + if (!is_null_sha1(refs->new_sha1) && + !feed_object(refs->new_sha1, po.in, 0)) + break; + refs = refs->next; + } + + close(po.in); + + if (args->stateless_rpc) { + char *buf = xmalloc(LARGE_PACKET_MAX); + while (1) { + ssize_t n = xread(po.out, buf, LARGE_PACKET_MAX); + if (n <= 0) + break; + send_sideband(fd, -1, buf, n, LARGE_PACKET_MAX); + } + free(buf); + close(po.out); + po.out = -1; + } + + if (finish_command(&po)) + return -1; + return 0; +} + +static int receive_status(int in, struct ref *refs) +{ + struct ref *hint; + char line[1000]; + int ret = 0; + int len = packet_read_line(in, line, sizeof(line)); + if (len < 10 || memcmp(line, "unpack ", 7)) + return error("did not receive remote status"); + if (memcmp(line, "unpack ok\n", 10)) { + char *p = line + strlen(line) - 1; + if (*p == '\n') + *p = '\0'; + error("unpack failed: %s", line + 7); + ret = -1; + } + hint = NULL; + while (1) { + char *refname; + char *msg; + len = packet_read_line(in, line, sizeof(line)); + if (!len) + break; + if (len < 3 || + (memcmp(line, "ok ", 3) && memcmp(line, "ng ", 3))) { + fprintf(stderr, "protocol error: %s\n", line); + ret = -1; + break; + } + + line[strlen(line)-1] = '\0'; + refname = line + 3; + msg = strchr(refname, ' '); + if (msg) + *msg++ = '\0'; + + /* first try searching at our hint, falling back to all refs */ + if (hint) + hint = find_ref_by_name(hint, refname); + if (!hint) + hint = find_ref_by_name(refs, refname); + if (!hint) { + warning("remote reported status on unknown ref: %s", + refname); + continue; + } + if (hint->status != REF_STATUS_EXPECTING_REPORT) { + warning("remote reported status on unexpected ref: %s", + refname); + continue; + } + + if (line[0] == 'o' && line[1] == 'k') + hint->status = REF_STATUS_OK; + else { + hint->status = REF_STATUS_REMOTE_REJECT; + ret = -1; + } + if (msg) + hint->remote_status = xstrdup(msg); + /* start our next search from the next ref */ + hint = hint->next; + } + return ret; +} + +static int sideband_demux(int in, int out, void *data) +{ + int *fd = data, ret; +#ifdef NO_PTHREADS + close(fd[1]); +#endif + ret = recv_sideband("send-pack", fd[0], out); + close(out); + return ret; +} + +int send_pack(struct send_pack_args *args, + int fd[], struct child_process *conn, + struct ref *remote_refs, + struct extra_have_objects *extra_have) +{ + int in = fd[0]; + int out = fd[1]; + struct strbuf req_buf = STRBUF_INIT; + struct ref *ref; + int new_refs; + int allow_deleting_refs = 0; + int status_report = 0; + int use_sideband = 0; + int quiet_supported = 0; + int agent_supported = 0; + unsigned cmds_sent = 0; + int ret; + struct async demux; + + /* Does the other end support the reporting? */ + if (server_supports("report-status")) + status_report = 1; + if (server_supports("delete-refs")) + allow_deleting_refs = 1; + if (server_supports("ofs-delta")) + args->use_ofs_delta = 1; + if (server_supports("side-band-64k")) + use_sideband = 1; + if (server_supports("quiet")) + quiet_supported = 1; + if (server_supports("agent")) + agent_supported = 1; + + if (!remote_refs) { + fprintf(stderr, "No refs in common and none specified; doing nothing.\n" + "Perhaps you should specify a branch such as 'master'.\n"); + return 0; + } + + /* + * Finally, tell the other end! + */ + new_refs = 0; + for (ref = remote_refs; ref; ref = ref->next) { + if (!ref->peer_ref && !args->send_mirror) + continue; + + /* Check for statuses set by set_ref_status_for_push() */ + switch (ref->status) { + case REF_STATUS_REJECT_NONFASTFORWARD: + case REF_STATUS_UPTODATE: + continue; + default: + ; /* do nothing */ + } + + if (ref->deletion && !allow_deleting_refs) { + ref->status = REF_STATUS_REJECT_NODELETE; + continue; + } + + if (!ref->deletion) + new_refs++; + + if (args->dry_run) { + ref->status = REF_STATUS_OK; + } else { + char *old_hex = sha1_to_hex(ref->old_sha1); + char *new_hex = sha1_to_hex(ref->new_sha1); + int quiet = quiet_supported && (args->quiet || !args->progress); + + if (!cmds_sent && (status_report || use_sideband || + quiet || agent_supported)) { + packet_buf_write(&req_buf, + "%s %s %s%c%s%s%s%s%s", + old_hex, new_hex, ref->name, 0, + status_report ? " report-status" : "", + use_sideband ? " side-band-64k" : "", + quiet ? " quiet" : "", + agent_supported ? " agent=" : "", + agent_supported ? git_user_agent_sanitized() : "" + ); + } + else + packet_buf_write(&req_buf, "%s %s %s", + old_hex, new_hex, ref->name); + ref->status = status_report ? + REF_STATUS_EXPECTING_REPORT : + REF_STATUS_OK; + cmds_sent++; + } + } + + if (args->stateless_rpc) { + if (!args->dry_run && cmds_sent) { + packet_buf_flush(&req_buf); + send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX); + } + } else { + safe_write(out, req_buf.buf, req_buf.len); + packet_flush(out); + } + strbuf_release(&req_buf); + + if (use_sideband && cmds_sent) { + memset(&demux, 0, sizeof(demux)); + demux.proc = sideband_demux; + demux.data = fd; + demux.out = -1; + if (start_async(&demux)) + die("send-pack: unable to fork off sideband demultiplexer"); + in = demux.out; + } + + if (new_refs && cmds_sent) { + if (pack_objects(out, remote_refs, extra_have, args) < 0) { + for (ref = remote_refs; ref; ref = ref->next) + ref->status = REF_STATUS_NONE; + if (args->stateless_rpc) + close(out); + if (git_connection_is_socket(conn)) + shutdown(fd[0], SHUT_WR); + if (use_sideband) + finish_async(&demux); + return -1; + } + } + if (args->stateless_rpc && cmds_sent) + packet_flush(out); + + if (status_report && cmds_sent) + ret = receive_status(in, remote_refs); + else + ret = 0; + if (args->stateless_rpc) + packet_flush(out); + + if (use_sideband && cmds_sent) { + if (finish_async(&demux)) { + error("error in sideband demultiplexer"); + ret = -1; + } + close(demux.out); + } + + if (ret < 0) + return ret; + + if (args->porcelain) + return 0; + + for (ref = remote_refs; ref; ref = ref->next) { + switch (ref->status) { + case REF_STATUS_NONE: + case REF_STATUS_UPTODATE: + case REF_STATUS_OK: + break; + default: + return -1; + } + } + return 0; +} diff --git a/sequencer.c b/sequencer.c index bf078f274..22604902a 100644 --- a/sequencer.c +++ b/sequencer.c @@ -17,7 +17,9 @@ #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" -void remove_sequencer_state(void) +const char sign_off_header[] = "Signed-off-by: "; + +static void remove_sequencer_state(void) { struct strbuf seq_dir = STRBUF_INIT; @@ -58,7 +60,7 @@ static int get_message(struct commit *commit, struct commit_message *out) out->reencoded_message = NULL; out->message = commit->buffer; - if (strcmp(encoding, git_commit_encoding)) + if (same_encoding(encoding, git_commit_encoding)) out->reencoded_message = reencode_string(commit->buffer, git_commit_encoding, encoding); if (out->reencoded_message) @@ -189,7 +191,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from) struct ref_lock *ref_lock; read_cache(); - if (checkout_fast_forward(from, to)) + if (checkout_fast_forward(from, to, 1)) exit(1); /* the callee should have complained already */ ref_lock = lock_any_ref_for_update("HEAD", from, 0); return write_ref_sha1(ref_lock, to, "cherry-pick"); @@ -233,6 +235,9 @@ static int do_recursive_merge(struct commit *base, struct commit *next, die(_("%s: Unable to write new index file"), action_name(opts)); rollback_lock_file(&index_lock); + if (opts->signoff) + append_signoff(msgbuf, 0); + if (!clean) { int i; strbuf_addstr(msgbuf, "\nConflicts:\n"); @@ -311,6 +316,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts, if (allow_empty) argv_array_push(&array, "--allow-empty"); + if (opts->allow_empty_message) + argv_array_push(&array, "--allow-empty-message"); + rc = run_command_v_opt(array.argv, RUN_GIT_CMD); argv_array_clear(&array); return rc; @@ -543,7 +551,11 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts) static void prepare_revs(struct replay_opts *opts) { - if (opts->action != REPLAY_REVERT) + /* + * picking (but not reverting) ranges (but not individual revisions) + * should be done in reverse + */ + if (opts->action == REPLAY_PICK && !opts->revs->no_walk) opts->revs->reverse ^= 1; if (prepare_revision_walk(opts->revs)) @@ -1004,3 +1016,63 @@ int sequencer_pick_revisions(struct replay_opts *opts) save_opts(opts); return pick_commits(todo_list, opts); } + +static int ends_rfc2822_footer(struct strbuf *sb, int ignore_footer) +{ + int ch; + int hit = 0; + int i, j, k; + int len = sb->len - ignore_footer; + int first = 1; + const char *buf = sb->buf; + + for (i = len - 1; i > 0; i--) { + if (hit && buf[i] == '\n') + break; + hit = (buf[i] == '\n'); + } + + while (i < len - 1 && buf[i] == '\n') + i++; + + for (; i < len; i = k) { + for (k = i; k < len && buf[k] != '\n'; k++) + ; /* do nothing */ + k++; + + if ((buf[k] == ' ' || buf[k] == '\t') && !first) + continue; + + first = 0; + + for (j = 0; i + j < len; j++) { + ch = buf[i + j]; + if (ch == ':') + break; + if (isalnum(ch) || + (ch == '-')) + continue; + return 0; + } + } + return 1; +} + +void append_signoff(struct strbuf *msgbuf, int ignore_footer) +{ + struct strbuf sob = STRBUF_INIT; + int i; + + strbuf_addstr(&sob, sign_off_header); + strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"), + getenv("GIT_COMMITTER_EMAIL"))); + strbuf_addch(&sob, '\n'); + for (i = msgbuf->len - 1 - ignore_footer; i > 0 && msgbuf->buf[i - 1] != '\n'; i--) + ; /* do nothing */ + if (prefixcmp(msgbuf->buf + i, sob.buf)) { + if (!i || !ends_rfc2822_footer(msgbuf, ignore_footer)) + strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0, "\n", 1); + strbuf_splice(msgbuf, msgbuf->len - ignore_footer, 0, sob.buf, sob.len); + } + strbuf_release(&sob); +} diff --git a/sequencer.h b/sequencer.h index aa5f17cc3..9d57d5752 100644 --- a/sequencer.h +++ b/sequencer.h @@ -30,6 +30,7 @@ struct replay_opts { int allow_ff; int allow_rerere_auto; int allow_empty; + int allow_empty_message; int keep_redundant_commits; int mainline; @@ -43,9 +44,10 @@ struct replay_opts { struct rev_info *revs; }; -/* Removes SEQ_DIR. */ -extern void remove_sequencer_state(void); - int sequencer_pick_revisions(struct replay_opts *opts); +extern const char sign_off_header[]; + +void append_signoff(struct strbuf *msgbuf, int ignore_footer); + #endif @@ -77,9 +77,6 @@ static void NORETURN die_verify_filename(const char *prefix, const char *arg, int diagnose_misspelt_rev) { - unsigned char sha1[20]; - unsigned mode; - if (!diagnose_misspelt_rev) die("%s: no such path in the working tree.\n" "Use 'git <command> -- <path>...' to specify paths that do not exist locally.", @@ -88,11 +85,10 @@ static void NORETURN die_verify_filename(const char *prefix, * Saying "'(icase)foo' does not exist in the index" when the * user gave us ":(icase)foo" is just stupid. A magic pathspec * begins with a colon and is followed by a non-alnum; do not - * let get_sha1_with_mode_1(only_to_die=1) to even trigger. + * let maybe_die_on_misspelt_object_name() even trigger. */ if (!(arg[0] == ':' && !isalnum(arg[1]))) - /* try a detailed diagnostic ... */ - get_sha1_with_mode_1(arg, sha1, &mode, 1, prefix); + maybe_die_on_misspelt_object_name(arg, prefix); /* ... or fall back the most general message. */ die("ambiguous argument '%s': unknown revision or path not in the working tree.\n" diff --git a/sha1-array.c b/sha1-array.c index b2f47f98f..6f4a2246c 100644 --- a/sha1-array.c +++ b/sha1-array.c @@ -14,7 +14,7 @@ static int void_hashcmp(const void *a, const void *b) return hashcmp(a, b); } -void sha1_array_sort(struct sha1_array *array) +static void sha1_array_sort(struct sha1_array *array) { qsort(array->sha1, array->nr, sizeof(*array->sha1), void_hashcmp); array->sorted = 1; diff --git a/sha1-array.h b/sha1-array.h index 4499b5dad..72bb33bec 100644 --- a/sha1-array.h +++ b/sha1-array.h @@ -11,7 +11,6 @@ struct sha1_array { #define SHA1_ARRAY_INIT { NULL, 0, 0, 0 } void sha1_array_append(struct sha1_array *array, const unsigned char *sha1); -void sha1_array_sort(struct sha1_array *array); int sha1_array_lookup(struct sha1_array *array, const unsigned char *sha1); void sha1_array_clear(struct sha1_array *array); diff --git a/sha1_file.c b/sha1_file.c index af5cfbde6..40b23297b 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -7,6 +7,7 @@ * creation etc. */ #include "cache.h" +#include "string-list.h" #include "delta.h" #include "pack.h" #include "blob.h" @@ -246,7 +247,7 @@ static int git_open_noatime(const char *name); * SHA1, an extra slash for the first level indirection, and the * terminating NUL. */ -static int link_alt_odb_entry(const char * entry, int len, const char * relative_base, int depth) +static int link_alt_odb_entry(const char *entry, const char *relative_base, int depth) { const char *objdir = get_object_directory(); struct alternate_object_database *ent; @@ -258,7 +259,7 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative strbuf_addstr(&pathbuf, real_path(relative_base)); strbuf_addch(&pathbuf, '/'); } - strbuf_add(&pathbuf, entry, len); + strbuf_addstr(&pathbuf, entry); normalize_path_copy(pathbuf.buf, pathbuf.buf); @@ -316,10 +317,12 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative return 0; } -static void link_alt_odb_entries(const char *alt, const char *ep, int sep, +static void link_alt_odb_entries(const char *alt, int len, int sep, const char *relative_base, int depth) { - const char *cp, *last; + struct string_list entries = STRING_LIST_INIT_NODUP; + char *alt_copy; + int i; if (depth > 5) { error("%s: ignoring alternate object stores, nesting too deep.", @@ -327,30 +330,21 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep, return; } - last = alt; - while (last < ep) { - cp = last; - if (cp < ep && *cp == '#') { - while (cp < ep && *cp != sep) - cp++; - last = cp + 1; + alt_copy = xmemdupz(alt, len); + string_list_split_in_place(&entries, alt_copy, sep, -1); + for (i = 0; i < entries.nr; i++) { + const char *entry = entries.items[i].string; + if (entry[0] == '\0' || entry[0] == '#') continue; + if (!is_absolute_path(entry) && depth) { + error("%s: ignoring relative alternate object store %s", + relative_base, entry); + } else { + link_alt_odb_entry(entry, relative_base, depth); } - while (cp < ep && *cp != sep) - cp++; - if (last != cp) { - if (!is_absolute_path(last) && depth) { - error("%s: ignoring relative alternate object store %s", - relative_base, last); - } else { - link_alt_odb_entry(last, cp - last, - relative_base, depth); - } - } - while (cp < ep && *cp == sep) - cp++; - last = cp; } + string_list_clear(&entries, 0); + free(alt_copy); } void read_info_alternates(const char * relative_base, int depth) @@ -377,7 +371,7 @@ void read_info_alternates(const char * relative_base, int depth) map = xmmap(NULL, mapsz, PROT_READ, MAP_PRIVATE, fd, 0); close(fd); - link_alt_odb_entries(map, map + mapsz, '\n', relative_base, depth); + link_alt_odb_entries(map, mapsz, '\n', relative_base, depth); munmap(map, mapsz); } @@ -391,7 +385,7 @@ void add_to_alternates_file(const char *reference) if (commit_lock_file(lock)) die("could not close alternates file"); if (alt_odb_tail) - link_alt_odb_entries(alt, alt + strlen(alt), '\n', NULL, 0); + link_alt_odb_entries(alt, strlen(alt), '\n', NULL, 0); } void foreach_alt_odb(alt_odb_fn fn, void *cb) @@ -415,7 +409,7 @@ void prepare_alt_odb(void) if (!alt) alt = ""; alt_odb_tail = &alt_odb_list; - link_alt_odb_entries(alt, alt + strlen(alt), PATH_SEP, NULL, 0); + link_alt_odb_entries(alt, strlen(alt), PATH_SEP, NULL, 0); read_info_alternates(get_object_directory(), 0); } @@ -731,6 +725,24 @@ void free_pack_by_name(const char *pack_name) } } +static unsigned int get_max_fd_limit(void) +{ +#ifdef RLIMIT_NOFILE + struct rlimit lim; + + if (getrlimit(RLIMIT_NOFILE, &lim)) + die_errno("cannot get RLIMIT_NOFILE"); + + return lim.rlim_cur; +#elif defined(_SC_OPEN_MAX) + return sysconf(_SC_OPEN_MAX); +#elif defined(OPEN_MAX) + return OPEN_MAX; +#else + return 1; /* see the caller ;-) */ +#endif +} + /* * Do not call this directly as this leaks p->pack_fd on error return; * call open_packed_git() instead. @@ -747,13 +759,7 @@ static int open_packed_git_1(struct packed_git *p) return error("packfile %s index unavailable", p->pack_name); if (!pack_max_fds) { - struct rlimit lim; - unsigned int max_fds; - - if (getrlimit(RLIMIT_NOFILE, &lim)) - die_errno("cannot get RLIMIT_NOFILE"); - - max_fds = lim.rlim_cur; + unsigned int max_fds = get_max_fd_limit(); /* Save 3 for stdin/stdout/stderr, 22 for work */ if (25 < max_fds) diff --git a/sha1_name.c b/sha1_name.c index 5d81ea056..95003c77e 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -9,14 +9,82 @@ static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *); -static int find_short_object_filename(int len, const char *name, unsigned char *sha1) +typedef int (*disambiguate_hint_fn)(const unsigned char *, void *); + +struct disambiguate_state { + disambiguate_hint_fn fn; + void *cb_data; + unsigned char candidate[20]; + unsigned candidate_exists:1; + unsigned candidate_checked:1; + unsigned candidate_ok:1; + unsigned disambiguate_fn_used:1; + unsigned ambiguous:1; + unsigned always_call_fn:1; +}; + +static void update_candidates(struct disambiguate_state *ds, const unsigned char *current) +{ + if (ds->always_call_fn) { + ds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0; + return; + } + if (!ds->candidate_exists) { + /* this is the first candidate */ + hashcpy(ds->candidate, current); + ds->candidate_exists = 1; + return; + } else if (!hashcmp(ds->candidate, current)) { + /* the same as what we already have seen */ + return; + } + + if (!ds->fn) { + /* cannot disambiguate between ds->candidate and current */ + ds->ambiguous = 1; + return; + } + + if (!ds->candidate_checked) { + ds->candidate_ok = ds->fn(ds->candidate, ds->cb_data); + ds->disambiguate_fn_used = 1; + ds->candidate_checked = 1; + } + + if (!ds->candidate_ok) { + /* discard the candidate; we know it does not satisify fn */ + hashcpy(ds->candidate, current); + ds->candidate_checked = 0; + return; + } + + /* if we reach this point, we know ds->candidate satisfies fn */ + if (ds->fn(current, ds->cb_data)) { + /* + * if both current and candidate satisfy fn, we cannot + * disambiguate. + */ + ds->candidate_ok = 0; + ds->ambiguous = 1; + } + + /* otherwise, current can be discarded and candidate is still good */ +} + +static void find_short_object_filename(int len, const char *hex_pfx, struct disambiguate_state *ds) { struct alternate_object_database *alt; char hex[40]; - int found = 0; static struct alternate_object_database *fakeent; if (!fakeent) { + /* + * Create a "fake" alternate object database that + * points to our own object database, to make it + * easier to get a temporary working space in + * alt->name/alt->base while iterating over the + * object databases including our own. + */ const char *objdir = get_object_directory(); int objdir_len = strlen(objdir); int entlen = objdir_len + 43; @@ -27,33 +95,28 @@ static int find_short_object_filename(int len, const char *name, unsigned char * } fakeent->next = alt_odb_list; - sprintf(hex, "%.2s", name); - for (alt = fakeent; alt && found < 2; alt = alt->next) { + sprintf(hex, "%.2s", hex_pfx); + for (alt = fakeent; alt && !ds->ambiguous; alt = alt->next) { struct dirent *de; DIR *dir; - sprintf(alt->name, "%.2s/", name); + sprintf(alt->name, "%.2s/", hex_pfx); dir = opendir(alt->base); if (!dir) continue; - while ((de = readdir(dir)) != NULL) { + + while (!ds->ambiguous && (de = readdir(dir)) != NULL) { + unsigned char sha1[20]; + if (strlen(de->d_name) != 38) continue; - if (memcmp(de->d_name, name + 2, len - 2)) + if (memcmp(de->d_name, hex_pfx + 2, len - 2)) continue; - if (!found) { - memcpy(hex + 2, de->d_name, 38); - found++; - } - else if (memcmp(hex + 2, de->d_name, 38)) { - found = 2; - break; - } + memcpy(hex + 2, de->d_name, 38); + if (!get_sha1_hex(hex, sha1)) + update_candidates(ds, sha1); } closedir(dir); } - if (found == 1) - return get_sha1_hex(hex, sha1) == 0; - return found; } static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b) @@ -71,103 +134,157 @@ static int match_sha(unsigned len, const unsigned char *a, const unsigned char * return 1; } -static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1) +static void unique_in_pack(int len, + const unsigned char *bin_pfx, + struct packed_git *p, + struct disambiguate_state *ds) { - struct packed_git *p; - const unsigned char *found_sha1 = NULL; - int found = 0; - - prepare_packed_git(); - for (p = packed_git; p && found < 2; p = p->next) { - uint32_t num, last; - uint32_t first = 0; - open_pack_index(p); - num = p->num_objects; - last = num; - while (first < last) { - uint32_t mid = (first + last) / 2; - const unsigned char *now; - int cmp; - - now = nth_packed_object_sha1(p, mid); - cmp = hashcmp(match, now); - if (!cmp) { - first = mid; - break; - } - if (cmp > 0) { - first = mid+1; - continue; - } - last = mid; + uint32_t num, last, i, first = 0; + const unsigned char *current = NULL; + + open_pack_index(p); + num = p->num_objects; + last = num; + while (first < last) { + uint32_t mid = (first + last) / 2; + const unsigned char *current; + int cmp; + + current = nth_packed_object_sha1(p, mid); + cmp = hashcmp(bin_pfx, current); + if (!cmp) { + first = mid; + break; } - if (first < num) { - const unsigned char *now, *next; - now = nth_packed_object_sha1(p, first); - if (match_sha(len, match, now)) { - next = nth_packed_object_sha1(p, first+1); - if (!next|| !match_sha(len, match, next)) { - /* unique within this pack */ - if (!found) { - found_sha1 = now; - found++; - } - else if (hashcmp(found_sha1, now)) { - found = 2; - break; - } - } - else { - /* not even unique within this pack */ - found = 2; - break; - } - } + if (cmp > 0) { + first = mid+1; + continue; } + last = mid; + } + + /* + * At this point, "first" is the location of the lowest object + * with an object name that could match "bin_pfx". See if we have + * 0, 1 or more objects that actually match(es). + */ + for (i = first; i < num && !ds->ambiguous; i++) { + current = nth_packed_object_sha1(p, i); + if (!match_sha(len, bin_pfx, current)) + break; + update_candidates(ds, current); } - if (found == 1) - hashcpy(sha1, found_sha1); - return found; +} + +static void find_short_packed_object(int len, const unsigned char *bin_pfx, + struct disambiguate_state *ds) +{ + struct packed_git *p; + + prepare_packed_git(); + for (p = packed_git; p && !ds->ambiguous; p = p->next) + unique_in_pack(len, bin_pfx, p, ds); } #define SHORT_NAME_NOT_FOUND (-1) #define SHORT_NAME_AMBIGUOUS (-2) -static int find_unique_short_object(int len, char *canonical, - unsigned char *res, unsigned char *sha1) +static int finish_object_disambiguation(struct disambiguate_state *ds, + unsigned char *sha1) { - int has_unpacked, has_packed; - unsigned char unpacked_sha1[20], packed_sha1[20]; + if (ds->ambiguous) + return SHORT_NAME_AMBIGUOUS; - prepare_alt_odb(); - has_unpacked = find_short_object_filename(len, canonical, unpacked_sha1); - has_packed = find_short_packed_object(len, res, packed_sha1); - if (!has_unpacked && !has_packed) + if (!ds->candidate_exists) return SHORT_NAME_NOT_FOUND; - if (1 < has_unpacked || 1 < has_packed) + + if (!ds->candidate_checked) + /* + * If this is the only candidate, there is no point + * calling the disambiguation hint callback. + * + * On the other hand, if the current candidate + * replaced an earlier candidate that did _not_ pass + * the disambiguation hint callback, then we do have + * more than one objects that match the short name + * given, so we should make sure this one matches; + * otherwise, if we discovered this one and the one + * that we previously discarded in the reverse order, + * we would end up showing different results in the + * same repository! + */ + ds->candidate_ok = (!ds->disambiguate_fn_used || + ds->fn(ds->candidate, ds->cb_data)); + + if (!ds->candidate_ok) return SHORT_NAME_AMBIGUOUS; - if (has_unpacked != has_packed) { - hashcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1)); + + hashcpy(sha1, ds->candidate); + return 0; +} + +static int disambiguate_commit_only(const unsigned char *sha1, void *cb_data_unused) +{ + int kind = sha1_object_info(sha1, NULL); + return kind == OBJ_COMMIT; +} + +static int disambiguate_committish_only(const unsigned char *sha1, void *cb_data_unused) +{ + struct object *obj; + int kind; + + kind = sha1_object_info(sha1, NULL); + if (kind == OBJ_COMMIT) + return 1; + if (kind != OBJ_TAG) return 0; - } - /* Both have unique ones -- do they match? */ - if (hashcmp(packed_sha1, unpacked_sha1)) - return SHORT_NAME_AMBIGUOUS; - hashcpy(sha1, packed_sha1); + + /* We need to do this the hard way... */ + obj = deref_tag(lookup_object(sha1), NULL, 0); + if (obj && obj->type == OBJ_COMMIT) + return 1; return 0; } -static int get_short_sha1(const char *name, int len, unsigned char *sha1, - int quietly) +static int disambiguate_tree_only(const unsigned char *sha1, void *cb_data_unused) { - int i, status; - char canonical[40]; - unsigned char res[20]; + int kind = sha1_object_info(sha1, NULL); + return kind == OBJ_TREE; +} - if (len < MINIMUM_ABBREV || len > 40) - return -1; - hashclr(res); - memset(canonical, 'x', 40); +static int disambiguate_treeish_only(const unsigned char *sha1, void *cb_data_unused) +{ + struct object *obj; + int kind; + + kind = sha1_object_info(sha1, NULL); + if (kind == OBJ_TREE || kind == OBJ_COMMIT) + return 1; + if (kind != OBJ_TAG) + return 0; + + /* We need to do this the hard way... */ + obj = deref_tag(lookup_object(sha1), NULL, 0); + if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT)) + return 1; + return 0; +} + +static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unused) +{ + int kind = sha1_object_info(sha1, NULL); + return kind == OBJ_BLOB; +} + +static int prepare_prefixes(const char *name, int len, + unsigned char *bin_pfx, + char *hex_pfx) +{ + int i; + + hashclr(bin_pfx); + memset(hex_pfx, 'x', 40); for (i = 0; i < len ;i++) { unsigned char c = name[i]; unsigned char val; @@ -181,18 +298,76 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1, } else return -1; - canonical[i] = c; + hex_pfx[i] = c; if (!(i & 1)) val <<= 4; - res[i >> 1] |= val; + bin_pfx[i >> 1] |= val; } + return 0; +} + +static int get_short_sha1(const char *name, int len, unsigned char *sha1, + unsigned flags) +{ + int status; + char hex_pfx[40]; + unsigned char bin_pfx[20]; + struct disambiguate_state ds; + int quietly = !!(flags & GET_SHA1_QUIETLY); + + if (len < MINIMUM_ABBREV || len > 40) + return -1; + if (prepare_prefixes(name, len, bin_pfx, hex_pfx) < 0) + return -1; + + prepare_alt_odb(); + + memset(&ds, 0, sizeof(ds)); + if (flags & GET_SHA1_COMMIT) + ds.fn = disambiguate_commit_only; + else if (flags & GET_SHA1_COMMITTISH) + ds.fn = disambiguate_committish_only; + else if (flags & GET_SHA1_TREE) + ds.fn = disambiguate_tree_only; + else if (flags & GET_SHA1_TREEISH) + ds.fn = disambiguate_treeish_only; + else if (flags & GET_SHA1_BLOB) + ds.fn = disambiguate_blob_only; + + find_short_object_filename(len, hex_pfx, &ds); + find_short_packed_object(len, bin_pfx, &ds); + status = finish_object_disambiguation(&ds, sha1); - status = find_unique_short_object(i, canonical, res, sha1); if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) - return error("short SHA1 %.*s is ambiguous.", len, canonical); + return error("short SHA1 %.*s is ambiguous.", len, hex_pfx); return status; } + +int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data) +{ + char hex_pfx[40]; + unsigned char bin_pfx[20]; + struct disambiguate_state ds; + int len = strlen(prefix); + + if (len < MINIMUM_ABBREV || len > 40) + return -1; + if (prepare_prefixes(prefix, len, bin_pfx, hex_pfx) < 0) + return -1; + + prepare_alt_odb(); + + memset(&ds, 0, sizeof(ds)); + ds.always_call_fn = 1; + ds.cb_data = cb_data; + ds.fn = fn; + + find_short_object_filename(len, hex_pfx, &ds); + find_short_packed_object(len, bin_pfx, &ds); + return ds.ambiguous; +} + const char *find_unique_abbrev(const unsigned char *sha1, int len) { int status, exists; @@ -204,7 +379,7 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len) return hex; while (len < 40) { unsigned char sha1_ret[20]; - status = get_short_sha1(hex, len, sha1_ret, 1); + status = get_short_sha1(hex, len, sha1_ret, GET_SHA1_QUIETLY); if (exists ? !status : status == SHORT_NAME_NOT_FOUND) { @@ -255,7 +430,7 @@ static inline int upstream_mark(const char *string, int len) return 0; } -static int get_sha1_1(const char *name, int len, unsigned char *sha1); +static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags); static int get_sha1_basic(const char *str, int len, unsigned char *sha1) { @@ -292,7 +467,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) ret = interpret_branch_name(str+at, &buf); if (ret > 0) { /* substitute this branch name and restart */ - return get_sha1_1(buf.buf, buf.len, sha1); + return get_sha1_1(buf.buf, buf.len, sha1, 0); } else if (ret == 0) { return -1; } @@ -362,7 +537,7 @@ static int get_parent(const char *name, int len, unsigned char *result, int idx) { unsigned char sha1[20]; - int ret = get_sha1_1(name, len, sha1); + int ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH); struct commit *commit; struct commit_list *p; @@ -395,7 +570,7 @@ static int get_nth_ancestor(const char *name, int len, struct commit *commit; int ret; - ret = get_sha1_1(name, len, sha1); + ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH); if (ret) return ret; commit = lookup_commit_reference(sha1); @@ -441,6 +616,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1) unsigned char outer[20]; const char *sp; unsigned int expected_type = 0; + unsigned lookup_flags = 0; struct object *o; /* @@ -476,7 +652,10 @@ static int peel_onion(const char *name, int len, unsigned char *sha1) else return -1; - if (get_sha1_1(name, sp - name - 2, outer)) + if (expected_type == OBJ_COMMIT) + lookup_flags = GET_SHA1_COMMITTISH; + + if (get_sha1_1(name, sp - name - 2, outer, lookup_flags)) return -1; o = parse_object(outer); @@ -525,6 +704,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1) static int get_describe_name(const char *name, int len, unsigned char *sha1) { const char *cp; + unsigned flags = GET_SHA1_QUIETLY | GET_SHA1_COMMIT; for (cp = name + len - 1; name + 2 <= cp; cp--) { char ch = *cp; @@ -535,14 +715,14 @@ static int get_describe_name(const char *name, int len, unsigned char *sha1) if (ch == 'g' && cp[-1] == '-') { cp++; len -= cp - name; - return get_short_sha1(cp, len, sha1, 1); + return get_short_sha1(cp, len, sha1, flags); } } } return -1; } -static int get_sha1_1(const char *name, int len, unsigned char *sha1) +static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags) { int ret, has_suffix; const char *cp; @@ -587,7 +767,7 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1) if (!ret) return 0; - return get_short_sha1(name, len, sha1, 0); + return get_short_sha1(name, len, sha1, lookup_flags); } /* @@ -769,7 +949,7 @@ int get_sha1_mb(const char *name, unsigned char *sha1) struct strbuf sb; strbuf_init(&sb, dots - name); strbuf_add(&sb, name, dots - name); - st = get_sha1(sb.buf, sha1_tmp); + st = get_sha1_committish(sb.buf, sha1_tmp); strbuf_release(&sb); } if (st) @@ -778,7 +958,7 @@ int get_sha1_mb(const char *name, unsigned char *sha1) if (!one) return -1; - if (get_sha1(dots[3] ? (dots + 3) : "HEAD", sha1_tmp)) + if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", sha1_tmp)) return -1; two = lookup_commit_reference_gently(sha1_tmp, 0); if (!two) @@ -905,7 +1085,52 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name) int get_sha1(const char *name, unsigned char *sha1) { struct object_context unused; - return get_sha1_with_context(name, sha1, &unused); + return get_sha1_with_context(name, 0, sha1, &unused); +} + +/* + * Many callers know that the user meant to name a committish by + * syntactical positions where the object name appears. Calling this + * function allows the machinery to disambiguate shorter-than-unique + * abbreviated object names between committish and others. + * + * Note that this does NOT error out when the named object is not a + * committish. It is merely to give a hint to the disambiguation + * machinery. + */ +int get_sha1_committish(const char *name, unsigned char *sha1) +{ + struct object_context unused; + return get_sha1_with_context(name, GET_SHA1_COMMITTISH, + sha1, &unused); +} + +int get_sha1_treeish(const char *name, unsigned char *sha1) +{ + struct object_context unused; + return get_sha1_with_context(name, GET_SHA1_TREEISH, + sha1, &unused); +} + +int get_sha1_commit(const char *name, unsigned char *sha1) +{ + struct object_context unused; + return get_sha1_with_context(name, GET_SHA1_COMMIT, + sha1, &unused); +} + +int get_sha1_tree(const char *name, unsigned char *sha1) +{ + struct object_context unused; + return get_sha1_with_context(name, GET_SHA1_TREE, + sha1, &unused); +} + +int get_sha1_blob(const char *name, unsigned char *sha1) +{ + struct object_context unused; + return get_sha1_with_context(name, GET_SHA1_BLOB, + sha1, &unused); } /* Must be called only when object_name:filename doesn't exist. */ @@ -1004,16 +1229,6 @@ static void diagnose_invalid_index_path(int stage, } -int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, - int only_to_die, const char *prefix) -{ - struct object_context oc; - int ret; - ret = get_sha1_with_context_1(name, sha1, &oc, only_to_die, prefix); - *mode = oc.mode; - return ret; -} - static char *resolve_relative_path(const char *rel) { if (prefixcmp(rel, "./") && prefixcmp(rel, "../")) @@ -1031,20 +1246,24 @@ static char *resolve_relative_path(const char *rel) rel); } -int get_sha1_with_context_1(const char *name, unsigned char *sha1, - struct object_context *oc, - int only_to_die, const char *prefix) +static int get_sha1_with_context_1(const char *name, + unsigned flags, + const char *prefix, + unsigned char *sha1, + struct object_context *oc) { int ret, bracket_depth; int namelen = strlen(name); const char *cp; + int only_to_die = flags & GET_SHA1_ONLY_TO_DIE; memset(oc, 0, sizeof(*oc)); oc->mode = S_IFINVALID; - ret = get_sha1_1(name, namelen, sha1); + ret = get_sha1_1(name, namelen, sha1, flags); if (!ret) return ret; - /* sha1:path --> object name of path in ent sha1 + /* + * sha1:path --> object name of path in ent sha1 * :path -> object name of absolute path in index * :./path -> object name of path relative to cwd in index * :[0-3]:path -> object name of path in index at stage @@ -1119,7 +1338,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, strncpy(object_name, name, cp-name); object_name[cp-name] = '\0'; } - if (!get_sha1_1(name, cp-name, tree_sha1)) { + if (!get_sha1_1(name, cp-name, tree_sha1, GET_SHA1_TREEISH)) { const char *filename = cp+1; char *new_filename = NULL; @@ -1146,3 +1365,22 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, } return ret; } + +/* + * Call this function when you know "name" given by the end user must + * name an object but it doesn't; the function _may_ die with a better + * diagnostic message than "no such object 'name'", e.g. "Path 'doc' does not + * exist in 'HEAD'" when given "HEAD:doc", or it may return in which case + * you have a chance to diagnose the error further. + */ +void maybe_die_on_misspelt_object_name(const char *name, const char *prefix) +{ + struct object_context oc; + unsigned char sha1[20]; + get_sha1_with_context_1(name, GET_SHA1_ONLY_TO_DIE, prefix, sha1, &oc); +} + +int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc) +{ + return get_sha1_with_context_1(str, flags, NULL, sha1, orc); +} @@ -44,7 +44,9 @@ void strbuf_release(struct strbuf *sb) char *strbuf_detach(struct strbuf *sb, size_t *sz) { - char *res = sb->alloc ? sb->buf : NULL; + char *res; + strbuf_grow(sb, 0); + res = sb->buf; if (sz) *sz = sb->len; strbuf_init(sb, 0); @@ -104,35 +106,30 @@ void strbuf_ltrim(struct strbuf *sb) sb->buf[sb->len] = '\0'; } -struct strbuf **strbuf_split_buf(const char *str, size_t slen, int delim, int max) +struct strbuf **strbuf_split_buf(const char *str, size_t slen, + int terminator, int max) { - int alloc = 2, pos = 0; - const char *n, *p; - struct strbuf **ret; + struct strbuf **ret = NULL; + size_t nr = 0, alloc = 0; struct strbuf *t; - ret = xcalloc(alloc, sizeof(struct strbuf *)); - p = n = str; - while (n < str + slen) { - int len; - if (max <= 0 || pos + 1 < max) - n = memchr(n, delim, slen - (n - str)); - else - n = NULL; - if (pos + 1 >= alloc) { - alloc = alloc * 2; - ret = xrealloc(ret, sizeof(struct strbuf *) * alloc); + while (slen) { + int len = slen; + if (max <= 0 || nr + 1 < max) { + const char *end = memchr(str, terminator, slen); + if (end) + len = end - str + 1; } - if (!n) - n = str + slen - 1; - len = n - p + 1; t = xmalloc(sizeof(struct strbuf)); strbuf_init(t, len); - strbuf_add(t, p, len); - ret[pos] = t; - ret[++pos] = NULL; - p = ++n; + strbuf_add(t, str, len); + ALLOC_GROW(ret, nr + 2, alloc); + ret[nr++] = t; + str += len; + slen -= len; } + ALLOC_GROW(ret, nr + 1, alloc); /* In case string was empty */ + ret[nr] = NULL; return ret; } @@ -445,8 +442,8 @@ static int is_rfc3986_unreserved(char ch) ch == '-' || ch == '_' || ch == '.' || ch == '~'; } -void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len, - int reserved) +static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len, + int reserved) { strbuf_grow(sb, len); while (len--) { @@ -465,15 +462,6 @@ void strbuf_addstr_urlencode(struct strbuf *sb, const char *s, strbuf_add_urlencode(sb, s, strlen(s), reserved); } -void strbuf_addf_ln(struct strbuf *sb, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - strbuf_vaddf(sb, fmt, ap); - va_end(ap); - strbuf_addch(sb, '\n'); -} - int printf_ln(const char *fmt, ...) { int ret; @@ -44,22 +44,56 @@ extern void strbuf_rtrim(struct strbuf *); extern void strbuf_ltrim(struct strbuf *); extern int strbuf_cmp(const struct strbuf *, const struct strbuf *); +/* + * Split str (of length slen) at the specified terminator character. + * Return a null-terminated array of pointers to strbuf objects + * holding the substrings. The substrings include the terminator, + * except for the last substring, which might be unterminated if the + * original string did not end with a terminator. If max is positive, + * then split the string into at most max substrings (with the last + * substring containing everything following the (max-1)th terminator + * character). + * + * For lighter-weight alternatives, see string_list_split() and + * string_list_split_in_place(). + */ extern struct strbuf **strbuf_split_buf(const char *, size_t, - int delim, int max); + int terminator, int max); + +/* + * Split a NUL-terminated string at the specified terminator + * character. See strbuf_split_buf() for more information. + */ static inline struct strbuf **strbuf_split_str(const char *str, - int delim, int max) + int terminator, int max) { - return strbuf_split_buf(str, strlen(str), delim, max); + return strbuf_split_buf(str, strlen(str), terminator, max); } + +/* + * Split a strbuf at the specified terminator character. See + * strbuf_split_buf() for more information. + */ static inline struct strbuf **strbuf_split_max(const struct strbuf *sb, - int delim, int max) + int terminator, int max) { - return strbuf_split_buf(sb->buf, sb->len, delim, max); + return strbuf_split_buf(sb->buf, sb->len, terminator, max); } -static inline struct strbuf **strbuf_split(const struct strbuf *sb, int delim) + +/* + * Split a strbuf at the specified terminator character. See + * strbuf_split_buf() for more information. + */ +static inline struct strbuf **strbuf_split(const struct strbuf *sb, + int terminator) { - return strbuf_split_max(sb, delim, 0); + return strbuf_split_max(sb, terminator, 0); } + +/* + * Free a NULL-terminated list of strbufs (for example, the return + * values of the strbuf_split*() functions). + */ extern void strbuf_list_free(struct strbuf **); /*----- add data in your buffer -----*/ @@ -99,8 +133,6 @@ __attribute__((format (printf,2,3))) extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); __attribute__((format (printf,2,0))) extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap); -__attribute__((format (printf,2,3))) -extern void strbuf_addf_ln(struct strbuf *sb, const char *fmt, ...); extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size); @@ -126,8 +158,6 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co extern int strbuf_branchname(struct strbuf *sb, const char *name); extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name); -extern void strbuf_add_urlencode(struct strbuf *, const char *, size_t, - int reserved); extern void strbuf_addstr_urlencode(struct strbuf *, const char *, int reserved); diff --git a/string-list.c b/string-list.c index d9810aba4..397e6cfa7 100644 --- a/string-list.c +++ b/string-list.c @@ -92,6 +92,23 @@ struct string_list_item *string_list_lookup(struct string_list *list, const char return list->items + i; } +void string_list_remove_duplicates(struct string_list *list, int free_util) +{ + if (list->nr > 1) { + int src, dst; + for (src = dst = 1; src < list->nr; src++) { + if (!strcmp(list->items[dst - 1].string, list->items[src].string)) { + if (list->strdup_strings) + free(list->items[src].string); + if (free_util) + free(list->items[src].util); + } else + list->items[dst++] = list->items[src]; + } + list->nr = dst; + } +} + int for_each_string_list(struct string_list *list, string_list_each_func_t fn, void *cb_data) { @@ -102,6 +119,52 @@ int for_each_string_list(struct string_list *list, return ret; } +void filter_string_list(struct string_list *list, int free_util, + string_list_each_func_t want, void *cb_data) +{ + int src, dst = 0; + for (src = 0; src < list->nr; src++) { + if (want(&list->items[src], cb_data)) { + list->items[dst++] = list->items[src]; + } else { + if (list->strdup_strings) + free(list->items[src].string); + if (free_util) + free(list->items[src].util); + } + } + list->nr = dst; +} + +static int item_is_not_empty(struct string_list_item *item, void *unused) +{ + return *item->string != '\0'; +} + +void string_list_remove_empty_items(struct string_list *list, int free_util) { + filter_string_list(list, free_util, item_is_not_empty, NULL); +} + +char *string_list_longest_prefix(const struct string_list *prefixes, + const char *string) +{ + int i, max_len = -1; + char *retval = NULL; + + for (i = 0; i < prefixes->nr; i++) { + char *prefix = prefixes->items[i].string; + if (!prefixcmp(string, prefix)) { + int len = strlen(prefix); + if (len > max_len) { + retval = prefix; + max_len = len; + } + } + } + + return retval; +} + void string_list_clear(struct string_list *list, int free_util) { if (list->items) { @@ -148,13 +211,23 @@ void print_string_list(const struct string_list *p, const char *text) printf("%s:%p\n", p->items[i].string, p->items[i].util); } -struct string_list_item *string_list_append(struct string_list *list, const char *string) +struct string_list_item *string_list_append_nodup(struct string_list *list, + char *string) { + struct string_list_item *retval; ALLOC_GROW(list->items, list->nr + 1, list->alloc); - list->items[list->nr].string = - list->strdup_strings ? xstrdup(string) : (char *)string; - list->items[list->nr].util = NULL; - return list->items + list->nr++; + retval = &list->items[list->nr++]; + retval->string = string; + retval->util = NULL; + return retval; +} + +struct string_list_item *string_list_append(struct string_list *list, + const char *string) +{ + return string_list_append_nodup( + list, + list->strdup_strings ? xstrdup(string) : (char *)string); } static int cmp_items(const void *a, const void *b) @@ -194,3 +267,56 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_ list->items[i] = list->items[list->nr-1]; list->nr--; } + +int string_list_split(struct string_list *list, const char *string, + int delim, int maxsplit) +{ + int count = 0; + const char *p = string, *end; + + if (!list->strdup_strings) + die("internal error in string_list_split(): " + "list->strdup_strings must be set"); + for (;;) { + count++; + if (maxsplit >= 0 && count > maxsplit) { + string_list_append(list, p); + return count; + } + end = strchr(p, delim); + if (end) { + string_list_append_nodup(list, xmemdupz(p, end - p)); + p = end + 1; + } else { + string_list_append(list, p); + return count; + } + } +} + +int string_list_split_in_place(struct string_list *list, char *string, + int delim, int maxsplit) +{ + int count = 0; + char *p = string, *end; + + if (list->strdup_strings) + die("internal error in string_list_split_in_place(): " + "list->strdup_strings must not be set"); + for (;;) { + count++; + if (maxsplit >= 0 && count > maxsplit) { + string_list_append(list, p); + return count; + } + end = strchr(p, delim); + if (end) { + *end = '\0'; + string_list_append(list, p); + p = end + 1; + } else { + string_list_append(list, p); + return count; + } + } +} diff --git a/string-list.h b/string-list.h index 0684cb73b..c50b0d0de 100644 --- a/string-list.h +++ b/string-list.h @@ -29,6 +29,31 @@ int for_each_string_list(struct string_list *list, #define for_each_string_list_item(item,list) \ for (item = (list)->items; item < (list)->items + (list)->nr; ++item) +/* + * Apply want to each item in list, retaining only the ones for which + * the function returns true. If free_util is true, call free() on + * the util members of any items that have to be deleted. Preserve + * the order of the items that are retained. + */ +void filter_string_list(struct string_list *list, int free_util, + string_list_each_func_t want, void *cb_data); + +/* + * Remove any empty strings from the list. If free_util is true, call + * free() on the util members of any items that have to be deleted. + * Preserve the order of the items that are retained. + */ +void string_list_remove_empty_items(struct string_list *list, int free_util); + +/* + * Return the longest string in prefixes that is a prefix (in the + * sense of prefixcmp()) of string, or NULL if no such prefix exists. + * This function does not require the string_list to be sorted (it + * does a linear search). + */ +char *string_list_longest_prefix(const struct string_list *prefixes, const char *string); + + /* Use these functions only on sorted lists: */ int string_list_has_string(const struct string_list *list, const char *string); int string_list_find_insert_index(const struct string_list *list, const char *string, @@ -38,11 +63,64 @@ struct string_list_item *string_list_insert_at_index(struct string_list *list, int insert_at, const char *string); struct string_list_item *string_list_lookup(struct string_list *list, const char *string); +/* + * Remove all but the first of consecutive entries with the same + * string value. If free_util is true, call free() on the util + * members of any items that have to be deleted. + */ +void string_list_remove_duplicates(struct string_list *sorted_list, int free_util); + + /* Use these functions only on unsorted lists: */ + +/* + * Add string to the end of list. If list->strdup_string is set, then + * string is copied; otherwise the new string_list_entry refers to the + * input string. + */ struct string_list_item *string_list_append(struct string_list *list, const char *string); + +/* + * Like string_list_append(), except string is never copied. When + * list->strdup_strings is set, this function can be used to hand + * ownership of a malloc()ed string to list without making an extra + * copy. + */ +struct string_list_item *string_list_append_nodup(struct string_list *list, char *string); + void sort_string_list(struct string_list *list); int unsorted_string_list_has_string(struct string_list *list, const char *string); struct string_list_item *unsorted_string_list_lookup(struct string_list *list, const char *string); + void unsorted_string_list_delete_item(struct string_list *list, int i, int free_util); + +/* + * Split string into substrings on character delim and append the + * substrings to list. The input string is not modified. + * list->strdup_strings must be set, as new memory needs to be + * allocated to hold the substrings. If maxsplit is non-negative, + * then split at most maxsplit times. Return the number of substrings + * appended to list. + * + * Examples: + * string_list_split(l, "foo:bar:baz", ':', -1) -> ["foo", "bar", "baz"] + * string_list_split(l, "foo:bar:baz", ':', 0) -> ["foo:bar:baz"] + * string_list_split(l, "foo:bar:baz", ':', 1) -> ["foo", "bar:baz"] + * string_list_split(l, "foo:bar:", ':', -1) -> ["foo", "bar", ""] + * string_list_split(l, "", ':', -1) -> [""] + * string_list_split(l, ":", ':', -1) -> ["", ""] + */ +int string_list_split(struct string_list *list, const char *string, + int delim, int maxsplit); + +/* + * Like string_list_split(), except that string is split in-place: the + * delimiter characters in string are overwritten with NULs, and the + * new string_list_items point into string (which therefore must not + * be modified or freed while the string_list is in use). + * list->strdup_strings must *not* be set. + */ +int string_list_split_in_place(struct string_list *list, char *string, + int delim, int maxsplit); #endif /* STRING_LIST_H */ diff --git a/submodule.c b/submodule.c index 19dc6a6c0..2f5543623 100644 --- a/submodule.c +++ b/submodule.c @@ -258,7 +258,7 @@ int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg) void show_submodule_summary(FILE *f, const char *path, unsigned char one[20], unsigned char two[20], - unsigned dirty_submodule, + unsigned dirty_submodule, const char *meta, const char *del, const char *add, const char *reset) { struct rev_info rev; @@ -292,15 +292,15 @@ void show_submodule_summary(FILE *f, const char *path, return; } - strbuf_addf(&sb, "Submodule %s %s..", path, + strbuf_addf(&sb, "%sSubmodule %s %s..", meta, path, find_unique_abbrev(one, DEFAULT_ABBREV)); if (!fast_backward && !fast_forward) strbuf_addch(&sb, '.'); strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV)); if (message) - strbuf_addf(&sb, " %s\n", message); + strbuf_addf(&sb, " %s%s\n", message, reset); else - strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : ""); + strbuf_addf(&sb, "%s:%s\n", fast_backward ? " (rewind)" : "", reset); fwrite(sb.buf, sb.len, 1, f); if (!message) { @@ -588,13 +588,13 @@ static void calculate_changed_submodule_paths(void) initialized_fetch_ref_tips = 0; } -int fetch_populated_submodules(int num_options, const char **options, +int fetch_populated_submodules(const struct argv_array *options, const char *prefix, int command_line_option, int quiet) { - int i, result = 0, argc = 0, default_argc; + int i, result = 0; struct child_process cp; - const char **argv; + struct argv_array argv = ARGV_ARRAY_INIT; struct string_list_item *name_for_path; const char *work_tree = get_git_work_tree(); if (!work_tree) @@ -604,17 +604,13 @@ int fetch_populated_submodules(int num_options, const char **options, if (read_cache() < 0) die("index file corrupt"); - /* 6: "fetch" (options) --recurse-submodules-default default "--submodule-prefix" prefix NULL */ - argv = xcalloc(num_options + 6, sizeof(const char *)); - argv[argc++] = "fetch"; - for (i = 0; i < num_options; i++) - argv[argc++] = options[i]; - argv[argc++] = "--recurse-submodules-default"; - default_argc = argc++; - argv[argc++] = "--submodule-prefix"; + argv_array_push(&argv, "fetch"); + for (i = 0; i < options->argc; i++) + argv_array_push(&argv, options->argv[i]); + argv_array_push(&argv, "--recurse-submodules-default"); + /* default value, "--submodule-prefix" and its value are added later */ memset(&cp, 0, sizeof(cp)); - cp.argv = argv; cp.env = local_repo_env; cp.git_cmd = 1; cp.no_stdin = 1; @@ -674,16 +670,21 @@ int fetch_populated_submodules(int num_options, const char **options, if (!quiet) printf("Fetching submodule %s%s\n", prefix, ce->name); cp.dir = submodule_path.buf; - argv[default_argc] = default_argv; - argv[argc] = submodule_prefix.buf; + argv_array_push(&argv, default_argv); + argv_array_push(&argv, "--submodule-prefix"); + argv_array_push(&argv, submodule_prefix.buf); + cp.argv = argv.argv; if (run_command(&cp)) result = 1; + argv_array_pop(&argv); + argv_array_pop(&argv); + argv_array_pop(&argv); } strbuf_release(&submodule_path); strbuf_release(&submodule_git_dir); strbuf_release(&submodule_prefix); } - free(argv); + argv_array_clear(&argv); out: string_list_clear(&changed_submodule_paths, 1); return result; @@ -758,6 +759,86 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked) return dirty_submodule; } +int submodule_uses_gitfile(const char *path) +{ + struct child_process cp; + const char *argv[] = { + "submodule", + "foreach", + "--quiet", + "--recursive", + "test -f .git", + NULL, + }; + struct strbuf buf = STRBUF_INIT; + const char *git_dir; + + strbuf_addf(&buf, "%s/.git", path); + git_dir = read_gitfile(buf.buf); + if (!git_dir) { + strbuf_release(&buf); + return 0; + } + strbuf_release(&buf); + + /* Now test that all nested submodules use a gitfile too */ + memset(&cp, 0, sizeof(cp)); + cp.argv = argv; + cp.env = local_repo_env; + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.no_stderr = 1; + cp.no_stdout = 1; + cp.dir = path; + if (run_command(&cp)) + return 0; + + return 1; +} + +int ok_to_remove_submodule(const char *path) +{ + struct stat st; + ssize_t len; + struct child_process cp; + const char *argv[] = { + "status", + "--porcelain", + "-u", + "--ignore-submodules=none", + NULL, + }; + struct strbuf buf = STRBUF_INIT; + int ok_to_remove = 1; + + if ((lstat(path, &st) < 0) || is_empty_dir(path)) + return 1; + + if (!submodule_uses_gitfile(path)) + return 0; + + memset(&cp, 0, sizeof(cp)); + cp.argv = argv; + cp.env = local_repo_env; + cp.git_cmd = 1; + cp.no_stdin = 1; + cp.out = -1; + cp.dir = path; + if (start_command(&cp)) + die("Could not run 'git status --porcelain -uall --ignore-submodules=none' in submodule %s", path); + + len = strbuf_read(&buf, cp.out, 1024); + if (len > 2) + ok_to_remove = 0; + close(cp.out); + + if (finish_command(&cp)) + die("'git status --porcelain -uall --ignore-submodules=none' failed in submodule %s", path); + + strbuf_release(&buf); + return ok_to_remove; +} + static int find_first_merges(struct object_array *result, const char *path, struct commit *a, struct commit *b) { @@ -788,7 +869,7 @@ static int find_first_merges(struct object_array *result, const char *path, die("revision walk setup failed"); while ((commit = get_revision(&revs)) != NULL) { struct object *o = &(commit->object); - if (in_merge_bases(b, &commit, 1)) + if (in_merge_bases(b, commit)) add_object_array(o, NULL, &merges); } reset_revision_walk(); @@ -803,7 +884,7 @@ static int find_first_merges(struct object_array *result, const char *path, contains_another = 0; for (j = 0; j < merges.nr; j++) { struct commit *m2 = (struct commit *) merges.objects[j].item; - if (i != j && in_merge_bases(m2, &m1, 1)) { + if (i != j && in_merge_bases(m2, m1)) { contains_another = 1; break; } @@ -865,18 +946,18 @@ int merge_submodule(unsigned char result[20], const char *path, } /* check whether both changes are forward */ - if (!in_merge_bases(commit_base, &commit_a, 1) || - !in_merge_bases(commit_base, &commit_b, 1)) { + if (!in_merge_bases(commit_base, commit_a) || + !in_merge_bases(commit_base, commit_b)) { MERGE_WARNING(path, "commits don't follow merge-base"); return 0; } /* Case #1: a is contained in b or vice versa */ - if (in_merge_bases(commit_a, &commit_b, 1)) { + if (in_merge_bases(commit_a, commit_b)) { hashcpy(result, b); return 1; } - if (in_merge_bases(commit_b, &commit_a, 1)) { + if (in_merge_bases(commit_b, commit_a)) { hashcpy(result, a); return 1; } diff --git a/submodule.h b/submodule.h index e105b0ebe..3dc1b3fe8 100644 --- a/submodule.h +++ b/submodule.h @@ -2,6 +2,7 @@ #define SUBMODULE_H struct diff_options; +struct argv_array; enum { RECURSE_SUBMODULES_ON_DEMAND = -1, @@ -19,14 +20,16 @@ void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *); int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg); void show_submodule_summary(FILE *f, const char *path, unsigned char one[20], unsigned char two[20], - unsigned dirty_submodule, + unsigned dirty_submodule, const char *meta, const char *del, const char *add, const char *reset); void set_config_fetch_recurse_submodules(int value); void check_for_new_submodule_commits(unsigned char new_sha1[20]); -int fetch_populated_submodules(int num_options, const char **options, +int fetch_populated_submodules(const struct argv_array *options, const char *prefix, int command_line_option, int quiet); unsigned is_submodule_modified(const char *path, int ignore_untracked); +int submodule_uses_gitfile(const char *path); +int ok_to_remove_submodule(const char *path); int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20], const unsigned char a[20], const unsigned char b[20], int search); int find_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name, diff --git a/symlinks.c b/symlinks.c index 290036744..c2b41a850 100644 --- a/symlinks.c +++ b/symlinks.c @@ -1,5 +1,8 @@ #include "cache.h" +static int threaded_check_leading_path(struct cache_def *cache, const char *name, int len); +static int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len); + /* * Returns the length (on a path component basis) of the longest * common prefix match of 'name_a' and 'name_b'. @@ -231,7 +234,7 @@ int check_leading_path(const char *name, int len) * Return path length if leading path exists and is neither a * directory nor a symlink. */ -int threaded_check_leading_path(struct cache_def *cache, const char *name, int len) +static int threaded_check_leading_path(struct cache_def *cache, const char *name, int len) { int flags; int match_len = lstat_cache_matchlen(cache, name, len, &flags, @@ -263,7 +266,7 @@ int has_dirs_only_path(const char *name, int len, int prefix_len) * 'prefix_len', thus we then allow for symlinks in the prefix part as * long as those points to real existing directories. */ -int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len) +static int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len) { return lstat_cache(cache, name, len, FL_DIR|FL_FULLPATH, prefix_len) & diff --git a/t/Git-SVN/00compile.t b/t/Git-SVN/00compile.t new file mode 100644 index 000000000..c92fee453 --- /dev/null +++ b/t/Git-SVN/00compile.t @@ -0,0 +1,14 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More tests => 7; + +require_ok 'Git::SVN'; +require_ok 'Git::SVN::Utils'; +require_ok 'Git::SVN::Ra'; +require_ok 'Git::SVN::Log'; +require_ok 'Git::SVN::Migration'; +require_ok 'Git::IndexInfo'; +require_ok 'Git::SVN::GlobSpec'; diff --git a/t/Git-SVN/Utils/add_path_to_url.t b/t/Git-SVN/Utils/add_path_to_url.t new file mode 100644 index 000000000..bfbd87845 --- /dev/null +++ b/t/Git-SVN/Utils/add_path_to_url.t @@ -0,0 +1,27 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils qw( + add_path_to_url +); + +# A reference cannot be a hash key, so we use an array. +my @tests = ( + ["http://x.com", "bar"] => 'http://x.com/bar', + ["http://x.com", ""] => 'http://x.com', + ["http://x.com/foo/", undef] => 'http://x.com/foo/', + ["http://x.com/foo/", "/bar/baz/"] => 'http://x.com/foo/bar/baz/', + ["http://x.com", 'per%cent'] => 'http://x.com/per%25cent', +); + +while(@tests) { + my($have, $want) = splice @tests, 0, 2; + + my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have; + my $name = "add_path_to_url($args) eq $want"; + is add_path_to_url(@$have), $want, $name; +} diff --git a/t/Git-SVN/Utils/can_compress.t b/t/Git-SVN/Utils/can_compress.t new file mode 100644 index 000000000..d7b49b8d5 --- /dev/null +++ b/t/Git-SVN/Utils/can_compress.t @@ -0,0 +1,11 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils qw(can_compress); + +# !! is the "convert this to boolean" operator. +is !!can_compress(), !!eval { require Compress::Zlib }; diff --git a/t/Git-SVN/Utils/canonicalize_url.t b/t/Git-SVN/Utils/canonicalize_url.t new file mode 100644 index 000000000..05795ab63 --- /dev/null +++ b/t/Git-SVN/Utils/canonicalize_url.t @@ -0,0 +1,26 @@ +#!/usr/bin/env perl + +# Test our own home rolled URL canonicalizer. Test the private one +# directly because we can't predict what the SVN API is doing to do. + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils; +my $canonicalize_url = \&Git::SVN::Utils::_canonicalize_url_ourselves; + +my %tests = ( + "http://x.com" => "http://x.com", + "http://x.com/" => "http://x.com", + "http://x.com/foo/bar" => "http://x.com/foo/bar", + "http://x.com//foo//bar//" => "http://x.com/foo/bar", + "http://x.com/ /%/" => "http://x.com/%20%20/%25", +); + +for my $arg (keys %tests) { + my $want = $tests{$arg}; + + is $canonicalize_url->($arg), $want, "canonicalize_url('$arg') => $want"; +} diff --git a/t/Git-SVN/Utils/collapse_dotdot.t b/t/Git-SVN/Utils/collapse_dotdot.t new file mode 100644 index 000000000..1da1cce15 --- /dev/null +++ b/t/Git-SVN/Utils/collapse_dotdot.t @@ -0,0 +1,23 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils; +my $collapse_dotdot = \&Git::SVN::Utils::_collapse_dotdot; + +my %tests = ( + "foo/bar/baz" => "foo/bar/baz", + ".." => "..", + "foo/.." => "", + "/foo/bar/../../baz" => "/baz", + "deeply/.././deeply/nested" => "./deeply/nested", +); + +for my $arg (keys %tests) { + my $want = $tests{$arg}; + + is $collapse_dotdot->($arg), $want, "_collapse_dotdot('$arg') => $want"; +} diff --git a/t/Git-SVN/Utils/fatal.t b/t/Git-SVN/Utils/fatal.t new file mode 100644 index 000000000..49e143829 --- /dev/null +++ b/t/Git-SVN/Utils/fatal.t @@ -0,0 +1,34 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +BEGIN { + # Override exit at BEGIN time before Git::SVN::Utils is loaded + # so it will see our local exit later. + *CORE::GLOBAL::exit = sub(;$) { + return @_ ? CORE::exit($_[0]) : CORE::exit(); + }; +} + +use Git::SVN::Utils qw(fatal); + +# fatal() +{ + # Capture the exit code and prevent exit. + my $exit_status; + no warnings 'redefine'; + local *CORE::GLOBAL::exit = sub { $exit_status = $_[0] || 0 }; + + # Trap fatal's message to STDERR + my $stderr; + close STDERR; + ok open STDERR, ">", \$stderr; + + fatal "Some", "Stuff", "Happened"; + + is $stderr, "Some Stuff Happened\n"; + is $exit_status, 1; +} diff --git a/t/Git-SVN/Utils/join_paths.t b/t/Git-SVN/Utils/join_paths.t new file mode 100644 index 000000000..d4488e716 --- /dev/null +++ b/t/Git-SVN/Utils/join_paths.t @@ -0,0 +1,32 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils qw( + join_paths +); + +# A reference cannot be a hash key, so we use an array. +my @tests = ( + [] => '', + ["/x.com", "bar"] => '/x.com/bar', + ["x.com", ""] => 'x.com', + ["/x.com/foo/", undef, "bar"] => '/x.com/foo/bar', + ["x.com/foo/", "/bar/baz/"] => 'x.com/foo/bar/baz/', + ["foo", "bar"] => 'foo/bar', + ["/foo/bar", "baz", "/biff"] => '/foo/bar/baz/biff', + ["", undef, "."] => '.', + [] => '', + +); + +while(@tests) { + my($have, $want) = splice @tests, 0, 2; + + my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have; + my $name = "join_paths($args) eq '$want'"; + is join_paths(@$have), $want, $name; +} diff --git a/t/Makefile b/t/Makefile index 88e289fc8..5c6de8169 100644 --- a/t/Makefile +++ b/t/Makefile @@ -6,13 +6,14 @@ -include ../config.mak.autogen -include ../config.mak -#GIT_TEST_OPTS=--verbose --debug +#GIT_TEST_OPTS = --verbose --debug SHELL_PATH ?= $(SHELL) PERL_PATH ?= /usr/bin/perl TAR ?= $(TAR) RM ?= rm -f PROVE ?= prove DEFAULT_TEST_TARGET ?= test +TEST_LINT ?= test-lint-duplicates test-lint-executable # Shell quote; SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) @@ -625,6 +625,15 @@ use these, and "test_set_prereq" for how to define your own. Git was compiled with USE_LIBPCRE=YesPlease. Wrap any tests that use git-grep --perl-regexp or git-grep -P in these. + - CASE_INSENSITIVE_FS + + Test is run on a case insensitive file system. + + - UTF8_NFD_TO_NFC + + Test is run on a filesystem which converts decomposed utf-8 (nfd) + to precomposed utf-8 (nfc). + Tips for Writing Tests ---------------------- diff --git a/t/lib-bash.sh b/t/lib-bash.sh new file mode 100644 index 000000000..11397f747 --- /dev/null +++ b/t/lib-bash.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# +# Ensures that tests are run under Bash; primarily intended for running tests +# of the completion script. + +if test -n "$BASH" && test -z "$POSIXLY_CORRECT"; then + # we are in full-on bash mode + true +elif type bash >/dev/null 2>&1; then + # execute in full-on bash mode + unset POSIXLY_CORRECT + exec bash "$0" "$@" +else + echo '1..0 #SKIP skipping bash completion tests; bash not available' + exit 0 +fi + +. ./test-lib.sh diff --git a/t/lib-credential.sh b/t/lib-credential.sh index 4a37cd79e..3c43ff11b 100755 --- a/t/lib-credential.sh +++ b/t/lib-credential.sh @@ -4,10 +4,24 @@ # stdout and stderr should be provided on stdin, # separated by "--". check() { + credential_opts= + credential_cmd=$1 + shift + for arg in "$@"; do + credential_opts="$credential_opts -c credential.helper='$arg'" + done read_chunk >stdin && read_chunk >expect-stdout && read_chunk >expect-stderr && - test-credential "$@" <stdin >stdout 2>stderr && + if ! eval "git $credential_opts credential $credential_cmd <stdin >stdout 2>stderr"; then + echo "git credential failed with code $?" && + cat stderr && + false + fi && + if test_have_prereq MINGW + then + dos2unix -q stderr + fi && test_cmp expect-stdout stdout && test_cmp expect-stderr stderr } @@ -41,7 +55,7 @@ reject() { echo protocol=$2 echo host=$3 echo username=$4 - ) | test-credential reject $1 + ) | git -c credential.helper=$1 credential reject } helper_test() { @@ -52,6 +66,8 @@ helper_test() { protocol=https host=example.com -- + protocol=https + host=example.com username=askpass-username password=askpass-password -- @@ -74,6 +90,8 @@ helper_test() { protocol=https host=example.com -- + protocol=https + host=example.com username=store-user password=store-pass -- @@ -85,6 +103,8 @@ helper_test() { protocol=http host=example.com -- + protocol=http + host=example.com username=askpass-username password=askpass-password -- @@ -98,6 +118,8 @@ helper_test() { protocol=https host=other.tld -- + protocol=https + host=other.tld username=askpass-username password=askpass-password -- @@ -112,6 +134,8 @@ helper_test() { host=example.com username=other -- + protocol=https + host=example.com username=other password=askpass-password -- @@ -133,6 +157,9 @@ helper_test() { host=path.tld path=bar.git -- + protocol=http + host=path.tld + path=bar.git username=askpass-username password=askpass-password -- @@ -150,6 +177,8 @@ helper_test() { protocol=https host=example.com -- + protocol=https + host=example.com username=askpass-username password=askpass-password -- @@ -176,6 +205,8 @@ helper_test() { host=example.com username=user1 -- + protocol=https + host=example.com username=user1 password=pass1 EOF @@ -184,6 +215,8 @@ helper_test() { host=example.com username=user2 -- + protocol=https + host=example.com username=user2 password=pass2 EOF @@ -200,6 +233,8 @@ helper_test() { host=example.com username=user1 -- + protocol=https + host=example.com username=user1 password=askpass-password -- @@ -213,6 +248,8 @@ helper_test() { host=example.com username=user2 -- + protocol=https + host=example.com username=user2 password=pass2 EOF @@ -234,6 +271,8 @@ helper_test_timeout() { protocol=https host=timeout.tld -- + protocol=https + host=timeout.tld username=askpass-username password=askpass-password -- diff --git a/t/lib-gettext.sh b/t/lib-gettext.sh index 0f76f6cdc..ae8883a07 100644 --- a/t/lib-gettext.sh +++ b/t/lib-gettext.sh @@ -14,12 +14,14 @@ export GIT_TEXTDOMAINDIR GIT_PO_PATH if test_have_prereq GETTEXT && ! test_have_prereq GETTEXT_POISON then # is_IS.UTF-8 on Solaris and FreeBSD, is_IS.utf8 on Debian - is_IS_locale=$(locale -a | sed -n '/^is_IS\.[uU][tT][fF]-*8$/{ + is_IS_locale=$(locale -a 2>/dev/null | + sed -n '/^is_IS\.[uU][tT][fF]-*8$/{ p q }') # is_IS.ISO8859-1 on Solaris and FreeBSD, is_IS.iso88591 on Debian - is_IS_iso_locale=$(locale -a | sed -n '/^is_IS\.[iI][sS][oO]8859-*1$/{ + is_IS_iso_locale=$(locale -a 2>/dev/null | + sed -n '/^is_IS\.[iI][sS][oO]8859-*1$/{ p q }') diff --git a/t/lib-git-p4.sh b/t/lib-git-p4.sh index 121e38002..7061dce7e 100644 --- a/t/lib-git-p4.sh +++ b/t/lib-git-p4.sh @@ -2,6 +2,10 @@ # Library code for git p4 tests # +# p4 tests never use the top-level repo; always build/clone into +# a subdirectory called "$git" +TEST_NO_CREATE_REPO=NoThanks + . ./test-lib.sh if ! test_have_prereq PYTHON; then @@ -22,28 +26,54 @@ testid=${this_test#t} git_p4_test_start=9800 P4DPORT=$((10669 + ($testid - $git_p4_test_start))) -export P4PORT=localhost:$P4DPORT -export P4CLIENT=client -export P4EDITOR=: +P4PORT=localhost:$P4DPORT +P4CLIENT=client +P4EDITOR=: +export P4PORT P4CLIENT P4EDITOR db="$TRASH_DIRECTORY/db" -cli="$TRASH_DIRECTORY/cli" +cli=$(test-path-utils real_path "$TRASH_DIRECTORY/cli") git="$TRASH_DIRECTORY/git" pidfile="$TRASH_DIRECTORY/p4d.pid" start_p4d() { mkdir -p "$db" "$cli" "$git" && + rm -f "$pidfile" && ( p4d -q -r "$db" -p $P4DPORT & echo $! >"$pidfile" ) && - for i in 1 2 3 4 5 ; do - p4 info >/dev/null 2>&1 && break || true && - echo waiting for p4d to start && + + # This gives p4d a long time to start up, as it can be + # quite slow depending on the machine. Set this environment + # variable to something smaller to fail faster in, say, + # an automated test setup. If the p4d process dies, that + # will be caught with the "kill -0" check below. + i=${P4D_START_PATIENCE:-300} + pid=$(cat "$pidfile") + ready= + while test $i -gt 0 + do + # succeed when p4 client commands start to work + if p4 info >/dev/null 2>&1 + then + ready=true + break + fi + # fail if p4d died + kill -0 $pid 2>/dev/null || break + echo waiting for p4d to start sleep 1 - done && - # complain if it never started - p4 info >/dev/null && + i=$(( $i - 1 )) + done + + if test -z "$ready" + then + # p4d failed to start + return 1 + fi + + # build a client ( cd "$cli" && p4 client -i <<-EOF @@ -53,6 +83,7 @@ start_p4d() { View: //depot/... //client/... EOF ) + return 0 } kill_p4d() { @@ -69,5 +100,36 @@ kill_p4d() { } cleanup_git() { - rm -rf "$git" + rm -rf "$git" && + mkdir "$git" +} + +marshal_dump() { + what=$1 && + line=${2:-1} && + cat >"$TRASH_DIRECTORY/marshal-dump.py" <<-EOF && + import marshal + import sys + for i in range($line): + d = marshal.load(sys.stdin) + print d['$what'] + EOF + "$PYTHON_PATH" "$TRASH_DIRECTORY/marshal-dump.py" +} + +# +# Construct a client with this list of View lines +# +client_view() { + ( + cat <<-EOF && + Client: client + Description: client + Root: $cli + View: + EOF + for arg ; do + printf "\t$arg\n" + done + ) | p4 client -i } diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index 0f31ef9be..02f442bfa 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -43,6 +43,10 @@ TEST_PATH="$TEST_DIRECTORY"/lib-httpd HTTPD_ROOT_PATH="$PWD"/httpd HTTPD_DOCUMENT_ROOT_PATH=$HTTPD_ROOT_PATH/www +# hack to suppress apache PassEnv warnings +GIT_VALGRIND=$GIT_VALGRIND; export GIT_VALGRIND +GIT_VALGRIND_OPTIONS=$GIT_VALGRIND_OPTIONS; export GIT_VALGRIND_OPTIONS + if ! test -x "$LIB_HTTPD_PATH" then skip_all="skipping test, no web server found at '$LIB_HTTPD_PATH'" diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index ec8618dfd..fe76e84b7 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -42,6 +42,9 @@ ErrorLog error.log </IfModule> </IfVersion> +PassEnv GIT_VALGRIND +PassEnv GIT_VALGRIND_OPTIONS + Alias /dumb/ www/ Alias /auth/dumb/ www/auth/dumb/ @@ -60,7 +63,7 @@ Alias /auth/dumb/ www/auth/dumb/ </LocationMatch> ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1 <Directory ${GIT_EXEC_PATH}> - Options None + Options FollowSymlinks </Directory> <Files ${GIT_EXEC_PATH}/git-http-backend> Options ExecCGI @@ -96,6 +99,13 @@ SSLEngine On Require valid-user </LocationMatch> +<LocationMatch "^/auth-fetch/.*/git-upload-pack$"> + AuthType Basic + AuthName "git-auth" + AuthUserFile passwd + Require valid-user +</LocationMatch> + <IfDefine DAV> LoadModule dav_module modules/mod_dav.so LoadModule dav_fs_module modules/mod_dav_fs.so diff --git a/t/perf/.gitignore b/t/perf/.gitignore index 50f5cc1ed..982eb8e3a 100644 --- a/t/perf/.gitignore +++ b/t/perf/.gitignore @@ -1,2 +1,3 @@ -build/ -test-results/ +/build/ +/test-results/ +/trash directory*/ diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh index a1361e530..a816fbcb7 100644 --- a/t/perf/perf-lib.sh +++ b/t/perf/perf-lib.sh @@ -42,6 +42,7 @@ else fi TEST_NO_CREATE_REPO=t +TEST_NO_MALLOC_CHECK=t . ../test-lib.sh diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index ccb5435b2..562cf41ca 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -18,16 +18,6 @@ swapping compression and hashing order, the person who is making the modification *should* take notice and update the test vectors here. ' -################################################################ -# It appears that people try to run tests without building... - -../git >/dev/null -if test $? != 1 -then - echo >&2 'You do not seem to have built git yet.' - exit 1 -fi - . ./test-lib.sh ################################################################ @@ -125,6 +115,38 @@ then exit 1 fi +test_lazy_prereq LAZY_TRUE true +havetrue=no +test_expect_success LAZY_TRUE 'test runs if lazy prereq is satisfied' ' + havetrue=yes +' +donthavetrue=yes +test_expect_success !LAZY_TRUE 'missing lazy prereqs skip tests' ' + donthavetrue=no +' + +if test "$havetrue$donthavetrue" != yesyes +then + say 'bug in test framework: lazy prerequisites do not work' + exit 1 +fi + +test_lazy_prereq LAZY_FALSE false +nothavefalse=no +test_expect_success !LAZY_FALSE 'negative lazy prereqs checked' ' + nothavefalse=yes +' +havefalse=yes +test_expect_success LAZY_FALSE 'missing negative lazy prereqs will skip' ' + havefalse=no +' + +if test "$nothavefalse$havefalse" != yesyes +then + say 'bug in test framework: negative lazy prerequisites do not work' + exit 1 +fi + clean=no test_expect_success 'tests clean up after themselves' ' test_when_finished clean=yes @@ -450,24 +472,6 @@ test_expect_success 'update-index D/F conflict' ' test $numpath0 = 1 ' -test_expect_success SYMLINKS 'real path works as expected' ' - mkdir first && - ln -s ../.git first/.git && - mkdir second && - ln -s ../first second/other && - mkdir third && - dir="$(cd .git; pwd -P)" && - dir2=third/../second/other/.git && - test "$dir" = "$(test-path-utils real_path $dir2)" && - file="$dir"/index && - test "$file" = "$(test-path-utils real_path $dir2/index)" && - basename=blub && - test "$dir/$basename" = "$(cd .git && test-path-utils real_path "$basename")" && - ln -s ../first/file .git/syml && - sym="$(cd first; pwd -P)"/file && - test "$sym" = "$(test-path-utils real_path "$dir2/syml")" -' - test_expect_success 'very long name in the index handled sanely' ' a=a && # 1 diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh index 51f3045ba..807b8b88e 100755 --- a/t/t0003-attributes.sh +++ b/t/t0003-attributes.sh @@ -123,16 +123,6 @@ test_expect_success 'attribute matching is case insensitive when core.ignorecase ' -test_expect_success 'check whether FS is case-insensitive' ' - mkdir junk && - echo good >junk/CamelCase && - echo bad >junk/camelcase && - if test "$(cat junk/CamelCase)" != good - then - test_set_prereq CASE_INSENSITIVE_FS - fi -' - test_expect_success CASE_INSENSITIVE_FS 'additional case insensitivity tests' ' test_must_fail attr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=0" && test_must_fail attr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=0" && @@ -206,6 +196,16 @@ test_expect_success 'root subdir attribute test' ' attr_check subdir/a/i unspecified ' +test_expect_success 'negative patterns' ' + echo "!f test=bar" >.gitattributes && + test_must_fail git check-attr test -- f +' + +test_expect_success 'patterns starting with exclamation' ' + echo "\!f test=foo" >.gitattributes && + attr_check "!f" foo +' + test_expect_success 'setup bare' ' git clone --bare . bare.git && cd bare.git diff --git a/t/t0006-date.sh b/t/t0006-date.sh index 1d29810a7..e53cf6d36 100755 --- a/t/t0006-date.sh +++ b/t/t0006-date.sh @@ -11,7 +11,7 @@ check_show() { echo "$t -> $2" >expect test_expect_${3:-success} "relative date ($2)" " test-date show $t >actual && - test_cmp expect actual + test_i18ncmp expect actual " } diff --git a/t/t0007-git-var.sh b/t/t0007-git-var.sh new file mode 100755 index 000000000..5868a8735 --- /dev/null +++ b/t/t0007-git-var.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +test_description='basic sanity checks for git var' +. ./test-lib.sh + +test_expect_success 'get GIT_AUTHOR_IDENT' ' + test_tick && + echo "$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect && + git var GIT_AUTHOR_IDENT >actual && + test_cmp expect actual +' + +test_expect_success 'get GIT_COMMITTER_IDENT' ' + test_tick && + echo "$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE" >expect && + git var GIT_COMMITTER_IDENT >actual && + test_cmp expect actual +' + +test_expect_success !AUTOIDENT 'requested identites are strict' ' + ( + sane_unset GIT_COMMITTER_NAME && + sane_unset GIT_COMMITTER_EMAIL && + test_must_fail git var GIT_COMMITTER_IDENT + ) +' + +# For git var -l, we check only a representative variable; +# testing the whole output would make our test too brittle with +# respect to unrelated changes in the test suite's environment. +test_expect_success 'git var -l lists variables' ' + git var -l >actual && + echo "$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect && + sed -n s/GIT_AUTHOR_IDENT=//p <actual >actual.author && + test_cmp expect actual.author +' + +test_expect_success 'git var -l lists config' ' + git var -l >actual && + echo false >expect && + sed -n s/core\\.bare=//p <actual >actual.bare && + test_cmp expect actual.bare +' + +test_expect_success 'listing and asking for variables are exclusive' ' + test_must_fail git var -l GIT_COMMITTER_IDENT +' + +test_done diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index e3f354a45..244a43c92 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -51,7 +51,7 @@ EOF test_expect_success 'test help' ' test_must_fail test-parse-options -h > output 2> output.err && test ! -s output.err && - test_cmp expect output + test_i18ncmp expect output ' mv expect expect.err @@ -79,6 +79,17 @@ check() { test_cmp expect output } +check_i18n() { + what="$1" && + shift && + expect="$1" && + shift && + sed "s/^$what .*/$what $expect/" <expect.template >expect && + test-parse-options $* >output 2>output.err && + test ! -s output.err && + test_i18ncmp expect output +} + check_unknown() { case "$1" in --*) @@ -92,6 +103,19 @@ check_unknown() { test_cmp expect output.err } +check_unknown_i18n() { + case "$1" in + --*) + echo error: unknown option \`${1#--}\' >expect ;; + -*) + echo error: unknown switch \`${1#-}\' >expect ;; + esac && + cat expect.err >>expect && + test_must_fail test-parse-options $* >output 2>output.err && + test ! -s output && + test_i18ncmp expect output.err +} + test_expect_success 'OPT_BOOL() #1' 'check boolean: 1 --yes' test_expect_success 'OPT_BOOL() #2' 'check boolean: 1 --no-doubt' test_expect_success 'OPT_BOOL() #3' 'check boolean: 1 -D' @@ -104,8 +128,8 @@ test_expect_success 'OPT_BOOL() is idempotent #2' 'check boolean: 1 -DB' test_expect_success 'OPT_BOOL() negation #1' 'check boolean: 0 -D --no-yes' test_expect_success 'OPT_BOOL() negation #2' 'check boolean: 0 -D --no-no-doubt' -test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown --fear' -test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown --no-no-fear' +test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown_i18n --fear' +test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown_i18n --no-no-fear' test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt' @@ -310,8 +334,8 @@ EOF test_expect_success 'OPT_CALLBACK() and callback errors work' ' test_must_fail test-parse-options --no-length > output 2> output.err && - test_cmp expect output && - test_cmp expect.err output.err + test_i18ncmp expect output && + test_i18ncmp expect.err output.err ' cat > expect <<EOF diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh index 1542cf6a1..78816d9d9 100755 --- a/t/t0050-filesystem.sh +++ b/t/t0050-filesystem.sh @@ -7,48 +7,26 @@ test_description='Various filesystem issues' auml=$(printf '\303\244') aumlcdiar=$(printf '\141\314\210') -case_insensitive= -unibad= -no_symlinks= -test_expect_success 'see what we expect' ' - - test_case=test_expect_success && - test_unicode=test_expect_success && - mkdir junk && - echo good >junk/CamelCase && - echo bad >junk/camelcase && - if test "$(cat junk/CamelCase)" != good - then - test_case=test_expect_failure && - case_insensitive=t - fi && - rm -fr junk && - mkdir junk && - >junk/"$auml" && - case "$(cd junk && echo *)" in - "$aumlcdiar") - test_unicode=test_expect_failure && - unibad=t - ;; - *) ;; - esac && - rm -fr junk && - { - ln -s x y 2> /dev/null && - test -h y 2> /dev/null || - no_symlinks=1 && - rm -f y - } -' - -test "$case_insensitive" && +if test_have_prereq CASE_INSENSITIVE_FS +then say "will test on a case insensitive filesystem" -test "$unibad" && + test_case=test_expect_failure +else + test_case=test_expect_success +fi + +if test_have_prereq UTF8_NFD_TO_NFC +then say "will test on a unicode corrupting filesystem" -test "$no_symlinks" && + test_unicode=test_expect_failure +else + test_unicode=test_expect_success +fi + +test_have_prereq SYMLINKS || say "will test on a filesystem lacking symbolic links" -if test "$case_insensitive" +if test_have_prereq CASE_INSENSITIVE_FS then test_expect_success "detection of case insensitive filesystem during repo init" ' @@ -62,18 +40,18 @@ test_expect_success "detection of case insensitive filesystem during repo init" ' fi -if test "$no_symlinks" +if test_have_prereq SYMLINKS then test_expect_success "detection of filesystem w/o symlink support during repo init" ' - v=$(git config --bool core.symlinks) && - test "$v" = false + test_must_fail git config --bool core.symlinks || + test "$(git config --bool core.symlinks)" = true ' else test_expect_success "detection of filesystem w/o symlink support during repo init" ' - test_must_fail git config --bool core.symlinks || - test "$(git config --bool core.symlinks)" = true + v=$(git config --bool core.symlinks) && + test "$v" = false ' fi diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index 53cf1f8dc..4ef234598 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -139,4 +139,63 @@ test_expect_success 'strip_path_suffix' ' test c:/msysgit = $(test-path-utils strip_path_suffix \ c:/msysgit/libexec//git-core libexec/git-core) ' + +test_expect_success 'absolute path rejects the empty string' ' + test_must_fail test-path-utils absolute_path "" +' + +test_expect_success 'real path rejects the empty string' ' + test_must_fail test-path-utils real_path "" +' + +test_expect_success POSIX 'real path works on absolute paths 1' ' + nopath="hopefully-absent-path" && + test "/" = "$(test-path-utils real_path "/")" && + test "/$nopath" = "$(test-path-utils real_path "/$nopath")" +' + +test_expect_success 'real path works on absolute paths 2' ' + nopath="hopefully-absent-path" && + # Find an existing top-level directory for the remaining tests: + d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") && + test "$d" = "$(test-path-utils real_path "$d")" && + test "$d/$nopath" = "$(test-path-utils real_path "$d/$nopath")" +' + +test_expect_success POSIX 'real path removes extra leading slashes' ' + nopath="hopefully-absent-path" && + test "/" = "$(test-path-utils real_path "///")" && + test "/$nopath" = "$(test-path-utils real_path "///$nopath")" && + # Find an existing top-level directory for the remaining tests: + d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") && + test "$d" = "$(test-path-utils real_path "//$d")" && + test "$d/$nopath" = "$(test-path-utils real_path "//$d/$nopath")" +' + +test_expect_success 'real path removes other extra slashes' ' + nopath="hopefully-absent-path" && + # Find an existing top-level directory for the remaining tests: + d=$(pwd -P | sed -e "s|^\([^/]*/[^/]*\)/.*|\1|") && + test "$d" = "$(test-path-utils real_path "$d///")" && + test "$d/$nopath" = "$(test-path-utils real_path "$d///$nopath")" +' + +test_expect_success SYMLINKS 'real path works on symlinks' ' + mkdir first && + ln -s ../.git first/.git && + mkdir second && + ln -s ../first second/other && + mkdir third && + dir="$(cd .git; pwd -P)" && + dir2=third/../second/other/.git && + test "$dir" = "$(test-path-utils real_path $dir2)" && + file="$dir"/index && + test "$file" = "$(test-path-utils real_path $dir2/index)" && + basename=blub && + test "$dir/$basename" = "$(cd .git && test-path-utils real_path "$basename")" && + ln -s ../first/file .git/syml && + sym="$(cd first; pwd -P)"/file && + test "$sym" = "$(test-path-utils real_path "$dir2/syml")" +' + test_done diff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh new file mode 100755 index 000000000..41c8826a7 --- /dev/null +++ b/t/t0063-string-list.sh @@ -0,0 +1,121 @@ +#!/bin/sh +# +# Copyright (c) 2012 Michael Haggerty +# + +test_description='Test string list functionality' + +. ./test-lib.sh + +test_split () { + cat >expected && + test_expect_success "split $1 at $2, max $3" " + test-string-list split '$1' '$2' '$3' >actual && + test_cmp expected actual && + test-string-list split_in_place '$1' '$2' '$3' >actual && + test_cmp expected actual + " +} + +test_longest_prefix () { + test "$(test-string-list longest_prefix "$1" "$2")" = "$3" +} + +test_no_longest_prefix () { + test_must_fail test-string-list longest_prefix "$1" "$2" +} + +test_split "foo:bar:baz" ":" "-1" <<EOF +3 +[0]: "foo" +[1]: "bar" +[2]: "baz" +EOF + +test_split "foo:bar:baz" ":" "0" <<EOF +1 +[0]: "foo:bar:baz" +EOF + +test_split "foo:bar:baz" ":" "1" <<EOF +2 +[0]: "foo" +[1]: "bar:baz" +EOF + +test_split "foo:bar:baz" ":" "2" <<EOF +3 +[0]: "foo" +[1]: "bar" +[2]: "baz" +EOF + +test_split "foo:bar:" ":" "-1" <<EOF +3 +[0]: "foo" +[1]: "bar" +[2]: "" +EOF + +test_split "" ":" "-1" <<EOF +1 +[0]: "" +EOF + +test_split ":" ":" "-1" <<EOF +2 +[0]: "" +[1]: "" +EOF + +test_expect_success "test filter_string_list" ' + test "x-" = "x$(test-string-list filter - y)" && + test "x-" = "x$(test-string-list filter no y)" && + test yes = "$(test-string-list filter yes y)" && + test yes = "$(test-string-list filter no:yes y)" && + test yes = "$(test-string-list filter yes:no y)" && + test y1:y2 = "$(test-string-list filter y1:y2 y)" && + test y2:y1 = "$(test-string-list filter y2:y1 y)" && + test "x-" = "x$(test-string-list filter x1:x2 y)" +' + +test_expect_success "test remove_duplicates" ' + test "x-" = "x$(test-string-list remove_duplicates -)" && + test "x" = "x$(test-string-list remove_duplicates "")" && + test a = "$(test-string-list remove_duplicates a)" && + test a = "$(test-string-list remove_duplicates a:a)" && + test a = "$(test-string-list remove_duplicates a:a:a:a:a)" && + test a:b = "$(test-string-list remove_duplicates a:b)" && + test a:b = "$(test-string-list remove_duplicates a:a:b)" && + test a:b = "$(test-string-list remove_duplicates a:b:b)" && + test a:b:c = "$(test-string-list remove_duplicates a:b:c)" && + test a:b:c = "$(test-string-list remove_duplicates a:a:b:c)" && + test a:b:c = "$(test-string-list remove_duplicates a:b:b:c)" && + test a:b:c = "$(test-string-list remove_duplicates a:b:c:c)" && + test a:b:c = "$(test-string-list remove_duplicates a:a:b:b:c:c)" && + test a:b:c = "$(test-string-list remove_duplicates a:a:a:b:b:b:c:c:c)" +' + +test_expect_success "test longest_prefix" ' + test_no_longest_prefix - '' && + test_no_longest_prefix - x && + test_longest_prefix "" x "" && + test_longest_prefix x x x && + test_longest_prefix "" foo "" && + test_longest_prefix : foo "" && + test_longest_prefix f foo f && + test_longest_prefix foo foobar foo && + test_longest_prefix foo foo foo && + test_no_longest_prefix bar foo && + test_no_longest_prefix bar:bar foo && + test_no_longest_prefix foobar foo && + test_longest_prefix foo:bar foo foo && + test_longest_prefix foo:bar bar bar && + test_longest_prefix foo::bar foo foo && + test_longest_prefix foo:foobar foo foo && + test_longest_prefix foobar:foo foo foo && + test_longest_prefix foo: bar "" && + test_longest_prefix :foo bar "" +' + +test_done diff --git a/t/t0201-gettext-fallbacks.sh b/t/t0201-gettext-fallbacks.sh index 52b1c27c2..5d80a985f 100755 --- a/t/t0201-gettext-fallbacks.sh +++ b/t/t0201-gettext-fallbacks.sh @@ -51,16 +51,16 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate v test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces' ' cmdline="git am" && export cmdline; - printf "When you have resolved this problem run git am --resolved." >expect && - eval_gettext "When you have resolved this problem run \$cmdline --resolved." >actual + printf "When you have resolved this problem, run git am --resolved." >expect && + eval_gettext "When you have resolved this problem, run \$cmdline --resolved." >actual test_i18ncmp expect actual ' test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces and quotes' ' cmdline="git am" && export cmdline; - printf "When you have resolved this problem run \"git am --resolved\"." >expect && - eval_gettext "When you have resolved this problem run \"\$cmdline --resolved\"." >actual + printf "When you have resolved this problem, run \"git am --resolved\"." >expect && + eval_gettext "When you have resolved this problem, run \"\$cmdline --resolved\"." >actual test_i18ncmp expect actual ' diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index 20e28e34e..538ea5fb1 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -82,6 +82,9 @@ test_expect_success 'credential_fill passes along metadata' ' host=example.com path=foo.git -- + protocol=ftp + host=example.com + path=foo.git username=one password=two -- @@ -213,6 +216,8 @@ test_expect_success 'match configured credential' ' host=example.com path=repo.git -- + protocol=https + host=example.com username=foo password=bar -- @@ -225,6 +230,8 @@ test_expect_success 'do not match configured credential' ' protocol=https host=bar -- + protocol=https + host=bar username=askpass-username password=askpass-password -- @@ -239,6 +246,8 @@ test_expect_success 'pull username from config' ' protocol=https host=example.com -- + protocol=https + host=example.com username=foo password=askpass-password -- @@ -252,6 +261,8 @@ test_expect_success 'http paths can be part of context' ' host=example.com path=foo.git -- + protocol=https + host=example.com username=foo password=bar -- @@ -265,6 +276,9 @@ test_expect_success 'http paths can be part of context' ' host=example.com path=foo.git -- + protocol=https + host=example.com + path=foo.git username=foo password=bar -- diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh index e23ac0e69..1e2945ec7 100755 --- a/t/t1020-subdirectory.sh +++ b/t/t1020-subdirectory.sh @@ -111,19 +111,19 @@ test_expect_success 'read-tree' ' test_expect_success 'alias expansion' ' ( - git config alias.ss status && + git config alias.test-status-alias status && cd dir && git status && - git ss + git test-status-alias ) ' test_expect_success NOT_MINGW '!alias expansion' ' pwd >expect && ( - git config alias.test !pwd && + git config alias.test-alias-directory !pwd && cd dir && - git test >../actual + git test-alias-directory >../actual ) && test_cmp expect actual ' @@ -131,9 +131,9 @@ test_expect_success NOT_MINGW '!alias expansion' ' test_expect_success 'GIT_PREFIX for !alias' ' printf "dir/" >expect && ( - git config alias.test "!sh -c \"printf \$GIT_PREFIX\"" && + git config alias.test-alias-directory "!sh -c \"printf \$GIT_PREFIX\"" && cd dir && - git test >../actual + git test-alias-directory >../actual ) && test_cmp expect actual ' diff --git a/t/t1050-large.sh b/t/t1050-large.sh index 55ed955ce..fd1052800 100755 --- a/t/t1050-large.sh +++ b/t/t1050-large.sh @@ -130,10 +130,27 @@ test_expect_success 'git-show a large file' ' ' +test_expect_success 'index-pack' ' + git clone file://"`pwd`"/.git foo && + GIT_DIR=non-existent git index-pack --strict --verify foo/.git/objects/pack/*.pack +' + test_expect_success 'repack' ' git repack -ad ' +test_expect_success 'pack-objects with large loose object' ' + SHA1=`git hash-object huge` && + test_create_repo loose && + echo $SHA1 | git pack-objects --stdout | + GIT_ALLOC_LIMIT=0 GIT_DIR=loose/.git git unpack-objects && + echo $SHA1 | GIT_DIR=loose/.git git pack-objects pack && + test_create_repo packed && + mv pack-* packed/.git/objects/pack && + GIT_DIR=packed/.git git cat-file blob $SHA1 >actual && + cmp huge actual +' + test_expect_success 'tar achiving' ' git archive --format=tar HEAD >/dev/null ' diff --git a/t/t1100-commit-tree-options.sh b/t/t1100-commit-tree-options.sh index a3b77239f..f8457f9d1 100755 --- a/t/t1100-commit-tree-options.sh +++ b/t/t1100-commit-tree-options.sh @@ -47,6 +47,7 @@ test_expect_success \ test_expect_success 'flags and then non flags' ' + test_tick && echo comment text | git commit-tree $(cat treeid) >commitid && echo comment text | diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index a477453e2..3c96fda54 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -55,11 +55,13 @@ test_expect_success 'uppercase section' ' test_cmp expect .git/config ' -test_expect_success 'replace with non-match' \ - 'git config core.penguin kingpin !blue' +test_expect_success 'replace with non-match' ' + git config core.penguin kingpin !blue +' -test_expect_success 'replace with non-match (actually matching)' \ - 'git config core.penguin "very blue" !kingpin' +test_expect_success 'replace with non-match (actually matching)' ' + git config core.penguin "very blue" !kingpin +' cat > expect << EOF [core] @@ -108,8 +110,9 @@ baz = multiple \ lines EOF -test_expect_success 'unset with cont. lines' \ - 'git config --unset beta.baz' +test_expect_success 'unset with cont. lines' ' + git config --unset beta.baz +' cat > expect <<\EOF [alpha] @@ -133,8 +136,9 @@ EOF cp .git/config .git/config2 -test_expect_success 'multiple unset' \ - 'git config --unset-all beta.haha' +test_expect_success 'multiple unset' ' + git config --unset-all beta.haha +' cat > expect << EOF [beta] ; silly comment # another comment @@ -145,7 +149,9 @@ noIndent= sillyValue ; 'nother silly comment [nextSection] noNewline = ouch EOF -test_expect_success 'multiple unset is correct' 'test_cmp expect .git/config' +test_expect_success 'multiple unset is correct' ' + test_cmp expect .git/config +' cp .git/config2 .git/config @@ -156,8 +162,9 @@ test_expect_success '--replace-all missing value' ' rm .git/config2 -test_expect_success '--replace-all' \ - 'git config --replace-all beta.haha gamma' +test_expect_success '--replace-all' ' + git config --replace-all beta.haha gamma +' cat > expect << EOF [beta] ; silly comment # another comment @@ -169,7 +176,9 @@ noIndent= sillyValue ; 'nother silly comment [nextSection] noNewline = ouch EOF -test_expect_success 'all replaced' 'test_cmp expect .git/config' +test_expect_success 'all replaced' ' + test_cmp expect .git/config +' cat > expect << EOF [beta] ; silly comment # another comment @@ -200,7 +209,11 @@ test_expect_success 'really really mean test' ' test_cmp expect .git/config ' -test_expect_success 'get value' 'test alpha = $(git config beta.haha)' +test_expect_success 'get value' ' + echo alpha >expect && + git config beta.haha >actual && + test_cmp expect actual +' cat > expect << EOF [beta] ; silly comment # another comment @@ -231,18 +244,30 @@ test_expect_success 'multivar' ' test_cmp expect .git/config ' -test_expect_success 'non-match' \ - 'git config --get nextsection.nonewline !for' +test_expect_success 'non-match' ' + git config --get nextsection.nonewline !for +' -test_expect_success 'non-match value' \ - 'test wow = $(git config --get nextsection.nonewline !for)' +test_expect_success 'non-match value' ' + echo wow >expect && + git config --get nextsection.nonewline !for >actual && + test_cmp expect actual +' -test_expect_success 'ambiguous get' ' - test_must_fail git config --get nextsection.nonewline +test_expect_success 'multi-valued get returns final one' ' + echo "wow2 for me" >expect && + git config --get nextsection.nonewline >actual && + test_cmp expect actual ' -test_expect_success 'get multivar' \ - 'git config --get-all nextsection.nonewline' +test_expect_success 'multi-valued get-all returns all' ' + cat >expect <<-\EOF && + wow + wow2 for me + EOF + git config --get-all nextsection.nonewline >actual && + test_cmp expect actual +' cat > expect << EOF [beta] ; silly comment # another comment @@ -259,10 +284,6 @@ test_expect_success 'multivar replace' ' test_cmp expect .git/config ' -test_expect_success 'ambiguous value' ' - test_must_fail git config nextsection.nonewline -' - test_expect_success 'ambiguous unset' ' test_must_fail git config --unset nextsection.nonewline ' @@ -290,8 +311,9 @@ test_expect_success 'invalid key' 'test_must_fail git config inval.2key blabla' test_expect_success 'correct key' 'git config 123456.a123 987' -test_expect_success 'hierarchical section' \ - 'git config Version.1.2.3eX.Alpha beta' +test_expect_success 'hierarchical section' ' + git config Version.1.2.3eX.Alpha beta +' cat > expect << EOF [beta] ; silly comment # another comment @@ -307,7 +329,9 @@ noIndent= sillyValue ; 'nother silly comment Alpha = beta EOF -test_expect_success 'hierarchical section value' 'test_cmp expect .git/config' +test_expect_success 'hierarchical section value' ' + test_cmp expect .git/config +' cat > expect << EOF beta.noindent=sillyValue @@ -316,9 +340,10 @@ nextsection.nonewline=wow2 for me version.1.2.3eX.alpha=beta EOF -test_expect_success 'working --list' \ - 'git config --list > output && cmp output expect' - +test_expect_success 'working --list' ' + git config --list > output && + test_cmp expect output +' cat > expect << EOF EOF @@ -332,8 +357,10 @@ beta.noindent sillyValue nextsection.nonewline wow2 for me EOF -test_expect_success '--get-regexp' \ - 'git config --get-regexp in > output && cmp output expect' +test_expect_success '--get-regexp' ' + git config --get-regexp in >output && + test_cmp expect output +' cat > expect << EOF wow2 for me @@ -353,45 +380,52 @@ cat > .git/config << EOF variable = EOF -test_expect_success 'get variable with no value' \ - 'git config --get novalue.variable ^$' +test_expect_success 'get variable with no value' ' + git config --get novalue.variable ^$ +' -test_expect_success 'get variable with empty value' \ - 'git config --get emptyvalue.variable ^$' +test_expect_success 'get variable with empty value' ' + git config --get emptyvalue.variable ^$ +' echo novalue.variable > expect -test_expect_success 'get-regexp variable with no value' \ - 'git config --get-regexp novalue > output && - cmp output expect' +test_expect_success 'get-regexp variable with no value' ' + git config --get-regexp novalue > output && + test_cmp expect output +' echo 'novalue.variable true' > expect -test_expect_success 'get-regexp --bool variable with no value' \ - 'git config --bool --get-regexp novalue > output && - cmp output expect' +test_expect_success 'get-regexp --bool variable with no value' ' + git config --bool --get-regexp novalue > output && + test_cmp expect output +' echo 'emptyvalue.variable ' > expect -test_expect_success 'get-regexp variable with empty value' \ - 'git config --get-regexp emptyvalue > output && - cmp output expect' +test_expect_success 'get-regexp variable with empty value' ' + git config --get-regexp emptyvalue > output && + test_cmp expect output +' echo true > expect -test_expect_success 'get bool variable with no value' \ - 'git config --bool novalue.variable > output && - cmp output expect' +test_expect_success 'get bool variable with no value' ' + git config --bool novalue.variable > output && + test_cmp expect output +' echo false > expect -test_expect_success 'get bool variable with empty value' \ - 'git config --bool emptyvalue.variable > output && - cmp output expect' +test_expect_success 'get bool variable with empty value' ' + git config --bool emptyvalue.variable > output && + test_cmp expect output +' test_expect_success 'no arguments, but no crash' ' test_must_fail git config >output 2>&1 && - grep usage output + test_i18ngrep usage output ' cat > .git/config << EOF @@ -427,8 +461,9 @@ test_expect_success 'new variable inserts into proper section' ' test_cmp expect .git/config ' -test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' \ - 'test_must_fail git config --file non-existing-config -l' +test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' ' + test_must_fail git config --file non-existing-config -l +' cat > other-config << EOF [ein] @@ -444,8 +479,10 @@ test_expect_success 'alternative GIT_CONFIG' ' test_cmp expect output ' -test_expect_success 'alternative GIT_CONFIG (--file)' \ - 'git config --file other-config -l > output && cmp output expect' +test_expect_success 'alternative GIT_CONFIG (--file)' ' + git config --file other-config -l > output && + test_cmp expect output +' test_expect_success 'refer config from subdirectory' ' mkdir x && @@ -489,8 +526,9 @@ cat > .git/config << EOF weird EOF -test_expect_success "rename section" \ - "git config --rename-section branch.eins branch.zwei" +test_expect_success 'rename section' ' + git config --rename-section branch.eins branch.zwei +' cat > expect << EOF # Hallo @@ -503,17 +541,22 @@ cat > expect << EOF weird EOF -test_expect_success "rename succeeded" "test_cmp expect .git/config" +test_expect_success 'rename succeeded' ' + test_cmp expect .git/config +' -test_expect_success "rename non-existing section" ' +test_expect_success 'rename non-existing section' ' test_must_fail git config --rename-section \ branch."world domination" branch.drei ' -test_expect_success "rename succeeded" "test_cmp expect .git/config" +test_expect_success 'rename succeeded' ' + test_cmp expect .git/config +' -test_expect_success "rename another section" \ - 'git config --rename-section branch."1 234 blabl/a" branch.drei' +test_expect_success 'rename another section' ' + git config --rename-section branch."1 234 blabl/a" branch.drei +' cat > expect << EOF # Hallo @@ -526,14 +569,17 @@ cat > expect << EOF weird EOF -test_expect_success "rename succeeded" "test_cmp expect .git/config" +test_expect_success 'rename succeeded' ' + test_cmp expect .git/config +' cat >> .git/config << EOF [branch "vier"] z = 1 EOF -test_expect_success "rename a section with a var on the same line" \ - 'git config --rename-section branch.vier branch.zwei' +test_expect_success 'rename a section with a var on the same line' ' + git config --rename-section branch.vier branch.zwei +' cat > expect << EOF # Hallo @@ -548,7 +594,9 @@ weird z = 1 EOF -test_expect_success "rename succeeded" "test_cmp expect .git/config" +test_expect_success 'rename succeeded' ' + test_cmp expect .git/config +' test_expect_success 'renaming empty section name is rejected' ' test_must_fail git config --rename-section branch.zwei "" @@ -562,7 +610,9 @@ cat >> .git/config << EOF [branch "zwei"] a = 1 [branch "vier"] EOF -test_expect_success "remove section" "git config --remove-section branch.zwei" +test_expect_success 'remove section' ' + git config --remove-section branch.zwei +' cat > expect << EOF # Hallo @@ -571,8 +621,9 @@ cat > expect << EOF weird EOF -test_expect_success "section was removed properly" \ - "test_cmp expect .git/config" +test_expect_success 'section was removed properly' ' + test_cmp expect .git/config +' cat > expect << EOF [gitcvs] @@ -583,7 +634,6 @@ cat > expect << EOF EOF test_expect_success 'section ending' ' - rm -f .git/config && git config gitcvs.enabled true && git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite && @@ -593,30 +643,25 @@ test_expect_success 'section ending' ' ' test_expect_success numbers ' - git config kilo.gram 1k && git config mega.ton 1m && - k=$(git config --int --get kilo.gram) && - test z1024 = "z$k" && - m=$(git config --int --get mega.ton) && - test z1048576 = "z$m" + echo 1024 >expect && + echo 1048576 >>expect && + git config --int --get kilo.gram >actual && + git config --int --get mega.ton >>actual && + test_cmp expect actual ' -cat > expect <<EOF -fatal: bad config value for 'aninvalid.unit' in .git/config -EOF - test_expect_success 'invalid unit' ' - git config aninvalid.unit "1auto" && - s=$(git config aninvalid.unit) && - test "z1auto" = "z$s" && - if git config --int --get aninvalid.unit 2>actual - then - echo config should have failed - false - fi && - cmp actual expect + echo 1auto >expect && + git config aninvalid.unit >actual && + test_cmp expect actual && + cat > expect <<-\EOF + fatal: bad config value for '\''aninvalid.unit'\'' in .git/config + EOF + test_must_fail git config --int --get aninvalid.unit 2>actual && + test_cmp actual expect ' cat > expect << EOF @@ -646,7 +691,7 @@ test_expect_success bool ' git config --bool --get bool.true$i >>result git config --bool --get bool.false$i >>result done && - cmp expect result' + test_cmp expect result' test_expect_success 'invalid bool (--get)' ' @@ -680,7 +725,7 @@ test_expect_success 'set --bool' ' git config --bool bool.false2 "" && git config --bool bool.false3 nO && git config --bool bool.false4 FALSE && - cmp expect .git/config' + test_cmp expect .git/config' cat > expect <<\EOF [int] @@ -695,39 +740,37 @@ test_expect_success 'set --int' ' git config --int int.val1 01 && git config --int int.val2 -1 && git config --int int.val3 5m && - cmp expect .git/config' + test_cmp expect .git/config +' -cat >expect <<\EOF -[bool] - true1 = true +test_expect_success 'get --bool-or-int' ' + cat >.git/config <<-\EOF && + [bool] + true1 true2 = true - false1 = false - false2 = false -[int] + false = false + [int] int1 = 0 int2 = 1 int3 = -1 -EOF - -test_expect_success 'get --bool-or-int' ' - rm -f .git/config && - ( - echo "[bool]" - echo true1 - echo true2 = true - echo false = false - echo "[int]" - echo int1 = 0 - echo int2 = 1 - echo int3 = -1 - ) >>.git/config && - test $(git config --bool-or-int bool.true1) = true && - test $(git config --bool-or-int bool.true2) = true && - test $(git config --bool-or-int bool.false) = false && - test $(git config --bool-or-int int.int1) = 0 && - test $(git config --bool-or-int int.int2) = 1 && - test $(git config --bool-or-int int.int3) = -1 - + EOF + cat >expect <<-\EOF && + true + true + false + 0 + 1 + -1 + EOF + { + git config --bool-or-int bool.true1 && + git config --bool-or-int bool.true2 && + git config --bool-or-int bool.false && + git config --bool-or-int int.int1 && + git config --bool-or-int int.int2 && + git config --bool-or-int int.int3 + } >actual && + test_cmp expect actual ' cat >expect <<\EOF @@ -803,6 +846,11 @@ test_expect_success NOT_MINGW 'get --path copes with unset $HOME' ' test_cmp expect result ' +test_expect_success 'get --path barfs on boolean variable' ' + echo "[path]bool" >.git/config && + test_must_fail git config --get --path path.bool +' + cat > expect << EOF [quote] leading = " test" @@ -844,7 +892,7 @@ EOF test_expect_success 'value continued on next line' ' git config --list > result && - cmp result expect + test_cmp result expect ' cat > .git/config <<\EOF @@ -880,11 +928,12 @@ test_expect_success '--null --get-regexp' ' test_expect_success 'inner whitespace kept verbatim' ' git config section.val "foo bar" && - test "z$(git config section.val)" = "zfoo bar" + echo "foo bar" >expect && + git config section.val >actual && + test_cmp expect actual ' test_expect_success SYMLINKS 'symlinked configuration' ' - ln -s notyet myconfig && GIT_CONFIG=myconfig git config test.frotz nitfol && test -h myconfig && @@ -893,9 +942,15 @@ test_expect_success SYMLINKS 'symlinked configuration' ' GIT_CONFIG=myconfig git config test.xyzzy rezrov && test -h myconfig && test -f notyet && - test "z$(GIT_CONFIG=notyet git config test.frotz)" = znitfol && - test "z$(GIT_CONFIG=notyet git config test.xyzzy)" = zrezrov - + cat >expect <<-\EOF && + nitfol + rezrov + EOF + { + GIT_CONFIG=notyet git config test.frotz && + GIT_CONFIG=notyet git config test.xyzzy + } >actual && + test_cmp expect actual ' test_expect_success 'nonexistent configuration' ' @@ -927,12 +982,20 @@ test_expect_success 'check split_cmdline return' " git commit -m 'initial commit' && git config branch.master.mergeoptions 'echo \"' && test_must_fail git merge master - " +" test_expect_success 'git -c "key=value" support' ' - test "z$(git -c core.name=value config core.name)" = zvalue && - test "z$(git -c foo.CamelCase=value config foo.camelcase)" = zvalue && - test "z$(git -c foo.flag config --bool foo.flag)" = ztrue && + cat >expect <<-\EOF && + value + value + true + EOF + { + git -c core.name=value config core.name && + git -c foo.CamelCase=value config foo.camelcase && + git -c foo.flag config --bool foo.flag + } >actual && + test_cmp expect actual && test_must_fail git -c name=value config core.name ' diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh index 2b962cfda..79045abb5 100755 --- a/t/t1304-default-acl.sh +++ b/t/t1304-default-acl.sh @@ -14,16 +14,15 @@ umask 077 # We need an arbitrary other user give permission to using ACLs. root # is a good candidate: exists on all unices, and it has permission # anyway, so we don't create a security hole running the testsuite. - -setfacl_out="$(setfacl -m u:root:rwx . 2>&1)" -setfacl_ret=$? - -if test $setfacl_ret != 0 -then - say "Unable to use setfacl (output: '$setfacl_out'; return code: '$setfacl_ret')" -else - test_set_prereq SETFACL -fi +test_expect_success 'checking for a working acl setup' ' + if setfacl -m d:m:rwx -m u:root:rwx . && + getfacl . | grep user:root:rwx && + touch should-have-readable-acl && + getfacl should-have-readable-acl | egrep "mask::?rw-" + then + test_set_prereq SETFACL + fi +' if test -z "$LOGNAME" then diff --git a/t/t1306-xdg-files.sh b/t/t1306-xdg-files.sh new file mode 100755 index 000000000..8b14ab187 --- /dev/null +++ b/t/t1306-xdg-files.sh @@ -0,0 +1,197 @@ +#!/bin/sh +# +# Copyright (c) 2012 Valentin Duperray, Lucien Kong, Franck Jonas, +# Thomas Nguy, Khoi Nguyen +# Grenoble INP Ensimag +# + +test_description='Compatibility with $XDG_CONFIG_HOME/git/ files' + +. ./test-lib.sh + +test_expect_success 'read config: xdg file exists and ~/.gitconfig doesn'\''t' ' + mkdir -p .config/git && + echo "[alias]" >.config/git/config && + echo " myalias = !echo in_config" >>.config/git/config && + echo in_config >expected && + git myalias >actual && + test_cmp expected actual +' + + +test_expect_success 'read config: xdg file exists and ~/.gitconfig exists' ' + >.gitconfig && + echo "[alias]" >.gitconfig && + echo " myalias = !echo in_gitconfig" >>.gitconfig && + echo in_gitconfig >expected && + git myalias >actual && + test_cmp expected actual +' + + +test_expect_success 'read with --get: xdg file exists and ~/.gitconfig doesn'\''t' ' + rm .gitconfig && + echo "[user]" >.config/git/config && + echo " name = read_config" >>.config/git/config && + echo read_config >expected && + git config --get user.name >actual && + test_cmp expected actual +' + +test_expect_success '"$XDG_CONFIG_HOME overrides $HOME/.config/git' ' + mkdir -p "$HOME"/xdg/git && + echo "[user]name = in_xdg" >"$HOME"/xdg/git/config && + echo in_xdg >expected && + XDG_CONFIG_HOME="$HOME"/xdg git config --get-all user.name >actual && + test_cmp expected actual +' + +test_expect_success 'read with --get: xdg file exists and ~/.gitconfig exists' ' + >.gitconfig && + echo "[user]" >.gitconfig && + echo " name = read_gitconfig" >>.gitconfig && + echo read_gitconfig >expected && + git config --get user.name >actual && + test_cmp expected actual +' + + +test_expect_success 'read with --list: xdg file exists and ~/.gitconfig doesn'\''t' ' + rm .gitconfig && + echo user.name=read_config >expected && + git config --global --list >actual && + test_cmp expected actual +' + + +test_expect_success 'read with --list: xdg file exists and ~/.gitconfig exists' ' + >.gitconfig && + echo "[user]" >.gitconfig && + echo " name = read_gitconfig" >>.gitconfig && + echo user.name=read_gitconfig >expected && + git config --global --list >actual && + test_cmp expected actual +' + + +test_expect_success 'Setup' ' + git init git && + cd git && + echo foo >to_be_excluded +' + + +test_expect_success 'Exclusion of a file in the XDG ignore file' ' + mkdir -p "$HOME"/.config/git/ && + echo to_be_excluded >"$HOME"/.config/git/ignore && + test_must_fail git add to_be_excluded +' + +test_expect_success '$XDG_CONFIG_HOME overrides $HOME/.config/git/ignore' ' + mkdir -p "$HOME"/xdg/git && + echo content >excluded_by_xdg_only && + echo excluded_by_xdg_only >"$HOME"/xdg/git/ignore && + test_when_finished "git read-tree --empty" && + (XDG_CONFIG_HOME="$HOME/xdg" && + export XDG_CONFIG_HOME && + git add to_be_excluded && + test_must_fail git add excluded_by_xdg_only + ) +' + +test_expect_success 'Exclusion in both XDG and local ignore files' ' + echo to_be_excluded >.gitignore && + test_must_fail git add to_be_excluded +' + + +test_expect_success 'Exclusion in a non-XDG global ignore file' ' + rm .gitignore && + echo >"$HOME"/.config/git/ignore && + echo to_be_excluded >"$HOME"/my_gitignore && + git config core.excludesfile "$HOME"/my_gitignore && + test_must_fail git add to_be_excluded +' + +test_expect_success 'Checking XDG ignore file when HOME is unset' ' + >expected && + (sane_unset HOME && + git config --unset core.excludesfile && + git ls-files --exclude-standard --ignored >actual) && + test_cmp expected actual +' + +test_expect_success 'Checking attributes in the XDG attributes file' ' + echo foo >f && + git check-attr -a f >actual && + test_line_count -eq 0 actual && + echo "f attr_f" >"$HOME"/.config/git/attributes && + echo "f: attr_f: set" >expected && + git check-attr -a f >actual && + test_cmp expected actual +' + +test_expect_success 'Checking XDG attributes when HOME is unset' ' + >expected && + (sane_unset HOME && + git check-attr -a f >actual) && + test_cmp expected actual +' + +test_expect_success '$XDG_CONFIG_HOME overrides $HOME/.config/git/attributes' ' + mkdir -p "$HOME"/xdg/git && + echo "f attr_f=xdg" >"$HOME"/xdg/git/attributes && + echo "f: attr_f: xdg" >expected && + XDG_CONFIG_HOME="$HOME/xdg" git check-attr -a f >actual && + test_cmp expected actual +' + +test_expect_success 'Checking attributes in both XDG and local attributes files' ' + echo "f -attr_f" >.gitattributes && + echo "f: attr_f: unset" >expected && + git check-attr -a f >actual && + test_cmp expected actual +' + + +test_expect_success 'Checking attributes in a non-XDG global attributes file' ' + test_might_fail rm .gitattributes && + echo "f attr_f=test" >"$HOME"/my_gitattributes && + git config core.attributesfile "$HOME"/my_gitattributes && + echo "f: attr_f: test" >expected && + git check-attr -a f >actual && + test_cmp expected actual +' + + +test_expect_success 'write: xdg file exists and ~/.gitconfig doesn'\''t' ' + mkdir -p "$HOME"/.config/git && + >"$HOME"/.config/git/config && + test_might_fail rm "$HOME"/.gitconfig && + git config --global user.name "write_config" && + echo "[user]" >expected && + echo " name = write_config" >>expected && + test_cmp expected "$HOME"/.config/git/config +' + + +test_expect_success 'write: xdg file exists and ~/.gitconfig exists' ' + >"$HOME"/.gitconfig && + git config --global user.name "write_gitconfig" && + echo "[user]" >expected && + echo " name = write_gitconfig" >>expected && + test_cmp expected "$HOME"/.gitconfig +' + + +test_expect_success 'write: ~/.config/git/ exists and config file doesn'\''t' ' + test_might_fail rm "$HOME"/.gitconfig && + test_might_fail rm "$HOME"/.config/git/config && + git config --global user.name "write_gitconfig" && + echo "[user]" >expected && + echo " name = write_gitconfig" >>expected && + test_cmp expected "$HOME"/.gitconfig +' + + +test_done diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index 4fd83a667..e415ee0bb 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -74,6 +74,24 @@ test_expect_success "delete $m (by HEAD)" ' ' rm -f .git/$m +test_expect_success \ + "create $m (by HEAD)" \ + "git update-ref HEAD $A && + test $A"' = $(cat .git/'"$m"')' +test_expect_success \ + "pack refs" \ + "git pack-refs --all" +test_expect_success \ + "move $m (by HEAD)" \ + "git update-ref HEAD $B $A && + test $B"' = $(cat .git/'"$m"')' +test_expect_success "delete $m (by HEAD) should remove both packed and loose $m" ' + git update-ref -d HEAD $B && + ! grep "$m" .git/packed-refs && + ! test -f .git/$m +' +rm -f .git/$m + cp -f .git/HEAD .git/HEAD.orig test_expect_success "delete symref without dereference" ' git update-ref --no-deref -d HEAD && diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh index 2c96551ed..36378b0e3 100755 --- a/t/t1401-symbolic-ref.sh +++ b/t/t1401-symbolic-ref.sh @@ -33,4 +33,34 @@ test_expect_success 'symbolic-ref refuses bare sha1' ' ' reset_to_sane +test_expect_success 'symbolic-ref deletes HEAD' ' + git symbolic-ref -d HEAD && + test_path_is_file .git/refs/heads/foo && + test_path_is_missing .git/HEAD +' +reset_to_sane + +test_expect_success 'symbolic-ref deletes dangling HEAD' ' + git symbolic-ref HEAD refs/heads/missing && + git symbolic-ref -d HEAD && + test_path_is_missing .git/refs/heads/missing && + test_path_is_missing .git/HEAD +' +reset_to_sane + +test_expect_success 'symbolic-ref fails to delete missing FOO' ' + echo "fatal: Cannot delete FOO, not a symbolic ref" >expect && + test_must_fail git symbolic-ref -d FOO >actual 2>&1 && + test_cmp expect actual +' +reset_to_sane + +test_expect_success 'symbolic-ref fails to delete real ref' ' + echo "fatal: Cannot delete refs/heads/foo, not a symbolic ref" >expect && + test_must_fail git symbolic-ref -d refs/heads/foo >actual 2>&1 && + test_path_is_file .git/refs/heads/foo && + test_cmp expect actual +' +reset_to_sane + test_done diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh index 1ae4d87c9..1a5a5f39f 100755 --- a/t/t1402-check-ref-format.sh +++ b/t/t1402-check-ref-format.sh @@ -11,7 +11,8 @@ valid_ref() { prereq=$1 shift esac - test_expect_success $prereq "ref name '$1' is valid${2:+ with options $2}" " + desc="ref name '$1' is valid${2:+ with options $2}" + test_expect_success $prereq "$desc" " git check-ref-format $2 '$1' " } @@ -22,7 +23,8 @@ invalid_ref() { prereq=$1 shift esac - test_expect_success $prereq "ref name '$1' is invalid${2:+ with options $2}" " + desc="ref name '$1' is invalid${2:+ with options $2}" + test_expect_success $prereq "$desc" " test_must_fail git check-ref-format $2 '$1' " } diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index bf7a2cd6f..08aa24ca1 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -177,9 +177,7 @@ test_expect_success 'tag pointing to something else than its type' ' test_when_finished "remove_object $tag" && echo $tag >.git/refs/tags/wrong && test_when_finished "git update-ref -d refs/tags/wrong" && - test_must_fail git fsck --tags 2>out && - cat out && - grep "error in tag.*broken links" out + test_must_fail git fsck --tags ' test_expect_success 'cleaned up' ' diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh index 1efd7f76d..13c88c9aa 100755 --- a/t/t1502-rev-parse-parseopt.sh +++ b/t/t1502-rev-parse-parseopt.sh @@ -41,7 +41,7 @@ EOF test_expect_success 'test --parseopt help output' ' test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec && - test_cmp expect output + test_i18ncmp expect output ' cat > expect <<EOF diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh new file mode 100755 index 000000000..6b3d797ce --- /dev/null +++ b/t/t1512-rev-parse-disambiguation.sh @@ -0,0 +1,264 @@ +#!/bin/sh + +test_description='object name disambiguation + +Create blobs, trees, commits and a tag that all share the same +prefix, and make sure "git rev-parse" can take advantage of +type information to disambiguate short object names that are +not necessarily unique. + +The final history used in the test has five commits, with the bottom +one tagged as v1.0.0. They all have one regular file each. + + +-------------------------------------------+ + | | + | .-------b3wettvi---- ad2uee | + | / / | + | a2onsxbvj---czy8f73t--ioiley5o | + | | + +-------------------------------------------+ + +' + +. ./test-lib.sh + +test_expect_success 'blob and tree' ' + test_tick && + ( + for i in 0 1 2 3 4 5 6 7 8 9 + do + echo $i + done + echo + echo b1rwzyc3 + ) >a0blgqsjc && + + # create one blob 0000000000b36 + git add a0blgqsjc && + + # create one tree 0000000000cdc + git write-tree +' + +test_expect_success 'warn ambiguity when no candidate matches type hint' ' + test_must_fail git rev-parse --verify 000000000^{commit} 2>actual && + grep "short SHA1 000000000 is ambiguous" actual +' + +test_expect_success 'disambiguate tree-ish' ' + # feed tree-ish in an unambiguous way + git rev-parse --verify 0000000000cdc:a0blgqsjc && + + # ambiguous at the object name level, but there is only one + # such tree-ish (the other is a blob) + git rev-parse --verify 000000000:a0blgqsjc +' + +test_expect_success 'disambiguate blob' ' + sed -e "s/|$//" >patch <<-EOF && + diff --git a/frotz b/frotz + index 000000000..ffffff 100644 + --- a/frotz + +++ b/frotz + @@ -10,3 +10,4 @@ + 9 + | + b1rwzyc3 + +irwry + EOF + ( + GIT_INDEX_FILE=frotz && + export GIT_INDEX_FILE && + git apply --build-fake-ancestor frotz patch && + git cat-file blob :frotz >actual + ) && + test_cmp a0blgqsjc actual +' + +test_expect_success 'disambiguate tree' ' + commit=$(echo "d7xm" | git commit-tree 000000000) && + test $(git rev-parse $commit^{tree}) = $(git rev-parse 0000000000cdc) +' + +test_expect_success 'first commit' ' + # create one commit 0000000000e4f + git commit -m a2onsxbvj +' + +test_expect_success 'disambiguate commit-ish' ' + # feed commit-ish in an unambiguous way + git rev-parse --verify 0000000000e4f^{commit} && + + # ambiguous at the object name level, but there is only one + # such commit (the others are tree and blob) + git rev-parse --verify 000000000^{commit} && + + # likewise + git rev-parse --verify 000000000^0 +' + +test_expect_success 'disambiguate commit' ' + commit=$(echo "hoaxj" | git commit-tree 0000000000cdc -p 000000000) && + test $(git rev-parse $commit^) = $(git rev-parse 0000000000e4f) +' + +test_expect_success 'log name1..name2 takes only commit-ishes on both ends' ' + git log 000000000..000000000 && + git log ..000000000 && + git log 000000000.. && + git log 000000000...000000000 && + git log ...000000000 && + git log 000000000... +' + +test_expect_success 'rev-parse name1..name2 takes only commit-ishes on both ends' ' + git rev-parse 000000000..000000000 && + git rev-parse ..000000000 && + git rev-parse 000000000.. +' + +test_expect_success 'git log takes only commit-ish' ' + git log 000000000 +' + +test_expect_success 'git reset takes only commit-ish' ' + git reset 000000000 +' + +test_expect_success 'first tag' ' + # create one tag 0000000000f8f + git tag -a -m j7cp83um v1.0.0 +' + +test_expect_failure 'two semi-ambiguous commit-ish' ' + # Once the parser becomes ultra-smart, it could notice that + # 110282 before ^{commit} name many different objects, but + # that only two (HEAD and v1.0.0 tag) can be peeled to commit, + # and that peeling them down to commit yield the same commit + # without ambiguity. + git rev-parse --verify 110282^{commit} && + + # likewise + git log 000000000..000000000 && + git log ..000000000 && + git log 000000000.. && + git log 000000000...000000000 && + git log ...000000000 && + git log 000000000... +' + +test_expect_failure 'three semi-ambiguous tree-ish' ' + # Likewise for tree-ish. HEAD, v1.0.0 and HEAD^{tree} share + # the prefix but peeling them to tree yields the same thing + git rev-parse --verify 000000000^{tree} +' + +test_expect_success 'parse describe name' ' + # feed an unambiguous describe name + git rev-parse --verify v1.0.0-0-g0000000000e4f && + + # ambiguous at the object name level, but there is only one + # such commit (others are blob, tree and tag) + git rev-parse --verify v1.0.0-0-g000000000 +' + +test_expect_success 'more history' ' + # commit 0000000000043 + git mv a0blgqsjc d12cr3h8t && + echo h62xsjeu >>d12cr3h8t && + git add d12cr3h8t && + + test_tick && + git commit -m czy8f73t && + + # commit 00000000008ec + git mv d12cr3h8t j000jmpzn && + echo j08bekfvt >>j000jmpzn && + git add j000jmpzn && + + test_tick && + git commit -m ioiley5o && + + # commit 0000000005b0 + git checkout v1.0.0^0 && + git mv a0blgqsjc f5518nwu && + + for i in h62xsjeu j08bekfvt kg7xflhm + do + echo $i + done >>f5518nwu && + git add f5518nwu && + + test_tick && + git commit -m b3wettvi && + side=$(git rev-parse HEAD) && + + # commit 000000000066 + git checkout master && + + # If you use recursive, merge will fail and you will need to + # clean up a0blgqsjc as well. If you use resolve, merge will + # succeed. + test_might_fail git merge --no-commit -s recursive $side && + git rm -f f5518nwu j000jmpzn && + + test_might_fail git rm -f a0blgqsjc && + ( + git cat-file blob $side:f5518nwu + echo j3l0i9s6 + ) >ab2gs879 && + git add ab2gs879 && + + test_tick && + git commit -m ad2uee + +' + +test_expect_failure 'parse describe name taking advantage of generation' ' + # ambiguous at the object name level, but there is only one + # such commit at generation 0 + git rev-parse --verify v1.0.0-0-g000000000 && + + # likewise for generation 2 and 4 + git rev-parse --verify v1.0.0-2-g000000000 && + git rev-parse --verify v1.0.0-4-g000000000 +' + +# Note: because rev-parse does not even try to disambiguate based on +# the generation number, this test currently succeeds for a wrong +# reason. When it learns to use the generation number, the previous +# test should succeed, and also this test should fail because the +# describe name used in the test with generation number can name two +# commits. Make sure that such a future enhancement does not randomly +# pick one. +test_expect_success 'parse describe name not ignoring ambiguity' ' + # ambiguous at the object name level, and there are two such + # commits at generation 1 + test_must_fail git rev-parse --verify v1.0.0-1-g000000000 +' + +test_expect_success 'ambiguous commit-ish' ' + # Now there are many commits that begin with the + # common prefix, none of these should pick one at + # random. They all should result in ambiguity errors. + test_must_fail git rev-parse --verify 110282^{commit} && + + # likewise + test_must_fail git log 000000000..000000000 && + test_must_fail git log ..000000000 && + test_must_fail git log 000000000.. && + test_must_fail git log 000000000...000000000 && + test_must_fail git log ...000000000 && + test_must_fail git log 000000000... +' + +test_expect_success 'rev-parse --disambiguate' ' + # The test creates 16 objects that share the prefix and two + # commits created by commit-tree in earlier tests share a + # different prefix. + git rev-parse --disambiguate=000000000 >actual && + test $(wc -l <actual) = 16 && + test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000 +' + +test_done diff --git a/t/t2006-checkout-index-basic.sh b/t/t2006-checkout-index-basic.sh index b8559838b..57cbdfe9b 100755 --- a/t/t2006-checkout-index-basic.sh +++ b/t/t2006-checkout-index-basic.sh @@ -7,7 +7,7 @@ test_description='basic checkout-index tests test_expect_success 'checkout-index --gobbledegook' ' test_expect_code 129 git checkout-index --gobbledegook 2>err && - grep "[Uu]sage" err + test_i18ngrep "[Uu]sage" err ' test_expect_success 'checkout-index -h in broken repository' ' @@ -18,7 +18,7 @@ test_expect_success 'checkout-index -h in broken repository' ' >.git/index && test_expect_code 129 git checkout-index -h >usage 2>&1 ) && - grep "[Uu]sage" broken/usage + test_i18ngrep "[Uu]sage" broken/usage ' test_done diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh index 81005373d..5d68729d7 100755 --- a/t/t2020-checkout-detach.sh +++ b/t/t2020-checkout-detach.sh @@ -151,6 +151,7 @@ test_expect_success 'checkout does not warn leaving reachable commit' ' cat >expect <<'EOF' Your branch is behind 'master' by 1 commit, and can be fast-forwarded. + (use "git pull" to update your local branch) EOF test_expect_success 'tracking count is accurate after orphan check' ' reset && diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh index 0dbbb00d7..a6405d318 100755 --- a/t/t2107-update-index-basic.sh +++ b/t/t2107-update-index-basic.sh @@ -15,7 +15,7 @@ test_expect_success 'update-index --nonsense fails' ' test_expect_success 'update-index --nonsense dumps usage' ' test_expect_code 129 git update-index --nonsense 2>err && - grep "[Uu]sage: git update-index" err + test_i18ngrep "[Uu]sage: git update-index" err ' test_expect_success 'update-index -h with corrupt index' ' @@ -26,7 +26,7 @@ test_expect_success 'update-index -h with corrupt index' ' >.git/index && test_expect_code 129 git update-index -h >usage 2>&1 ) && - grep "[Uu]sage: git update-index" broken/usage + test_i18ngrep "[Uu]sage: git update-index" broken/usage ' test_expect_success '--cacheinfo does not accept blob null sha1' ' diff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh index ec35409f9..2a4a749b4 100755 --- a/t/t2203-add-intent.sh +++ b/t/t2203-add-intent.sh @@ -62,5 +62,25 @@ test_expect_success 'can "commit -a" with an i-t-a entry' ' git commit -a -m all ' +test_expect_success 'cache-tree invalidates i-t-a paths' ' + git reset --hard && + mkdir dir && + : >dir/foo && + git add dir/foo && + git commit -m foo && + + : >dir/bar && + git add -N dir/bar && + git diff --cached --name-only >actual && + echo dir/bar >expect && + test_cmp expect actual && + + git write-tree >/dev/null && + + git diff --cached --name-only >actual && + echo dir/bar >expect && + test_cmp expect actual +' + test_done diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index c8fe97826..dc2f0458f 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -214,4 +214,10 @@ test_expect_success 'subdirectory ignore (l1)' ' test_cmp expect actual ' +test_expect_success 'pattern matches prefix completely' ' + : >expect && + git ls-files -i -o --exclude "/three/a.3[abc]" >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3004-ls-files-basic.sh b/t/t3004-ls-files-basic.sh index 490e05287..8d9bc3c2a 100755 --- a/t/t3004-ls-files-basic.sh +++ b/t/t3004-ls-files-basic.sh @@ -22,7 +22,7 @@ test_expect_success 'ls-files with nonexistent path' ' test_expect_success 'ls-files with nonsense option' ' test_expect_code 129 git ls-files --nonsense 2>actual && - grep "[Uu]sage: git ls-files" actual + test_i18ngrep "[Uu]sage: git ls-files" actual ' test_expect_success 'ls-files -h in corrupt repository' ' @@ -33,7 +33,7 @@ test_expect_success 'ls-files -h in corrupt repository' ' >.git/index && test_expect_code 129 git ls-files -h >usage 2>&1 ) && - grep "[Uu]sage: git ls-files " broken/usage + test_i18ngrep "[Uu]sage: git ls-files " broken/usage ' test_done diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index a17f8b2a4..80e6be39d 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -31,7 +31,7 @@ test_expect_success 'branch -h in broken repository' ' >.git/refs/heads/master && test_expect_code 129 git branch -h >usage 2>&1 ) && - grep "[Uu]sage" broken/usage + test_i18ngrep "[Uu]sage" broken/usage ' test_expect_success \ @@ -74,7 +74,7 @@ test_expect_success \ test_expect_success \ 'git branch -m dumps usage' \ 'test_expect_code 129 git branch -m 2>err && - grep "[Uu]sage: git branch" err' + test_i18ngrep "[Uu]sage: git branch" err' test_expect_success \ 'git branch -m m m/m should work' \ @@ -262,6 +262,25 @@ test_expect_success 'config information was renamed, too' \ "test $(git config branch.s.dummy) = Hello && test_must_fail git config branch.s/s/dummy" +test_expect_success 'deleting a symref' ' + git branch target && + git symbolic-ref refs/heads/symref refs/heads/target && + echo "Deleted branch symref (was refs/heads/target)." >expect && + git branch -d symref >actual && + test_path_is_file .git/refs/heads/target && + test_path_is_missing .git/refs/heads/symref && + test_i18ncmp expect actual +' + +test_expect_success 'deleting a dangling symref' ' + git symbolic-ref refs/heads/dangling-symref nowhere && + test_path_is_file .git/refs/heads/dangling-symref && + echo "Deleted branch dangling-symref (was nowhere)." >expect && + git branch -d dangling-symref >actual && + test_path_is_missing .git/refs/heads/dangling-symref && + test_i18ncmp expect actual +' + test_expect_success 'renaming a symref is not allowed' \ ' git symbolic-ref refs/heads/master2 refs/heads/master && @@ -369,6 +388,76 @@ test_expect_success \ 'git tag foobar && test_must_fail git branch --track my11 foobar' +test_expect_success 'use --set-upstream-to modify HEAD' \ + 'test_config branch.master.remote foo && + test_config branch.master.merge foo && + git branch my12 + git branch --set-upstream-to my12 && + test "$(git config branch.master.remote)" = "." && + test "$(git config branch.master.merge)" = "refs/heads/my12"' + +test_expect_success 'use --set-upstream-to modify a particular branch' \ + 'git branch my13 + git branch --set-upstream-to master my13 && + test "$(git config branch.my13.remote)" = "." && + test "$(git config branch.my13.merge)" = "refs/heads/master"' + +test_expect_success '--unset-upstream should fail if given a non-existent branch' \ + 'test_must_fail git branch --unset-upstream i-dont-exist' + +test_expect_success 'test --unset-upstream on HEAD' \ + 'git branch my14 + test_config branch.master.remote foo && + test_config branch.master.merge foo && + git branch --set-upstream-to my14 && + git branch --unset-upstream && + test_must_fail git config branch.master.remote && + test_must_fail git config branch.master.merge && + # fail for a branch without upstream set + test_must_fail git branch --unset-upstream +' + +test_expect_success 'test --unset-upstream on a particular branch' \ + 'git branch my15 + git branch --set-upstream-to master my14 && + git branch --unset-upstream my14 && + test_must_fail git config branch.my14.remote && + test_must_fail git config branch.my14.merge' + +test_expect_success '--set-upstream shows message when creating a new branch that exists as remote-tracking' \ + 'git update-ref refs/remotes/origin/master HEAD && + git branch --set-upstream origin/master 2>actual && + test_when_finished git update-ref -d refs/remotes/origin/master && + test_when_finished git branch -d origin/master && + cat >expected <<EOF && +The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to + +If you wanted to make '"'master'"' track '"'origin/master'"', do this: + + git branch -d origin/master + git branch --set-upstream-to origin/master +EOF + test_cmp expected actual +' + +test_expect_success '--set-upstream with two args only shows the deprecation message' \ + 'git branch --set-upstream master my13 2>actual && + test_when_finished git branch --unset-upstream master && + cat >expected <<EOF && +The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to +EOF + test_cmp expected actual +' + +test_expect_success '--set-upstream with one arg only shows the deprecation message if the branch existed' \ + 'git branch --set-upstream my13 2>actual && + test_when_finished git branch --unset-upstream my13 && + cat >expected <<EOF && +The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to +EOF + test_cmp expected actual +' + # Keep this test last, as it changes the current branch cat >expect <<EOF $_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh index 1f35e55ee..7480d6e7c 100755 --- a/t/t3300-funny-names.sh +++ b/t/t3300-funny-names.sh @@ -11,6 +11,16 @@ tree, index, and tree objects. . ./test-lib.sh +HT=' ' + +echo 2>/dev/null > "Name with an${HT}HT" +if ! test -f "Name with an${HT}HT" +then + # since FAT/NTFS does not allow tabs in filenames, skip this test + skip_all='Your filesystem does not allow tabs in filenames' + test_done +fi + p0='no-funny' p1='tabs ," (dq) and spaces' p2='just space' @@ -23,21 +33,9 @@ test_expect_success 'setup' ' EOF { cat "$p0" >"$p1" || :; } && - { echo "Foo Bar Baz" >"$p2" || :; } && - - if test -f "$p1" && cmp "$p0" "$p1" - then - test_set_prereq TABS_IN_FILENAMES - fi + { echo "Foo Bar Baz" >"$p2" || :; } ' -if ! test_have_prereq TABS_IN_FILENAMES -then - # since FAT/NTFS does not allow tabs in filenames, skip this test - skip_all='Your filesystem does not allow tabs in filenames' - test_done -fi - test_expect_success 'setup: populate index and tree' ' git update-index --add "$p0" "$p2" && t0=$(git write-tree) diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 7788ae02a..1de0ebda2 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -68,24 +68,24 @@ test_expect_success 'rebase against master' ' test_expect_success 'rebase against master twice' ' git rebase master >out && - grep "Current branch my-topic-branch is up to date" out + test_i18ngrep "Current branch my-topic-branch is up to date" out ' test_expect_success 'rebase against master twice with --force' ' git rebase --force-rebase master >out && - grep "Current branch my-topic-branch is up to date, rebase forced" out + test_i18ngrep "Current branch my-topic-branch is up to date, rebase forced" out ' test_expect_success 'rebase against master twice from another branch' ' git checkout my-topic-branch^ && git rebase master my-topic-branch >out && - grep "Current branch my-topic-branch is up to date" out + test_i18ngrep "Current branch my-topic-branch is up to date" out ' test_expect_success 'rebase fast-forward to master' ' git checkout my-topic-branch^ && git rebase my-topic-branch >out && - grep "Fast-forwarded HEAD to my-topic-branch" out + test_i18ngrep "Fast-forwarded HEAD to my-topic-branch" out ' test_expect_success 'the rebase operation should not have destroyed author information' ' diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 025c1c610..32fdc9938 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -118,6 +118,17 @@ test_expect_success 'rebase -i with the exec command checks tree cleanness' ' git rebase --continue ' +test_expect_success 'rebase -i with exec of inexistent command' ' + git checkout master && + test_when_finished "git rebase --abort" && + ( + FAKE_LINES="exec_this-command-does-not-exist 1" && + export FAKE_LINES && + test_must_fail git rebase -i HEAD^ >actual 2>&1 + ) && + ! grep "Maybe git-rebase is broken" actual +' + test_expect_success 'no changes are a nop' ' git checkout branch2 && git rebase -i F && @@ -755,4 +766,178 @@ test_expect_success 'rebase-i history with funny messages' ' test_cmp expect actual ' + +test_expect_success 'prepare for rebase -i --exec' ' + git checkout master && + git checkout -b execute && + test_commit one_exec main.txt one_exec && + test_commit two_exec main.txt two_exec && + test_commit three_exec main.txt three_exec +' + + +test_expect_success 'running "git rebase -i --exec git show HEAD"' ' + git rebase -i --exec "git show HEAD" HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,9d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'running "git rebase --exec git show HEAD -i"' ' + git reset --hard execute && + git rebase --exec "git show HEAD" -i HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,9d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'running "git rebase -ix git show HEAD"' ' + git reset --hard execute && + git rebase -ix "git show HEAD" HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,9d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'rebase -ix with several <CMD>' ' + git reset --hard execute && + git rebase -ix "git show HEAD; pwd" HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,9d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'rebase -ix with several instances of --exec' ' + git reset --hard execute && + git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual && + ( + FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2 + exec_git_show_HEAD exec_pwd" && + export FAKE_LINES && + git rebase -i HEAD~2 >expect + ) && + sed -e "1,11d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'rebase -ix with --autosquash' ' + git reset --hard execute && + git checkout -b autosquash && + echo second >second.txt && + git add second.txt && + git commit -m "fixup! two_exec" && + echo bis >bis.txt && + git add bis.txt && + git commit -m "fixup! two_exec" && + ( + git checkout -b autosquash_actual && + git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual + ) && + git checkout autosquash && + ( + git checkout -b autosquash_expected && + FAKE_LINES="1 fixup 3 fixup 4 exec_git_show_HEAD 2 exec_git_show_HEAD" && + export FAKE_LINES && + git rebase -i HEAD~4 >expect + ) && + sed -e "1,13d" expect >expected && + test_cmp expected actual +' + + +test_expect_success 'rebase --exec without -i shows error message' ' + git reset --hard execute && + test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual && + echo "The --exec option must be used with the --interactive option" >expected && + test_i18ncmp expected actual +' + + +test_expect_success 'rebase -i --exec without <CMD>' ' + git reset --hard execute && + test_must_fail git rebase -i --exec 2>tmp && + sed -e "1d" tmp >actual && + test_must_fail git rebase -h >expected && + test_cmp expected actual && + git checkout master +' + +test_expect_success 'rebase -i --root re-order and drop commits' ' + git checkout E && + FAKE_LINES="3 1 2 5" git rebase -i --root && + test E = $(git cat-file commit HEAD | sed -ne \$p) && + test B = $(git cat-file commit HEAD^ | sed -ne \$p) && + test A = $(git cat-file commit HEAD^^ | sed -ne \$p) && + test C = $(git cat-file commit HEAD^^^ | sed -ne \$p) && + test 0 = $(git cat-file commit HEAD^^^ | grep -c ^parent\ ) +' + +test_expect_success 'rebase -i --root retain root commit author and message' ' + git checkout A && + echo B >file7 && + git add file7 && + GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" && + FAKE_LINES="2" git rebase -i --root && + git cat-file commit HEAD | grep -q "^author Twerp Snog" && + git cat-file commit HEAD | grep -q "^different author$" +' + +test_expect_success 'rebase -i --root temporary sentinel commit' ' + git checkout B && + ( + FAKE_LINES="2" && + export FAKE_LINES && + test_must_fail git rebase -i --root + ) && + git cat-file commit HEAD | grep "^tree 4b825dc642cb" && + git rebase --abort +' + +test_expect_success 'rebase -i --root fixup root commit' ' + git checkout B && + FAKE_LINES="1 fixup 2" git rebase -i --root && + test A = $(git cat-file commit HEAD | sed -ne \$p) && + test B = $(git show HEAD:file1) && + test 0 = $(git cat-file commit HEAD | grep -c ^parent\ ) +' + +test_expect_success 'rebase --edit-todo does not works on non-interactive rebase' ' + git reset --hard && + git checkout conflict-branch && + test_must_fail git rebase --onto HEAD~2 HEAD~ && + test_must_fail git rebase --edit-todo && + git rebase --abort +' + +test_expect_success 'rebase --edit-todo can be used to modify todo' ' + git reset --hard && + git checkout no-conflict-branch^0 && + FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 && + FAKE_LINES="2 1" git rebase --edit-todo && + git rebase --continue + test M = $(git cat-file commit HEAD^ | sed -ne \$p) && + test L = $(git cat-file commit HEAD | sed -ne \$p) +' + test_done diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh index e5ad67c64..19eddadcf 100755 --- a/t/t3405-rebase-malformed.sh +++ b/t/t3405-rebase-malformed.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='rebase should not insist on git message convention' +test_description='rebase should handle arbitrary git message' . ./test-lib.sh @@ -12,6 +12,11 @@ It has two paragraphs, but its first paragraph is not friendly to oneline summary format. EOF +cat >G <<\EOF +commit log message containing a diff +EOF + + test_expect_success setup ' >file1 && @@ -19,8 +24,9 @@ test_expect_success setup ' git add file1 file2 && test_tick && git commit -m "Initial commit" && + git branch diff-in-message - git checkout -b side && + git checkout -b multi-line-subject && cat F >file2 && git add file2 && test_tick && @@ -28,6 +34,17 @@ test_expect_success setup ' git cat-file commit HEAD | sed -e "1,/^\$/d" >F0 && + git checkout diff-in-message && + echo "commit log message containing a diff" >G && + echo "" >>G + cat G >file2 && + git add file2 && + git diff --cached >>G && + test_tick && + git commit -F G && + + git cat-file commit HEAD | sed -e "1,/^\$/d" >G0 && + git checkout master && echo One >file1 && @@ -36,13 +53,20 @@ test_expect_success setup ' git commit -m "Second commit" ' -test_expect_success rebase ' +test_expect_success 'rebase commit with multi-line subject' ' - git rebase master side && + git rebase master multi-line-subject && git cat-file commit HEAD | sed -e "1,/^\$/d" >F1 && test_cmp F0 F1 && test_cmp F F0 ' +test_expect_success 'rebase commit with diff in message' ' + git rebase master diff-in-message && + git cat-file commit HEAD | sed -e "1,/^$/d" >G1 && + test_cmp G0 G1 && + test_cmp G G0 +' + test_done diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index 689837791..e6a9a0d43 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -62,9 +62,16 @@ test_expect_success 'rebase -n overrides config rebase.stat config' ' ! grep "^ fileX | *1 +$" diffstat.txt ' +# Output to stderr: +# +# "Does not point to a valid commit: invalid-ref" +# +# NEEDSWORK: This "grep" is fine in real non-C locales, but +# GETTEXT_POISON poisons the refname along with the enclosing +# error message. test_expect_success 'rebase --onto outputs the invalid ref' ' test_must_fail git rebase --onto invalid-ref HEAD HEAD 2>err && - grep "invalid-ref" err + test_i18ngrep "invalid-ref" err ' test_done diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh index 086c91c7b..0b5210572 100755 --- a/t/t3412-rebase-root.sh +++ b/t/t3412-rebase-root.sh @@ -22,8 +22,9 @@ test_expect_success 'prepare repository' ' test_commit 4 B ' -test_expect_success 'rebase --root expects --onto' ' - test_must_fail git rebase --root +test_expect_success 'rebase --root fails with too many args' ' + git checkout -B fail other && + test_must_fail git rebase --onto master --root fail fail ' test_expect_success 'setup pre-rebase hook' ' @@ -42,7 +43,7 @@ cat > expect <<EOF EOF test_expect_success 'rebase --root --onto <newbase>' ' - git checkout -b work && + git checkout -b work other && git rebase --root --onto master && git log --pretty=tformat:"%s" > rebased && test_cmp expect rebased diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh index 595d2ff99..34c86e5de 100755 --- a/t/t3501-revert-cherry-pick.sh +++ b/t/t3501-revert-cherry-pick.sh @@ -47,7 +47,7 @@ test_expect_success 'cherry-pick --nonsense' ' git diff --exit-code HEAD && test_must_fail git cherry-pick --nonsense 2>msg && git diff --exit-code HEAD "$pos" && - grep '[Uu]sage:' msg + test_i18ngrep '[Uu]sage:' msg ' test_expect_success 'revert --nonsense' ' @@ -56,7 +56,7 @@ test_expect_success 'revert --nonsense' ' git diff --exit-code HEAD && test_must_fail git revert --nonsense 2>msg && git diff --exit-code HEAD "$pos" && - grep '[Uu]sage:' msg + test_i18ngrep '[Uu]sage:' msg ' test_expect_success 'cherry-pick after renaming branch' ' diff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh index 5a1340cee..a0c6e30d8 100755 --- a/t/t3505-cherry-pick-empty.sh +++ b/t/t3505-cherry-pick-empty.sh @@ -53,6 +53,11 @@ test_expect_success 'index lockfile was removed' ' ' +test_expect_success 'cherry-pick a commit with an empty message with --allow-empty-message' ' + git checkout -f master && + git cherry-pick --allow-empty-message empty-branch +' + test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' ' git checkout master && echo fourth >>file2 && diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index 0c81b3c42..c82f7210c 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -30,6 +30,7 @@ test_expect_success setup ' test_commit initial foo a && test_commit base foo b && test_commit picked foo c && + test_commit --signoff picked-signed foo d && git config advice.detachedhead false ' @@ -340,4 +341,35 @@ test_expect_success 'revert conflict, diff3 -m style' ' test_cmp expected actual ' +test_expect_success 'failed cherry-pick does not forget -s' ' + pristine_detach initial && + test_must_fail git cherry-pick -s picked && + test_i18ngrep -e "Signed-off-by" .git/MERGE_MSG +' + +test_expect_success 'commit after failed cherry-pick does not add duplicated -s' ' + pristine_detach initial && + test_must_fail git cherry-pick -s picked-signed && + git commit -a -s && + test $(git show -s |grep -c "Signed-off-by") = 1 +' + +test_expect_success 'commit after failed cherry-pick adds -s at the right place' ' + pristine_detach initial && + test_must_fail git cherry-pick picked && + git commit -a -s && + pwd && + cat <<EOF > expected && +picked + +Signed-off-by: C O Mitter <committer@example.com> + +Conflicts: + foo +EOF + + git show -s --pretty=format:%B > actual && + test_cmp expected actual +' + test_done diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh index 75f7ff4f2..340afc760 100755 --- a/t/t3508-cherry-pick-many-commits.sh +++ b/t/t3508-cherry-pick-many-commits.sh @@ -44,6 +44,21 @@ test_expect_success 'cherry-pick first..fourth works' ' check_head_differs_from fourth ' +test_expect_success 'cherry-pick three one two works' ' + git checkout -f first && + test_commit one && + test_commit two && + test_commit three && + git checkout -f master && + git reset --hard first && + git cherry-pick three one two && + git diff --quiet three && + git diff --quiet HEAD three && + test "$(git log --reverse --format=%s first..)" = "three +one +two" +' + test_expect_success 'output to keep user entertained during multi-pick' ' cat <<-\EOF >expected && [master OBJID] second diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh index f4e6450d6..b5fb527b2 100755 --- a/t/t3510-cherry-pick-sequence.sh +++ b/t/t3510-cherry-pick-sequence.sh @@ -410,7 +410,7 @@ test_expect_success '--continue respects -x in first commit in multi-pick' ' grep "cherry picked from.*$picked" msg ' -test_expect_success '--signoff is not automatically propagated to resolved conflict' ' +test_expect_failure '--signoff is automatically propagated to resolved conflict' ' pristine_detach initial && test_expect_code 1 git cherry-pick --signoff base..anotherpick && echo "c" >foo && @@ -428,7 +428,7 @@ test_expect_success '--signoff is not automatically propagated to resolved confl grep "Signed-off-by:" anotherpick_msg ' -test_expect_success '--signoff dropped for implicit commit of resolution, multi-pick case' ' +test_expect_failure '--signoff dropped for implicit commit of resolution, multi-pick case' ' pristine_detach initial && test_must_fail git cherry-pick -s picked anotherpick && echo c >foo && @@ -441,7 +441,7 @@ test_expect_success '--signoff dropped for implicit commit of resolution, multi- ! grep Signed-off-by: msg ' -test_expect_success 'sign-off needs to be reaffirmed after conflict resolution, single-pick case' ' +test_expect_failure 'sign-off needs to be reaffirmed after conflict resolution, single-pick case' ' pristine_detach initial && test_must_fail git cherry-pick -s picked && echo c >foo && diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 9fd28bcf3..37bf5f13b 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -262,4 +262,364 @@ test_expect_success 'rm removes subdirectories recursively' ' ! test -d dir ' +cat >expect <<EOF +D submod +EOF + +cat >expect.modified <<EOF + M submod +EOF + +test_expect_success 'rm removes empty submodules from work tree' ' + mkdir submod && + git update-index --add --cacheinfo 160000 $(git rev-parse HEAD) submod && + git config -f .gitmodules submodule.sub.url ./. && + git config -f .gitmodules submodule.sub.path submod && + git submodule init && + git add .gitmodules && + git commit -m "add submodule" && + git rm submod && + test ! -e submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm removes removed submodule from index' ' + git reset --hard && + git submodule update && + rm -rf submod && + git rm submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm removes work tree of unmodified submodules' ' + git reset --hard && + git submodule update && + git rm submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm removes a submodule with a trailing /' ' + git reset --hard && + git submodule update && + git rm submod/ && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm fails when given a file with a trailing /' ' + test_must_fail git rm empty/ +' + +test_expect_success 'rm succeeds when given a directory with a trailing /' ' + git rm -r frotz/ +' + +test_expect_success 'rm of a populated submodule with different HEAD fails unless forced' ' + git reset --hard && + git submodule update && + (cd submod && + git checkout HEAD^ + ) && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.modified actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated submodule with modifications fails unless forced' ' + git reset --hard && + git submodule update && + (cd submod && + echo X >empty + ) && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.modified actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated submodule with untracked files fails unless forced' ' + git reset --hard && + git submodule update && + (cd submod && + echo X >untracked + ) && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.modified actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'setup submodule conflict' ' + git reset --hard && + git submodule update && + git checkout -b branch1 && + echo 1 >nitfol && + git add nitfol && + git commit -m "added nitfol 1" && + git checkout -b branch2 master && + echo 2 >nitfol && + git add nitfol && + git commit -m "added nitfol 2" && + git checkout -b conflict1 master && + (cd submod && + git fetch && + git checkout branch1 + ) && + git add submod && + git commit -m "submod 1" && + git checkout -b conflict2 master && + (cd submod && + git checkout branch2 + ) && + git add submod && + git commit -m "submod 2" +' + +cat >expect.conflict <<EOF +UU submod +EOF + +test_expect_success 'rm removes work tree of unmodified conflicted submodule' ' + git checkout conflict1 && + git reset --hard && + git submodule update && + test_must_fail git merge conflict2 && + git rm submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a conflicted populated submodule with different HEAD fails unless forced' ' + git checkout conflict1 && + git reset --hard && + git submodule update && + (cd submod && + git checkout HEAD^ + ) && + test_must_fail git merge conflict2 && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.conflict actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a conflicted populated submodule with modifications fails unless forced' ' + git checkout conflict1 && + git reset --hard && + git submodule update && + (cd submod && + echo X >empty + ) && + test_must_fail git merge conflict2 && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.conflict actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a conflicted populated submodule with untracked files fails unless forced' ' + git checkout conflict1 && + git reset --hard && + git submodule update && + (cd submod && + echo X >untracked + ) && + test_must_fail git merge conflict2 && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.conflict actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a conflicted populated submodule with a .git directory fails even when forced' ' + git checkout conflict1 && + git reset --hard && + git submodule update && + (cd submod && + rm .git && + cp -R ../.git/modules/sub .git && + GIT_WORK_TREE=. git config --unset core.worktree + ) && + test_must_fail git merge conflict2 && + test_must_fail git rm submod && + test -d submod && + test -d submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.conflict actual && + test_must_fail git rm -f submod && + test -d submod && + test -d submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.conflict actual && + git merge --abort && + rm -rf submod +' + +test_expect_success 'rm of a conflicted unpopulated submodule succeeds' ' + git checkout conflict1 && + git reset --hard && + test_must_fail git merge conflict2 && + git rm submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated submodule with a .git directory fails even when forced' ' + git checkout -f master && + git reset --hard && + git submodule update && + (cd submod && + rm .git && + cp -R ../.git/modules/sub .git && + GIT_WORK_TREE=. git config --unset core.worktree + ) && + test_must_fail git rm submod && + test -d submod && + test -d submod/.git && + git status -s -uno --ignore-submodules=none > actual && + ! test -s actual && + test_must_fail git rm -f submod && + test -d submod && + test -d submod/.git && + git status -s -uno --ignore-submodules=none > actual && + ! test -s actual && + rm -rf submod +' + +cat >expect.deepmodified <<EOF + M submod/subsubmod +EOF + +test_expect_success 'setup subsubmodule' ' + git reset --hard && + git submodule update && + (cd submod && + git update-index --add --cacheinfo 160000 $(git rev-parse HEAD) subsubmod && + git config -f .gitmodules submodule.sub.url ../. && + git config -f .gitmodules submodule.sub.path subsubmod && + git submodule init && + git add .gitmodules && + git commit -m "add subsubmodule" && + git submodule update subsubmod + ) && + git commit -a -m "added deep submodule" +' + +test_expect_success 'rm recursively removes work tree of unmodified submodules' ' + git rm submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated nested submodule with different nested HEAD fails unless forced' ' + git reset --hard && + git submodule update --recursive && + (cd submod/subsubmod && + git checkout HEAD^ + ) && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.modified actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated nested submodule with nested modifications fails unless forced' ' + git reset --hard && + git submodule update --recursive && + (cd submod/subsubmod && + echo X >empty + ) && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.modified actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated nested submodule with nested untracked files fails unless forced' ' + git reset --hard && + git submodule update --recursive && + (cd submod/subsubmod && + echo X >untracked + ) && + test_must_fail git rm submod && + test -d submod && + test -f submod/.git && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect.modified actual && + git rm -f submod && + test ! -d submod && + git status -s -uno --ignore-submodules=none > actual && + test_cmp expect actual +' + +test_expect_success 'rm of a populated nested submodule with a nested .git directory fails even when forced' ' + git reset --hard && + git submodule update --recursive && + (cd submod/subsubmod && + rm .git && + cp -R ../../.git/modules/sub/modules/sub .git && + GIT_WORK_TREE=. git config --unset core.worktree + ) && + test_must_fail git rm submod && + test -d submod && + test -d submod/subsubmod/.git && + git status -s -uno --ignore-submodules=none > actual && + ! test -s actual && + test_must_fail git rm -f submod && + test -d submod && + test -d submod/subsubmod/.git && + git status -s -uno --ignore-submodules=none > actual && + ! test -s actual && + rm -rf submod +' + test_done diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh index 534ee08a4..892f56784 100755 --- a/t/t3902-quoted.sh +++ b/t/t3902-quoted.sh @@ -16,9 +16,8 @@ echo foo 2>/dev/null > "Name and an${HT}HT" if ! test -f "Name and an${HT}HT" then # FAT/NTFS does not allow tabs in filenames - say 'Your filesystem does not allow tabs in filenames' -else - test_set_prereq TABS_IN_FILENAMES + skip_all='Your filesystem does not allow tabs in filenames' + test_done fi for_each_name () { @@ -31,7 +30,7 @@ for_each_name () { done } -test_expect_success TABS_IN_FILENAMES 'setup' ' +test_expect_success 'setup' ' mkdir "$FN" && for_each_name "echo initial >\"\$name\"" && @@ -45,7 +44,7 @@ test_expect_success TABS_IN_FILENAMES 'setup' ' ' -test_expect_success TABS_IN_FILENAMES 'setup expected files' ' +test_expect_success 'setup expected files' ' cat >expect.quoted <<\EOF && Name "Name and a\nLF" @@ -75,74 +74,74 @@ With SP in it EOF ' -test_expect_success TABS_IN_FILENAMES 'check fully quoted output from ls-files' ' +test_expect_success 'check fully quoted output from ls-files' ' git ls-files >current && test_cmp expect.quoted current ' -test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-files' ' +test_expect_success 'check fully quoted output from diff-files' ' git diff --name-only >current && test_cmp expect.quoted current ' -test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-index' ' +test_expect_success 'check fully quoted output from diff-index' ' git diff --name-only HEAD >current && test_cmp expect.quoted current ' -test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-tree' ' +test_expect_success 'check fully quoted output from diff-tree' ' git diff --name-only HEAD^ HEAD >current && test_cmp expect.quoted current ' -test_expect_success TABS_IN_FILENAMES 'check fully quoted output from ls-tree' ' +test_expect_success 'check fully quoted output from ls-tree' ' git ls-tree --name-only -r HEAD >current && test_cmp expect.quoted current ' -test_expect_success TABS_IN_FILENAMES 'setting core.quotepath' ' +test_expect_success 'setting core.quotepath' ' git config --bool core.quotepath false ' -test_expect_success TABS_IN_FILENAMES 'check fully quoted output from ls-files' ' +test_expect_success 'check fully quoted output from ls-files' ' git ls-files >current && test_cmp expect.raw current ' -test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-files' ' +test_expect_success 'check fully quoted output from diff-files' ' git diff --name-only >current && test_cmp expect.raw current ' -test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-index' ' +test_expect_success 'check fully quoted output from diff-index' ' git diff --name-only HEAD >current && test_cmp expect.raw current ' -test_expect_success TABS_IN_FILENAMES 'check fully quoted output from diff-tree' ' +test_expect_success 'check fully quoted output from diff-tree' ' git diff --name-only HEAD^ HEAD >current && test_cmp expect.raw current ' -test_expect_success TABS_IN_FILENAMES 'check fully quoted output from ls-tree' ' +test_expect_success 'check fully quoted output from ls-tree' ' git ls-tree --name-only -r HEAD >current && test_cmp expect.raw current diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index cd042633b..5dfbda749 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -610,7 +610,7 @@ test_expect_success 'stash apply shows status same as git status (relative to cu git stash apply ) | sed -e 1,2d >actual && # drop "Saved..." and "HEAD is now..." - test_cmp expect actual + test_i18ncmp expect actual ' cat > expect << EOF diff --git a/t/t3910-mac-os-precompose.sh b/t/t3910-mac-os-precompose.sh new file mode 100755 index 000000000..5fe57c543 --- /dev/null +++ b/t/t3910-mac-os-precompose.sh @@ -0,0 +1,153 @@ +#!/bin/sh +# +# Copyright (c) 2012 Torsten Bögershausen +# + +test_description='utf-8 decomposed (nfd) converted to precomposed (nfc)' + +. ./test-lib.sh + +if ! test_have_prereq UTF8_NFD_TO_NFC +then + skip_all="filesystem does not corrupt utf-8" + test_done +fi + +# create utf-8 variables +Adiarnfc=`printf '\303\204'` +Adiarnfd=`printf 'A\314\210'` + +Odiarnfc=`printf '\303\226'` +Odiarnfd=`printf 'O\314\210'` +AEligatu=`printf '\303\206'` +Invalidu=`printf '\303\377'` + + +#Create a string with 255 bytes (decomposed) +Alongd=$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd #21 Byte +Alongd=$Alongd$Alongd$Alongd #63 Byte +Alongd=$Alongd$Alongd$Alongd$Alongd$Adiarnfd #255 Byte + +#Create a string with 254 bytes (precomposed) +Alongc=$AEligatu$AEligatu$AEligatu$AEligatu$AEligatu #10 Byte +Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #50 Byte +Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #250 Byte +Alongc=$Alongc$AEligatu$AEligatu #254 Byte + +test_expect_success "detect if nfd needed" ' + precomposeunicode=`git config core.precomposeunicode` && + test "$precomposeunicode" = false && + git config core.precomposeunicode true +' +test_expect_success "setup" ' + >x && + git add x && + git commit -m "1st commit" && + git rm x && + git commit -m "rm x" +' +test_expect_success "setup case mac" ' + git checkout -b mac_os +' +# This will test nfd2nfc in readdir() +test_expect_success "add file Adiarnfc" ' + echo f.Adiarnfc >f.$Adiarnfc && + git add f.$Adiarnfc && + git commit -m "add f.$Adiarnfc" +' +# This will test nfd2nfc in git stage() +test_expect_success "stage file d.Adiarnfd/f.Adiarnfd" ' + mkdir d.$Adiarnfd && + echo d.$Adiarnfd/f.$Adiarnfd >d.$Adiarnfd/f.$Adiarnfd && + git stage d.$Adiarnfd/f.$Adiarnfd && + git commit -m "add d.$Adiarnfd/f.$Adiarnfd" +' +test_expect_success "add link Adiarnfc" ' + ln -s d.$Adiarnfd/f.$Adiarnfd l.$Adiarnfc && + git add l.$Adiarnfc && + git commit -m "add l.Adiarnfc" +' +# This will test git log +test_expect_success "git log f.Adiar" ' + git log f.$Adiarnfc > f.Adiarnfc.log && + git log f.$Adiarnfd > f.Adiarnfd.log && + test -s f.Adiarnfc.log && + test -s f.Adiarnfd.log && + test_cmp f.Adiarnfc.log f.Adiarnfd.log && + rm f.Adiarnfc.log f.Adiarnfd.log +' +# This will test git ls-files +test_expect_success "git lsfiles f.Adiar" ' + git ls-files f.$Adiarnfc > f.Adiarnfc.log && + git ls-files f.$Adiarnfd > f.Adiarnfd.log && + test -s f.Adiarnfc.log && + test -s f.Adiarnfd.log && + test_cmp f.Adiarnfc.log f.Adiarnfd.log && + rm f.Adiarnfc.log f.Adiarnfd.log +' +# This will test git mv +test_expect_success "git mv" ' + git mv f.$Adiarnfd f.$Odiarnfc && + git mv d.$Adiarnfd d.$Odiarnfc && + git mv l.$Adiarnfd l.$Odiarnfc && + git commit -m "mv Adiarnfd Odiarnfc" +' +# Files can be checked out as nfc +# And the link has been corrected from nfd to nfc +test_expect_success "git checkout nfc" ' + rm f.$Odiarnfc && + git checkout f.$Odiarnfc +' +# Make it possible to checkout files with their NFD names +test_expect_success "git checkout file nfd" ' + rm -f f.* && + git checkout f.$Odiarnfd +' +# Make it possible to checkout links with their NFD names +test_expect_success "git checkout link nfd" ' + rm l.* && + git checkout l.$Odiarnfd +' +test_expect_success "setup case mac2" ' + git checkout master && + git reset --hard && + git checkout -b mac_os_2 +' +# This will test nfd2nfc in git commit +test_expect_success "commit file d2.Adiarnfd/f.Adiarnfd" ' + mkdir d2.$Adiarnfd && + echo d2.$Adiarnfd/f.$Adiarnfd >d2.$Adiarnfd/f.$Adiarnfd && + git add d2.$Adiarnfd/f.$Adiarnfd && + git commit -m "add d2.$Adiarnfd/f.$Adiarnfd" -- d2.$Adiarnfd/f.$Adiarnfd +' +test_expect_success "setup for long decomposed filename" ' + git checkout master && + git reset --hard && + git checkout -b mac_os_long_nfd_fn +' +test_expect_success "Add long decomposed filename" ' + echo longd >$Alongd && + git add * && + git commit -m "Long filename" +' +test_expect_success "setup for long precomposed filename" ' + git checkout master && + git reset --hard && + git checkout -b mac_os_long_nfc_fn +' +test_expect_success "Add long precomposed filename" ' + echo longc >$Alongc && + git add * && + git commit -m "Long filename" +' +# Test if the global core.precomposeunicode stops autosensing +# Must be the last test case +test_expect_success "respect git config --global core.precomposeunicode" ' + git config --global core.precomposeunicode true && + rm -rf .git && + git init && + precomposeunicode=`git config core.precomposeunicode` && + test "$precomposeunicode" = "true" +' + +test_done diff --git a/t/t4006-diff-mode.sh b/t/t4006-diff-mode.sh index 7a3e1f9a2..05911492c 100755 --- a/t/t4006-diff-mode.sh +++ b/t/t4006-diff-mode.sh @@ -32,28 +32,28 @@ test_expect_success 'prepare binary file' ' git commit -m binbin ' -test_expect_success '--stat output after text chmod' ' - test_chmod -x rezrov && - echo " 0 files changed" >expect && - git diff HEAD --stat >actual && - test_cmp expect actual -' - -test_expect_success '--shortstat output after text chmod' ' - git diff HEAD --shortstat >actual && - test_cmp expect actual -' - -test_expect_success '--stat output after binary chmod' ' - test_chmod +x binbin && - echo " 0 files changed" >expect && - git diff HEAD --stat >actual && - test_cmp expect actual -' - -test_expect_success '--shortstat output after binary chmod' ' - git diff HEAD --shortstat >actual && - test_cmp expect actual -' +# test_expect_success '--stat output after text chmod' ' +# test_chmod -x rezrov && +# echo " 0 files changed" >expect && +# git diff HEAD --stat >actual && +# test_i18ncmp expect actual +# ' +# +# test_expect_success '--shortstat output after text chmod' ' +# git diff HEAD --shortstat >actual && +# test_i18ncmp expect actual +# ' +# +# test_expect_success '--stat output after binary chmod' ' +# test_chmod +x binbin && +# echo " 0 files changed" >expect && +# git diff HEAD --stat >actual && +# test_i18ncmp expect actual +# ' +# +# test_expect_success '--shortstat output after binary chmod' ' +# git diff HEAD --shortstat >actual && +# test_i18ncmp expect actual +# ' test_done diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh index 6cebb3951..1215ae544 100755 --- a/t/t4012-diff-binary.sh +++ b/t/t4012-diff-binary.sh @@ -15,13 +15,14 @@ cat >expect.binary-numstat <<\EOF - - d EOF -test_expect_success 'prepare repository' \ - 'echo AIT >a && echo BIT >b && echo CIT >c && echo DIT >d && - git update-index --add a b c d && - echo git >a && - cat "$TEST_DIRECTORY"/test-binary-1.png >b && - echo git >c && - cat b b >d' +test_expect_success 'prepare repository' ' + echo AIT >a && echo BIT >b && echo CIT >c && echo DIT >d && + git update-index --add a b c d && + echo git >a && + cat "$TEST_DIRECTORY"/test-binary-1.png >b && + echo git >c && + cat b b >d +' cat > expected <<\EOF a | 2 +- @@ -30,16 +31,16 @@ cat > expected <<\EOF d | Bin 4 files changed, 2 insertions(+), 2 deletions(-) EOF -test_expect_success '"apply --stat" output for binary file change' ' +test_expect_success 'apply --stat output for binary file change' ' git diff >diff && git apply --stat --summary <diff >current && test_i18ncmp expected current ' test_expect_success 'diff --shortstat output for binary file change' ' - echo " 4 files changed, 2 insertions(+), 2 deletions(-)" >expected && + tail -n 1 expected >expect && git diff --shortstat >current && - test_i18ncmp expected current + test_i18ncmp expect current ' test_expect_success 'diff --shortstat output for binary file change only' ' @@ -62,49 +63,42 @@ test_expect_success 'apply --numstat understands diff --binary format' ' # apply needs to be able to skip the binary material correctly # in order to report the line number of a corrupt patch. -test_expect_success 'apply detecting corrupt patch correctly' \ - 'git diff | sed -e 's/-CIT/xCIT/' >broken && - if git apply --stat --summary broken 2>detected - then - echo unhappy - should have detected an error - (exit 1) - else - echo happy - fi && - detected=`cat detected` && - detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && - detected=`sed -ne "${detected}p" broken` && - test "$detected" = xCIT' - -test_expect_success 'apply detecting corrupt patch correctly' \ - 'git diff --binary | sed -e 's/-CIT/xCIT/' >broken && - if git apply --stat --summary broken 2>detected - then - echo unhappy - should have detected an error - (exit 1) - else - echo happy - fi && - detected=`cat detected` && - detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && - detected=`sed -ne "${detected}p" broken` && - test "$detected" = xCIT' +test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' ' + git diff >output && + sed -e "s/-CIT/xCIT/" <output >broken && + test_must_fail git apply --stat --summary broken 2>detected && + detected=`cat detected` && + detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && + detected=`sed -ne "${detected}p" broken` && + test "$detected" = xCIT +' + +test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' ' + git diff --binary | sed -e "s/-CIT/xCIT/" >broken && + test_must_fail git apply --stat --summary broken 2>detected && + detected=`cat detected` && + detected=`expr "$detected" : "fatal.*at line \\([0-9]*\\)\$"` && + detected=`sed -ne "${detected}p" broken` && + test "$detected" = xCIT +' test_expect_success 'initial commit' 'git commit -a -m initial' # Try removal (b), modification (d), and creation (e). -test_expect_success 'diff-index with --binary' \ - 'echo AIT >a && mv b e && echo CIT >c && cat e >d && - git update-index --add --remove a b c d e && - tree0=`git write-tree` && - git diff --cached --binary >current && - git apply --stat --summary current' - -test_expect_success 'apply binary patch' \ - 'git reset --hard && - git apply --binary --index <current && - tree1=`git write-tree` && - test "$tree1" = "$tree0"' +test_expect_success 'diff-index with --binary' ' + echo AIT >a && mv b e && echo CIT >c && cat e >d && + git update-index --add --remove a b c d e && + tree0=`git write-tree` && + git diff --cached --binary >current && + git apply --stat --summary current +' + +test_expect_success 'apply binary patch' ' + git reset --hard && + git apply --binary --index <current && + tree1=`git write-tree` && + test "$tree1" = "$tree0" +' test_expect_success 'diff --no-index with binary creation' ' echo Q | q_to_nul >binary && @@ -125,7 +119,7 @@ cat >expect <<EOF EOF test_expect_success 'diff --stat with binary files and big change count' ' - echo X | dd of=binfile bs=1k seek=1 && + printf "\01\00%1024d" 1 >binfile && git add binfile && i=0 && while test $i -lt 10000; do diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 959aa26ef..90fd598c7 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -110,73 +110,107 @@ test_expect_success 'replay did not screw up the log message' ' test_expect_success 'extra headers' ' - git config format.headers "To: R. E. Cipient <rcipient@example.com> + git config format.headers "To: R E Cipient <rcipient@example.com> " && - git config --add format.headers "Cc: S. E. Cipient <scipient@example.com> + git config --add format.headers "Cc: S E Cipient <scipient@example.com> " && git format-patch --stdout master..side > patch2 && sed -e "/^\$/q" patch2 > hdrs2 && - grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs2 && - grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs2 + grep "^To: R E Cipient <rcipient@example.com>\$" hdrs2 && + grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs2 ' test_expect_success 'extra headers without newlines' ' - git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" && - git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>" && + git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" && + git config --add format.headers "Cc: S E Cipient <scipient@example.com>" && git format-patch --stdout master..side >patch3 && sed -e "/^\$/q" patch3 > hdrs3 && - grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs3 && - grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs3 + grep "^To: R E Cipient <rcipient@example.com>\$" hdrs3 && + grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs3 ' test_expect_success 'extra headers with multiple To:s' ' - git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" && - git config --add format.headers "To: S. E. Cipient <scipient@example.com>" && + git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" && + git config --add format.headers "To: S E Cipient <scipient@example.com>" && git format-patch --stdout master..side > patch4 && sed -e "/^\$/q" patch4 > hdrs4 && - grep "^To: R. E. Cipient <rcipient@example.com>,\$" hdrs4 && - grep "^ *S. E. Cipient <scipient@example.com>\$" hdrs4 + grep "^To: R E Cipient <rcipient@example.com>,\$" hdrs4 && + grep "^ *S E Cipient <scipient@example.com>\$" hdrs4 ' -test_expect_success 'additional command line cc' ' +test_expect_success 'additional command line cc (ascii)' ' - git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" && + git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" && + git format-patch --cc="S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 && + grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 && + grep "^ *S E Cipient <scipient@example.com>\$" patch5 +' + +test_expect_failure 'additional command line cc (rfc822)' ' + + git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" && git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 && - grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch5 && - grep "^ *S. E. Cipient <scipient@example.com>\$" patch5 + grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 && + grep "^ *\"S. E. Cipient\" <scipient@example.com>\$" patch5 ' test_expect_success 'command line headers' ' git config --unset-all format.headers && - git format-patch --add-header="Cc: R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 && - grep "^Cc: R. E. Cipient <rcipient@example.com>\$" patch6 + git format-patch --add-header="Cc: R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 && + grep "^Cc: R E Cipient <rcipient@example.com>\$" patch6 ' test_expect_success 'configuration headers and command line headers' ' - git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" && - git format-patch --add-header="Cc: S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 && - grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch7 && - grep "^ *S. E. Cipient <scipient@example.com>\$" patch7 + git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" && + git format-patch --add-header="Cc: S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 && + grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch7 && + grep "^ *S E Cipient <scipient@example.com>\$" patch7 ' -test_expect_success 'command line To: header' ' +test_expect_success 'command line To: header (ascii)' ' git config --unset-all format.headers && + git format-patch --to="R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 && + grep "^To: R E Cipient <rcipient@example.com>\$" patch8 +' + +test_expect_failure 'command line To: header (rfc822)' ' + git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: R. E. Cipient <rcipient@example.com>\$" patch8 + grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch8 +' + +test_expect_failure 'command line To: header (rfc2047)' ' + + git format-patch --to="R Ä Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 && + grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch8 +' + +test_expect_success 'configuration To: header (ascii)' ' + + git config format.to "R E Cipient <rcipient@example.com>" && + git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && + grep "^To: R E Cipient <rcipient@example.com>\$" patch9 ' -test_expect_success 'configuration To: header' ' +test_expect_failure 'configuration To: header (rfc822)' ' git config format.to "R. E. Cipient <rcipient@example.com>" && git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: R. E. Cipient <rcipient@example.com>\$" patch9 + grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch9 +' + +test_expect_failure 'configuration To: header (rfc2047)' ' + + git config format.to "R Ä Cipient <rcipient@example.com>" && + git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && + grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch9 ' # check_patch <patch>: Verify that <patch> looks like a half-sane @@ -190,11 +224,11 @@ check_patch () { test_expect_success '--no-to overrides config.to' ' git config --replace-all format.to \ - "R. E. Cipient <rcipient@example.com>" && + "R E Cipient <rcipient@example.com>" && git format-patch --no-to --stdout master..side | sed -e "/^\$/q" >patch10 && check_patch patch10 && - ! grep "^To: R. E. Cipient <rcipient@example.com>\$" patch10 + ! grep "^To: R E Cipient <rcipient@example.com>\$" patch10 ' test_expect_success '--no-to and --to replaces config.to' ' @@ -212,21 +246,21 @@ test_expect_success '--no-to and --to replaces config.to' ' test_expect_success '--no-cc overrides config.cc' ' git config --replace-all format.cc \ - "C. E. Cipient <rcipient@example.com>" && + "C E Cipient <rcipient@example.com>" && git format-patch --no-cc --stdout master..side | sed -e "/^\$/q" >patch12 && check_patch patch12 && - ! grep "^Cc: C. E. Cipient <rcipient@example.com>\$" patch12 + ! grep "^Cc: C E Cipient <rcipient@example.com>\$" patch12 ' test_expect_success '--no-add-header overrides config.headers' ' git config --replace-all format.headers \ - "Header1: B. E. Cipient <rcipient@example.com>" && + "Header1: B E Cipient <rcipient@example.com>" && git format-patch --no-add-header --stdout master..side | sed -e "/^\$/q" >patch13 && check_patch patch13 && - ! grep "^Header1: B. E. Cipient <rcipient@example.com>\$" patch13 + ! grep "^Header1: B E Cipient <rcipient@example.com>\$" patch13 ' test_expect_success 'multiple files' ' @@ -616,8 +650,19 @@ test_expect_success 'format-patch --in-reply-to' ' ' test_expect_success 'format-patch --signoff' ' - git format-patch -1 --signoff --stdout | - grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" + git format-patch -1 --signoff --stdout >out && + grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" out +' + +test_expect_success 'format-patch --notes --signoff' ' + git notes --ref test add -m "test message" HEAD && + git format-patch -1 --signoff --stdout --notes=test >out && + # Three dashes must come after S-o-b + ! sed "/^Signed-off-by: /q" out | grep "test message" && + sed "1,/^Signed-off-by: /d" out | grep "test message" && + # Notes message must come after three dashes + ! sed "/^---$/q" out | grep "test message" && + sed "1,/^---$/d" out | grep "test message" ' echo "fatal: --name-only does not make sense" > expect.name-only @@ -752,16 +797,14 @@ M64=$M8$M8$M8$M8$M8$M8$M8$M8 M512=$M64$M64$M64$M64$M64$M64$M64$M64 cat >expect <<'EOF' Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo - bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar - foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo - bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar - foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo - bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar - foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo - bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar - foo bar foo bar foo bar foo bar + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo + bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar EOF -test_expect_success 'format-patch wraps extremely long headers (ascii)' ' +test_expect_success 'format-patch wraps extremely long subject (ascii)' ' echo content >>file && git add file && git commit -m "$M512" && @@ -774,30 +817,31 @@ M8="föö bar " M64=$M8$M8$M8$M8$M8$M8$M8$M8 M512=$M64$M64$M64$M64$M64$M64$M64$M64 cat >expect <<'EOF' -Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= +Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= + =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?= + =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?= + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?= + =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?= + =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= + =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?= + =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?= + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?= + =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?= + =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= + =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?= + =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?= + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?= + =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?= + =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= EOF -test_expect_success 'format-patch wraps extremely long headers (rfc2047)' ' +test_expect_success 'format-patch wraps extremely long subject (rfc2047)' ' rm -rf patches/ && echo content >>file && git add file && @@ -807,52 +851,80 @@ test_expect_success 'format-patch wraps extremely long headers (rfc2047)' ' test_cmp expect subject ' -M8="foo_bar_" -M64=$M8$M8$M8$M8$M8$M8$M8$M8 -cat >expect <<EOF -From: $M64 - <foobar@foo.bar> -EOF -test_expect_success 'format-patch wraps non-quotable headers' ' - rm -rf patches/ && - echo content >>file && - git add file && - git commit -mfoo --author "$M64 <foobar@foo.bar>" && - git format-patch --stdout -1 >patch && - sed -n "/^From: /p; /^ /p; /^$/q" <patch >from && - test_cmp expect from -' - check_author() { echo content >>file && git add file && GIT_AUTHOR_NAME=$1 git commit -m author-check && git format-patch --stdout -1 >patch && - grep ^From: patch >actual && + sed -n "/^From: /p; /^ /p; /^$/q" <patch >actual && test_cmp expect actual } cat >expect <<'EOF' From: "Foo B. Bar" <author@example.com> EOF -test_expect_success 'format-patch quotes dot in headers' ' +test_expect_success 'format-patch quotes dot in from-headers' ' check_author "Foo B. Bar" ' cat >expect <<'EOF' From: "Foo \"The Baz\" Bar" <author@example.com> EOF -test_expect_success 'format-patch quotes double-quote in headers' ' +test_expect_success 'format-patch quotes double-quote in from-headers' ' check_author "Foo \"The Baz\" Bar" ' cat >expect <<'EOF' -From: =?UTF-8?q?"F=C3=B6o=20B.=20Bar"?= <author@example.com> +From: =?UTF-8?q?F=C3=B6o=20Bar?= <author@example.com> +EOF +test_expect_success 'format-patch uses rfc2047-encoded from-headers when necessary' ' + check_author "Föo Bar" +' + +cat >expect <<'EOF' +From: =?UTF-8?q?F=C3=B6o=20B=2E=20Bar?= <author@example.com> EOF -test_expect_success 'rfc2047-encoded headers also double-quote 822 specials' ' +test_expect_success 'rfc2047-encoded from-headers leave no rfc822 specials' ' check_author "Föo B. Bar" ' +cat >expect <<EOF +From: foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_ + <author@example.com> +EOF +test_expect_success 'format-patch wraps moderately long from-header (ascii)' ' + check_author "foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_" +' + +cat >expect <<'EOF' +From: Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar + Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo + Bar Foo Bar Foo Bar Foo Bar <author@example.com> +EOF +test_expect_success 'format-patch wraps extremely long from-header (ascii)' ' + check_author "Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar" +' + +cat >expect <<'EOF' +From: "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar + Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo + Bar Foo Bar Foo Bar Foo Bar" <author@example.com> +EOF +test_expect_success 'format-patch wraps extremely long from-header (rfc822)' ' + check_author "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar" +' + +cat >expect <<'EOF' +From: =?UTF-8?q?Fo=C3=B6=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo?= + =?UTF-8?q?=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20?= + =?UTF-8?q?Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar?= + =?UTF-8?q?=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20?= + =?UTF-8?q?Foo=20Bar=20Foo=20Bar?= <author@example.com> +EOF +test_expect_success 'format-patch wraps extremely long from-header (rfc2047)' ' + check_author "Foö Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar" +' + cat >expect <<'EOF' Subject: header with . in it EOF diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh index 97b81778c..cd543ecc5 100755 --- a/t/t4016-diff-quote.sh +++ b/t/t4016-diff-quote.sh @@ -13,14 +13,12 @@ P1='pathname with HT' P2='pathname with SP' P3='pathname with LF' -if : 2>/dev/null >"$P1" && test -f "$P1" && rm -f "$P1" -then - test_set_prereq TABS_IN_FILENAMES -else - say 'Your filesystem does not allow tabs in filenames' -fi +echo 2>/dev/null >"$P1" && test -f "$P1" && rm -f "$P1" || { + skip_all='Your filesystem does not allow tabs in filenames' + test_done +} -test_expect_success TABS_IN_FILENAMES setup ' +test_expect_success setup ' echo P0.0 >"$P0.0" && echo P0.1 >"$P0.1" && echo P0.2 >"$P0.2" && @@ -40,7 +38,7 @@ test_expect_success TABS_IN_FILENAMES setup ' : ' -test_expect_success TABS_IN_FILENAMES 'setup expected files' ' +test_expect_success 'setup expected files' ' cat >expect <<\EOF rename pathname.1 => "Rpathname\twith HT.0" (100%) rename pathname.3 => "Rpathname\nwith LF.0" (100%) @@ -52,12 +50,12 @@ cat >expect <<\EOF EOF ' -test_expect_success TABS_IN_FILENAMES 'git diff --summary -M HEAD' ' +test_expect_success 'git diff --summary -M HEAD' ' git diff --summary -M HEAD >actual && test_cmp expect actual ' -test_expect_success TABS_IN_FILENAMES 'git diff --numstat -M HEAD' ' +test_expect_success 'git diff --numstat -M HEAD' ' cat >expect <<-\EOF && 0 0 pathname.1 => "Rpathname\twith HT.0" 0 0 pathname.3 => "Rpathname\nwith LF.0" @@ -71,7 +69,7 @@ test_expect_success TABS_IN_FILENAMES 'git diff --numstat -M HEAD' ' test_cmp expect actual ' -test_expect_success TABS_IN_FILENAMES 'git diff --stat -M HEAD' ' +test_expect_success 'git diff --stat -M HEAD' ' cat >expect <<-\EOF && pathname.1 => "Rpathname\twith HT.0" | 0 pathname.3 => "Rpathname\nwith LF.0" | 0 diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 4bd2a1c83..082d3e83b 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -105,7 +105,7 @@ test_expect_funcname () { grep "^@@.*@@ $1" diff } -for p in bibtex cpp csharp fortran html java matlab objc pascal perl php python ruby tex +for p in ada bibtex cpp csharp fortran html java matlab objc pascal perl php python ruby tex do test_expect_success "builtin $p pattern compiles" ' echo "*.java diff=$p" >.gitattributes && diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh index eebb1eed8..53ec330ce 100755 --- a/t/t4030-diff-textconv.sh +++ b/t/t4030-diff-textconv.sh @@ -84,6 +84,30 @@ test_expect_success 'status -v produces text' ' git reset --soft HEAD@{1} ' +test_expect_success 'grep-diff (-G) operates on textconv data (add)' ' + echo one >expect && + git log --root --format=%s -G0 >actual && + test_cmp expect actual +' + +test_expect_success 'grep-diff (-G) operates on textconv data (modification)' ' + echo two >expect && + git log --root --format=%s -G1 >actual && + test_cmp expect actual +' + +test_expect_success 'pickaxe (-S) operates on textconv data (add)' ' + echo one >expect && + git log --root --format=%s -S0 >actual && + test_cmp expect actual +' + +test_expect_success 'pickaxe (-S) operates on textconv data (modification)' ' + echo two >expect && + git log --root --format=%s -S1 >actual && + test_cmp expect actual +' + cat >expect.stat <<'EOF' file | Bin 2 -> 4 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 30d42cb3b..40ab333a8 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -298,6 +298,7 @@ test_expect_success 'unset default driver' ' test_unconfig diff.wordregex ' +test_language_driver ada test_language_driver bibtex test_language_driver cpp test_language_driver csharp diff --git a/t/t4034/ada/expect b/t/t4034/ada/expect new file mode 100644 index 000000000..be2376e90 --- /dev/null +++ b/t/t4034/ada/expect @@ -0,0 +1,27 @@ +<BOLD>diff --git a/pre b/post<RESET> +<BOLD>index d96fdd1..df21bb0 100644<RESET> +<BOLD>--- a/pre<RESET> +<BOLD>+++ b/post<RESET> +<CYAN>@@ -1,13 +1,13 @@<RESET> +Ada.Text_IO.Put_Line("Hello World<RED>!<RESET><GREEN>?<RESET>"); +1 1e<RED>-<RESET>10 16#FE12#E2 3.141_592 '<RED>x<RESET><GREEN>y<RESET>' +<RED>a<RESET><GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>**<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>(<RED>b<RESET><GREEN>y<RESET>) +<RED>a<RESET><GREEN>x<RESET>:=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>/= <RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>,<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>=><RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET>..<RED>b<RESET> +<RED>a<RESET><GREEN>y<RESET> +<GREEN>x<RESET><><RED>b<RESET><GREEN>y<RESET> diff --git a/t/t4034/ada/post b/t/t4034/ada/post new file mode 100644 index 000000000..df21bb044 --- /dev/null +++ b/t/t4034/ada/post @@ -0,0 +1,13 @@ +Ada.Text_IO.Put_Line("Hello World?"); +1 1e10 16#FE12#E2 3.141_592 'y' +x+y x-y +x*y x/y +x**y +x(y) +x:=y +x=y x/= y +x<y x<=y x>y x>=y +x,y +x=>y +x..y +x<>y diff --git a/t/t4034/ada/pre b/t/t4034/ada/pre new file mode 100644 index 000000000..d96fdd1e8 --- /dev/null +++ b/t/t4034/ada/pre @@ -0,0 +1,13 @@ +Ada.Text_IO.Put_Line("Hello World!"); +1 1e-10 16#FE12#E2 3.141_592 'x' +a+b a-b +a*b a/b +a**b +a(b) +a:=b +a=b a/= b +a<b a<=b a>b a>=b +a,b +a=>b +a..b +a<>b diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh index 6c01d0c05..32d4a6042 100755 --- a/t/t4041-diff-submodule-option.sh +++ b/t/t4041-diff-submodule-option.sh @@ -11,18 +11,18 @@ This test tries to verify the sanity of the --submodule option of git diff. . ./test-lib.sh add_file () { - sm=$1 - shift - owd=$(pwd) - cd "$sm" - for name; do - echo "$name" > "$name" && - git add "$name" && - test_tick && - git commit -m "Add $name" - done >/dev/null - git rev-parse --verify HEAD | cut -c1-7 - cd "$owd" + ( + cd "$1" && + shift && + for name + do + echo "$name" >"$name" && + git add "$name" && + test_tick && + git commit -m "Add $name" || exit + done >/dev/null && + git rev-parse --short --verify HEAD + ) } commit_file () { test_tick && @@ -33,92 +33,133 @@ test_create_repo sm1 && add_file . foo >/dev/null head1=$(add_file sm1 foo1 foo2) +fullhead1=$(cd sm1; git rev-parse --verify HEAD) -test_expect_success 'added submodule' " +test_expect_success 'added submodule' ' git add sm1 && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 0000000...$head1 (new submodule) -EOF + Submodule sm1 0000000...$head1 (new submodule) + EOF + test_cmp expected actual +' + +test_expect_success 'added submodule, set diff.submodule' ' + git config diff.submodule log && + git add sm1 && + git diff --cached >actual && + cat >expected <<-EOF && + Submodule sm1 0000000...$head1 (new submodule) + EOF + git config --unset diff.submodule && + test_cmp expected actual +' + +test_expect_success '--submodule=short overrides diff.submodule' ' + test_config diff.submodule log && + git add sm1 && + git diff --submodule=short --cached >actual && + cat >expected <<-EOF && + diff --git a/sm1 b/sm1 + new file mode 160000 + index 0000000..$head1 + --- /dev/null + +++ b/sm1 + @@ -0,0 +1 @@ + +Subproject commit $fullhead1 + EOF test_cmp expected actual -" +' + +test_expect_success 'diff.submodule does not affect plumbing' ' + test_config diff.submodule log && + git diff-index -p HEAD >actual && + cat >expected <<-EOF && + diff --git a/sm1 b/sm1 + new file mode 160000 + index 0000000..$head1 + --- /dev/null + +++ b/sm1 + @@ -0,0 +1 @@ + +Subproject commit $fullhead1 + EOF + test_cmp expected actual +' commit_file sm1 && head2=$(add_file sm1 foo3) -test_expect_success 'modified submodule(forward)' " +test_expect_success 'modified submodule(forward)' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head1..$head2: - > Add foo3 -EOF + Submodule sm1 $head1..$head2: + > Add foo3 + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule(forward)' " +test_expect_success 'modified submodule(forward)' ' git diff --submodule=log >actual && cat >expected <<-EOF && -Submodule sm1 $head1..$head2: - > Add foo3 -EOF + Submodule sm1 $head1..$head2: + > Add foo3 + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule(forward) --submodule' " +test_expect_success 'modified submodule(forward) --submodule' ' git diff --submodule >actual && cat >expected <<-EOF && -Submodule sm1 $head1..$head2: - > Add foo3 -EOF + Submodule sm1 $head1..$head2: + > Add foo3 + EOF test_cmp expected actual -" +' -fullhead1=$(cd sm1; git rev-list --max-count=1 $head1) -fullhead2=$(cd sm1; git rev-list --max-count=1 $head2) -test_expect_success 'modified submodule(forward) --submodule=short' " +fullhead2=$(cd sm1; git rev-parse --verify HEAD) +test_expect_success 'modified submodule(forward) --submodule=short' ' git diff --submodule=short >actual && cat >expected <<-EOF && -diff --git a/sm1 b/sm1 -index $head1..$head2 160000 ---- a/sm1 -+++ b/sm1 -@@ -1 +1 @@ --Subproject commit $fullhead1 -+Subproject commit $fullhead2 -EOF + diff --git a/sm1 b/sm1 + index $head1..$head2 160000 + --- a/sm1 + +++ b/sm1 + @@ -1 +1 @@ + -Subproject commit $fullhead1 + +Subproject commit $fullhead2 + EOF test_cmp expected actual -" +' commit_file sm1 && head3=$( cd sm1 && git reset --hard HEAD~2 >/dev/null && - git rev-parse --verify HEAD | cut -c1-7 + git rev-parse --short --verify HEAD ) -test_expect_success 'modified submodule(backward)' " +test_expect_success 'modified submodule(backward)' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head2..$head3 (rewind): - < Add foo3 - < Add foo2 -EOF + Submodule sm1 $head2..$head3 (rewind): + < Add foo3 + < Add foo2 + EOF test_cmp expected actual -" +' -head4=$(add_file sm1 foo4 foo5) && -head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD) -test_expect_success 'modified submodule(backward and forward)' " +head4=$(add_file sm1 foo4 foo5) +test_expect_success 'modified submodule(backward and forward)' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head2...$head4: - > Add foo5 - > Add foo4 - < Add foo3 - < Add foo2 -EOF + Submodule sm1 $head2...$head4: + > Add foo5 + > Add foo4 + < Add foo3 + < Add foo2 + EOF test_cmp expected actual -" +' commit_file sm1 && mv sm1 sm1-bak && @@ -128,319 +169,319 @@ git add sm1 && rm -f sm1 && mv sm1-bak sm1 -test_expect_success 'typechanged submodule(submodule->blob), --cached' " +test_expect_success 'typechanged submodule(submodule->blob), --cached' ' git diff --submodule=log --cached >actual && cat >expected <<-EOF && -Submodule sm1 41fbea9...0000000 (submodule deleted) -diff --git a/sm1 b/sm1 -new file mode 100644 -index 0000000..9da5fb8 ---- /dev/null -+++ b/sm1 -@@ -0,0 +1 @@ -+sm1 -EOF + Submodule sm1 $head4...0000000 (submodule deleted) + diff --git a/sm1 b/sm1 + new file mode 100644 + index 0000000..$head5 + --- /dev/null + +++ b/sm1 + @@ -0,0 +1 @@ + +sm1 + EOF test_cmp expected actual -" +' -test_expect_success 'typechanged submodule(submodule->blob)' " +test_expect_success 'typechanged submodule(submodule->blob)' ' git diff --submodule=log >actual && cat >expected <<-EOF && -diff --git a/sm1 b/sm1 -deleted file mode 100644 -index 9da5fb8..0000000 ---- a/sm1 -+++ /dev/null -@@ -1 +0,0 @@ --sm1 -Submodule sm1 0000000...$head4 (new submodule) -EOF + diff --git a/sm1 b/sm1 + deleted file mode 100644 + index $head5..0000000 + --- a/sm1 + +++ /dev/null + @@ -1 +0,0 @@ + -sm1 + Submodule sm1 0000000...$head4 (new submodule) + EOF test_cmp expected actual -" +' rm -rf sm1 && git checkout-index sm1 -test_expect_success 'typechanged submodule(submodule->blob)' " +test_expect_success 'typechanged submodule(submodule->blob)' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head4...0000000 (submodule deleted) -diff --git a/sm1 b/sm1 -new file mode 100644 -index 0000000..$head5 ---- /dev/null -+++ b/sm1 -@@ -0,0 +1 @@ -+sm1 -EOF + Submodule sm1 $head4...0000000 (submodule deleted) + diff --git a/sm1 b/sm1 + new file mode 100644 + index 0000000..$head5 + --- /dev/null + +++ b/sm1 + @@ -0,0 +1 @@ + +sm1 + EOF test_cmp expected actual -" +' rm -f sm1 && test_create_repo sm1 && head6=$(add_file sm1 foo6 foo7) -fullhead6=$(cd sm1; git rev-list --max-count=1 $head6) -test_expect_success 'nonexistent commit' " +fullhead6=$(cd sm1; git rev-parse --verify HEAD) +test_expect_success 'nonexistent commit' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head4...$head6 (commits not present) -EOF + Submodule sm1 $head4...$head6 (commits not present) + EOF test_cmp expected actual -" +' commit_file -test_expect_success 'typechanged submodule(blob->submodule)' " +test_expect_success 'typechanged submodule(blob->submodule)' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -diff --git a/sm1 b/sm1 -deleted file mode 100644 -index $head5..0000000 ---- a/sm1 -+++ /dev/null -@@ -1 +0,0 @@ --sm1 -Submodule sm1 0000000...$head6 (new submodule) -EOF + diff --git a/sm1 b/sm1 + deleted file mode 100644 + index $head5..0000000 + --- a/sm1 + +++ /dev/null + @@ -1 +0,0 @@ + -sm1 + Submodule sm1 0000000...$head6 (new submodule) + EOF test_cmp expected actual -" +' commit_file sm1 && -test_expect_success 'submodule is up to date' " +test_expect_success 'submodule is up to date' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -EOF + EOF test_cmp expected actual -" +' -test_expect_success 'submodule contains untracked content' " +test_expect_success 'submodule contains untracked content' ' echo new > sm1/new-file && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains untracked content -EOF + Submodule sm1 contains untracked content + EOF test_cmp expected actual -" +' -test_expect_success 'submodule contains untracked content (untracked ignored)' " +test_expect_success 'submodule contains untracked content (untracked ignored)' ' git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'submodule contains untracked content (dirty ignored)' " +test_expect_success 'submodule contains untracked content (dirty ignored)' ' git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'submodule contains untracked content (all ignored)' " +test_expect_success 'submodule contains untracked content (all ignored)' ' git diff-index -p --ignore-submodules=all --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'submodule contains untracked and modifed content' " +test_expect_success 'submodule contains untracked and modifed content' ' echo new > sm1/foo6 && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains untracked content -Submodule sm1 contains modified content -EOF + Submodule sm1 contains untracked content + Submodule sm1 contains modified content + EOF test_cmp expected actual -" +' -test_expect_success 'submodule contains untracked and modifed content (untracked ignored)' " +test_expect_success 'submodule contains untracked and modifed content (untracked ignored)' ' echo new > sm1/foo6 && git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains modified content -EOF + Submodule sm1 contains modified content + EOF test_cmp expected actual -" +' -test_expect_success 'submodule contains untracked and modifed content (dirty ignored)' " +test_expect_success 'submodule contains untracked and modifed content (dirty ignored)' ' echo new > sm1/foo6 && git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'submodule contains untracked and modifed content (all ignored)' " +test_expect_success 'submodule contains untracked and modifed content (all ignored)' ' echo new > sm1/foo6 && git diff-index -p --ignore-submodules --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'submodule contains modifed content' " +test_expect_success 'submodule contains modifed content' ' rm -f sm1/new-file && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains modified content -EOF + Submodule sm1 contains modified content + EOF test_cmp expected actual -" +' (cd sm1; git commit -mchange foo6 >/dev/null) && -head8=$(cd sm1; git rev-parse --verify HEAD | cut -c1-7) && -test_expect_success 'submodule is modified' " +head8=$(cd sm1; git rev-parse --short --verify HEAD) && +test_expect_success 'submodule is modified' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked content' " +test_expect_success 'modified submodule contains untracked content' ' echo new > sm1/new-file && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains untracked content -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 contains untracked content + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked content (untracked ignored)' " +test_expect_success 'modified submodule contains untracked content (untracked ignored)' ' git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked content (dirty ignored)' " +test_expect_success 'modified submodule contains untracked content (dirty ignored)' ' git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked content (all ignored)' " +test_expect_success 'modified submodule contains untracked content (all ignored)' ' git diff-index -p --ignore-submodules=all --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'modified submodule contains untracked and modifed content' " +test_expect_success 'modified submodule contains untracked and modifed content' ' echo modification >> sm1/foo6 && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains untracked content -Submodule sm1 contains modified content -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 contains untracked content + Submodule sm1 contains modified content + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked and modifed content (untracked ignored)' " +test_expect_success 'modified submodule contains untracked and modifed content (untracked ignored)' ' echo modification >> sm1/foo6 && git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains modified content -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 contains modified content + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked and modifed content (dirty ignored)' " +test_expect_success 'modified submodule contains untracked and modifed content (dirty ignored)' ' echo modification >> sm1/foo6 && git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' -test_expect_success 'modified submodule contains untracked and modifed content (all ignored)' " +test_expect_success 'modified submodule contains untracked and modifed content (all ignored)' ' echo modification >> sm1/foo6 && git diff-index -p --ignore-submodules --submodule=log HEAD >actual && ! test -s actual -" +' -test_expect_success 'modified submodule contains modifed content' " +test_expect_success 'modified submodule contains modifed content' ' rm -f sm1/new-file && git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 contains modified content -Submodule sm1 $head6..$head8: - > change -EOF + Submodule sm1 contains modified content + Submodule sm1 $head6..$head8: + > change + EOF test_cmp expected actual -" +' rm -rf sm1 -test_expect_success 'deleted submodule' " +test_expect_success 'deleted submodule' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head6...0000000 (submodule deleted) -EOF + Submodule sm1 $head6...0000000 (submodule deleted) + EOF test_cmp expected actual -" +' test_create_repo sm2 && head7=$(add_file sm2 foo8 foo9) && git add sm2 -test_expect_success 'multiple submodules' " +test_expect_success 'multiple submodules' ' git diff-index -p --submodule=log HEAD >actual && cat >expected <<-EOF && -Submodule sm1 $head6...0000000 (submodule deleted) -Submodule sm2 0000000...$head7 (new submodule) -EOF + Submodule sm1 $head6...0000000 (submodule deleted) + Submodule sm2 0000000...$head7 (new submodule) + EOF test_cmp expected actual -" +' -test_expect_success 'path filter' " +test_expect_success 'path filter' ' git diff-index -p --submodule=log HEAD sm2 >actual && cat >expected <<-EOF && -Submodule sm2 0000000...$head7 (new submodule) -EOF + Submodule sm2 0000000...$head7 (new submodule) + EOF test_cmp expected actual -" +' commit_file sm2 -test_expect_success 'given commit' " +test_expect_success 'given commit' ' git diff-index -p --submodule=log HEAD^ >actual && cat >expected <<-EOF && -Submodule sm1 $head6...0000000 (submodule deleted) -Submodule sm2 0000000...$head7 (new submodule) -EOF + Submodule sm1 $head6...0000000 (submodule deleted) + Submodule sm2 0000000...$head7 (new submodule) + EOF test_cmp expected actual -" +' -test_expect_success 'given commit --submodule' " +test_expect_success 'given commit --submodule' ' git diff-index -p --submodule HEAD^ >actual && cat >expected <<-EOF && -Submodule sm1 $head6...0000000 (submodule deleted) -Submodule sm2 0000000...$head7 (new submodule) -EOF + Submodule sm1 $head6...0000000 (submodule deleted) + Submodule sm2 0000000...$head7 (new submodule) + EOF test_cmp expected actual -" +' -fullhead7=$(cd sm2; git rev-list --max-count=1 $head7) +fullhead7=$(cd sm2; git rev-parse --verify HEAD) -test_expect_success 'given commit --submodule=short' " +test_expect_success 'given commit --submodule=short' ' git diff-index -p --submodule=short HEAD^ >actual && cat >expected <<-EOF && -diff --git a/sm1 b/sm1 -deleted file mode 160000 -index $head6..0000000 ---- a/sm1 -+++ /dev/null -@@ -1 +0,0 @@ --Subproject commit $fullhead6 -diff --git a/sm2 b/sm2 -new file mode 160000 -index 0000000..$head7 ---- /dev/null -+++ b/sm2 -@@ -0,0 +1 @@ -+Subproject commit $fullhead7 -EOF - test_cmp expected actual -" + diff --git a/sm1 b/sm1 + deleted file mode 160000 + index $head6..0000000 + --- a/sm1 + +++ /dev/null + @@ -1 +0,0 @@ + -Subproject commit $fullhead6 + diff --git a/sm2 b/sm2 + new file mode 160000 + index 0000000..$head7 + --- /dev/null + +++ b/sm2 + @@ -0,0 +1 @@ + +Subproject commit $fullhead7 + EOF + test_cmp expected actual +' test_expect_success 'setup .git file for sm2' ' (cd sm2 && @@ -452,9 +493,9 @@ test_expect_success 'setup .git file for sm2' ' test_expect_success 'diff --submodule with .git file' ' git diff --submodule HEAD^ >actual && cat >expected <<-EOF && -Submodule sm1 $head6...0000000 (submodule deleted) -Submodule sm2 0000000...$head7 (new submodule) -EOF + Submodule sm1 $head6...0000000 (submodule deleted) + Submodule sm2 0000000...$head7 (new submodule) + EOF test_cmp expected actual ' diff --git a/t/t4049-diff-stat-count.sh b/t/t4049-diff-stat-count.sh index b41eb61ca..5b594e878 100755 --- a/t/t4049-diff-stat-count.sh +++ b/t/t4049-diff-stat-count.sh @@ -4,19 +4,62 @@ test_description='diff --stat-count' . ./test-lib.sh -test_expect_success setup ' +test_expect_success 'setup' ' >a && >b && >c && >d && git add a b c d && - chmod +x c d && + git commit -m initial +' + +test_expect_success 'mode-only change show as a 0-line change' ' + git reset --hard && + test_chmod +x b d && + echo a >a && + echo c >c && + cat >expect <<-\EOF + a | 1 + + b | 0 + ... + 4 files changed, 2 insertions(+) + EOF + git diff --stat --stat-count=2 HEAD >actual && + test_i18ncmp expect actual +' + +test_expect_success 'binary changes do not count in lines' ' + git reset --hard && + echo a >a && + echo c >c && + cat "$TEST_DIRECTORY"/test-binary-1.png >d && + cat >expect <<-\EOF + a | 1 + + c | 1 + + ... + 3 files changed, 2 insertions(+) + EOF + git diff --stat --stat-count=2 >actual && + test_i18ncmp expect actual +' + +test_expect_success 'exclude unmerged entries from total file count' ' + git reset --hard && echo a >a && echo b >b && + git ls-files -s a >x && + git rm -f d && + for stage in 1 2 3 + do + sed -e "s/ 0 a/ $stage d/" x + done | + git update-index --index-info && + echo d >d && cat >expect <<-\EOF a | 1 + b | 1 + - 2 files changed, 2 insertions(+) + ... + 3 files changed, 3 insertions(+) EOF git diff --stat --stat-count=2 >actual && test_i18ncmp expect actual diff --git a/t/t4055-diff-context.sh b/t/t4055-diff-context.sh new file mode 100755 index 000000000..97172b46b --- /dev/null +++ b/t/t4055-diff-context.sh @@ -0,0 +1,92 @@ +#!/bin/sh +# +# Copyright (c) 2012 Mozilla Foundation +# + +test_description='diff.context configuration' + +. ./test-lib.sh + +test_expect_success 'setup' ' + cat >template <<-\EOF && + firstline + b + c + d + e + f + preline + TARGET + postline + i + j + k + l + m + n + EOF + sed "/TARGET/d" >x <template && + git update-index --add x && + git commit -m initial && + + sed "s/TARGET/ADDED/" >x <template && + git update-index --add x && + git commit -m next && + + sed "s/TARGET/MODIFIED/" >x <template +' + +test_expect_success 'the default number of context lines is 3' ' + git diff >output && + ! grep "^ d" output && + grep "^ e" output && + grep "^ j" output && + ! grep "^ k" output +' + +test_expect_success 'diff.context honored by "log"' ' + git log -1 -p >output && + ! grep firstline output && + git config diff.context 8 && + git log -1 -p >output && + grep "^ firstline" output +' + +test_expect_success 'The -U option overrides diff.context' ' + git config diff.context 8 && + git log -U4 -1 >output && + ! grep "^ firstline" output +' + +test_expect_success 'diff.context honored by "diff"' ' + git config diff.context 8 && + git diff >output && + grep "^ firstline" output +' + +test_expect_success 'plumbing not affected' ' + git config diff.context 8 && + git diff-files -p >output && + ! grep "^ firstline" output +' + +test_expect_success 'non-integer config parsing' ' + git config diff.context no && + test_must_fail git diff 2>output && + test_i18ngrep "bad config value" output +' + +test_expect_success 'negative integer config parsing' ' + git config diff.context -1 && + test_must_fail git diff 2>output && + test_i18ngrep "bad config file" output +' + +test_expect_success '-U0 is valid, so is diff.context=0' ' + git config diff.context 0 && + git diff >output && + grep "^-ADDED" output && + grep "^+MODIFIED" output +' + +test_done diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh new file mode 100755 index 000000000..fa5d4efb8 --- /dev/null +++ b/t/t4108-apply-threeway.sh @@ -0,0 +1,157 @@ +#!/bin/sh + +test_description='git apply --3way' + +. ./test-lib.sh + +create_file () { + for i + do + echo "$i" + done +} + +sanitize_conflicted_diff () { + sed -e ' + /^index /d + s/^\(+[<>][<>][<>][<>]*\) .*/\1/ + ' +} + +test_expect_success setup ' + test_tick && + create_file >one 1 2 3 4 5 6 7 && + cat one >two && + git add one two && + git commit -m initial && + + git branch side && + + test_tick && + create_file >one 1 two 3 4 5 six 7 && + create_file >two 1 two 3 4 5 6 7 && + git commit -a -m master && + + git checkout side && + create_file >one 1 2 3 4 five 6 7 && + create_file >two 1 2 3 4 five 6 7 && + git commit -a -m side && + + git checkout master +' + +test_expect_success 'apply without --3way' ' + git diff side^ side >P.diff && + + # should fail to apply + git reset --hard && + git checkout master^0 && + test_must_fail git apply --index P.diff && + # should leave things intact + git diff-files --exit-code && + git diff-index --exit-code --cached HEAD +' + +test_expect_success 'apply with --3way' ' + # Merging side should be similar to applying this patch + git diff ...side >P.diff && + + # The corresponding conflicted merge + git reset --hard && + git checkout master^0 && + test_must_fail git merge --no-commit side && + git ls-files -s >expect.ls && + git diff HEAD | sanitize_conflicted_diff >expect.diff && + + # should fail to apply + git reset --hard && + git checkout master^0 && + test_must_fail git apply --index --3way P.diff && + git ls-files -s >actual.ls && + git diff HEAD | sanitize_conflicted_diff >actual.diff && + + # The result should resemble the corresponding merge + test_cmp expect.ls actual.ls && + test_cmp expect.diff actual.diff +' + +test_expect_success 'apply with --3way with rerere enabled' ' + git config rerere.enabled true && + + # Merging side should be similar to applying this patch + git diff ...side >P.diff && + + # The corresponding conflicted merge + git reset --hard && + git checkout master^0 && + test_must_fail git merge --no-commit side && + + # Manually resolve and record the resolution + create_file 1 two 3 4 five six 7 >one && + git rerere && + cat one >expect && + + # should fail to apply + git reset --hard && + git checkout master^0 && + test_must_fail git apply --index --3way P.diff && + + # but rerere should have replayed the recorded resolution + test_cmp expect one +' + +test_expect_success 'apply -3 with add/add conflict setup' ' + git reset --hard && + + git checkout -b adder && + create_file 1 2 3 4 5 6 7 >three && + create_file 1 2 3 4 5 6 7 >four && + git add three four && + git commit -m "add three and four" && + + git checkout -b another adder^ && + create_file 1 2 3 4 5 6 7 >three && + create_file 1 2 3 four 5 6 7 >four && + git add three four && + git commit -m "add three and four" && + + # Merging another should be similar to applying this patch + git diff adder...another >P.diff && + + git checkout adder^0 && + test_must_fail git merge --no-commit another && + git ls-files -s >expect.ls && + git diff HEAD | sanitize_conflicted_diff >expect.diff +' + +test_expect_success 'apply -3 with add/add conflict' ' + # should fail to apply ... + git reset --hard && + git checkout adder^0 && + test_must_fail git apply --index --3way P.diff && + # ... and leave conflicts in the index and in the working tree + git ls-files -s >actual.ls && + git diff HEAD | sanitize_conflicted_diff >actual.diff && + + # The result should resemble the corresponding merge + test_cmp expect.ls actual.ls && + test_cmp expect.diff actual.diff +' + +test_expect_success 'apply -3 with add/add conflict (dirty working tree)' ' + # should fail to apply ... + git reset --hard && + git checkout adder^0 && + echo >>four && + cat four >four.save && + cat three >three.save && + git ls-files -s >expect.ls && + test_must_fail git apply --index --3way P.diff && + # ... and should not touch anything + git ls-files -s >actual.ls && + test_cmp expect.ls actual.ls && + test_cmp four.save four && + test_cmp three.save three +' + +test_done diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh index e9ccd161e..8e15ecbdf 100755 --- a/t/t4117-apply-reject.sh +++ b/t/t4117-apply-reject.sh @@ -46,6 +46,14 @@ test_expect_success setup ' cat file1 >saved.file1 ' +test_expect_success 'apply --reject is incompatible with --3way' ' + test_when_finished "cat saved.file1 >file1" && + git diff >patch.0 && + git checkout file1 && + test_must_fail git apply --reject --3way patch.0 && + git diff --exit-code +' + test_expect_success 'apply without --reject should fail' ' if git apply patch.1 diff --git a/t/t4120-apply-popt.sh b/t/t4120-apply-popt.sh index a33d510bf..c5fecdfed 100755 --- a/t/t4120-apply-popt.sh +++ b/t/t4120-apply-popt.sh @@ -32,7 +32,7 @@ test_expect_success 'apply git diff with -p2' ' test_expect_success 'apply with too large -p' ' cp file1.saved file1 && test_must_fail git apply --stat -p3 patch.file 2>err && - grep "removing 3 leading" err + test_i18ngrep "removing 3 leading" err ' test_expect_success 'apply (-p2) traditional diff with funny filenames' ' @@ -54,7 +54,7 @@ test_expect_success 'apply (-p2) traditional diff with funny filenames' ' test_expect_success 'apply with too large -p and fancy filename' ' cp file1.saved file1 && test_must_fail git apply --stat -p3 patch.escaped 2>err && - grep "removing 3 leading" err + test_i18ngrep "removing 3 leading" err ' test_expect_success 'apply (-p2) diff, mode change only' ' diff --git a/t/t4133-apply-filenames.sh b/t/t4133-apply-filenames.sh index 94da99075..2ecb4216b 100755 --- a/t/t4133-apply-filenames.sh +++ b/t/t4133-apply-filenames.sh @@ -30,9 +30,9 @@ EOF test_expect_success 'apply diff with inconsistent filenames in headers' ' test_must_fail git apply bad1.patch 2>err && - grep "inconsistent new filename" err && + test_i18ngrep "inconsistent new filename" err && test_must_fail git apply bad2.patch 2>err && - grep "inconsistent old filename" err + test_i18ngrep "inconsistent old filename" err ' test_done diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index 3ab670d36..7f6666fcd 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -382,13 +382,13 @@ test_expect_success 'rerere --no-no-rerere-autoupdate' ' git update-index --index-info <failedmerge && cp file3.conflict file3 && test_must_fail git rerere --no-no-rerere-autoupdate 2>err && - grep [Uu]sage err && + test_i18ngrep [Uu]sage err && test_must_fail git update-index --refresh ' test_expect_success 'rerere -h' ' test_must_fail git rerere -h >help && - grep [Uu]sage help + test_i18ngrep [Uu]sage help ' test_done diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh index 6872ba1a4..5493500ef 100755 --- a/t/t4201-shortlog.sh +++ b/t/t4201-shortlog.sh @@ -120,6 +120,30 @@ test_expect_success 'shortlog from non-git directory' ' test_cmp expect out ' +test_expect_success 'shortlog should add newline when input line matches wraplen' ' + cat >expect <<\EOF && +A U Thor (2): + bbbbbbbbbbbbbbbbbb: bbbbbbbb bbb bbbb bbbbbbb bb bbbb bbb bbbbb bbbbbb + aaaaaaaaaaaaaaaaaaaaaa: aaaaaa aaaaaaaaaa aaaa aaaaaaaa aa aaaa aa aaa + +EOF + git shortlog -w >out <<\EOF && +commit 0000000000000000000000000000000000000001 +Author: A U Thor <author@example.com> +Date: Thu Apr 7 15:14:13 2005 -0700 + + aaaaaaaaaaaaaaaaaaaaaa: aaaaaa aaaaaaaaaa aaaa aaaaaaaa aa aaaa aa aaa + +commit 0000000000000000000000000000000000000002 +Author: A U Thor <author@example.com> +Date: Thu Apr 7 15:14:13 2005 -0700 + + bbbbbbbbbbbbbbbbbb: bbbbbbbb bbb bbbb bbbbbbb bb bbbb bbb bbbbb bbbbbb + +EOF + test_cmp expect out +' + iconvfromutf8toiso88591() { printf "%s" "$*" | iconv -f UTF-8 -t ISO8859-1 } diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 45058cc8c..fa686b887 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -72,9 +72,9 @@ cat > expect << EOF commit. EOF -test_expect_success 'format %w(12,1,2)' ' +test_expect_success 'format %w(11,1,2)' ' - git log -2 --format="%w(12,1,2)This is the %s commit." > actual && + git log -2 --format="%w(11,1,2)This is the %s commit." > actual && test_cmp expect actual ' @@ -178,11 +178,21 @@ test_expect_success 'git log --no-walk <commits> sorts by commit time' ' test_cmp expect actual ' +test_expect_success 'git log --no-walk=sorted <commits> sorts by commit time' ' + git log --no-walk=sorted --oneline 5d31159 804a787 394ef78 > actual && + test_cmp expect actual +' + cat > expect << EOF 5d31159 fourth 804a787 sixth 394ef78 fifth EOF +test_expect_success 'git log --no-walk=unsorted <commits> leaves list of commits as given' ' + git log --no-walk=unsorted --oneline 5d31159 804a787 394ef78 > actual && + test_cmp expect actual +' + test_expect_success 'git show <commits> leaves list of commits as given' ' git show --oneline -s 5d31159 804a787 394ef78 > actual && test_cmp expect actual @@ -220,6 +230,12 @@ test_expect_success 'log --grep -i' ' test_cmp expect actual ' +test_expect_success 'log -F -E --grep=<ere> uses ere' ' + echo second >expect && + git log -1 --pretty="tformat:%s" -F -E --grep=s.c.nd >actual && + test_cmp expect actual +' + cat > expect <<EOF * Second * sixth @@ -264,6 +280,16 @@ test_expect_success 'log --graph with merge' ' test_cmp expect actual ' +test_expect_success 'log --raw --graph -m with merge' ' + git log --raw --graph --oneline -m master | head -n 500 >actual && + grep "initial" actual +' + +test_expect_success 'diff-tree --graph' ' + git diff-tree --graph master^ | head -n 500 >actual && + grep "one" actual +' + cat > expect <<\EOF * commit master |\ Merge: A B @@ -803,7 +829,7 @@ sanitize_output () { test_expect_success 'log --graph with diff and stats' ' git log --graph --pretty=short --stat -p >actual && sanitize_output >actual.sanitized <actual && - test_cmp expect actual.sanitized + test_i18ncmp expect actual.sanitized ' test_expect_success 'dotdot is a parent directory' ' diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh index 4afd77815..98a43d457 100755 --- a/t/t4205-log-pretty-formats.sh +++ b/t/t4205-log-pretty-formats.sh @@ -85,18 +85,18 @@ test_expect_success 'NUL termination' ' test_expect_success 'NUL separation with --stat' ' stat0_part=$(git diff --stat HEAD^ HEAD) && - stat1_part=$(git diff --stat --root HEAD^) && + stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) && printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n" >expected && git log -z --stat --pretty="format:%s" >actual && - test_cmp expected actual + test_i18ncmp expected actual ' test_expect_failure 'NUL termination with --stat' ' stat0_part=$(git diff --stat HEAD^ HEAD) && - stat1_part=$(git diff --stat --root HEAD^) && + stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) && printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n\0" >expected && git log -z --stat --pretty="tformat:%s" >actual && - test_cmp expected actual + test_i18ncmp expected actual ' test_done diff --git a/t/t5002-archive-attr-pattern.sh b/t/t5002-archive-attr-pattern.sh new file mode 100755 index 000000000..0c847fb45 --- /dev/null +++ b/t/t5002-archive-attr-pattern.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +test_description='git archive attribute pattern tests' + +. ./test-lib.sh + +test_expect_exists() { + test_expect_success " $1 exists" "test -e $1" +} + +test_expect_missing() { + test_expect_success " $1 does not exist" "test ! -e $1" +} + +test_expect_success 'setup' ' + echo ignored >ignored && + echo ignored export-ignore >>.git/info/attributes && + git add ignored && + + mkdir not-ignored-dir && + echo ignored-in-tree >not-ignored-dir/ignored && + echo not-ignored-in-tree >not-ignored-dir/ignored-only-if-dir && + git add not-ignored-dir && + + mkdir ignored-only-if-dir && + echo ignored by ignored dir >ignored-only-if-dir/ignored-by-ignored-dir && + echo ignored-only-if-dir/ export-ignore >>.git/info/attributes && + git add ignored-only-if-dir && + + + mkdir -p one-level-lower/two-levels-lower/ignored-only-if-dir && + echo ignored by ignored dir >one-level-lower/two-levels-lower/ignored-only-if-dir/ignored-by-ignored-dir && + git add one-level-lower && + + git commit -m. && + + git clone --bare . bare && + cp .git/info/attributes bare/info/attributes +' + +test_expect_success 'git archive' ' + git archive HEAD >archive.tar && + (mkdir archive && cd archive && "$TAR" xf -) <archive.tar +' + +test_expect_missing archive/ignored +test_expect_missing archive/not-ignored-dir/ignored +test_expect_exists archive/not-ignored-dir/ignored-only-if-dir +test_expect_exists archive/not-ignored-dir/ +test_expect_missing archive/ignored-only-if-dir/ +test_expect_missing archive/ignored-ony-if-dir/ignored-by-ignored-dir +test_expect_exists archive/one-level-lower/ +test_expect_missing archive/one-level-lower/two-levels-lower/ignored-only-if-dir/ +test_expect_missing archive/one-level-lower/two-levels-lower/ignored-ony-if-dir/ignored-by-ignored-dir + + +test_done diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index 81904d9ec..3e64a7a65 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -11,7 +11,7 @@ test_expect_success 'split sample box' \ 'git mailsplit -o. "$TEST_DIRECTORY"/t5100/sample.mbox >last && last=`cat last` && echo total is $last && - test `cat last` = 16' + test `cat last` = 17' check_mailinfo () { mail=$1 opt=$2 diff --git a/t/t5100/info0017 b/t/t5100/info0017 new file mode 100644 index 000000000..d2bc89ffe --- /dev/null +++ b/t/t5100/info0017 @@ -0,0 +1,5 @@ +Author: A U Thor +Email: a.u.thor@example.com +Subject: A E I O U +Date: Mon, 17 Sep 2012 14:23:44 -0700 + diff --git a/t/t5100/msg0017 b/t/t5100/msg0017 new file mode 100644 index 000000000..2ee090085 --- /dev/null +++ b/t/t5100/msg0017 @@ -0,0 +1,2 @@ +New content here + diff --git a/t/t5100/patch0017 b/t/t5100/patch0017 new file mode 100644 index 000000000..35cf84c9a --- /dev/null +++ b/t/t5100/patch0017 @@ -0,0 +1,6 @@ +diff --git a/foo b/foo +index e69de29..d95f3ad 100644 +--- a/foo ++++ b/foo +@@ -0,0 +1 @@ ++New content diff --git a/t/t5100/sample.mbox b/t/t5100/sample.mbox index 34a09a0fc..8b2ae064c 100644 --- a/t/t5100/sample.mbox +++ b/t/t5100/sample.mbox @@ -683,3 +683,19 @@ index e69de29..d95f3ad 100644 @@ -0,0 +1 @@ +content +From nobody Mon Sep 17 00:00:00 2001 +From: A U Thor <a.u.thor@example.com> +Subject: A E I O U +Date: Mon, 17 Sep 2012 14:23:44 -0700 +MIME-Version: 1.0 +Content-Type: text/plain; charset="iso-2022-jp" +Content-type: text/plain; charset="UTF-8" + +New content here + +diff --git a/foo b/foo +index e69de29..d95f3ad 100644 +--- a/foo ++++ b/foo +@@ -0,0 +1 @@ ++New content diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 4fd69a19e..a07c87179 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -416,6 +416,11 @@ test_expect_success \ test_expect_success \ 'make sure index-pack detects the SHA1 collision' \ 'test_must_fail git index-pack -o bad.idx test-3.pack 2>msg && - grep "SHA1 COLLISION FOUND" msg' + test_i18ngrep "SHA1 COLLISION FOUND" msg' + +test_expect_success \ + 'make sure index-pack detects the SHA1 collision (large blobs)' \ + 'test_must_fail git -c core.bigfilethreshold=1 index-pack -o bad.idx test-3.pack 2>msg && + test_i18ngrep "SHA1 COLLISION FOUND" msg' test_done diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh index 250c720c1..129fc88bd 100755 --- a/t/t5400-send-pack.sh +++ b/t/t5400-send-pack.sh @@ -159,7 +159,7 @@ test_expect_success 'receive-pack runs auto-gc in remote repo' ' git commit -a -m "Second commit" && git repack ) && - cp -a parent child && + cp -R parent child && ( # Set the child to auto-pack if more than one pack exists cd child && @@ -174,8 +174,7 @@ test_expect_success 'receive-pack runs auto-gc in remote repo' ' cd parent && echo "Even more text" >>file.txt && git commit -a -m "Third commit" && - git send-pack ../child HEAD:refs/heads/test_auto_gc >output 2>&1 && - grep "Auto packing the repository for optimum performance." output + git send-pack ../child HEAD:refs/heads/test_auto_gc ) && test ! -e child/.git/objects/tmp_test_object ' diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index e80a2af34..6322e8ade 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -391,10 +391,55 @@ test_expect_success 'fetch mixed refs from cmdline and stdin' ' test_expect_success 'test duplicate refs from stdin' ' ( cd client && - test_must_fail git fetch-pack --stdin --no-progress .. <../input.dup + git fetch-pack --stdin --no-progress .. <../input.dup ) >output && cut -d " " -f 2 <output | sort >actual && test_cmp expect actual ' +test_expect_success 'set up tests of missing reference' ' + cat >expect-error <<-\EOF + error: no such remote ref refs/heads/xyzzy + EOF +' + +test_expect_success 'test lonely missing ref' ' + ( + cd client && + test_must_fail git fetch-pack --no-progress .. refs/heads/xyzzy + ) >/dev/null 2>error-m && + test_cmp expect-error error-m +' + +test_expect_success 'test missing ref after existing' ' + ( + cd client && + test_must_fail git fetch-pack --no-progress .. refs/heads/A refs/heads/xyzzy + ) >/dev/null 2>error-em && + test_cmp expect-error error-em +' + +test_expect_success 'test missing ref before existing' ' + ( + cd client && + test_must_fail git fetch-pack --no-progress .. refs/heads/xyzzy refs/heads/A + ) >/dev/null 2>error-me && + test_cmp expect-error error-me +' + +test_expect_success 'test --all, --depth, and explicit head' ' + ( + cd client && + git fetch-pack --no-progress --all --depth=1 .. refs/heads/A + ) >out-adh 2>error-adh +' + +test_expect_success 'test --all, --depth, and explicit tag' ' + git tag OLDTAG refs/heads/B~5 && + ( + cd client && + git fetch-pack --no-progress --all --depth=1 .. refs/tags/OLDTAG + ) >out-adt 2>error-adt +' + test_done diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh index 35ec294d9..69ee13c8b 100755 --- a/t/t5504-fetch-receive-strict.sh +++ b/t/t5504-fetch-receive-strict.sh @@ -89,7 +89,7 @@ test_expect_success 'push with !receive.fsckobjects' ' cat >exp <<EOF To dst -! refs/heads/master:refs/heads/test [remote rejected] (n/a (unpacker error)) +! refs/heads/master:refs/heads/test [remote rejected] (unpacker error) EOF test_expect_success 'push with receive.fsckobjects' ' diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index e8af615e6..ccc55ebf4 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -52,7 +52,7 @@ test_expect_success setup ' ' -test_expect_success 'remote information for the origin' ' +test_expect_success C_LOCALE_OUTPUT 'remote information for the origin' ' ( cd test && tokens_match origin "$(git remote)" && @@ -66,8 +66,6 @@ test_expect_success 'add another remote' ' cd test && git remote add -f second ../two && tokens_match "origin second" "$(git remote)" && - check_remote_track origin master side && - check_remote_track second master side another && check_tracking_branch second master side another && git for-each-ref "--format=%(refname)" refs/remotes | sed -e "/^refs\/remotes\/origin\//d" \ @@ -77,6 +75,14 @@ test_expect_success 'add another remote' ' ) ' +test_expect_success C_LOCALE_OUTPUT 'check remote tracking' ' +( + cd test && + check_remote_track origin master side && + check_remote_track second master side another +) +' + test_expect_success 'remote forces tracking branches' ' ( cd test && @@ -95,7 +101,7 @@ test_expect_success 'remove remote' ' ) ' -test_expect_success 'remove remote' ' +test_expect_success C_LOCALE_OUTPUT 'remove remote' ' ( cd test && tokens_match origin "$(git remote)" && @@ -125,14 +131,14 @@ EOF } && git tag footag && git config --add remote.oops.fetch "+refs/*:refs/*" && - git remote rm oops 2>actual1 && + git remote remove oops 2>actual1 && git branch foobranch && git config --add remote.oops.fetch "+refs/*:refs/*" && git remote rm oops 2>actual2 && git branch -d foobranch && git tag -d footag && - test_cmp expect1 actual1 && - test_cmp expect2 actual2 + test_i18ncmp expect1 actual1 && + test_i18ncmp expect2 actual2 ) ' @@ -192,7 +198,7 @@ test_expect_success 'show' ' git config --add remote.two.push refs/heads/master:refs/heads/another && git remote show origin two > output && git branch -d rebase octopus && - test_cmp expect output) + test_i18ncmp expect output) ' cat > test/expect << EOF @@ -217,7 +223,7 @@ test_expect_success 'show -n' ' cd test && git remote show -n origin > output && mv ../one.unreachable ../one && - test_cmp expect output) + test_i18ncmp expect output) ' test_expect_success 'prune' ' @@ -255,7 +261,7 @@ EOF test_expect_success 'set-head --auto fails w/multiple HEADs' ' (cd test && test_must_fail git remote set-head --auto two >output 2>&1 && - test_cmp expect output) + test_i18ncmp expect output) ' cat >test/expect <<EOF @@ -285,7 +291,7 @@ test_expect_success 'prune --dry-run' ' test_must_fail git rev-parse refs/remotes/origin/side && (cd ../one && git branch -m side side2) && - test_cmp expect output) + test_i18ncmp expect output) ' test_expect_success 'add --mirror && prune' ' @@ -672,7 +678,7 @@ test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' ' git clone one five && origin_url=$(pwd)/one && (cd five && - git remote rm origin && + git remote remove origin && mkdir -p .git/remotes && cat ../remotes_origin > .git/remotes/origin && git remote rename origin origin && @@ -705,7 +711,7 @@ test_expect_success 'remote prune to cause a dangling symref' ' cd seven && git remote prune origin ) >err 2>&1 && - grep "has become dangling" err && + test_i18ngrep "has become dangling" err && : And the dangling symref will not cause other annoying errors && ( diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 6764d511c..d16e5d384 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -87,17 +87,15 @@ test_expect_success 'use branch.<name>.remote if possible' ' test_expect_success 'confuses pattern as remote when no remote specified' ' cat >exp <<-\EOF && fatal: '\''refs*master'\'' does not appear to be a git repository - fatal: The remote end hung up unexpectedly + fatal: Could not read from remote repository. + + Please make sure you have the correct access rights + and the repository exists. EOF # - # Do not expect "git ls-remote <pattern>" to work; ls-remote, correctly, - # confuses <pattern> for <remote>. Although ugly, this behaviour is akin - # to the confusion of refspecs for remotes by git-fetch and git-push, - # eg: - # - # $ git fetch branch - # - + # Do not expect "git ls-remote <pattern>" to work; ls-remote needs + # <remote> if you want to feed <pattern>, just like you cannot say + # fetch <branch>. # We could just as easily have used "master"; the "*" emphasizes its # role as a pattern. test_must_fail git ls-remote refs*master >actual 2>&1 && diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh index 227dd5613..0f8140957 100755 --- a/t/t5514-fetch-multiple.sh +++ b/t/t5514-fetch-multiple.sh @@ -151,4 +151,34 @@ test_expect_success 'git fetch --multiple (ignoring skipFetchAll)' ' test_cmp ../expect output) ' +test_expect_success 'git fetch --all --no-tags' ' + >expect && + git clone one test5 && + git clone test5 test6 && + (cd test5 && git tag test-tag) && + ( + cd test6 && + git fetch --all --no-tags && + git tag >output + ) && + test_cmp expect test6/output +' + +test_expect_success 'git fetch --all --tags' ' + echo test-tag >expect && + git clone one test7 && + git clone test7 test8 && + ( + cd test7 && + test_commit test-tag && + git reset --hard HEAD^ + ) && + ( + cd test8 && + git fetch --all --tags && + git tag >output + ) && + test_cmp expect test8/output +' + test_done diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh index 6b2a5f4a6..c983d3694 100755 --- a/t/t5530-upload-pack-error.sh +++ b/t/t5530-upload-pack-error.sh @@ -35,8 +35,8 @@ test_expect_success 'upload-pack fails due to error in pack-objects packing' ' printf "0032want %s\n00000009done\n0000" \ $(git rev-parse HEAD) >input && test_must_fail git upload-pack . <input >/dev/null 2>output.err && - grep "unable to read" output.err && - grep "pack-objects died" output.err + test_i18ngrep "unable to read" output.err && + test_i18ngrep "pack-objects died" output.err ' test_expect_success 'corrupt repo differently' ' diff --git a/t/t5535-fetch-push-symref.sh b/t/t5535-fetch-push-symref.sh new file mode 100755 index 000000000..8ed58d27f --- /dev/null +++ b/t/t5535-fetch-push-symref.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +test_description='avoiding conflicting update thru symref aliasing' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit one && + git clone . src && + git clone src dst1 && + git clone src dst2 && + test_commit two && + ( cd src && git pull ) +' + +test_expect_success 'push' ' + ( + cd src && + git push ../dst1 "refs/remotes/*:refs/remotes/*" + ) && + git ls-remote src "refs/remotes/*" >expect && + git ls-remote dst1 "refs/remotes/*" >actual && + test_cmp expect actual && + ( cd src && git symbolic-ref refs/remotes/origin/HEAD ) >expect && + ( cd dst1 && git symbolic-ref refs/remotes/origin/HEAD ) >actual && + test_cmp expect actual +' + +test_expect_success 'fetch' ' + ( + cd dst2 && + git fetch ../src "refs/remotes/*:refs/remotes/*" + ) && + git ls-remote src "refs/remotes/*" >expect && + git ls-remote dst2 "refs/remotes/*" >actual && + test_cmp expect actual && + ( cd src && git symbolic-ref refs/remotes/origin/HEAD ) >expect && + ( cd dst2 && git symbolic-ref refs/remotes/origin/HEAD ) >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh index f141f2d1d..01d0d95b4 100755 --- a/t/t5540-http-push.sh +++ b/t/t5540-http-push.sh @@ -109,7 +109,7 @@ test_expect_success 'http-push fetches packed objects' ' # By reset, we force git to retrieve the packed object (cd "$ROOT_PATH"/test_repo_clone_packed && git reset --hard HEAD^ && - git remote rm origin && + git remote remove origin && git reflog expire --expire=0 --all && git prune && git push -f -v $HTTPD_URL/dumb/test_repo_packed.git master) diff --git a/t/t5541-http-push.sh b/t/t5541-http-push.sh index ef6d6b6e4..4b4b4a604 100755 --- a/t/t5541-http-push.sh +++ b/t/t5541-http-push.sh @@ -66,7 +66,10 @@ test_expect_success 'no empty path components' ' test_expect_success 'clone remote repository' ' rm -rf test_repo_clone && - git clone $HTTPD_URL/smart/test_repo.git test_repo_clone + git clone $HTTPD_URL/smart/test_repo.git test_repo_clone && + ( + cd test_repo_clone && git config push.default matching + ) ' test_expect_success 'push to remote repository (standard)' ' diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh index 16ef0419e..80d20c876 100755 --- a/t/t5550-http-fetch.sh +++ b/t/t5550-http-fetch.sh @@ -22,7 +22,7 @@ test_expect_success 'setup repository' ' ' test_expect_success 'create http-accessible bare repository with loose objects' ' - cp -a .git "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && + cp -R .git "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && (cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && git config core.bare true && mkdir -p hooks && diff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch.sh index 2db5c3564..c5cd2e348 100755 --- a/t/t5551-http-fetch.sh +++ b/t/t5551-http-fetch.sh @@ -32,13 +32,14 @@ setup_askpass_helper cat >exp <<EOF > GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 > Accept: */* +> Accept-Encoding: gzip > Pragma: no-cache < HTTP/1.1 200 OK < Pragma: no-cache < Cache-Control: no-cache, max-age=0, must-revalidate < Content-Type: application/x-git-upload-pack-advertisement > POST /smart/repo.git/git-upload-pack HTTP/1.1 -> Accept-Encoding: deflate, gzip +> Accept-Encoding: gzip > Content-Type: application/x-git-upload-pack-request > Accept: application/x-git-upload-pack-result > Content-Length: xxx @@ -129,6 +130,33 @@ test_expect_success 'clone from auth-only-for-push repository' ' test_cmp expect actual ' +test_expect_success 'clone from auth-only-for-objects repository' ' + echo two >expect && + set_askpass user@host && + git clone --bare "$HTTPD_URL/auth-fetch/smart/repo.git" half-auth && + expect_askpass both user@host && + git --git-dir=half-auth log -1 --format=%s >actual && + test_cmp expect actual +' + +test_expect_success 'no-op half-auth fetch does not require a password' ' + set_askpass wrong && + git --git-dir=half-auth fetch && + expect_askpass none +' + +test_expect_success 'disable dumb http on server' ' + git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ + config http.getanyfile false +' + +test_expect_success 'GIT_SMART_HTTP can disable smart http' ' + (GIT_SMART_HTTP=0 && + export GIT_SMART_HTTP && + cd clone && + test_must_fail git fetch) +' + test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE test_expect_success EXPENSIVE 'create 50,000 tags in the repo' ' diff --git a/t/t5701-clone-local.sh b/t/t5701-clone-local.sh index c6feca44e..7ff6e0e16 100755 --- a/t/t5701-clone-local.sh +++ b/t/t5701-clone-local.sh @@ -124,4 +124,14 @@ test_expect_success 'cloning non-git directory fails' ' test_must_fail git clone not-a-git-repo not-a-git-repo-clone ' +test_expect_success 'cloning file:// does not hardlink' ' + git clone --bare file://"$(pwd)"/a non-local && + ! repo_is_hardlinked non-local +' + +test_expect_success 'cloning a local path with --no-local does not hardlink' ' + git clone --bare --no-local a force-nonlocal && + ! repo_is_hardlinked force-nonlocal +' + test_done diff --git a/t/t5709-clone-refspec.sh b/t/t5709-clone-refspec.sh new file mode 100755 index 000000000..6f1ea984d --- /dev/null +++ b/t/t5709-clone-refspec.sh @@ -0,0 +1,156 @@ +#!/bin/sh + +test_description='test refspec written by clone-command' +. ./test-lib.sh + +test_expect_success 'setup' ' + # Make two branches, "master" and "side" + echo one >file && + git add file && + git commit -m one && + echo two >file && + git commit -a -m two && + git tag two && + echo three >file && + git commit -a -m three && + git checkout -b side && + echo four >file && + git commit -a -m four && + git checkout master && + + # default clone + git clone . dir_all && + + # default --single that follows HEAD=master + git clone --single-branch . dir_master && + + # default --single that follows HEAD=side + git checkout side && + git clone --single-branch . dir_side && + + # explicit --single that follows side + git checkout master && + git clone --single-branch --branch side . dir_side2 && + + # default --single with --mirror + git clone --single-branch --mirror . dir_mirror && + + # default --single with --branch and --mirror + git clone --single-branch --mirror --branch side . dir_mirror_side && + + # --single that does not know what branch to follow + git checkout two^ && + git clone --single-branch . dir_detached && + + # explicit --single with tag + git clone --single-branch --branch two . dir_tag && + + # advance both "master" and "side" branches + git checkout side && + echo five >file && + git commit -a -m five && + git checkout master && + echo six >file && + git commit -a -m six && + + # update tag + git tag -d two && git tag two +' + +test_expect_success 'by default all branches will be kept updated' ' + ( + cd dir_all && git fetch && + git for-each-ref refs/remotes/origin | + sed -e "/HEAD$/d" \ + -e "s|/remotes/origin/|/heads/|" >../actual + ) && + # follow both master and side + git for-each-ref refs/heads >expect && + test_cmp expect actual +' + +test_expect_success 'by default no tags will be kept updated' ' + ( + cd dir_all && git fetch && + git for-each-ref refs/tags >../actual + ) && + git for-each-ref refs/tags >expect && + test_must_fail test_cmp expect actual +' + +test_expect_success '--single-branch while HEAD pointing at master' ' + ( + cd dir_master && git fetch && + git for-each-ref refs/remotes/origin | + sed -e "/HEAD$/d" \ + -e "s|/remotes/origin/|/heads/|" >../actual + ) && + # only follow master + git for-each-ref refs/heads/master >expect && + test_cmp expect actual +' + +test_expect_success '--single-branch while HEAD pointing at side' ' + ( + cd dir_side && git fetch && + git for-each-ref refs/remotes/origin | + sed -e "/HEAD$/d" \ + -e "s|/remotes/origin/|/heads/|" >../actual + ) && + # only follow side + git for-each-ref refs/heads/side >expect && + test_cmp expect actual +' + +test_expect_success '--single-branch with explicit --branch side' ' + ( + cd dir_side2 && git fetch && + git for-each-ref refs/remotes/origin | + sed -e "/HEAD$/d" \ + -e "s|/remotes/origin/|/heads/|" >../actual + ) && + # only follow side + git for-each-ref refs/heads/side >expect && + test_cmp expect actual +' + +test_expect_success '--single-branch with explicit --branch with tag fetches updated tag' ' + ( + cd dir_tag && git fetch && + git for-each-ref refs/tags >../actual + ) && + git for-each-ref refs/tags >expect && + test_cmp expect actual +' + +test_expect_success '--single-branch with --mirror' ' + ( + cd dir_mirror && git fetch && + git for-each-ref refs > ../actual + ) && + git for-each-ref refs >expect && + test_cmp expect actual +' + +test_expect_success '--single-branch with explicit --branch and --mirror' ' + ( + cd dir_mirror_side && git fetch && + git for-each-ref refs > ../actual + ) && + git for-each-ref refs >expect && + test_cmp expect actual +' + +test_expect_success '--single-branch with detached' ' + ( + cd dir_detached && git fetch && + git for-each-ref refs/remotes/origin | + sed -e "/HEAD$/d" \ + -e "s|/remotes/origin/|/heads/|" >../actual + ) + # nothing + >expect && + test_cmp expect actual +' + +test_done diff --git a/t/t5800-remote-helpers.sh b/t/t5800-remote-helpers.sh index 570233451..e7dc668ce 100755 --- a/t/t5800-remote-helpers.sh +++ b/t/t5800-remote-helpers.sh @@ -76,7 +76,7 @@ test_expect_success 'pushing to local repo' ' # git-remote-testgit, but is too slow to leave in for general use. : test_expect_success 'racily pushing to local repo' ' test_when_finished "rm -rf server2 localclone2" && - cp -a server server2 && + cp -R server server2 && git clone "testgit::${PWD}/server2" localclone2 && (cd localclone2 && echo content >>file && diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index 110424918..c680f789a 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -242,10 +242,10 @@ test_expect_success 'merge of identical changes in a renamed file' ' rm -f A M N && git reset --hard && git checkout change+rename && - GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" && + GIT_MERGE_VERBOSITY=3 git merge change | test_i18ngrep "^Skipped B" && git reset --hard HEAD^ && git checkout change && - GIT_MERGE_VERBOSITY=3 git merge change+rename | grep "^Skipped B" + GIT_MERGE_VERBOSITY=3 git merge change+rename | test_i18ngrep "^Skipped B" ' test_expect_success 'setup for rename + d/f conflicts' ' @@ -303,9 +303,9 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' ' git checkout -q renamed-file-has-no-conflicts^0 && test_must_fail git merge --strategy=recursive dir-in-way >output && - grep "CONFLICT (modify/delete): dir/file-in-the-way" output && - grep "Auto-merging dir" output && - grep "Adding as dir~HEAD instead" output && + test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output && + test_i18ngrep "Auto-merging dir" output && + test_i18ngrep "Adding as dir~HEAD instead" output && test 3 -eq "$(git ls-files -u | wc -l)" && test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" && @@ -325,9 +325,9 @@ test_expect_success 'Same as previous, but merged other way' ' test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors && ! grep "error: refusing to lose untracked file at" errors && - grep "CONFLICT (modify/delete): dir/file-in-the-way" output && - grep "Auto-merging dir" output && - grep "Adding as dir~renamed-file-has-no-conflicts instead" output && + test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output && + test_i18ngrep "Auto-merging dir" output && + test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output && test 3 -eq "$(git ls-files -u | wc -l)" && test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" && diff --git a/t/t6037-merge-ours-theirs.sh b/t/t6037-merge-ours-theirs.sh index 2cf42c73f..3889eca4a 100755 --- a/t/t6037-merge-ours-theirs.sh +++ b/t/t6037-merge-ours-theirs.sh @@ -53,7 +53,19 @@ test_expect_success 'recursive favouring ours' ' ! grep 1 file ' -test_expect_success 'pull with -X' ' +test_expect_success 'binary file with -Xours/-Xtheirs' ' + echo file binary >.gitattributes && + + git reset --hard master && + git merge -s recursive -X theirs side && + git diff --exit-code side HEAD -- file && + + git reset --hard master && + git merge -s recursive -X ours side && + git diff --exit-code master HEAD -- file +' + +test_expect_success 'pull passes -X to underlying merge' ' git reset --hard master && git pull -s recursive -Xours . side && git reset --hard master && git pull -s recursive -X ours . side && git reset --hard master && git pull -s recursive -Xtheirs . side && diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh index 466fa3804..411550d2b 100755 --- a/t/t6042-merge-rename-corner-cases.sh +++ b/t/t6042-merge-rename-corner-cases.sh @@ -380,7 +380,7 @@ test_expect_success 'handle rename/rename (2to1) conflict correctly' ' git checkout B^0 && test_must_fail git merge -s recursive C^0 >out && - grep "CONFLICT (rename/rename)" out && + test_i18ngrep "CONFLICT (rename/rename)" out && test 2 -eq $(git ls-files -s | wc -l) && test 2 -eq $(git ls-files -u | wc -l) && diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh index 5c87f28e4..decdc33c5 100755 --- a/t/t6050-replace.sh +++ b/t/t6050-replace.sh @@ -140,6 +140,17 @@ test_expect_success '"git replace" replacing' ' test "$HASH2" = "$(git replace)" ' +test_expect_success '"git replace" resolves sha1' ' + SHORTHASH2=$(git rev-parse --short=8 $HASH2) && + git replace -d $SHORTHASH2 && + git replace $SHORTHASH2 $R && + git show $HASH2 | grep "O Thor" && + test_must_fail git replace $HASH2 $R && + git replace -f $HASH2 $R && + test_must_fail git replace -f && + test "$HASH2" = "$(git replace)" +' + # This creates a side branch where the bug in H2 # does not appear because P2 is created by applying # H2 and squashing H5 into it. diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index 82f363993..b1a63655f 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -11,7 +11,7 @@ test_expect_success 'gc empty repository' ' test_expect_success 'gc --gobbledegook' ' test_expect_code 129 git gc --nonsense 2>err && - grep "[Uu]sage: git gc" err + test_i18ngrep "[Uu]sage: git gc" err ' test_expect_success 'gc -h with invalid configuration' ' @@ -22,7 +22,7 @@ test_expect_success 'gc -h with invalid configuration' ' echo "[gc] pruneexpire = CORRUPT" >>.git/config && test_expect_code 129 git gc -h >usage 2>&1 ) && - grep "[Uu]sage" broken/usage + test_i18ngrep "[Uu]sage" broken/usage ' test_done diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index 4d13e10de..1e7a209ef 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -167,10 +167,11 @@ test_expect_success 'author information is preserved' ' test_tick && GIT_AUTHOR_NAME="B V Uips" git commit -m bvuips && git branch preserved-author && - git filter-branch -f --msg-filter "cat; \ + (sane_unset GIT_AUTHOR_NAME && + git filter-branch -f --msg-filter "cat; \ test \$GIT_COMMIT != $(git rev-parse master) || \ echo Hallo" \ - preserved-author && + preserved-author) && test 1 = $(git rev-list --author="B V Uips" preserved-author | wc -l) ' diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 518944653..f5a79b13a 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1066,12 +1066,12 @@ test_expect_success GPG \ ' # usage with rfc1991 signatures -echo "rfc1991" > gpghome/gpg.conf get_tag_header rfc1991-signed-tag $commit commit $time >expect echo "RFC1991 signed tag" >>expect echo '-----BEGIN PGP MESSAGE-----' >>expect test_expect_success GPG \ 'creating a signed tag with rfc1991' ' + echo "rfc1991" >gpghome/gpg.conf && git tag -s -m "RFC1991 signed tag" rfc1991-signed-tag $commit && get_tag_msg rfc1991-signed-tag >actual && test_cmp expect actual @@ -1085,6 +1085,7 @@ chmod +x fakeeditor test_expect_success GPG \ 'reediting a signed tag body omits signature' ' + echo "rfc1991" >gpghome/gpg.conf && echo "RFC1991 signed tag" >expect && GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit && test_cmp expect actual @@ -1092,11 +1093,13 @@ test_expect_success GPG \ test_expect_success GPG \ 'verifying rfc1991 signature' ' + echo "rfc1991" >gpghome/gpg.conf && git tag -v rfc1991-signed-tag ' test_expect_success GPG \ 'list tag with rfc1991 signature' ' + echo "rfc1991" >gpghome/gpg.conf && echo "rfc1991-signed-tag RFC1991 signed tag" >expect && git tag -l -n1 rfc1991-signed-tag >actual && test_cmp expect actual && diff --git a/t/t7008-grep-binary.sh b/t/t7008-grep-binary.sh index fd6410fc7..26f831984 100755 --- a/t/t7008-grep-binary.sh +++ b/t/t7008-grep-binary.sh @@ -111,6 +111,28 @@ test_expect_success 'grep respects binary diff attribute' ' test_cmp expect actual ' +test_expect_success 'grep --cached respects binary diff attribute' ' + git grep --cached text t >actual && + test_cmp expect actual +' + +test_expect_success 'grep --cached respects binary diff attribute (2)' ' + git add .gitattributes && + rm .gitattributes && + git grep --cached text t >actual && + test_when_finished "git rm --cached .gitattributes" && + test_when_finished "git checkout .gitattributes" && + test_cmp expect actual +' + +test_expect_success 'grep revision respects binary diff attribute' ' + git commit -m new && + echo "Binary file HEAD:t matches" >expect && + git grep text HEAD -- t >actual && + test_when_finished "git reset HEAD^" && + test_cmp expect actual +' + test_expect_success 'grep respects not-binary diff attribute' ' echo binQary | q_to_nul >b && git add b && diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh index b8cb4906a..f4f38a5e7 100755 --- a/t/t7060-wtstatus.sh +++ b/t/t7060-wtstatus.sh @@ -30,6 +30,9 @@ test_expect_success 'Report new path with conflict' ' cat >expect <<EOF # On branch side +# You have unmerged paths. +# (fix conflicts and run "git commit") +# # Unmerged paths: # (use "git add/rm <file>..." as appropriate to mark resolution) # @@ -118,4 +121,97 @@ test_expect_success 'git diff-index --cached -C shows 2 copies + 1 unmerged' ' test_cmp expected actual ' + +test_expect_success 'status when conflicts with add and rm advice (deleted by them)' ' + git reset --hard && + git checkout master && + test_commit init main.txt init && + git checkout -b second_branch && + git rm main.txt && + git commit -m "main.txt deleted on second_branch" && + test_commit second conflict.txt second && + git checkout master && + test_commit on_second main.txt on_second && + test_commit master conflict.txt master && + test_must_fail git merge second_branch && + cat >expected <<-\EOF && + # On branch master + # You have unmerged paths. + # (fix conflicts and run "git commit") + # + # Unmerged paths: + # (use "git add/rm <file>..." as appropriate to mark resolution) + # + # both added: conflict.txt + # deleted by them: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for conflicts' ' + git reset --hard && + git checkout -b conflict && + test_commit one main.txt one && + git branch conflict_second && + git mv main.txt sub_master.txt && + git commit -m "main.txt renamed in sub_master.txt" && + git checkout conflict_second && + git mv main.txt sub_second.txt && + git commit -m "main.txt renamed in sub_second.txt" +' + + +test_expect_success 'status when conflicts with add and rm advice (both deleted)' ' + test_must_fail git merge conflict && + cat >expected <<-\EOF && + # On branch conflict_second + # You have unmerged paths. + # (fix conflicts and run "git commit") + # + # Unmerged paths: + # (use "git add/rm <file>..." as appropriate to mark resolution) + # + # both deleted: main.txt + # added by them: sub_master.txt + # added by us: sub_second.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when conflicts with only rm advice (both deleted)' ' + git reset --hard conflict_second && + test_must_fail git merge conflict && + git add sub_master.txt && + git add sub_second.txt && + cat >expected <<-\EOF && + # On branch conflict_second + # You have unmerged paths. + # (fix conflicts and run "git commit") + # + # Changes to be committed: + # + # new file: sub_master.txt + # + # Unmerged paths: + # (use "git rm <file>..." to mark resolution) + # + # both deleted: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual && + git reset --hard && + git checkout master +' + + test_done diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 0278f4839..de7d45352 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -438,8 +438,8 @@ test_expect_success 'moving to a commit without submodule does not leave empty d git checkout second ' -test_expect_success 'submodule <invalid-path> warns' ' - test_failure_with_unknown_submodule +test_expect_success 'submodule <invalid-subcommand> fails' ' + test_must_fail git submodule no-such-subcommand ' test_expect_success 'add submodules without specifying an explicit path' ' @@ -501,21 +501,72 @@ test_expect_success 'set up for relative path tests' ' git add sub && git config -f .gitmodules submodule.sub.path sub && git config -f .gitmodules submodule.sub.url ../subrepo && - cp .git/config pristine-.git-config + cp .git/config pristine-.git-config && + cp .gitmodules pristine-.gitmodules ) ' -test_expect_success 'relative path works with URL' ' +test_expect_success '../subrepo works with URL - ssh://hostname/repo' ' ( cd reltest && cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && git config remote.origin.url ssh://hostname/repo && git submodule init && test "$(git config submodule.sub.url)" = ssh://hostname/subrepo ) ' -test_expect_success 'relative path works with user@host:path' ' +test_expect_success '../subrepo works with port-qualified URL - ssh://hostname:22/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ssh://hostname:22/repo && + git submodule init && + test "$(git config submodule.sub.url)" = ssh://hostname:22/subrepo + ) +' + +# About the choice of the path in the next test: +# - double-slash side-steps path mangling issues on Windows +# - it is still an absolute local path +# - there cannot be a server with a blank in its name just in case the +# path is used erroneously to access a //server/share style path +test_expect_success '../subrepo path works with local path - //somewhere else/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url "//somewhere else/repo" && + git submodule init && + test "$(git config submodule.sub.url)" = "//somewhere else/subrepo" + ) +' + +test_expect_success '../subrepo works with file URL - file:///tmp/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url file:///tmp/repo && + git submodule init && + test "$(git config submodule.sub.url)" = file:///tmp/subrepo + ) +' + +test_expect_success '../subrepo works with helper URL- helper:://hostname/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url helper:://hostname/repo && + git submodule init && + test "$(git config submodule.sub.url)" = helper:://hostname/subrepo + ) +' + +test_expect_success '../subrepo works with scp-style URL - user@host:repo' ' ( cd reltest && cp pristine-.git-config .git/config && @@ -525,6 +576,98 @@ test_expect_success 'relative path works with user@host:path' ' ) ' +test_expect_success '../subrepo works with scp-style URL - user@host:path/to/repo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url user@host:path/to/repo && + git submodule init && + test "$(git config submodule.sub.url)" = user@host:path/to/subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - foo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url foo && + # actual: fails with an error + git submodule init && + test "$(git config submodule.sub.url)" = subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - foo/bar' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url foo/bar && + git submodule init && + test "$(git config submodule.sub.url)" = foo/subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - ./foo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ./foo && + git submodule init && + test "$(git config submodule.sub.url)" = subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - ./foo/bar' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ./foo/bar && + git submodule init && + test "$(git config submodule.sub.url)" = foo/subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - ../foo' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ../foo && + git submodule init && + test "$(git config submodule.sub.url)" = ../subrepo + ) +' + +test_expect_success '../subrepo works with relative local path - ../foo/bar' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + git config remote.origin.url ../foo/bar && + git submodule init && + test "$(git config submodule.sub.url)" = ../foo/subrepo + ) +' + +test_expect_success '../bar/a/b/c works with relative local path - ../foo/bar.git' ' + ( + cd reltest && + cp pristine-.git-config .git/config && + cp pristine-.gitmodules .gitmodules && + mkdir -p a/b/c && + (cd a/b/c; git init) && + git config remote.origin.url ../foo/bar.git && + git submodule add ../bar/a/b/c ./a/b/c && + git submodule init && + test "$(git config submodule.a/b/c.url)" = ../foo/bar/a/b/c + ) +' + test_expect_success 'moving the superproject does not break submodules' ' ( cd addtest && @@ -538,4 +681,79 @@ test_expect_success 'moving the superproject does not break submodules' ' ) ' +test_expect_success 'submodule add --name allows to replace a submodule with another at the same path' ' + ( + cd addtest2 && + ( + cd repo && + echo "$submodurl/repo" >expect && + git config remote.origin.url >actual && + test_cmp expect actual && + echo "gitdir: ../.git/modules/repo" >expect && + test_cmp expect .git + ) && + rm -rf repo && + git rm repo && + git submodule add -q --name repo_new "$submodurl/bare.git" repo >actual && + test ! -s actual && + echo "gitdir: ../.git/modules/submod" >expect && + test_cmp expect submod/.git && + ( + cd repo && + echo "$submodurl/bare.git" >expect && + git config remote.origin.url >actual && + test_cmp expect actual && + echo "gitdir: ../.git/modules/repo_new" >expect && + test_cmp expect .git + ) && + echo "repo" >expect && + git config -f .gitmodules submodule.repo.path >actual && + test_cmp expect actual && + git config -f .gitmodules submodule.repo_new.path >actual && + test_cmp expect actual&& + echo "$submodurl/repo" >expect && + git config -f .gitmodules submodule.repo.url >actual && + test_cmp expect actual && + echo "$submodurl/bare.git" >expect && + git config -f .gitmodules submodule.repo_new.url >actual && + test_cmp expect actual && + echo "$submodurl/repo" >expect && + git config submodule.repo.url >actual && + test_cmp expect actual && + echo "$submodurl/bare.git" >expect && + git config submodule.repo_new.url >actual && + test_cmp expect actual + ) +' + +test_expect_success 'submodule add with an existing name fails unless forced' ' + ( + cd addtest2 && + rm -rf repo && + git rm repo && + test_must_fail git submodule add -q --name repo_new "$submodurl/repo.git" repo && + test ! -d repo && + echo "repo" >expect && + git config -f .gitmodules submodule.repo_new.path >actual && + test_cmp expect actual&& + echo "$submodurl/bare.git" >expect && + git config -f .gitmodules submodule.repo_new.url >actual && + test_cmp expect actual && + echo "$submodurl/bare.git" >expect && + git config submodule.repo_new.url >actual && + test_cmp expect actual && + git submodule add -f -q --name repo_new "$submodurl/repo.git" repo && + test -d repo && + echo "repo" >expect && + git config -f .gitmodules submodule.repo_new.path >actual && + test_cmp expect actual&& + echo "$submodurl/repo.git" >expect && + git config -f .gitmodules submodule.repo_new.url >actual && + test_cmp expect actual && + echo "$submodurl/repo.git" >expect && + git config submodule.repo_new.url >actual && + test_cmp expect actual + ) +' + test_done diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh index 3620215c1..94e26c47e 100755 --- a/t/t7403-submodule-sync.sh +++ b/t/t7403-submodule-sync.sh @@ -17,16 +17,25 @@ test_expect_success setup ' git commit -m upstream && git clone . super && git clone super submodule && + (cd submodule && + git submodule add ../submodule sub-submodule && + test_tick && + git commit -m "sub-submodule" + ) && (cd super && git submodule add ../submodule submodule && test_tick && git commit -m "submodule" ) && git clone super super-clone && - (cd super-clone && git submodule update --init) && + (cd super-clone && git submodule update --init --recursive) && git clone super empty-clone && (cd empty-clone && git submodule init) && - git clone super top-only-clone + git clone super top-only-clone && + git clone super relative-clone && + (cd relative-clone && git submodule update --init --recursive) && + git clone super recursive-clone && + (cd recursive-clone && git submodule update --init --recursive) ' test_expect_success 'change submodule' ' @@ -44,6 +53,11 @@ test_expect_success 'change submodule url' ' git pull ) && mv submodule moved-submodule && + (cd moved-submodule && + git config -f .gitmodules submodule.sub-submodule.url ../moved-submodule && + test_tick && + git commit -a -m moved-sub-submodule + ) && (cd super && git config -f .gitmodules submodule.submodule.url ../moved-submodule && test_tick && @@ -59,6 +73,9 @@ test_expect_success '"git submodule sync" should update submodule URLs' ' test -d "$(cd super-clone/submodule && git config remote.origin.url )" && + test ! -d "$(cd super-clone/submodule/sub-submodule && + git config remote.origin.url + )" && (cd super-clone/submodule && git checkout master && git pull @@ -68,6 +85,25 @@ test_expect_success '"git submodule sync" should update submodule URLs' ' ) ' +test_expect_success '"git submodule sync --recursive" should update all submodule URLs' ' + (cd super-clone && + (cd submodule && + git pull --no-recurse-submodules + ) && + git submodule sync --recursive + ) && + test -d "$(cd super-clone/submodule && + git config remote.origin.url + )" && + test -d "$(cd super-clone/submodule/sub-submodule && + git config remote.origin.url + )" && + (cd super-clone/submodule/sub-submodule && + git checkout master && + git pull + ) +' + test_expect_success '"git submodule sync" should update known submodule URLs' ' (cd empty-clone && git pull && @@ -86,4 +122,107 @@ test_expect_success '"git submodule sync" should not vivify uninteresting submod ) ' +test_expect_success '"git submodule sync" handles origin URL of the form foo' ' + (cd relative-clone && + git remote set-url origin foo && + git submodule sync && + (cd submodule && + #actual fails with: "cannot strip off url foo + test "$(git config remote.origin.url)" = "../submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form foo/bar' ' + (cd relative-clone && + git remote set-url origin foo/bar && + git submodule sync && + (cd submodule && + #actual foo/submodule + test "$(git config remote.origin.url)" = "../foo/submodule" + ) + (cd submodule/sub-submodule && + test "$(git config remote.origin.url)" != "../../foo/submodule" + ) + ) +' + +test_expect_success '"git submodule sync --recursive" propagates changes in origin' ' + (cd recursive-clone && + git remote set-url origin foo/bar && + git submodule sync --recursive && + (cd submodule && + #actual foo/submodule + test "$(git config remote.origin.url)" = "../foo/submodule" + ) + (cd submodule/sub-submodule && + test "$(git config remote.origin.url)" = "../../foo/submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ./foo' ' + (cd relative-clone && + git remote set-url origin ./foo && + git submodule sync && + (cd submodule && + #actual ./submodule + test "$(git config remote.origin.url)" = "../submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ./foo/bar' ' + (cd relative-clone && + git remote set-url origin ./foo/bar && + git submodule sync && + (cd submodule && + #actual ./foo/submodule + test "$(git config remote.origin.url)" = "../foo/submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ../foo' ' + (cd relative-clone && + git remote set-url origin ../foo && + git submodule sync && + (cd submodule && + #actual ../submodule + test "$(git config remote.origin.url)" = "../../submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ../foo/bar' ' + (cd relative-clone && + git remote set-url origin ../foo/bar && + git submodule sync && + (cd submodule && + #actual ../foo/submodule + test "$(git config remote.origin.url)" = "../../foo/submodule" + ) + ) +' + +test_expect_success '"git submodule sync" handles origin URL of the form ../foo/bar with deeply nested submodule' ' + (cd relative-clone && + git remote set-url origin ../foo/bar && + mkdir -p a/b/c && + ( cd a/b/c && + git init && + :> .gitignore && + git add .gitignore && + test_tick && + git commit -m "initial commit" ) && + git submodule add ../bar/a/b/c ./a/b/c && + git submodule sync && + (cd a/b/c && + #actual ../foo/bar/a/b/c + test "$(git config remote.origin.url)" = "../../../../foo/bar/a/b/c" + ) + ) +' + + test_done diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index 15426530e..feaec6cdf 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -627,7 +627,7 @@ test_expect_success 'submodule add properly re-creates deeper level submodules' (cd super && git reset --hard master && rm -rf deeper/ && - git submodule add ../submodule deeper/submodule + git submodule add --force ../submodule deeper/submodule ) ' diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh index 9b69fe2e1..107b4b7c4 100755 --- a/t/t7407-submodule-foreach.sh +++ b/t/t7407-submodule-foreach.sh @@ -226,14 +226,14 @@ test_expect_success 'test "status --recursive"' ' test_cmp expect actual ' -sed -e "/nested1 /s/.*/+$nested1sha1 nested1 (file2~1)/;/sub[1-3]/d" < expect > expect2 +sed -e "/nested2 /s/.*/+$nested2sha1 nested1\/nested2 (file2~1)/;/sub[1-3]/d" < expect > expect2 mv -f expect2 expect test_expect_success 'ensure "status --cached --recursive" preserves the --cached flag' ' ( cd clone3 && ( - cd nested1 && + cd nested1/nested2 && test_commit file2 ) && git submodule status --cached --recursive -- nested1 > ../actual diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-worktree.sh new file mode 100755 index 000000000..2fec13dcd --- /dev/null +++ b/t/t7409-submodule-detached-worktree.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# +# Copyright (c) 2012 Daniel Graña +# + +test_description='Test submodules on detached working tree + +This test verifies that "git submodule" initialization, update and addition works +on detahced working trees +' + +TEST_NO_CREATE_REPO=1 +. ./test-lib.sh + +test_expect_success 'submodule on detached working tree' ' + git init --bare remote && + test_create_repo bundle1 && + ( + cd bundle1 && + test_commit "shoot" && + git rev-parse --verify HEAD >../expect + ) && + mkdir home && + ( + cd home && + export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" && + git clone --bare ../remote .dotfiles && + git submodule add ../bundle1 .vim/bundle/sogood && + test_commit "sogood" && + ( + unset GIT_WORK_TREE GIT_DIR && + cd .vim/bundle/sogood && + git rev-parse --verify HEAD >actual && + test_cmp ../../../../expect actual + ) && + git push origin master + ) && + mkdir home2 && + ( + cd home2 && + git clone --bare ../remote .dotfiles && + export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" && + git checkout master && + git submodule update --init && + ( + unset GIT_WORK_TREE GIT_DIR && + cd .vim/bundle/sogood && + git rev-parse --verify HEAD >actual && + test_cmp ../../../../expect actual + ) + ) +' + +test_expect_success 'submodule on detached working pointed by core.worktree' ' + mkdir home3 && + ( + cd home3 && + export GIT_DIR="$(pwd)/.dotfiles" && + git clone --bare ../remote "$GIT_DIR" && + git config core.bare false && + git config core.worktree .. && + git checkout master && + git submodule add ../bundle1 .vim/bundle/dupe && + test_commit "dupe" && + git push origin master + ) && + ( + cd home && + export GIT_DIR="$(pwd)/.dotfiles" && + git config core.bare false && + git config core.worktree .. && + git pull && + git submodule update --init && + test -f .vim/bundle/dupe/shoot.t + ) +' + +test_done diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index 181456aa9..1a5cb6983 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -235,44 +235,46 @@ test_expect_success 'cleanup commit messages (strip,-F,-e): output' ' test_i18ncmp expect actual ' -echo "# -# Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> -#" >> expect - -test_expect_success 'author different from committer' ' +test_expect_success 'message shows author when it is not equal to committer' ' echo >>negative && - test_might_fail git commit -e -m "sample" && - head -n 7 .git/COMMIT_EDITMSG >actual && - test_i18ncmp expect actual + git commit -e -m "sample" -a && + test_i18ngrep \ + "^# Author: *A U Thor <author@example.com>\$" \ + .git/COMMIT_EDITMSG ' -mv expect expect.tmp -sed '$d' < expect.tmp > expect -rm -f expect.tmp -echo "# Committer: -#" >> expect - -test_expect_success 'committer is automatic' ' +test_expect_success AUTOIDENT 'message shows committer when it is automatic' ' echo >>negative && ( sane_unset GIT_COMMITTER_EMAIL && sane_unset GIT_COMMITTER_NAME && - # must fail because there is no change - test_must_fail git commit -e -m "sample" + git commit -e -m "sample" -a ) && - head -n 8 .git/COMMIT_EDITMSG | \ - sed "s/^# Committer: .*/# Committer:/" >actual - test_i18ncmp expect actual + # the ident is calculated from the system, so we cannot + # check the actual value, only that it is there + test_i18ngrep "^# Committer: " .git/COMMIT_EDITMSG ' -pwd=`pwd` -cat >> .git/FAKE_EDITOR << EOF -#! /bin/sh -echo editor started > "$pwd/.git/result" +write_script .git/FAKE_EDITOR <<EOF +echo editor started > "$(pwd)/.git/result" exit 0 EOF -chmod +x .git/FAKE_EDITOR + +test_expect_success !AUTOIDENT 'do not fire editor when committer is bogus' ' + >.git/result + >expect && + + echo >>negative && + ( + sane_unset GIT_COMMITTER_EMAIL && + sane_unset GIT_COMMITTER_NAME && + GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" && + export GIT_EDITOR && + test_must_fail git commit -e -m sample -a + ) && + test_cmp expect .git/result +' test_expect_success 'do not fire editor in the presence of conflicts' ' @@ -293,16 +295,14 @@ test_expect_success 'do not fire editor in the presence of conflicts' ' test_must_fail git cherry-pick -n master && echo "editor not started" >.git/result && ( - GIT_EDITOR="$(pwd)/.git/FAKE_EDITOR" && + GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" && export GIT_EDITOR && test_must_fail git commit ) && test "$(cat .git/result)" = "editor not started" ' -pwd=`pwd` -cat >.git/FAKE_EDITOR <<EOF -#! $SHELL_PATH +write_script .git/FAKE_EDITOR <<EOF # kill -TERM command added below. EOF @@ -339,13 +339,12 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo ' -cat >.git/FAKE_EDITOR <<EOF -#!$SHELL_PATH -mv "\$1" "\$1.orig" +write_script .git/FAKE_EDITOR <<\EOF +mv "$1" "$1.orig" ( echo message - cat "\$1.orig" -) >"\$1" + cat "$1.orig" +) >"$1" EOF echo '## Custom template' >template diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh index 5b4b694f1..357375151 100755 --- a/t/t7505-prepare-commit-msg-hook.sh +++ b/t/t7505-prepare-commit-msg-hook.sh @@ -167,5 +167,19 @@ test_expect_success 'with failing hook (--no-verify)' ' ' +test_expect_success 'with failing hook (merge)' ' + + git checkout -B other HEAD@{1} && + echo "more" >> file && + git add file && + rm -f "$HOOK" && + git commit -m other && + write_script "$HOOK" <<-EOF + exit 1 + EOF + git checkout - && + test_must_fail git merge other + +' test_done diff --git a/t/t7508-status.sh b/t/t7508-status.sh index c206f4777..e313ef196 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -80,7 +80,7 @@ test_expect_success 'status --column' ' # dir1/untracked dir2/untracked untracked # dir2/modified output EOF - test_cmp expect output + test_i18ncmp expect output ' cat >expect <<\EOF diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh new file mode 100755 index 000000000..b3f6eb9c6 --- /dev/null +++ b/t/t7512-status-help.sh @@ -0,0 +1,649 @@ +#!/bin/sh +# +# Copyright (c) 2012 Valentin Duperray, Lucien Kong, Franck Jonas, +# Thomas Nguy, Khoi Nguyen +# Grenoble INP Ensimag +# + +test_description='git status advices' + +. ./test-lib.sh + +. "$TEST_DIRECTORY"/lib-rebase.sh + +set_fake_editor + +test_expect_success 'prepare for conflicts' ' + test_commit init main.txt init && + git branch conflicts && + test_commit on_master main.txt on_master && + git checkout conflicts && + test_commit on_conflicts main.txt on_conflicts +' + + +test_expect_success 'status when conflicts unresolved' ' + test_must_fail git merge master && + cat >expected <<-\EOF && + # On branch conflicts + # You have unmerged paths. + # (fix conflicts and run "git commit") + # + # Unmerged paths: + # (use "git add <file>..." to mark resolution) + # + # both modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when conflicts resolved before commit' ' + git reset --hard conflicts && + test_must_fail git merge master && + echo one >main.txt && + git add main.txt && + cat >expected <<-\EOF && + # On branch conflicts + # All conflicts fixed but you are still merging. + # (use "git commit" to conclude merge) + # + # Changes to be committed: + # + # modified: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for rebase conflicts' ' + git reset --hard master && + git checkout -b rebase_conflicts && + test_commit one_rebase main.txt one && + test_commit two_rebase main.txt two && + test_commit three_rebase main.txt three +' + + +test_expect_success 'status when rebase in progress before resolving conflicts' ' + test_when_finished "git rebase --abort" && + test_must_fail git rebase HEAD^ --onto HEAD^^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # (fix conflicts and then run "git rebase --continue") + # (use "git rebase --skip" to skip this patch) + # (use "git rebase --abort" to check out the original branch) + # + # Unmerged paths: + # (use "git reset HEAD <file>..." to unstage) + # (use "git add <file>..." to mark resolution) + # + # both modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when rebase in progress before rebase --continue' ' + git reset --hard rebase_conflicts && + test_when_finished "git rebase --abort" && + test_must_fail git rebase HEAD^ --onto HEAD^^ && + echo three >main.txt && + git add main.txt && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # (all conflicts fixed: run "git rebase --continue") + # + # Changes to be committed: + # (use "git reset HEAD <file>..." to unstage) + # + # modified: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for rebase_i_conflicts' ' + git reset --hard master && + git checkout -b rebase_i_conflicts && + test_commit one_unmerge main.txt one_unmerge && + git branch rebase_i_conflicts_second && + test_commit one_master main.txt one_master && + git checkout rebase_i_conflicts_second && + test_commit one_second main.txt one_second +' + + +test_expect_success 'status during rebase -i when conflicts unresolved' ' + test_when_finished "git rebase --abort" && + test_must_fail git rebase -i rebase_i_conflicts && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # (fix conflicts and then run "git rebase --continue") + # (use "git rebase --skip" to skip this patch) + # (use "git rebase --abort" to check out the original branch) + # + # Unmerged paths: + # (use "git reset HEAD <file>..." to unstage) + # (use "git add <file>..." to mark resolution) + # + # both modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status during rebase -i after resolving conflicts' ' + git reset --hard rebase_i_conflicts_second && + test_when_finished "git rebase --abort" && + test_must_fail git rebase -i rebase_i_conflicts && + git add main.txt && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # (all conflicts fixed: run "git rebase --continue") + # + # Changes to be committed: + # (use "git reset HEAD <file>..." to unstage) + # + # modified: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when rebasing -i in edit mode' ' + git reset --hard master && + git checkout -b rebase_i_edit && + test_commit one_rebase_i main.txt one && + test_commit two_rebase_i main.txt two && + test_commit three_rebase_i main.txt three && + FAKE_LINES="1 edit 2" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~2 && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when splitting a commit' ' + git reset --hard master && + git checkout -b split_commit && + test_commit one_split main.txt one && + test_commit two_split main.txt two && + test_commit three_split main.txt three && + test_commit four_split main.txt four && + FAKE_LINES="1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git reset HEAD^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently splitting a commit during a rebase. + # (Once your working directory is clean, run "git rebase --continue") + # + # Changes not staged for commit: + # (use "git add <file>..." to update what will be committed) + # (use "git checkout -- <file>..." to discard changes in working directory) + # + # modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status after editing the last commit with --amend during a rebase -i' ' + git reset --hard master && + git checkout -b amend_last && + test_commit one_amend main.txt one && + test_commit two_amend main.txt two && + test_commit three_amend main.txt three && + test_commit four_amend main.txt four && + FAKE_LINES="1 2 edit 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git commit --amend -m "foo" && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for several edits' ' + git reset --hard master && + git checkout -b several_edits && + test_commit one_edits main.txt one && + test_commit two_edits main.txt two && + test_commit three_edits main.txt three && + test_commit four_edits main.txt four +' + + +test_expect_success 'status: (continue first edit) second edit' ' + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git rebase --continue && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (continue first edit) second edit and split' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git rebase --continue && + git reset HEAD^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently splitting a commit during a rebase. + # (Once your working directory is clean, run "git rebase --continue") + # + # Changes not staged for commit: + # (use "git add <file>..." to update what will be committed) + # (use "git checkout -- <file>..." to discard changes in working directory) + # + # modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (continue first edit) second edit and amend' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git rebase --continue && + git commit --amend -m "foo" && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (amend first edit) second edit' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git commit --amend -m "a" && + git rebase --continue && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (amend first edit) second edit and split' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git commit --amend -m "b" && + git rebase --continue && + git reset HEAD^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently splitting a commit during a rebase. + # (Once your working directory is clean, run "git rebase --continue") + # + # Changes not staged for commit: + # (use "git add <file>..." to update what will be committed) + # (use "git checkout -- <file>..." to discard changes in working directory) + # + # modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (amend first edit) second edit and amend' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git commit --amend -m "c" && + git rebase --continue && + git commit --amend -m "d" && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (split first edit) second edit' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git reset HEAD^ && + git add main.txt && + git commit -m "e" && + git rebase --continue && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (split first edit) second edit and split' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git reset HEAD^ && + git add main.txt && + git commit --amend -m "f" && + git rebase --continue && + git reset HEAD^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently splitting a commit during a rebase. + # (Once your working directory is clean, run "git rebase --continue") + # + # Changes not staged for commit: + # (use "git add <file>..." to update what will be committed) + # (use "git checkout -- <file>..." to discard changes in working directory) + # + # modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status: (split first edit) second edit and amend' ' + git reset --hard several_edits && + FAKE_LINES="edit 1 edit 2 3" && + export FAKE_LINES && + test_when_finished "git rebase --abort" && + git rebase -i HEAD~3 && + git reset HEAD^ && + git add main.txt && + git commit --amend -m "g" && + git rebase --continue && + git commit --amend -m "h" && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently editing a commit during a rebase. + # (use "git commit --amend" to amend the current commit) + # (use "git rebase --continue" once you are satisfied with your changes) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare am_session' ' + git reset --hard master && + git checkout -b am_session && + test_commit one_am one.txt "one" && + test_commit two_am two.txt "two" && + test_commit three_am three.txt "three" +' + + +test_expect_success 'status in an am session: file already exists' ' + git checkout -b am_already_exists && + test_when_finished "rm Maildir/* && git am --abort" && + git format-patch -1 -oMaildir && + test_must_fail git am Maildir/*.patch && + cat >expected <<-\EOF && + # On branch am_already_exists + # You are in the middle of an am session. + # (fix conflicts and then run "git am --resolved") + # (use "git am --skip" to skip this patch) + # (use "git am --abort" to restore the original branch) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status in an am session: file does not exist' ' + git reset --hard am_session && + git checkout -b am_not_exists && + git rm three.txt && + git commit -m "delete three.txt" && + test_when_finished "rm Maildir/* && git am --abort" && + git format-patch -1 -oMaildir && + test_must_fail git am Maildir/*.patch && + cat >expected <<-\EOF && + # On branch am_not_exists + # You are in the middle of an am session. + # (fix conflicts and then run "git am --resolved") + # (use "git am --skip" to skip this patch) + # (use "git am --abort" to restore the original branch) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status in an am session: empty patch' ' + git reset --hard am_session && + git checkout -b am_empty && + test_when_finished "rm Maildir/* && git am --abort" && + git format-patch -3 -oMaildir && + git rm one.txt two.txt three.txt && + git commit -m "delete all am_empty" && + echo error >Maildir/0002-two_am.patch && + test_must_fail git am Maildir/*.patch && + cat >expected <<-\EOF && + # On branch am_empty + # You are in the middle of an am session. + # The current patch is empty. + # (use "git am --skip" to skip this patch) + # (use "git am --abort" to restore the original branch) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when bisecting' ' + git reset --hard master && + git checkout -b bisect && + test_commit one_bisect main.txt one && + test_commit two_bisect main.txt two && + test_commit three_bisect main.txt three && + test_when_finished "git bisect reset" && + git bisect start && + git bisect bad && + git bisect good one_bisect && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently bisecting. + # (use "git bisect reset" to get back to the original branch) + # + nothing to commit (use -u to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when rebase conflicts with statushints disabled' ' + git reset --hard master && + git checkout -b statushints_disabled && + test_when_finished "git config --local advice.statushints true" && + git config --local advice.statushints false && + test_commit one_statushints main.txt one && + test_commit two_statushints main.txt two && + test_commit three_statushints main.txt three && + test_when_finished "git rebase --abort" && + test_must_fail git rebase HEAD^ --onto HEAD^^ && + cat >expected <<-\EOF && + # Not currently on any branch. + # You are currently rebasing. + # + # Unmerged paths: + # both modified: main.txt + # + no changes added to commit + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'prepare for cherry-pick conflicts' ' + git reset --hard master && + git checkout -b cherry_branch && + test_commit one_cherry main.txt one && + test_commit two_cherries main.txt two && + git checkout -b cherry_branch_second && + test_commit second_cherry main.txt second && + git checkout cherry_branch && + test_commit three_cherries main.txt three +' + + +test_expect_success 'status when cherry-picking before resolving conflicts' ' + test_when_finished "git cherry-pick --abort" && + test_must_fail git cherry-pick cherry_branch_second && + cat >expected <<-\EOF && + # On branch cherry_branch + # You are currently cherry-picking. + # (fix conflicts and run "git commit") + # + # Unmerged paths: + # (use "git add <file>..." to mark resolution) + # + # both modified: main.txt + # + no changes added to commit (use "git add" and/or "git commit -a") + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_expect_success 'status when cherry-picking after resolving conflicts' ' + git reset --hard cherry_branch && + test_when_finished "git cherry-pick --abort" && + test_must_fail git cherry-pick cherry_branch_second && + echo end >main.txt && + git add main.txt && + cat >expected <<-\EOF && + # On branch cherry_branch + # You are currently cherry-picking. + # (all conflicts fixed: run "git commit") + # + # Changes to be committed: + # + # modified: main.txt + # + # Untracked files not listed (use -u option to show untracked files) + EOF + git status --untracked-files=no >actual && + test_i18ncmp expected actual +' + + +test_done diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index 9e27bbf90..5e19598fe 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -157,7 +157,7 @@ test_expect_success 'merge -h with invalid index' ' >.git/index && test_expect_code 129 git merge -h 2>usage ) && - grep "[Uu]sage: git merge" broken/usage + test_i18ngrep "[Uu]sage: git merge" broken/usage ' test_expect_success 'reject non-strategy with a git-merge-foo name' ' diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index 6fa0c7050..bc38737b2 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -509,4 +509,17 @@ test_expect_success 'file with no base' ' git reset --hard master >/dev/null 2>&1 ' +test_expect_success 'custom commands override built-ins' ' + git checkout -b test14 branch1 && + git config mergetool.defaults.cmd "cat \"\$REMOTE\" >\"\$MERGED\"" && + git config mergetool.defaults.trustExitCode true && + test_must_fail git merge master && + git mergetool --no-prompt --tool defaults -- both && + echo master both added >expected && + test_cmp both expected && + git config --unset mergetool.defaults.cmd && + git config --unset mergetool.defaults.trustExitCode && + git reset --hard master >/dev/null 2>&1 +' + test_done diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh index 9c3e997b9..eb1d3f85b 100755 --- a/t/t7800-difftool.sh +++ b/t/t7800-difftool.sh @@ -76,6 +76,17 @@ test_expect_success PERL 'custom commands' ' test "$diff" = "branch" ' +# Ensures that a custom difftool.<tool>.cmd overrides built-ins +test_expect_success PERL 'custom commands override built-ins' ' + restore_test_defaults && + git config difftool.defaults.cmd "cat \$REMOTE" && + + diff=$(git difftool --tool defaults --no-prompt branch) && + test "$diff" = "master" && + + git config --unset difftool.defaults.cmd +' + # Ensures that git-difftool ignores bogus --tool values test_expect_success PERL 'difftool ignores bad --tool values' ' diff=$(git difftool --no-prompt --tool=bad-tool branch) diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 523d04123..f698001c9 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -250,6 +250,84 @@ do git -c grep.extendedRegexp=true grep "a+b*c" ab >actual && test_cmp expected actual ' + + test_expect_success "grep $L with grep.patterntype=basic" ' + echo "ab:a+bc" >expected && + git -c grep.patterntype=basic grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success "grep $L with grep.patterntype=extended" ' + echo "ab:abc" >expected && + git -c grep.patterntype=extended grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success "grep $L with grep.patterntype=fixed" ' + echo "ab:a+b*c" >expected && + git -c grep.patterntype=fixed grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success LIBPCRE "grep $L with grep.patterntype=perl" ' + echo "ab:a+b*c" >expected && + git -c grep.patterntype=perl grep "a\x{2b}b\x{2a}c" ab >actual && + test_cmp expected actual + ' + + test_expect_success "grep $L with grep.patternType=default and grep.extendedRegexp=true" ' + echo "ab:abc" >expected && + git \ + -c grep.patternType=default \ + -c grep.extendedRegexp=true \ + grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success "grep $L with grep.extendedRegexp=true and grep.patternType=default" ' + echo "ab:abc" >expected && + git \ + -c grep.extendedRegexp=true \ + -c grep.patternType=default \ + grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success 'grep $L with grep.patternType=extended and grep.extendedRegexp=false' ' + echo "ab:abc" >expected && + git \ + -c grep.patternType=extended \ + -c grep.extendedRegexp=false \ + grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success 'grep $L with grep.patternType=basic and grep.extendedRegexp=true' ' + echo "ab:a+bc" >expected && + git \ + -c grep.patternType=basic \ + -c grep.extendedRegexp=true \ + grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success 'grep $L with grep.extendedRegexp=false and grep.patternType=extended' ' + echo "ab:abc" >expected && + git \ + -c grep.extendedRegexp=false \ + -c grep.patternType=extended \ + grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success 'grep $L with grep.extendedRegexp=true and grep.patternType=basic' ' + echo "ab:a+bc" >expected && + git \ + -c grep.extendedRegexp=true \ + -c grep.patternType=basic \ + grep "a+b*c" ab >actual && + test_cmp expected actual + ' done cat >expected <<EOF @@ -424,31 +502,41 @@ test_expect_success 'log grep setup' ' test_expect_success 'log grep (1)' ' git log --author=author --pretty=tformat:%s >actual && - ( echo third ; echo initial ) >expect && + { + echo third && echo initial + } >expect && test_cmp expect actual ' test_expect_success 'log grep (2)' ' git log --author=" * " -F --pretty=tformat:%s >actual && - ( echo second ) >expect && + { + echo second + } >expect && test_cmp expect actual ' test_expect_success 'log grep (3)' ' git log --author="^A U" --pretty=tformat:%s >actual && - ( echo third ; echo initial ) >expect && + { + echo third && echo initial + } >expect && test_cmp expect actual ' test_expect_success 'log grep (4)' ' git log --author="frotz\.com>$" --pretty=tformat:%s >actual && - ( echo second ) >expect && + { + echo second + } >expect && test_cmp expect actual ' test_expect_success 'log grep (5)' ' git log --author=Thor -F --pretty=tformat:%s >actual && - ( echo third ; echo initial ) >expect && + { + echo third && echo initial + } >expect && test_cmp expect actual ' @@ -458,11 +546,49 @@ test_expect_success 'log grep (6)' ' test_cmp expect actual ' -test_expect_success 'log --grep --author implicitly uses all-match' ' - # grep matches initial and second but not third - # author matches only initial and third - git log --author="A U Thor" --grep=s --grep=l --format=%s >actual && - echo initial >expect && +test_expect_success 'log grep (7)' ' + git log -g --grep-reflog="commit: third" --pretty=tformat:%s >actual && + echo third >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (8)' ' + git log -g --grep-reflog="commit: third" --grep-reflog="commit: second" --pretty=tformat:%s >actual && + { + echo third && echo second + } >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (9)' ' + git log -g --grep-reflog="commit: third" --author="Thor" --pretty=tformat:%s >actual && + echo third >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (9)' ' + git log -g --grep-reflog="commit: third" --author="non-existant" --pretty=tformat:%s >actual && + : >expect && + test_cmp expect actual +' + +test_expect_success 'log --grep-reflog can only be used under -g' ' + test_must_fail git log --grep-reflog="commit: third" +' + +test_expect_success 'log with multiple --grep uses union' ' + git log --grep=i --grep=r --format=%s >actual && + { + echo fourth && echo third && echo initial + } >expect && + test_cmp expect actual +' + +test_expect_success 'log --all-match with multiple --grep uses intersection' ' + git log --all-match --grep=i --grep=r --format=%s >actual && + { + echo third + } >expect && test_cmp expect actual ' @@ -474,7 +600,47 @@ test_expect_success 'log with multiple --author uses union' ' test_cmp expect actual ' -test_expect_success 'log with --grep and multiple --author uses all-match' ' +test_expect_success 'log --all-match with multiple --author still uses union' ' + git log --all-match --author="Thor" --author="Aster" --format=%s >actual && + { + echo third && echo second && echo initial + } >expect && + test_cmp expect actual +' + +test_expect_success 'log --grep --author uses intersection' ' + # grep matches only third and fourth + # author matches only initial and third + git log --author="A U Thor" --grep=r --format=%s >actual && + { + echo third + } >expect && + test_cmp expect actual +' + +test_expect_success 'log --grep --grep --author takes union of greps and intersects with author' ' + # grep matches initial and second but not third + # author matches only initial and third + git log --author="A U Thor" --grep=s --grep=l --format=%s >actual && + { + echo initial + } >expect && + test_cmp expect actual +' + +test_expect_success 'log ---all-match -grep --author --author still takes union of authors and intersects with grep' ' + # grep matches only initial and third + # author matches all but second + git log --all-match --author="Thor" --author="Night" --grep=i --format=%s >actual && + { + echo third && echo initial + } >expect && + test_cmp expect actual +' + +test_expect_success 'log --grep --author --author takes union of authors and intersects with grep' ' + # grep matches only initial and third + # author matches all but second git log --author="Thor" --author="Night" --grep=i --format=%s >actual && { echo third && echo initial @@ -482,9 +648,25 @@ test_expect_success 'log with --grep and multiple --author uses all-match' ' test_cmp expect actual ' -test_expect_success 'log with --grep and multiple --author uses all-match' ' - git log --author="Thor" --author="Night" --grep=q --format=%s >actual && - >expect && +test_expect_success 'log --all-match --grep --grep --author takes intersection' ' + # grep matches only third + # author matches only initial and third + git log --all-match --author="A U Thor" --grep=i --grep=r --format=%s >actual && + { + echo third + } >expect && + test_cmp expect actual +' + +test_expect_success 'log --author does not search in timestamp' ' + : >expect && + git log --author="$GIT_AUTHOR_DATE" >actual && + test_cmp expect actual +' + +test_expect_success 'log --committer does not search in timestamp' ' + : >expect && + git log --committer="$GIT_COMMITTER_DATE" >actual && test_cmp expect actual ' @@ -761,44 +943,147 @@ test_expect_success 'grep -G invalidpattern properly dies ' ' test_must_fail git grep -G "a[" ' +test_expect_success 'grep invalidpattern properly dies with grep.patternType=basic' ' + test_must_fail git -c grep.patterntype=basic grep "a[" +' + test_expect_success 'grep -E invalidpattern properly dies ' ' test_must_fail git grep -E "a[" ' +test_expect_success 'grep invalidpattern properly dies with grep.patternType=extended' ' + test_must_fail git -c grep.patterntype=extended grep "a[" +' + test_expect_success LIBPCRE 'grep -P invalidpattern properly dies ' ' test_must_fail git grep -P "a[" ' +test_expect_success LIBPCRE 'grep invalidpattern properly dies with grep.patternType=perl' ' + test_must_fail git -c grep.patterntype=perl grep "a[" +' + test_expect_success 'grep -G -E -F pattern' ' echo "ab:a+b*c" >expected && git grep -G -E -F "a+b*c" ab >actual && test_cmp expected actual ' +test_expect_success 'grep pattern with grep.patternType=basic, =extended, =fixed' ' + echo "ab:a+b*c" >expected && + git \ + -c grep.patterntype=basic \ + -c grep.patterntype=extended \ + -c grep.patterntype=fixed \ + grep "a+b*c" ab >actual && + test_cmp expected actual +' + test_expect_success 'grep -E -F -G pattern' ' echo "ab:a+bc" >expected && git grep -E -F -G "a+b*c" ab >actual && test_cmp expected actual ' +test_expect_success 'grep pattern with grep.patternType=extended, =fixed, =basic' ' + echo "ab:a+bc" >expected && + git \ + -c grep.patterntype=extended \ + -c grep.patterntype=fixed \ + -c grep.patterntype=basic \ + grep "a+b*c" ab >actual && + test_cmp expected actual +' + test_expect_success 'grep -F -G -E pattern' ' echo "ab:abc" >expected && git grep -F -G -E "a+b*c" ab >actual && test_cmp expected actual ' +test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =extended' ' + echo "ab:abc" >expected && + git \ + -c grep.patterntype=fixed \ + -c grep.patterntype=basic \ + -c grep.patterntype=extended \ + grep "a+b*c" ab >actual && + test_cmp expected actual +' + test_expect_success 'grep -G -F -P -E pattern' ' >empty && test_must_fail git grep -G -F -P -E "a\x{2b}b\x{2a}c" ab >actual && test_cmp empty actual ' +test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =perl, =extended' ' + >empty && + test_must_fail git \ + -c grep.patterntype=fixed \ + -c grep.patterntype=basic \ + -c grep.patterntype=perl \ + -c grep.patterntype=extended \ + grep "a\x{2b}b\x{2a}c" ab >actual && + test_cmp empty actual +' + test_expect_success LIBPCRE 'grep -G -F -E -P pattern' ' echo "ab:a+b*c" >expected && git grep -G -F -E -P "a\x{2b}b\x{2a}c" ab >actual && test_cmp expected actual ' +test_expect_success LIBPCRE 'grep pattern with grep.patternType=fixed, =basic, =extended, =perl' ' + echo "ab:a+b*c" >expected && + git \ + -c grep.patterntype=fixed \ + -c grep.patterntype=basic \ + -c grep.patterntype=extended \ + -c grep.patterntype=perl \ + grep "a\x{2b}b\x{2a}c" ab >actual && + test_cmp expected actual +' + +test_expect_success LIBPCRE 'grep -P pattern with grep.patternType=fixed' ' + echo "ab:a+b*c" >expected && + git \ + -c grep.patterntype=fixed \ + grep -P "a\x{2b}b\x{2a}c" ab >actual && + test_cmp expected actual +' + +test_expect_success 'grep -F pattern with grep.patternType=basic' ' + echo "ab:a+b*c" >expected && + git \ + -c grep.patterntype=basic \ + grep -F "*c" ab >actual && + test_cmp expected actual +' + +test_expect_success 'grep -G pattern with grep.patternType=fixed' ' + { + echo "ab:a+b*c" + echo "ab:a+bc" + } >expected && + git \ + -c grep.patterntype=fixed \ + grep -G "a+b" ab >actual && + test_cmp expected actual +' + +test_expect_success 'grep -E pattern with grep.patternType=fixed' ' + { + echo "ab:a+b*c" + echo "ab:a+bc" + echo "ab:abc" + } >expected && + git \ + -c grep.patterntype=fixed \ + grep -E "a+" ab >actual && + test_cmp expected actual +' + test_config() { git config "$1" "$2" && test_when_finished "git config --unset $1" diff --git a/t/t8004-blame-with-conflicts.sh b/t/t8004-blame-with-conflicts.sh index ba19ac127..9c353ab22 100755 --- a/t/t8004-blame-with-conflicts.sh +++ b/t/t8004-blame-with-conflicts.sh @@ -66,7 +66,7 @@ test_expect_success \ git blame file2 ' -test_expect_success 'blame runs on conflicted file in stages 1,3' ' +test_expect_success 'blame does not crash with conflicted file in stages 1,3' ' git blame file1 ' diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 035122808..97d6f4c7d 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -191,17 +191,44 @@ test_expect_success $PREREQ 'Show all headers' ' test_expect_success $PREREQ 'Prompting works' ' clean_fake_sendmail && - (echo "Example <from@example.com>" - echo "to@example.com" + (echo "to@example.com" echo "" ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \ --smtp-server="$(pwd)/fake.sendmail" \ $patches \ 2>errors && - grep "^From: Example <from@example.com>\$" msgtxt1 && + grep "^From: A U Thor <author@example.com>\$" msgtxt1 && grep "^To: to@example.com\$" msgtxt1 ' +test_expect_success $PREREQ,AUTOIDENT 'implicit ident is allowed' ' + clean_fake_sendmail && + (sane_unset GIT_AUTHOR_NAME && + sane_unset GIT_AUTHOR_EMAIL && + sane_unset GIT_COMMITTER_NAME && + sane_unset GIT_COMMITTER_EMAIL && + GIT_SEND_EMAIL_NOTTY=1 git send-email \ + --smtp-server="$(pwd)/fake.sendmail" \ + --to=to@example.com \ + $patches </dev/null 2>errors + ) +' + +test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email' ' + clean_fake_sendmail && + (sane_unset GIT_AUTHOR_NAME && + sane_unset GIT_AUTHOR_EMAIL && + sane_unset GIT_COMMITTER_NAME && + sane_unset GIT_COMMITTER_EMAIL && + GIT_SEND_EMAIL_NOTTY=1 && export GIT_SEND_EMAIL_NOTTY && + test_must_fail git send-email \ + --smtp-server="$(pwd)/fake.sendmail" \ + --to=to@example.com \ + $patches </dev/null 2>errors && + test_i18ngrep "tell me who you are" errors + ) +' + test_expect_success $PREREQ 'tocmd works' ' clean_fake_sendmail && cp $patches tocmd.patch && @@ -854,6 +881,75 @@ test_expect_success $PREREQ 'utf8 author is correctly passed on' ' grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1 ' +test_expect_success $PREREQ 'sendemail.composeencoding works' ' + clean_fake_sendmail && + git config sendemail.composeencoding iso-8859-1 && + (echo "#!$SHELL_PATH" && + echo "echo utf8 body: à éìöú >>\"\$1\"" + ) >fake-editor-utf8 && + chmod +x fake-editor-utf8 && + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && + grep "^utf8 body" msgtxt1 && + grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 +' + +test_expect_success $PREREQ '--compose-encoding works' ' + clean_fake_sendmail && + (echo "#!$SHELL_PATH" && + echo "echo utf8 body: à éìöú >>\"\$1\"" + ) >fake-editor-utf8 && + chmod +x fake-editor-utf8 && + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose-encoding iso-8859-1 \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && + grep "^utf8 body" msgtxt1 && + grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 +' + +test_expect_success $PREREQ '--compose-encoding overrides sendemail.composeencoding' ' + clean_fake_sendmail && + git config sendemail.composeencoding iso-8859-1 && + (echo "#!$SHELL_PATH" && + echo "echo utf8 body: à éìöú >>\"\$1\"" + ) >fake-editor-utf8 && + chmod +x fake-editor-utf8 && + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose-encoding iso-8859-2 \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && + grep "^utf8 body" msgtxt1 && + grep "^Content-Type: text/plain; charset=iso-8859-2" msgtxt1 +' + +test_expect_success $PREREQ '--compose-encoding adds correct MIME for subject' ' + clean_fake_sendmail && + GIT_EDITOR="\"$(pwd)/fake-editor\"" \ + git send-email \ + --compose-encoding iso-8859-2 \ + --compose --subject utf8-sübjëct \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && + grep "^fake edit" msgtxt1 && + grep "^Subject: =?iso-8859-2?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1 +' + test_expect_success $PREREQ 'detects ambiguous reference/file conflict' ' echo master > master && git add master && @@ -1074,6 +1170,23 @@ EOF ' test_expect_success $PREREQ 'setup expect' ' +cat >expected <<EOF +Subject: subject goes here +EOF +' + +test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' ' + clean_fake_sendmail && + echo bogus | + git send-email --from=author@example.com --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + --8bit-encoding=UTF-8 \ + email-using-8bit >stdout && + grep "Subject" msgtxt1 >actual && + test_cmp expected actual +' + +test_expect_success $PREREQ 'setup expect' ' cat >content-type-decl <<EOF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 diff --git a/t/t9020-remote-svn.sh b/t/t9020-remote-svn.sh new file mode 100755 index 000000000..2d2f016f6 --- /dev/null +++ b/t/t9020-remote-svn.sh @@ -0,0 +1,88 @@ +#!/bin/sh + +test_description='tests remote-svn' + +. ./test-lib.sh + +MARKSPATH=.git/info/fast-import/remote-svn + +if ! test_have_prereq PYTHON +then + skip_all='skipping remote-svn tests, python not available' + test_done +fi + +# Override svnrdump with our simulator +PATH="$HOME:$PATH" +export PATH PYTHON_PATH GIT_BUILD_DIR + +write_script "$HOME/svnrdump" <<\EOF +exec "$PYTHON_PATH" "$GIT_BUILD_DIR/contrib/svn-fe/svnrdump_sim.py" "$@" +EOF + +init_git () { + rm -fr .git && + git init && + #git remote add svnsim testsvn::sim:///$TEST_DIRECTORY/t9020/example.svnrdump + # let's reuse an exisiting dump file!? + git remote add svnsim testsvn::sim://$TEST_DIRECTORY/t9154/svn.dump + git remote add svnfile testsvn::file://$TEST_DIRECTORY/t9154/svn.dump +} + +if test -e "$GIT_BUILD_DIR/git-remote-testsvn" +then + test_set_prereq REMOTE_SVN +fi + +test_debug ' + git --version + type git + type svnrdump +' + +test_expect_success REMOTE_SVN 'simple fetch' ' + init_git && + git fetch svnsim && + test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master && + cp .git/refs/remotes/svnsim/master master.good +' + +test_debug ' + cat .git/refs/svn/svnsim/master + cat .git/refs/remotes/svnsim/master +' + +test_expect_success REMOTE_SVN 'repeated fetch, nothing shall change' ' + git fetch svnsim && + test_cmp master.good .git/refs/remotes/svnsim/master +' + +test_expect_success REMOTE_SVN 'fetch from a file:// url gives the same result' ' + git fetch svnfile +' + +test_expect_failure REMOTE_SVN 'the sha1 differ because the git-svn-id line in the commit msg contains the url' ' + test_cmp .git/refs/remotes/svnfile/master .git/refs/remotes/svnsim/master +' + +test_expect_success REMOTE_SVN 'mark-file regeneration' ' + # filter out any other marks, that can not be regenerated. Only up to 3 digit revisions are allowed here + grep ":[0-9]\{1,3\} " $MARKSPATH/svnsim.marks > $MARKSPATH/svnsim.marks.old && + rm $MARKSPATH/svnsim.marks && + git fetch svnsim && + test_cmp $MARKSPATH/svnsim.marks.old $MARKSPATH/svnsim.marks +' + +test_expect_success REMOTE_SVN 'incremental imports must lead to the same head' ' + export SVNRMAX=3 && + init_git && + git fetch svnsim && + test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master && + unset SVNRMAX && + git fetch svnsim && + test_cmp master.good .git/refs/remotes/svnsim/master +' + +test_debug 'git branch -a' + +test_done diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index 289fc313f..ee73013ee 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -27,15 +27,17 @@ test_expect_success 'setup old-looking metadata' ' head=`git rev-parse --verify refs/heads/git-svn-HEAD^0` test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'" +svnrepo_escaped=`echo $svnrepo | sed 's/ /%20/'` + test_expect_success 'initialize old-style (v0) git svn layout' ' mkdir -p "$GIT_DIR"/git-svn/info "$GIT_DIR"/svn/info && echo "$svnrepo" > "$GIT_DIR"/git-svn/info/url && echo "$svnrepo" > "$GIT_DIR"/svn/info/url && git svn migrate && - ! test -d "$GIT_DIR"/git svn && + ! test -d "$GIT_DIR"/git-svn && git rev-parse --verify refs/${remotes_git_svn}^0 && git rev-parse --verify refs/remotes/svn^0 && - test "$(git config --get svn-remote.svn.url)" = "$svnrepo" && + test "$(git config --get svn-remote.svn.url)" = "$svnrepo_escaped" && test `git config --get svn-remote.svn.fetch` = \ ":refs/${remotes_git_svn}" ' diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh index 63fc982c8..15f93b4c2 100755 --- a/t/t9118-git-svn-funky-branch-names.sh +++ b/t/t9118-git-svn-funky-branch-names.sh @@ -28,10 +28,15 @@ test_expect_success 'setup svnrepo' ' svn_cmd cp -m "trailing .lock" "$svnrepo/pr ject/trunk" \ "$svnrepo/pr ject/branches/trailing_dotlock.lock" && svn_cmd cp -m "reflog" "$svnrepo/pr ject/trunk" \ - "$svnrepo/pr ject/branches/not-a%40{0}reflog" && + "$svnrepo/pr ject/branches/not-a@{0}reflog@" && start_httpd ' +# SVN 1.7 will truncate "not-a%40{0]" to just "not-a". +# Look at what SVN wound up naming the branch and use that. +# Be sure to escape the @ if it shows up. +non_reflog=`svn_cmd ls "$svnrepo/pr ject/branches" | grep not-a | sed 's/\///' | sed 's/@/%40/'` + test_expect_success 'test clone with funky branch names' ' git svn clone -s "$svnrepo/pr ject" project && ( @@ -42,7 +47,7 @@ test_expect_success 'test clone with funky branch names' ' git rev-parse "refs/remotes/%2Eleading_dot" && git rev-parse "refs/remotes/trailing_dot%2E" && git rev-parse "refs/remotes/trailing_dotlock%2Elock" && - git rev-parse "refs/remotes/not-a%40{0}reflog" + git rev-parse "refs/remotes/$non_reflog" ) ' diff --git a/t/t9154-git-svn-fancy-glob.sh b/t/t9154-git-svn-fancy-glob.sh index a6a56a6cb..b780e0efe 100755 --- a/t/t9154-git-svn-fancy-glob.sh +++ b/t/t9154-git-svn-fancy-glob.sh @@ -21,6 +21,15 @@ test_expect_success 'add red branch' " test_must_fail git rev-parse refs/remotes/blue " +test_expect_success 'add gre branch' " + GIT_CONFIG=.git/svn/.metadata git config --unset svn-remote.svn.branches-maxRev && + git config svn-remote.svn.branches 'branches/{red,gre}:refs/remotes/*' && + git svn fetch && + git rev-parse refs/remotes/red && + test_must_fail git rev-parse refs/remotes/green && + test_must_fail git rev-parse refs/remotes/blue + " + test_expect_success 'add green branch' " GIT_CONFIG=.git/svn/.metadata git config --unset svn-remote.svn.branches-maxRev && git config svn-remote.svn.branches 'branches/{red,green}:refs/remotes/*' && diff --git a/t/t9163-git-svn-reset-clears-caches.sh b/t/t9163-git-svn-reset-clears-caches.sh new file mode 100755 index 000000000..cd4c662ba --- /dev/null +++ b/t/t9163-git-svn-reset-clears-caches.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# +# Copyright (c) 2012 Peter Baumann +# + +test_description='git svn reset clears memoized caches' +. ./lib-git-svn.sh + +svn_ver="$(svn --version --quiet)" +case $svn_ver in +0.* | 1.[0-4].*) + skip_all="skipping git-svn test - SVN too old ($svn_ver)" + test_done + ;; +esac + +# ... a - b - m <- trunk +# \ / +# ... c <- branch1 +# +# SVN Commits not interesting for this test are abbreviated with "..." +# +test_expect_success 'initialize source svn repo' ' + svn_cmd mkdir -m "create trunk" "$svnrepo"/trunk && + svn_cmd mkdir -m "create branches" "$svnrepo/branches" && + svn_cmd co "$svnrepo"/trunk "$SVN_TREE" && + ( + cd "$SVN_TREE" && + touch foo && + svn_cmd add foo && + svn_cmd commit -m "a" && + svn_cmd cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 && + svn_cmd switch "$svnrepo"/branches/branch1 && + touch bar && + svn_cmd add bar && + svn_cmd commit -m b && + svn_cmd switch "$svnrepo"/trunk && + touch baz && + svn_cmd add baz && + svn_cmd commit -m c && + svn_cmd up && + svn_cmd merge "$svnrepo"/branches/branch1 && + svn_cmd commit -m "m" + ) && + rm -rf "$SVN_TREE" +' + +test_expect_success 'fetch to merge-base (a)' ' + git svn init -s "$svnrepo" && + git svn fetch --revision BASE:3 +' + +# git svn rebase looses the merge commit +# +# ... a - b - m <- trunk +# \ +# ... c +# +test_expect_success 'rebase looses SVN merge (m)' ' + git svn rebase && + git svn fetch && + test 1 = $(git cat-file -p master|grep parent|wc -l) +' + +# git svn fetch creates correct history with merge commit +# +# ... a - b - m <- trunk +# \ / +# ... c <- branch1 +# +test_expect_success 'reset and fetch gets the SVN merge (m) correctly' ' + git svn reset -r 3 && + git reset --hard trunk && + git svn fetch && + test 2 = $(git cat-file -p trunk|grep parent|wc -l) +' + +test_done diff --git a/t/t9164-git-svn-dcommit-concurrent.sh b/t/t9164-git-svn-dcommit-concurrent.sh new file mode 100755 index 000000000..d8464d421 --- /dev/null +++ b/t/t9164-git-svn-dcommit-concurrent.sh @@ -0,0 +1,216 @@ +#!/bin/sh +# +# Copyright (c) 2012 Robert Luberda +# + +test_description='concurrent git svn dcommit' +. ./lib-git-svn.sh + + + +test_expect_success 'setup svn repository' ' + svn_cmd checkout "$svnrepo" work.svn && + ( + cd work.svn && + echo >file && echo > auto_updated_file + svn_cmd add file auto_updated_file && + svn_cmd commit -m "initial commit" + ) && + svn_cmd checkout "$svnrepo" work-auto-commits.svn +' +N=0 +next_N() +{ + N=$(( $N + 1 )) +} + +# Setup SVN repository hooks to emulate SVN failures or concurrent commits +# The function adds +# either pre-commit hook, which causes SVN commit given in second argument +# to fail +# or post-commit hook, which creates a new commit (a new line added to +# auto_updated_file) after given SVN commit +# The first argument contains a type of the hook +# The second argument contains a number (not SVN revision) of commit +# the hook should be applied for (each time the hook is run, the given +# number is decreased by one until it gets 0, in which case the hook +# will execute its real action) +setup_hook() +{ + hook_type="$1" # "pre-commit" or "post-commit" + skip_revs="$2" + [ "$hook_type" = "pre-commit" ] || + [ "$hook_type" = "post-commit" ] || + { echo "ERROR: invalid argument ($hook_type)" \ + "passed to setup_hook" >&2 ; return 1; } + echo "cnt=$skip_revs" > "$hook_type-counter" + rm -f "$rawsvnrepo/hooks/"*-commit # drop previous hooks + hook="$rawsvnrepo/hooks/$hook_type" + cat > "$hook" <<- 'EOF1' + #!/bin/sh + set -e + cd "$1/.." # "$1" is repository location + exec >> svn-hook.log 2>&1 + hook="$(basename "$0")" + echo "*** Executing $hook $@" + set -x + . ./$hook-counter + cnt="$(($cnt - 1))" + echo "cnt=$cnt" > ./$hook-counter + [ "$cnt" = "0" ] || exit 0 +EOF1 + if [ "$hook_type" = "pre-commit" ]; then + echo "echo 'commit disallowed' >&2; exit 1" >>"$hook" + else + echo "PATH=\"$PATH\"; export PATH" >>"$hook" + echo "svnconf=\"$svnconf\"" >>"$hook" + cat >>"$hook" <<- 'EOF2' + cd work-auto-commits.svn + svn up --config-dir "$svnconf" + echo "$$" >> auto_updated_file + svn commit --config-dir "$svnconf" \ + -m "auto-committing concurrent change" + exit 0 +EOF2 + fi + chmod 755 "$hook" +} + +check_contents() +{ + gitdir="$1" + (cd ../work.svn && svn_cmd up) && + test_cmp file ../work.svn/file && + test_cmp auto_updated_file ../work.svn/auto_updated_file +} + +test_expect_success 'check if post-commit hook creates a concurrent commit' ' + setup_hook post-commit 1 && + ( + cd work.svn && + cp auto_updated_file au_file_saved && + echo 1 >> file && + svn_cmd commit -m "changing file" && + svn_cmd up && + test_must_fail test_cmp auto_updated_file au_file_saved + ) +' + +test_expect_success 'check if pre-commit hook fails' ' + setup_hook pre-commit 2 && + ( + cd work.svn && + echo 2 >> file && + svn_cmd commit -m "changing file once again" && + echo 3 >> file && + test_must_fail svn_cmd commit -m "this commit should fail" && + svn_cmd revert file + ) +' + +test_expect_success 'dcommit error handling' ' + setup_hook pre-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + echo 1 >> file && git commit -am "commit change $N.1" && + echo 2 >> file && git commit -am "commit change $N.2" && + echo 3 >> file && git commit -am "commit change $N.3" && + # should fail to dcommit 2nd and 3rd change + # but still should leave the repository in reasonable state + test_must_fail git svn dcommit && + git update-index --refresh && + git show HEAD~2 | grep -q git-svn-id && + ! git show HEAD~1 | grep -q git-svn-id && + ! git show HEAD | grep -q git-svn-id + ) +' + +test_expect_success 'dcommit concurrent change in non-changed file' ' + setup_hook post-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + echo 1 >> file && git commit -am "commit change $N.1" && + echo 2 >> file && git commit -am "commit change $N.2" && + echo 3 >> file && git commit -am "commit change $N.3" && + # should rebase and leave the repository in reasonable state + git svn dcommit && + git update-index --refresh && + check_contents && + git show HEAD~3 | grep -q git-svn-id && + git show HEAD~2 | grep -q git-svn-id && + git show HEAD~1 | grep -q auto-committing && + git show HEAD | grep -q git-svn-id + ) +' + +# An utility function used in the following test +delete_first_line() +{ + file="$1" && + sed 1d < "$file" > "${file}.tmp" && + rm "$file" && + mv "${file}.tmp" "$file" +} + +test_expect_success 'dcommit concurrent non-conflicting change' ' + setup_hook post-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + cat file >> auto_updated_file && + git commit -am "commit change $N.1" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.2" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.3" && + # should rebase and leave the repository in reasonable state + git svn dcommit && + git update-index --refresh && + check_contents && + git show HEAD~3 | grep -q git-svn-id && + git show HEAD~2 | grep -q git-svn-id && + git show HEAD~1 | grep -q auto-committing && + git show HEAD | grep -q git-svn-id + ) +' + +test_expect_success 'dcommit --no-rebase concurrent non-conflicting change' ' + setup_hook post-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + cat file >> auto_updated_file && + git commit -am "commit change $N.1" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.2" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.3" && + # should fail as rebase is needed + test_must_fail git svn dcommit --no-rebase && + # but should leave HEAD unchanged + git update-index --refresh && + ! git show HEAD~2 | grep -q git-svn-id && + ! git show HEAD~1 | grep -q git-svn-id && + ! git show HEAD | grep -q git-svn-id + ) +' + +test_expect_success 'dcommit fails on concurrent conflicting change' ' + setup_hook post-commit 1 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + echo a >> file && + git commit -am "commit change $N.1" && + echo b >> auto_updated_file && + git commit -am "commit change $N.2" && + echo c >> auto_updated_file && + git commit -am "commit change $N.3" && + test_must_fail git svn dcommit && # rebase should fail + test_must_fail git update-index --refresh + ) +' + +test_done diff --git a/t/t9165-git-svn-fetch-merge-branch-of-branch.sh b/t/t9165-git-svn-fetch-merge-branch-of-branch.sh new file mode 100755 index 000000000..13ae7e33f --- /dev/null +++ b/t/t9165-git-svn-fetch-merge-branch-of-branch.sh @@ -0,0 +1,60 @@ +#!/bin/sh +# +# Copyright (c) 2012 Steven Walter +# + +test_description='git svn merge detection' +. ./lib-git-svn.sh + +svn_ver="$(svn --version --quiet)" +case $svn_ver in +0.* | 1.[0-4].*) + skip_all="skipping git-svn test - SVN too old ($svn_ver)" + test_done + ;; +esac + +test_expect_success 'initialize source svn repo' ' + svn_cmd mkdir -m x "$svnrepo"/trunk && + svn_cmd mkdir -m x "$svnrepo"/branches && + svn_cmd co "$svnrepo"/trunk "$SVN_TREE" && + ( + cd "$SVN_TREE" && + touch foo && + svn_cmd add foo && + svn_cmd commit -m "initial commit" && + svn_cmd cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 && + svn_cmd switch "$svnrepo"/branches/branch1 && + touch bar && + svn_cmd add bar && + svn_cmd commit -m branch1 && + svn_cmd cp -m branch "$svnrepo"/branches/branch1 "$svnrepo"/branches/branch2 && + svn_cmd switch "$svnrepo"/branches/branch2 && + touch baz && + svn_cmd add baz && + svn_cmd commit -m branch2 && + svn_cmd switch "$svnrepo"/trunk && + touch bar2 && + svn_cmd add bar2 && + svn_cmd commit -m trunk && + svn_cmd switch "$svnrepo"/branches/branch2 && + svn_cmd merge "$svnrepo"/trunk && + svn_cmd commit -m "merge trunk" + svn_cmd switch "$svnrepo"/trunk && + svn_cmd merge --reintegrate "$svnrepo"/branches/branch2 && + svn_cmd commit -m "merge branch2" + ) && + rm -rf "$SVN_TREE" +' + +test_expect_success 'clone svn repo' ' + git svn init -s "$svnrepo" && + git svn fetch +' + +test_expect_success 'verify merge commit' 'x=$(git rev-parse HEAD^2) && + y=$(git rev-parse branch2) && + test "x$x" = "x$y" +' + +test_done diff --git a/t/t9166-git-svn-fetch-merge-branch-of-branch2.sh b/t/t9166-git-svn-fetch-merge-branch-of-branch2.sh new file mode 100755 index 000000000..af0ec0e2e --- /dev/null +++ b/t/t9166-git-svn-fetch-merge-branch-of-branch2.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# +# Copyright (c) 2012 Steven Walter +# + +test_description='git svn merge detection' +. ./lib-git-svn.sh + +svn_ver="$(svn --version --quiet)" +case $svn_ver in +0.* | 1.[0-4].*) + skip_all="skipping git-svn test - SVN too old ($svn_ver)" + test_done + ;; +esac + +test_expect_success 'initialize source svn repo' ' + svn_cmd mkdir -m x "$svnrepo"/trunk && + svn_cmd mkdir -m x "$svnrepo"/branches && + svn_cmd co "$svnrepo"/trunk "$SVN_TREE" && + ( + cd "$SVN_TREE" && + touch foo && + svn_cmd add foo && + svn_cmd commit -m "initial commit" && + svn_cmd cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 && + svn_cmd switch "$svnrepo"/branches/branch1 && + touch bar && + svn_cmd add bar && + svn_cmd commit -m branch1 && + svn_cmd cp -m branch "$svnrepo"/branches/branch1 "$svnrepo"/branches/branch2 && + svn_cmd switch "$svnrepo"/branches/branch2 && + touch baz && + svn_cmd add baz && + svn_cmd commit -m branch2 && + svn_cmd switch "$svnrepo"/trunk && + svn_cmd merge --reintegrate "$svnrepo"/branches/branch2 && + svn_cmd commit -m "merge branch2" + ) && + rm -rf "$SVN_TREE" +' + +test_expect_success 'clone svn repo' ' + git svn init -s "$svnrepo" && + git svn fetch +' + +test_expect_success 'verify merge commit' 'x=$(git rev-parse HEAD^2) && + y=$(git rev-parse branch2) && + test "x$x" = "x$y" +' + +test_done diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index b59be9a89..3fb336890 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -19,14 +19,15 @@ then test_done fi -CVSROOT=$PWD/cvsroot +CVSROOT=$PWD/tmpcvsroot CVSWORK=$PWD/cvswork GIT_DIR=$PWD/.git export CVSROOT CVSWORK GIT_DIR rm -rf "$CVSROOT" "$CVSWORK" -mkdir "$CVSROOT" && + cvs init && +test -d "$CVSROOT" && cvs -Q co -d "$CVSWORK" . && echo >empty && git add empty && diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 806623e88..9502f2438 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -400,7 +400,7 @@ cat >expected.C <<EOF Line 0 ======= LINE 0 ->>>>>>> merge.3 +>>>>>>> merge.1.3 EOF for i in 1 2 3 4 5 6 7 8 @@ -505,6 +505,76 @@ test_expect_success 'cvs co -c (shows module database)' ' ' #------------ +# CVS LOG +#------------ + +# Known issues with git-cvsserver current log output: +# - Hard coded "lines: +2 -3" placeholder, instead of real numbers. +# - CVS normally does not internally add a blank first line +# nor a last line with nothing but a space to log messages. +# - The latest cvs 1.12.x server sends +0000 timezone (with some hidden "MT" +# tagging in the protocol), and if cvs 1.12.x client sees the MT tags, +# it converts to local time zone. git-cvsserver doesn't do the +0000 +# or the MT tags... +# - The latest 1.12.x releases add a "commitid:" field on to the end of the +# "date:" line (after "lines:"). Maybe we could stick git's commit id +# in it? Or does CVS expect a certain number of bits (too few for +# a full sha1)? +# +# Given the above, expect the following test to break if git-cvsserver's +# log output is improved. The test is just to ensure it doesn't +# accidentally get worse. + +sed -e 's/^x//' -e 's/SP$/ /' > "$WORKDIR/expect" <<EOF +x +xRCS file: $WORKDIR/gitcvs.git/master/merge,v +xWorking file: merge +xhead: 1.4 +xbranch: +xlocks: strict +xaccess list: +xsymbolic names: +xkeyword substitution: kv +xtotal revisions: 4; selected revisions: 4 +xdescription: +x---------------------------- +xrevision 1.4 +xdate: __DATE__; author: author; state: Exp; lines: +2 -3 +x +xMerge test (no-op) +xSP +x---------------------------- +xrevision 1.3 +xdate: __DATE__; author: author; state: Exp; lines: +2 -3 +x +xMerge test (conflict) +xSP +x---------------------------- +xrevision 1.2 +xdate: __DATE__; author: author; state: Exp; lines: +2 -3 +x +xMerge test (merge) +xSP +x---------------------------- +xrevision 1.1 +xdate: __DATE__; author: author; state: Exp; lines: +2 -3 +x +xMerge test (pre-merge) +xSP +x============================================================================= +EOF +expectStat="$?" + +cd "$WORKDIR" +test_expect_success 'cvs log' ' + cd cvswork && + test x"$expectStat" = x"0" && + GIT_CONFIG="$git_config" cvs log merge >../out && + sed -e "s%2[0-9][0-9][0-9]/[01][0-9]/[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]%__DATE__%" ../out > ../actual && + test_cmp ../expect ../actual +' + +#------------ # CVS ANNOTATE #------------ diff --git a/t/t9401-git-cvsserver-crlf.sh b/t/t9401-git-cvsserver-crlf.sh index ff6d6fb47..1c5bc84fa 100755 --- a/t/t9401-git-cvsserver-crlf.sh +++ b/t/t9401-git-cvsserver-crlf.sh @@ -38,6 +38,25 @@ not_present() { fi } +check_status_options() { + (cd "$1" && + GIT_CONFIG="$git_config" cvs -Q status "$2" > "${WORKDIR}/status.out" 2>&1 + ) + if [ x"$?" != x"0" ] ; then + echo "Error from cvs status: $1 $2" >> "${WORKDIR}/marked.log" + return 1; + fi + got="$(sed -n -e 's/^[ ]*Sticky Options:[ ]*//p' "${WORKDIR}/status.out")" + expect="$3" + if [ x"$expect" = x"" ] ; then + expect="(none)" + fi + test x"$got" = x"$expect" + stat=$? + echo "cvs status: $1 $2 $stat '$3' '$got'" >> "${WORKDIR}/marked.log" + return $stat +} + cvs >/dev/null 2>&1 if test $? -ne 1 then @@ -233,6 +252,22 @@ test_expect_success 'cvs co another copy (guess)' ' marked_as cvswork2/subdir newfile.c "" ' +test_expect_success 'cvs status - sticky options' ' + check_status_options cvswork2 textfile.c "" && + check_status_options cvswork2 binfile.bin -kb && + check_status_options cvswork2 .gitattributes "" && + check_status_options cvswork2 mixedUp.c -kb && + check_status_options cvswork2 multiline.c -kb && + check_status_options cvswork2 multilineTxt.c "" && + check_status_options cvswork2/subdir withCr.bin -kb && + check_status_options cvswork2 subdir/withCr.bin -kb && + check_status_options cvswork2/subdir file.h "" && + check_status_options cvswork2 subdir/file.h "" && + check_status_options cvswork2/subdir unspecified.other "" && + check_status_options cvswork2/subdir newfile.bin "" && + check_status_options cvswork2/subdir newfile.c "" +' + test_expect_success 'add text (guess)' ' (cd cvswork && echo "simpleText" > simpleText.c && diff --git a/t/t9502-gitweb-standalone-parse-output.sh b/t/t9502-gitweb-standalone-parse-output.sh index 731e64c3a..86dfee2e4 100755 --- a/t/t9502-gitweb-standalone-parse-output.sh +++ b/t/t9502-gitweb-standalone-parse-output.sh @@ -40,7 +40,7 @@ check_snapshot () { echo "basename=$basename" grep "filename=.*$basename.tar" gitweb.headers >/dev/null 2>&1 && "$TAR" tf gitweb.body >file_list && - ! grep -v "^$prefix/" file_list + ! grep -v -e "^$prefix$" -e "^$prefix/" -e "^pax_global_header$" file_list } test_expect_success setup ' @@ -185,5 +185,20 @@ test_expect_success 'forks: project_index lists all projects (incl. forks)' ' test_cmp expected actual ' +xss() { + echo >&2 "Checking $1..." && + gitweb_run "$1" && + if grep "$TAG" gitweb.body; then + echo >&2 "xss: $TAG should have been quoted in output" + return 1 + fi + return 0 +} + +test_expect_success 'xss checks' ' + TAG="<magic-xss-tag>" && + xss "a=rss&p=$TAG" && + xss "a=rss&p=foo.git&f=$TAG" +' test_done diff --git a/t/t9604-cvsimport-timestamps.sh b/t/t9604-cvsimport-timestamps.sh new file mode 100755 index 000000000..1fd51423e --- /dev/null +++ b/t/t9604-cvsimport-timestamps.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +test_description='git cvsimport timestamps' +. ./lib-cvs.sh + +setup_cvs_test_repository t9604 + +test_expect_success 'check timestamps are UTC (TZ=CST6CDT)' ' + + TZ=CST6CDT git cvsimport -p"-x" -C module-1 module && + git cvsimport -p"-x" -C module-1 module && + ( + cd module-1 && + git log --format="%s %ai" + ) >actual-1 && + cat >expect-1 <<-EOF && + Rev 16 2006-10-29 07:00:01 +0000 + Rev 15 2006-10-29 06:59:59 +0000 + Rev 14 2006-04-02 08:00:01 +0000 + Rev 13 2006-04-02 07:59:59 +0000 + Rev 12 2005-12-01 00:00:00 +0000 + Rev 11 2005-11-01 00:00:00 +0000 + Rev 10 2005-10-01 00:00:00 +0000 + Rev 9 2005-09-01 00:00:00 +0000 + Rev 8 2005-08-01 00:00:00 +0000 + Rev 7 2005-07-01 00:00:00 +0000 + Rev 6 2005-06-01 00:00:00 +0000 + Rev 5 2005-05-01 00:00:00 +0000 + Rev 4 2005-04-01 00:00:00 +0000 + Rev 3 2005-03-01 00:00:00 +0000 + Rev 2 2005-02-01 00:00:00 +0000 + Rev 1 2005-01-01 00:00:00 +0000 + EOF + test_cmp actual-1 expect-1 +' + +test_expect_success 'check timestamps with author-specific timezones' ' + + cat >cvs-authors <<-EOF && + user1=User One <user1@domain.org> + user2=User Two <user2@domain.org> CST6CDT + user3=User Three <user3@domain.org> EST5EDT + user4=User Four <user4@domain.org> MST7MDT + EOF + git cvsimport -p"-x" -A cvs-authors -C module-2 module && + ( + cd module-2 && + git log --format="%s %ai %an" + ) >actual-2 && + cat >expect-2 <<-EOF && + Rev 16 2006-10-29 01:00:01 -0600 User Two + Rev 15 2006-10-29 01:59:59 -0500 User Two + Rev 14 2006-04-02 03:00:01 -0500 User Two + Rev 13 2006-04-02 01:59:59 -0600 User Two + Rev 12 2005-11-30 17:00:00 -0700 User Four + Rev 11 2005-10-31 19:00:00 -0500 User Three + Rev 10 2005-09-30 19:00:00 -0500 User Two + Rev 9 2005-09-01 00:00:00 +0000 User One + Rev 8 2005-07-31 18:00:00 -0600 User Four + Rev 7 2005-06-30 20:00:00 -0400 User Three + Rev 6 2005-05-31 19:00:00 -0500 User Two + Rev 5 2005-05-01 00:00:00 +0000 User One + Rev 4 2005-03-31 17:00:00 -0700 User Four + Rev 3 2005-02-28 19:00:00 -0500 User Three + Rev 2 2005-01-31 18:00:00 -0600 User Two + Rev 1 2005-01-01 00:00:00 +0000 User One + EOF + test_cmp actual-2 expect-2 +' + +test_done diff --git a/t/t9604/cvsroot/.gitattributes b/t/t9604/cvsroot/.gitattributes new file mode 100644 index 000000000..562b12e16 --- /dev/null +++ b/t/t9604/cvsroot/.gitattributes @@ -0,0 +1 @@ +* -whitespace diff --git a/t/t9604/cvsroot/CVSROOT/.gitignore b/t/t9604/cvsroot/CVSROOT/.gitignore new file mode 100644 index 000000000..3bb9b3417 --- /dev/null +++ b/t/t9604/cvsroot/CVSROOT/.gitignore @@ -0,0 +1,2 @@ +history +val-tags diff --git a/t/t9604/cvsroot/module/a,v b/t/t9604/cvsroot/module/a,v new file mode 100644 index 000000000..80658c3c8 --- /dev/null +++ b/t/t9604/cvsroot/module/a,v @@ -0,0 +1,264 @@ +head 1.16; +access; +symbols; +locks; strict; +comment @# @; + + +1.16 +date 2006.10.29.07.00.01; author user2; state Exp; +branches; +next 1.15; + +1.15 +date 2006.10.29.06.59.59; author user2; state Exp; +branches; +next 1.14; + +1.14 +date 2006.04.02.08.00.01; author user2; state Exp; +branches; +next 1.13; + +1.13 +date 2006.04.02.07.59.59; author user2; state Exp; +branches; +next 1.12; + +1.12 +date 2005.12.01.00.00.00; author user4; state Exp; +branches; +next 1.11; + +1.11 +date 2005.11.01.00.00.00; author user3; state Exp; +branches; +next 1.10; + +1.10 +date 2005.10.01.00.00.00; author user2; state Exp; +branches; +next 1.9; + +1.9 +date 2005.09.01.00.00.00; author user1; state Exp; +branches; +next 1.8; + +1.8 +date 2005.08.01.00.00.00; author user4; state Exp; +branches; +next 1.7; + +1.7 +date 2005.07.01.00.00.00; author user3; state Exp; +branches; +next 1.6; + +1.6 +date 2005.06.01.00.00.00; author user2; state Exp; +branches; +next 1.5; + +1.5 +date 2005.05.01.00.00.00; author user1; state Exp; +branches; +next 1.4; + +1.4 +date 2005.04.01.00.00.00; author user4; state Exp; +branches; +next 1.3; + +1.3 +date 2005.03.01.00.00.00; author user3; state Exp; +branches; +next 1.2; + +1.2 +date 2005.02.01.00.00.00; author user2; state Exp; +branches; +next 1.1; + +1.1 +date 2005.01.01.00.00.00; author user1; state Exp; +branches; +next ; + + +desc +@@ + + +1.16 +log +@Rev 16 +@ +text +@Rev 16 +@ + + +1.15 +log +@Rev 15 +@ +text +@d1 1 +a1 1 +Rev 15 +@ + + +1.14 +log +@Rev 14 +@ +text +@d1 1 +a1 1 +Rev 14 +@ + + +1.13 +log +@Rev 13 +@ +text +@d1 1 +a1 1 +Rev 13 +@ + + +1.12 +log +@Rev 12 +@ +text +@d1 1 +a1 1 +Rev 12 +@ + + +1.11 +log +@Rev 11 +@ +text +@d1 1 +a1 1 +Rev 11 +@ + + +1.10 +log +@Rev 10 +@ +text +@d1 1 +a1 1 +Rev 10 +@ + + +1.9 +log +@Rev 9 +@ +text +@d1 1 +a1 1 +Rev 9 +@ + + +1.8 +log +@Rev 8 +@ +text +@d1 1 +a1 1 +Rev 8 +@ + + +1.7 +log +@Rev 7 +@ +text +@d1 1 +a1 1 +Rev 7 +@ + + +1.6 +log +@Rev 6 +@ +text +@d1 1 +a1 1 +Rev 6 +@ + + +1.5 +log +@Rev 5 +@ +text +@d1 1 +a1 1 +Rev 5 +@ + + +1.4 +log +@Rev 4 +@ +text +@d1 1 +a1 1 +Rev 4 +@ + + +1.3 +log +@Rev 3 +@ +text +@d1 1 +a1 1 +Rev 3 +@ + + +1.2 +log +@Rev 2 +@ +text +@d1 1 +a1 1 +Rev 2 +@ + + +1.1 +log +@Rev 1 +@ +text +@d1 1 +a1 1 +Rev 1 +@ diff --git a/t/t9700/test.pl b/t/t9700/test.pl index 3b9b48408..0d4e36623 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -46,8 +46,7 @@ is($r->get_color("color.test.slot1", "red"), $ansi_green, "get_color"); # Save and restore STDERR; we will probably extract this into a # "dies_ok" method and possibly move the STDERR handling to Git.pm. open our $tmpstderr, ">&STDERR" or die "cannot save STDERR"; close STDERR; -eval { $r->config("test.dupstring") }; -ok($@, "config: duplicate entry in scalar context fails"); +is($r->config("test.dupstring"), "value2", "config: multivar"); eval { $r->config_bool("test.boolother") }; ok($@, "config_bool: non-boolean values fail"); open STDERR, ">&", $tmpstderr or die "cannot restore STDERR"; diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh index 0f410c45f..8c5979647 100755 --- a/t/t9800-git-p4-basic.sh +++ b/t/t9800-git-p4-basic.sh @@ -45,7 +45,8 @@ test_expect_success 'git p4 sync uninitialized repo' ' test_when_finished cleanup_git && ( cd "$git" && - test_must_fail git p4 sync + test_must_fail git p4 sync 2>errs && + test_i18ngrep "Perhaps you never did" errs ) ' @@ -126,150 +127,35 @@ test_expect_success 'clone two dirs, @all, conflicting files' ' ' test_expect_success 'exit when p4 fails to produce marshaled output' ' - badp4dir="$TRASH_DIRECTORY/badp4dir" && - mkdir "$badp4dir" && - test_when_finished "rm \"$badp4dir/p4\" && rmdir \"$badp4dir\"" && - cat >"$badp4dir"/p4 <<-EOF && + mkdir badp4dir && + test_when_finished "rm badp4dir/p4 && rmdir badp4dir" && + cat >badp4dir/p4 <<-EOF && #!$SHELL_PATH exit 1 EOF - chmod 755 "$badp4dir"/p4 && - PATH="$badp4dir:$PATH" git p4 clone --dest="$git" //depot >errs 2>&1 ; retval=$? && - test $retval -eq 1 && - test_must_fail grep -q Traceback errs -' - -test_expect_success 'add p4 files with wildcards in the names' ' - ( - cd "$cli" && - echo file-wild-hash >file-wild#hash && - echo file-wild-star >file-wild\*star && - echo file-wild-at >file-wild@at && - echo file-wild-percent >file-wild%percent && - p4 add -f file-wild* && - p4 submit -d "file wildcards" - ) -' - -test_expect_success 'wildcard files git p4 clone' ' - git p4 clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - test -f file-wild#hash && - test -f file-wild\*star && - test -f file-wild@at && - test -f file-wild%percent - ) -' - -test_expect_success 'wildcard files submit back to p4, add' ' - test_when_finished cleanup_git && - git p4 clone --dest="$git" //depot && - ( - cd "$git" && - echo git-wild-hash >git-wild#hash && - echo git-wild-star >git-wild\*star && - echo git-wild-at >git-wild@at && - echo git-wild-percent >git-wild%percent && - git add git-wild* && - git commit -m "add some wildcard filenames" && - git config git-p4.skipSubmitEdit true && - git p4 submit - ) && - ( - cd "$cli" && - test_path_is_file git-wild#hash && - test_path_is_file git-wild\*star && - test_path_is_file git-wild@at && - test_path_is_file git-wild%percent - ) -' - -test_expect_success 'wildcard files submit back to p4, modify' ' - test_when_finished cleanup_git && - git p4 clone --dest="$git" //depot && - ( - cd "$git" && - echo new-line >>git-wild#hash && - echo new-line >>git-wild\*star && - echo new-line >>git-wild@at && - echo new-line >>git-wild%percent && - git add git-wild* && - git commit -m "modify the wildcard files" && - git config git-p4.skipSubmitEdit true && - git p4 submit - ) && + chmod 755 badp4dir/p4 && ( - cd "$cli" && - test_line_count = 2 git-wild#hash && - test_line_count = 2 git-wild\*star && - test_line_count = 2 git-wild@at && - test_line_count = 2 git-wild%percent - ) -' - -test_expect_success 'wildcard files submit back to p4, copy' ' - test_when_finished cleanup_git && - git p4 clone --dest="$git" //depot && - ( - cd "$git" && - cp file2 git-wild-cp#hash && - git add git-wild-cp#hash && - cp git-wild\*star file-wild-3 && - git add file-wild-3 && - git commit -m "wildcard copies" && - git config git-p4.detectCopies true && - git config git-p4.detectCopiesHarder true && - git config git-p4.skipSubmitEdit true && - git p4 submit + PATH="$TRASH_DIRECTORY/badp4dir:$PATH" && + export PATH && + test_expect_code 1 git p4 clone --dest="$git" //depot >errs 2>&1 ) && - ( - cd "$cli" && - test_path_is_file git-wild-cp#hash && - test_path_is_file file-wild-3 - ) + cat errs && + ! test_i18ngrep Traceback errs ' -test_expect_success 'wildcard files submit back to p4, rename' ' +# Hide a file from p4d, make sure we catch its complaint. This won't fail in +# p4 changes, files, or describe; just in p4 print. If P4CLIENT is unset, the +# message will include "Librarian checkout". +test_expect_success 'exit gracefully for p4 server errors' ' + test_when_finished "mv \"$db\"/depot/file1,v,hidden \"$db\"/depot/file1,v" && + mv "$db"/depot/file1,v "$db"/depot/file1,v,hidden && test_when_finished cleanup_git && - git p4 clone --dest="$git" //depot && - ( - cd "$git" && - git mv git-wild@at file-wild-4 && - git mv file-wild-3 git-wild-cp%percent && - git commit -m "wildcard renames" && - git config git-p4.detectRenames true && - git config git-p4.skipSubmitEdit true && - git p4 submit - ) && - ( - cd "$cli" && - test_path_is_missing git-wild@at && - test_path_is_file git-wild-cp%percent - ) -' - -test_expect_success 'wildcard files submit back to p4, delete' ' - test_when_finished cleanup_git && - git p4 clone --dest="$git" //depot && - ( - cd "$git" && - git rm git-wild* && - git commit -m "delete the wildcard files" && - git config git-p4.skipSubmitEdit true && - git p4 submit - ) && - ( - cd "$cli" && - test_path_is_missing git-wild#hash && - test_path_is_missing git-wild\*star && - test_path_is_missing git-wild@at && - test_path_is_missing git-wild%percent - ) + test_expect_code 1 git p4 clone --dest="$git" //depot@1 >out 2>err && + test_i18ngrep "Error from p4 print" err ' -test_expect_success 'clone bare' ' +test_expect_success 'clone --bare should make a bare repository' ' + rm -rf "$git" && git p4 clone --dest="$git" --bare //depot && test_when_finished cleanup_git && ( @@ -280,138 +166,6 @@ test_expect_success 'clone bare' ' ) ' -p4_add_user() { - name=$1 fullname=$2 && - p4 user -f -i <<-EOF && - User: $name - Email: $name@localhost - FullName: $fullname - EOF - p4 passwd -P secret $name -} - -p4_grant_admin() { - name=$1 && - { - p4 protect -o && - echo " admin user $name * //depot/..." - } | p4 protect -i -} - -p4_check_commit_author() { - file=$1 user=$2 && - p4 changes -m 1 //depot/$file | grep -q $user -} - -make_change_by_user() { - file=$1 name=$2 email=$3 && - echo "username: a change by $name" >>"$file" && - git add "$file" && - git commit --author "$name <$email>" -m "a change by $name" -} - -# Test username support, submitting as user 'alice' -test_expect_success 'preserve users' ' - p4_add_user alice Alice && - p4_add_user bob Bob && - p4_grant_admin alice && - git p4 clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - echo "username: a change by alice" >>file1 && - echo "username: a change by bob" >>file2 && - git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 && - git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 && - git config git-p4.skipSubmitEditCheck true && - P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user && - p4_check_commit_author file1 alice && - p4_check_commit_author file2 bob - ) -' - -# Test username support, submitting as bob, who lacks admin rights. Should -# not submit change to p4 (git diff should show deltas). -test_expect_success 'refuse to preserve users without perms' ' - git p4 clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEditCheck true && - echo "username-noperms: a change by alice" >>file1 && - git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 && - P4EDITOR=touch P4USER=bob P4PASSWD=secret && - export P4EDITOR P4USER P4PASSWD && - test_must_fail git p4 commit --preserve-user && - ! git diff --exit-code HEAD..p4/master - ) -' - -# What happens with unknown author? Without allowMissingP4Users it should fail. -test_expect_success 'preserve user where author is unknown to p4' ' - git p4 clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEditCheck true && - echo "username-bob: a change by bob" >>file1 && - git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 && - echo "username-unknown: a change by charlie" >>file1 && - git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 && - P4EDITOR=touch P4USER=alice P4PASSWD=secret && - export P4EDITOR P4USER P4PASSWD && - test_must_fail git p4 commit --preserve-user && - ! git diff --exit-code HEAD..p4/master && - - echo "$0: repeat with allowMissingP4Users enabled" && - git config git-p4.allowMissingP4Users true && - git config git-p4.preserveUser true && - git p4 commit && - git diff --exit-code HEAD..p4/master && - p4_check_commit_author file1 alice - ) -' - -# If we're *not* using --preserve-user, git p4 should warn if we're submitting -# changes that are not all ours. -# Test: user in p4 and user unknown to p4. -# Test: warning disabled and user is the same. -test_expect_success 'not preserving user with mixed authorship' ' - git p4 clone --dest="$git" //depot && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEditCheck true && - p4_add_user derek Derek && - - make_change_by_user usernamefile3 Derek derek@localhost && - P4EDITOR=cat P4USER=alice P4PASSWD=secret && - export P4EDITOR P4USER P4PASSWD && - git p4 commit |\ - grep "git author derek@localhost does not match" && - - make_change_by_user usernamefile3 Charlie charlie@localhost && - git p4 commit |\ - grep "git author charlie@localhost does not match" && - - make_change_by_user usernamefile3 alice alice@localhost && - git p4 commit |\ - test_must_fail grep "git author.*does not match" && - - git config git-p4.skipUserNameCheck true && - make_change_by_user usernamefile3 Charlie charlie@localhost && - git p4 commit |\ - test_must_fail grep "git author.*does not match" && - - p4_check_commit_author usernamefile3 alice - ) -' - -marshal_dump() { - what=$1 - "$PYTHON_PATH" -c 'import marshal, sys; d = marshal.load(sys.stdin); print d["'$what'"]' -} - # Sleep a bit so that the top-most p4 change did not happen "now". Then # import the repo and make sure that the initial import has the same time # as the top-most change. @@ -429,143 +183,15 @@ test_expect_success 'initial import time from top change time' ' ) ' -# Rename a file and confirm that rename is not detected in P4. -# Rename the new file again with detectRenames option enabled and confirm that -# this is detected in P4. -# Rename the new file again adding an extra line, configure a big threshold in -# detectRenames and confirm that rename is not detected in P4. -# Repeat, this time with a smaller threshold and confirm that the rename is -# detected in P4. -test_expect_success 'detect renames' ' - git p4 clone --dest="$git" //depot@all && - test_when_finished cleanup_git && - ( - cd "$git" && - git config git-p4.skipSubmitEdit true && - - git mv file1 file4 && - git commit -a -m "Rename file1 to file4" && - git diff-tree -r -M HEAD && - git p4 submit && - p4 filelog //depot/file4 && - p4 filelog //depot/file4 | test_must_fail grep -q "branch from" && - - git mv file4 file5 && - git commit -a -m "Rename file4 to file5" && - git diff-tree -r -M HEAD && - git config git-p4.detectRenames true && - git p4 submit && - p4 filelog //depot/file5 && - p4 filelog //depot/file5 | grep -q "branch from //depot/file4" && - - git mv file5 file6 && - echo update >>file6 && - git add file6 && - git commit -a -m "Rename file5 to file6 with changes" && - git diff-tree -r -M HEAD && - level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && - test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && - git config git-p4.detectRenames $(($level + 2)) && - git p4 submit && - p4 filelog //depot/file6 && - p4 filelog //depot/file6 | test_must_fail grep -q "branch from" && - - git mv file6 file7 && - echo update >>file7 && - git add file7 && - git commit -a -m "Rename file6 to file7 with changes" && - git diff-tree -r -M HEAD && - level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && - test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && - git config git-p4.detectRenames $(($level - 2)) && - git p4 submit && - p4 filelog //depot/file7 && - p4 filelog //depot/file7 | grep -q "branch from //depot/file6" - ) -' - -# Copy a file and confirm that copy is not detected in P4. -# Copy a file with detectCopies option enabled and confirm that copy is not -# detected in P4. -# Modify and copy a file with detectCopies option enabled and confirm that copy -# is detected in P4. -# Copy a file with detectCopies and detectCopiesHarder options enabled and -# confirm that copy is detected in P4. -# Modify and copy a file, configure a bigger threshold in detectCopies and -# confirm that copy is not detected in P4. -# Modify and copy a file, configure a smaller threshold in detectCopies and -# confirm that copy is detected in P4. -test_expect_success 'detect copies' ' - git p4 clone --dest="$git" //depot@all && +test_expect_success 'unresolvable host in P4PORT should display error' ' test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && ( cd "$git" && - git config git-p4.skipSubmitEdit true && - - cp file2 file8 && - git add file8 && - git commit -a -m "Copy file2 to file8" && - git diff-tree -r -C HEAD && - git p4 submit && - p4 filelog //depot/file8 && - p4 filelog //depot/file8 | test_must_fail grep -q "branch from" && - - cp file2 file9 && - git add file9 && - git commit -a -m "Copy file2 to file9" && - git diff-tree -r -C HEAD && - git config git-p4.detectCopies true && - git p4 submit && - p4 filelog //depot/file9 && - p4 filelog //depot/file9 | test_must_fail grep -q "branch from" && - - echo "file2" >>file2 && - cp file2 file10 && - git add file2 file10 && - git commit -a -m "Modify and copy file2 to file10" && - git diff-tree -r -C HEAD && - git p4 submit && - p4 filelog //depot/file10 && - p4 filelog //depot/file10 | grep -q "branch from //depot/file" && - - cp file2 file11 && - git add file11 && - git commit -a -m "Copy file2 to file11" && - git diff-tree -r -C --find-copies-harder HEAD && - src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 && - git config git-p4.detectCopiesHarder true && - git p4 submit && - p4 filelog //depot/file11 && - p4 filelog //depot/file11 | grep -q "branch from //depot/file" && - - cp file2 file12 && - echo "some text" >>file12 && - git add file12 && - git commit -a -m "Copy file2 to file12 with changes" && - git diff-tree -r -C --find-copies-harder HEAD && - level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && - test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && - src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 && - git config git-p4.detectCopies $(($level + 2)) && - git p4 submit && - p4 filelog //depot/file12 && - p4 filelog //depot/file12 | test_must_fail grep -q "branch from" && - - cp file2 file13 && - echo "different text" >>file13 && - git add file13 && - git commit -a -m "Copy file2 to file13 with changes" && - git diff-tree -r -C --find-copies-harder HEAD && - level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && - test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && - src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && - test "$src" = file10 && - git config git-p4.detectCopies $(($level - 2)) && - git p4 submit && - p4 filelog //depot/file13 && - p4 filelog //depot/file13 | grep -q "branch from //depot/file" + P4PORT=nosuchhost:65537 && + export P4PORT && + test_expect_code 1 git p4 sync >out 2>err && + grep "connect to nosuchhost" err ) ' diff --git a/t/t9801-git-p4-branch.sh b/t/t9801-git-p4-branch.sh index 99fe16b72..9730821c3 100755 --- a/t/t9801-git-p4-branch.sh +++ b/t/t9801-git-p4-branch.sh @@ -410,6 +410,83 @@ test_expect_failure 'git p4 clone file subset branch' ' test_path_is_missing file3 ) ' + +# From a report in http://stackoverflow.com/questions/11893688 +# where --use-client-spec caused branch prefixes not to be removed; +# every file in git appeared into a subdirectory of the branch name. +test_expect_success 'use-client-spec detect-branches setup' ' + rm -rf "$cli" && + mkdir "$cli" && + ( + cd "$cli" && + client_view "//depot/usecs/... //client/..." && + mkdir b1 && + echo b1/b1-file1 >b1/b1-file1 && + p4 add b1/b1-file1 && + p4 submit -d "b1/b1-file1" && + + p4 integrate //depot/usecs/b1/... //depot/usecs/b2/... && + p4 submit -d "b1 -> b2" && + p4 branch -i <<-EOF && + Branch: b2 + View: //depot/usecs/b1/... //depot/usecs/b2/... + EOF + + echo b2/b2-file2 >b2/b2-file2 && + p4 add b2/b2-file2 && + p4 submit -d "b2/b2-file2" + ) +' + +test_expect_success 'use-client-spec detect-branches files in top-level' ' + test_when_finished cleanup_git && + test_create_repo "$git" && + ( + cd "$git" && + git p4 sync --detect-branches --use-client-spec //depot/usecs@all && + git checkout -b master p4/usecs/b1 && + test_path_is_file b1-file1 && + test_path_is_missing b2-file2 && + test_path_is_missing b1 && + test_path_is_missing b2 && + + git checkout -b b2 p4/usecs/b2 && + test_path_is_file b1-file1 && + test_path_is_file b2-file2 && + test_path_is_missing b1 && + test_path_is_missing b2 + ) +' + +test_expect_success 'use-client-spec detect-branches skips branches setup' ' + ( + cd "$cli" && + + p4 integrate //depot/usecs/b1/... //depot/usecs/b3/... && + p4 submit -d "b1 -> b3" && + p4 branch -i <<-EOF && + Branch: b3 + View: //depot/usecs/b1/... //depot/usecs/b3/... + EOF + + echo b3/b3-file3 >b3/b3-file3 && + p4 add b3/b3-file3 && + p4 submit -d "b3/b3-file3" + ) +' + +test_expect_success 'use-client-spec detect-branches skips branches' ' + client_view "//depot/usecs/... //client/..." \ + "-//depot/usecs/b3/... //client/b3/..." && + test_when_finished cleanup_git && + test_create_repo "$git" && + ( + cd "$git" && + git p4 sync --detect-branches --use-client-spec //depot/usecs@all && + test_must_fail git rev-parse refs/remotes/p4/usecs/b3 + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9805-git-p4-skip-submit-edit.sh b/t/t9805-git-p4-skip-submit-edit.sh index 353dcfbe0..ff2cc7970 100755 --- a/t/t9805-git-p4-skip-submit-edit.sh +++ b/t/t9805-git-p4-skip-submit-edit.sh @@ -38,7 +38,7 @@ test_expect_success 'no config, unedited, say no' ' cd "$git" && echo line >>file1 && git commit -a -m "change 3 (not really)" && - printf "bad response\nn\n" | git p4 submit && + printf "bad response\nn\n" | test_expect_code 1 git p4 submit && p4 changes //depot/... >wc && test_line_count = 2 wc ) @@ -78,20 +78,19 @@ test_expect_success 'skipSubmitEditCheck' ' test_expect_success 'no config, edited' ' git p4 clone --dest="$git" //depot && test_when_finished cleanup_git && - ed="$TRASH_DIRECTORY/ed.sh" && - test_when_finished "rm \"$ed\"" && - cat >"$ed" <<-EOF && + test_when_finished "rm ed.sh" && + cat >ed.sh <<-EOF && #!$SHELL_PATH sleep 1 touch "\$1" exit 0 EOF - chmod 755 "$ed" && + chmod 755 ed.sh && ( cd "$git" && echo line >>file1 && git commit -a -m "change 5" && - P4EDITOR="" EDITOR="\"$ed\"" git p4 submit && + P4EDITOR="" EDITOR="\"$TRASH_DIRECTORY/ed.sh\"" git p4 submit && p4 changes //depot/... >wc && test_line_count = 5 wc ) diff --git a/t/t9806-git-p4-options.sh b/t/t9806-git-p4-options.sh index 289236783..fa40cc8bb 100755 --- a/t/t9806-git-p4-options.sh +++ b/t/t9806-git-p4-options.sh @@ -39,10 +39,9 @@ test_expect_success 'clone --branch' ' ' test_expect_success 'clone --changesfile' ' - cf="$TRASH_DIRECTORY/cf" && - test_when_finished "rm \"$cf\"" && - printf "1\n3\n" >"$cf" && - git p4 clone --changesfile="$cf" --dest="$git" //depot && + test_when_finished "rm cf" && + printf "1\n3\n" >cf && + git p4 clone --changesfile="$TRASH_DIRECTORY/cf" --dest="$git" //depot && test_when_finished cleanup_git && ( cd "$git" && @@ -55,10 +54,9 @@ test_expect_success 'clone --changesfile' ' ' test_expect_success 'clone --changesfile, @all' ' - cf="$TRASH_DIRECTORY/cf" && - test_when_finished "rm \"$cf\"" && - printf "1\n3\n" >"$cf" && - test_must_fail git p4 clone --changesfile="$cf" --dest="$git" //depot@all + test_when_finished "rm cf" && + printf "1\n3\n" >cf && + test_must_fail git p4 clone --changesfile="$TRASH_DIRECTORY/cf" --dest="$git" //depot@all ' # imports both master and p4/master in refs/heads @@ -128,7 +126,7 @@ test_expect_success 'clone --use-client-spec' ' exec >/dev/null && test_must_fail git p4 clone --dest="$git" --use-client-spec ) && - cli2="$TRASH_DIRECTORY/cli2" && + cli2=$(test-path-utils real_path "$TRASH_DIRECTORY/cli2") && mkdir -p "$cli2" && test_when_finished "rmdir \"$cli2\"" && ( @@ -151,7 +149,6 @@ test_expect_success 'clone --use-client-spec' ' cleanup_git && # same thing again, this time with variable instead of option - mkdir "$git" && ( cd "$git" && git init && diff --git a/t/t9807-git-p4-submit.sh b/t/t9807-git-p4-submit.sh index f23b4c362..0ae048f29 100755 --- a/t/t9807-git-p4-submit.sh +++ b/t/t9807-git-p4-submit.sh @@ -54,6 +54,47 @@ test_expect_success 'submit --origin' ' ) ' +test_expect_success 'submit --dry-run' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + test_commit "dry-run1" && + test_commit "dry-run2" && + git p4 submit --dry-run >out && + test_i18ngrep "Would apply" out + ) && + ( + cd "$cli" && + test_path_is_missing "dry-run1.t" && + test_path_is_missing "dry-run2.t" + ) +' + +test_expect_success 'submit --dry-run --export-labels' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo dry-run1 >dry-run1 && + git add dry-run1 && + git commit -m "dry-run1" dry-run1 && + git config git-p4.skipSubmitEdit true && + git p4 submit && + echo dry-run2 >dry-run2 && + git add dry-run2 && + git commit -m "dry-run2" dry-run2 && + git tag -m "dry-run-tag1" dry-run-tag1 HEAD^ && + git p4 submit --dry-run --export-labels >out && + test_i18ngrep "Would create p4 label" out + ) && + ( + cd "$cli" && + test_path_is_file "dry-run1" && + test_path_is_missing "dry-run2" + ) +' + test_expect_success 'submit with allowSubmit' ' test_when_finished cleanup_git && git p4 clone --dest="$git" //depot && @@ -182,6 +223,185 @@ test_expect_success 'submit rename' ' ) ' +# +# Converting git commit message to p4 change description, including +# parsing out the optional Jobs: line. +# +test_expect_success 'simple one-line description' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc2 >desc2 && + git add desc2 && + cat >msg <<-EOF && + One-line description line for desc2. + EOF + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + git p4 submit && + change=$(p4 -G changes -m 1 //depot/... | \ + marshal_dump change) && + # marshal_dump always adds a newline + p4 -G describe $change | marshal_dump desc | sed \$d >pmsg && + test_cmp msg pmsg + ) +' + +test_expect_success 'description with odd formatting' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc3 >desc3 && + git add desc3 && + ( + printf "subject line\n\n\tExtra tab\nline.\n\n" && + printf "Description:\n\tBogus description marker\n\n" && + # git commit eats trailing newlines; only use one + printf "Files:\n\tBogus descs marker\n" + ) >msg && + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + git p4 submit && + change=$(p4 -G changes -m 1 //depot/... | \ + marshal_dump change) && + # marshal_dump always adds a newline + p4 -G describe $change | marshal_dump desc | sed \$d >pmsg && + test_cmp msg pmsg + ) +' + +make_job() { + name="$1" && + tab="$(printf \\t)" && + p4 job -o | \ + sed -e "/^Job:/s/.*/Job: $name/" \ + -e "/^Description/{ n; s/.*/$tab job text/; }" | \ + p4 job -i +} + +test_expect_success 'description with Jobs section at end' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc4 >desc4 && + git add desc4 && + echo 6060842 >jobname && + ( + printf "subject line\n\n\tExtra tab\nline.\n\n" && + printf "Files:\n\tBogus files marker\n" && + printf "Junk: 3164175\n" && + printf "Jobs: $(cat jobname)\n" + ) >msg && + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + # build a job + make_job $(cat jobname) && + git p4 submit && + change=$(p4 -G changes -m 1 //depot/... | \ + marshal_dump change) && + # marshal_dump always adds a newline + p4 -G describe $change | marshal_dump desc | sed \$d >pmsg && + # make sure Jobs line and all following is gone + sed "/^Jobs:/,\$d" msg >jmsg && + test_cmp jmsg pmsg && + # make sure p4 knows about job + p4 -G describe $change | marshal_dump job0 >job0 && + test_cmp jobname job0 + ) +' + +test_expect_success 'description with Jobs and values on separate lines' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc5 >desc5 && + git add desc5 && + echo PROJ-6060842 >jobname1 && + echo PROJ-6060847 >jobname2 && + ( + printf "subject line\n\n\tExtra tab\nline.\n\n" && + printf "Files:\n\tBogus files marker\n" && + printf "Junk: 3164175\n" && + printf "Jobs:\n" && + printf "\t$(cat jobname1)\n" && + printf "\t$(cat jobname2)\n" + ) >msg && + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + # build two jobs + make_job $(cat jobname1) && + make_job $(cat jobname2) && + git p4 submit && + change=$(p4 -G changes -m 1 //depot/... | \ + marshal_dump change) && + # marshal_dump always adds a newline + p4 -G describe $change | marshal_dump desc | sed \$d >pmsg && + # make sure Jobs line and all following is gone + sed "/^Jobs:/,\$d" msg >jmsg && + test_cmp jmsg pmsg && + # make sure p4 knows about the two jobs + p4 -G describe $change >change && + ( + marshal_dump job0 <change && + marshal_dump job1 <change + ) | sort >jobs && + cat jobname1 jobname2 | sort >expected && + test_cmp expected jobs + ) +' + +test_expect_success 'description with Jobs section and bogus following text' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo desc6 >desc6 && + git add desc6 && + echo 6060843 >jobname && + ( + printf "subject line\n\n\tExtra tab\nline.\n\n" && + printf "Files:\n\tBogus files marker\n" && + printf "Junk: 3164175\n" && + printf "Jobs: $(cat jobname)\n" && + printf "MoreJunk: 3711\n" + ) >msg && + git commit -F - <msg && + git config git-p4.skipSubmitEdit true && + # build a job + make_job $(cat jobname) && + test_must_fail git p4 submit 2>err && + test_i18ngrep "Unknown field name" err + ) && + ( + cd "$cli" && + p4 revert desc6 && + rm desc6 + ) +' + +test_expect_success 'submit --prepare-p4-only' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo prep-only-add >prep-only-add && + git add prep-only-add && + git commit -m "prep only add" && + git p4 submit --prepare-p4-only >out && + test_i18ngrep "prepared for submission" out && + test_i18ngrep "must be deleted" out + ) && + ( + cd "$cli" && + test_path_is_file prep-only-add && + p4 fstat -T action prep-only-add | grep -w add + ) +' + test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9808-git-p4-chdir.sh b/t/t9808-git-p4-chdir.sh index 2f8014a60..dc92e60cd 100755 --- a/t/t9808-git-p4-chdir.sh +++ b/t/t9808-git-p4-chdir.sh @@ -21,7 +21,7 @@ test_expect_success 'init depot' ' # environment variable is set test_expect_success 'P4CONFIG and absolute dir clone' ' printf "P4PORT=$P4PORT\nP4CLIENT=$P4CLIENT\n" >p4config && - test_when_finished "rm \"$TRASH_DIRECTORY/p4config\"" && + test_when_finished "rm p4config" && test_when_finished cleanup_git && ( P4CONFIG=p4config && export P4CONFIG && @@ -33,7 +33,7 @@ test_expect_success 'P4CONFIG and absolute dir clone' ' # same thing, but with relative directory name, note missing $ on --dest test_expect_success 'P4CONFIG and relative dir clone' ' printf "P4PORT=$P4PORT\nP4CLIENT=$P4CLIENT\n" >p4config && - test_when_finished "rm \"$TRASH_DIRECTORY/p4config\"" && + test_when_finished "rm p4config" && test_when_finished cleanup_git && ( P4CONFIG=p4config && export P4CONFIG && diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh index 7d993ef80..281be2917 100755 --- a/t/t9809-git-p4-client-view.sh +++ b/t/t9809-git-p4-client-view.sh @@ -9,23 +9,6 @@ test_expect_success 'start p4d' ' ' # -# Construct a client with this list of View lines -# -client_view() { - ( - cat <<-EOF && - Client: client - Description: client - Root: $cli - View: - EOF - for arg ; do - printf "\t$arg\n" - done - ) | p4 client -i -} - -# # Verify these files exist, exactly. Caller creates # a list of files in file "files". # diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh index b00ad09d2..34fbc9000 100755 --- a/t/t9810-git-p4-rcs.sh +++ b/t/t9810-git-p4-rcs.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-p4 rcs keywords' +test_description='git p4 rcs keywords' . ./lib-git-p4.sh @@ -26,10 +26,8 @@ test_expect_success 'init depot' ' line7 line8 EOF - cp filek fileko && - sed -i "s/Revision/Revision: do not scrub me/" fileko - cp fileko file_text && - sed -i "s/Id/Id: do not scrub me/" file_text + sed "s/Revision/Revision: do not scrub me/" <filek >fileko && + sed "s/Id/Id: do not scrub me/" <fileko >file_text && p4 add -t text+k filek && p4 submit -d "filek" && p4 add -t text+ko fileko && @@ -88,7 +86,8 @@ test_expect_success 'edit far away from RCS lines' ' ( cd "$git" && git config git-p4.skipSubmitEdit true && - sed -i "s/^line7/line7 edit/" filek && + sed "s/^line7/line7 edit/" <filek >filek.tmp && + mv -f filek.tmp filek && git commit -m "filek line7 edit" filek && git p4 submit && scrub_k_check filek @@ -105,7 +104,8 @@ test_expect_success 'edit near RCS lines' ' cd "$git" && git config git-p4.skipSubmitEdit true && git config git-p4.attemptRCSCleanup true && - sed -i "s/^line4/line4 edit/" filek && + sed "s/^line4/line4 edit/" <filek >filek.tmp && + mv -f filek.tmp filek && git commit -m "filek line4 edit" filek && git p4 submit && scrub_k_check filek @@ -122,7 +122,8 @@ test_expect_success 'edit keyword lines' ' cd "$git" && git config git-p4.skipSubmitEdit true && git config git-p4.attemptRCSCleanup true && - sed -i "/Revision/d" filek && + sed "/Revision/d" <filek >filek.tmp && + mv -f filek.tmp filek && git commit -m "filek remove Revision line" filek && git p4 submit && scrub_k_check filek @@ -139,7 +140,8 @@ test_expect_success 'scrub ko files differently' ' cd "$git" && git config git-p4.skipSubmitEdit true && git config git-p4.attemptRCSCleanup true && - sed -i "s/^line4/line4 edit/" fileko && + sed "s/^line4/line4 edit/" <fileko >fileko.tmp && + mv -f fileko.tmp fileko && git commit -m "fileko line4 edit" fileko && git p4 submit && scrub_ko_check fileko && @@ -147,7 +149,7 @@ test_expect_success 'scrub ko files differently' ' ) ' -# hack; git-p4 submit should do it on its own +# hack; git p4 submit should do it on its own test_expect_success 'cleanup after failure' ' ( cd "$cli" && @@ -155,14 +157,30 @@ test_expect_success 'cleanup after failure' ' ) ' +# perl $File:: bug check +test_expect_success 'ktext expansion should not expand multi-line $File::' ' + ( + cd "$cli" && + cat >lv.pm <<-\EOF + my $wanted = sub { my $f = $File::Find::name; + if ( -f && $f =~ /foo/ ) { + EOF + p4 add -t ktext lv.pm && + p4 submit -d "lv.pm" + ) && + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + test_cmp "$cli/lv.pm" lv.pm + ) +' + # # Do not scrub anything but +k or +ko files. Sneak a change into # the cli file so that submit will get a conflict. Make sure that # scrubbing doesn't make a mess of things. # -# Assumes that git-p4 exits leaving the p4 file open, with the -# conflict-generating patch unapplied. -# # This might happen only if the git repo is behind the p4 repo at # submit time, and there is a conflict. # @@ -173,27 +191,26 @@ test_expect_success 'do not scrub plain text' ' cd "$git" && git config git-p4.skipSubmitEdit true && git config git-p4.attemptRCSCleanup true && - sed -i "s/^line4/line4 edit/" file_text && + sed "s/^line4/line4 edit/" <file_text >file_text.tmp && + mv -f file_text.tmp file_text && git commit -m "file_text line4 edit" file_text && ( cd "$cli" && p4 open file_text && - sed -i "s/^line5/line5 p4 edit/" file_text && + sed "s/^line5/line5 p4 edit/" <file_text >file_text.tmp && + mv -f file_text.tmp file_text && p4 submit -d "file5 p4 edit" ) && - ! git p4 submit && + echo s | test_expect_code 1 git p4 submit && ( - # exepct something like: - # file_text - file(s) not opened on this client - # but not copious diff output + # make sure the file is not left open cd "$cli" && - p4 diff file_text >wc && - test_line_count = 1 wc + ! p4 fstat -T action file_text ) ) ' -# hack; git-p4 submit should do it on its own +# hack; git p4 submit should do it on its own test_expect_success 'cleanup after failure 2' ' ( cd "$cli" && @@ -244,7 +261,7 @@ test_expect_success 'cope with rcs keyword expansion damage' ' cd "$git" && git config git-p4.skipSubmitEdit true && git config git-p4.attemptRCSCleanup true && - (cd ../cli && p4_append_to_file kwfile1.c) && + (cd "$cli" && p4_append_to_file kwfile1.c) && old_lines=$(wc -l <kwfile1.c) && "$PERL_PATH" -n -i -e "print unless m/Revision:/" kwfile1.c && new_lines=$(wc -l <kwfile1.c) && @@ -343,44 +360,6 @@ test_expect_failure 'Add keywords in git which do not match the default p4 value ) ' -# Check that the existing merge conflict handling still works. -# Modify kwfile1.c in git, and delete in p4. We should be able -# to skip the git commit. -# -test_expect_success 'merge conflict handling still works' ' - test_when_finished cleanup_git && - ( - cd "$cli" && - echo "Hello:\$Id\$" >merge2.c && - echo "World" >>merge2.c && - p4 add -t ktext merge2.c && - p4 submit -d "add merge test file" - ) && - git p4 clone --dest="$git" //depot && - ( - cd "$git" && - sed -e "/Hello/d" merge2.c >merge2.c.tmp && - mv merge2.c.tmp merge2.c && - git add merge2.c && - git commit -m "Modifying merge2.c" - ) && - ( - cd "$cli" && - p4 delete merge2.c && - p4 submit -d "remove merge test file" - ) && - ( - cd "$git" && - test -f merge2.c && - git config git-p4.skipSubmitEdit true && - git config git-p4.attemptRCSCleanup true && - !(echo "s" | git p4 submit) && - git rebase --skip && - ! test -f merge2.c - ) -' - - test_expect_success 'kill p4d' ' kill_p4d ' diff --git a/t/t9812-git-p4-wildcards.sh b/t/t9812-git-p4-wildcards.sh new file mode 100755 index 000000000..143d41305 --- /dev/null +++ b/t/t9812-git-p4-wildcards.sh @@ -0,0 +1,147 @@ +#!/bin/sh + +test_description='git p4 wildcards' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'add p4 files with wildcards in the names' ' + ( + cd "$cli" && + printf "file2\nhas\nsome\nrandom\ntext\n" >file2 && + p4 add file2 && + echo file-wild-hash >file-wild#hash && + echo file-wild-star >file-wild\*star && + echo file-wild-at >file-wild@at && + echo file-wild-percent >file-wild%percent && + p4 add -f file-wild* && + p4 submit -d "file wildcards" + ) +' + +test_expect_success 'wildcard files git p4 clone' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + test -f file-wild#hash && + test -f file-wild\*star && + test -f file-wild@at && + test -f file-wild%percent + ) +' + +test_expect_success 'wildcard files submit back to p4, add' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo git-wild-hash >git-wild#hash && + echo git-wild-star >git-wild\*star && + echo git-wild-at >git-wild@at && + echo git-wild-percent >git-wild%percent && + git add git-wild* && + git commit -m "add some wildcard filenames" && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file git-wild#hash && + test_path_is_file git-wild\*star && + test_path_is_file git-wild@at && + test_path_is_file git-wild%percent + ) +' + +test_expect_success 'wildcard files submit back to p4, modify' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo new-line >>git-wild#hash && + echo new-line >>git-wild\*star && + echo new-line >>git-wild@at && + echo new-line >>git-wild%percent && + git add git-wild* && + git commit -m "modify the wildcard files" && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_line_count = 2 git-wild#hash && + test_line_count = 2 git-wild\*star && + test_line_count = 2 git-wild@at && + test_line_count = 2 git-wild%percent + ) +' + +test_expect_success 'wildcard files submit back to p4, copy' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + cp file2 git-wild-cp#hash && + git add git-wild-cp#hash && + cp git-wild\*star file-wild-3 && + git add file-wild-3 && + git commit -m "wildcard copies" && + git config git-p4.detectCopies true && + git config git-p4.detectCopiesHarder true && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file git-wild-cp#hash && + test_path_is_file file-wild-3 + ) +' + +test_expect_success 'wildcard files submit back to p4, rename' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git mv git-wild@at file-wild-4 && + git mv file-wild-3 git-wild-cp%percent && + git commit -m "wildcard renames" && + git config git-p4.detectRenames true && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing git-wild@at && + test_path_is_file git-wild-cp%percent + ) +' + +test_expect_success 'wildcard files submit back to p4, delete' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git rm git-wild* && + git commit -m "delete the wildcard files" && + git config git-p4.skipSubmitEdit true && + git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing git-wild#hash && + test_path_is_missing git-wild\*star && + test_path_is_missing git-wild@at && + test_path_is_missing git-wild%percent + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9813-git-p4-preserve-users.sh b/t/t9813-git-p4-preserve-users.sh new file mode 100755 index 000000000..f2e85e518 --- /dev/null +++ b/t/t9813-git-p4-preserve-users.sh @@ -0,0 +1,153 @@ +#!/bin/sh + +test_description='git p4 preserve users' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'create files' ' + ( + cd "$cli" && + p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i && + echo file1 >file1 && + echo file2 >file2 && + p4 add file1 file2 && + p4 submit -d "add files" + ) +' + +p4_add_user() { + name=$1 fullname=$2 && + p4 user -f -i <<-EOF && + User: $name + Email: $name@localhost + FullName: $fullname + EOF + p4 passwd -P secret $name +} + +p4_grant_admin() { + name=$1 && + { + p4 protect -o && + echo " admin user $name * //depot/..." + } | p4 protect -i +} + +p4_check_commit_author() { + file=$1 user=$2 && + p4 changes -m 1 //depot/$file | grep -q $user +} + +make_change_by_user() { + file=$1 name=$2 email=$3 && + echo "username: a change by $name" >>"$file" && + git add "$file" && + git commit --author "$name <$email>" -m "a change by $name" +} + +# Test username support, submitting as user 'alice' +test_expect_success 'preserve users' ' + p4_add_user alice Alice && + p4_add_user bob Bob && + p4_grant_admin alice && + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + echo "username: a change by alice" >>file1 && + echo "username: a change by bob" >>file2 && + git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 && + git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 && + git config git-p4.skipSubmitEditCheck true && + P4EDITOR=touch P4USER=alice P4PASSWD=secret git p4 commit --preserve-user && + p4_check_commit_author file1 alice && + p4_check_commit_author file2 bob + ) +' + +# Test username support, submitting as bob, who lacks admin rights. Should +# not submit change to p4 (git diff should show deltas). +test_expect_success 'refuse to preserve users without perms' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEditCheck true && + echo "username-noperms: a change by alice" >>file1 && + git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 && + P4EDITOR=touch P4USER=bob P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + test_must_fail git p4 commit --preserve-user && + ! git diff --exit-code HEAD..p4/master + ) +' + +# What happens with unknown author? Without allowMissingP4Users it should fail. +test_expect_success 'preserve user where author is unknown to p4' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEditCheck true && + echo "username-bob: a change by bob" >>file1 && + git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 && + echo "username-unknown: a change by charlie" >>file1 && + git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 && + P4EDITOR=touch P4USER=alice P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + test_must_fail git p4 commit --preserve-user && + ! git diff --exit-code HEAD..p4/master && + + echo "$0: repeat with allowMissingP4Users enabled" && + git config git-p4.allowMissingP4Users true && + git config git-p4.preserveUser true && + git p4 commit && + git diff --exit-code HEAD..p4/master && + p4_check_commit_author file1 alice + ) +' + +# If we're *not* using --preserve-user, git-p4 should warn if we're submitting +# changes that are not all ours. +# Test: user in p4 and user unknown to p4. +# Test: warning disabled and user is the same. +test_expect_success 'not preserving user with mixed authorship' ' + git p4 clone --dest="$git" //depot && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEditCheck true && + p4_add_user derek Derek && + + make_change_by_user usernamefile3 Derek derek@localhost && + P4EDITOR=cat P4USER=alice P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + git p4 commit |\ + grep "git author derek@localhost does not match" && + + make_change_by_user usernamefile3 Charlie charlie@localhost && + git p4 commit |\ + grep "git author charlie@localhost does not match" && + + make_change_by_user usernamefile3 alice alice@localhost && + git p4 commit |\ + test_must_fail grep "git author.*does not match" && + + git config git-p4.skipUserNameCheck true && + make_change_by_user usernamefile3 Charlie charlie@localhost && + git p4 commit |\ + test_must_fail grep "git author.*does not match" && + + p4_check_commit_author usernamefile3 alice + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9814-git-p4-rename.sh b/t/t9814-git-p4-rename.sh new file mode 100755 index 000000000..be802e0e1 --- /dev/null +++ b/t/t9814-git-p4-rename.sh @@ -0,0 +1,241 @@ +#!/bin/sh + +test_description='git p4 rename' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +# We rely on this behavior to detect for p4 move availability. +test_expect_success 'p4 help unknown returns 1' ' + ( + cd "$cli" && + ( + p4 help client >errs 2>&1 + echo $? >retval + ) + echo 0 >expected && + test_cmp expected retval && + rm retval && + ( + p4 help nosuchcommand >errs 2>&1 + echo $? >retval + ) + echo 1 >expected && + test_cmp expected retval && + rm retval + ) +' + +test_expect_success 'create files' ' + ( + cd "$cli" && + p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i && + cat >file1 <<-EOF && + A large block of text + in file1 that will generate + enough context so that rename + and copy detection will find + something interesting to do. + EOF + cat >file2 <<-EOF && + /* + * This blob looks a bit + * different. + */ + int main(int argc, char **argv) + { + char text[200]; + + strcpy(text, "copy/rename this"); + printf("text is %s\n", text); + return 0; + } + EOF + p4 add file1 file2 && + p4 submit -d "add files" + ) +' + +# Rename a file and confirm that rename is not detected in P4. +# Rename the new file again with detectRenames option enabled and confirm that +# this is detected in P4. +# Rename the new file again adding an extra line, configure a big threshold in +# detectRenames and confirm that rename is not detected in P4. +# Repeat, this time with a smaller threshold and confirm that the rename is +# detected in P4. +test_expect_success 'detect renames' ' + git p4 clone --dest="$git" //depot@all && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + + git mv file1 file4 && + git commit -a -m "Rename file1 to file4" && + git diff-tree -r -M HEAD && + git p4 submit && + p4 filelog //depot/file4 >filelog && + ! grep " from //depot" filelog && + + git mv file4 file5 && + git commit -a -m "Rename file4 to file5" && + git diff-tree -r -M HEAD && + git config git-p4.detectRenames true && + git p4 submit && + p4 filelog //depot/file5 >filelog && + grep " from //depot/file4" filelog && + + git mv file5 file6 && + echo update >>file6 && + git add file6 && + git commit -a -m "Rename file5 to file6 with changes" && + git diff-tree -r -M HEAD && + level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && + test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && + git config git-p4.detectRenames $(($level + 2)) && + git p4 submit && + p4 filelog //depot/file6 >filelog && + ! grep " from //depot" filelog && + + git mv file6 file7 && + echo update >>file7 && + git add file7 && + git commit -a -m "Rename file6 to file7 with changes" && + git diff-tree -r -M HEAD && + level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && + test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && + git config git-p4.detectRenames $(($level - 2)) && + git p4 submit && + p4 filelog //depot/file7 >filelog && + grep " from //depot/file6" filelog + ) +' + +# Copy a file and confirm that copy is not detected in P4. +# Copy a file with detectCopies option enabled and confirm that copy is not +# detected in P4. +# Modify and copy a file with detectCopies option enabled and confirm that copy +# is detected in P4. +# Copy a file with detectCopies and detectCopiesHarder options enabled and +# confirm that copy is detected in P4. +# Modify and copy a file, configure a bigger threshold in detectCopies and +# confirm that copy is not detected in P4. +# Modify and copy a file, configure a smaller threshold in detectCopies and +# confirm that copy is detected in P4. +test_expect_success 'detect copies' ' + git p4 clone --dest="$git" //depot@all && + test_when_finished cleanup_git && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + + cp file2 file8 && + git add file8 && + git commit -a -m "Copy file2 to file8" && + git diff-tree -r -C HEAD && + git p4 submit && + p4 filelog //depot/file8 && + p4 filelog //depot/file8 | test_must_fail grep -q "branch from" && + + cp file2 file9 && + git add file9 && + git commit -a -m "Copy file2 to file9" && + git diff-tree -r -C HEAD && + git config git-p4.detectCopies true && + git p4 submit && + p4 filelog //depot/file9 && + p4 filelog //depot/file9 | test_must_fail grep -q "branch from" && + + echo "file2" >>file2 && + cp file2 file10 && + git add file2 file10 && + git commit -a -m "Modify and copy file2 to file10" && + git diff-tree -r -C HEAD && + git p4 submit && + p4 filelog //depot/file10 && + p4 filelog //depot/file10 | grep -q "branch from //depot/file" && + + cp file2 file11 && + git add file11 && + git commit -a -m "Copy file2 to file11" && + git diff-tree -r -C --find-copies-harder HEAD && + src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && + test "$src" = file10 && + git config git-p4.detectCopiesHarder true && + git p4 submit && + p4 filelog //depot/file11 && + p4 filelog //depot/file11 | grep -q "branch from //depot/file" && + + cp file2 file12 && + echo "some text" >>file12 && + git add file12 && + git commit -a -m "Copy file2 to file12 with changes" && + git diff-tree -r -C --find-copies-harder HEAD && + level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && + test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && + src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && + test "$src" = file10 -o "$src" = file11 && + git config git-p4.detectCopies $(($level + 2)) && + git p4 submit && + p4 filelog //depot/file12 && + p4 filelog //depot/file12 | test_must_fail grep -q "branch from" && + + cp file2 file13 && + echo "different text" >>file13 && + git add file13 && + git commit -a -m "Copy file2 to file13 with changes" && + git diff-tree -r -C --find-copies-harder HEAD && + level=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/C0*//") && + test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && + src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && + test "$src" = file10 -o "$src" = file11 -o "$src" = file12 && + git config git-p4.detectCopies $(($level - 2)) && + git p4 submit && + p4 filelog //depot/file13 && + p4 filelog //depot/file13 | grep -q "branch from //depot/file" + ) +' + +# See if configurables can be set, and in particular if the run.move.allow +# variable exists, which allows admins to disable the "p4 move" command. +test_expect_success 'p4 configure command and run.move.allow are available' ' + p4 configure show run.move.allow >out ; retval=$? && + test $retval = 0 && + { + egrep ^run.move.allow: out && + test_set_prereq P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW || + true + } || true +' + +# If move can be disabled, turn it off and test p4 move handling +test_expect_success P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW \ + 'do not use p4 move when administratively disabled' ' + test_when_finished "p4 configure set run.move.allow=1" && + p4 configure set run.move.allow=0 && + ( + cd "$cli" && + echo move-disallow-file >move-disallow-file && + p4 add move-disallow-file && + p4 submit -d "add move-disallow-file" + ) && + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.detectRenames true && + git mv move-disallow-file move-disallow-file-moved && + git commit -m "move move-disallow-file" && + git p4 submit + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9815-git-p4-submit-fail.sh b/t/t9815-git-p4-submit-fail.sh new file mode 100755 index 000000000..d2b7b3d98 --- /dev/null +++ b/t/t9815-git-p4-submit-fail.sh @@ -0,0 +1,429 @@ +#!/bin/sh + +test_description='git p4 submit failure handling' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +test_expect_success 'init depot' ' + ( + cd "$cli" && + p4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i && + echo line1 >file1 && + p4 add file1 && + p4 submit -d "line1 in file1" + ) +' + +test_expect_success 'conflict on one commit' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$cli" && + p4 open file1 && + echo line2 >>file1 && + p4 submit -d "line2 in file1" + ) && + ( + # now this commit should cause a conflict + cd "$git" && + git config git-p4.skipSubmitEdit true && + echo line3 >>file1 && + git add file1 && + git commit -m "line3 in file1 will conflict" && + test_expect_code 1 git p4 submit >out && + test_i18ngrep "No commits applied" out + ) +' + +test_expect_success 'conflict on second of two commits' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$cli" && + p4 open file1 && + echo line3 >>file1 && + p4 submit -d "line3 in file1" + ) && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + # this commit is okay + test_commit "first_commit_okay" && + # now this submit should cause a conflict + echo line4 >>file1 && + git add file1 && + git commit -m "line4 in file1 will conflict" && + test_expect_code 1 git p4 submit >out && + test_i18ngrep "Applied only the commits" out + ) +' + +test_expect_success 'conflict on first of two commits, skip' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$cli" && + p4 open file1 && + echo line4 >>file1 && + p4 submit -d "line4 in file1" + ) && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + # this submit should cause a conflict + echo line5 >>file1 && + git add file1 && + git commit -m "line5 in file1 will conflict" && + # but this commit is okay + test_commit "okay_commit_after_skip" && + echo s | test_expect_code 1 git p4 submit >out && + test_i18ngrep "Applied only the commits" out + ) +' + +test_expect_success 'conflict on first of two commits, quit' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$cli" && + p4 open file1 && + echo line7 >>file1 && + p4 submit -d "line7 in file1" + ) && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + # this submit should cause a conflict + echo line8 >>file1 && + git add file1 && + git commit -m "line8 in file1 will conflict" && + # but this commit is okay + test_commit "okay_commit_after_quit" && + echo q | test_expect_code 1 git p4 submit >out && + test_i18ngrep "No commits applied" out + ) +' + +test_expect_success 'conflict cli and config options' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git p4 submit --conflict=ask && + git p4 submit --conflict=skip && + git p4 submit --conflict=quit && + test_expect_code 2 git p4 submit --conflict=foo && + test_expect_code 2 git p4 submit --conflict && + git config git-p4.conflict foo && + test_expect_code 1 git p4 submit && + git config --unset git-p4.conflict && + git p4 submit + ) +' + +test_expect_success 'conflict on first of two commits, --conflict=skip' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$cli" && + p4 open file1 && + echo line9 >>file1 && + p4 submit -d "line9 in file1" + ) && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + # this submit should cause a conflict + echo line10 >>file1 && + git add file1 && + git commit -m "line10 in file1 will conflict" && + # but this commit is okay + test_commit "okay_commit_after_auto_skip" && + test_expect_code 1 git p4 submit --conflict=skip >out && + test_i18ngrep "Applied only the commits" out + ) +' + +test_expect_success 'conflict on first of two commits, --conflict=quit' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$cli" && + p4 open file1 && + echo line11 >>file1 && + p4 submit -d "line11 in file1" + ) && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + # this submit should cause a conflict + echo line12 >>file1 && + git add file1 && + git commit -m "line12 in file1 will conflict" && + # but this commit is okay + test_commit "okay_commit_after_auto_quit" && + test_expect_code 1 git p4 submit --conflict=quit >out && + test_i18ngrep "No commits applied" out + ) +' + +# +# Cleanup after submit fail, all cases. Some modifications happen +# before trying to apply the patch. Make sure these are unwound +# properly. Put each one in a diff along with something that will +# obviously conflict. Make sure it is back to normal after. +# + +test_expect_success 'cleanup edit p4 populate' ' + ( + cd "$cli" && + echo text file >text && + p4 add text && + echo text+x file >text+x && + chmod 755 text+x && + p4 add text+x && + p4 submit -d "populate p4" + ) +' + +setup_conflict() { + # clone before modifying file1 to force it to conflict + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + # ticks outside subshells + test_tick && + ( + cd "$cli" && + p4 open file1 && + echo $test_tick >>file1 && + p4 submit -d "$test_tick in file1" + ) && + test_tick && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + # easy conflict + echo $test_tick >>file1 && + git add file1 + # caller will add more and submit + ) +} + +test_expect_success 'cleanup edit after submit fail' ' + setup_conflict && + ( + cd "$git" && + echo another line >>text && + git add text && + git commit -m "conflict" && + test_expect_code 1 git p4 submit + ) && + ( + cd "$cli" && + # make sure it is not open + ! p4 fstat -T action text + ) +' + +test_expect_success 'cleanup add after submit fail' ' + setup_conflict && + ( + cd "$git" && + echo new file >textnew && + git add textnew && + git commit -m "conflict" && + test_expect_code 1 git p4 submit + ) && + ( + cd "$cli" && + # make sure it is not there + # and that p4 thinks it is not added + # P4 returns 0 both for "not there but added" and + # "not there", so grep. + test_path_is_missing textnew && + p4 fstat -T action textnew 2>&1 | grep "no such file" + ) +' + +test_expect_success 'cleanup delete after submit fail' ' + setup_conflict && + ( + cd "$git" && + git rm text+x && + git commit -m "conflict" && + test_expect_code 1 git p4 submit + ) && + ( + cd "$cli" && + # make sure it is there + test_path_is_file text+x && + ! p4 fstat -T action text+x + ) +' + +test_expect_success 'cleanup copy after submit fail' ' + setup_conflict && + ( + cd "$git" && + cp text text2 && + git add text2 && + git commit -m "conflict" && + git config git-p4.detectCopies true && + git config git-p4.detectCopiesHarder true && + # make sure setup is okay + git diff-tree -r -C --find-copies-harder HEAD | grep text2 | grep C100 && + test_expect_code 1 git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing text2 && + p4 fstat -T action text2 2>&1 | grep "no such file" + ) +' + +test_expect_success 'cleanup rename after submit fail' ' + setup_conflict && + ( + cd "$git" && + git mv text text2 && + git commit -m "conflict" && + git config git-p4.detectRenames true && + # make sure setup is okay + git diff-tree -r -M HEAD | grep text2 | grep R100 && + test_expect_code 1 git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing text2 && + p4 fstat -T action text2 2>&1 | grep "no such file" + ) +' + +# +# Cleanup after deciding not to submit during editTemplate. This +# involves unwinding more work, because files have been added, deleted +# and chmod-ed now. Same approach as above. +# + +test_expect_success 'cleanup edit after submit cancel' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo line >>text && + git add text && + git commit -m text && + echo n | test_expect_code 1 git p4 submit && + git reset --hard HEAD^ + ) && + ( + cd "$cli" && + ! p4 fstat -T action text && + test_cmp "$git"/text text + ) +' + +test_expect_success 'cleanup add after submit cancel' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + echo line >textnew && + git add textnew && + git commit -m textnew && + echo n | test_expect_code 1 git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing textnew && + p4 fstat -T action textnew 2>&1 | grep "no such file" + ) +' + +test_expect_success 'cleanup delete after submit cancel' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git rm text && + git commit -m "rm text" && + echo n | test_expect_code 1 git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file text && + ! p4 fstat -T action text + ) +' + +test_expect_success 'cleanup copy after submit cancel' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + cp text text2 && + git add text2 && + git commit -m text2 && + git config git-p4.detectCopies true && + git config git-p4.detectCopiesHarder true && + git diff-tree -r -C --find-copies-harder HEAD | grep text2 | grep C100 && + echo n | test_expect_code 1 git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing text2 && + p4 fstat -T action text2 2>&1 | grep "no such file" + ) +' + +test_expect_success 'cleanup rename after submit cancel' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + git mv text text2 && + git commit -m text2 && + git config git-p4.detectRenames true && + git diff-tree -r -M HEAD | grep text2 | grep R100 && + echo n | test_expect_code 1 git p4 submit + ) && + ( + cd "$cli" && + test_path_is_missing text2 && + p4 fstat -T action text2 2>&1 | grep "no such file" + test_path_is_file text && + ! p4 fstat -T action text + ) +' + +test_expect_success 'cleanup chmod after submit cancel' ' + test_when_finished cleanup_git && + git p4 clone --dest="$git" //depot && + ( + cd "$git" && + chmod u+x text && + chmod u-x text+x && + git add text text+x && + git commit -m "chmod texts" && + echo n | test_expect_code 1 git p4 submit + ) && + ( + cd "$cli" && + test_path_is_file text && + ! p4 fstat -T action text && + stat --format=%A text | egrep ^-r-- && + test_path_is_file text+x && + ! p4 fstat -T action text+x && + stat --format=%A text+x | egrep ^-r-x + ) +' + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 256e6a0b3..3cd53f87f 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -3,21 +3,9 @@ # Copyright (c) 2012 Felipe Contreras # -if test -n "$BASH" && test -z "$POSIXLY_CORRECT"; then - # we are in full-on bash mode - true -elif type bash >/dev/null 2>&1; then - # execute in full-on bash mode - unset POSIXLY_CORRECT - exec bash "$0" "$@" -else - echo '1..0 #SKIP skipping bash completion tests; bash not available' - exit 0 -fi - test_description='test bash completion' -. ./test-lib.sh +. ./lib-bash.sh complete () { @@ -66,96 +54,78 @@ run_completion () __git_wrap__git_main && print_comp } +# Test high-level completion +# Arguments are: +# 1: typed text so far (cur) +# 2: expected completion test_completion () { - test $# -gt 1 && echo "$2" > expected - run_completion "$@" && + if test $# -gt 1 + then + printf '%s\n' "$2" >expected + else + sed -e 's/Z$//' >expected + fi && + run_completion "$1" && test_cmp expected out } -newline=$'\n' +# Test __gitcomp. +# The first argument is the typed text so far (cur); the rest are +# passed to __gitcomp. Expected output comes is read from the +# standard input, like test_completion(). +test_gitcomp () +{ + local -a COMPREPLY && + sed -e 's/Z$//' >expected && + cur="$1" && + shift && + __gitcomp "$@" && + print_comp && + test_cmp expected out +} test_expect_success '__gitcomp - trailing space - options' ' - sed -e "s/Z$//" >expected <<-\EOF && + test_gitcomp "--re" "--dry-run --reuse-message= --reedit-message= + --reset-author" <<-EOF --reuse-message=Z --reedit-message=Z --reset-author Z EOF - ( - local -a COMPREPLY && - cur="--re" && - __gitcomp "--dry-run --reuse-message= --reedit-message= - --reset-author" && - IFS="$newline" && - echo "${COMPREPLY[*]}" > out - ) && - test_cmp expected out ' test_expect_success '__gitcomp - trailing space - config keys' ' - sed -e "s/Z$//" >expected <<-\EOF && + test_gitcomp "br" "branch. branch.autosetupmerge + branch.autosetuprebase browser." <<-\EOF branch.Z branch.autosetupmerge Z branch.autosetuprebase Z browser.Z EOF - ( - local -a COMPREPLY && - cur="br" && - __gitcomp "branch. branch.autosetupmerge - branch.autosetuprebase browser." && - IFS="$newline" && - echo "${COMPREPLY[*]}" > out - ) && - test_cmp expected out ' test_expect_success '__gitcomp - option parameter' ' - sed -e "s/Z$//" >expected <<-\EOF && + test_gitcomp "--strategy=re" "octopus ours recursive resolve subtree" \ + "" "re" <<-\EOF recursive Z resolve Z EOF - ( - local -a COMPREPLY && - cur="--strategy=re" && - __gitcomp "octopus ours recursive resolve subtree - " "" "re" && - IFS="$newline" && - echo "${COMPREPLY[*]}" > out - ) && - test_cmp expected out ' test_expect_success '__gitcomp - prefix' ' - sed -e "s/Z$//" >expected <<-\EOF && + test_gitcomp "branch.me" "remote merge mergeoptions rebase" \ + "branch.maint." "me" <<-\EOF branch.maint.merge Z branch.maint.mergeoptions Z EOF - ( - local -a COMPREPLY && - cur="branch.me" && - __gitcomp "remote merge mergeoptions rebase - " "branch.maint." "me" && - IFS="$newline" && - echo "${COMPREPLY[*]}" > out - ) && - test_cmp expected out ' test_expect_success '__gitcomp - suffix' ' - sed -e "s/Z$//" >expected <<-\EOF && + test_gitcomp "branch.me" "master maint next pu" "branch." \ + "ma" "." <<-\EOF branch.master.Z branch.maint.Z EOF - ( - local -a COMPREPLY && - cur="branch.me" && - __gitcomp "master maint next pu - " "branch." "ma" "." && - IFS="$newline" && - echo "${COMPREPLY[*]}" > out - ) && - test_cmp expected out ' test_expect_success 'basic' ' @@ -172,7 +142,7 @@ test_expect_success 'basic' ' ' test_expect_success 'double dash "git" itself' ' - sed -e "s/Z$//" >expected <<-\EOF && + test_completion "git --" <<-\EOF --paginate Z --no-pager Z --git-dir= @@ -187,11 +157,10 @@ test_expect_success 'double dash "git" itself' ' --no-replace-objects Z --help Z EOF - test_completion "git --" ' test_expect_success 'double dash "git checkout"' ' - sed -e "s/Z$//" >expected <<-\EOF && + test_completion "git checkout --" <<-\EOF --quiet Z --ours Z --theirs Z @@ -202,17 +171,15 @@ test_expect_success 'double dash "git checkout"' ' --orphan Z --patch Z EOF - test_completion "git checkout --" ' test_expect_success 'general options' ' test_completion "git --ver" "--version " && test_completion "git --hel" "--help " && - sed -e "s/Z$//" >expected <<-\EOF && + test_completion "git --exe" <<-\EOF && --exec-path Z --exec-path= EOF - test_completion "git --exe" && test_completion "git --htm" "--html-path " && test_completion "git --pag" "--paginate " && test_completion "git --no-p" "--no-pager " && @@ -240,4 +207,60 @@ test_expect_success 'general options plus command' ' test_completion "git --no-replace-objects check" "checkout " ' +test_expect_success 'setup for ref completion' ' + echo content >file1 && + echo more >file2 && + git add . && + git commit -m one && + git branch mybranch && + git tag mytag +' + +test_expect_success 'checkout completes ref names' ' + test_completion "git checkout m" <<-\EOF + master Z + mybranch Z + mytag Z + EOF +' + +test_expect_success 'show completes all refs' ' + test_completion "git show m" <<-\EOF + master Z + mybranch Z + mytag Z + EOF +' + +test_expect_success '<ref>: completes paths' ' + test_completion "git show mytag:f" <<-\EOF + file1 Z + file2 Z + EOF +' + +test_expect_success 'complete tree filename with spaces' ' + echo content >"name with spaces" && + git add . && + git commit -m spaces && + test_completion "git show HEAD:nam" <<-\EOF + name with spaces Z + EOF +' + +test_expect_failure 'complete tree filename with metacharacters' ' + echo content >"name with \${meta}" && + git add . && + git commit -m meta && + test_completion "git show HEAD:nam" <<-\EOF + name with ${meta} Z + name with spaces Z + EOF +' + +test_expect_success 'send-email' ' + test_completion "git send-email --cov" "--cover-letter " && + test_completion "git send-email ma" "master " +' + test_done diff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh new file mode 100755 index 000000000..f17c1f8b8 --- /dev/null +++ b/t/t9903-bash-prompt.sh @@ -0,0 +1,456 @@ +#!/bin/sh +# +# Copyright (c) 2012 SZEDER Gábor +# + +test_description='test git-specific bash prompt functions' + +. ./lib-bash.sh + +. "$GIT_BUILD_DIR/contrib/completion/git-prompt.sh" + +actual="$TRASH_DIRECTORY/actual" + +test_expect_success 'setup for prompt tests' ' + mkdir -p subdir/subsubdir && + git init otherrepo && + echo 1 > file && + git add file && + test_tick && + git commit -m initial && + git tag -a -m msg1 t1 && + git checkout -b b1 && + echo 2 > file && + git commit -m "second b1" file && + echo 3 > file && + git commit -m "third b1" file && + git tag -a -m msg2 t2 && + git checkout -b b2 master && + echo 0 > file && + git commit -m "second b2" file && + git checkout master +' + +test_expect_success 'gitdir - from command line (through $__git_dir)' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + ( + __git_dir="$TRASH_DIRECTORY/otherrepo/.git" && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - repo as argument' ' + echo "otherrepo/.git" > expected && + __gitdir "otherrepo" > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - remote as argument' ' + echo "remote" > expected && + __gitdir "remote" > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - .git directory in cwd' ' + echo ".git" > expected && + __gitdir > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - .git directory in parent' ' + echo "$TRASH_DIRECTORY/.git" > expected && + ( + cd subdir/subsubdir && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - cwd is a .git directory' ' + echo "." > expected && + ( + cd .git && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - parent is a .git directory' ' + echo "$TRASH_DIRECTORY/.git" > expected && + ( + cd .git/refs/heads && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - $GIT_DIR set while .git directory in cwd' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + ( + GIT_DIR="$TRASH_DIRECTORY/otherrepo/.git" && + export GIT_DIR && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - $GIT_DIR set while .git directory in parent' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + ( + GIT_DIR="$TRASH_DIRECTORY/otherrepo/.git" && + export GIT_DIR && + cd subdir && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - non-existing $GIT_DIR' ' + ( + GIT_DIR="$TRASH_DIRECTORY/non-existing" && + export GIT_DIR && + test_must_fail __gitdir + ) +' + +test_expect_success 'gitdir - gitfile in cwd' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git && + test_when_finished "rm -f subdir/.git" && + ( + cd subdir && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - gitfile in parent' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git && + test_when_finished "rm -f subdir/.git" && + ( + cd subdir/subsubdir && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks' ' + echo "$TRASH_DIRECTORY/otherrepo/.git" > expected && + mkdir otherrepo/dir && + test_when_finished "rm -rf otherrepo/dir" && + ln -s otherrepo/dir link && + test_when_finished "rm -f link" && + ( + cd link && + __gitdir > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'gitdir - not a git repository' ' + ( + cd subdir/subsubdir && + GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY" && + export GIT_CEILING_DIRECTORIES && + test_must_fail __gitdir + ) +' + +test_expect_success 'prompt - branch name' ' + printf " (master)" > expected && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - detached head' ' + printf " ((%s...))" $(git log -1 --format="%h" b1^) > expected && + git checkout b1^ && + test_when_finished "git checkout master" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - describe detached head - contains' ' + printf " ((t2~1))" > expected && + git checkout b1^ && + test_when_finished "git checkout master" && + ( + GIT_PS1_DESCRIBE_STYLE=contains && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - describe detached head - branch' ' + printf " ((b1~1))" > expected && + git checkout b1^ && + test_when_finished "git checkout master" && + ( + GIT_PS1_DESCRIBE_STYLE=branch && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - describe detached head - describe' ' + printf " ((t1-1-g%s))" $(git log -1 --format="%h" b1^) > expected && + git checkout b1^ && + test_when_finished "git checkout master" && + ( + GIT_PS1_DESCRIBE_STYLE=describe && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - describe detached head - default' ' + printf " ((t2))" > expected && + git checkout --detach b1 && + test_when_finished "git checkout master" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - inside .git directory' ' + printf " (GIT_DIR!)" > expected && + ( + cd .git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - deep inside .git directory' ' + printf " (GIT_DIR!)" > expected && + ( + cd .git/refs/heads && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - inside bare repository' ' + printf " (BARE:master)" > expected && + git init --bare bare.git && + test_when_finished "rm -rf bare.git" && + ( + cd bare.git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - interactive rebase' ' + printf " (b1|REBASE-i)" > expected + echo "#!$SHELL_PATH" >fake_editor.sh && + cat >>fake_editor.sh <<\EOF && +echo "edit $(git log -1 --format="%h")" > "$1" +EOF + test_when_finished "rm -f fake_editor.sh" && + chmod a+x fake_editor.sh && + test_set_editor "$TRASH_DIRECTORY/fake_editor.sh" && + git checkout b1 && + test_when_finished "git checkout master" && + git rebase -i HEAD^ && + test_when_finished "git rebase --abort" + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - rebase merge' ' + printf " (b2|REBASE-m)" > expected && + git checkout b2 && + test_when_finished "git checkout master" && + test_must_fail git rebase --merge b1 b2 && + test_when_finished "git rebase --abort" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - rebase' ' + printf " ((t2)|REBASE)" > expected && + git checkout b2 && + test_when_finished "git checkout master" && + test_must_fail git rebase b1 b2 && + test_when_finished "git rebase --abort" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - merge' ' + printf " (b1|MERGING)" > expected && + git checkout b1 && + test_when_finished "git checkout master" && + test_must_fail git merge b2 && + test_when_finished "git reset --hard" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - cherry-pick' ' + printf " (master|CHERRY-PICKING)" > expected && + test_must_fail git cherry-pick b1 && + test_when_finished "git reset --hard" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - bisect' ' + printf " (master|BISECTING)" > expected && + git bisect start && + test_when_finished "git bisect reset" && + __git_ps1 > "$actual" && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - clean' ' + printf " (master)" > expected && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - dirty worktree' ' + printf " (master *)" > expected && + echo "dirty" > file && + test_when_finished "git reset --hard" && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - dirty index' ' + printf " (master +)" > expected && + echo "dirty" > file && + test_when_finished "git reset --hard" && + git add -u && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - dirty index and worktree' ' + printf " (master *+)" > expected && + echo "dirty index" > file && + test_when_finished "git reset --hard" && + git add -u && + echo "dirty worktree" > file && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - before root commit' ' + printf " (master #)" > expected && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + cd otherrepo && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - disabled by config' ' + printf " (master)" > expected && + echo "dirty" > file && + test_when_finished "git reset --hard" && + test_config bash.showDirtyState false && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - dirty status indicator - not shown inside .git directory' ' + printf " (GIT_DIR!)" > expected && + echo "dirty" > file && + test_when_finished "git reset --hard" && + ( + GIT_PS1_SHOWDIRTYSTATE=y && + cd .git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - stash status indicator - no stash' ' + printf " (master)" > expected && + ( + GIT_PS1_SHOWSTASHSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - stash status indicator - stash' ' + printf " (master $)" > expected && + echo 2 >file && + git stash && + test_when_finished "git stash drop" && + ( + GIT_PS1_SHOWSTASHSTATE=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - stash status indicator - not shown inside .git directory' ' + printf " (GIT_DIR!)" > expected && + echo 2 >file && + git stash && + test_when_finished "git stash drop" && + ( + GIT_PS1_SHOWSTASHSTATE=y && + cd .git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - no untracked files' ' + printf " (master)" > expected && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + cd otherrepo && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - untracked files' ' + printf " (master %%)" > expected && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - untracked files status indicator - not shown inside .git directory' ' + printf " (GIT_DIR!)" > expected && + ( + GIT_PS1_SHOWUNTRACKEDFILES=y && + cd .git && + __git_ps1 > "$actual" + ) && + test_cmp expected "$actual" +' + +test_expect_success 'prompt - format string starting with dash' ' + printf -- "-master" > expected && + __git_ps1 "-%s" > "$actual" && + test_cmp expected "$actual" +' + +test_done diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 9096398b1..22a4f8fb6 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -144,11 +144,22 @@ test_pause () { test_commit () { notick= && - if test "z$1" = "z--notick" - then - notick=yes + signoff= && + while test $# != 0 + do + case "$1" in + --notick) + notick=yes + ;; + --signoff) + signoff="$1" + ;; + *) + break + ;; + esac shift - fi && + done && file=${2:-"$1.t"} && echo "${3-$1}" > "$file" && git add "$file" && @@ -156,7 +167,7 @@ test_commit () { then test_tick fi && - git commit -m "$1" && + git commit $signoff -m "$1" && git tag "$1" } @@ -221,9 +232,35 @@ write_script () { # capital letters by convention). test_set_prereq () { - satisfied="$satisfied$1 " + satisfied_prereq="$satisfied_prereq$1 " +} +satisfied_prereq=" " +lazily_testable_prereq= lazily_tested_prereq= + +# Usage: test_lazy_prereq PREREQ 'script' +test_lazy_prereq () { + lazily_testable_prereq="$lazily_testable_prereq$1 " + eval test_prereq_lazily_$1=\$2 +} + +test_run_lazy_prereq_ () { + script=' +mkdir -p "$TRASH_DIRECTORY/prereq-test-dir" && +( + cd "$TRASH_DIRECTORY/prereq-test-dir" &&'"$2"' +)' + say >&3 "checking prerequisite: $1" + say >&3 "$script" + test_eval_ "$script" + eval_ret=$? + rm -rf "$TRASH_DIRECTORY/prereq-test-dir" + if test "$eval_ret" = 0; then + say >&3 "prerequisite $1 ok" + else + say >&3 "prerequisite $1 not satisfied" + fi + return $eval_ret } -satisfied=" " test_have_prereq () { # prerequisites can be concatenated with ',' @@ -238,13 +275,48 @@ test_have_prereq () { for prerequisite do + case "$prerequisite" in + !*) + negative_prereq=t + prerequisite=${prerequisite#!} + ;; + *) + negative_prereq= + esac + + case " $lazily_tested_prereq " in + *" $prerequisite "*) + ;; + *) + case " $lazily_testable_prereq " in + *" $prerequisite "*) + eval "script=\$test_prereq_lazily_$prerequisite" && + if test_run_lazy_prereq_ "$prerequisite" "$script" + then + test_set_prereq $prerequisite + fi + lazily_tested_prereq="$lazily_tested_prereq$prerequisite " + esac + ;; + esac + total_prereq=$(($total_prereq + 1)) - case $satisfied in + case "$satisfied_prereq" in *" $prerequisite "*) + satisfied_this_prereq=t + ;; + *) + satisfied_this_prereq= + esac + + case "$satisfied_this_prereq,$negative_prereq" in + t,|,t) ok_prereq=$(($ok_prereq + 1)) ;; *) - # Keep a list of missing prerequisites + # Keep a list of missing prerequisites; restore + # the negative marker if necessary. + prerequisite=${negative_prereq:+!}$prerequisite if test -z "$missing_prereq" then missing_prereq=$prerequisite diff --git a/t/test-lib.sh b/t/test-lib.sh index acda33d17..f50f8341d 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -15,6 +15,38 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . +# Keep the original TERM for say_color +ORIGINAL_TERM=$TERM + +# Test the binaries we have just built. The tests are kept in +# t/ subdirectory and are run in 'trash directory' subdirectory. +if test -z "$TEST_DIRECTORY" +then + # We allow tests to override this, in case they want to run tests + # outside of t/, e.g. for running tests on the test library + # itself. + TEST_DIRECTORY=$(pwd) +fi +if test -z "$TEST_OUTPUT_DIRECTORY" +then + # Similarly, override this to store the test-results subdir + # elsewhere + TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY +fi +GIT_BUILD_DIR="$TEST_DIRECTORY"/.. + +################################################################ +# It appears that people try to run tests without building... +"$GIT_BUILD_DIR/git" >/dev/null +if test $? != 1 +then + echo >&2 'error: you do not seem to have built git yet.' + exit 1 +fi + +. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS +export PERL_PATH SHELL_PATH + # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$GIT_TEST_TEE_STARTED, $* " in @@ -24,16 +56,13 @@ done,*) *' --tee '*|*' --va'*) mkdir -p test-results BASE=test-results/$(basename "$0" .sh) - (GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1; + (GIT_TEST_TEE_STARTED=done ${SHELL_PATH} "$0" "$@" 2>&1; echo $? > $BASE.exit) | tee $BASE.out test "$(cat $BASE.exit)" = 0 exit ;; esac -# Keep the original TERM for say_color -ORIGINAL_TERM=$TERM - # For repeatability, reset the environment to known value. LANG=C LC_ALL=C @@ -46,7 +75,7 @@ EDITOR=: # /usr/xpg4/bin/sh and /bin/ksh to bail out. So keep the unsets # deriving from the command substitution clustered with the other # ones. -unset VISUAL EMAIL LANGUAGE COLUMNS $(perl -e ' +unset VISUAL EMAIL LANGUAGE COLUMNS $("$PERL_PATH" -e ' my @env = keys %ENV; my $ok = join("|", qw( TRACE @@ -61,6 +90,7 @@ unset VISUAL EMAIL LANGUAGE COLUMNS $(perl -e ' my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env); print join("\n", @vars); ') +unset XDG_CONFIG_HOME GIT_AUTHOR_EMAIL=author@example.com GIT_AUTHOR_NAME='A U Thor' GIT_COMMITTER_EMAIL=committer@example.com @@ -72,6 +102,27 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME export EDITOR +# Add libc MALLOC and MALLOC_PERTURB test +# only if we are not executing the test with valgrind +if expr " $GIT_TEST_OPTS " : ".* --valgrind " >/dev/null || + test -n "$TEST_NO_MALLOC_CHECK" +then + setup_malloc_check () { + : nothing + } + teardown_malloc_check () { + : nothing + } +else + setup_malloc_check () { + MALLOC_CHECK_=3 MALLOC_PERTURB_=165 + export MALLOC_CHECK_ MALLOC_PERTURB_ + } + teardown_malloc_check () { + unset MALLOC_CHECK_ MALLOC_PERTURB_ + } +fi + # Protect ourselves from common misconfiguration to export # CDPATH into the environment unset CDPATH @@ -79,12 +130,12 @@ unset CDPATH unset GREP_OPTIONS case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in - 1|2|true) - echo "* warning: Some tests will not work if GIT_TRACE" \ - "is set as to trace on STDERR ! *" - echo "* warning: Please set GIT_TRACE to something" \ - "other than 1, 2 or true ! *" - ;; +1|2|true) + echo "* warning: Some tests will not work if GIT_TRACE" \ + "is set as to trace on STDERR ! *" + echo "* warning: Please set GIT_TRACE to something" \ + "other than 1, 2 or true ! *" + ;; esac # Convenience @@ -151,17 +202,23 @@ do esac done -if test -n "$color"; then +if test -n "$color" +then say_color () { ( TERM=$ORIGINAL_TERM export TERM case "$1" in - error) tput bold; tput setaf 1;; # bold red - skip) tput bold; tput setaf 2;; # bold green - pass) tput setaf 2;; # green - info) tput setaf 3;; # brown - *) test -n "$quiet" && return;; + error) + tput bold; tput setaf 1;; # bold red + skip) + tput bold; tput setaf 2;; # bold green + pass) + tput setaf 2;; # green + info) + tput setaf 3;; # brown + *) + test -n "$quiet" && return;; esac shift printf "%s" "$*" @@ -173,7 +230,7 @@ else say_color() { test -z "$1" && test -n "$quiet" && return shift - echo "$*" + printf "%s\n" "$*" } fi @@ -229,7 +286,7 @@ trap 'die' EXIT # The user-facing functions are loaded from a separate file so that # test_perf subshells can have them too -. "${TEST_DIRECTORY:-.}"/test-lib-functions.sh +. "$TEST_DIRECTORY/test-lib-functions.sh" # You are not expected to call test_ok_ and test_failure_ directly, use # the text_expect_* functions instead. @@ -275,9 +332,12 @@ test_run_ () { if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure" then + setup_malloc_check test_eval_ "$test_cleanup" + teardown_malloc_check fi - if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then + if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE" + then echo "" fi return "$eval_ret" @@ -325,10 +385,12 @@ test_at_end_hook_ () { test_done () { GIT_EXIT_OK=t - if test -z "$HARNESS_ACTIVE"; then + if test -z "$HARNESS_ACTIVE" + then test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results" mkdir -p "$test_results_dir" - test_results_path="$test_results_dir/${0%.sh}-$$.counts" + base=${0##*/} + test_results_path="$test_results_dir/${base%.sh}-$$.counts" cat >>"$test_results_path" <<-EOF total $test_count @@ -354,10 +416,18 @@ test_done () { case "$test_failure" in 0) # Maybe print SKIP message + if test -n "$skip_all" && test $test_count -gt 0 + then + error "Can't use skip_all after running some tests" + fi [ -z "$skip_all" ] || skip_all=" # SKIP $skip_all" - if test $test_external_has_tap -eq 0; then - say_color pass "# passed all $msg" + if test $test_external_has_tap -eq 0 + then + if test $test_count -gt 0 + then + say_color pass "# passed all $msg" + fi say "1..$test_count$skip_all" fi @@ -370,7 +440,8 @@ test_done () { exit 0 ;; *) - if test $test_external_has_tap -eq 0; then + if test $test_external_has_tap -eq 0 + then say_color error "# failed $test_failure among $msg" say "1..$test_count" fi @@ -380,23 +451,6 @@ test_done () { esac } -# Test the binaries we have just built. The tests are kept in -# t/ subdirectory and are run in 'trash directory' subdirectory. -if test -z "$TEST_DIRECTORY" -then - # We allow tests to override this, in case they want to run tests - # outside of t/, e.g. for running tests on the test library - # itself. - TEST_DIRECTORY=$(pwd) -fi -if test -z "$TEST_OUTPUT_DIRECTORY" -then - # Similarly, override this to store the test-results subdir - # elsewhere - TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY -fi -GIT_BUILD_DIR="$TEST_DIRECTORY"/.. - if test -n "$valgrind" then make_symlink () { @@ -467,22 +521,26 @@ then PATH=$GIT_VALGRIND/bin:$PATH GIT_EXEC_PATH=$GIT_VALGRIND/bin export GIT_VALGRIND -elif test -n "$GIT_TEST_INSTALLED" ; then +elif test -n "$GIT_TEST_INSTALLED" +then GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path) || error "Cannot run git from $GIT_TEST_INSTALLED." PATH=$GIT_TEST_INSTALLED:$GIT_BUILD_DIR:$PATH GIT_EXEC_PATH=${GIT_TEST_EXEC_PATH:-$GIT_EXEC_PATH} else # normal case, use ../bin-wrappers only unless $with_dashes: git_bin_dir="$GIT_BUILD_DIR/bin-wrappers" - if ! test -x "$git_bin_dir/git" ; then - if test -z "$with_dashes" ; then + if ! test -x "$git_bin_dir/git" + then + if test -z "$with_dashes" + then say "$git_bin_dir/git is not executable; using GIT_EXEC_PATH" fi with_dashes=t fi PATH="$git_bin_dir:$PATH" GIT_EXEC_PATH=$GIT_BUILD_DIR - if test -n "$with_dashes" ; then + if test -n "$with_dashes" + then PATH="$GIT_BUILD_DIR:$PATH" fi fi @@ -492,10 +550,6 @@ GIT_CONFIG_NOSYSTEM=1 GIT_ATTR_NOSYSTEM=1 export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM -. "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS - -export PERL_PATH - if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" @@ -521,7 +575,8 @@ then } fi -if ! test -x "$GIT_BUILD_DIR"/test-chmtime; then +if ! test -x "$GIT_BUILD_DIR"/test-chmtime +then echo >&2 'You need to build test-chmtime:' echo >&2 'Run "make test-chmtime" in the source (toplevel) directory' exit 1 @@ -544,7 +599,8 @@ rm -fr "$test" || { HOME="$TRASH_DIRECTORY" export HOME -if test -z "$TEST_NO_CREATE_REPO"; then +if test -z "$TEST_NO_CREATE_REPO" +then test_create_repo "$test" else mkdir -p "$test" @@ -659,9 +715,35 @@ test_i18ngrep () { fi } -# test whether the filesystem supports symbolic links -ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS -rm -f y +test_lazy_prereq SYMLINKS ' + # test whether the filesystem supports symbolic links + ln -s x y && test -h y +' + +test_lazy_prereq CASE_INSENSITIVE_FS ' + echo good >CamelCase && + echo bad >camelcase && + test "$(cat CamelCase)" != good +' + +test_lazy_prereq UTF8_NFD_TO_NFC ' + # check whether FS converts nfd unicode to nfc + auml=$(printf "\303\244") + aumlcdiar=$(printf "\141\314\210") + >"$auml" && + case "$(echo *)" in + "$aumlcdiar") + true ;; + *) + false ;; + esac +' + +test_lazy_prereq AUTOIDENT ' + sane_unset GIT_AUTHOR_NAME && + sane_unset GIT_AUTHOR_EMAIL && + git var GIT_AUTHOR_IDENT +' # When the tests are run as root, permission tests will report that # things are writable when they shouldn't be. diff --git a/test-credential.c b/test-credential.c deleted file mode 100644 index dee200e7f..000000000 --- a/test-credential.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "cache.h" -#include "credential.h" -#include "string-list.h" - -static const char usage_msg[] = -"test-credential <fill|approve|reject> [helper...]"; - -int main(int argc, const char **argv) -{ - const char *op; - struct credential c = CREDENTIAL_INIT; - int i; - - op = argv[1]; - if (!op) - usage(usage_msg); - for (i = 2; i < argc; i++) - string_list_append(&c.helpers, argv[i]); - - if (credential_read(&c, stdin) < 0) - die("unable to read credential from stdin"); - - if (!strcmp(op, "fill")) { - credential_fill(&c); - if (c.username) - printf("username=%s\n", c.username); - if (c.password) - printf("password=%s\n", c.password); - } - else if (!strcmp(op, "approve")) - credential_approve(&c); - else if (!strcmp(op, "reject")) - credential_reject(&c); - else - usage(usage_msg); - - return 0; -} diff --git a/test-line-buffer.c b/test-line-buffer.c index 7ec9b13c9..ef1d7bae1 100644 --- a/test-line-buffer.c +++ b/test-line-buffer.c @@ -87,6 +87,5 @@ int main(int argc, char *argv[]) die("input error"); if (ferror(stdout)) die("output error"); - buffer_reset(&stdin_buf); return 0; } diff --git a/test-string-list.c b/test-string-list.c new file mode 100644 index 000000000..4693295a9 --- /dev/null +++ b/test-string-list.c @@ -0,0 +1,123 @@ +#include "cache.h" +#include "string-list.h" + +/* + * Parse an argument into a string list. arg should either be a + * ':'-separated list of strings, or "-" to indicate an empty string + * list (as opposed to "", which indicates a string list containing a + * single empty string). list->strdup_strings must be set. + */ +static void parse_string_list(struct string_list *list, const char *arg) +{ + if (!strcmp(arg, "-")) + return; + + (void)string_list_split(list, arg, ':', -1); +} + +static void write_list(const struct string_list *list) +{ + int i; + for (i = 0; i < list->nr; i++) + printf("[%d]: \"%s\"\n", i, list->items[i].string); +} + +static void write_list_compact(const struct string_list *list) +{ + int i; + if (!list->nr) + printf("-\n"); + else { + printf("%s", list->items[0].string); + for (i = 1; i < list->nr; i++) + printf(":%s", list->items[i].string); + printf("\n"); + } +} + +static int prefix_cb(struct string_list_item *item, void *cb_data) +{ + const char *prefix = (const char *)cb_data; + return !prefixcmp(item->string, prefix); +} + +int main(int argc, char **argv) +{ + if (argc == 5 && !strcmp(argv[1], "split")) { + struct string_list list = STRING_LIST_INIT_DUP; + int i; + const char *s = argv[2]; + int delim = *argv[3]; + int maxsplit = atoi(argv[4]); + + i = string_list_split(&list, s, delim, maxsplit); + printf("%d\n", i); + write_list(&list); + string_list_clear(&list, 0); + return 0; + } + + if (argc == 5 && !strcmp(argv[1], "split_in_place")) { + struct string_list list = STRING_LIST_INIT_NODUP; + int i; + char *s = xstrdup(argv[2]); + int delim = *argv[3]; + int maxsplit = atoi(argv[4]); + + i = string_list_split_in_place(&list, s, delim, maxsplit); + printf("%d\n", i); + write_list(&list); + string_list_clear(&list, 0); + free(s); + return 0; + } + + if (argc == 4 && !strcmp(argv[1], "filter")) { + /* + * Retain only the items that have the specified prefix. + * Arguments: list|- prefix + */ + struct string_list list = STRING_LIST_INIT_DUP; + const char *prefix = argv[3]; + + parse_string_list(&list, argv[2]); + filter_string_list(&list, 0, prefix_cb, (void *)prefix); + write_list_compact(&list); + string_list_clear(&list, 0); + return 0; + } + + if (argc == 3 && !strcmp(argv[1], "remove_duplicates")) { + struct string_list list = STRING_LIST_INIT_DUP; + + parse_string_list(&list, argv[2]); + string_list_remove_duplicates(&list, 0); + write_list_compact(&list); + string_list_clear(&list, 0); + return 0; + } + + if (argc == 4 && !strcmp(argv[1], "longest_prefix")) { + /* arguments: <colon-separated-prefixes>|- <string> */ + struct string_list prefixes = STRING_LIST_INIT_DUP; + int retval; + const char *prefix_string = argv[2]; + const char *string = argv[3]; + const char *match; + + parse_string_list(&prefixes, prefix_string); + match = string_list_longest_prefix(&prefixes, string); + if (match) { + printf("%s\n", match); + retval = 0; + } + else + retval = 1; + string_list_clear(&prefixes, 0); + return retval; + } + + fprintf(stderr, "%s: unknown function name: %s\n", argv[0], + argv[1] ? argv[1] : "(there was none)"); + return 1; +} diff --git a/test-svn-fe.c b/test-svn-fe.c index 332a5f711..0f2d9a4a3 100644 --- a/test-svn-fe.c +++ b/test-svn-fe.c @@ -31,9 +31,7 @@ static int apply_delta(int argc, char *argv[]) die_errno("cannot close preimage"); if (buffer_deinit(&delta)) die_errno("cannot close delta"); - buffer_reset(&preimage); strbuf_release(&preimage_view.buf); - buffer_reset(&delta); return 0; } @@ -42,7 +40,7 @@ int main(int argc, char *argv[]) if (argc == 2) { if (svndump_init(argv[1])) return 1; - svndump_read(NULL); + svndump_read(NULL, "refs/heads/master", "refs/notes/svn/revs"); svndump_deinit(); svndump_reset(); return 0; @@ -62,7 +62,7 @@ static int get_trace_fd(const char *key, int *need_close) static const char err_msg[] = "Could not trace into fd given by " "GIT_TRACE environment variable"; -void trace_vprintf(const char *key, const char *fmt, va_list ap) +static void trace_vprintf(const char *key, const char *fmt, va_list ap) { struct strbuf buf = STRBUF_INIT; diff --git a/transport-helper.c b/transport-helper.c index 61c928f6c..4713b6930 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -10,6 +10,7 @@ #include "string-list.h" #include "thread-utils.h" #include "sigchain.h" +#include "argv-array.h" static int debug; @@ -19,6 +20,7 @@ struct helper_data { FILE *out; unsigned fetch : 1, import : 1, + bidi_import : 1, export : 1, option : 1, push : 1, @@ -101,6 +103,7 @@ static void do_take_over(struct transport *transport) static struct child_process *get_helper(struct transport *transport) { struct helper_data *data = transport->data; + struct argv_array argv = ARGV_ARRAY_INIT; struct strbuf buf = STRBUF_INIT; struct child_process *helper; const char **refspecs = NULL; @@ -122,11 +125,10 @@ static struct child_process *get_helper(struct transport *transport) helper->in = -1; helper->out = -1; helper->err = 0; - helper->argv = xcalloc(4, sizeof(*helper->argv)); - strbuf_addf(&buf, "git-remote-%s", data->name); - helper->argv[0] = strbuf_detach(&buf, NULL); - helper->argv[1] = transport->remote->name; - helper->argv[2] = remove_ext_force(transport->url); + argv_array_pushf(&argv, "git-remote-%s", data->name); + argv_array_push(&argv, transport->remote->name); + argv_array_push(&argv, remove_ext_force(transport->url)); + helper->argv = argv_array_detach(&argv, NULL); helper->git_cmd = 0; helper->silent_exec_failure = 1; @@ -178,6 +180,8 @@ static struct child_process *get_helper(struct transport *transport) data->push = 1; else if (!strcmp(capname, "import")) data->import = 1; + else if (!strcmp(capname, "bidi-import")) + data->bidi_import = 1; else if (!strcmp(capname, "export")) data->export = 1; else if (!data->refspecs && !prefixcmp(capname, "refspec ")) { @@ -241,8 +245,7 @@ static int disconnect_helper(struct transport *transport) close(data->helper->out); fclose(data->out); res = finish_command(data->helper); - free((char *)data->helper->argv[0]); - free(data->helper->argv); + argv_array_free_detached(data->helper->argv); free(data->helper); data->helper = NULL; } @@ -376,14 +379,23 @@ static int fetch_with_fetch(struct transport *transport, static int get_importer(struct transport *transport, struct child_process *fastimport) { struct child_process *helper = get_helper(transport); + struct helper_data *data = transport->data; + struct argv_array argv = ARGV_ARRAY_INIT; + int cat_blob_fd, code; memset(fastimport, 0, sizeof(*fastimport)); fastimport->in = helper->out; - fastimport->argv = xcalloc(5, sizeof(*fastimport->argv)); - fastimport->argv[0] = "fast-import"; - fastimport->argv[1] = "--quiet"; + argv_array_push(&argv, "fast-import"); + argv_array_push(&argv, debug ? "--stats" : "--quiet"); + if (data->bidi_import) { + cat_blob_fd = xdup(helper->in); + argv_array_pushf(&argv, "--cat-blob-fd=%d", cat_blob_fd); + } + fastimport->argv = argv.argv; fastimport->git_cmd = 1; - return start_command(fastimport); + + code = start_command(fastimport); + return code; } static int get_exporter(struct transport *transport, @@ -438,12 +450,33 @@ static int fetch_with_import(struct transport *transport, } write_constant(data->helper->in, "\n"); + /* + * remote-helpers that advertise the bidi-import capability are required to + * buffer the complete batch of import commands until this newline before + * sending data to fast-import. + * These helpers read back data from fast-import on their stdin, which could + * be mixed with import commands, otherwise. + */ if (finish_command(&fastimport)) die("Error while running fast-import"); - free(fastimport.argv); - fastimport.argv = NULL; + argv_array_free_detached(fastimport.argv); + /* + * The fast-import stream of a remote helper that advertises + * the "refspec" capability writes to the refs named after the + * right hand side of the first refspec matching each ref we + * were fetching. + * + * (If no "refspec" capability was specified, for historical + * reasons we default to *:*.) + * + * Store the result in to_fetch[i].old_sha1. Callers such + * as "git fetch" can use the value to write feedback to the + * terminal, populate FETCH_HEAD, and determine what new value + * should be written to peer_ref if the update is a + * fast-forward or this is a forced update. + */ for (i = 0; i < nr_heads; i++) { char *private; posn = to_fetch[i]; diff --git a/transport.c b/transport.c index 1811b500d..9932f402d 100644 --- a/transport.c +++ b/transport.c @@ -518,8 +518,7 @@ static int fetch_refs_via_pack(struct transport *transport, int nr_heads, struct ref **to_fetch) { struct git_transport_data *data = transport->data; - char **heads = xmalloc(nr_heads * sizeof(*heads)); - char **origh = xmalloc(nr_heads * sizeof(*origh)); + struct string_list sought = STRING_LIST_INIT_DUP; const struct ref *refs; char *dest = xstrdup(transport->url); struct fetch_pack_args args; @@ -538,7 +537,7 @@ static int fetch_refs_via_pack(struct transport *transport, args.depth = data->options.depth; for (i = 0; i < nr_heads; i++) - origh[i] = heads[i] = xstrdup(to_fetch[i]->name); + string_list_append(&sought, to_fetch[i]->name); if (!data->got_remote_heads) { connect_setup(transport, 0, 0); @@ -548,7 +547,7 @@ static int fetch_refs_via_pack(struct transport *transport, refs = fetch_pack(&args, data->fd, data->conn, refs_tmp ? refs_tmp : transport->remote_refs, - dest, nr_heads, heads, &transport->pack_lockfile); + dest, &sought, &transport->pack_lockfile); close(data->fd[0]); close(data->fd[1]); if (finish_connect(data->conn)) @@ -558,10 +557,7 @@ static int fetch_refs_via_pack(struct transport *transport, free_refs(refs_tmp); - for (i = 0; i < nr_heads; i++) - free(origh[i]); - free(origh); - free(heads); + string_list_clear(&sought, 0); free(dest); return (refs ? 0 : -1); } diff --git a/transport.h b/transport.h index b866c126e..4a61c0c3f 100644 --- a/transport.h +++ b/transport.h @@ -106,6 +106,7 @@ struct transport { #define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256 #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) +#define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x) /* Returns a transport suitable for the url */ struct transport *transport_get(struct remote *, const char *); @@ -174,4 +175,9 @@ void transport_print_push_status(const char *dest, struct ref *refs, typedef void alternate_ref_fn(const struct ref *, void *); extern void for_each_alternate_ref(alternate_ref_fn, void *); +struct send_pack_args; +extern int send_pack(struct send_pack_args *args, + int fd[], struct child_process *conn, + struct ref *remote_refs, + struct extra_have_objects *extra_have); #endif diff --git a/tree-walk.c b/tree-walk.c index 492c7cd74..3f54c02d7 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -490,11 +490,11 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch static int match_entry(const struct name_entry *entry, int pathlen, const char *match, int matchlen, - int *never_interesting) + enum interesting *never_interesting) { int m = -1; /* signals that we haven't called strncmp() */ - if (*never_interesting) { + if (*never_interesting != entry_not_interesting) { /* * We have not seen any match that sorts later * than the current path. @@ -522,7 +522,7 @@ static int match_entry(const struct name_entry *entry, int pathlen, * the variable to -1 and that is what will be * returned, allowing the caller to terminate early. */ - *never_interesting = 0; + *never_interesting = entry_not_interesting; } if (pathlen > matchlen) @@ -584,7 +584,7 @@ enum interesting tree_entry_interesting(const struct name_entry *entry, { int i; int pathlen, baselen = base->len - base_offset; - int never_interesting = ps->has_wildcard ? + enum interesting never_interesting = ps->has_wildcard ? entry_not_interesting : all_entries_not_interesting; if (!ps->nr) { @@ -22,7 +22,8 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b ce = xcalloc(1, size); ce->ce_mode = create_ce_mode(mode); - ce->ce_flags = create_ce_flags(baselen + len, stage); + ce->ce_flags = create_ce_flags(stage); + ce->ce_namelen = baselen + len; memcpy(ce->name, base, baselen); memcpy(ce->name + baselen, pathname, len+1); hashcpy(ce->sha1, sha1); @@ -133,8 +134,8 @@ static int cmp_cache_name_compare(const void *a_, const void *b_) ce1 = *((const struct cache_entry **)a_); ce2 = *((const struct cache_entry **)b_); - return cache_name_compare(ce1->name, ce1->ce_flags, - ce2->name, ce2->ce_flags); + return cache_name_stage_compare(ce1->name, ce1->ce_namelen, ce_stage(ce1), + ce2->name, ce2->ce_namelen, ce_stage(ce2)); } int read_tree(struct tree *tree, int stage, struct pathspec *match) diff --git a/unpack-trees.c b/unpack-trees.c index 33a581924..6d9636623 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -539,7 +539,8 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, con struct cache_entry *ce = xcalloc(1, cache_entry_size(len)); ce->ce_mode = create_ce_mode(n->mode); - ce->ce_flags = create_ce_flags(len, stage); + ce->ce_flags = create_ce_flags(stage); + ce->ce_namelen = len; hashcpy(ce->sha1, n->sha1); make_traverse_path(ce->name, info, n); @@ -1296,7 +1297,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, * First let's make sure we do not have a local modification * in that directory. */ - namelen = strlen(ce->name); + namelen = ce_namelen(ce); for (i = locate_in_src_index(ce, o); i < o->src_index->cache_nr; i++) { diff --git a/upload-pack.c b/upload-pack.c index bb08e2eb0..6142421ea 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -11,6 +11,7 @@ #include "list-objects.h" #include "run-command.h" #include "sigchain.h" +#include "version.h" static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=<n>] <dir>"; @@ -726,17 +727,14 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo " include-tag multi_ack_detailed"; struct object *o = lookup_unknown_object(sha1); const char *refname_nons = strip_namespace(refname); - - if (o->type == OBJ_NONE) { - o->type = sha1_object_info(sha1, NULL); - if (o->type < 0) - die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1)); - } + unsigned char peeled[20]; if (capabilities) - packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname_nons, + packet_write(1, "%s %s%c%s%s agent=%s\n", + sha1_to_hex(sha1), refname_nons, 0, capabilities, - stateless_rpc ? " no-done" : ""); + stateless_rpc ? " no-done" : "", + git_user_agent_sanitized()); else packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname_nons); capabilities = NULL; @@ -744,11 +742,8 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo o->flags |= OUR_REF; nr_our_refs++; } - if (o->type == OBJ_TAG) { - o = deref_tag_noverify(o); - if (o) - packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname_nons); - } + if (!peel_ref(refname, peeled)) + packet_write(1, "%s %s^{}\n", sha1_to_hex(peeled), refname_nons); return 0; } @@ -6,6 +6,8 @@ #include "git-compat-util.h" #include "cache.h" +static int dying; + void vreportf(const char *prefix, const char *err, va_list params) { char msg[4096]; @@ -82,6 +84,12 @@ void NORETURN die(const char *err, ...) { va_list params; + if (dying) { + fputs("fatal: recursion detected in die handler\n", stderr); + exit(128); + } + dying = 1; + va_start(params, err); die_routine(err, params); va_end(params); @@ -94,6 +102,13 @@ void NORETURN die_errno(const char *fmt, ...) char str_error[256], *err; int i, j; + if (dying) { + fputs("fatal: recursion detected in die_errno handler\n", + stderr); + exit(128); + } + dying = 1; + err = strerror(errno); for (i = j = 0; err[i] && j < sizeof(str_error) - 1; ) { if ((str_error[j++] = err[i++]) != '%') diff --git a/userdiff.c b/userdiff.c index 1e7184f7f..ed958ef6b 100644 --- a/userdiff.c +++ b/userdiff.c @@ -14,6 +14,15 @@ static int drivers_alloc; { name, NULL, -1, { pattern, REG_EXTENDED | REG_ICASE }, \ word_regex "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+" } static struct userdiff_driver builtin_drivers[] = { +IPATTERN("ada", + "!^(.*[ \t])?(is new|renames|is separate)([ \t].*)?$\n" + "!^[ \t]*with[ \t].*$\n" + "^[ \t]*((procedure|function)[ \t]+.*)$\n" + "^[ \t]*((package|protected|task)[ \t]+.*)$", + /* -- */ + "[a-zA-Z][a-zA-Z0-9_]*" + "|[0-9][-+0-9#_.eE]" + "|=>|\\.\\.|\\*\\*|:=|/=|>=|<=|<<|>>|<>"), IPATTERN("fortran", "!^([C*]|[ \t]*!)\n" "!^[ \t]*MODULE[ \t]+PROCEDURE[ \t]\n" @@ -323,7 +323,7 @@ static size_t display_mode_esc_sequence_len(const char *s) * If indent is negative, assume that already -indent columns have been * consumed (and no extra indent is necessary for the first line). */ -int strbuf_add_wrapped_text(struct strbuf *buf, +void strbuf_add_wrapped_text(struct strbuf *buf, const char *text, int indent1, int indent2, int width) { int indent, w, assume_utf8 = 1; @@ -332,7 +332,7 @@ int strbuf_add_wrapped_text(struct strbuf *buf, if (width <= 0) { strbuf_add_indented_text(buf, text, indent1, indent2); - return 1; + return; } retry: @@ -353,17 +353,17 @@ retry: c = *text; if (!c || isspace(c)) { - if (w < width || !space) { + if (w <= width || !space) { const char *start = bol; if (!c && text == start) - return w; + return; if (space) start = space; else strbuf_addchars(buf, ' ', indent); strbuf_add(buf, start, text - start); if (!c) - return w; + return; space = text; if (c == '\t') w |= 0x07; @@ -405,13 +405,12 @@ new_line: } } -int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len, +void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len, int indent, int indent2, int width) { char *tmp = xstrndup(data, len); - int r = strbuf_add_wrapped_text(buf, tmp, indent, indent2, width); + strbuf_add_wrapped_text(buf, tmp, indent, indent2, width); free(tmp); - return r; } int is_encoding_utf8(const char *name) @@ -423,6 +422,13 @@ int is_encoding_utf8(const char *name) return 0; } +int same_encoding(const char *src, const char *dst) +{ + if (is_encoding_utf8(src) && is_encoding_utf8(dst)) + return 1; + return !strcasecmp(src, dst); +} + /* * Given a buffer and its encoding, return it re-encoded * with iconv. If the conversion fails, returns NULL. @@ -433,19 +439,12 @@ int is_encoding_utf8(const char *name) #else typedef char * iconv_ibp; #endif -char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding) +char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv) { - iconv_t conv; - size_t insz, outsz, outalloc; + size_t outsz, outalloc; char *out, *outpos; iconv_ibp cp; - if (!in_encoding) - return NULL; - conv = iconv_open(out_encoding, in_encoding); - if (conv == (iconv_t) -1) - return NULL; - insz = strlen(in); outsz = insz; outalloc = outsz + 1; /* for terminating NUL */ out = xmalloc(outalloc); @@ -459,7 +458,6 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e size_t sofar; if (errno != E2BIG) { free(out); - iconv_close(conv); return NULL; } /* insz has remaining number of bytes. @@ -478,6 +476,20 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e break; } } + return out; +} + +char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding) +{ + iconv_t conv; + char *out; + + if (!in_encoding) + return NULL; + conv = iconv_open(out_encoding, in_encoding); + if (conv == (iconv_t) -1) + return NULL; + out = reencode_string_iconv(in, strlen(in), conv); iconv_close(conv); return out; } @@ -7,13 +7,15 @@ int utf8_width(const char **start, size_t *remainder_p); int utf8_strwidth(const char *string); int is_utf8(const char *text); int is_encoding_utf8(const char *name); +int same_encoding(const char *, const char *); -int strbuf_add_wrapped_text(struct strbuf *buf, +void strbuf_add_wrapped_text(struct strbuf *buf, const char *text, int indent, int indent2, int width); -int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len, +void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len, int indent, int indent2, int width); #ifndef NO_ICONV +char *reencode_string_iconv(const char *in, size_t insz, iconv_t conv); char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding); #else #define reencode_string(a,b,c) NULL diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c index b823b8519..f2b23c81d 100644 --- a/vcs-svn/fast_export.c +++ b/vcs-svn/fast_export.c @@ -3,8 +3,7 @@ * See LICENSE for details. */ -#include "git-compat-util.h" -#include "strbuf.h" +#include "cache.h" #include "quote.h" #include "fast_export.h" #include "repo_tree.h" @@ -42,11 +41,6 @@ void fast_export_deinit(void) die_errno("error closing fast-import feedback stream"); } -void fast_export_reset(void) -{ - buffer_reset(&report_buffer); -} - void fast_export_delete(const char *path) { putchar('D'); @@ -73,11 +67,33 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref) putchar('\n'); } +void fast_export_begin_note(uint32_t revision, const char *author, + const char *log, unsigned long timestamp, const char *note_ref) +{ + static int firstnote = 1; + size_t loglen = strlen(log); + printf("commit %s\n", note_ref); + printf("committer %s <%s@%s> %ld +0000\n", author, author, "local", timestamp); + printf("data %"PRIuMAX"\n", (uintmax_t)loglen); + fwrite(log, loglen, 1, stdout); + if (firstnote) { + if (revision > 1) + printf("from %s^0", note_ref); + firstnote = 0; + } + fputc('\n', stdout); +} + +void fast_export_note(const char *committish, const char *dataref) +{ + printf("N %s %s\n", dataref, committish); +} + static char gitsvnline[MAX_GITSVN_LINE_LEN]; void fast_export_begin_commit(uint32_t revision, const char *author, const struct strbuf *log, const char *uuid, const char *url, - unsigned long timestamp) + unsigned long timestamp, const char *local_ref) { static const struct strbuf empty = STRBUF_INIT; if (!log) @@ -89,7 +105,7 @@ void fast_export_begin_commit(uint32_t revision, const char *author, } else { *gitsvnline = '\0'; } - printf("commit refs/heads/master\n"); + printf("commit %s\n", local_ref); printf("mark :%"PRIu32"\n", revision); printf("committer %s <%s@%s> %ld +0000\n", *author ? author : "nobody", @@ -163,7 +179,7 @@ static int parse_cat_response_line(const char *header, off_t *len) if (ends_with(header, headerlen, " missing")) return error("cat-blob reports missing blob: %s", header); - type = memmem(header, headerlen, " blob ", strlen(" blob ")); + type = strstr(header, " blob "); if (!type) return error("cat-blob header has wrong object type: %s", header); n = strtoumax(type + strlen(" blob "), (char **) &end, 10); @@ -227,6 +243,13 @@ static long apply_delta(off_t len, struct line_buffer *input, return ret; } +void fast_export_buf_to_data(const struct strbuf *data) +{ + printf("data %"PRIuMAX"\n", (uintmax_t)data->len); + fwrite(data->buf, data->len, 1, stdout); + fputc('\n', stdout); +} + void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input) { assert(len >= 0); @@ -259,7 +282,7 @@ static int parse_ls_response(const char *response, uint32_t *mode, } /* Mode. */ - if (response_end - response < strlen("100644") || + if (response_end - response < (signed) strlen("100644") || response[strlen("100644")] != ' ') die("invalid ls response: missing mode: %s", response); *mode = 0; @@ -272,7 +295,7 @@ static int parse_ls_response(const char *response, uint32_t *mode, } /* ' blob ' or ' tree ' */ - if (response_end - response < strlen(" blob ") || + if (response_end - response < (signed) strlen(" blob ") || (response[1] != 'b' && response[1] != 't')) die("unexpected ls response: not a tree or blob: %s", response); response += strlen(" blob "); diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h index aa629f54f..c8b5adb81 100644 --- a/vcs-svn/fast_export.h +++ b/vcs-svn/fast_export.h @@ -6,15 +6,18 @@ struct line_buffer; void fast_export_init(int fd); void fast_export_deinit(void); -void fast_export_reset(void); void fast_export_delete(const char *path); void fast_export_modify(const char *path, uint32_t mode, const char *dataref); +void fast_export_note(const char *committish, const char *dataref); +void fast_export_begin_note(uint32_t revision, const char *author, + const char *log, unsigned long timestamp, const char *note_ref); void fast_export_begin_commit(uint32_t revision, const char *author, - const struct strbuf *log, const char *uuid, - const char *url, unsigned long timestamp); + const struct strbuf *log, const char *uuid,const char *url, + unsigned long timestamp, const char *local_ref); void fast_export_end_commit(uint32_t revision); void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input); +void fast_export_buf_to_data(const struct strbuf *data); void fast_export_blob_delta(uint32_t mode, uint32_t old_mode, const char *old_data, off_t len, struct line_buffer *input); diff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c index 01fcb842f..57cc1cec0 100644 --- a/vcs-svn/line_buffer.c +++ b/vcs-svn/line_buffer.c @@ -124,7 +124,3 @@ off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes) } return done; } - -void buffer_reset(struct line_buffer *buf) -{ -} diff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h index 8901f214b..ee23b4f49 100644 --- a/vcs-svn/line_buffer.h +++ b/vcs-svn/line_buffer.h @@ -14,7 +14,6 @@ struct line_buffer { int buffer_init(struct line_buffer *buf, const char *filename); int buffer_fdinit(struct line_buffer *buf, int fd); int buffer_deinit(struct line_buffer *buf); -void buffer_reset(struct line_buffer *buf); int buffer_tmpfile_init(struct line_buffer *buf); FILE *buffer_tmpfile_rewind(struct line_buffer *buf); /* prepare to write. */ diff --git a/vcs-svn/sliding_window.c b/vcs-svn/sliding_window.c index ec2707c9c..f11d49099 100644 --- a/vcs-svn/sliding_window.c +++ b/vcs-svn/sliding_window.c @@ -54,7 +54,7 @@ int move_window(struct sliding_view *view, off_t off, size_t width) return -1; if (off < view->off || off + width < view->off + view->width) return error("invalid delta: window slides left"); - if (view->max_off >= 0 && view->max_off < off + width) + if (view->max_off >= 0 && view->max_off < off + (off_t) width) return error("delta preimage ends early"); file_offset = view->off + view->buf.len; diff --git a/vcs-svn/svndiff.c b/vcs-svn/svndiff.c index 1647c1a78..74c97c454 100644 --- a/vcs-svn/svndiff.c +++ b/vcs-svn/svndiff.c @@ -77,8 +77,9 @@ static int error_short_read(struct line_buffer *input) static int read_chunk(struct line_buffer *delta, off_t *delta_len, struct strbuf *buf, size_t len) { + assert(*delta_len >= 0); strbuf_reset(buf); - if (len > *delta_len || + if (len > (uintmax_t) *delta_len || buffer_read_binary(delta, buf, len) != len) return error_short_read(delta); *delta_len -= buf->len; @@ -258,6 +259,7 @@ static int apply_window_in_core(struct window *ctx) static int apply_one_window(struct line_buffer *delta, off_t *delta_len, struct sliding_view *preimage, FILE *out) { + int rv = -1; struct window ctx = WINDOW_INIT(preimage); size_t out_len; size_t instructions_len; @@ -275,27 +277,26 @@ static int apply_one_window(struct line_buffer *delta, off_t *delta_len, if (apply_window_in_core(&ctx)) goto error_out; if (ctx.out.len != out_len) { - error("invalid delta: incorrect postimage length"); + rv = error("invalid delta: incorrect postimage length"); goto error_out; } if (write_strbuf(&ctx.out, out)) goto error_out; - window_release(&ctx); - return 0; + rv = 0; error_out: window_release(&ctx); - return -1; + return rv; } int svndiff0_apply(struct line_buffer *delta, off_t delta_len, struct sliding_view *preimage, FILE *postimage) { - assert(delta && preimage && postimage); + assert(delta && preimage && postimage && delta_len >= 0); if (read_magic(delta, &delta_len)) return -1; while (delta_len) { /* For each window: */ - off_t pre_off = pre_off; /* stupid GCC... */ + off_t pre_off = -1; size_t pre_len; if (read_offset(delta, &pre_off, &delta_len) || diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c index 0899790a3..31d1d83d4 100644 --- a/vcs-svn/svndump.c +++ b/vcs-svn/svndump.c @@ -34,14 +34,13 @@ #define NODE_CTX 2 /* node metadata */ #define INTERNODE_CTX 3 /* between nodes */ -#define LENGTH_UNKNOWN (~0) #define DATE_RFC2822_LEN 31 static struct line_buffer input = LINE_BUFFER_INIT; static struct { - uint32_t action, propLength, srcRev, type; - off_t text_length; + uint32_t action, srcRev, type; + off_t prop_length, text_length; struct strbuf src, dst; uint32_t text_delta, prop_delta; } node_ctx; @@ -49,7 +48,7 @@ static struct { static struct { uint32_t revision; unsigned long timestamp; - struct strbuf log, author; + struct strbuf log, author, note; } rev_ctx; static struct { @@ -61,7 +60,7 @@ static void reset_node_ctx(char *fname) { node_ctx.type = 0; node_ctx.action = NODEACT_UNKNOWN; - node_ctx.propLength = LENGTH_UNKNOWN; + node_ctx.prop_length = -1; node_ctx.text_length = -1; strbuf_reset(&node_ctx.src); node_ctx.srcRev = 0; @@ -78,6 +77,7 @@ static void reset_rev_ctx(uint32_t revision) rev_ctx.timestamp = 0; strbuf_reset(&rev_ctx.log); strbuf_reset(&rev_ctx.author); + strbuf_reset(&rev_ctx.note); } static void reset_dump_ctx(const char *url) @@ -209,7 +209,7 @@ static void read_props(void) static void handle_node(void) { const uint32_t type = node_ctx.type; - const int have_props = node_ctx.propLength != LENGTH_UNKNOWN; + const int have_props = node_ctx.prop_length != -1; const int have_text = node_ctx.text_length != -1; /* * Old text for this node: @@ -273,7 +273,7 @@ static void handle_node(void) if (have_props) { if (!node_ctx.prop_delta) node_ctx.type = type; - if (node_ctx.propLength) + if (node_ctx.prop_length) read_props(); } @@ -300,22 +300,29 @@ static void handle_node(void) node_ctx.text_length, &input); } -static void begin_revision(void) +static void begin_revision(const char *remote_ref) { if (!rev_ctx.revision) /* revision 0 gets no git commit. */ return; fast_export_begin_commit(rev_ctx.revision, rev_ctx.author.buf, &rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf, - rev_ctx.timestamp); + rev_ctx.timestamp, remote_ref); } -static void end_revision(void) +static void end_revision(const char *note_ref) { - if (rev_ctx.revision) + struct strbuf mark = STRBUF_INIT; + if (rev_ctx.revision) { fast_export_end_commit(rev_ctx.revision); + fast_export_begin_note(rev_ctx.revision, "remote-svn", + "Note created by remote-svn.", rev_ctx.timestamp, note_ref); + strbuf_addf(&mark, ":%"PRIu32, rev_ctx.revision); + fast_export_note(mark.buf, "inline"); + fast_export_buf_to_data(&rev_ctx.note); + } } -void svndump_read(const char *url) +void svndump_read(const char *url, const char *local_ref, const char *notes_ref) { char *val; char *t; @@ -354,26 +361,29 @@ void svndump_read(const char *url) if (active_ctx == NODE_CTX) handle_node(); if (active_ctx == REV_CTX) - begin_revision(); + begin_revision(local_ref); if (active_ctx != DUMP_CTX) - end_revision(); + end_revision(notes_ref); active_ctx = REV_CTX; reset_rev_ctx(atoi(val)); + strbuf_addf(&rev_ctx.note, "%s\n", t); break; case sizeof("Node-path"): - if (prefixcmp(t, "Node-")) + if (constcmp(t, "Node-")) continue; if (!constcmp(t + strlen("Node-"), "path")) { if (active_ctx == NODE_CTX) handle_node(); if (active_ctx == REV_CTX) - begin_revision(); + begin_revision(local_ref); active_ctx = NODE_CTX; reset_node_ctx(val); + strbuf_addf(&rev_ctx.note, "%s\n", t); break; } if (constcmp(t + strlen("Node-"), "kind")) continue; + strbuf_addf(&rev_ctx.note, "%s\n", t); if (!strcmp(val, "dir")) node_ctx.type = REPO_MODE_DIR; else if (!strcmp(val, "file")) @@ -384,6 +394,7 @@ void svndump_read(const char *url) case sizeof("Node-action"): if (constcmp(t, "Node-action")) continue; + strbuf_addf(&rev_ctx.note, "%s\n", t); if (!strcmp(val, "delete")) { node_ctx.action = NODEACT_DELETE; } else if (!strcmp(val, "add")) { @@ -402,29 +413,35 @@ void svndump_read(const char *url) continue; strbuf_reset(&node_ctx.src); strbuf_addstr(&node_ctx.src, val); + strbuf_addf(&rev_ctx.note, "%s\n", t); break; case sizeof("Node-copyfrom-rev"): if (constcmp(t, "Node-copyfrom-rev")) continue; node_ctx.srcRev = atoi(val); + strbuf_addf(&rev_ctx.note, "%s\n", t); break; case sizeof("Text-content-length"): - if (!constcmp(t, "Text-content-length")) { + if (constcmp(t, "Text") && constcmp(t, "Prop")) + continue; + if (constcmp(t + 4, "-content-length")) + continue; + { char *end; - uintmax_t textlen; + uintmax_t len; - textlen = strtoumax(val, &end, 10); + len = strtoumax(val, &end, 10); if (!isdigit(*val) || *end) die("invalid dump: non-numeric length %s", val); - if (textlen > maximum_signed_value_of_type(off_t)) + if (len > maximum_signed_value_of_type(off_t)) die("unrepresentable length in dump: %s", val); - node_ctx.text_length = (off_t) textlen; + + if (*t == 'T') + node_ctx.text_length = (off_t) len; + else + node_ctx.prop_length = (off_t) len; break; } - if (constcmp(t, "Prop-content-length")) - continue; - node_ctx.propLength = atoi(val); - break; case sizeof("Text-delta"): if (!constcmp(t, "Text-delta")) { node_ctx.text_delta = !strcmp(val, "true"); @@ -460,25 +477,40 @@ void svndump_read(const char *url) if (active_ctx == NODE_CTX) handle_node(); if (active_ctx == REV_CTX) - begin_revision(); + begin_revision(local_ref); if (active_ctx != DUMP_CTX) - end_revision(); + end_revision(notes_ref); } -int svndump_init(const char *filename) +static void init(int report_fd) { - if (buffer_init(&input, filename)) - return error("cannot open %s: %s", filename, strerror(errno)); - fast_export_init(REPORT_FILENO); + fast_export_init(report_fd); strbuf_init(&dump_ctx.uuid, 4096); strbuf_init(&dump_ctx.url, 4096); strbuf_init(&rev_ctx.log, 4096); strbuf_init(&rev_ctx.author, 4096); + strbuf_init(&rev_ctx.note, 4096); strbuf_init(&node_ctx.src, 4096); strbuf_init(&node_ctx.dst, 4096); reset_dump_ctx(NULL); reset_rev_ctx(0); reset_node_ctx(NULL); + return; +} + +int svndump_init(const char *filename) +{ + if (buffer_init(&input, filename)) + return error("cannot open %s: %s", filename ? filename : "NULL", strerror(errno)); + init(REPORT_FILENO); + return 0; +} + +int svndump_init_fd(int in_fd, int back_fd) +{ + if(buffer_fdinit(&input, xdup(in_fd))) + return error("cannot open fd %d: %s", in_fd, strerror(errno)); + init(xdup(back_fd)); return 0; } @@ -489,6 +521,8 @@ void svndump_deinit(void) reset_rev_ctx(0); reset_node_ctx(NULL); strbuf_release(&rev_ctx.log); + strbuf_release(&rev_ctx.author); + strbuf_release(&rev_ctx.note); strbuf_release(&node_ctx.src); strbuf_release(&node_ctx.dst); if (buffer_deinit(&input)) @@ -499,8 +533,6 @@ void svndump_deinit(void) void svndump_reset(void) { - fast_export_reset(); - buffer_reset(&input); strbuf_release(&dump_ctx.uuid); strbuf_release(&dump_ctx.url); strbuf_release(&rev_ctx.log); diff --git a/vcs-svn/svndump.h b/vcs-svn/svndump.h index df9ceb0e8..b8eb12954 100644 --- a/vcs-svn/svndump.h +++ b/vcs-svn/svndump.h @@ -2,7 +2,8 @@ #define SVNDUMP_H_ int svndump_init(const char *filename); -void svndump_read(const char *url); +int svndump_init_fd(int in_fd, int back_fd); +void svndump_read(const char *url, const char *local_ref, const char *notes_ref); void svndump_deinit(void); void svndump_reset(void); diff --git a/version.c b/version.c new file mode 100644 index 000000000..6106a8098 --- /dev/null +++ b/version.c @@ -0,0 +1,38 @@ +#include "git-compat-util.h" +#include "version.h" +#include "strbuf.h" + +const char git_version_string[] = GIT_VERSION; + +const char *git_user_agent(void) +{ + static const char *agent = NULL; + + if (!agent) { + agent = getenv("GIT_USER_AGENT"); + if (!agent) + agent = GIT_USER_AGENT; + } + + return agent; +} + +const char *git_user_agent_sanitized(void) +{ + static const char *agent = NULL; + + if (!agent) { + struct strbuf buf = STRBUF_INIT; + int i; + + strbuf_addstr(&buf, git_user_agent()); + strbuf_trim(&buf); + for (i = 0; i < buf.len; i++) { + if (buf.buf[i] <= 32 || buf.buf[i] >= 127) + buf.buf[i] = '.'; + } + agent = buf.buf; + } + + return agent; +} diff --git a/version.h b/version.h new file mode 100644 index 000000000..6911a4f15 --- /dev/null +++ b/version.h @@ -0,0 +1,9 @@ +#ifndef VERSION_H +#define VERSION_H + +extern const char git_version_string[]; + +const char *git_user_agent(void); +const char *git_user_agent_sanitized(void); + +#endif /* VERSION_H */ @@ -229,7 +229,7 @@ int xmkstemp(char *template) int saved_errno = errno; const char *nonrelative_template; - if (!template[0]) + if (strlen(template) != strlen(origtemplate)) template = origtemplate; nonrelative_template = absolute_path(template); @@ -403,6 +403,27 @@ int remove_or_warn(unsigned int mode, const char *file) return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file); } +void warn_on_inaccessible(const char *path) +{ + warning(_("unable to access '%s': %s"), path, strerror(errno)); +} + +int access_or_warn(const char *path, int mode) +{ + int ret = access(path, mode); + if (ret && errno != ENOENT && errno != ENOTDIR) + warn_on_inaccessible(path); + return ret; +} + +int access_or_die(const char *path, int mode) +{ + int ret = access(path, mode); + if (ret && errno != ENOENT && errno != ENOTDIR) + die_errno(_("unable to access '%s'"), path); + return ret; +} + struct passwd *xgetpwuid_self(void) { struct passwd *pw; diff --git a/write_or_die.c b/write_or_die.c index d45b53602..960f448cf 100644 --- a/write_or_die.c +++ b/write_or_die.c @@ -34,12 +34,7 @@ void maybe_flush_or_die(FILE *f, const char *desc) return; } if (fflush(f)) { - /* - * On Windows, EPIPE is returned only by the first write() - * after the reading end has closed its handle; subsequent - * write()s return EINVAL. - */ - if (errno == EPIPE || errno == EINVAL) + if (errno == EPIPE) exit(0); die_errno("write failure on '%s'", desc); } diff --git a/wt-status.c b/wt-status.c index dd6d8c410..2a9658bad 100644 --- a/wt-status.c +++ b/wt-status.c @@ -12,6 +12,7 @@ #include "refs.h" #include "submodule.h" #include "column.h" +#include "strbuf.h" static char default_wt_status_colors[][COLOR_MAXLEN] = { GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */ @@ -99,8 +100,8 @@ void status_printf(struct wt_status *s, const char *color, va_end(ap); } -void status_printf_more(struct wt_status *s, const char *color, - const char *fmt, ...) +static void status_printf_more(struct wt_status *s, const char *color, + const char *fmt, ...) { va_list ap; @@ -130,9 +131,34 @@ void wt_status_prepare(struct wt_status *s) static void wt_status_print_unmerged_header(struct wt_status *s) { + int i; + int del_mod_conflict = 0; + int both_deleted = 0; + int not_deleted = 0; const char *c = color(WT_STATUS_HEADER, s); status_printf_ln(s, c, _("Unmerged paths:")); + + for (i = 0; i < s->change.nr; i++) { + struct string_list_item *it = &(s->change.items[i]); + struct wt_status_change_data *d = it->util; + + switch (d->stagemask) { + case 0: + break; + case 1: + both_deleted = 1; + break; + case 3: + case 5: + del_mod_conflict = 1; + break; + default: + not_deleted = 1; + break; + } + } + if (!advice_status_hints) return; if (s->whence != FROM_COMMIT) @@ -141,7 +167,17 @@ static void wt_status_print_unmerged_header(struct wt_status *s) status_printf_ln(s, c, _(" (use \"git reset %s <file>...\" to unstage)"), s->reference); else status_printf_ln(s, c, _(" (use \"git rm --cached <file>...\" to unstage)")); - status_printf_ln(s, c, _(" (use \"git add/rm <file>...\" as appropriate to mark resolution)")); + + if (!both_deleted) { + if (!del_mod_conflict) + status_printf_ln(s, c, _(" (use \"git add <file>...\" to mark resolution)")); + else + status_printf_ln(s, c, _(" (use \"git add/rm <file>...\" as appropriate to mark resolution)")); + } else if (!del_mod_conflict && !not_deleted) { + status_printf_ln(s, c, _(" (use \"git rm <file>...\" to mark resolution)")); + } else { + status_printf_ln(s, c, _(" (use \"git add/rm <file>...\" as appropriate to mark resolution)")); + } status_printf_ln(s, c, ""); } @@ -185,7 +221,7 @@ static void wt_status_print_other_header(struct wt_status *s, const char *how) { const char *c = color(WT_STATUS_HEADER, s); - status_printf_ln(s, c, _("%s files:"), what); + status_printf_ln(s, c, "%s:", what); if (!advice_status_hints) return; status_printf_ln(s, c, _(" (use \"git %s <file>...\" to include in what will be committed)"), how); @@ -728,6 +764,211 @@ static void wt_status_print_tracking(struct wt_status *s) color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); } +static int has_unmerged(struct wt_status *s) +{ + int i; + + for (i = 0; i < s->change.nr; i++) { + struct wt_status_change_data *d; + d = s->change.items[i].util; + if (d->stagemask) + return 1; + } + return 0; +} + +static void show_merge_in_progress(struct wt_status *s, + struct wt_status_state *state, + const char *color) +{ + if (has_unmerged(s)) { + status_printf_ln(s, color, _("You have unmerged paths.")); + if (advice_status_hints) + status_printf_ln(s, color, + _(" (fix conflicts and run \"git commit\")")); + } else { + status_printf_ln(s, color, + _("All conflicts fixed but you are still merging.")); + if (advice_status_hints) + status_printf_ln(s, color, + _(" (use \"git commit\" to conclude merge)")); + } + wt_status_print_trailer(s); +} + +static void show_am_in_progress(struct wt_status *s, + struct wt_status_state *state, + const char *color) +{ + status_printf_ln(s, color, + _("You are in the middle of an am session.")); + if (state->am_empty_patch) + status_printf_ln(s, color, + _("The current patch is empty.")); + if (advice_status_hints) { + if (!state->am_empty_patch) + status_printf_ln(s, color, + _(" (fix conflicts and then run \"git am --resolved\")")); + status_printf_ln(s, color, + _(" (use \"git am --skip\" to skip this patch)")); + status_printf_ln(s, color, + _(" (use \"git am --abort\" to restore the original branch)")); + } + wt_status_print_trailer(s); +} + +static char *read_line_from_git_path(const char *filename) +{ + struct strbuf buf = STRBUF_INIT; + FILE *fp = fopen(git_path("%s", filename), "r"); + if (!fp) { + strbuf_release(&buf); + return NULL; + } + strbuf_getline(&buf, fp, '\n'); + if (!fclose(fp)) { + return strbuf_detach(&buf, NULL); + } else { + strbuf_release(&buf); + return NULL; + } +} + +static int split_commit_in_progress(struct wt_status *s) +{ + int split_in_progress = 0; + char *head = read_line_from_git_path("HEAD"); + char *orig_head = read_line_from_git_path("ORIG_HEAD"); + char *rebase_amend = read_line_from_git_path("rebase-merge/amend"); + char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head"); + + if (!head || !orig_head || !rebase_amend || !rebase_orig_head || + !s->branch || strcmp(s->branch, "HEAD")) + return split_in_progress; + + if (!strcmp(rebase_amend, rebase_orig_head)) { + if (strcmp(head, rebase_amend)) + split_in_progress = 1; + } else if (strcmp(orig_head, rebase_orig_head)) { + split_in_progress = 1; + } + + if (!s->amend && !s->nowarn && !s->workdir_dirty) + split_in_progress = 0; + + free(head); + free(orig_head); + free(rebase_amend); + free(rebase_orig_head); + return split_in_progress; +} + +static void show_rebase_in_progress(struct wt_status *s, + struct wt_status_state *state, + const char *color) +{ + struct stat st; + + if (has_unmerged(s)) { + status_printf_ln(s, color, _("You are currently rebasing.")); + if (advice_status_hints) { + status_printf_ln(s, color, + _(" (fix conflicts and then run \"git rebase --continue\")")); + status_printf_ln(s, color, + _(" (use \"git rebase --skip\" to skip this patch)")); + status_printf_ln(s, color, + _(" (use \"git rebase --abort\" to check out the original branch)")); + } + } else if (state->rebase_in_progress || !stat(git_path("MERGE_MSG"), &st)) { + status_printf_ln(s, color, _("You are currently rebasing.")); + if (advice_status_hints) + status_printf_ln(s, color, + _(" (all conflicts fixed: run \"git rebase --continue\")")); + } else if (split_commit_in_progress(s)) { + status_printf_ln(s, color, _("You are currently splitting a commit during a rebase.")); + if (advice_status_hints) + status_printf_ln(s, color, + _(" (Once your working directory is clean, run \"git rebase --continue\")")); + } else { + status_printf_ln(s, color, _("You are currently editing a commit during a rebase.")); + if (advice_status_hints && !s->amend) { + status_printf_ln(s, color, + _(" (use \"git commit --amend\" to amend the current commit)")); + status_printf_ln(s, color, + _(" (use \"git rebase --continue\" once you are satisfied with your changes)")); + } + } + wt_status_print_trailer(s); +} + +static void show_cherry_pick_in_progress(struct wt_status *s, + struct wt_status_state *state, + const char *color) +{ + status_printf_ln(s, color, _("You are currently cherry-picking.")); + if (advice_status_hints) { + if (has_unmerged(s)) + status_printf_ln(s, color, + _(" (fix conflicts and run \"git commit\")")); + else + status_printf_ln(s, color, + _(" (all conflicts fixed: run \"git commit\")")); + } + wt_status_print_trailer(s); +} + +static void show_bisect_in_progress(struct wt_status *s, + struct wt_status_state *state, + const char *color) +{ + status_printf_ln(s, color, _("You are currently bisecting.")); + if (advice_status_hints) + status_printf_ln(s, color, + _(" (use \"git bisect reset\" to get back to the original branch)")); + wt_status_print_trailer(s); +} + +static void wt_status_print_state(struct wt_status *s) +{ + const char *state_color = color(WT_STATUS_HEADER, s); + struct wt_status_state state; + struct stat st; + + memset(&state, 0, sizeof(state)); + + if (!stat(git_path("MERGE_HEAD"), &st)) { + state.merge_in_progress = 1; + } else if (!stat(git_path("rebase-apply"), &st)) { + if (!stat(git_path("rebase-apply/applying"), &st)) { + state.am_in_progress = 1; + if (!stat(git_path("rebase-apply/patch"), &st) && !st.st_size) + state.am_empty_patch = 1; + } else { + state.rebase_in_progress = 1; + } + } else if (!stat(git_path("rebase-merge"), &st)) { + if (!stat(git_path("rebase-merge/interactive"), &st)) + state.rebase_interactive_in_progress = 1; + else + state.rebase_in_progress = 1; + } else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) { + state.cherry_pick_in_progress = 1; + } + if (!stat(git_path("BISECT_LOG"), &st)) + state.bisect_in_progress = 1; + + if (state.merge_in_progress) + show_merge_in_progress(s, &state, state_color); + else if (state.am_in_progress) + show_am_in_progress(s, &state, state_color); + else if (state.rebase_in_progress || state.rebase_interactive_in_progress) + show_rebase_in_progress(s, &state, state_color); + else if (state.cherry_pick_in_progress) + show_cherry_pick_in_progress(s, &state, state_color); + if (state.bisect_in_progress) + show_bisect_in_progress(s, &state, state_color); +} + void wt_status_print(struct wt_status *s) { const char *branch_color = color(WT_STATUS_ONBRANCH, s); @@ -750,6 +991,7 @@ void wt_status_print(struct wt_status *s) wt_status_print_tracking(s); } + wt_status_print_state(s); if (s->is_initial) { status_printf_ln(s, color(WT_STATUS_HEADER, s), ""); status_printf_ln(s, color(WT_STATUS_HEADER, s), _("Initial commit")); @@ -766,9 +1008,9 @@ void wt_status_print(struct wt_status *s) wt_status_print_submodule_summary(s, 1); /* unstaged */ } if (s->show_untracked_files) { - wt_status_print_other(s, &s->untracked, _("Untracked"), "add"); + wt_status_print_other(s, &s->untracked, _("Untracked files"), "add"); if (s->show_ignored_files) - wt_status_print_other(s, &s->ignored, _("Ignored"), "add -f"); + wt_status_print_other(s, &s->ignored, _("Ignored files"), "add -f"); } else if (s->commitable) status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"), advice_status_hints @@ -781,23 +1023,31 @@ void wt_status_print(struct wt_status *s) status_printf_ln(s, GIT_COLOR_NORMAL, _("No changes")); else if (s->nowarn) ; /* nothing */ - else if (s->workdir_dirty) - printf(_("no changes added to commit%s\n"), - advice_status_hints - ? _(" (use \"git add\" and/or \"git commit -a\")") : ""); - else if (s->untracked.nr) - printf(_("nothing added to commit but untracked files present%s\n"), - advice_status_hints - ? _(" (use \"git add\" to track)") : ""); - else if (s->is_initial) - printf(_("nothing to commit%s\n"), advice_status_hints - ? _(" (create/copy files and use \"git add\" to track)") : ""); - else if (!s->show_untracked_files) - printf(_("nothing to commit%s\n"), advice_status_hints - ? _(" (use -u to show untracked files)") : ""); - else - printf(_("nothing to commit%s\n"), advice_status_hints - ? _(" (working directory clean)") : ""); + else if (s->workdir_dirty) { + if (advice_status_hints) + printf(_("no changes added to commit " + "(use \"git add\" and/or \"git commit -a\")\n")); + else + printf(_("no changes added to commit\n")); + } else if (s->untracked.nr) { + if (advice_status_hints) + printf(_("nothing added to commit but untracked files " + "present (use \"git add\" to track)\n")); + else + printf(_("nothing added to commit but untracked files present\n")); + } else if (s->is_initial) { + if (advice_status_hints) + printf(_("nothing to commit (create/copy files " + "and use \"git add\" to track)\n")); + else + printf(_("nothing to commit\n")); + } else if (!s->show_untracked_files) { + if (advice_status_hints) + printf(_("nothing to commit (use -u to show untracked files)\n")); + else + printf(_("nothing to commit\n")); + } else + printf(_("nothing to commit, working directory clean\n")); } } diff --git a/wt-status.h b/wt-status.h index 14aa9f7e1..236b41fd3 100644 --- a/wt-status.h +++ b/wt-status.h @@ -71,6 +71,16 @@ struct wt_status { struct string_list ignored; }; +struct wt_status_state { + int merge_in_progress; + int am_in_progress; + int am_empty_patch; + int rebase_in_progress; + int rebase_interactive_in_progress; + int cherry_pick_in_progress; + int bisect_in_progress; +}; + void wt_status_prepare(struct wt_status *s); void wt_status_print(struct wt_status *s); void wt_status_collect(struct wt_status *s); @@ -82,7 +92,5 @@ void status_printf_ln(struct wt_status *s, const char *color, const char *fmt, . ; void status_printf(struct wt_status *s, const char *color, const char *fmt, ...) ; -void status_printf_more(struct wt_status *s, const char *color, const char *fmt, ...) - __attribute__((format(printf, 3, 4))); #endif /* STATUS_H */ |