/test-string-list
/test-subprocess
/test-svn-fe
+/test-urlmatch-normalization
/test-wildmatch
/common-cmds.h
*.tar.gz
Ted Percival <ted@midg3t.net> <ted.percival@quest.com>
Theodore Ts'o <tytso@mit.edu>
Thomas Ackermann <th.acker@arcor.de> <th.acker66@arcor.de>
-Thomas Rast <trast@inf.ethz.ch> <trast@student.ethz.ch>
+Thomas Rast <tr@thomasrast.ch> <trast@student.ethz.ch>
+Thomas Rast <tr@thomasrast.ch> <trast@inf.ethz.ch>
+Thomas Rast <tr@thomasrast.ch> <trast@google.com>
Timo Hirvonen <tihirvon@gmail.com> <tihirvon@ee.oulu.fi>
Toby Allsopp <Toby.Allsopp@navman.co.nz> <toby.allsopp@navman.co.nz>
Tom Grennan <tmgrennan@gmail.com> <tgrennan@redback.com>
they were describing changes. Often splitting a function
into two makes the intention of the code much clearer.
+ - Multi-line comments include their delimiters on separate lines from
+ the text. E.g.
+
+ /*
+ * A very long
+ * multi-line comment.
+ */
+
- Double negation is often harder to understand than no negation
at all.
processed into HTML and manpages (e.g. git.html and git.1 in the
same directory).
+ The documentation liberally mixes US and UK English (en_US/UK)
+ norms for spelling and grammar, which is somewhat unfortunate.
+ In an ideal world, it would have been better if it consistently
+ used only one and not the other, and we would have picked en_US
+ (if you wish to correct the English of some of the existing
+ documentation, please see the documentation-related advice in the
+ Documentation/SubmittingPatches file).
+
Every user-visible change should be reflected in the documentation.
The same general rule as for code applies -- imitate the existing
conventions. A few commented examples follow to provide reference
INSTALL_INFO = install-info
DOCBOOK2X_TEXI = docbook2x-texi
DBLATEX = dblatex
+ASCIIDOC_DBLATEX_DIR = /etc/asciidoc/dblatex
ifndef PERL_PATH
PERL_PATH = /usr/bin/perl
endif
user-manual.pdf: user-manual.xml
$(QUIET_DBLATEX)$(RM) $@+ $@ && \
- $(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \
+ $(DBLATEX) -o $@+ -p $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.xsl -s $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.sty $< && \
mv $@+ $@
gitman.texi: $(MAN_XML) cat-texi.perl
* "git diff --no-index" did not work with pagers correctly.
* "git diff COPYING HEAD:COPYING" gave a nonsense error message that
- claimed that the treeish HEAD did not have COPYING in it.
+ claimed that the tree-ish HEAD did not have COPYING in it.
* When "git log" gets "--simplify-merges/by-decoration" together with
"--first-parent", the combination of these options makes the
--- /dev/null
+Git v1.8.4.1 Release Notes
+========================
+
+Fixes since v1.8.4
+------------------
+
+ * Some old versions of bash do not grok some constructs like
+ 'printf -v varname' which the prompt and completion code started
+ to use recently. The completion and prompt scripts have been
+ adjusted to work better with these old versions of bash.
+
+ * In FreeBSD's and NetBSD's "sh", a return in a dot script in a
+ function returns from the function, not only in the dot script,
+ breaking "git rebase" on these platforms (regression introduced
+ in 1.8.4-rc1).
+
+ * "git rebase -i" and other scripted commands were feeding a
+ random, data dependant error message to 'echo' and expecting it
+ to come out literally.
+
+ * Setting the "submodule.<name>.path" variable to the empty
+ "true" caused the configuration parser to segfault.
+
+ * Output from "git log --full-diff -- <pathspec>" looked strange
+ because comparison was done with the previous ancestor that
+ touched the specified <pathspec>, causing the patches for paths
+ outside the pathspec to show more than the single commit has
+ changed.
+
+ * The auto-tag-following code in "git fetch" tries to reuse the
+ same transport twice when the serving end does not cooperate and
+ does not give tags that point to commits that are asked for as
+ part of the primary transfer. Unfortunately, Git-aware transport
+ helper interface is not designed to be used more than once, hence
+ this did not work over smart-http transfer. Fixed.
+
+ * Send a large request to read(2)/write(2) as a smaller but still
+ reasonably large chunks, which would improve the latency when the
+ operation needs to be killed and incidentally works around broken
+ 64-bit systems that cannot take a 2GB write or read in one go.
+
+ * A ".mailmap" file that ends with an incomplete line, when read
+ from a blob, was not handled properly.
+
+ * The recent "short-cut clone connectivity check" topic broke a
+ shallow repository when a fetch operation tries to auto-follow
+ tags.
+
+ * When send-email comes up with an error message to die with upon
+ failure to start an SSL session, it tried to read the error
+ string from a wrong place.
+
+ * A call to xread() was used without a loop to cope with short
+ read in the codepath to stream large blobs to a pack.
+
+ * On platforms with fgetc() and friends defined as macros, the
+ configuration parser did not compile.
+
+ * New versions of MediaWiki introduced a new API for returning
+ more than 500 results in response to a query, which would cause
+ the MediaWiki remote helper to go into an infinite loop.
+
+ * Subversion's serf access method (the only one available in
+ Subversion 1.8) for http and https URLs in skelta mode tells its
+ caller to open multiple files at a time, which made "git svn
+ fetch" complain that "Temp file with moniker 'svn_delta' already
+ in use" instead of fetching.
+
+
+Also contains a handful of trivial code clean-ups, documentation
+updates, updates to the test suite, etc.
--- /dev/null
+Git v1.8.4.2 Release Notes
+========================
+
+Fixes since v1.8.4.1
+--------------------
+
+ * "git clone" gave some progress messages to the standard output, not
+ to the standard error, and did not allow suppressing them with the
+ "--no-progress" option.
+
+ * "format-patch --from=<whom>" forgot to omit unnecessary in-body
+ from line, i.e. when <whom> is the same as the real author.
+
+ * "git shortlog" used to choke and die when there is a malformed
+ commit (e.g. missing authors); it now simply ignore such a commit
+ and keeps going.
+
+ * "git merge-recursive" did not parse its "--diff-algorithm=" command
+ line option correctly.
+
+ * "git branch --track" had a minor regression in v1.8.3.2 and later
+ that made it impossible to base your local work on anything but a
+ local branch of the upstream repository you are tracking from.
+
+ * "git ls-files -k" needs to crawl only the part of the working tree
+ that may overlap the paths in the index to find killed files, but
+ shared code with the logic to find all the untracked files, which
+ made it unnecessarily inefficient.
+
+ * When there is no sufficient overlap between old and new history
+ during a "git fetch" into a shallow repository, objects that the
+ sending side knows the receiving end has were unnecessarily sent.
+
+ * When running "fetch -q", a long silence while the sender side
+ computes the set of objects to send can be mistaken by proxies as
+ dropped connection. The server side has been taught to send a
+ small empty messages to keep the connection alive.
+
+ * When the webserver responds with "405 Method Not Allowed", "git
+ http-backend" should tell the client what methods are allowed with
+ the "Allow" header.
+
+ * "git cvsserver" computed the permission mode bits incorrectly for
+ executable files.
+
+ * The implementation of "add -i" has a crippling code to work around
+ ActiveState Perl limitation but it by mistake also triggered on Git
+ for Windows where MSYS perl is used.
+
+ * We made sure that we notice the user-supplied GIT_DIR is actually a
+ gitfile, but did not do the same when the default ".git" is a
+ gitfile.
+
+ * When an object is not found after checking the packfiles and then
+ loose object directory, read_sha1_file() re-checks the packfiles to
+ prevent racing with a concurrent repacker; teach the same logic to
+ has_sha1_file().
+
+ * "git commit --author=$name", when $name is not in the canonical
+ "A. U. Thor <au.thor@example.xz>" format, looks for a matching name
+ from existing history, but did not consult mailmap to grab the
+ preferred author name.
+
+ * The commit object names in the insn sheet that was prepared at the
+ beginning of "rebase -i" session can become ambiguous as the
+ rebasing progresses and the repository gains more commits. Make
+ sure the internal record is kept with full 40-hex object names.
+
+ * "git rebase --preserve-merges" internally used the merge machinery
+ and as a side effect, left merge summary message in the log, but
+ when rebasing, there should not be a need for merge summary.
+
+ * "git rebase -i" forgot that the comment character can be
+ configurable while reading its insn sheet.
+
+Also contains a handful of trivial code clean-ups, documentation
+updates, updates to the test suite, etc.
--- /dev/null
+Git v1.8.5 Release Notes
+========================
+
+Backward compatibility notes (for Git 2.0)
+------------------------------------------
+
+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). In Git 2.0, the default will change to the "simple"
+semantics that pushes:
+
+ - only the current branch to the branch with the same name, and only
+ when the current branch is set to integrate with that remote
+ branch, if you are pushing to the same remote as you fetch from; or
+
+ - only the current branch to the branch with the same name, if you
+ are pushing to a remote that is not where you usually fetch from.
+
+Use the user preference configuration variable "push.default" to
+change this. If you are an old-timer who is used to the "matching"
+semantics, you can set the variable to "matching" to keep the
+traditional behaviour. If you want to live in the future early, you
+can set it to "simple" today without waiting for Git 2.0.
+
+When "git add -u" (and "git add -A") is run inside a subdirectory and
+does not specify which paths to add on the command line, it
+will operate on the entire tree in Git 2.0 for consistency
+with "git commit -a" and other commands. There will be no
+mechanism to make plain "git add -u" behave like "git add -u .".
+Current users of "git add -u" (without a pathspec) should start
+training their fingers to explicitly say "git add -u ."
+before Git 2.0 comes. A warning is issued when these commands are
+run without a pathspec and when you have local changes outside the
+current directory, because the behaviour in Git 2.0 will be different
+from today's version in such a situation.
+
+In Git 2.0, "git add <path>" will behave as "git add -A <path>", so
+that "git add dir/" will notice paths you removed from the directory
+and record the removal. Versions before Git 2.0, including this
+release, will keep ignoring removals, but the users who rely on this
+behaviour are encouraged to start using "git add --ignore-removal <path>"
+now before 2.0 is released.
+
+The default prefix for "git svn" will change in Git 2.0. For a long
+time, "git svn" created its remote-tracking branches directly under
+refs/remotes, but it will place them under refs/remotes/origin/ unless
+it is told otherwise with its --prefix option.
+
+
+Updates since v1.8.4
+--------------------
+
+Foreign interfaces, subsystems and ports.
+
+ * "git-svn" used with SVN 1.8.0 when talking over https:// connection
+ dumped core due to a bug in the serf library that SVN uses. Work
+ it around on our side, even though the SVN side is being fixed.
+
+ * On MacOS X, we detected if the filesystem needs the "pre-composed
+ unicode strings" workaround, but did not automatically enable it.
+ Now we do.
+
+ * remote-hg remote helper misbehaved when interacting with a local Hg
+ repository relative to the home directory, e.g. "clone hg::~/there".
+
+ * imap-send ported to OS X uses Apple's security framework instead of
+ OpenSSL one.
+
+ * Subversion 1.8.0 that was recently released breaks older subversion
+ clients coming over http/https in various ways.
+
+ * "git fast-import" treats an empty path given to "ls" as the root of
+ the tree.
+
+
+UI, Workflows & Features
+
+ * "git grep" and "git show" pays attention to "--textconv" option
+ when these commands are told to operate on blob objects (e.g. "git
+ grep -e pattern HEAD:Makefile").
+
+ * "git replace" helper no longer allows an object to be replaced with
+ another object of a different type to avoid confusion (you can
+ still manually craft such replacement using "git update-ref", as an
+ escape hatch).
+
+ * "git status" no longer prints dirty status information for
+ submodules for which submodule.$name.ignore is set to "all".
+
+ * "git rebase -i" honours core.abbrev when preparing the insn sheet
+ for editing.
+
+ * "git status" during a cherry-pick shows what original commit is
+ being picked.
+
+ * Instead of typing four capital letters "HEAD", you can say "@" now,
+ e.g. "git log @".
+
+ * "git check-ignore" follows the same rule as "git add" and "git
+ status" in that the ignore/exclude mechanism does not take effect
+ on paths that are already tracked. With "--no-index" option, it
+ can be used to diagnose which paths that should have been ignored
+ have been mistakenly added to the index.
+
+ * Some irrelevant "advice" messages that are shared with "git status"
+ output have been removed from the commit log template.
+
+ * "update-refs" learnt a "--stdin" option to read multiple update
+ requests and perform them in an all-or-none fashion.
+
+ * Just like "make -C <directory>", "git -C <directory> ..." tells Git
+ to go there before doing anything else.
+
+ * Just like "git checkout -" knows to check out and "git merge -"
+ knows to merge the branch you were previously on, "git cherry-pick"
+ now understands "git cherry-pick -" to pick from the previous
+ branch.
+
+ * "git status" now omits the prefix to make its output a comment in a
+ commit log editor, which is not necessary for human consumption.
+ Scripts that parse the output of "git status" are advised to use
+ "git status --porcelain" instead, as its format is stable and easier
+ to parse.
+
+ * Make "foo^{tag}" to peel a tag to itself, i.e. no-op., and fail if
+ "foo" is not a tag. "git rev-parse --verify v1.0^{tag}" would be
+ a more convenient way to say "test $(git cat-file -t v1.0) = tag".
+
+ * "git branch -v -v" (and "git status") did not distinguish among a
+ branch that does not build on any other branch, a branch that is in
+ sync with the branch it builds on, and a branch that is configured
+ to build on some other branch that no longer exists.
+
+ * A packfile that stores the same object more than once is broken and
+ will be rejected by "git index-pack" that is run when receiving
+ data over the wire.
+
+ * Earlier we started rejecting an attempt to add 0{40} object name to
+ the index and to tree objects, but it sometimes is necessary to
+ allow so to be able to use tools like filter-branch to correct such
+ broken tree objects. "filter-branch" can again be used to to do
+ so.
+
+ * "git config" did not provide a way to set or access numbers larger
+ than a native "int" on the platform; it now provides 64-bit signed
+ integers on all platforms.
+
+ * "git pull --rebase" always chose to do the bog-standard flattening
+ rebase. You can tell it to run "rebase --preserve-merges" by
+ setting "pull.rebase" configuration to "preserve".
+
+ * "git push --no-thin" actually disables the "thin pack transfer"
+ optimization.
+
+ * Magic pathspecs like ":(icase)makefile" that matches both
+ Makefile and makefile can be used in more places.
+
+ * The "http.*" variables can now be specified per URL that the
+ configuration applies. For example,
+
+ [http]
+ sslVerify = true
+ [http "https://weak.example.com/"]
+ sslVerify = false
+
+ would flip http.sslVerify off only when talking to that specified
+ site.
+
+ * "git mv A B" when moving a submodule A has been taught to
+ relocate its working tree and to adjust the paths in the
+ .gitmodules file.
+
+ * "git blame" can now take more than one -L option to discover the
+ origin of multiple blocks of the lines.
+
+ * The http transport clients can optionally ask to save cookies
+ with http.savecookies configuration variable.
+
+ * "git push" learned a more fine grained control over a blunt
+ "--force" when requesting a non-fast-forward update with the
+ "--force-with-lease=<refname>:<expected object name>" option.
+
+ * "git diff --diff-filter=<classes of changes>" can now take
+ lowercase letters (e.g. "--diff-filter=d") to mean "show
+ everything but these classes". "git diff-files -q" is now a
+ deprecated synonym for "git diff-files --diff-filter=d".
+
+ * "git fetch" (hence "git pull" as well) learned to check
+ "fetch.prune" and "remote.*.prune" configuration variables and
+ to behave as if the "--prune" command line option was given.
+
+ * "git check-ignore -z" applied the NUL termination to both its input
+ (with --stdin) and its output, but "git check-attr -z" ignored the
+ option on the output side. Make both honor -z on the input and
+ output side the same way.
+
+ * "git whatchanged" may still be used by old timers, but mention of
+ it in documents meant for new users will only waste readers' time
+ wonderig what the difference is between it and "git log". Make it
+ less prominent in the general part of the documentation and explain
+ that it is merely a "git log" with different default behaviour in
+ its own document.
+
+
+Performance, Internal Implementation, etc.
+
+ * The HTTP transport will try to use TCP keepalive when able.
+
+ * "git repack" is now written in C.
+
+ * Build procedure for MSVC has been updated.
+
+ * If a build-time fallback is set to "cat" instead of "less", we
+ should apply the same "no subprocess or pipe" optimization as we
+ apply to user-supplied GIT_PAGER=cat.
+
+ * Many commands use --dashed-option as a operation mode selector
+ (e.g. "git tag --delete") that the user can use at most one
+ (e.g. "git tag --delete --verify" is a nonsense) and you cannot
+ negate (e.g. "git tag --no-delete" is a nonsense). parse-options
+ API learned a new OPT_CMDMODE macro to make it easier to implement
+ such a set of options.
+
+ * OPT_BOOLEAN() in parse-options API was misdesigned to be "counting
+ up" but many subcommands expect it to behave as "on/off". Update
+ them to use OPT_BOOL() which is a proper boolean.
+
+ * "git gc" exits early without doing a double-work when it detects
+ that another instance of itself is already running.
+
+ * Under memory pressure and/or file descriptor pressure, we used to
+ close pack windows that are not used and also closed filehandle to
+ an open but unused packfiles. These are now controlled separately
+ to better cope with the load.
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v1.8.4
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.4 in the maintenance
+track are contained in this release (see release notes to them for
+details).
+
+ * Coloring around octopus merges in "log --graph" output was screwy.
+ (merge 339c17b hn/log-graph-color-octopus later to maint).
+
+ * "git checkout topic", when there is not yet a local "topic" branch
+ but there is a unique remote-tracking branch for a remote "topic"
+ branch, pretended as if "git checkout -t -b topic remote/$r/topic"
+ (for that unique remote $r) was run. This hack however was not
+ implemented for "git checkout topic --".
+ (merge bca3969 mm/checkout-auto-track-fix later to maint).
+
+ * One long-standing flaw in the pack transfer protocol used by "git
+ clone" was that there was no way to tell the other end which branch
+ "HEAD" points at, and the receiving end needed to guess. A new
+ capability has been defined in the pack protocol to convey this
+ information so that cloning from a repository with more than one
+ branches pointing at the same commit where the HEAD is at now
+ reliably sets the initial branch in the resulting repository.
+ (merge 360a326 jc/upload-pack-send-symref later to maint).
+
+ * We did not handle cases where http transport gets redirected during
+ the authorization request (e.g. from http:// to https://).
+ (merge 70900ed jk/http-auth-redirects later to maint).
+
+ * Bash prompting code to deal with an SVN remote as an upstream
+ were coded in a way not supported by older Bash versions (3.x).
+ (merge 52ec889 sg/prompt-svn-remote-fix later to maint).
+
+ * The fall-back parsing of commit objects with broken author or
+ committer lines were less robust than ideal in picking up the
+ timestamps.
+ (merge 03818a4 jk/split-broken-ident later to maint).
+
+ * "git rev-list --objects ^v1.0^ v1.0" gave v1.0 tag itself in the
+ output, but "git rev-list --objects v1.0^..v1.0" did not.
+ (merge 895c5ba jc/revision-range-unpeel later to maint).
+
+ * "git clone" gave some progress messages to the standard output, not
+ to the standard error, and did not allow suppressing them with the
+ --no-progress option.
+ (merge 643f918 jk/clone-progress-to-stderr later to maint).
+
+ * "format-patch --from=<whom>" forgot to omit unnecessary in-body
+ from line, i.e. when <whom> is the same as the real author.
+ (merge 662cc30 jk/format-patch-from later to maint).
+
+ * "git shortlog" used to choke and die when there is a malformed
+ commit (e.g. missing authors); it now simply ignore such a commit
+ and keeps going.
+ (merge cd4f09e jk/shortlog-tolerate-broken-commit later to maint).
+
+ * "git merge-recursive" did not parse its "--diff-algorithm=" command
+ line option correctly.
+ (merge 6562928 jk/diff-algo later to maint).
+
+ * When running "fetch -q", a long silence while the sender side
+ computes the set of objects to send can be mistaken by proxies as
+ dropped connection. The server side has been taught to send a
+ small empty messages to keep the connection alive.
+ (merge 115dedd jk/upload-pack-keepalive later to maint).
+
+ * "git rebase" had a portability regression in v1.8.4 to trigger a
+ bug in some BSD shell implementations.
+ (merge 99855dd mm/rebase-continue-freebsd-WB later to maint).
+
+ * "git branch --track" had a minor regression in v1.8.3.2 and later
+ that made it impossible to base your local work on anything but a
+ local branch of the upstream repository you are tracking from.
+ (merge b0f49ff jh/checkout-auto-tracking later to maint).
+
+ * When the webserver responds with "405 Method Not Allowed", "git
+ http-backend" should tell the client what methods are allowed with
+ the "Allow" header.
+ (merge 9247be0 bc/http-backend-allow-405 later to maint).
+
+ * When there is no sufficient overlap between old and new history
+ during a "git fetch" into a shallow repository, objects that the
+ sending side knows the receiving end has were unnecessarily sent.
+ (merge f21d2a7 nd/fetch-into-shallow later to maint).
+
+ * "git cvsserver" computed the permission mode bits incorrectly for
+ executable files.
+ (merge 1b48d56 jc/cvsserver-perm-bit-fix later to maint).
+
+ * When send-email comes up with an error message to die with upon
+ failure to start an SSL session, it tried to read the error string
+ from a wrong place.
+ (merge 6cb0c88 bc/send-email-ssl-die-message-fix later to maint).
+
+ * The implementation of "add -i" has a crippling code to work around
+ ActiveState Perl limitation but it by mistake also triggered on Git
+ for Windows where MSYS perl is used.
+ (merge df17e77 js/add-i-mingw later to maint).
+
+ * We made sure that we notice the user-supplied GIT_DIR is actually a
+ gitfile, but did not do the same when the default ".git" is a
+ gitfile.
+ (merge 487a2b7 nd/git-dir-pointing-at-gitfile later to maint).
+
+ * When an object is not found after checking the packfiles and then
+ loose object directory, read_sha1_file() re-checks the packfiles to
+ prevent racing with a concurrent repacker; teach the same logic to
+ has_sha1_file().
+ (merge 45e8a74 jk/has-sha1-file-retry-packed later to maint).
+
+ * "git commit --author=$name", when $name is not in the canonical
+ "A. U. Thor <au.thor@example.xz>" format, looks for a matching name
+ from existing history, but did not consult mailmap to grab the
+ preferred author name.
+ (merge ea16794 ap/commit-author-mailmap later to maint).
+
+ * "git ls-files -k" needs to crawl only the part of the working tree
+ that may overlap the paths in the index to find killed files, but
+ shared code with the logic to find all the untracked files, which
+ made it unnecessarily inefficient.
+ (merge 680be04 jc/ls-files-killed-optim later to maint).
+
+ * The commit object names in the insn sheet that was prepared at the
+ beginning of "rebase -i" session can become ambiguous as the
+ rebasing progresses and the repository gains more commits. Make
+ sure the internal record is kept with full 40-hex object names.
+ (merge 75c6976 es/rebase-i-no-abbrev later to maint).
+
+ * "git rebase --preserve-merges" internally used the merge machinery
+ and as a side effect, left merge summary message in the log, but
+ when rebasing, there should not be a need for merge summary.
+ (merge a9f739c rt/rebase-p-no-merge-summary later to maint).
+
+ * A call to xread() was used without a loop around to cope with short
+ read in the codepath to stream new contents to a pack.
+ (merge e92527c js/xread-in-full later to maint).
+
+ * "git rebase -i" forgot that the comment character can be
+ configurable while reading its insn sheet.
+ (merge 7bca7af es/rebase-i-respect-core-commentchar later to maint).
+
+ * The mailmap support code read past the allocated buffer when the
+ mailmap file ended with an incomplete line.
+ (merge f972a16 jk/mailmap-incomplete-line later to maint).
+
+ * We used to send a large request to read(2)/write(2) as a single
+ system call, which was bad from the latency point of view when
+ the operation needs to be killed, and also triggered an error on
+ broken 64-bit systems that refuse to take more than 2GB read or
+ write in one go.
+ (merge a487916 sp/clip-read-write-to-8mb later to maint).
+
+ * "git fetch" that auto-followed tags incorrectly reused the
+ connection with Git-aware transport helper (like the sample "ext::"
+ helper shipped with Git).
+ (merge 0f73f8b jc/transport-do-not-use-connect-twice-in-fetch later to maint).
+
+ * "git log --full-diff -- <pathspec>" showed a huge diff for paths
+ outside the given <pathspec> for each commit, instead of showing
+ the change relative to the parent of the commit. "git reflog -p"
+ had a similar problem.
+ (merge 838f9a1 tr/log-full-diff-keep-true-parents later to maint).
+
+ * Setting submodule.*.path configuration variable to true (without
+ giving "= value") caused Git to segfault.
+ (merge 4b05440 jl/some-submodule-config-are-not-boolean later to maint).
+
+ * "git rebase -i" (there could be others, as the root cause is pretty
+ generic) fed a random, data dependeant string to 'echo' and
+ expects it to come out literally, corrupting its error message.
+ (merge 89b0230 mm/no-shell-escape-in-die-message later to maint).
+
+ * Some people still use rather old versions of bash, which cannot
+ grok some constructs like 'printf -v varname' the prompt and
+ completion code started to use recently.
+ (merge a44aa69 bc/completion-for-bash-3.0 later to maint).
+
+ * Code to read configuration from a blob object did not compile on
+ platforms with fgetc() etc. implemented as macros.
+ (merge 49d6cfa hv/config-from-blob later to maint-1.8.3).
+
+ * The recent "short-cut clone connectivity check" topic broke a
+ shallow repository when a fetch operation tries to auto-follow tags.
+ (merge 6da8bdc nd/fetch-pack-shallow-fix later to maint-1.8.3).
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
+Speaking of the documentation, it is currently a liberal mixture of US
+and UK English norms for spelling and grammar, which is somewhat
+unfortunate. A huge patch that touches the files all over the place
+only to correct the inconsistency is not welcome, though. Potential
+clashes with other changes that can result from such a patch are not
+worth it. We prefer to gradually reconcile the inconsistencies in
+favor of US English, with small and easily digestible patches, as a
+side effect of doing some other real work in the vicinity (e.g.
+rewriting a paragraph for clarity, while turning en_UK spelling to
+en_US). Obvious typographical fixes are much more welcomed ("teh ->
+"the"), preferably submitted as independent patches separate from
+other documentation changes.
+
+Oh, another thing. We are 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.
-L <start>,<end>::
-L :<regex>::
- Annotate only the given line range. <start> and <end> are optional.
- ``-L <start>'' or ``-L <start>,'' spans from <start> to end of file.
- ``-L ,<end>'' spans from start of file to <end>.
+ Annotate only the given line range. May be specified multiple times.
+ Overlapping ranges are allowed.
++
+<start> and <end> are optional. ``-L <start>'' or ``-L <start>,'' spans from
+<start> to end of file. ``-L ,<end>'' spans from start of file to <end>.
+
-<start> and <end> can take one of these forms:
-
include::line-range-format.txt[]
-l::
pushNeedsForce::
Shown when linkgit:git-push[1] rejects an update that
tries to overwrite a remote ref that points at an
- object that is not a committish, or make the remote
- ref point at an object that is not a committish.
+ object that is not a commit-ish, or make the remote
+ ref point at an object that is not a commit-ish.
statusHints::
Show directions on how to proceed from the current
state in the output of linkgit:git-status[1], in
When not configured the default commit message editor is used instead.
core.pager::
- The command that Git will use to paginate output. Can
- be overridden with the `GIT_PAGER` environment
- variable. Note that Git sets the `LESS` environment
- variable to `FRSX` if it is unset when it runs the
- pager. One can change these settings by setting the
- `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 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 -+S`. This will be passed to the shell by
- Git, which will translate the final command to
- `LESS=FRSX less -+S`.
+ Text viewer for use by Git commands (e.g., 'less'). The value
+ is meant to be interpreted by the shell. The order of preference
+ is the `$GIT_PAGER` environment variable, then `core.pager`
+ configuration, then `$PAGER`, and then the default chosen at
+ compile time (usually 'less').
++
+When the `LESS` environment variable is unset, Git sets it to `FRSX`
+(if `LESS` environment variable is set, Git does not change it at
+all). If you want to selectively override Git's default setting
+for `LESS`, you can set `core.pager` to e.g. `less -+S`. This will
+be passed to the shell by Git, which will translate the final
+command to `LESS=FRSX less -+S`. The environment tells the command
+to set the `S` option to chop long lines but the command line
+resets it to the default to fold long lines.
core.whitespace::
A comma separated list of common whitespace problems to
overridden by `branch.<name>.pushremote`. If no remote is
configured, or if you are not on any branch, it defaults to
`origin` for fetching and `remote.pushdefault` for pushing.
+ Additionally, `.` (a period) is the current local repository
+ (a dot-repository), see `branch.<name>.merge`'s final note below.
branch.<name>.pushremote::
When on branch <name>, it overrides `branch.<name>.remote` for
Specify multiple values to get an octopus merge.
If you wish to setup 'git pull' so that it merges into <name> from
another branch in the local repository, you can point
- branch.<name>.merge to the desired branch, and use the special setting
- `.` (a period) for branch.<name>.remote.
+ branch.<name>.merge to the desired branch, and use the relative path
+ setting `.` (a period) for branch.<name>.remote.
branch.<name>.mergeoptions::
Sets default options for merging into branch <name>. The syntax and
instead of merging the default branch from the default remote when
"git pull" is run. See "pull.rebase" for doing this in a non
branch-specific manner.
++
+ When preserve, also pass `--preserve-merges` along to 'git rebase'
+ so that locally committed merge commits will not be flattened
+ by running 'git pull'.
+
*NOTE*: this is a possibly dangerous operation; do *not* use
it unless you understand the implications (see linkgit:git-rebase[1]
working repository in gitweb (see linkgit:git-instaweb[1]).
clean.requireForce::
- A boolean to make git-clean do nothing unless given -f
- or -n. Defaults to true.
+ A boolean to make git-clean do nothing unless given -f,
+ -i or -n. Defaults to true.
color.branch::
A boolean to enable/disable color in the output of
especially on slow filesystems. If not set, the value of
`transfer.unpackLimit` is used instead.
+fetch.prune::
+ If true, fetch will automatically behave as if the `--prune`
+ option was given on the command line. See also `remote.<name>.prune`.
+
format.attach::
Enable multipart/mixed attachments as the default for
'format-patch'. The value can also be a double quoted string
of the file to read cookies from should be plain HTTP headers or
the Netscape/Mozilla cookie file format (see linkgit:curl[1]).
NOTE that the file specified with http.cookiefile is only used as
- input. No cookies will be stored in the file.
+ input unless http.saveCookies is set.
+
+http.savecookies::
+ If set, store cookies received during requests to the file specified by
+ http.cookiefile. Has no effect if http.cookiefile is unset.
http.sslVerify::
Whether to verify the SSL certificate when fetching or pushing
of common USER_AGENT strings (but not including those like git/1.7.1).
Can be overridden by the 'GIT_HTTP_USER_AGENT' environment variable.
+http.<url>.*::
+ Any of the http.* options above can be applied selectively to some urls.
+ For a config key to match a URL, each element of the config key is
+ compared to that of the URL, in the following order:
++
+--
+. Scheme (e.g., `https` in `https://example.com/`). This field
+ must match exactly between the config key and the URL.
+
+. Host/domain name (e.g., `example.com` in `https://example.com/`).
+ This field must match exactly between the config key and the URL.
+
+. Port number (e.g., `8080` in `http://example.com:8080/`).
+ This field must match exactly between the config key and the URL.
+ Omitted port numbers are automatically converted to the correct
+ default for the scheme before matching.
+
+. Path (e.g., `repo.git` in `https://example.com/repo.git`). The
+ path field of the config key must match the path field of the URL
+ either exactly or as a prefix of slash-delimited path elements. This means
+ a config key with path `foo/` matches URL path `foo/bar`. A prefix can only
+ match on a slash (`/`) boundary. Longer matches take precedence (so a config
+ key with path `foo/bar` is a better match to URL path `foo/bar` than a config
+ key with just path `foo/`).
+
+. User name (e.g., `user` in `https://user@example.com/repo.git`). If
+ the config key has a user name it must match the user name in the
+ URL exactly. If the config key does not have a user name, that
+ config key will match a URL with any user name (including none),
+ but at a lower precedence than a config key with a user name.
+--
++
+The list above is ordered by decreasing precedence; a URL that matches
+a config key's path is preferred to one that matches its user name. For example,
+if the URL is `https://user@example.com/foo/bar` a config key match of
+`https://example.com/foo` will be preferred over a config key match of
+`https://user@example.com`.
++
+All URLs are normalized before attempting any matching (the password part,
+if embedded in the URL, is always ignored for matching purposes) so that
+equivalent urls that are simply spelled differently will match properly.
+Environment variable settings always override any matches. The urls that are
+matched against are those given directly to Git commands. This means any URLs
+visited as a result of a redirection do not participate in matching.
+
i18n.commitEncoding::
Character encoding the commit messages are stored in; Git itself
does not care per se, but this information is necessary e.g. when
of merging the default branch from the default remote when "git
pull" is run. See "branch.<name>.rebase" for setting this on a
per-branch basis.
++
+ When preserve, also pass `--preserve-merges` along to 'git rebase'
+ so that locally committed merge commits will not be flattened
+ by running 'git pull'.
+
*NOTE*: this is a possibly dangerous operation; do *not* use
it unless you understand the implications (see linkgit:git-rebase[1]
Setting this to a value <vcs> will cause Git to interact with
the remote with the git-remote-<vcs> helper.
+remote.<name>.prune::
+ When set to true, fetching from this remote by default will also
+ remove any remote-tracking branches which no longer exist on the
+ remote (as if the `--prune` option was give on the command line).
+ Overrides `fetch.prune` settings, if any.
+
remotes.<group>::
The list of remotes which are fetched by "git remote update
<group>". See linkgit:git-remote[1].
Set to true to enable --branch by default in linkgit:git-status[1].
The option --no-branch takes precedence over this variable.
+status.displayCommentPrefix::
+ If set to true, linkgit:git-status[1] will insert a comment
+ prefix before each output line (starting with
+ `core.commentChar`, i.e. `#` by default). This was the
+ behavior of linkgit:git-status[1] in Git 1.8.4 and previous.
+ Defaults to false.
+
status.showUntrackedFiles::
By default, linkgit:git-status[1] and linkgit:git-commit[1] show
files which are not currently tracked by Git. Directories which
If this is set to a non zero number or true (identical to -1 or an
unlimited number), the submodule summary will be enabled and a
summary of commits for modified submodules will be shown (see
- --summary-limit option of linkgit:git-submodule[1]).
+ --summary-limit option of linkgit:git-submodule[1]). Please note
+ that the summary output command will be suppressed for all
+ submodules when `diff.ignoreSubmodules` is set to 'all' or only
+ for those submodules where `submodule.<name>.ignore=all`. To
+ also view the summary for ignored submodules you can either use
+ the --ignore-submodules=dirty command line option or the 'git
+ submodule summary' command, which shows a similar output but does
+ not honor these settings.
submodule.<name>.path::
submodule.<name>.url::
submodules that have untracked files in their work tree as changed.
This setting overrides any setting made in .gitmodules for this submodule,
both settings can be overridden on the command line by using the
- "--ignore-submodules" option.
+ "--ignore-submodules" option. The 'git submodule' commands are not
+ affected by this setting.
tar.umask::
This variable can be used to restrict the permission bits of
of a hidden ref (by default, such a request is rejected).
see also `uploadpack.hiderefs`.
+uploadpack.keepalive::
+ When `upload-pack` has started `pack-objects`, there may be a
+ quiet period while `pack-objects` prepares the pack. Normally
+ it would output progress information, but if `--quiet` was used
+ for the fetch, `pack-objects` will output nothing at all until
+ the pack data begins. Some clients and networks may consider
+ the server to be hung and give up. Setting this option instructs
+ `upload-pack` to send an empty keepalive packet every
+ `uploadpack.keepalive` seconds. Setting this option to 0
+ disables keepalive packets entirely. The default is 5 seconds.
+
url.<base>.insteadOf::
Any URL that starts with this value will be rewritten to
start, instead, with <base>. In cases where some site serves a
environment variables. See linkgit:git-commit-tree[1].
user.signingkey::
- If linkgit:git-tag[1] is not selecting the key you want it to
- automatically when creating a signed tag, you can override the
- default selection with this variable. This option is passed
- unchanged to gpg's --local-user parameter, so you may specify a key
- using any method that gpg supports.
+ If linkgit:git-tag[1] or linkgit:git-commit[1] is not selecting the
+ key you want it to automatically when creating a signed tag or
+ commit, you can override the default selection with this variable.
+ This option is passed unchanged to gpg's --local-user parameter,
+ so you may specify a key using any method that gpg supports.
web.browser::
Specify a web browser that may be used by some commands.
Sets the default value of --ignore-submodules. Note that this
affects only 'git diff' Porcelain, and not lower level 'diff'
commands such as 'git diff-files'. 'git checkout' also honors
- this setting when reporting uncommitted changes.
+ this setting when reporting uncommitted changes. Setting it to
+ 'all' disables the submodule summary normally shown by 'git commit'
+ and 'git status' when 'status.submodulesummary' is set unless it is
+ overridden by using the --ignore-submodules command line option.
+ The 'git submodule' commands are not affected by this setting.
diff.mnemonicprefix::
If set, 'git diff' uses a prefix pair that is different from the
* linkgit:git-shell[1] can be used as a 'restricted login shell'
for shared central repository users.
-link:howto/update-hook-example.txt[update hook howto] has a good
+link:howto/update-hook-example.html[update hook howto] has a good
example of managing a shared central repository.
--------
[verse]
'git blame' [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-e] [-p] [-w] [--incremental]
- [-L n,m | -L :fn] [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>]
+ [-L <range>] [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>]
[--abbrev=<n>] [<rev> | --contents <file> | --reverse <rev>] [--] <file>
DESCRIPTION
Annotates each line in the given file with information from the revision which
last modified the line. Optionally, start annotating from the given revision.
-The command can also limit the range of lines annotated.
+When specified one or more times, `-L` restricts annotation to the requested
+lines.
The origin of lines is automatically followed across whole-file
renames (currently there is no option to turn the rename-following
Unlike 'git blame' and 'git annotate' in older versions of git, the extent
of the annotation can be limited to both line ranges and revision
-ranges. When you are interested in finding the origin for
+ranges. The `-L` option, which limits annotation to a range of lines, may be
+specified multiple times.
+
+When you are interested in finding the origin for
lines 40-60 for file `foo`, you can use the `-L` option like so
(they mean the same thing -- both ask for 21 lines starting at
line 40):
new branch.
When a local branch is started off a remote-tracking branch, Git sets up the
-branch so that 'git pull' will appropriately merge from
+branch (specifically the `branch.<name>.remote` and `branch.<name>.merge`
+configuration entries) 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
-t::
--track::
- When creating a new branch, set up configuration to mark the
+ When creating a new branch, set up `branch.<name>.remote` and
+ `branch.<name>.merge` configuration entries to mark the
start-point branch as "upstream" from the new branch. This
configuration will tell git to show the relationship between the
two branches in `git status` and `git branch -v`. Furthermore,
--textconv::
Show the content as transformed by a textconv filter. In this case,
- <object> has be of the form <treeish>:<path>, or :<path> in order
+ <object> has be of the form <tree-ish>:<path>, or :<path> in order
to apply the filter to the content recorded in the index at <path>.
--batch::
------------
If `--batch` or `--batch-check` is given, `cat-file` will read objects
-from stdin, one per line, and print information about them.
-
-Each line is considered as a whole object name, and is parsed as if
-given to linkgit:git-rev-parse[1].
+from stdin, one per line, and print information about them. By default,
+the whole line is considered as an object, as if it were fed to
+linkgit:git-rev-parse[1].
You can specify the information shown for each object by using a custom
`<format>`. The `<format>` is copied literally to stdout for each
The size, in bytes, that the object takes up on disk. See the
note about on-disk sizes in the `CAVEATS` section below.
+`rest`::
+ If this atom is used in the output string, input lines are split
+ at the first whitespace boundary. All characters before that
+ whitespace are considered to be the object name; characters
+ after that first run of whitespace (i.e., the "rest" of the
+ line) are output in place of the `%(rest)` atom.
+
If no format is specified, the default format is `%(objectname)
%(objecttype) %(objectsize)`.
Read file names from stdin instead of from the command-line.
-z::
- Only meaningful with `--stdin`; paths are separated with a
- NUL character instead of a linefeed character.
+ The output format is modified to be machine-parseable.
+ If `--stdin` is also given, input paths are separated
+ with a NUL character instead of a linefeed character.
\--::
Interpret all preceding arguments as attributes and all following
The output is of the form:
<path> COLON SP <attribute> COLON SP <info> LF
+unless `-z` is in effect, in which case NUL is used as delimiter:
+<path> NUL <attribute> NUL <info> NUL
+
+
<path> is the path of a file being queried, <attribute> is an attribute
being queried and <info> can be either:
not be possible to distinguish between paths which match a
pattern and those which don't.
+--no-index::
+ Don't look in the index when undertaking the checks. This can
+ be used to debug why a path became tracked by e.g. `git add .`
+ and was not ignored by the rules as expected by the user or when
+ developing patterns including negation to match a path previously
+ added with `git add -f`.
+
OUTPUT
------
. They cannot contain a sequence `@{`.
+. They cannot be the single character `@`.
+
. They cannot contain a `\`.
These rules make it easy for shell script based tools to parse
--------
[verse]
'git checkout' [-q] [-f] [-m] [<branch>]
-'git checkout' [-q] [-f] [-m] [--detach] [<commit>]
+'git checkout' [-q] [-f] [-m] --detach [<branch>]
+'git checkout' [-q] [-f] [-m] [--detach] <commit>
'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
'git checkout' [-p|--patch] [<tree-ish>] [--] [<paths>...]
successful.
'git checkout' --detach [<branch>]::
-'git checkout' <commit>::
+'git checkout' [--detach] <commit>::
Prepare to work on top of <commit>, by detaching HEAD at it
(see "DETACHED HEAD" section), and updating the index and the
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.
+When the <commit> argument is a branch name, the `--detach` option can
+be used to detach HEAD at the tip of the branch (`git checkout
+<branch>` would check out that branch without detaching HEAD).
++
+Omitting <branch> detaches HEAD at the tip of the current branch.
'git checkout' [-p|--patch] [<tree-ish>] [--] <pathspec>...::
-----------
The changeset (or "diff") of each commit between the fork-point and <head>
is compared against each commit between the fork-point and <upstream>.
-The commits are compared with their 'patch id', obtained from
-the 'git patch-id' program.
+The diffs are compared after removing any whitespace and line numbers.
Every commit that doesn't exist in the <upstream> branch
has its id (sha1) reported, prefixed by a symbol. The ones that have
'git config' [<file-option>] [type] [-z|--null] --get name [value_regex]
'git config' [<file-option>] [type] [-z|--null] --get-all name [value_regex]
'git config' [<file-option>] [type] [-z|--null] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [type] [-z|--null] --get-urlmatch name URL
'git config' [<file-option>] --unset name [value_regex]
'git config' [<file-option>] --unset-all name [value_regex]
'git config' [<file-option>] --rename-section old_name new_name
in which section and variable names are lowercased, but subsection
names are not.
+--get-urlmatch name URL::
+ When given a two-part name section.key, the value for
+ section.<url>.key whose <url> part matches the best to the
+ given URL is returned (if no such key exists, the value for
+ section.key is used as a fallback). When given just the
+ section as name, do so for all the keys in the section and
+ list them.
+
--global::
For writing options: write to global `~/.gitconfig` file
rather than the repository `.git/config`, write to
gitproxy=proxy-command for kernel.org
gitproxy=default-proxy ; for all the rest
+ ; HTTP
+ [http]
+ sslVerify
+ [http "https://weak.example.com"]
+ sslVerify = false
+ cookieFile = /tmp/cookie.txt
+
you can set the filemode to true with
------------
echo "${WS}your whitespace color or blue reverse${RESET}"
------------
+For URLs in `https://weak.example.com`, `http.sslVerify` is set to
+false, while it is set to `true` for all others:
+
+------------
+% git config --bool --get-urlmatch http.sslverify https://good.example.com
+true
+% git config --bool --get-urlmatch http.sslverify https://weak.example.com
+false
+% git config --get-urlmatch http https://weak.example.com
+http.cookiefile /tmp/cookie.txt
+http.sslverify false
+------------
+
include::config.txt[]
GIT
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
+link:technical/api-credentials.html[the Git credential API] for more
background on the concepts.
git-credential takes an "action" option on the command-line (one of
SYNOPSIS
--------
[verse]
-'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] <committish>...
+'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] <commit-ish>...
'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]
DESCRIPTION
OPTIONS
-------
-<committish>...::
- Committish object names to describe.
+<commit-ish>...::
+ Commit-ish object names to describe.
--dirty[=<mark>]::
Describe the working tree.
--candidates=<n>::
Instead of considering only the 10 most recent tags as
- candidates to describe the input committish consider
+ candidates to describe the input commit-ish consider
up to <n> candidates. Increasing <n> above 10 will take
slightly longer but may produce a more accurate result.
An <n> of 0 will cause only exact matches to be output.
SEARCH STRATEGY
---------------
-For each committish supplied, 'git describe' will first look for
+For each commit-ish supplied, 'git describe' will first look for
a tag which tags exactly that commit. Annotated tags will always
be preferred over lightweight tags, and tags with newer dates will
always be preferred over tags with older dates. If an exact match
If an exact match was not found, 'git describe' will walk back
through the commit history to locate an ancestor commit which
has been tagged. The ancestor's tag will be output along with an
-abbreviation of the input committish's SHA-1. If '--first-parent' was
+abbreviation of the input commit-ish's SHA-1. If '--first-parent' was
specified then the walk will only consider the first parent of each
commit.
If multiple tags were found during the walk then the tag which
-has the fewest commits different from the input committish will be
+has the fewest commits different from the input commit-ish will be
selected and output. Here fewest commits different is defined as
the number of commits which would be shown by `git log tag..input`
will be the smallest number of commits possible.
words, the differences are what you _could_ tell Git to
further add to the index but you still haven't. You can
stage these changes by using linkgit:git-add[1].
-+
-If exactly two paths are given and at least one points outside
-the current repository, 'git diff' will compare the two files /
-directories. This behavior can be forced by --no-index.
+
+'git diff' --no-index [--options] [--] [<path>...]::
+
+ This form is to compare the given two paths on the
+ filesystem. You can omit the `--no-index` option when
+ running the command in a working tree controlled by Git and
+ at least one of the paths points outside the working tree,
+ or when running the command outside a working tree
+ controlled by Git.
'git diff' [--options] --cached [<commit>] [--] [<path>...]::
`--cat-blob-fd` or `stdout` if unspecified.
`feature`::
- Require that fast-import supports the specified feature, or
- abort if it does not.
+ Enable the specified feature. This requires that fast-import
+ supports the specified feature, and aborts if it does not.
`option`::
Specify any of the options listed under OPTIONS that do not
('author' (SP <name>)? SP LT <email> GT SP <when> LF)?
'committer' (SP <name>)? SP LT <email> GT SP <when> LF
data
- ('from' SP <committish> LF)?
- ('merge' SP <committish> LF)?
+ ('from' SP <commit-ish> LF)?
+ ('merge' SP <commit-ish> LF)?
(filemodify | filedelete | filecopy | filerename | filedeleteall | notemodify)*
LF?
....
be the first ancestor of the new commit.
As `LF` is not valid in a Git refname or SHA-1 expression, no
-quoting or escaping syntax is supported within `<committish>`.
+quoting or escaping syntax is supported within `<commit-ish>`.
-Here `<committish>` is any of the following:
+Here `<commit-ish>` is any of the following:
* The name of an existing branch already in fast-import's internal branch
table. If fast-import doesn't know the name, it's treated as a SHA-1
it is suggested that frontends do not use more than 15 `merge`
commands per commit; 16, if starting a new, empty branch.
-Here `<committish>` is any of the commit specification expressions
+Here `<commit-ish>` is any of the commit specification expressions
also accepted by `from` (see above).
`filemodify`
`notemodify`
^^^^^^^^^^^^
Included in a `commit` `<notes_ref>` command to add a new note
-annotating a `<committish>` or change this annotation contents.
-Internally it is similar to filemodify 100644 on `<committish>`
+annotating a `<commit-ish>` or change this annotation contents.
+Internally it is similar to filemodify 100644 on `<commit-ish>`
path (maybe split into subdirectories). It's not advised to
use any other commands to write to the `<notes_ref>` tree except
`filedeleteall` to delete all existing notes in this tree.
commit that is to be annotated.
+
....
- 'N' SP <dataref> SP <committish> LF
+ 'N' SP <dataref> SP <commit-ish> LF
....
+
Here `<dataref>` can be either a mark reference (`:<idnum>`)
command.
+
....
- 'N' SP 'inline' SP <committish> LF
+ 'N' SP 'inline' SP <commit-ish> LF
data
....
+
See below for a detailed description of the `data` command.
-In both formats `<committish>` is any of the commit specification
+In both formats `<commit-ish>` is any of the commit specification
expressions also accepted by `from` (see above).
`mark`
....
'tag' SP <name> LF
- 'from' SP <committish> LF
+ 'from' SP <commit-ish> LF
'tagger' (SP <name>)? SP LT <email> GT SP <when> LF
data
....
....
'reset' SP <ref> LF
- ('from' SP <committish> LF)?
+ ('from' SP <commit-ish> LF)?
LF?
....
-For a detailed description of `<ref>` and `<committish>` see above
+For a detailed description of `<ref>` and `<commit-ish>` see above
under `commit` and `from`.
The `LF` after the command is optional (it used to be required).
--no-progress::
Do not show the progress.
+--check-self-contained-and-connected::
+ Output "connectivity-ok" if the received pack is
+ self-contained and connected.
+
-v::
Run verbosely.
Note that the leading character does not have to be a dot; for example,
you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`.
+-q::
--quiet::
Do not print the names of the generated files to standard output.
In Thunderbird 3:
Edit..Preferences..Advanced..Config Editor. Search for
"mail.wrap_long_lines".
-Toggle it to make sure it is set to `false`.
+Toggle it to make sure it is set to `false`. Also, search for
+"mailnews.wraplength" and set the value to 0.
3. Disable the use of format=flowed:
Edit..Preferences..Advanced..Config Editor. Search for
SYNOPSIS
--------
[verse]
-'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune]
+'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune] [--force]
DESCRIPTION
-----------
--quiet::
Suppress all progress reports.
+--force::
+ Force `git gc` to run even if there may be another `git gc`
+ instance running on this repository.
+
Configuration
-------------
SYNOPSIS
--------
[verse]
-'git grep' [-a | --text] [-I] [-i | --ignore-case] [-w | --word-regexp]
+'git grep' [-a | --text] [-I] [--textconv] [-i | --ignore-case] [-w | --word-regexp]
[-v | --invert-match] [-h|-H] [--full-name]
[-E | --extended-regexp] [-G | --basic-regexp]
[-P | --perl-regexp]
--text::
Process binary files as if they were text.
+--textconv::
+ Honor textconv filter settings.
+
+--no-textconv::
+ Do not honor textconv filter settings.
+ This is the default.
+
-i::
--ignore-case::
Ignore case differences between the patterns and the
Note that only message is considered, if also a diff is shown
its size is not included.
--L <start>,<end>:<file>, -L :<regex>:<file>::
+-L <start>,<end>:<file>::
+-L :<regex>:<file>::
Trace the evolution of the line range given by "<start>,<end>"
(or the funcname regex <regex>) within the <file>. You may
give zero or one positive revision arguments.
You can specify this option more than once.
+
-<start> and <end> can take one of these forms:
-
include::line-range-format.txt[]
<revision range>::
[verse]
'git merge-file' [-L <current-name> [-L <base-name> [-L <other-name>]]]
[--ours|--theirs|--union] [-p|--stdout] [-q|--quiet] [--marker-size=<n>]
- <current-file> <base-file> <other-file>
+ [--[no-]diff3] <current-file> <base-file> <other-file>
DESCRIPTION
-q::
Quiet; do not warn about conflicts.
+--diff3::
+ Show conflicts in "diff3" style.
+
--ours::
--theirs::
--union::
DESCRIPTION
-----------
-Reads three treeish, and output trivial merge results and
+Reads three tree-ish, and output trivial merge results and
conflicting stages to the standard output. This is similar to
what three-way 'git read-tree -m' does, but instead of storing the
results in the index, the command outputs the entries to the
--------
[verse]
'git merge' [-n] [--stat] [--no-commit] [--squash] [--[no-]edit]
- [-s <strategy>] [-X <strategy-option>]
+ [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]]
[--[no-]rerere-autoupdate] [-m <msg>] [<commit>...]
'git merge' <msg> HEAD <commit>...
'git merge' --abort
-------
include::merge-options.txt[]
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+ GPG-sign the resulting merge commit.
+
-m <msg>::
Set the commit message to be used for the merge commit (in
case one is created).
to `git merge`, or pass `--ff-only` when you do not have any work on
your own. e.g.
----
+----
git fetch origin
git merge v1.2.3^0
git merge --ff-only v1.2.3
----
+----
HOW CONFLICTS ARE PRESENTED
DESCRIPTION
-----------
-This script is used to move or rename a file, directory or symlink.
+Move or rename a file, directory or symlink.
git mv [-v] [-f] [-n] [-k] <source> <destination>
git mv [-v] [-f] [-n] [-k] <source> ... <destination directory>
--verbose::
Report the names of files as they are moved.
+SUBMODULES
+----------
+Moving a submodule using a gitfile (which means they were cloned
+with a Git version 1.7.8 or newer) will update the gitfile and
+core.worktree setting to make the submodule work in the new location.
+It also will attempt to update the submodule.<name>.path setting in
+the linkgit:gitmodules[5] file and stage that file (unless -n is used).
+
GIT
---
Part of the linkgit:git[1] suite
--------
[verse]
'git name-rev' [--tags] [--refs=<pattern>]
- ( --all | --stdin | <committish>... )
+ ( --all | --stdin | <commit-ish>... )
DESCRIPTION
-----------
DESCRIPTION
-----------
-This program searches the `$GIT_OBJECT_DIR` for all objects that currently
+This program searches the `$GIT_OBJECT_DIRECTORY` for all objects that currently
exist in a pack file as well as the independent object directories.
All such extra objects are removed.
:git-pull: 1
-r::
---rebase::
- Rebase the current branch on top of the upstream branch after
- fetching. If there is a remote-tracking branch corresponding to
- the upstream branch and the upstream branch was rebased since last
- fetched, the rebase uses that information to avoid rebasing
- non-local changes.
+--rebase[=false|true|preserve]::
+ When true, rebase the current branch on top of the upstream
+ branch after fetching. If there is a remote-tracking branch
+ corresponding to the upstream branch and the upstream branch
+ was rebased since last fetched, the rebase uses that information
+ to avoid rebasing non-local changes.
++
+When preserve, also rebase the current branch on top of the upstream
+branch, but pass `--preserve-merges` along to `git rebase` so that
+locally created merge commits will not be flattened.
++
+When false, merge the current branch into the upstream branch.
+
See `pull.rebase`, `branch.<name>.rebase` and `branch.autosetuprebase` in
linkgit:git-config[1] if you want to make `git pull` always use
[verse]
'git push' [--all | --mirror | --tags] [--follow-tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
[--repo=<repository>] [-f | --force] [--prune] [-v | --verbose] [-u | --set-upstream]
+ [--force-with-lease[=<refname>[:<expect>]]]
[--no-verify] [<repository> [<refspec>...]]
DESCRIPTION
--follow-tags::
Push all the refs that would be pushed without this option,
and also push annotated tags in `refs/tags` that are missing
- from the remote but are pointing at committish that are
+ from the remote but are pointing at commit-ish that are
reachable from the refs being pushed.
--receive-pack=<git-receive-pack>::
repository over ssh, and you do not have the program in
a directory on the default $PATH.
+--[no-]force-with-lease::
+--force-with-lease=<refname>::
+--force-with-lease=<refname>:<expect>::
+ Usually, "git push" refuses to update a remote ref that is
+ not an ancestor of the local ref used to overwrite it.
++
+This option bypasses the check, but instead requires that the
+current value of the ref to be the expected value. "git push"
+fails otherwise.
++
+Imagine that you have to rebase what you have already published.
+You will have to bypass the "must fast-forward" rule in order to
+replace the history you originally published with the rebased history.
+If somebody else built on top of your original history while you are
+rebasing, the tip of the branch at the remote may advance with her
+commit, and blindly pushing with `--force` will lose her work.
++
+This option allows you to say that you expect the history you are
+updating is what you rebased and want to replace. If the remote ref
+still points at the commit you specified, you can be sure that no
+other people did anything to the ref (it is like taking a "lease" on
+the ref without explicitly locking it, and you update the ref while
+making sure that your earlier "lease" is still valid).
++
+`--force-with-lease` alone, without specifying the details, will protect
+all remote refs that are going to be updated by requiring their
+current value to be the same as the remote-tracking branch we have
+for them, unless specified with a `--force-with-lease=<refname>:<expect>`
+option that explicitly states what the expected value is.
++
+`--force-with-lease=<refname>`, without specifying the expected value, will
+protect the named ref (alone), if it is going to be updated, by
+requiring its current value to be the same as the remote-tracking
+branch we have for it.
++
+`--force-with-lease=<refname>:<expect>` will protect the named ref (alone),
+if it is going to be updated, by requiring its current value to be
+the same as the specified value <expect> (which is allowed to be
+different from the remote-tracking branch we have for the refname,
+or we do not even have to have such a remote-tracking branch when
+this form is used).
++
+Note that all forms other than `--force-with-lease=<refname>:<expect>`
+that specifies the expected current value of the ref explicitly are
+still experimental and their semantics may change as we gain experience
+with this feature.
++
+"--no-force-with-lease" will cancel all the previous --force-with-lease on the
+command line.
+
-f::
--force::
Usually, the command refuses to update a remote ref that is
not an ancestor of the local ref used to overwrite it.
- This flag disables the check. This can cause the
- remote repository to lose commits; use it with care.
- Note that `--force` applies to all the refs that are pushed,
- hence using it with `push.default` set to `matching` or with
- multiple push destinations configured with `remote.*.push`
- may overwrite refs other than the current branch (including
- local refs that are strictly behind their remote counterpart).
- To force a push to only one branch, use a `+` in front of the
- refspec to push (e.g `git push origin +master` to force a push
- to the `master` branch). See the `<refspec>...` section above
- for details.
+ Also, when `--force-with-lease` option is used, the command refuses
+ to update a remote ref whose current value does not match
+ what is expected.
++
+This flag disables these checks, and can cause the remote repository
+to lose commits; use it with care.
++
+Note that `--force` applies to all the refs that are pushed, hence
+using it with `push.default` set to `matching` or with multiple push
+destinations configured with `remote.*.push` may overwrite refs
+other than the current branch (including local refs that are
+strictly behind their remote counterpart). To force a push to only
+one branch, use a `+` in front of the refspec to push (e.g `git push
+origin +master` to force a push to the `master` branch). See the
+`<refspec>...` section above for details.
--repo=<repository>::
This option is only relevant if no <repository> argument is
reverting a topic branch merge, as this option recreates the topic branch with
fresh commits so it can be remerged successfully without needing to "revert
the reversion" (see the
-link:howto/revert-a-faulty-merge.txt[revert-a-faulty-merge How-To] for details).
+link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).
--ignore-whitespace::
--whitespace=<option>::
You may find this helpful after reverting a topic branch merge, as this option
recreates the topic branch with fresh commits so it can be remerged
successfully without needing to "revert the reversion" (see the
-link:howto/revert-a-faulty-merge.txt[revert-a-faulty-merge How-To] for details).
+link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).
include::merge-strategies.txt[]
'git remote add' [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=<fetch|push>] <name> <url>
'git remote rename' <old> <new>
'git remote remove' <name>
-'git remote set-head' <name> (-a | -d | <branch>)
+'git remote set-head' <name> (-a | --auto | -d | --delete | <branch>)
'git remote set-branches' [--add] <name> <branch>...
'git remote set-url' [--push] <name> <newurl> [<oldurl>]
'git remote set-url --add' [--push] <name> <newurl>
`master`, then `origin` may be specified wherever you would normally
specify `origin/master`.
+
-With `-d`, the symbolic ref `refs/remotes/<name>/HEAD` is deleted.
+With `-d` or `--delete`, the symbolic ref `refs/remotes/<name>/HEAD` is deleted.
+
-With `-a`, the remote is queried to determine its `HEAD`, then the
+With `-a` or `--auto`, the remote is queried to determine its `HEAD`, then the
symbolic-ref `refs/remotes/<name>/HEAD` is set to the same branch. e.g., if the remote
`HEAD` is pointed at `next`, "`git remote set-head origin -a`" will set
the symbolic-ref `refs/remotes/origin/HEAD` to `refs/remotes/origin/next`. This will
DESCRIPTION
-----------
-This script is used to combine all objects that do not currently
+This command is used to combine all objects that do not currently
reside in a "pack", into a pack. It can also be used to re-organize
existing packs into a single, more efficient pack.
replaced. The content of the 'replace' reference is the SHA-1 of the
replacement object.
+The replaced object and the replacement object must be of the same type.
+This restriction can be bypassed using `-f`.
+
Unless `-f` is given, the 'replace' reference must not yet exist.
+There is no other restriction on the replaced and replacement objects.
+Merge commits can be replaced by non-merge commits and vice versa.
+
Replacement references will be used by default by all Git commands
except those doing reachability traversal (prune, pack transfer and
fsck).
OPTIONS
-------
-f::
+--force::
If an existing replace ref for the same object exists, it will
be overwritten (instead of failing).
-d::
+--delete::
Delete existing replace refs for the given objects.
-l <pattern>::
+--list <pattern>::
List replace refs for objects that match the given pattern (or
all if no pattern is given).
Typing "git replace" without arguments, also lists all replace
refs.
+CREATING REPLACEMENT OBJECTS
+----------------------------
+
+linkgit:git-filter-branch[1], linkgit:git-hash-object[1] and
+linkgit:git-rebase[1], among other git commands, can be used to create
+replacement objects from existing objects.
+
+If you want to replace many blobs, trees or commits that are part of a
+string of commits, you may just want to create a replacement string of
+commits and then only replace the commit at the tip of the target
+string of commits with the commit at the tip of the replacement string
+of commits.
+
BUGS
----
Comparing blobs or trees that have been replaced with those that
commit instead of the replaced commit.
There may be other problems when using 'git rev-list' related to
-pending objects. And of course things may break if an object of one
-type is replaced by an object of another type (for example a blob
-replaced by a commit).
+pending objects.
SEE ALSO
--------
+linkgit:git-hash-object[1]
+linkgit:git-filter-branch[1]
+linkgit:git-rebase[1]
linkgit:git-tag[1]
linkgit:git-branch[1]
linkgit:git[1]
OPTIONS
-------
+
+Operation Modes
+~~~~~~~~~~~~~~~
+
+Each of these options must appear first on the command line.
+
--parseopt::
Use 'git rev-parse' in option parsing mode (see PARSEOPT section below).
+--sq-quote::
+ Use 'git rev-parse' in shell quoting mode (see SQ-QUOTE
+ section below). In contrast to the `--sq` option below, this
+ mode does only quoting. Nothing else is done to command input.
+
+Options for --parseopt
+~~~~~~~~~~~~~~~~~~~~~~
+
--keep-dashdash::
Only meaningful in `--parseopt` mode. Tells the option parser to echo
out the first `--` met instead of skipping it.
the first non-option argument. This can be used to parse sub-commands
that take options themselves.
---sq-quote::
- Use 'git rev-parse' in shell quoting mode (see SQ-QUOTE
- section below). In contrast to the `--sq` option below, this
- mode does only quoting. Nothing else is done to command input.
+Options for Filtering
+~~~~~~~~~~~~~~~~~~~~~
--revs-only::
Do not output flags and parameters not meant for
--no-flags::
Do not output flag parameters.
+Options for Output
+~~~~~~~~~~~~~~~~~~
+
--default <arg>::
If there is no parameter given by the user, use `<arg>`
instead.
strip '{caret}' prefix from the object names that already have
one.
+--abbrev-ref[=(strict|loose)]::
+ A non-ambiguous short name of the objects name.
+ The option core.warnAmbiguousRefs is used to select the strict
+ abbreviation mode.
+
+--short::
+--short=number::
+ Instead of outputting the full SHA-1 values of object names try to
+ abbreviate them to a shorter unique name. When no length is specified
+ 7 is used. The minimum length is 4.
+
--symbolic::
Usually the object names are output in SHA-1 form (with
possible '{caret}' prefix); this option makes them output in a
unfortunately named tag "master"), and show them as full
refnames (e.g. "refs/heads/master").
---abbrev-ref[=(strict|loose)]::
- A non-ambiguous short name of the objects name.
- The option core.warnAmbiguousRefs is used to select the strict
- abbreviation mode.
-
---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.
+Options for Objects
+~~~~~~~~~~~~~~~~~~~
--all::
Show all refs found in `refs/`.
character (`?`, `*`, or `[`), it is turned into a prefix
match by appending `/*`.
---show-toplevel::
- Show the absolute path of the top-level directory.
+--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.
---show-prefix::
- When the command is invoked from a subdirectory, show the
- path of the current directory relative to the top-level
- directory.
+Options for Files
+~~~~~~~~~~~~~~~~~
---show-cdup::
- When the command is invoked from a subdirectory, show the
- path of the top-level directory relative to the current
- directory (typically a sequence of "../", or an empty string).
+--local-env-vars::
+ List the GIT_* environment variables that are local to the
+ repository (e.g. GIT_DIR or GIT_WORK_TREE, but not GIT_EDITOR).
+ Only the names of the variables are listed, not their value,
+ even if they are set.
--git-dir::
Show `$GIT_DIR` if defined. Otherwise show the path to
--is-bare-repository::
When the repository is bare print "true", otherwise "false".
---local-env-vars::
- List the GIT_* environment variables that are local to the
- repository (e.g. GIT_DIR or GIT_WORK_TREE, but not GIT_EDITOR).
- Only the names of the variables are listed, not their value,
- even if they are set.
+--resolve-git-dir <path>::
+ Check if <path> is a valid repository or a gitfile that
+ points at a valid repository, and print the location of the
+ repository. If <path> is a gitfile then the resolved path
+ to the real repository is printed.
---short::
---short=number::
- Instead of outputting the full SHA-1 values of object names try to
- abbreviate them to a shorter unique name. When no length is specified
- 7 is used. The minimum length is 4.
+--show-cdup::
+ When the command is invoked from a subdirectory, show the
+ path of the top-level directory relative to the current
+ directory (typically a sequence of "../", or an empty string).
+
+--show-prefix::
+ When the command is invoked from a subdirectory, show the
+ path of the current directory relative to the top-level
+ directory.
+
+--show-toplevel::
+ Show the absolute path of the top-level directory.
+
+Other Options
+~~~~~~~~~~~~~
--since=datestring::
--after=datestring::
<args>...::
Flags and parameters to be parsed.
---resolve-git-dir <path>::
- Check if <path> is a valid repository or a gitfile that
- points at a valid repository, and print the location of the
- repository. If <path> is a gitfile then the resolved path
- to the real repository is printed.
-
include::revisions.txt[]
changes introduced by commits that are not ancestors of the previously
reverted merge. This may or may not be what you want.
+
-See the link:howto/revert-a-faulty-merge.txt[revert-a-faulty-merge How-To] for
+See the link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for
more details.
--no-edit::
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached
----------------
-Submodules
-~~~~~~~~~~
+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.
+or not - to protect the submodule's history. If it exists the
+submodule.<name> section in the linkgit:gitmodules[5] file will also
+be removed and that file will be staged (unless --cached or -n are used).
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
die with the usage message.
set_reflog_action::
- set the message that will be recorded to describe the
- end-user action in the reflog, when the script updates a
- ref.
+ Set GIT_REFLOG_ACTION environment to a given string (typically
+ the name of the program) unless it is already set. Whenever
+ the script runs a `git` command that updates refs, a reflog
+ entry is created using the value of this string to leave the
+ record of what command updated the ref.
git_editor::
runs an editor of user's choice (GIT_EDITOR, core.editor, VISUAL or
If `status.submodulesummary` is set to a non zero number or true (identical
to -1 or an unlimited number), the submodule summary will be enabled for
the long format and a summary of commits for modified submodules will be
-shown (see --summary-limit option of linkgit:git-submodule[1]).
+shown (see --summary-limit option of linkgit:git-submodule[1]). Please note
+that the summary output from the status command will be suppressed for all
+submodules when `diff.ignoreSubmodules` is set to 'all' or only for those
+submodules where `submodule.<name>.ignore=all`. To also view the summary for
+ignored submodules you can either use the --ignore-submodules=dirty command
+line option or the 'git submodule summary' command, which shows a similar
+output but does not honor these settings.
SEE ALSO
--------
trailing slash, so be sure you include one in the
argument if that is what you want. If --branches/-b is
specified, the prefix must include a trailing slash.
- Setting a prefix is useful if you wish to track multiple
- projects that share a common repository.
+ Setting a prefix (with a trailing slash) is strongly
+ encouraged in any case, as your SVN-tracking refs will
+ then be located at "refs/remotes/$prefix/*", which is
+ compatible with Git's own remote-tracking ref layout
+ (refs/remotes/$remote/*). Setting a prefix is also useful
+ if you wish to track multiple projects that share a common
+ repository.
++
+NOTE: In Git v2.0, the default prefix will CHANGE from "" (no prefix)
+to "origin/". This is done to put SVN-tracking refs at
+"refs/remotes/origin/*" instead of "refs/remotes/*", and make them
+more compatible with how Git's own remote-tracking refs are organized
+(i.e. refs/remotes/$remote/*). You can enjoy the same benefits today,
+by using the --prefix option.
+
--ignore-paths=<regex>;;
When passed to 'init' or 'clone' this regular expression will
be preserved as a config key. See 'fetch' for a description
'fetch'::
Fetch unfetched revisions from the Subversion remote we are
tracking. The name of the [svn-remote "..."] section in the
- .git/config file may be specified as an optional command-line
- argument.
+ $GIT_DIR/config file may be specified as an optional
+ command-line argument.
++
+This automatically updates the rev_map if needed (see
+'$GIT_DIR/svn/\*\*/.rev_map.*' in the FILES section below for details).
--localtime;;
Store Git commit times in the local timezone instead of UTC. This
precedence over '--include-paths'.
--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.
+ 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
+
Like 'git rebase'; this requires that the working tree be clean
and have no uncommitted changes.
++
+This automatically updates the rev_map if needed (see
+'$GIT_DIR/svn/\*\*/.rev_map.*' in the FILES section below for details).
-l;;
--local;;
For each patch, one may answer "yes" (accept this patch), "no" (discard this
patch), "all" (accept all patches), or "quit".
+
- 'git svn dcommit' returns immediately if answer is "no" or "quit", without
+ 'git svn dcommit' returns immediately if answer is "no" or "quit", without
committing anything to SVN.
'branch'::
Any other arguments are passed directly to 'git log'
'blame'::
- Show what revision and author last modified each line of a file. The
- output of this mode is format-compatible with the output of
- `svn blame' by default. Like the SVN blame command,
- local uncommitted changes in the working tree are ignored;
- the version of the file in the HEAD revision is annotated. Unknown
- arguments are passed directly to 'git blame'.
+ Show what revision and author last modified each line of a file. The
+ output of this mode is format-compatible with the output of
+ `svn blame' by default. Like the SVN blame command,
+ local uncommitted changes in the working tree are ignored;
+ the version of the file in the HEAD revision is annotated. Unknown
+ arguments are passed directly to 'git blame'.
+
--git-format;;
Produce output in the same format as 'git blame', but with
specific revision.
'gc'::
- Compress $GIT_DIR/svn/<refname>/unhandled.log files in .git/svn
- and remove $GIT_DIR/svn/<refname>index files in .git/svn.
+ Compress $GIT_DIR/svn/<refname>/unhandled.log files and remove
+ $GIT_DIR/svn/<refname>/index files.
'reset'::
Undoes the effects of 'fetch' back to the specified revision.
file cannot be ignored forever (with --ignore-paths) the only
way to repair the repo is to use 'reset'.
+
-Only the rev_map and refs/remotes/git-svn are changed. Follow 'reset'
-with a 'fetch' and then 'git reset' or 'git rebase' to move local
-branches onto the new tree.
+Only the rev_map and refs/remotes/git-svn are changed (see
+'$GIT_DIR/svn/\*\*/.rev_map.*' in the FILES section below for details).
+Follow 'reset' with a 'fetch' and then 'git reset' or 'git rebase' to
+move local branches onto the new tree.
-r <n>;;
--revision=<n>;;
+
This option can only be used for one-shot imports as 'git svn'
will not be able to fetch again without metadata. Additionally,
-if you lose your .git/svn/**/.rev_map.* files, 'git svn' will not
+if you lose your '$GIT_DIR/svn/\*\*/.rev_map.*' files, 'git svn' will not
be able to rebuild them.
+
The 'git svn log' command will not work on repositories using
------------------------------------------------------------------------
# Clone a repo with standard SVN directory layout (like git clone):
- git svn clone http://svn.example.com/project --stdlayout
+ git svn clone http://svn.example.com/project --stdlayout --prefix svn/
# Or, if the repo uses a non-standard directory layout:
- git svn clone http://svn.example.com/project -T tr -b branch -t tag
+ git svn clone http://svn.example.com/project -T tr -b branch -t tag --prefix svn/
# View all branches and tags you have cloned:
git branch -r
# Create a new branch in SVN
- git svn branch waldo
+ git svn branch waldo
# Reset your master to trunk (or any other branch, replacing 'trunk'
# with the appropriate name):
- git reset --hard remotes/trunk
+ git reset --hard svn/trunk
# You may only dcommit to one branch/tag/trunk at a time. The usage
# of dcommit/rebase/show-ignore should be the same as above.
------------------------------------------------------------------------
------------------------------------------------------------------------
# Do the initial import on a server
- ssh server "cd /pub && git svn clone http://svn.example.com/project
+ ssh server "cd /pub && git svn clone http://svn.example.com/project [options...]"
# Clone locally - make sure the refs/remotes/ space matches the server
mkdir project
cd project
git config --remove-section remote.origin
# Create a local branch from one of the branches just fetched
git checkout -b master FETCH_HEAD
-# Initialize 'git svn' locally (be sure to use the same URL and -T/-b/-t options as were used on server)
- git svn init http://svn.example.com/project
+# Initialize 'git svn' locally (be sure to use the same URL and
+# --stdlayout/-T/-b/-t/--prefix options as were used on server)
+ git svn init http://svn.example.com/project [options...]
# Pull the latest changes from Subversion
git svn rebase
------------------------------------------------------------------------
branches and tags is required, the options '--trunk' / '--branches' /
'--tags' must be used.
+When using the options for describing the repository layout (--trunk,
+--tags, --branches, --stdlayout), please also specify the --prefix
+option (e.g. '--prefix=origin/') to cause your SVN-tracking refs to be
+placed at refs/remotes/origin/* rather than the default refs/remotes/*.
+The former is more compatible with the layout of Git's "regular"
+remote-tracking refs (refs/remotes/$remote/*), and may potentially
+prevent similarly named SVN branches and Git remotes from clobbering
+each other. In Git v2.0 the default prefix used (i.e. when no --prefix
+is given) will change from "" (no prefix) to "origin/".
+
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,
use 'init' to set up your Git repository then, before your first 'fetch', edit
-the .git/config file so that the branches and tags are associated with
-different name spaces. For example:
+the $GIT_DIR/config file so that the branches and tags are associated
+with different name spaces. For example:
branches = stable/*:refs/remotes/svn/stable/*
branches = debug/*:refs/remotes/svn/debug/*
-------------
'git svn' stores [svn-remote] configuration information in the
-repository .git/config file. It is similar the core Git
+repository $GIT_DIR/config file. It is similar the core Git
[remote] sections except 'fetch' keys do not accept glob
arguments; but they are instead handled by the 'branches'
and 'tags' keys. Since some SVN repositories are oddly
[svn-remote "huge-project"]
url = http://server.org/svn
fetch = trunk/src:refs/remotes/trunk
- branches = branches/{red,green}/src:refs/remotes/branches/*
- tags = tags/{1.0,2.0}/src:refs/remotes/tags/*
+ branches = branches/{red,green}/src:refs/remotes/project-a/branches/*
+ tags = tags/{1.0,2.0}/src:refs/remotes/project-a/tags/*
------------------------------------------------------------------------
Multiple fetch, branches, and tags keys are supported:
Note that git-svn keeps track of the highest revision in which a branch
or tag has appeared. If the subset of branches or tags is changed after
-fetching, then .git/svn/.metadata must be manually edited to remove (or
-reset) branches-maxRev and/or tags-maxRev as appropriate.
+fetching, then $GIT_DIR/svn/.metadata must be manually edited to remove
+(or reset) branches-maxRev and/or tags-maxRev as appropriate.
+
+FILES
+-----
+$GIT_DIR/svn/\*\*/.rev_map.*::
+ Mapping between Subversion revision numbers and Git commit
+ names. In a repository where the noMetadata option is not set,
+ this can be rebuilt from the git-svn-id: lines that are at the
+ end of every commit (see the 'svn.noMetadata' section above for
+ details).
++
+'git svn fetch' and 'git svn rebase' automatically update the rev_map
+if it is missing or not up to date. 'git svn reset' automatically
+rewinds it.
SEE ALSO
--------
SYNOPSIS
--------
[verse]
-'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] <ref> <newvalue> [<oldvalue>])
+'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
DESCRIPTION
-----------
With `-d` flag, it deletes the named <ref> after verifying it
still contains <oldvalue>.
+With `--stdin`, update-ref reads instructions from standard input and
+performs all modifications together. Specify commands of the form:
+
+ update SP <ref> SP <newvalue> [SP <oldvalue>] LF
+ create SP <ref> SP <newvalue> LF
+ delete SP <ref> [SP <oldvalue>] LF
+ verify SP <ref> [SP <oldvalue>] LF
+ option SP <opt> LF
+
+Quote fields containing whitespace as if they were strings in C source
+code. Alternatively, use `-z` to specify commands without quoting:
+
+ update SP <ref> NUL <newvalue> NUL [<oldvalue>] NUL
+ create SP <ref> NUL <newvalue> NUL
+ delete SP <ref> NUL [<oldvalue>] NUL
+ verify SP <ref> NUL [<oldvalue>] NUL
+ option SP <opt> NUL
+
+Lines of any other format or a repeated <ref> produce an error.
+Command meanings are:
+
+update::
+ Set <ref> to <newvalue> after verifying <oldvalue>, if given.
+ Specify a zero <newvalue> to ensure the ref does not exist
+ after the update and/or a zero <oldvalue> to make sure the
+ ref does not exist before the update.
+
+create::
+ Create <ref> with <newvalue> after verifying it does not
+ exist. The given <newvalue> may not be zero.
+
+delete::
+ Delete <ref> after verifying it exists with <oldvalue>, if
+ given. If given, <oldvalue> may not be zero.
+
+verify::
+ Verify <ref> against <oldvalue> but do not change it. If
+ <oldvalue> zero or missing, the ref must not exist.
+
+option::
+ Modify behavior of the next command naming a <ref>.
+ The only valid option is `no-deref` to avoid dereferencing
+ a symbolic ref.
+
+Use 40 "0" or the empty string to specify a zero value, except that
+with `-z` an empty <oldvalue> is considered missing.
+
+If all <ref>s can be locked with matching <oldvalue>s
+simultaneously, all modifications are performed. Otherwise, no
+modifications are performed. Note that while each individual
+<ref> is updated or deleted atomically, a concurrent reader may
+still see a subset of the modifications.
Logging Updates
---------------
DESCRIPTION
-----------
-Shows commit logs and diff output each commit introduces. The
-command internally invokes 'git rev-list' piped to
-'git diff-tree', and takes command line options for both of
-these commands.
-This manual page describes only the most frequently used options.
+Shows commit logs and diff output each commit introduces.
+New users are encouraged to use linkgit:git-log[1] instead. The
+`whatchanged` command is essentially the same as linkgit:git-log[1]
+but defaults to show the raw format diff output and to skip merges.
-OPTIONS
--------
--p::
- Show textual diffs, instead of the Git internal diff
- output format that is useful only to tell the changed
- paths and their nature of changes.
+The command is kept primarily for historical reasons; fingers of
+many people who learned Git long before `git log` was invented by
+reading Linux kernel mailing list are trained to type it.
--<n>::
- Limit output to <n> commits.
-
-<since>..<until>::
- Limit output to between the two named commits (bottom
- exclusive, top inclusive).
-
--r::
- Show Git internal diff output, but for the whole tree,
- not just the top level.
-
--m::
- By default, differences for merge commits are not shown.
- With this flag, show differences to that commit from all
- of its parents.
-+
-However, it is not very useful in general, although it
-*is* useful on a file-by-file basis.
-
-include::pretty-options.txt[]
-
-include::pretty-formats.txt[]
Examples
--------
SYNOPSIS
--------
[verse]
-'git' [--version] [--help] [-c <name>=<value>]
+'git' [--version] [--help] [-C <path>] [-c <name>=<value>]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v1.8.4/git.html[documentation for release 1.8.4]
+* link:v1.8.4.2/git.html[documentation for release 1.8.4.2]
* release notes for
+ link:RelNotes/1.8.4.2.txt[1.8.4.2],
+ link:RelNotes/1.8.4.1.txt[1.8.4.1],
link:RelNotes/1.8.4.txt[1.8.4].
* link:v1.8.3.4/git.html[documentation for release 1.8.3.4]
because `git --help ...` is converted internally into `git
help ...`.
+-C <path>::
+ Run as if git was started in '<path>' instead of the current working
+ directory. When multiple `-C` options are given, each subsequent
+ non-absolute `-C <path>` is interpreted relative to the preceding `-C
+ <path>`.
++
+This option affects options that expect path name like `--git-dir` and
+`--work-tree` in that their interpretations of the path names would be
+made relative to the working directory caused by the `-C` option. For
+example the following invocations are equivalent:
+
+ git --git-dir=a.git --work-tree=b -C c status
+ git --git-dir=c/a.git --work-tree=c/b status
+
-c <name>=<value>::
Pass a configuration parameter to the command. The value
given will override values from configuration files.
linkgit:git-replace[1] for more information.
--literal-pathspecs::
- Treat pathspecs literally, rather than as glob patterns. This is
- equivalent to setting the `GIT_LITERAL_PATHSPECS` environment
+ Treat pathspecs literally (i.e. no globbing, no pathspec magic).
+ This is equivalent to setting the `GIT_LITERAL_PATHSPECS` environment
variable to `1`.
+--glob-pathspecs::
+ Add "glob" magic to all pathspec. This is equivalent to setting
+ the `GIT_GLOB_PATHSPECS` environment variable to `1`. Disabling
+ globbing on individual pathspecs can be done using pathspec
+ magic ":(literal)"
+
+--noglob-pathspecs::
+ Add "literal" magic to all pathspec. This is equivalent to setting
+ the `GIT_NOGLOB_PATHSPECS` environment variable to `1`. Enabling
+ globbing on individual pathspecs can be done using pathspec
+ magic ":(glob)"
+
+--icase-pathspecs::
+ Add "icase" magic to all pathspec. This is equivalent to setting
+ the `GIT_ICASE_PATHSPECS` environment variable to `1`.
GIT COMMANDS
------------
'GIT_FLUSH'::
If this environment variable is set to "1", then commands such
as 'git blame' (in incremental mode), 'git rev-list', 'git log',
- 'git check-attr', 'git check-ignore', and 'git whatchanged' will
+ 'git check-attr' and 'git check-ignore' will
force a flush of the output stream after each record have been
flushed. If this
variable is set to "0", the output of these commands will be done
literal paths to Git (e.g., paths previously given to you by
`git ls-tree`, `--raw` diff output, etc).
+GIT_GLOB_PATHSPECS::
+ Setting this variable to `1` will cause Git to treat all
+ pathspecs as glob patterns (aka "glob" magic).
+
+GIT_NOGLOB_PATHSPECS::
+ Setting this variable to `1` will cause Git to treat all
+ pathspecs as literal (aka "literal" magic).
+
+GIT_ICASE_PATHSPECS::
+ Setting this variable to `1` will cause Git to treat all
+ pathspecs as case-insensitive.
+
+'GIT_REFLOG_ACTION'::
+ When a ref is updated, reflog entries are created to keep
+ track of the reason why the ref was updated (which is
+ typically the name of the high-level command that updated
+ the ref), in addition to the old and new values of the ref.
+ A scripted Porcelain command can use set_reflog_action
+ helper function in `git-sh-setup` to set its name to this
+ variable when it is invoked as the top level command by the
+ end user, to be recorded in the body of the reflog.
+
Discussion[[Discussion]]
------------------------
see `hello.c` in your working tree with the former, but with the latter
you will.
+ * Just as the filesystem '.' (period) refers to the current directory,
+ using a '.' as a repository name in Git (a dot-repository) is a relative
+ path and means your current repository.
+
Here are the rules regarding the "flags" that you should follow when you are
scripting Git:
+
---------------------------------------------
$ git describe -h
-usage: git describe [options] <committish>*
+usage: git describe [options] <commit-ish>*
or: git describe [options] --dirty
--contains find the tag that comes after the commit
In fact, together with the 'git rev-list' program (which generates a
list of revisions), 'git diff-tree' ends up being a veritable fount of
-changes. A trivial (but very useful) script called 'git whatchanged' is
-included with Git which does exactly this, and shows a log of recent
-activities.
-
-To see the whole history of our pitiful little git-tutorial project, you
-can do
-
-----------------
-$ git log
-----------------
-
-which shows just the log messages, or if we want to see the log together
-with the associated patches use the more complex (and much more
-powerful)
-
-----------------
-$ git whatchanged -p
-----------------
-
-and you will see exactly what has changed in the repository over its
-short history.
-
-[NOTE]
-When using the above two commands, the initial commit will be shown.
-If this is a problem because it is huge, you can hide it by setting
-the log.showroot configuration variable to false. Having this, you
-can still show it for each command just adding the `--root` option,
-which is a flag for 'git diff-tree' accepted by both commands.
-
-With that, you should now be having some inkling of what Git does, and
-can explore on your own.
-
-[NOTE]
-Most likely, you are not directly using the core
-Git Plumbing commands, but using Porcelain such as 'git add', `git-rm'
-and `git-commit'.
+changes. You can emulate `git log`, `git log -p`, etc. with a trivial
+script that pipes the output of `git rev-list` to `git diff-tree --stdin`,
+which was exactly how early versions of `git log` were implemented.
Tagging a version
repository to a mailing list. See linkgit:githooks[5].
You can enforce finer grained permissions using update hooks. See
-link:howto/update-hook-example.txt[Controlling access to branches using
+link:howto/update-hook-example.html[Controlling access to branches using
update hooks].
Providing CVS Access to a Git Repository
SYNOPSIS
--------
[verse]
-'gitk' [<option>...] [<revs>] [--] [<path>...]
+'gitk' [<options>] [<revision range>] [\--] [<path>...]
DESCRIPTION
-----------
visualizing the commit graph, showing information related to each commit, and
the files in the trees of each revision.
-Historically, gitk was the first repository browser. It's written in tcl/tk
-and started off in a separate repository but was later merged into the main
-Git repository.
-
OPTIONS
-------
-To control which revisions to show, the command takes options applicable to
-the 'git rev-list' command (see linkgit:git-rev-list[1]).
-This manual page describes only the most
-frequently used options.
--n <number>::
---max-count=<number>::
+To control which revisions to show, gitk supports most options
+applicable to the 'git rev-list' command. It also supports a few
+options applicable to the 'git diff-*' commands to control how the
+changes each commit introduces are shown. Finally, it supports some
+gitk-specific options.
+
+gitk generally only understands options with arguments in the
+'sticked' form (see linkgit:gitcli[7]) due to limitations in the
+command line parser.
+
+rev-list options and arguments
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This manual page describes only the most frequently used options. See
+linkgit:git-rev-list[1] for a complete list.
+
+--all::
+
+ Show all refs (branches, tags, etc.).
- Limits the number of commits to show.
+--branches[=<pattern>]::
+--tags[=<pattern>]::
+--remotes[=<pattern>]::
+
+ Pretend as if all the branches (tags, remote branches, resp.)
+ are listed on the command line as '<commit>'. If '<pattern>'
+ is given, limit refs to ones matching given shell glob. If
+ pattern lacks '?', '{asterisk}', or '[', '/{asterisk}' at the
+ end is implied.
--since=<date>::
Show commits older than a specific date.
---all::
+--date-order::
- Show all branches.
+ Sort commits by date when possible.
--merge::
that modify the conflicted files and do not exist on all the heads
being merged.
---argscmd=<command>::
- Command to be run each time gitk has to determine the list of
- <revs> to show. The command is expected to print on its standard
- output a list of additional revs to be shown, one per line.
- Use this instead of explicitly specifying <revs> if the set of
- commits to show may vary between refreshes.
+--left-right::
---select-commit=<ref>::
+ Mark which side of a symmetric diff a commit is reachable
+ from. Commits from the left side are prefixed with a `<`
+ symbol and those from the right with a `>` symbol.
- Automatically select the specified commit after loading the graph.
- Default behavior is equivalent to specifying '--select-commit=HEAD'.
+--full-history::
+
+ When filtering history with '<path>...', does not prune some
+ history. (See "History simplification" in linkgit:git-log[1]
+ for a more detailed explanation.)
+
+--simplify-merges::
-<revs>::
+ Additional option to '--full-history' to remove some needless
+ merges from the resulting history, as there are no selected
+ commits contributing to this merge. (See "History
+ simplification" in linkgit:git-log[1] for a more detailed
+ explanation.)
+
+--ancestry-path::
+
+ When given a range of commits to display
+ (e.g. 'commit1..commit2' or 'commit2 {caret}commit1'), only
+ display commits that exist directly on the ancestry chain
+ between the 'commit1' and 'commit2', i.e. commits that are
+ both descendants of 'commit1', and ancestors of 'commit2'.
+ (See "History simplification" in linkgit:git-log[1] for a more
+ detailed explanation.)
+
+<revision range>::
Limit the revisions to show. This can be either a single revision
meaning show from the given revision and back, or it can be a range in
avoid ambiguity with respect to revision names use "--" to separate the paths
from any preceding options.
+gitk-specific options
+~~~~~~~~~~~~~~~~~~~~~
+
+--argscmd=<command>::
+
+ Command to be run each time gitk has to determine the revision
+ range to show. The command is expected to print on its
+ standard output a list of additional revisions to be shown,
+ one per line. Use this instead of explicitly specifying a
+ '<revision range>' if the set of commits to show may vary
+ between refreshes.
+
+--select-commit=<ref>::
+
+ Select the specified commit after loading the graph.
+ Default behavior is equivalent to specifying '--select-commit=HEAD'.
+
Examples
--------
gitk v2.6.12.. include/scsi drivers/scsi::
Gitk creates the .gitk file in your $HOME directory to store preferences
such as display options, font, and colors.
+History
+-------
+Gitk was the first graphical repository browser. It's written in
+tcl/tk and started off in a separate repository but was later merged
+into the main Git repository.
+
+
SEE ALSO
--------
'qgit(1)'::
the superproject, the setting there will override the one found in
.gitmodules.
Both settings can be overridden on the command line by using the
- "--ignore-submodule" option.
+ "--ignore-submodule" option. The 'git submodule' commands are not
+ affected by this setting.
EXAMPLES
When choosing between 'push' and 'export', Git prefers 'push'.
Other frontends may have some other order of preference.
+'no-private-update'::
+ When using the 'refspec' capability, git normally updates the
+ private ref on successful push. This update is disabled when
+ the remote-helper declares the capability 'no-private-update'.
+
Capabilities for Fetching
^^^^^^^^^^^^^^^^^^^^^^^^^
+
Supported commands: 'list', 'import'.
+'check-connectivity'::
+ Can guarantee that when a clone is requested, the received
+ pack is self contained and is connected.
+
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).
advertised with this capability must cover all refs reported by
the list command. If no 'refspec' capability is advertised,
there is an implied `refspec *:*`.
++
+When writing remote-helpers for decentralized version control
+systems, it is advised to keep a local copy of the repository to
+interact with, and to let the private namespace refs point to this
+local repository, while the refs/remotes namespace is used to track
+the remote repository.
'bidi-import'::
This modifies the 'import' capability.
GIT_DIR/objects/pack which is keeping a pack until refs can be
suitably updated.
+
+If option 'check-connectivity' is requested, the helper must output
+'connectivity-ok' if the clone is self-contained and connected.
++
Supported if the helper has the "fetch" capability.
'push' +<src>:<dst>::
must not rely on this option being set before
connect request occurs.
+'option check-connectivity' \{'true'|'false'\}::
+ Request the helper to check connectivity of a clone.
+
SEE ALSO
--------
linkgit:git-remote[1]
to the top <<def_directory,directory>> of the stored
revision.
+[[def_commit-ish]]commit-ish (also committish)::
+ A <<def_commit_object,commit object>> or an
+ <<def_object,object>> that can be recursively dereferenced to
+ a commit object.
+ The following are all commit-ishes:
+ a commit object,
+ a <<def_tag_object,tag object>> that points to a commit
+ object,
+ a tag object that points to a tag object that points to a
+ commit object,
+ etc.
+
[[def_core_git]]core Git::
Fundamental data structures and utilities of Git. Exposes only limited
source code management tools.
against the path.
+
The "magic signature" consists of an ASCII symbol that is not
-alphanumeric. Currently only the slash `/` is recognized as a
-"magic signature": it makes the pattern match from the root of
-the working tree, even when you are running the command from
-inside a subdirectory.
+alphanumeric.
++
+--
+top `/`;;
+ The magic word `top` (mnemonic: `/`) makes the pattern match
+ from the root of the working tree, even when you are running
+ the command from inside a subdirectory.
+
+literal;;
+ Wildcards in the pattern such as `*` or `?` are treated
+ as literal characters.
+
+icase;;
+ Case insensitive match.
+
+glob;;
+ Git treats the pattern as a shell glob suitable for
+ consumption by fnmatch(3) with the FNM_PATHNAME flag:
+ wildcards in the pattern will not match a / in the pathname.
+ For example, "Documentation/{asterisk}.html" matches
+ "Documentation/git.html" but not "Documentation/ppc/ppc.html"
+ or "tools/perf/Documentation/perf.html".
++
+Two consecutive asterisks ("`**`") in patterns matched against
+full pathname may have special meaning:
+
+ - A leading "`**`" followed by a slash means match in all
+ directories. For example, "`**/foo`" matches file or directory
+ "`foo`" anywhere, the same as pattern "`foo`". "**/foo/bar"
+ matches file or directory "`bar`" anywhere that is directly
+ under directory "`foo`".
+
+ - A trailing "/**" matches everything inside. For example,
+ "abc/**" matches all files inside directory "abc", relative
+ to the location of the `.gitignore` file, with infinite depth.
+
+ - A slash followed by two consecutive asterisks then a slash
+ matches zero or more directories. For example, "`a/**/b`"
+ matches "`a/b`", "`a/x/b`", "`a/x/y/b`" and so on.
+
+ - Other consecutive asterisks are considered invalid.
++
+Glob magic is incompatible with literal magic.
+--
++
+Currently only the slash `/` is recognized as the "magic signature",
+but it is envisioned that we will support more types of magic in later
+versions of Git.
+
A pathspec with only a colon means "there is no pathspec". This form
should not be combined with other pathspec.
to the result.
[[def_ref]]ref::
- A 40-byte hex representation of a <<def_SHA1,SHA-1>> or a name that
- denotes a particular <<def_object,object>>. They may be stored in
- a file under `$GIT_DIR/refs/` directory, or
- in the `$GIT_DIR/packed-refs` file.
+ A name that begins with `refs/` (e.g. `refs/heads/master`)
+ that points to an <<def_object_name,object name>> or another
+ ref (the latter is called a <<def_symref,symbolic ref>>).
+ For convenience, a ref can sometimes be abbreviated when used
+ as an argument to a Git command; see linkgit:gitrevisions[7]
+ for details.
+ Refs are stored in the <<def_repository,repository>>.
++
+The ref namespace is hierarchical.
+Different subhierarchies are used for different purposes (e.g. the
+`refs/heads/` hierarchy is used to represent local branches).
++
+There are a few special-purpose refs that do not begin with `refs/`.
+The most notable example is `HEAD`.
[[def_reflog]]reflog::
A reflog shows the local "history" of a ref. In other words,
with refs to the associated blob and/or tree objects. A
<<def_tree,tree>> is equivalent to a <<def_directory,directory>>.
-[[def_tree-ish]]tree-ish::
- A <<def_ref,ref>> pointing to either a <<def_commit_object,commit
- object>>, a <<def_tree_object,tree object>>, or a <<def_tag_object,tag
- object>> pointing to a tag or commit or tree object.
+[[def_tree-ish]]tree-ish (also treeish)::
+ A <<def_tree_object,tree object>> or an <<def_object,object>>
+ that can be recursively dereferenced to a tree object.
+ Dereferencing a <<def_commit_object,commit object>> yields the
+ tree object corresponding to the <<def_revision,revision>>'s
+ top <<def_directory,directory>>.
+ The following are all tree-ishes:
+ a <<def_commit-ish,commit-ish>>,
+ a tree object,
+ a <<def_tag_object,tag object>> that points to a tree object,
+ a tag object that points to a tag object that points to a tree
+ object,
+ etc.
[[def_unmerged_index]]unmerged index::
An <<def_index,index>> which contains unmerged
merge that brings these premature changes into the mainline, x are changes
unrelated to what the side branch did and already made on the mainline,
and W is the "revert of the merge M" (doesn't W look M upside down?).
-IOW, "diff W^..W" is similar to "diff -R M^..M".
+IOW, `"diff W^..W"` is similar to `"diff -R M^..M"`.
Such a "revert" of a merge can be made with:
---A---B A'--B'--C'
where Y is the revert of W, A' and B' are rerolled A and B, and there may
-also be a further fix-up C' on the side branch. "diff Y^..Y" is similar
-to "diff -R W^..W" (which in turn means it is similar to "diff M^..M"),
-and "diff A'^..C'" by definition would be similar but different from that,
+also be a further fix-up C' on the side branch. `"diff Y^..Y"` is similar
+to `"diff -R W^..W"` (which in turn means it is similar to `"diff M^..M"`),
+and `"diff A'^..C'"` by definition would be similar but different from that,
because it is a rerolled series of the earlier change. There will be a
lot of overlapping changes that result in conflicts. So do not do "revert
of revert" blindly without thinking..
Packing 0 objects
Unpacking 0 objects
-* committish: e3a693c... refs/heads/master from .
+* commit-ish: e3a693c... refs/heads/master from .
Trying to merge e3a693c... into 8c1f5f0... using 10d781b...
Committed merge 7fb9b7262a1d1e0a47bbfdcbbcf50ce0635d3f8f
cache.h | 8 ++++----
$ git --bare init
-Change the ownership to your web-server's credentials. Use "grep ^User
-httpd.conf" and "grep ^Group httpd.conf" to find out:
+Change the ownership to your web-server's credentials. Use `"grep ^User
+httpd.conf"` and `"grep ^Group httpd.conf"` to find out:
$ chown -R www.www .
+<start> and <end> can take one of these forms:
+
- number
+
If <start> or <end> is a number, it specifies an
- /regex/
+
This form will use the first line matching the given
-POSIX regex. If <end> is a regex, it will search
+POSIX regex. If <start> is a regex, it will search from the end of
+the previous `-L` range, if any, otherwise from the start of file.
+If <start> is ``^/regex/'', it will search from the start of file.
+If <end> is a regex, it will search
starting at the line given by <start>.
+
+
This is only valid for <end> and will specify a number
of lines before or after the line given by <start>.
-+
-- :regex
+
-If the option's argument is of the form :regex, it denotes the range
+If ``:<regex>'' is given in place of <start> and <end>, it denotes the range
from the first funcname line that matches <regex>, up to the next
-funcname line.
-+
+funcname line. ``:<regex>'' searches from the end of the previous `-L` range,
+if any, otherwise from the start of file.
+``^:<regex>'' searches from the start of file.
While the ref name encoding is unspecified, UTF-8 is preferred as
some output processing may assume ref names in UTF-8.
+'@'::
+ '@' alone is a shortcut for 'HEAD'.
+
'<refname>@\{<date>\}', e.g. 'master@\{yesterday\}', 'HEAD@\{5 minutes ago\}'::
A ref followed by the suffix '@' with a date specification
enclosed in a brace
'<rev>{caret}\{<type>\}', e.g. 'v0.99.8{caret}\{commit\}'::
A suffix '{caret}' followed by an object type name enclosed in
- brace pair means the object
- could be a tag, and dereference the tag recursively until an
- object of that type is found or the object cannot be
- dereferenced anymore (in which case, barf). '<rev>{caret}0'
+ brace pair means dereference the object at '<rev>' recursively until
+ an object of type '<type>' is found or the object cannot be
+ dereferenced anymore (in which case, barf).
+ For example, if '<rev>' is a commit-ish, '<rev>{caret}\{commit\}'
+ describes the corresponding commit object.
+ Similarly, if '<rev>' is a tree-ish, '<rev>{caret}\{tree\}'
+ describes the corresponding tree object.
+ '<rev>{caret}0'
is a short-hand for '<rev>{caret}\{commit\}'.
+
'rev{caret}\{object\}' can be used to make sure 'rev' names an
object that exists, without requiring 'rev' to be a tag, and
without dereferencing 'rev'; because a tag is already an object,
it does not have to be dereferenced even once to get to an object.
++
+'rev{caret}\{tag\}' can be used to ensure that 'rev' identifies an
+existing tag object.
'<rev>{caret}\{\}', e.g. 'v0.99.8{caret}\{\}'::
A suffix '{caret}' followed by an empty brace pair
* Call `diff_setup_done()`; this inspects the options set up so far for
internal consistency and make necessary tweaking to it (e.g. if
- textual patch output was asked, recursive behaviour is turned on).
+ textual patch output was asked, recursive behaviour is turned on);
+ the callback set_default in diff_options can be used to tweak this more.
* As you find different pairs of files, call `diff_change()` to feed
modified files, `diff_addremove()` to feed created or deleted files,
operation, but some do not have anything to do with the diffcore
library.
+`touched_flags`::
+ Records whether a flag has been changed due to user request
+ (rather than just set/unset by default).
+
+`set_default`::
+ Callback which allows tweaking the options in diff_setup_done().
+
BINARY, TEXT;;
Affects the way how a file that is seemingly binary is treated.
* is_inside_git_dir()
* is_inside_work_tree()
* setup_work_tree()
-* get_pathspec()
(Dscho)
+
+Pathspec
+--------
+
+See glossary-context.txt for the syntax of pathspec. In memory, a
+pathspec set is represented by "struct pathspec" and is prepared by
+parse_pathspec(). This function takes several arguments:
+
+- magic_mask specifies what features that are NOT supported by the
+ following code. If a user attempts to use such a feature,
+ parse_pathspec() can reject it early.
+
+- flags specifies other things that the caller wants parse_pathspec to
+ perform.
+
+- prefix and args come from cmd_* functions
+
+get_pathspec() is obsolete and should never be used in new code.
+
+parse_pathspec() helps catch unsupported features and reject them
+politely. At a lower level, different pathspec-related functions may
+not support the same set of features. Such pathspec-sensitive
+functions are guarded with GUARD_PATHSPEC(), which will die in an
+unfriendly way when an unsupported feature is requested.
+
+The command designers are supposed to make sure that GUARD_PATHSPEC()
+never dies. They have to make sure all unsupported features are caught
+by parse_pathspec(), not by GUARD_PATHSPEC. grepping GUARD_PATHSPEC()
+should give the designers all pathspec-sensitive codepaths and what
+features they support.
+
+A similar process is applied when a new pathspec magic is added. The
+designer lifts the GUARD_PATHSPEC restriction in the functions that
+support the new magic. At the same time (s)he has to make sure this
+new feature will be caught at parse_pathspec() in commands that cannot
+handle the new magic in some cases. grepping parse_pathspec() should
+help.
--- /dev/null
+HTTP transfer protocols
+=======================
+
+Git supports two HTTP based transfer protocols. A "dumb" protocol
+which requires only a standard HTTP server on the server end of the
+connection, and a "smart" protocol which requires a Git aware CGI
+(or server module). This document describes both protocols.
+
+As a design feature smart clients can automatically upgrade "dumb"
+protocol URLs to smart URLs. This permits all users to have the
+same published URL, and the peers automatically select the most
+efficient transport available to them.
+
+
+URL Format
+----------
+
+URLs for Git repositories accessed by HTTP use the standard HTTP
+URL syntax documented by RFC 1738, so they are of the form:
+
+ http://<host>:<port>/<path>?<searchpart>
+
+Within this documentation the placeholder $GIT_URL will stand for
+the http:// repository URL entered by the end-user.
+
+Servers SHOULD handle all requests to locations matching $GIT_URL, as
+both the "smart" and "dumb" HTTP protocols used by Git operate
+by appending additional path components onto the end of the user
+supplied $GIT_URL string.
+
+An example of a dumb client requesting for a loose object:
+
+ $GIT_URL: http://example.com:8080/git/repo.git
+ URL request: http://example.com:8080/git/repo.git/objects/d0/49f6c27a2244e12041955e262a404c7faba355
+
+An example of a smart request to a catch-all gateway:
+
+ $GIT_URL: http://example.com/daemon.cgi?svc=git&q=
+ URL request: http://example.com/daemon.cgi?svc=git&q=/info/refs&service=git-receive-pack
+
+An example of a request to a submodule:
+
+ $GIT_URL: http://example.com/git/repo.git/path/submodule.git
+ URL request: http://example.com/git/repo.git/path/submodule.git/info/refs
+
+Clients MUST strip a trailing '/', if present, from the user supplied
+$GIT_URL string to prevent empty path tokens ('//') from appearing
+in any URL sent to a server. Compatible clients MUST expand
+'$GIT_URL/info/refs' as 'foo/info/refs' and not 'foo//info/refs'.
+
+
+Authentication
+--------------
+
+Standard HTTP authentication is used if authentication is required
+to access a repository, and MAY be configured and enforced by the
+HTTP server software.
+
+Because Git repositories are accessed by standard path components
+server administrators MAY use directory based permissions within
+their HTTP server to control repository access.
+
+Clients SHOULD support Basic authentication as described by RFC 2616.
+Servers SHOULD support Basic authentication by relying upon the
+HTTP server placed in front of the Git server software.
+
+Servers SHOULD NOT require HTTP cookies for the purposes of
+authentication or access control.
+
+Clients and servers MAY support other common forms of HTTP based
+authentication, such as Digest authentication.
+
+
+SSL
+---
+
+Clients and servers SHOULD support SSL, particularly to protect
+passwords when relying on Basic HTTP authentication.
+
+
+Session State
+-------------
+
+The Git over HTTP protocol (much like HTTP itself) is stateless
+from the perspective of the HTTP server side. All state MUST be
+retained and managed by the client process. This permits simple
+round-robin load-balancing on the server side, without needing to
+worry about state management.
+
+Clients MUST NOT require state management on the server side in
+order to function correctly.
+
+Servers MUST NOT require HTTP cookies in order to function correctly.
+Clients MAY store and forward HTTP cookies during request processing
+as described by RFC 2616 (HTTP/1.1). Servers SHOULD ignore any
+cookies sent by a client.
+
+
+General Request Processing
+--------------------------
+
+Except where noted, all standard HTTP behavior SHOULD be assumed
+by both client and server. This includes (but is not necessarily
+limited to):
+
+If there is no repository at $GIT_URL, or the resource pointed to by a
+location matching $GIT_URL does not exist, the server MUST NOT respond
+with '200 OK' response. A server SHOULD respond with
+'404 Not Found', '410 Gone', or any other suitable HTTP status code
+which does not imply the resource exists as requested.
+
+If there is a repository at $GIT_URL, but access is not currently
+permitted, the server MUST respond with the '403 Forbidden' HTTP
+status code.
+
+Servers SHOULD support both HTTP 1.0 and HTTP 1.1.
+Servers SHOULD support chunked encoding for both request and response
+bodies.
+
+Clients SHOULD support both HTTP 1.0 and HTTP 1.1.
+Clients SHOULD support chunked encoding for both request and response
+bodies.
+
+Servers MAY return ETag and/or Last-Modified headers.
+
+Clients MAY revalidate cached entities by including If-Modified-Since
+and/or If-None-Match request headers.
+
+Servers MAY return '304 Not Modified' if the relevant headers appear
+in the request and the entity has not changed. Clients MUST treat
+'304 Not Modified' identical to '200 OK' by reusing the cached entity.
+
+Clients MAY reuse a cached entity without revalidation if the
+Cache-Control and/or Expires header permits caching. Clients and
+servers MUST follow RFC 2616 for cache controls.
+
+
+Discovering References
+----------------------
+
+All HTTP clients MUST begin either a fetch or a push exchange by
+discovering the references available on the remote repository.
+
+Dumb Clients
+~~~~~~~~~~~~
+
+HTTP clients that only support the "dumb" protocol MUST discover
+references by making a request for the special info/refs file of
+the repository.
+
+Dumb HTTP clients MUST make a GET request to $GIT_URL/info/refs,
+without any search/query parameters.
+
+ C: GET $GIT_URL/info/refs HTTP/1.0
+
+ S: 200 OK
+ S:
+ S: 95dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint
+ S: d049f6c27a2244e12041955e262a404c7faba355 refs/heads/master
+ S: 2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0
+ S: a3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}
+
+The Content-Type of the returned info/refs entity SHOULD be
+"text/plain; charset=utf-8", but MAY be any content type.
+Clients MUST NOT attempt to validate the returned Content-Type.
+Dumb servers MUST NOT return a return type starting with
+"application/x-git-".
+
+Cache-Control headers MAY be returned to disable caching of the
+returned entity.
+
+When examining the response clients SHOULD only examine the HTTP
+status code. Valid responses are '200 OK', or '304 Not Modified'.
+
+The returned content is a UNIX formatted text file describing
+each ref and its known value. The file SHOULD be sorted by name
+according to the C locale ordering. The file SHOULD NOT include
+the default ref named 'HEAD'.
+
+ info_refs = *( ref_record )
+ ref_record = any_ref / peeled_ref
+
+ any_ref = obj-id HTAB refname LF
+ peeled_ref = obj-id HTAB refname LF
+ obj-id HTAB refname "^{}" LF
+
+Smart Clients
+~~~~~~~~~~~~~
+
+HTTP clients that support the "smart" protocol (or both the
+"smart" and "dumb" protocols) MUST discover references by making
+a parameterized request for the info/refs file of the repository.
+
+The request MUST contain exactly one query parameter,
+'service=$servicename', where $servicename MUST be the service
+name the client wishes to contact to complete the operation.
+The request MUST NOT contain additional query parameters.
+
+ C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0
+
+ dumb server reply:
+ S: 200 OK
+ S:
+ S: 95dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint
+ S: d049f6c27a2244e12041955e262a404c7faba355 refs/heads/master
+ S: 2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0
+ S: a3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}
+
+ smart server reply:
+ S: 200 OK
+ S: Content-Type: application/x-git-upload-pack-advertisement
+ S: Cache-Control: no-cache
+ S:
+ S: 001e# service=git-upload-pack\n
+ S: 004895dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint\0multi_ack\n
+ S: 0042d049f6c27a2244e12041955e262a404c7faba355 refs/heads/master\n
+ S: 003c2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0\n
+ S: 003fa3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}\n
+
+Dumb Server Response
+^^^^^^^^^^^^^^^^^^^^
+Dumb servers MUST respond with the dumb server reply format.
+
+See the prior section under dumb clients for a more detailed
+description of the dumb server response.
+
+Smart Server Response
+^^^^^^^^^^^^^^^^^^^^^
+If the server does not recognize the requested service name, or the
+requested service name has been disabled by the server administrator,
+the server MUST respond with the '403 Forbidden' HTTP status code.
+
+Otherwise, smart servers MUST respond with the smart server reply
+format for the requested service name.
+
+Cache-Control headers SHOULD be used to disable caching of the
+returned entity.
+
+The Content-Type MUST be 'application/x-$servicename-advertisement'.
+Clients SHOULD fall back to the dumb protocol if another content
+type is returned. When falling back to the dumb protocol clients
+SHOULD NOT make an additional request to $GIT_URL/info/refs, but
+instead SHOULD use the response already in hand. Clients MUST NOT
+continue if they do not support the dumb protocol.
+
+Clients MUST validate the status code is either '200 OK' or
+'304 Not Modified'.
+
+Clients MUST validate the first five bytes of the response entity
+matches the regex "^[0-9a-f]{4}#". If this test fails, clients
+MUST NOT continue.
+
+Clients MUST parse the entire response as a sequence of pkt-line
+records.
+
+Clients MUST verify the first pkt-line is "# service=$servicename".
+Servers MUST set $servicename to be the request parameter value.
+Servers SHOULD include an LF at the end of this line.
+Clients MUST ignore an LF at the end of the line.
+
+Servers MUST terminate the response with the magic "0000" end
+pkt-line marker.
+
+The returned response is a pkt-line stream describing each ref and
+its known value. The stream SHOULD be sorted by name according to
+the C locale ordering. The stream SHOULD include the default ref
+named 'HEAD' as the first ref. The stream MUST include capability
+declarations behind a NUL on the first ref.
+
+ smart_reply = PKT-LINE("# service=$servicename" LF)
+ ref_list
+ "0000"
+ ref_list = empty_list / non_empty_list
+
+ empty_list = PKT-LINE(zero-id SP "capabilities^{}" NUL cap-list LF)
+
+ non_empty_list = PKT-LINE(obj-id SP name NUL cap_list LF)
+ *ref_record
+
+ cap-list = capability *(SP capability)
+ capability = 1*(LC_ALPHA / DIGIT / "-" / "_")
+ LC_ALPHA = %x61-7A
+
+ ref_record = any_ref / peeled_ref
+ any_ref = PKT-LINE(obj-id SP name LF)
+ peeled_ref = PKT-LINE(obj-id SP name LF)
+ PKT-LINE(obj-id SP name "^{}" LF
+
+Smart Service git-upload-pack
+------------------------------
+This service reads from the repository pointed to by $GIT_URL.
+
+Clients MUST first perform ref discovery with
+'$GIT_URL/info/refs?service=git-upload-pack'.
+
+ C: POST $GIT_URL/git-upload-pack HTTP/1.0
+ C: Content-Type: application/x-git-upload-pack-request
+ C:
+ C: 0032want 0a53e9ddeaddad63ad106860237bbf53411d11a7\n
+ C: 0032have 441b40d833fdfa93eb2908e52742248faf0ee993\n
+ C: 0000
+
+ S: 200 OK
+ S: Content-Type: application/x-git-upload-pack-result
+ S: Cache-Control: no-cache
+ S:
+ S: ....ACK %s, continue
+ S: ....NAK
+
+Clients MUST NOT reuse or revalidate a cached reponse.
+Servers MUST include sufficient Cache-Control headers
+to prevent caching of the response.
+
+Servers SHOULD support all capabilities defined here.
+
+Clients MUST send at least one 'want' command in the request body.
+Clients MUST NOT reference an id in a 'want' command which did not
+appear in the response obtained through ref discovery unless the
+server advertises capability "allow-tip-sha1-in-want".
+
+ compute_request = want_list
+ have_list
+ request_end
+ request_end = "0000" / "done"
+
+ want_list = PKT-LINE(want NUL cap_list LF)
+ *(want_pkt)
+ want_pkt = PKT-LINE(want LF)
+ want = "want" SP id
+ cap_list = *(SP capability) SP
+
+ have_list = *PKT-LINE("have" SP id LF)
+
+TODO: Document this further.
+TODO: Don't use uppercase for variable names below.
+
+The Negotiation Algorithm
+~~~~~~~~~~~~~~~~~~~~~~~~~
+The computation to select the minimal pack proceeds as follows
+(c = client, s = server):
+
+ init step:
+ (c) Use ref discovery to obtain the advertised refs.
+ (c) Place any object seen into set ADVERTISED.
+
+ (c) Build an empty set, COMMON, to hold the objects that are later
+ determined to be on both ends.
+ (c) Build a set, WANT, of the objects from ADVERTISED the client
+ wants to fetch, based on what it saw during ref discovery.
+
+ (c) Start a queue, C_PENDING, ordered by commit time (popping newest
+ first). Add all client refs. When a commit is popped from
+ the queue its parents SHOULD be automatically inserted back.
+ Commits MUST only enter the queue once.
+
+ one compute step:
+ (c) Send one $GIT_URL/git-upload-pack request:
+
+ C: 0032want <WANT #1>...............................
+ C: 0032want <WANT #2>...............................
+ ....
+ C: 0032have <COMMON #1>.............................
+ C: 0032have <COMMON #2>.............................
+ ....
+ C: 0032have <HAVE #1>...............................
+ C: 0032have <HAVE #2>...............................
+ ....
+ C: 0000
+
+ The stream is organized into "commands", with each command
+ appearing by itself in a pkt-line. Within a command line
+ the text leading up to the first space is the command name,
+ and the remainder of the line to the first LF is the value.
+ Command lines are terminated with an LF as the last byte of
+ the pkt-line value.
+
+ Commands MUST appear in the following order, if they appear
+ at all in the request stream:
+
+ * want
+ * have
+
+ The stream is terminated by a pkt-line flush ("0000").
+
+ A single "want" or "have" command MUST have one hex formatted
+ SHA-1 as its value. Multiple SHA-1s MUST be sent by sending
+ multiple commands.
+
+ The HAVE list is created by popping the first 32 commits
+ from C_PENDING. Less can be supplied if C_PENDING empties.
+
+ If the client has sent 256 HAVE commits and has not yet
+ received one of those back from S_COMMON, or the client has
+ emptied C_PENDING it SHOULD include a "done" command to let
+ the server know it won't proceed:
+
+ C: 0009done
+
+ (s) Parse the git-upload-pack request:
+
+ Verify all objects in WANT are directly reachable from refs.
+
+ The server MAY walk backwards through history or through
+ the reflog to permit slightly stale requests.
+
+ If no WANT objects are received, send an error:
+
+TODO: Define error if no want lines are requested.
+
+ If any WANT object is not reachable, send an error:
+
+TODO: Define error if an invalid want is requested.
+
+ Create an empty list, S_COMMON.
+
+ If 'have' was sent:
+
+ Loop through the objects in the order supplied by the client.
+ For each object, if the server has the object reachable from
+ a ref, add it to S_COMMON. If a commit is added to S_COMMON,
+ do not add any ancestors, even if they also appear in HAVE.
+
+ (s) Send the git-upload-pack response:
+
+ If the server has found a closed set of objects to pack or the
+ request ends with "done", it replies with the pack.
+
+TODO: Document the pack based response
+ S: PACK...
+
+ The returned stream is the side-band-64k protocol supported
+ by the git-upload-pack service, and the pack is embedded into
+ stream 1. Progress messages from the server side MAY appear
+ in stream 2.
+
+ Here a "closed set of objects" is defined to have at least
+ one path from every WANT to at least one COMMON object.
+
+ If the server needs more information, it replies with a
+ status continue response:
+
+TODO: Document the non-pack response
+
+ (c) Parse the upload-pack response:
+
+TODO: Document parsing response
+
+ Do another compute step.
+
+
+Smart Service git-receive-pack
+------------------------------
+This service reads from the repository pointed to by $GIT_URL.
+
+Clients MUST first perform ref discovery with
+'$GIT_URL/info/refs?service=git-receive-pack'.
+
+ C: POST $GIT_URL/git-receive-pack HTTP/1.0
+ C: Content-Type: application/x-git-receive-pack-request
+ C:
+ C: ....0a53e9ddeaddad63ad106860237bbf53411d11a7 441b40d833fdfa93eb2908e52742248faf0ee993 refs/heads/maint\0 report-status
+ C: 0000
+ C: PACK....
+
+ S: 200 OK
+ S: Content-Type: application/x-git-receive-pack-result
+ S: Cache-Control: no-cache
+ S:
+ S: ....
+
+Clients MUST NOT reuse or revalidate a cached reponse.
+Servers MUST include sufficient Cache-Control headers
+to prevent caching of the response.
+
+Servers SHOULD support all capabilities defined here.
+
+Clients MUST send at least one command in the request body.
+Within the command portion of the request body clients SHOULD send
+the id obtained through ref discovery as old_id.
+
+ update_request = command_list
+ "PACK" <binary data>
+
+ command_list = PKT-LINE(command NUL cap_list LF)
+ *(command_pkt)
+ command_pkt = PKT-LINE(command LF)
+ cap_list = *(SP capability) SP
+
+ command = create / delete / update
+ create = zero-id SP new_id SP name
+ delete = old_id SP zero-id SP name
+ update = old_id SP new_id SP name
+
+TODO: Document this further.
+
+
+References
+----------
+
+link:http://www.ietf.org/rfc/rfc1738.txt[RFC 1738: Uniform Resource Locators (URL)]
+link:http://www.ietf.org/rfc/rfc2616.txt[RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1]
+link:technical/pack-protocol.html
+link:technical/protocol-capabilities.html
<linus> Yes, we always write out most recent first
-For the other record:
-
- <pasky> njs`: http://pastebin.com/547965
-
-The 'net never forgets, so that should be good until the end of time.
-
<njs`> And, yeah, I got the part about deeper-in-history stuff
having worse IO characteristics, one sort of doesn't care.
-Git User's Manual (for version 1.5.3 or newer)
-______________________________________________
-
+Git User Manual
+_______________
Git is a fast distributed revision control system.
The best way to see how this works is using the linkgit:gitk[1]
command; running gitk now on a Git repository and looking for merge
-commits will help understand how the Git organizes history.
+commits will help understand how Git organizes history.
In the following, we say that commit X is "reachable" from commit Y
if commit X is an ancestor of commit Y. Equivalently, you could say
a summary of the commands:
`git branch`::
- list all branches
+ list all branches.
`git branch <branch>`::
create a new branch named `<branch>`, referencing the same
- point in history as the current branch
+ point in history as the current branch.
`git branch <branch> <start-point>`::
create a new branch named `<branch>`, referencing
`<start-point>`, which may be specified any way you like,
- including using a branch name or a tag name
+ including using a branch name or a tag name.
`git branch -d <branch>`::
- delete the branch `<branch>`; if the branch you are deleting
- points to a commit which is not reachable from the current
- branch, this command will fail with a warning.
+ delete the branch `<branch>`; if the branch is not fully
+ merged in its upstream branch or contained in the current branch,
+ this command will fail with a warning.
`git branch -D <branch>`::
- even if the branch points to a commit not reachable
- from the current branch, you may know that that commit
- is still reachable from some other branch or tag. In that
- case it is safe to use this command to force Git to delete
- the branch.
+ delete the branch `<branch>` irrespective of its merged status.
`git checkout <branch>`::
make the current branch `<branch>`, updating the working
- directory to reflect the version referenced by `<branch>`
+ directory to reflect the version referenced by `<branch>`.
`git checkout -b <new> <start-point>`::
create a new branch `<new>` referencing `<start-point>`, and
check it out.
------------------------------------------------
$ git checkout v2.6.17
-Note: moving to "v2.6.17" which isn't a local branch
-If you want to create a new branch from this checkout, you may do so
-(now or later) by using -b with the checkout command again. Example:
- git checkout -b <new_branch_name>
+Note: checking out 'v2.6.17'.
+
+You are in 'detached HEAD' state. You can look around, make experimental
+changes and commit them, and you can discard any commits you make in this
+state without impacting any branches by performing another checkout.
+
+If you want to create a new branch to retain commits you create, you may
+do so (now or later) by using -b with the checkout command again. Example:
+
+ git checkout -b new_branch_name
+
HEAD is now at 427abfa... Linux v2.6.17
------------------------------------------------
$ cat .git/HEAD
427abfa28afedffadfca9dd8b067eb6d36bac53f
$ git branch
-* (no branch)
+* (detached from v2.6.17)
master
------------------------------------------------
-------------------------------------------------
Or you could recall that the `...` operator selects all commits
-contained reachable from either one reference or the other but not
+reachable from either one reference or the other but not
both; so
-------------------------------------------------
$ gitk e05db0fd..
-------------------------------------------------
-Or you can use linkgit:git-name-rev[1], which will give the commit a
+or you can use linkgit:git-name-rev[1], which will give the commit a
name based on any tag it finds pointing to one of the commit's
descendants:
As yet another alternative, the linkgit:git-show-branch[1] command lists
the commits reachable from its arguments with a display on the left-hand
-side that indicates which arguments that commit is reachable from. So,
-you can run something like
+side that indicates which arguments that commit is reachable from.
+So, if you run something like
-------------------------------------------------
$ git show-branch e05db0fd v1.5.0-rc0 v1.5.0-rc1 v1.5.0-rc2
...
-------------------------------------------------
-then search for a line that looks like
+then a line like
-------------------------------------------------
+ ++ [e05db0fd] Fix warnings in sha1_file.c - use C99 printf format if
available
-------------------------------------------------
-Which shows that e05db0fd is reachable from itself, from v1.5.0-rc1, and
-from v1.5.0-rc2, but not from v1.5.0-rc0.
+shows that e05db0fd is reachable from itself, from v1.5.0-rc1,
+and from v1.5.0-rc2, and not from v1.5.0-rc0.
[[showing-commits-unique-to-a-branch]]
Showing commits unique to a given branch
Modifying the index is easy:
-To update the index with the new contents of a modified file, use
-
--------------------------------------------------
-$ git add path/to/file
--------------------------------------------------
-
-To add the contents of a new file to the index, use
+To update the index with the contents of a new or modified file, use
-------------------------------------------------
$ git add path/to/file
-------------------------------------------------
-To remove a file from the index and from the working tree,
+To remove a file from the index and from the working tree, use
-------------------------------------------------
$ git rm path/to/file
$ git merge branch
-------------------------------------------------
-are roughly equivalent. The former is actually very commonly used.
+are roughly equivalent.
[[submitting-patches]]
Submitting patches to a project
-------------------------------------------------
(See also
-link:howto/setup-git-server-over-http.txt[setup-git-server-over-http]
+link:howto/setup-git-server-over-http.html[setup-git-server-over-http]
for a slightly more sophisticated setup using WebDAV which also
allows pushing over HTTP.)
$ ... patch ... test ... commit [ ... patch ... test ... commit ]*
-------------------------------------------------
-When you are happy with the state of this change, you can pull it into the
+When you are happy with the state of this change, you can merge it into the
"test" branch in preparation to make it public:
-------------------------------------------------
-$ git checkout test && git pull . speed-up-spinlocks
+$ git checkout test && git merge speed-up-spinlocks
-------------------------------------------------
It is unlikely that you would have any conflicts here ... but you might if you
means that the patches can be moved into the `release` tree in any order.
-------------------------------------------------
-$ git checkout release && git pull . speed-up-spinlocks
+$ git checkout release && git merge speed-up-spinlocks
-------------------------------------------------
After a while, you will have a number of branches, and despite the
You can save space and make Git faster by moving these loose objects in
to a "pack file", which stores a group of objects in an efficient
compressed format; the details of how pack files are formatted can be
-found in link:technical/pack-format.txt[technical/pack-format.txt].
+found in link:technical/pack-format.html[pack format].
To put the loose objects into a pack, just run git repack:
------------------------------------------------
$ git repack
-Generating pack...
-Done counting 6020 objects.
-Deltifying 6020 objects.
- 100% (6020/6020) done
-Writing 6020 objects.
- 100% (6020/6020) done
-Total 6020, written 6020 (delta 4070), reused 0 (delta 0)
-Pack pack-3e54ad29d5b2e05838c75df582c65257b8d08e1c created.
+Counting objects: 6020, done.
+Delta compression using up to 4 threads.
+Compressing objects: 100% (6020/6020), done.
+Writing objects: 100% (6020/6020), done.
+Total 6020 (delta 4070), reused 0 (delta 0)
------------------------------------------------
-You can then run
+This creates a single "pack file" in .git/objects/pack/
+containing all currently unpacked objects. You can then run
------------------------------------------------
$ git prune
$ git prune
------------------------------------------------
-and they'll be gone. But you should only run `git prune` on a quiescent
+and they'll be gone. (You should only run `git prune` on a quiescent
repository--it's kind of like doing a filesystem fsck recovery: you
don't want to do that while the filesystem is mounted.
-
-(The same is true of `git fsck` itself, btw, but since
-`git fsck` never actually *changes* the repository, it just reports
-on what it found, `git fsck` itself is never 'dangerous' to run.
-Running it while somebody is actually changing the repository can cause
-confusing and scary messages, but it won't actually do anything bad. In
-contrast, running `git prune` while somebody is actively changing the
-repository is a *BAD* idea).
+`git prune` is designed not to cause any harm in such cases of concurrent
+accesses to a repository but you might receive confusing or scary messages.)
[[recovering-from-repository-corruption]]
Recovering from repository corruption
manually check them out; earlier versions won't recognize the submodules at
all.
-To see how submodule support works, create (for example) four example
+To see how submodule support works, create four example
repositories that can be used later as a submodule:
-------------------------------------------------
-------------------------------------------------
$ git branch
-* (no branch)
+* (detached from d266b98)
master
-------------------------------------------------
previous states represented by other commits.
In other words, while a "tree" represents a particular directory state
-of a working directory, a "commit" represents that state in "time",
+of a working directory, a "commit" represents that state in time,
and explains how we got there.
You create a commit object by giving it the tree that describes the
result to the file pointed at by `.git/HEAD`, so that we can always see
what the last committed state was.
-Here is an ASCII art by Jon Loeliger that illustrates how
-various pieces fit together.
+Here is a picture that illustrates how various pieces fit together:
------------
Merging multiple trees
----------------------
-Git helps you do a three-way merge, which you can expand to n-way by
-repeating the merge procedure arbitrary times until you finally
-"commit" the state. The normal situation is that you'd only do one
-three-way merge (two parents), and commit it, but if you like to, you
-can do multiple parents in one go.
+Git can help you perform a three-way merge, which can in turn be
+used for a many-way merge by repeating the merge procedure several
+times. The usual situation is that you only do one three-way merge
+(reconciling two lines of history) and commit the result, but if
+you like to, you can merge several branches in one go.
-To do a three-way merge, you need the two sets of "commit" objects
-that you want to merge, use those to find the closest common parent (a
-third "commit" object), and then use those commit objects to find the
-state of the directory ("tree" object) at these points.
+To perform a three-way merge, you start with the two commits you
+want to merge, find their closest common parent (a third commit),
+and compare the trees corresponding to these three commits.
-To get the "base" for the merge, you first look up the common parent
-of two commits with
+To get the "base" for the merge, look up the common parent of two
+commits:
-------------------------------------------------
$ git merge-base <commit1> <commit2>
-------------------------------------------------
-which will return you the commit they are both based on. You should
-now look up the "tree" objects of those commits, which you can easily
-do with (for example)
+This prints the name of a commit they are both based on. You should
+now look up the tree objects of those commits, which you can easily
+do with
-------------------------------------------------
$ git cat-file commit <commitname> | head -1
that is used to name the object is the hash of the original data
plus this header, so `sha1sum` 'file' does not match the object name
for 'file'.
-(Historical note: in the dawn of the age of Git the hash
-was the SHA-1 of the 'compressed' object.)
As a result, the general consistency of an object can always be tested
independently of the contents or the type of the object: all objects can
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.8.4
+DEF_VER=v1.8.5-rc0
LF='
'
# Define NO_MSGFMT_EXTENDED_OPTIONS if your implementation of msgfmt
# doesn't support GNU extensions like --check and --statistics
#
-# Define NEEDS_CLIPPED_WRITE if your write(2) cannot write more than
-# INT_MAX bytes at once (e.g. MacOS X).
-#
# Define HAVE_PATHS_H if you have paths.h and want to use the default PATH
# it specifies.
#
SCRIPT_SH += git-quiltimport.sh
SCRIPT_SH += git-rebase.sh
SCRIPT_SH += git-remote-testgit.sh
-SCRIPT_SH += git-repack.sh
SCRIPT_SH += git-request-pull.sh
SCRIPT_SH += git-stash.sh
SCRIPT_SH += git-submodule.sh
SCRIPT_PERL += git-send-email.perl
SCRIPT_PERL += git-svn.perl
-SCRIPT_PYTHON += git-remote-testpy.py
SCRIPT_PYTHON += git-p4.py
NO_INSTALL += git-remote-testgit
-NO_INSTALL += git-remote-testpy
# Generated files for scripts
SCRIPT_SH_GEN = $(patsubst %.sh,%,$(SCRIPT_SH))
TEST_PROGRAMS_NEED_X += test-string-list
TEST_PROGRAMS_NEED_X += test-subprocess
TEST_PROGRAMS_NEED_X += test-svn-fe
+TEST_PROGRAMS_NEED_X += test-urlmatch-normalization
TEST_PROGRAMS_NEED_X += test-wildmatch
TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
LIB_H += tree.h
LIB_H += unpack-trees.h
LIB_H += url.h
+LIB_H += urlmatch.h
LIB_H += userdiff.h
LIB_H += utf8.h
LIB_H += varint.h
LIB_OBJS += tree-walk.o
LIB_OBJS += unpack-trees.o
LIB_OBJS += url.o
+LIB_OBJS += urlmatch.o
LIB_OBJS += usage.o
LIB_OBJS += userdiff.o
LIB_OBJS += utf8.o
BUILTIN_OBJS += builtin/remote.o
BUILTIN_OBJS += builtin/remote-ext.o
BUILTIN_OBJS += builtin/remote-fd.o
+BUILTIN_OBJS += builtin/repack.o
BUILTIN_OBJS += builtin/replace.o
BUILTIN_OBJS += builtin/rerere.o
BUILTIN_OBJS += builtin/reset.o
else
LIB_4_CRYPTO = $(OPENSSL_LINK) -lcrypto
endif
+ifdef APPLE_COMMON_CRYPTO
+ LIB_4_CRYPTO += -framework Security -framework CoreFoundation
+endif
endif
ifdef NEEDS_LIBICONV
ifdef ICONVDIR
MSGFMT += --check --statistics
endif
-ifdef NEEDS_CLIPPED_WRITE
- BASIC_CFLAGS += -DNEEDS_CLIPPED_WRITE
- COMPAT_OBJS += compat/clipped-write.o
-endif
-
ifneq (,$(XDL_FAST_HASH))
BASIC_CFLAGS += -DXDL_FAST_HASH
endif
endif
ifndef NO_PERL
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' localedir='$(localedir_SQ)' all
-endif
-ifndef NO_PYTHON
- $(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all
endif
$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
$(SCRIPT_PYTHON_GEN): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS
$(SCRIPT_PYTHON_GEN): % : %.py
$(QUIET_GEN)$(RM) $@ $@+ && \
- INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
- --no-print-directory prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' \
- instlibdir` && \
sed -e '1s|#!.*python|#!$(PYTHON_PATH_SQ)|' \
- -e 's|\(os\.getenv("GITPYTHONLIB"\)[^)]*)|\1,"@@INSTLIBDIR@@")|' \
- -e 's|@@INSTLIBDIR@@|'"$$INSTLIBDIR"'|g' \
$< >$@+ && \
chmod +x $@+ && \
mv $@+ $@
gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
-DGIT_LOCALE_PATH='"$(localedir_SQ)"'
+http-push.sp http.sp http-walker.sp remote-curl.sp: SPARSE_FLAGS += \
+ -DCURL_DISABLE_TYPECHECK
+
ifdef NO_EXPAT
http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
endif
$(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
$(MAKE) -C gitweb install
endif
-ifndef NO_PYTHON
- $(MAKE) -C git_remote_helpers prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
-endif
ifndef NO_TCLTK
$(MAKE) -C gitk-git install
$(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install
ifndef NO_PERL
$(MAKE) -C gitweb clean
$(MAKE) -C perl clean
-endif
-ifndef NO_PYTHON
- $(MAKE) -C git_remote_helpers clean
endif
$(MAKE) -C templates/ clean
$(MAKE) -C t/ clean
-Documentation/RelNotes/1.8.4.txt
\ No newline at end of file
+Documentation/RelNotes/1.8.5.txt
\ No newline at end of file
else
goto error_out;
}
- if (len && !is_dir_sep(buf[len-1]))
+ if (len && !is_dir_sep(buf[len - 1]))
buf[len++] = '/';
strcpy(buf + len, last_elem);
free(last_elem);
if (!cwd)
die_errno("Cannot determine the current working directory");
len = strlen(cwd);
- fmt = (len > 0 && is_dir_sep(cwd[len-1])) ? "%s%s" : "%s/%s";
+ fmt = (len > 0 && is_dir_sep(cwd[len - 1])) ? "%s%s" : "%s/%s";
if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX)
die("Too long path: %.*s", 60, path);
}
static int alias_lookup_cb(const char *k, const char *v, void *cb)
{
- if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) {
+ if (!prefixcmp(k, "alias.") && !strcmp(k + 6, alias_key)) {
if (!v)
return config_error_nonbool(k);
alias_val = xstrdup(v);
int src, dst, count = 0, size = 16;
char quoted = 0;
- *argv = xmalloc(sizeof(char *) * size);
+ *argv = xmalloc(sizeof(**argv) * size);
/* split alias_string */
(*argv)[count++] = cmdline;
while (cmdline[++src]
&& isspace(cmdline[src]))
; /* skip */
- ALLOC_GROW(*argv, count+1, size);
+ ALLOC_GROW(*argv, count + 1, size);
(*argv)[count++] = cmdline + dst;
} else if (!quoted && (c == '\'' || c == '"')) {
quoted = c;
return -SPLIT_CMDLINE_UNCLOSED_QUOTE;
}
- ALLOC_GROW(*argv, count+1, size);
+ ALLOC_GROW(*argv, count + 1, size);
(*argv)[count] = NULL;
return count;
}
-const char *split_cmdline_strerror(int split_cmdline_errno) {
- return split_cmdline_errors[-split_cmdline_errno-1];
+const char *split_cmdline_strerror(int split_cmdline_errno)
+{
+ return split_cmdline_errors[-split_cmdline_errno - 1];
}
}
#define REPORT(name) \
- report(#name, name##_allocs, name##_allocs*sizeof(struct name) >> 10)
+ report(#name, name##_allocs, name##_allocs * sizeof(struct name) >> 10)
void alloc_report(void)
{
struct archiver_context context;
struct unpack_trees_options opts;
struct tree_desc t;
- struct pathspec pathspec;
int err;
if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
git_attr_set_direction(GIT_ATTR_INDEX, &the_index);
}
- init_pathspec(&pathspec, args->pathspec);
- err = read_tree_recursive(args->tree, "", 0, 0, &pathspec,
+ err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec,
write_archive_entry, &context);
- free_pathspec(&pathspec);
if (err == READ_TREE_RECURSIVE)
err = 0;
return err;
struct pathspec pathspec;
int ret;
- init_pathspec(&pathspec, paths);
+ parse_pathspec(&pathspec, 0, 0, "", paths);
ret = read_tree_recursive(tree, "", 0, 0, &pathspec, reject_entry, NULL);
free_pathspec(&pathspec);
return ret != 0;
static void parse_pathspec_arg(const char **pathspec,
struct archiver_args *ar_args)
{
- ar_args->pathspec = pathspec = get_pathspec("", pathspec);
+ /*
+ * must be consistent with parse_pathspec in path_exists()
+ * Also if pathspec patterns are dependent, we're in big
+ * trouble as we test each one separately
+ */
+ parse_pathspec(&ar_args->pathspec, 0,
+ PATHSPEC_PREFER_FULL,
+ "", pathspec);
if (pathspec) {
while (*pathspec) {
if (**pathspec && !path_exists(ar_args->tree, *pathspec))
- die("path not found: %s", *pathspec);
+ die(_("pathspec '%s' did not match any files"), *pathspec);
pathspec++;
}
}
* prefix is non-empty (k.e., we don't match .tar.gz with no actual
* filename).
*/
- if (prefixlen < 2 || filename[prefixlen-1] != '.')
+ if (prefixlen < 2 || filename[prefixlen - 1] != '.')
return 0;
return !strcmp(filename + prefixlen, ext);
}
#ifndef ARCHIVE_H
#define ARCHIVE_H
+#include "pathspec.h"
+
struct archiver_args {
const char *base;
size_t baselen;
const unsigned char *commit_sha1;
const struct commit *commit;
time_t time;
- const char **pathspec;
+ struct pathspec pathspec;
unsigned int verbose : 1;
unsigned int worktree_attributes : 1;
unsigned int convert : 1;
{
prep_base85();
- say2("decode 85 <%.*s>", len/4*5, buffer);
+ say2("decode 85 <%.*s>", len / 4 * 5, buffer);
while (len) {
unsigned acc = 0;
int de, cnt = 4;
if (prepare_revision_walk(revs))
die("revision walk setup failed");
if (revs->tree_objects)
- mark_edges_uninteresting(revs->commits, revs, NULL);
+ mark_edges_uninteresting(revs, NULL);
}
static void exit_if_skipped_commits(struct commit_list *tried,
padlen[1] = htonl((uint32_t)(ctx->size << 3));
i = ctx->size & 63;
- blk_SHA1_Update(ctx, pad, 1+ (63 & (55 - i)));
+ blk_SHA1_Update(ctx, pad, 1 + (63 & (55 - i)));
blk_SHA1_Update(ctx, padlen, 8);
/* Output hash */
for (i = 0; i < 5; i++)
- put_be32(hashout + i*4, ctx->H[i]);
+ put_be32(hashout + i * 4, ctx->H[i]);
}
struct refspec query;
memset(&query, 0, sizeof(struct refspec));
query.dst = tracking_branch;
- return !(remote_find_tracking(remote, &query) ||
- prefixcmp(query.src, "refs/heads/"));
+ return !remote_find_tracking(remote, &query);
}
static int validate_remote_tracking_branch(char *ref)
hashcpy(sha1, commit->object.sha1);
if (!dont_change_ref) {
- lock = lock_any_ref_for_update(ref.buf, NULL, 0);
+ lock = lock_any_ref_for_update(ref.buf, NULL, 0, NULL);
if (!lock)
die_errno(_("Failed to lock ref for update"));
}
start_name);
if (real_ref && track)
- setup_tracking(ref.buf+11, real_ref, track, quiet);
+ setup_tracking(ref.buf + 11, real_ref, track, quiet);
if (!dont_change_ref)
if (write_ref_sha1(lock, sha1, msg) < 0)
extern int cmd_remote(int argc, const char **argv, const char *prefix);
extern int cmd_remote_ext(int argc, const char **argv, const char *prefix);
extern int cmd_remote_fd(int argc, const char **argv, const char *prefix);
+extern int cmd_repack(int argc, const char **argv, const char *prefix);
extern int cmd_repo_config(int argc, const char **argv, const char *prefix);
extern int cmd_rerere(int argc, const char **argv, const char *prefix);
extern int cmd_reset(int argc, const char **argv, const char *prefix);
}
}
-static void update_files_in_cache(const char *prefix, const char **pathspec,
+static void update_files_in_cache(const char *prefix,
+ const struct pathspec *pathspec,
struct update_callback_data *data)
{
struct rev_info rev;
init_revisions(&rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
- init_pathspec(&rev.prune_data, pathspec);
+ if (pathspec)
+ copy_pathspec(&rev.prune_data, pathspec);
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = update_callback;
rev.diffopt.format_callback_data = data;
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
}
-int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
+int add_files_to_cache(const char *prefix,
+ const struct pathspec *pathspec, int flags)
{
struct update_callback_data data;
}
#define WARN_IMPLICIT_DOT (1u << 0)
-static char *prune_directory(struct dir_struct *dir, const char **pathspec,
+static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec,
int prefix, unsigned flag)
{
char *seen;
- int i, specs;
+ int i;
struct dir_entry **src, **dst;
- for (specs = 0; pathspec[specs]; specs++)
- /* nothing */;
- seen = xcalloc(specs, 1);
+ seen = xcalloc(pathspec->nr, 1);
src = dst = dir->entries;
i = dir->nr;
while (--i >= 0) {
struct dir_entry *entry = *src++;
- if (match_pathspec(pathspec, entry->name, entry->len,
- prefix, seen))
+ if (match_pathspec_depth(pathspec, entry->name, entry->len,
+ prefix, seen))
*dst++ = entry;
else if (flag & WARN_IMPLICIT_DOT)
/*
warn_pathless_add();
}
dir->nr = dst - dir->entries;
- add_pathspec_matches_against_index(pathspec, seen, specs);
+ add_pathspec_matches_against_index(pathspec, seen);
return seen;
}
-/*
- * Checks the index to see whether any path in pathspec refers to
- * something inside a submodule. If so, dies with an error message.
- */
-static void treat_gitlinks(const char **pathspec)
-{
- int i;
-
- if (!pathspec || !*pathspec)
- return;
-
- for (i = 0; pathspec[i]; i++)
- pathspec[i] = check_path_for_gitlink(pathspec[i]);
-}
-
-static void refresh(int verbose, const char **pathspec)
+static void refresh(int verbose, const struct pathspec *pathspec)
{
char *seen;
- int i, specs;
+ int i;
- for (specs = 0; pathspec[specs]; specs++)
- /* nothing */;
- seen = xcalloc(specs, 1);
+ seen = xcalloc(pathspec->nr, 1);
refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
pathspec, seen, _("Unstaged changes after refreshing the index:"));
- for (i = 0; i < specs; i++) {
+ for (i = 0; i < pathspec->nr; i++) {
if (!seen[i])
- die(_("pathspec '%s' did not match any files"), pathspec[i]);
+ die(_("pathspec '%s' did not match any files"),
+ pathspec->items[i].match);
}
free(seen);
}
-/*
- * Normalizes argv relative to prefix, via get_pathspec(), and then
- * runs die_if_path_beyond_symlink() on each path in the normalized
- * list.
- */
-static const char **validate_pathspec(const char **argv, const char *prefix)
-{
- const char **pathspec = get_pathspec(prefix, argv);
-
- if (pathspec) {
- const char **p;
- for (p = pathspec; *p; p++) {
- die_if_path_beyond_symlink(*p, prefix);
- }
- }
-
- return pathspec;
-}
-
int run_add_interactive(const char *revision, const char *patch_mode,
- const char **pathspec)
+ const struct pathspec *pathspec)
{
- int status, ac, pc = 0;
+ int status, ac, i;
const char **args;
- if (pathspec)
- while (pathspec[pc])
- pc++;
-
- args = xcalloc(sizeof(const char *), (pc + 5));
+ args = xcalloc(sizeof(const char *), (pathspec->nr + 6));
ac = 0;
args[ac++] = "add--interactive";
if (patch_mode)
if (revision)
args[ac++] = revision;
args[ac++] = "--";
- if (pc) {
- memcpy(&(args[ac]), pathspec, sizeof(const char *) * pc);
- ac += pc;
- }
- args[ac] = NULL;
+ for (i = 0; i < pathspec->nr; i++)
+ /* pass original pathspec, to be re-parsed */
+ args[ac++] = pathspec->items[i].original;
status = run_command_v_opt(args, RUN_GIT_CMD);
free(args);
int interactive_add(int argc, const char **argv, const char *prefix, int patch)
{
- const char **pathspec = NULL;
+ struct pathspec pathspec;
- if (argc) {
- pathspec = validate_pathspec(argv, prefix);
- if (!pathspec)
- return -1;
- }
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_FULL |
+ PATHSPEC_SYMLINK_LEADING_PATH |
+ PATHSPEC_PREFIX_ORIGIN,
+ prefix, argv);
return run_add_interactive(NULL,
patch ? "--patch" : NULL,
- pathspec);
+ &pathspec);
}
static int edit_patch(int argc, const char **argv, const char *prefix)
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
if (read_cache() < 0)
- die (_("Could not read the index"));
+ die(_("Could not read the index"));
init_revisions(&rev, prefix);
rev.diffopt.context = 7;
DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
out = open(file, O_CREAT | O_WRONLY, 0666);
if (out < 0)
- die (_("Could not open '%s' for writing."), file);
+ die(_("Could not open '%s' for writing."), file);
rev.diffopt.file = xfdopen(out, "w");
rev.diffopt.close_file = 1;
if (run_diff_files(&rev, 0))
- die (_("Could not write patch"));
+ die(_("Could not write patch"));
launch_editor(file, NULL, NULL);
child.git_cmd = 1;
child.argv = apply_argv;
if (run_command(&child))
- die (_("Could not apply '%s'"), file);
+ die(_("Could not apply '%s'"), file);
unlink(file);
free(file);
{
int exit_status = 0;
int newfd;
- const char **pathspec;
+ struct pathspec pathspec;
struct dir_struct dir;
int flags;
int add_new_files;
fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
return 0;
}
- pathspec = validate_pathspec(argv, prefix);
if (read_cache() < 0)
die(_("index file corrupt"));
- treat_gitlinks(pathspec);
+
+ /*
+ * Check the "pathspec '%s' did not match any files" block
+ * below before enabling new magic.
+ */
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_FULL |
+ PATHSPEC_SYMLINK_LEADING_PATH |
+ PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE,
+ prefix, argv);
if (add_new_files) {
int baselen;
+ struct pathspec empty_pathspec;
/* Set up the default git porcelain excludes */
memset(&dir, 0, sizeof(dir));
setup_standard_excludes(&dir);
}
+ memset(&empty_pathspec, 0, sizeof(empty_pathspec));
/* This picks up the paths that are not tracked */
- baselen = fill_directory(&dir, implicit_dot ? NULL : pathspec);
- if (pathspec)
- seen = prune_directory(&dir, pathspec, baselen,
+ baselen = fill_directory(&dir, implicit_dot ? &empty_pathspec : &pathspec);
+ if (pathspec.nr)
+ seen = prune_directory(&dir, &pathspec, baselen,
implicit_dot ? WARN_IMPLICIT_DOT : 0);
}
if (refresh_only) {
- refresh(verbose, pathspec);
+ refresh(verbose, &pathspec);
goto finish;
}
if (implicit_dot && prefix)
refresh_cache(REFRESH_QUIET);
- if (pathspec) {
+ if (pathspec.nr) {
int i;
if (!seen)
- seen = find_pathspecs_matching_against_index(pathspec);
- for (i = 0; pathspec[i]; i++) {
- if (!seen[i] && pathspec[i][0]
- && !file_exists(pathspec[i])) {
+ seen = find_pathspecs_matching_against_index(&pathspec);
+
+ /*
+ * file_exists() assumes exact match
+ */
+ GUARD_PATHSPEC(&pathspec,
+ PATHSPEC_FROMTOP |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ICASE);
+
+ for (i = 0; i < pathspec.nr; i++) {
+ const char *path = pathspec.items[i].match;
+ if (!seen[i] &&
+ ((pathspec.items[i].magic &
+ (PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
+ !file_exists(path))) {
if (ignore_missing) {
int dtype = DT_UNKNOWN;
- if (is_excluded(&dir, pathspec[i], &dtype))
- dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i]));
+ if (is_excluded(&dir, path, &dtype))
+ dir_add_ignored(&dir, path, pathspec.items[i].len);
} else
die(_("pathspec '%s' did not match any files"),
- pathspec[i]);
+ pathspec.items[i].original);
}
}
free(seen);
*/
update_data.implicit_dot = prefix;
update_data.implicit_dot_len = strlen(prefix);
- pathspec = NULL;
+ free_pathspec(&pathspec);
+ memset(&pathspec, 0, sizeof(pathspec));
}
update_data.flags = flags & ~ADD_CACHE_IMPLICIT_DOT;
- update_files_in_cache(prefix, pathspec, &update_data);
+ update_files_in_cache(prefix, &pathspec, &update_data);
exit_status |= !!update_data.add_errors;
if (add_new_files)
unplug_bulk_checkin();
- finish:
+finish:
if (active_cache_changed) {
if (write_cache(newfd, active_cache, active_nr) ||
commit_locked_index(&lock_file))
{ OPTION_CALLBACK, 'p', NULL, NULL, N_("num"),
N_("remove <num> leading slashes from traditional diff paths"),
0, option_parse_p },
- OPT_BOOLEAN(0, "no-add", &no_add,
+ OPT_BOOL(0, "no-add", &no_add,
N_("ignore additions made by the patch")),
- OPT_BOOLEAN(0, "stat", &diffstat,
+ OPT_BOOL(0, "stat", &diffstat,
N_("instead of applying the patch, output diffstat for the input")),
OPT_NOOP_NOARG(0, "allow-binary-replacement"),
OPT_NOOP_NOARG(0, "binary"),
- OPT_BOOLEAN(0, "numstat", &numstat,
+ OPT_BOOL(0, "numstat", &numstat,
N_("show number of added and deleted lines in decimal notation")),
- OPT_BOOLEAN(0, "summary", &summary,
+ OPT_BOOL(0, "summary", &summary,
N_("instead of applying the patch, output a summary for the input")),
- OPT_BOOLEAN(0, "check", &check,
+ OPT_BOOL(0, "check", &check,
N_("instead of applying the patch, see if the patch is applicable")),
- OPT_BOOLEAN(0, "index", &check_index,
+ OPT_BOOL(0, "index", &check_index,
N_("make sure the patch is applicable to the current index")),
- OPT_BOOLEAN(0, "cached", &cached,
+ OPT_BOOL(0, "cached", &cached,
N_("apply a patch without touching the working tree")),
- OPT_BOOLEAN(0, "apply", &force_apply,
+ OPT_BOOL(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")),
{ OPTION_CALLBACK, 0, "ignore-whitespace", NULL, NULL,
N_("ignore changes in whitespace when finding context"),
PARSE_OPT_NOARG, option_parse_space_change },
- OPT_BOOLEAN('R', "reverse", &apply_in_reverse,
+ OPT_BOOL('R', "reverse", &apply_in_reverse,
N_("apply the patch in reverse")),
- OPT_BOOLEAN(0, "unidiff-zero", &unidiff_zero,
+ OPT_BOOL(0, "unidiff-zero", &unidiff_zero,
N_("don't expect at least one line of context")),
- OPT_BOOLEAN(0, "reject", &apply_with_reject,
+ OPT_BOOL(0, "reject", &apply_with_reject,
N_("leave the rejected hunks in corresponding *.rej files")),
- OPT_BOOLEAN(0, "allow-overlap", &allow_overlap,
+ OPT_BOOL(0, "allow-overlap", &allow_overlap,
N_("allow overlapping hunks")),
OPT__VERBOSE(&apply_verbosely, N_("be verbose")),
OPT_BIT(0, "inaccurate-eof", &options,
int next_all = 0;
int no_checkout = 0;
struct option options[] = {
- OPT_BOOLEAN(0, "next-all", &next_all,
- N_("perform 'git bisect next'")),
- OPT_BOOLEAN(0, "no-checkout", &no_checkout,
- N_("update BISECT_HEAD instead of checking out the current commit")),
+ OPT_BOOL(0, "next-all", &next_all,
+ N_("perform 'git bisect next'")),
+ OPT_BOOL(0, "no-checkout", &no_checkout,
+ N_("update BISECT_HEAD instead of checking out the current commit")),
OPT_END()
};
#include "utf8.h"
#include "userdiff.h"
#include "line-range.h"
+#include "line-log.h"
static char blame_usage[] = N_("git blame [options] [rev-opts] [rev] [--] file");
paths[0] = origin->path;
paths[1] = NULL;
- diff_tree_setup_paths(paths, &diff_opts);
+ parse_pathspec(&diff_opts.pathspec, PATHSPEC_ALL_MAGIC, 0, "", paths);
diff_setup_done(&diff_opts);
if (is_null_sha1(origin->commit->object.sha1))
}
}
diff_flush(&diff_opts);
- diff_tree_release_paths(&diff_opts);
+ free_pathspec(&diff_opts.pathspec);
if (porigin) {
/*
* Create a freestanding copy that is not part of
struct origin *porigin = NULL;
struct diff_options diff_opts;
int i;
- const char *paths[2];
diff_setup(&diff_opts);
DIFF_OPT_SET(&diff_opts, RECURSIVE);
diff_opts.detect_rename = DIFF_DETECT_RENAME;
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
diff_opts.single_follow = origin->path;
- paths[0] = NULL;
- diff_tree_setup_paths(paths, &diff_opts);
diff_setup_done(&diff_opts);
if (is_null_sha1(origin->commit->object.sha1))
}
}
diff_flush(&diff_opts);
- diff_tree_release_paths(&diff_opts);
+ free_pathspec(&diff_opts.pathspec);
return porigin;
}
int opt)
{
struct diff_options diff_opts;
- const char *paths[1];
int i, j;
int retval;
struct blame_list *blame_list;
DIFF_OPT_SET(&diff_opts, RECURSIVE);
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
- paths[0] = NULL;
- diff_tree_setup_paths(paths, &diff_opts);
diff_setup_done(&diff_opts);
/* Try "find copies harder" on new path if requested;
}
reset_scanned_flag(sb);
diff_flush(&diff_opts);
- diff_tree_release_paths(&diff_opts);
+ free_pathspec(&diff_opts.pathspec);
return retval;
}
return prefix_path(prefix, prefix ? strlen(prefix) : 0, path);
}
-/*
- * Parsing of -L option
- */
-static void prepare_blame_range(struct scoreboard *sb,
- const char *bottomtop,
- long lno,
- long *bottom, long *top)
-{
- if (parse_range_arg(bottomtop, nth_line_cb, sb, lno, bottom, top, sb->path))
- usage(blame_usage);
-}
-
static int git_blame_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "blame.showroot")) {
return 0;
}
-static int blame_bottomtop_callback(const struct option *option, const char *arg, int unset)
-{
- const char **bottomtop = option->value;
- if (!arg)
- return -1;
- if (*bottomtop)
- die("More than one '-L n,m' option given");
- *bottomtop = arg;
- return 0;
-}
-
int cmd_blame(int argc, const char **argv, const char *prefix)
{
struct rev_info revs;
const char *path;
struct scoreboard sb;
struct origin *o;
- struct blame_entry *ent;
- long dashdash_pos, bottom, top, lno;
+ struct blame_entry *ent = NULL;
+ long dashdash_pos, lno;
const char *final_commit_name = NULL;
enum object_type type;
- static const char *bottomtop = NULL;
+ static struct string_list range_list;
static int output_option = 0, opt = 0;
static int show_stats = 0;
static const char *revs_file = NULL;
static const char *contents_from = NULL;
static const struct option options[] = {
- 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_BOOL(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")),
+ OPT_BOOL('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")),
+ OPT_BOOL(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
+ OPT_BOOL(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_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_STRING_LIST('L', NULL, &range_list, N_("n,m"), N_("Process only line range n,m, counting from 1")),
OPT__ABBREV(&abbrev),
OPT_END()
};
struct parse_opt_ctx_t ctx;
int cmd_is_annotate = !strcmp(argv[0], "annotate");
+ struct range_set ranges;
+ unsigned int range_i;
+ long anchor;
git_config(git_blame_config, NULL);
init_revisions(&revs, NULL);
num_read_blob++;
lno = prepare_lines(&sb);
- bottom = top = 0;
- if (bottomtop)
- prepare_blame_range(&sb, bottomtop, lno, &bottom, &top);
- if (bottom < 1)
- bottom = 1;
- if (top < 1)
- top = lno;
- bottom--;
- if (lno < top || lno < bottom)
- die("file %s has only %lu lines", path, lno);
-
- ent = xcalloc(1, sizeof(*ent));
- ent->lno = bottom;
- ent->num_lines = top - bottom;
- ent->suspect = o;
- ent->s_lno = bottom;
+ if (lno && !range_list.nr)
+ string_list_append(&range_list, xstrdup("1"));
+
+ anchor = 1;
+ range_set_init(&ranges, range_list.nr);
+ for (range_i = 0; range_i < range_list.nr; ++range_i) {
+ long bottom, top;
+ if (parse_range_arg(range_list.items[range_i].string,
+ nth_line_cb, &sb, lno, anchor,
+ &bottom, &top, sb.path))
+ usage(blame_usage);
+ if (lno < top || ((lno || bottom) && lno < bottom))
+ die("file %s has only %lu lines", path, lno);
+ if (bottom < 1)
+ bottom = 1;
+ if (top < 1)
+ top = lno;
+ bottom--;
+ range_set_append_unsafe(&ranges, bottom, top);
+ anchor = top + 1;
+ }
+ sort_and_merge_range_set(&ranges);
+
+ for (range_i = ranges.nr; range_i > 0; --range_i) {
+ const struct range *r = &ranges.ranges[range_i - 1];
+ long bottom = r->start;
+ long top = r->end;
+ struct blame_entry *next = ent;
+ ent = xcalloc(1, sizeof(*ent));
+ ent->lno = bottom;
+ ent->num_lines = top - bottom;
+ ent->suspect = o;
+ ent->s_lno = bottom;
+ ent->next = next;
+ if (next)
+ next->prev = ent;
+ origin_incref(o);
+ }
+ origin_decref(o);
+
+ range_set_release(&ranges);
+ string_list_clear(&range_list, 0);
sb.ent = ent;
sb.path = path;
char *ref = NULL;
struct branch *branch = branch_get(branch_name);
struct strbuf fancy = STRBUF_INIT;
+ int upstream_is_gone = 0;
- if (!stat_tracking_info(branch, &ours, &theirs)) {
- if (branch && branch->merge && branch->merge[0]->dst &&
- show_upstream_ref) {
- ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
- if (want_color(branch_use_color))
- strbuf_addf(stat, "[%s%s%s] ",
- branch_get_color(BRANCH_COLOR_UPSTREAM),
- ref, branch_get_color(BRANCH_COLOR_RESET));
- else
- strbuf_addf(stat, "[%s] ", ref);
- }
+ switch (stat_tracking_info(branch, &ours, &theirs)) {
+ case 0:
+ /* no base */
return;
+ case -1:
+ /* with "gone" base */
+ upstream_is_gone = 1;
+ break;
+ default:
+ /* with base */
+ break;
}
if (show_upstream_ref) {
strbuf_addstr(&fancy, ref);
}
- if (!ours) {
- if (ref)
+ if (upstream_is_gone) {
+ if (show_upstream_ref)
+ strbuf_addf(stat, _("[%s: gone]"), fancy.buf);
+ } else if (!ours && !theirs) {
+ if (show_upstream_ref)
+ strbuf_addf(stat, _("[%s]"), fancy.buf);
+ } else if (!ours) {
+ if (show_upstream_ref)
strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
else
strbuf_addf(stat, _("[behind %d]"), theirs);
} else if (!theirs) {
- if (ref)
+ if (show_upstream_ref)
strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
else
strbuf_addf(stat, _("[ahead %d]"), ours);
} else {
- if (ref)
+ if (show_upstream_ref)
strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
fancy.buf, ours, theirs);
else
OPT_SET_INT( 0, "set-upstream", &track, N_("change upstream info"),
BRANCH_TRACK_OVERRIDE),
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_BOOL(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),
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,
- N_("edit the description for the branch")),
+ OPT_BOOL(0, "list", &list, N_("list branch names")),
+ OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")),
+ OPT_BOOL(0, "edit-description", &edit_description,
+ 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,
if (with_commit || merge_filter != NO_FILTER)
list = 1;
- if (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1)
+ if (!!delete + !!rename + !!force_create + !!new_upstream +
+ list + unset_upstream > 1)
usage_with_options(builtin_branch_usage, options);
if (abbrev == -1)
case 'e':
return !has_sha1_file(sha1);
+ case 'c':
+ if (!obj_context.path[0])
+ die("git cat-file --textconv %s: <object> must be <sha1:path>",
+ obj_name);
+
+ if (textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))
+ break;
+
case 'p':
type = sha1_object_info(sha1, NULL);
if (type < 0)
/* otherwise just spit out the data */
break;
- case 'c':
- if (!obj_context.path[0])
- die("git cat-file --textconv %s: <object> must be <sha1:path>",
- obj_name);
-
- if (!textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))
- die("git cat-file --textconv: unable to run textconv on %s",
- obj_name);
- break;
-
case 0:
if (type_from_string(exp_type) == OBJ_BLOB) {
unsigned char blob_sha1[20];
enum object_type type;
unsigned long size;
unsigned long disk_size;
+ const char *rest;
/*
* If mark_query is true, we do not expand anything, but rather
*/
int mark_query;
+ /*
+ * Whether to split the input on whitespace before feeding it to
+ * get_sha1; this is decided during the mark_query phase based on
+ * whether we have a %(rest) token in our format.
+ */
+ int split_on_whitespace;
+
/*
* After a mark_query run, this object_info is set up to be
* passed to sha1_object_info_extended. It will point to the data
data->info.disk_sizep = &data->disk_size;
else
strbuf_addf(sb, "%lu", data->disk_size);
+ } else if (is_atom("rest", atom, len)) {
+ if (data->mark_query)
+ data->split_on_whitespace = 1;
+ else if (data->rest)
+ strbuf_addstr(sb, data->rest);
} else
die("unknown format element: %.*s", len, atom);
}
warn_on_object_refname_ambiguity = 0;
while (strbuf_getline(&buf, stdin, '\n') != EOF) {
- int error = batch_one_object(buf.buf, opt, &data);
+ int error;
+
+ if (data.split_on_whitespace) {
+ /*
+ * Split at first whitespace, tying off the beginning
+ * of the string and saving the remainder (or NULL) in
+ * data.rest.
+ */
+ char *p = strpbrk(buf.buf, " \t");
+ if (p) {
+ while (*p && strchr(" \t", *p))
+ *p++ = '\0';
+ }
+ data.rest = p;
+ }
+
+ error = batch_one_object(buf.buf, opt, &data);
if (error)
return error;
}
NULL
};
-static int null_term_line;
+static int nul_term_line;
static const struct option check_attr_options[] = {
- 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,
- N_("input paths are terminated by a null character")),
+ OPT_BOOL('a', "all", &all_attrs, N_("report all attributes set on file")),
+ OPT_BOOL(0, "cached", &cached_attrs, N_("use .gitattributes only from the index")),
+ OPT_BOOL(0 , "stdin", &stdin_paths, N_("read file names from stdin")),
+ OPT_BOOL('z', NULL, &nul_term_line,
+ N_("terminate input and output records by a NUL character")),
OPT_END()
};
else if (ATTR_UNSET(value))
value = "unspecified";
- quote_c_style(file, NULL, stdout, 0);
- printf(": %s: %s\n", git_attr_name(check[j].attr), value);
+ if (nul_term_line) {
+ printf("%s%c" /* path */
+ "%s%c" /* attrname */
+ "%s%c" /* attrvalue */,
+ file, 0, git_attr_name(check[j].attr), 0, value, 0);
+ } else {
+ quote_c_style(file, NULL, stdout, 0);
+ printf(": %s: %s\n", git_attr_name(check[j].attr), value);
+ }
+
}
}
struct git_attr_check *check)
{
struct strbuf buf, nbuf;
- int line_termination = null_term_line ? 0 : '\n';
+ int line_termination = nul_term_line ? 0 : '\n';
strbuf_init(&buf, 0);
strbuf_init(&nbuf, 0);
#include "pathspec.h"
#include "parse-options.h"
-static int quiet, verbose, stdin_paths, show_non_matching;
+static int quiet, verbose, stdin_paths, show_non_matching, no_index;
static const char * const check_ignore_usage[] = {
"git check-ignore [options] pathname...",
"git check-ignore [options] --stdin < <list-of-paths>",
NULL
};
-static int null_term_line;
+static int nul_term_line;
static const struct option check_ignore_options[] = {
OPT__QUIET(&quiet, N_("suppress progress reporting")),
OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_GROUP(""),
- OPT_BOOLEAN(0, "stdin", &stdin_paths,
- N_("read file names from stdin")),
- OPT_BOOLEAN('z', NULL, &null_term_line,
- N_("input paths are terminated by a null character")),
- OPT_BOOLEAN('n', "non-matching", &show_non_matching,
- N_("show non-matching input paths")),
+ OPT_BOOL(0, "stdin", &stdin_paths,
+ N_("read file names from stdin")),
+ OPT_BOOL('z', NULL, &nul_term_line,
+ N_("terminate input and output records by a NUL character")),
+ OPT_BOOL('n', "non-matching", &show_non_matching,
+ N_("show non-matching input paths")),
+ OPT_BOOL(0, "no-index", &no_index,
+ N_("ignore index when checking")),
OPT_END()
};
{
char *bang = (exclude && exclude->flags & EXC_FLAG_NEGATIVE) ? "!" : "";
char *slash = (exclude && exclude->flags & EXC_FLAG_MUSTBEDIR) ? "/" : "";
- if (!null_term_line) {
+ if (!nul_term_line) {
if (!verbose) {
write_name_quoted(path, stdout, '\n');
} else {
}
static int check_ignore(struct dir_struct *dir,
- const char *prefix, const char **pathspec)
+ const char *prefix, int argc, const char **argv)
{
- const char *path, *full_path;
+ const char *full_path;
char *seen;
int num_ignored = 0, dtype = DT_UNKNOWN, i;
struct exclude *exclude;
+ struct pathspec pathspec;
- if (!pathspec || !*pathspec) {
+ if (!argc) {
if (!quiet)
fprintf(stderr, "no pathspec given.\n");
return 0;
}
+ /*
+ * check-ignore just needs paths. Magic beyond :/ is really
+ * irrelevant.
+ */
+ parse_pathspec(&pathspec,
+ PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,
+ PATHSPEC_SYMLINK_LEADING_PATH |
+ PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE |
+ PATHSPEC_KEEP_ORDER,
+ prefix, argv);
+
/*
* look for pathspecs matching entries in the index, since these
* should not be ignored, in order to be consistent with
* 'git status', 'git add' etc.
*/
- seen = find_pathspecs_matching_against_index(pathspec);
- for (i = 0; pathspec[i]; i++) {
- path = pathspec[i];
- full_path = prefix_path(prefix, prefix
- ? strlen(prefix) : 0, path);
- full_path = check_path_for_gitlink(full_path);
- die_if_path_beyond_symlink(full_path, prefix);
+ seen = find_pathspecs_matching_against_index(&pathspec);
+ for (i = 0; i < pathspec.nr; i++) {
+ full_path = pathspec.items[i].match;
exclude = NULL;
if (!seen[i]) {
exclude = last_exclude_matching(dir, full_path, &dtype);
}
if (!quiet && (exclude || show_non_matching))
- output_exclude(path, exclude);
+ output_exclude(pathspec.items[i].original, exclude);
if (exclude)
num_ignored++;
}
{
struct strbuf buf, nbuf;
char *pathspec[2] = { NULL, NULL };
- int line_termination = null_term_line ? 0 : '\n';
+ int line_termination = nul_term_line ? 0 : '\n';
int num_ignored = 0;
strbuf_init(&buf, 0);
strbuf_swap(&buf, &nbuf);
}
pathspec[0] = buf.buf;
- num_ignored += check_ignore(dir, prefix, (const char **)pathspec);
+ num_ignored += check_ignore(dir, prefix,
+ 1, (const char **)pathspec);
maybe_flush_or_die(stdout, "check-ignore to stdout");
}
strbuf_release(&buf);
if (argc > 0)
die(_("cannot specify pathnames with --stdin"));
} else {
- if (null_term_line)
+ if (nul_term_line)
die(_("-z only makes sense with --stdin"));
if (argc == 0)
die(_("no path specified"));
die(_("--non-matching is only valid with --verbose"));
/* read_cache() is only necessary so we can watch out for submodules. */
- if (read_cache() < 0)
+ if (!no_index && read_cache() < 0)
die(_("index file corrupt"));
memset(&dir, 0, sizeof(dir));
if (stdin_paths) {
num_ignored = check_ignore_stdin_paths(&dir, prefix);
} else {
- num_ignored = check_ignore(&dir, prefix, argv);
+ num_ignored = check_ignore(&dir, prefix, argc, argv);
maybe_flush_or_die(stdout, "ignore to stdout");
}
static int line_termination = '\n';
static int checkout_stage; /* default to checkout stage0 */
static int to_tempfile;
-static char topath[4][PATH_MAX + 1];
+static char topath[4][TEMPORARY_FILENAME_LENGTH + 1];
static struct checkout state;
int prefix_length;
int force = 0, quiet = 0, not_new = 0;
struct option builtin_checkout_index_options[] = {
- OPT_BOOLEAN('a', "all", &all,
+ OPT_BOOL('a', "all", &all,
N_("check out all files in the index")),
OPT__FORCE(&force, N_("force overwrite of existing files")),
OPT__QUIET(&quiet,
N_("no warning for existing files and files not in index")),
- OPT_BOOLEAN('n', "no-create", ¬_new,
+ OPT_BOOL('n', "no-create", ¬_new,
N_("don't checkout new files")),
{ OPTION_CALLBACK, 'u', "index", &newfd, NULL,
N_("update stat information in the index file"),
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
N_("paths are separated with NUL character"),
PARSE_OPT_NOARG, option_parse_z },
- OPT_BOOLEAN(0, "stdin", &read_from_stdin,
+ OPT_BOOL(0, "stdin", &read_from_stdin,
N_("read list of paths from the standard input")),
- OPT_BOOLEAN(0, "temp", &to_tempfile,
+ OPT_BOOL(0, "temp", &to_tempfile,
N_("write the content to temporary files")),
OPT_CALLBACK(0, "prefix", NULL, N_("string"),
N_("when creating files, prepend <string>"),
int branch_exists;
const char *prefix;
- const char **pathspec;
+ struct pathspec pathspec;
struct tree *source_tree;
};
return 0;
}
-static int read_tree_some(struct tree *tree, const char **pathspec)
+static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
{
- struct pathspec ps;
- init_pathspec(&ps, pathspec);
- read_tree_recursive(tree, "", 0, 0, &ps, update_some, NULL);
- free_pathspec(&ps);
+ read_tree_recursive(tree, "", 0, 0, pathspec, update_some, NULL);
/* update the index with the given tree's info
* for all args, expanding wildcards, and exit
int flag;
struct commit *head;
int errs = 0;
- int stage = opts->writeout_stage;
- int merge = opts->merge;
int newfd;
struct lock_file *lock_file;
if (opts->patch_mode)
return run_add_interactive(revision, "--patch=checkout",
- opts->pathspec);
+ &opts->pathspec);
lock_file = xcalloc(1, sizeof(struct lock_file));
newfd = hold_locked_index(lock_file, 1);
- if (read_cache_preload(opts->pathspec) < 0)
+ if (read_cache_preload(&opts->pathspec) < 0)
return error(_("corrupt index file"));
if (opts->source_tree)
- read_tree_some(opts->source_tree, opts->pathspec);
+ read_tree_some(opts->source_tree, &opts->pathspec);
- for (pos = 0; opts->pathspec[pos]; pos++)
- ;
- ps_matched = xcalloc(1, pos);
+ ps_matched = xcalloc(1, opts->pathspec.nr);
/*
* Make sure all pathspecs participated in locating the paths
* match_pathspec() for _all_ entries when
* opts->source_tree != NULL.
*/
- if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce),
+ if (match_pathspec_depth(&opts->pathspec, ce->name, ce_namelen(ce),
0, ps_matched))
ce->ce_flags |= CE_MATCHED;
}
- if (report_path_error(ps_matched, opts->pathspec, opts->prefix)) {
+ if (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) {
free(ps_matched);
return 1;
}
continue;
if (opts->force) {
warning(_("path '%s' is unmerged"), ce->name);
- } else if (stage) {
- errs |= check_stage(stage, ce, pos);
+ } else if (opts->writeout_stage) {
+ errs |= check_stage(opts->writeout_stage, ce, pos);
} else if (opts->merge) {
errs |= check_stages((1<<2) | (1<<3), ce, pos);
} else {
errs |= checkout_entry(ce, &state, NULL);
continue;
}
- if (stage)
- errs |= checkout_stage(stage, ce, pos, &state);
- else if (merge)
+ if (opts->writeout_stage)
+ errs |= checkout_stage(opts->writeout_stage, ce, pos, &state);
+ else if (opts->merge)
errs |= checkout_merged(pos, &state);
pos = skip_same_name(ce, pos) - 1;
}
int argcount = 0;
unsigned char branch_rev[20];
const char *arg;
- int has_dash_dash;
+ int dash_dash_pos;
+ int has_dash_dash = 0;
+ int i;
/*
* case 1: git checkout <ref> -- [<paths>]
*
* everything after the '--' must be paths.
*
- * case 3: git checkout <something> [<paths>]
+ * case 3: git checkout <something> [--]
*
- * With no paths, if <something> is a commit, that is to
- * switch to the branch or detach HEAD at it. As a special case,
- * if <something> is A...B (missing A or B means HEAD but you can
- * omit at most one side), and if there is a unique merge base
- * between A and B, A...B names that merge base.
+ * (a) If <something> is a commit, that is to
+ * switch to the branch or detach HEAD at it. As a special case,
+ * if <something> is A...B (missing A or B means HEAD but you can
+ * omit at most one side), and if there is a unique merge base
+ * between A and B, A...B names that merge base.
*
- * With no paths, if <something> is _not_ a commit, no -t nor -b
- * was given, and there is a tracking branch whose name is
- * <something> in one and only one remote, then this is a short-hand
- * to fork local <something> from that remote-tracking branch.
+ * (b) If <something> is _not_ a commit, either "--" is present
+ * or <something> is not a path, no -t nor -b was given, and
+ * and there is a tracking branch whose name is <something>
+ * in one and only one remote, then this is a short-hand to
+ * fork local <something> from that remote-tracking branch.
*
- * Otherwise <something> shall not be ambiguous.
+ * (c) Otherwise, if "--" is present, treat it like case (1).
+ *
+ * (d) Otherwise :
+ * - if it's a reference, treat it like case (1)
+ * - else if it's a path, treat it like case (2)
+ * - else: fail.
+ *
+ * case 4: git checkout <something> <paths>
+ *
+ * The first argument must not be ambiguous.
* - If it's *only* a reference, treat it like case (1).
* - If it's only a path, treat it like case (2).
* - else: fail.
if (!argc)
return 0;
- if (!strcmp(argv[0], "--")) /* case (2) */
- return 1;
-
arg = argv[0];
- has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
+ dash_dash_pos = -1;
+ for (i = 0; i < argc; i++) {
+ if (!strcmp(argv[i], "--")) {
+ dash_dash_pos = i;
+ break;
+ }
+ }
+ if (dash_dash_pos == 0)
+ return 1; /* case (2) */
+ else if (dash_dash_pos == 1)
+ has_dash_dash = 1; /* case (3) or (1) */
+ else if (dash_dash_pos >= 2)
+ die(_("only one reference expected, %d given."), dash_dash_pos);
if (!strcmp(arg, "-"))
arg = "@{-1}";
if (get_sha1_mb(arg, rev)) {
- if (has_dash_dash) /* case (1) */
- die(_("invalid reference: %s"), arg);
- if (dwim_new_local_branch_ok &&
- !check_filename(NULL, arg) &&
- argc == 1) {
+ /*
+ * Either case (3) or (4), with <something> not being
+ * a commit, or an attempt to use case (1) with an
+ * invalid ref.
+ *
+ * It's likely an error, but we need to find out if
+ * we should auto-create the branch, case (3).(b).
+ */
+ int recover_with_dwim = dwim_new_local_branch_ok;
+
+ if (check_filename(NULL, arg) && !has_dash_dash)
+ recover_with_dwim = 0;
+ /*
+ * Accept "git checkout foo" and "git checkout foo --"
+ * as candidates for dwim.
+ */
+ if (!(argc == 1 && !has_dash_dash) &&
+ !(argc == 2 && has_dash_dash))
+ recover_with_dwim = 0;
+
+ if (recover_with_dwim) {
const char *remote = unique_tracking_name(arg, rev);
- if (!remote)
- return argcount;
- *new_branch = arg;
- arg = remote;
- /* DWIMmed to create local branch */
- } else {
+ if (remote) {
+ *new_branch = arg;
+ arg = remote;
+ /* DWIMmed to create local branch, case (3).(b) */
+ } else {
+ recover_with_dwim = 0;
+ }
+ }
+
+ if (!recover_with_dwim) {
+ if (has_dash_dash)
+ die(_("invalid reference: %s"), arg);
return argcount;
}
}
if (!*source_tree) /* case (1): want a tree */
die(_("reference is not a tree: %s"), arg);
- if (!has_dash_dash) {/* case (3 -> 1) */
+ if (!has_dash_dash) {/* case (3).(d) -> (1) */
/*
* Do not complain the most common case
* git checkout branch
static int checkout_branch(struct checkout_opts *opts,
struct branch_info *new)
{
- if (opts->pathspec)
+ if (opts->pathspec.nr)
die(_("paths cannot be used with switching branches"));
if (opts->patch_mode)
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_BOOL('l', NULL, &opts.new_branch_log, N_("create reflog for new branch")),
+ OPT_BOOL(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, N_("new branch"), N_("new unparented branch")),
OPT_SET_INT('3', "theirs", &opts.writeout_stage, N_("checkout their version for unmerged files"),
3),
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_BOOL('m', "merge", &opts.merge, N_("perform a 3-way merge with the new branch")),
+ OPT_BOOL(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")),
+ OPT_BOOL('p', "patch", &opts.patch_mode, N_("select hunks interactively")),
OPT_BOOL(0, "ignore-skip-worktree-bits", &opts.ignore_skipworktree,
N_("do not limit pathspecs to sparse entries only")),
- { OPTION_BOOLEAN, 0, "guess", &dwim_new_local_branch, NULL,
- N_("second guess 'git checkout no-such-branch'"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+ OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
+ N_("second guess 'git checkout no-such-branch'")),
OPT_END(),
};
}
if (argc) {
- opts.pathspec = get_pathspec(prefix, argv);
+ parse_pathspec(&opts.pathspec, 0,
+ opts.patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,
+ prefix, argv);
- if (!opts.pathspec)
+ if (!opts.pathspec.nr)
die(_("invalid path specification"));
/*
strbuf_release(&buf);
}
- if (opts.patch_mode || opts.pathspec)
+ if (opts.patch_mode || opts.pathspec.nr)
return checkout_paths(&opts, new.name);
else
return checkout_branch(&opts, &new);
#include "quote.h"
#include "column.h"
#include "color.h"
+#include "pathspec.h"
static int force = -1; /* unset */
static int interactive;
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
struct strbuf abs_path = STRBUF_INIT;
struct dir_struct dir;
- static const char **pathspec;
+ struct pathspec pathspec;
struct strbuf buf = STRBUF_INIT;
struct string_list exclude_list = STRING_LIST_INIT_NODUP;
struct exclude_list *el;
struct string_list_item *item;
const char *qname;
- char *seen = NULL;
struct option options[] = {
OPT__QUIET(&quiet, N_("do not print names of files removed")),
OPT__DRY_RUN(&dry_run, N_("dry run")),
OPT__FORCE(&force, N_("force")),
OPT_BOOL('i', "interactive", &interactive, N_("interactive cleaning")),
- OPT_BOOLEAN('d', NULL, &remove_directories,
+ OPT_BOOL('d', NULL, &remove_directories,
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,
+ OPT_BOOL('x', NULL, &ignored, N_("remove ignored files, too")),
+ OPT_BOOL('X', NULL, &ignored_only,
N_("remove only ignored files")),
OPT_END()
};
for (i = 0; i < exclude_list.nr; i++)
add_exclude(exclude_list.items[i].string, "", 0, el, -(i+1));
- pathspec = get_pathspec(prefix, argv);
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_CWD,
+ prefix, argv);
- fill_directory(&dir, pathspec);
-
- if (pathspec)
- seen = xmalloc(argc > 0 ? argc : 1);
+ fill_directory(&dir, &pathspec);
for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
if (lstat(ent->name, &st))
die_errno("Cannot lstat '%s'", ent->name);
- if (pathspec) {
- memset(seen, 0, argc > 0 ? argc : 1);
- matches = match_pathspec(pathspec, ent->name, len,
- 0, seen);
- }
+ if (pathspec.nr)
+ matches = match_pathspec_depth(&pathspec, ent->name,
+ len, 0, NULL);
if (S_ISDIR(st.st_mode)) {
if (remove_directories || (matches == MATCHED_EXACTLY)) {
string_list_append(&del_list, rel);
}
} else {
- if (pathspec && !matches)
+ if (pathspec.nr && !matches)
continue;
rel = relative_path(ent->name, prefix, &buf);
string_list_append(&del_list, rel);
}
strbuf_reset(&abs_path);
}
- free(seen);
strbuf_release(&abs_path);
strbuf_release(&buf);
OPT__VERBOSITY(&option_verbosity),
OPT_BOOL(0, "progress", &option_progress,
N_("force progress reporting")),
- OPT_BOOLEAN('n', "no-checkout", &option_no_checkout,
- N_("don't create a checkout")),
- OPT_BOOLEAN(0, "bare", &option_bare, N_("create a bare repository")),
- { OPTION_BOOLEAN, 0, "naked", &option_bare, NULL,
- N_("create a bare repository"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
- OPT_BOOLEAN(0, "mirror", &option_mirror,
- N_("create a mirror repository (implies bare)")),
+ OPT_BOOL('n', "no-checkout", &option_no_checkout,
+ N_("don't create a checkout")),
+ OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
+ OPT_HIDDEN_BOOL(0, "naked", &option_bare,
+ N_("create a bare repository")),
+ OPT_BOOL(0, "mirror", &option_mirror,
+ 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,
+ OPT_BOOL(0, "no-hardlinks", &option_no_hardlinks,
N_("don't use local hardlinks, always copy")),
- OPT_BOOLEAN('s', "shared", &option_shared,
+ OPT_BOOL('s', "shared", &option_shared,
N_("setup as shared repository")),
- OPT_BOOLEAN(0, "recursive", &option_recursive,
+ OPT_BOOL(0, "recursive", &option_recursive,
N_("initialize submodules in the clone")),
- OPT_BOOLEAN(0, "recurse-submodules", &option_recursive,
+ OPT_BOOL(0, "recurse-submodules", &option_recursive,
N_("initialize submodules in the clone")),
OPT_STRING(0, "template", &option_template, N_("template-directory"),
N_("directory from which templates will be used")),
}
if (0 <= option_verbosity)
- printf(_("done.\n"));
+ fprintf(stderr, _("done.\n"));
}
static const char *junk_work_tree;
const struct ref *rm = mapped_refs;
if (check_connectivity) {
- if (0 <= option_verbosity)
- printf(_("Checking connectivity... "));
+ if (transport->progress)
+ fprintf(stderr, _("Checking connectivity... "));
if (check_everything_connected_with_transport(iterate_ref_map,
0, &rm, transport))
die(_("remote did not send all necessary objects"));
- if (0 <= option_verbosity)
- printf(_("done\n"));
+ if (transport->progress)
+ fprintf(stderr, _("done.\n"));
}
if (refs) {
if (0 <= option_verbosity) {
if (option_bare)
- printf(_("Cloning into bare repository '%s'...\n"), dir);
+ fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir);
else
- printf(_("Cloning into '%s'...\n"), dir);
+ fprintf(stderr, _("Cloning into '%s'...\n"), dir);
}
init_db(option_template, INIT_DB_QUIET);
write_config(&option_config);
remote = remote_get(option_origin);
transport = transport_get(remote, remote->url[0]);
- if (!is_local) {
- if (!transport->get_refs_list || !transport->fetch)
- die(_("Don't know how to clone %s"), transport->url);
+ if (!transport->get_refs_list || (!is_local && !transport->fetch))
+ die(_("Don't know how to clone %s"), transport->url);
- transport_set_option(transport, TRANS_OPT_KEEP, "yes");
+ transport_set_option(transport, TRANS_OPT_KEEP, "yes");
- if (option_depth)
- transport_set_option(transport, TRANS_OPT_DEPTH,
- option_depth);
- if (option_single_branch)
- transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
+ if (option_depth)
+ transport_set_option(transport, TRANS_OPT_DEPTH,
+ option_depth);
+ if (option_single_branch)
+ transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
- transport_set_verbosity(transport, option_verbosity, option_progress);
+ transport_set_verbosity(transport, option_verbosity, option_progress);
- if (option_upload_pack)
- transport_set_option(transport, TRANS_OPT_UPLOADPACK,
- option_upload_pack);
+ if (option_upload_pack)
+ transport_set_option(transport, TRANS_OPT_UPLOADPACK,
+ option_upload_pack);
- if (transport->smart_options && !option_depth)
- transport->smart_options->check_self_contained_and_connected = 1;
- }
+ if (transport->smart_options && !option_depth)
+ transport->smart_options->check_self_contained_and_connected = 1;
refs = transport_get_remote_refs(transport);
our_head_points_at = remote_head_points_at;
}
else {
+ if (option_branch)
+ die(_("Remote branch %s not found in upstream %s"),
+ option_branch, option_origin);
+
warning(_("You appear to have cloned an empty repository."));
mapped_refs = NULL;
our_head_points_at = NULL;
#include "column.h"
#include "sequencer.h"
#include "notes-utils.h"
+#include "mailmap.h"
static const char * const builtin_commit_usage[] = {
N_("git commit [options] [--] <pathspec>..."),
s->whence = whence;
}
+static void status_init_config(struct wt_status *s, config_fn_t fn)
+{
+ wt_status_prepare(s);
+ gitmodules_config();
+ git_config(fn, s);
+ determine_whence(s);
+ s->hints = advice_status_hints; /* must come after git_config() */
+}
+
static void rollback_index_files(void)
{
switch (commit_style) {
* and return the paths that match the given pattern in list.
*/
static int list_paths(struct string_list *list, const char *with_tree,
- const char *prefix, const char **pattern)
+ const char *prefix, const struct pathspec *pattern)
{
int i;
char *m;
- if (!pattern)
+ if (!pattern->nr)
return 0;
- for (i = 0; pattern[i]; i++)
- ;
- m = xcalloc(1, i);
+ m = xcalloc(1, pattern->nr);
if (with_tree) {
char *max_prefix = common_prefix(pattern);
if (ce->ce_flags & CE_UPDATE)
continue;
- if (!match_pathspec(pattern, ce->name, ce_namelen(ce), 0, m))
+ if (!match_pathspec_depth(pattern, ce->name, ce_namelen(ce), 0, m))
continue;
item = string_list_insert(list, ce->name);
if (ce_skip_worktree(ce))
{
int fd;
struct string_list partial;
- const char **pathspec = NULL;
+ struct pathspec pathspec;
char *old_index_env = NULL;
int refresh_flags = REFRESH_QUIET;
if (is_status)
refresh_flags |= REFRESH_UNMERGED;
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_FULL,
+ prefix, argv);
- if (*argv)
- pathspec = get_pathspec(prefix, argv);
-
- if (read_cache_preload(pathspec) < 0)
+ if (read_cache_preload(&pathspec) < 0)
die(_("index file corrupt"));
if (interactive) {
* (A) if all goes well, commit the real index;
* (B) on failure, rollback the real index.
*/
- if (all || (also && pathspec && *pathspec)) {
+ if (all || (also && pathspec.nr)) {
fd = hold_locked_index(&index_lock, 1);
- add_files_to_cache(also ? prefix : NULL, pathspec, 0);
+ add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
refresh_cache_or_die(refresh_flags);
update_main_cache_tree(WRITE_TREE_SILENT);
if (write_cache(fd, active_cache, active_nr) ||
* and create commit from the_index.
* We still need to refresh the index here.
*/
- if (!only && (!pathspec || !*pathspec)) {
+ if (!only && !pathspec.nr) {
fd = hold_locked_index(&index_lock, 1);
refresh_cache_or_die(refresh_flags);
if (active_cache_changed) {
memset(&partial, 0, sizeof(partial));
partial.strdup_strings = 1;
- if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, pathspec))
+ if (list_paths(&partial, !current_head ? NULL : "HEAD", prefix, &pathspec))
exit(1);
discard_cache();
const char *hook_arg2 = NULL;
int ident_shown = 0;
int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
+ int old_display_comment_prefix;
/* This checks and barfs if author is badly specified */
determine_author_info(author_ident);
if (s->fp == NULL)
die_errno(_("could not open '%s'"), git_path(commit_editmsg));
+ /* Ignore status.displayCommentPrefix: we do need comments in COMMIT_EDITMSG. */
+ old_display_comment_prefix = s->display_comment_prefix;
+ s->display_comment_prefix = 1;
+
+ /*
+ * Most hints are counter-productive when the commit has
+ * already started.
+ */
+ s->hints = 0;
+
if (clean_message_contents)
stripspace(&sb, 0);
*/
if (!commitable && whence != FROM_MERGE && !allow_empty &&
!(amend && is_a_merge(current_head))) {
+ s->display_comment_prefix = old_display_comment_prefix;
run_status(stdout, index_file, prefix, 0, s);
if (amend)
fputs(_(empty_amend_advice), stderr);
struct rev_info revs;
struct commit *commit;
struct strbuf buf = STRBUF_INIT;
+ struct string_list mailmap = STRING_LIST_INIT_NODUP;
const char *av[20];
int ac = 0;
av[++ac] = buf.buf;
av[++ac] = NULL;
setup_revisions(ac, av, &revs, NULL);
+ revs.mailmap = &mailmap;
+ read_mailmap(revs.mailmap, NULL);
+
prepare_revision_walk(&revs);
commit = get_revision(&revs);
if (commit) {
struct pretty_print_context ctx = {0};
ctx.date_mode = DATE_NORMAL;
strbuf_release(&buf);
- format_commit_message(commit, "%an <%ae>", &buf, &ctx);
+ format_commit_message(commit, "%aN <%aE>", &buf, &ctx);
+ clear_mailmap(&mailmap);
return strbuf_detach(&buf, NULL);
}
die(_("No existing author found with '%s'"), name);
if (patch_interactive)
interactive = 1;
- if (!!also + !!only + !!all + !!interactive > 1)
+ if (also + only + all + interactive > 1)
die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
if (argc == 0 && (also || (only && !amend)))
die(_("No paths with --include/--only does not make sense."));
s->use_color = git_config_colorbool(k, v);
return 0;
}
+ if (!strcmp(k, "status.displaycommentprefix")) {
+ s->display_comment_prefix = git_config_bool(k, v);
+ return 0;
+ }
if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
int slot = parse_status_slot(k, 13);
if (slot < 0)
OPT_SET_INT(0, "long", &status_format,
N_("show status in long format (default)"),
STATUS_FORMAT_LONG),
- OPT_BOOLEAN('z', "null", &s.null_termination,
- N_("terminate entries with NUL")),
+ OPT_BOOL('z', "null", &s.null_termination,
+ N_("terminate entries with NUL")),
{ 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" },
- OPT_BOOLEAN(0, "ignored", &show_ignored_in_status,
- N_("show ignored files")),
+ OPT_BOOL(0, "ignored", &show_ignored_in_status,
+ 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" },
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_status_usage, builtin_status_options);
- wt_status_prepare(&s);
- gitmodules_config();
- git_config(git_status_config, &s);
- determine_whence(&s);
+ status_init_config(&s, git_status_config);
argc = parse_options(argc, argv, prefix,
builtin_status_options,
builtin_status_usage, 0);
handle_untracked_files_arg(&s);
if (show_ignored_in_status)
s.show_ignored_files = 1;
- if (*argv)
- s.pathspec = get_pathspec(prefix, argv);
+ parse_pathspec(&s.pathspec, 0,
+ PATHSPEC_PREFER_FULL,
+ prefix, argv);
- read_cache_preload(s.pathspec);
- refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL);
+ read_cache_preload(&s.pathspec);
+ refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL);
fd = hold_locked_index(&index_lock, 0);
if (0 <= fd)
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_BOOL(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
+ OPT_BOOL('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")),
+ OPT_BOOL(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(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_BOOL('a', "all", &all, N_("commit all changed files")),
+ OPT_BOOL('i', "include", &also, N_("add specified files to index for commit")),
+ OPT_BOOL(0, "interactive", &interactive, N_("interactively add files")),
+ OPT_BOOL('p', "patch", &patch_interactive, N_("interactively add changes")),
+ OPT_BOOL('o', "only", &only, N_("commit only specified files")),
+ OPT_BOOL('n', "no-verify", &no_verify, N_("bypass pre-commit hook")),
+ OPT_BOOL(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_BOOL(0, "branch", &s.show_branch, N_("show branch information")),
OPT_SET_INT(0, "long", &status_format,
N_("show status in long format (default)"),
STATUS_FORMAT_LONG),
- OPT_BOOLEAN('z', "null", &s.null_termination,
- 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")),
+ OPT_BOOL('z', "null", &s.null_termination,
+ N_("terminate entries with NUL")),
+ OPT_BOOL(0, "amend", &amend, N_("amend previous commit")),
+ OPT_BOOL(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,
- N_("ok to record an empty change"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
- { OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL,
- N_("ok to record a change with an empty message"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+ OPT_HIDDEN_BOOL(0, "allow-empty", &allow_empty,
+ N_("ok to record an empty change")),
+ OPT_HIDDEN_BOOL(0, "allow-empty-message", &allow_empty_message,
+ N_("ok to record a change with an empty message")),
OPT_END()
};
if (argc == 2 && !strcmp(argv[1], "-h"))
usage_with_options(builtin_commit_usage, builtin_commit_options);
- wt_status_prepare(&s);
- gitmodules_config();
- git_config(git_commit_config, &s);
+ status_init_config(&s, git_commit_config);
status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
- determine_whence(&s);
s.colopts = 0;
if (get_sha1("HEAD", sha1))
!current_head
? NULL
: current_head->object.sha1,
- 0);
+ 0, NULL);
nl = strchr(sb.buf, '\n');
if (nl)
#include "cache.h"
#include "color.h"
#include "parse-options.h"
+#include "urlmatch.h"
static const char *const builtin_config_usage[] = {
N_("git config [options]"),
#define ACTION_SET_ALL (1<<12)
#define ACTION_GET_COLOR (1<<13)
#define ACTION_GET_COLORBOOL (1<<14)
+#define ACTION_GET_URLMATCH (1<<15)
#define TYPE_BOOL (1<<0)
#define TYPE_INT (1<<1)
static struct option builtin_config_options[] = {
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_BOOL(0, "global", &use_global_config, N_("use global config file")),
+ OPT_BOOL(0, "system", &use_system_config, N_("use system config file")),
+ OPT_BOOL(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_STRING(0, "blob", &given_config_blob, N_("blob-id"), N_("read config from given blob object")),
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, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH),
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, "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('z', "null", &end_null, N_("terminate values with NUL byte")),
OPT_BOOL(0, "includes", &respect_includes, N_("respect include directives on lookup")),
OPT_END(),
};
int alloc;
};
-static int collect_config(const char *key_, const char *value_, void *cb)
+static int format_config(struct strbuf *buf, const char *key_, const char *value_)
{
- struct strbuf_list *values = cb;
- struct strbuf *buf;
- char value[256];
- const char *vptr = value;
int must_free_vptr = 0;
int must_print_delim = 0;
+ char value[256];
+ const char *vptr = value;
- if (!use_key_regexp && strcmp(key_, key))
- return 0;
- if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
- return 0;
- if (regexp != NULL &&
- (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) {
must_print_delim = 1;
}
if (types == TYPE_INT)
- sprintf(value, "%d", git_config_int(key_, value_?value_:""));
+ sprintf(value, "%"PRId64,
+ git_config_int64(key_, value_ ? value_ : ""));
else if (types == TYPE_BOOL)
vptr = git_config_bool(key_, value_) ? "true" : "false";
else if (types == TYPE_BOOL_OR_INT) {
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
- * const.
- */
free((char *)vptr);
-
return 0;
}
+static int collect_config(const char *key_, const char *value_, void *cb)
+{
+ struct strbuf_list *values = cb;
+
+ if (!use_key_regexp && strcmp(key_, key))
+ return 0;
+ if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
+ return 0;
+ if (regexp != NULL &&
+ (do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
+ return 0;
+
+ ALLOC_GROW(values->items, values->nr + 1, values->alloc);
+
+ return format_config(&values->items[values->nr++], key_, value_);
+}
+
static int get_value(const char *key_, const char *regex_)
{
int ret = CONFIG_GENERIC_ERROR;
else {
normalized = xmalloc(64);
if (types == TYPE_INT) {
- int v = git_config_int(key, value);
- sprintf(normalized, "%d", v);
+ int64_t v = git_config_int64(key, value);
+ sprintf(normalized, "%"PRId64, v);
}
else if (types == TYPE_BOOL)
sprintf(normalized, "%s",
die("writing config blobs is not supported");
}
+struct urlmatch_current_candidate_value {
+ char value_is_null;
+ struct strbuf value;
+};
+
+static int urlmatch_collect_fn(const char *var, const char *value, void *cb)
+{
+ struct string_list *values = cb;
+ struct string_list_item *item = string_list_insert(values, var);
+ struct urlmatch_current_candidate_value *matched = item->util;
+
+ if (!matched) {
+ matched = xmalloc(sizeof(*matched));
+ strbuf_init(&matched->value, 0);
+ item->util = matched;
+ } else {
+ strbuf_reset(&matched->value);
+ }
+
+ if (value) {
+ strbuf_addstr(&matched->value, value);
+ matched->value_is_null = 0;
+ } else {
+ matched->value_is_null = 1;
+ }
+ return 0;
+}
+
+static char *dup_downcase(const char *string)
+{
+ char *result;
+ size_t len, i;
+
+ len = strlen(string);
+ result = xmalloc(len + 1);
+ for (i = 0; i < len; i++)
+ result[i] = tolower(string[i]);
+ result[i] = '\0';
+ return result;
+}
+
+static int get_urlmatch(const char *var, const char *url)
+{
+ char *section_tail;
+ struct string_list_item *item;
+ struct urlmatch_config config = { STRING_LIST_INIT_DUP };
+ struct string_list values = STRING_LIST_INIT_DUP;
+
+ config.collect_fn = urlmatch_collect_fn;
+ config.cascade_fn = NULL;
+ config.cb = &values;
+
+ if (!url_normalize(url, &config.url))
+ die("%s", config.url.err);
+
+ config.section = dup_downcase(var);
+ section_tail = strchr(config.section, '.');
+ if (section_tail) {
+ *section_tail = '\0';
+ config.key = section_tail + 1;
+ show_keys = 0;
+ } else {
+ config.key = NULL;
+ show_keys = 1;
+ }
+
+ git_config_with_options(urlmatch_config_entry, &config,
+ given_config_file, NULL, respect_includes);
+
+ for_each_string_list_item(item, &values) {
+ struct urlmatch_current_candidate_value *matched = item->util;
+ struct strbuf key = STRBUF_INIT;
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addstr(&key, item->string);
+ format_config(&buf, key.buf,
+ matched->value_is_null ? NULL : matched->value.buf);
+ fwrite(buf.buf, 1, buf.len, stdout);
+ strbuf_release(&key);
+ strbuf_release(&buf);
+
+ strbuf_release(&matched->value);
+ }
+ string_list_clear(&config.vars, 1);
+ string_list_clear(&values, 1);
+ free(config.url.url);
+
+ free((void *)config.section);
+ return 0;
+}
+
int cmd_config(int argc, const char **argv, const char *prefix)
{
int nongit = !startup_info->have_repository;
check_argc(argc, 1, 2);
return get_value(argv[0], argv[1]);
}
+ else if (actions == ACTION_GET_URLMATCH) {
+ check_argc(argc, 2, 2);
+ return get_urlmatch(argv[0], argv[1]);
+ }
else if (actions == ACTION_UNSET) {
check_blob_write();
check_argc(argc, 1, 2);
#define MAX_TAGS (FLAG_BITS - 1)
static const char * const describe_usage[] = {
- N_("git describe [options] <committish>*"),
+ N_("git describe [options] <commit-ish>*"),
N_("git describe [options] --dirty"),
NULL
};
{
int contains = 0;
struct option options[] = {
- 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")),
- OPT_BOOLEAN(0, "tags", &tags, N_("use any tag, even unannotated")),
- OPT_BOOLEAN(0, "long", &longformat, N_("always use long format")),
- OPT_BOOLEAN(0, "first-parent", &first_parent, N_("only follow first parent")),
+ OPT_BOOL(0, "contains", &contains, N_("find the tag that comes after the commit")),
+ OPT_BOOL(0, "debug", &debug, N_("debug search strategy on stderr")),
+ OPT_BOOL(0, "all", &all, N_("use any ref")),
+ OPT_BOOL(0, "tags", &tags, N_("use any tag, even unannotated")),
+ OPT_BOOL(0, "long", &longformat, N_("always use long format")),
+ OPT_BOOL(0, "first-parent", &first_parent, N_("only follow first parent")),
OPT__ABBREV(&abbrev),
OPT_SET_INT(0, "exact-match", &max_candidates,
N_("only output exact matches"), 0),
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,
- N_("show abbreviated commit object as fallback")),
+ OPT_BOOL(0, "always", &always,
+ 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"},
+ N_("append <mark> on dirty working tree (default: \"-dirty\")"),
+ PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
OPT_END(),
};
}
describe("HEAD", 1);
} else if (dirty) {
- die(_("--dirty is incompatible with committishes"));
+ die(_("--dirty is incompatible with commit-ishes"));
} else {
while (argc-- > 0) {
describe(*argv++, argc == 0);
(rev.diffopt.output_format & DIFF_FORMAT_PATCH))
rev.combine_merges = rev.dense_combined_merges = 1;
- if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) {
+ if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
perror("read_cache_preload");
return -1;
}
usage(diff_cache_usage);
if (!cached) {
setup_work_tree();
- if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) {
+ if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
perror("read_cache_preload");
return -1;
}
usage(builtin_diff_usage);
if (!cached) {
setup_work_tree();
- if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
+ if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
perror("read_cache_preload");
return -1;
}
revs->combine_merges = revs->dense_combined_merges = 1;
setup_work_tree();
- if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
+ if (read_cache_preload(&revs->diffopt.pathspec) < 0) {
perror("read_cache_preload");
return -1;
}
}
}
if (rev.prune_data.nr) {
+ /* builtin_diff_b_f() */
+ GUARD_PATHSPEC(&rev.prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
if (!path)
path = rev.prune_data.items[0].match;
paths += rev.prune_data.nr;
static int use_done_feature;
static int no_data;
static int full_tree;
+static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
static int parse_opt_signed_tag_mode(const struct option *opt,
const char *arg, int unset)
(int)message_size, (int)message_size, message ? message : "");
}
-static void get_tags_and_duplicates(struct rev_cmdline_info *info,
- struct string_list *extra_refs)
+static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
+{
+ switch (e->item->type) {
+ case OBJ_COMMIT:
+ return (struct commit *)e->item;
+ case OBJ_TAG: {
+ struct tag *tag = (struct tag *)e->item;
+
+ /* handle nested tags */
+ while (tag && tag->object.type == OBJ_TAG) {
+ parse_object(tag->object.sha1);
+ string_list_append(&extra_refs, full_name)->util = tag;
+ tag = (struct tag *)tag->tagged;
+ }
+ if (!tag)
+ die("Tag %s points nowhere?", e->name);
+ return (struct commit *)tag;
+ break;
+ }
+ default:
+ return NULL;
+ }
+}
+
+static void get_tags_and_duplicates(struct rev_cmdline_info *info)
{
- struct tag *tag;
int i;
for (i = 0; i < info->nr; i++) {
if (dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
continue;
- switch (e->item->type) {
- case OBJ_COMMIT:
- commit = (struct commit *)e->item;
- break;
- case OBJ_TAG:
- tag = (struct tag *)e->item;
-
- /* handle nested tags */
- while (tag && tag->object.type == OBJ_TAG) {
- parse_object(tag->object.sha1);
- string_list_append(extra_refs, full_name)->util = tag;
- tag = (struct tag *)tag->tagged;
- }
- if (!tag)
- die ("Tag %s points nowhere?", e->name);
- switch(tag->object.type) {
- case OBJ_COMMIT:
- commit = (struct commit *)tag;
- break;
- case OBJ_BLOB:
- export_blob(tag->object.sha1);
- continue;
- default: /* OBJ_TAG (nested tags) is already handled */
- warning("Tag points to object of unexpected type %s, skipping.",
- typename(tag->object.type));
- continue;
- }
- break;
- default:
+ commit = get_commit(e, full_name);
+ if (!commit) {
warning("%s: Unexpected object of type %s, skipping.",
e->name,
typename(e->item->type));
continue;
}
+ switch(commit->object.type) {
+ case OBJ_COMMIT:
+ break;
+ case OBJ_BLOB:
+ export_blob(commit->object.sha1);
+ continue;
+ default: /* OBJ_TAG (nested tags) is already handled */
+ warning("Tag points to object of unexpected type %s, skipping.",
+ typename(commit->object.type));
+ continue;
+ }
+
/*
* This ref will not be updated through a commit, lets make
* sure it gets properly updated eventually.
*/
if (commit->util || commit->object.flags & SHOWN)
- string_list_append(extra_refs, full_name)->util = commit;
+ string_list_append(&extra_refs, full_name)->util = commit;
if (!commit->util)
commit->util = full_name;
}
}
-static void handle_tags_and_duplicates(struct string_list *extra_refs)
+static void handle_tags_and_duplicates(void)
{
struct commit *commit;
int i;
- for (i = extra_refs->nr - 1; i >= 0; i--) {
- const char *name = extra_refs->items[i].string;
- struct object *object = extra_refs->items[i].util;
+ for (i = extra_refs.nr - 1; i >= 0; i--) {
+ const char *name = extra_refs.items[i].string;
+ struct object *object = extra_refs.items[i].util;
switch (object->type) {
case OBJ_TAG:
handle_tag(name, (struct tag *)object);
{
struct rev_info revs;
struct object_array commits = OBJECT_ARRAY_INIT;
- struct string_list extra_refs = STRING_LIST_INIT_NODUP;
struct commit *commit;
char *export_filename = NULL, *import_filename = NULL;
uint32_t lastimportid;
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,
- N_("Fake a tagger when tags lack one")),
- OPT_BOOLEAN(0, "full-tree", &full_tree,
- N_("Output full tree for each commit")),
- OPT_BOOLEAN(0, "use-done-feature", &use_done_feature,
+ OPT_BOOL(0, "fake-missing-tagger", &fake_missing_tagger,
+ N_("Fake a tagger when tags lack one")),
+ OPT_BOOL(0, "full-tree", &full_tree,
+ N_("Output full tree for each commit")),
+ OPT_BOOL(0, "use-done-feature", &use_done_feature,
N_("Use the done feature to terminate the stream")),
OPT_BOOL(0, "no-data", &no_data, N_("Skip output of blob data")),
OPT_END()
if (import_filename && revs.prune_data.nr)
full_tree = 1;
- get_tags_and_duplicates(&revs.cmdline, &extra_refs);
+ get_tags_and_duplicates(&revs.cmdline);
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
}
}
- handle_tags_and_duplicates(&extra_refs);
+ handle_tags_and_duplicates();
if (export_filename && lastimportid != last_idnum)
export_marks(export_filename);
#include "builtin.h"
#include "pkt-line.h"
#include "fetch-pack.h"
+#include "remote.h"
+#include "connect.h"
static const char fetch_pack_usage[] =
"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
pack_lockfile_ptr = &pack_lockfile;
continue;
}
+ if (!strcmp("--check-self-contained-and-connected", arg)) {
+ args.check_self_contained_and_connected = 1;
+ continue;
+ }
usage(fetch_pack_usage);
}
printf("lock %s\n", pack_lockfile);
fflush(stdout);
}
+ if (args.check_self_contained_and_connected &&
+ args.self_contained_and_connected) {
+ printf("connectivity-ok\n");
+ fflush(stdout);
+ }
close(fd[0]);
close(fd[1]);
if (finish_connect(conn))
TAGS_SET = 2
};
-static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity;
+static int fetch_prune_config = -1; /* unspecified */
+static int prune = -1; /* unspecified */
+#define PRUNE_BY_DEFAULT 0 /* do we prune by default? */
+
+static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity;
static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
static int tags = TAGS_DEFAULT, unshallow;
static const char *depth;
static const char *upload_pack;
static struct strbuf default_rla = STRBUF_INIT;
-static struct transport *transport;
+static struct transport *gtransport;
+static struct transport *gsecondary;
static const char *submodule_prefix = "";
static const char *recurse_submodules_default;
return 0;
}
+static int git_fetch_config(const char *k, const char *v, void *cb)
+{
+ if (!strcmp(k, "fetch.prune")) {
+ fetch_prune_config = git_config_bool(k, v);
+ return 0;
+ }
+ return 0;
+}
+
static struct option builtin_fetch_options[] = {
OPT__VERBOSITY(&verbosity),
- OPT_BOOLEAN(0, "all", &all,
- N_("fetch from all remotes")),
- OPT_BOOLEAN('a', "append", &append,
- N_("append to .git/FETCH_HEAD instead of overwriting")),
+ OPT_BOOL(0, "all", &all,
+ N_("fetch from all remotes")),
+ OPT_BOOL('a', "append", &append,
+ 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,
- N_("fetch from multiple remotes")),
+ OPT_BOOL('m', "multiple", &multiple,
+ N_("fetch from multiple remotes")),
OPT_SET_INT('t', "tags", &tags,
N_("fetch all tags and associated objects"), TAGS_SET),
OPT_SET_INT('n', NULL, &tags,
N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
- OPT_BOOLEAN('p', "prune", &prune,
- N_("prune remote-tracking branches no longer on remote")),
+ OPT_BOOL('p', "prune", &prune,
+ 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,
- N_("dry run")),
- OPT_BOOLEAN('k', "keep", &keep, N_("keep downloaded pack")),
- OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
+ OPT_BOOL(0, "dry-run", &dry_run,
+ N_("dry run")),
+ OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
+ OPT_BOOL('u', "update-head-ok", &update_head_ok,
N_("allow updating of HEAD ref")),
OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
OPT_STRING(0, "depth", &depth, N_("depth"),
static void unlock_pack(void)
{
- if (transport)
- transport_unlock_pack(transport);
+ if (gtransport)
+ transport_unlock_pack(gtransport);
+ if (gsecondary)
+ transport_unlock_pack(gsecondary);
}
static void unlock_pack_on_signal(int signo)
rla = default_rla.buf;
snprintf(msg, sizeof(msg), "%s: %s", rla, action);
lock = lock_any_ref_for_update(ref->name,
- check_old ? ref->old_sha1 : NULL, 0);
+ check_old ? ref->old_sha1 : NULL,
+ 0, NULL);
if (!lock)
return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
STORE_REF_ERROR_OTHER;
return 0;
}
+static void set_option(struct transport *transport, const char *name, const char *value)
+{
+ int r = transport_set_option(transport, name, value);
+ if (r < 0)
+ die(_("Option \"%s\" value \"%s\" is not valid for %s"),
+ name, value, transport->url);
+ if (r > 0)
+ warning(_("Option \"%s\" is ignored for %s\n"),
+ name, transport->url);
+}
+
+static struct transport *prepare_transport(struct remote *remote)
+{
+ struct transport *transport;
+ transport = transport_get(remote, NULL);
+ transport_set_verbosity(transport, verbosity, progress);
+ if (upload_pack)
+ set_option(transport, TRANS_OPT_UPLOADPACK, upload_pack);
+ if (keep)
+ set_option(transport, TRANS_OPT_KEEP, "yes");
+ if (depth)
+ set_option(transport, TRANS_OPT_DEPTH, depth);
+ return transport;
+}
+
+static void backfill_tags(struct transport *transport, struct ref *ref_map)
+{
+ if (transport->cannot_reuse) {
+ gsecondary = prepare_transport(transport->remote);
+ transport = gsecondary;
+ }
+
+ transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
+ transport_set_option(transport, TRANS_OPT_DEPTH, "0");
+ fetch_refs(transport, ref_map);
+
+ if (gsecondary) {
+ transport_disconnect(gsecondary);
+ gsecondary = NULL;
+ }
+}
+
static int do_fetch(struct transport *transport,
struct refspec *refs, int ref_count)
{
goto cleanup;
}
if (prune) {
- /* If --tags was specified, pretend the user gave us the canonical tags refspec */
+ /*
+ * If --tags was specified, pretend that the user gave us
+ * the canonical tags refspec
+ */
if (tags == TAGS_SET) {
const char *tags_str = "refs/tags/*:refs/tags/*";
struct refspec *tags_refspec, *refspec;
struct ref **tail = &ref_map;
ref_map = NULL;
find_non_local_tags(transport, &ref_map, &tail);
- if (ref_map) {
- transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
- transport_set_option(transport, TRANS_OPT_DEPTH, "0");
- fetch_refs(transport, ref_map);
- }
+ if (ref_map)
+ backfill_tags(transport, ref_map);
free_refs(ref_map);
}
return retcode;
}
-static void set_option(const char *name, const char *value)
-{
- int r = transport_set_option(transport, name, value);
- if (r < 0)
- die(_("Option \"%s\" value \"%s\" is not valid for %s"),
- name, value, transport->url);
- if (r > 0)
- warning(_("Option \"%s\" is ignored for %s\n"),
- name, transport->url);
-}
-
static int get_one_remote_for_fetch(struct remote *remote, void *priv)
{
struct string_list *list = priv;
{
if (dry_run)
argv_array_push(argv, "--dry-run");
- if (prune)
+ if (prune > 0)
argv_array_push(argv, "--prune");
if (update_head_ok)
argv_array_push(argv, "--update-head-ok");
die(_("No remote repository specified. Please, specify either a URL or a\n"
"remote name from which new revisions should be fetched."));
- transport = transport_get(remote, NULL);
- transport_set_verbosity(transport, verbosity, progress);
- if (upload_pack)
- set_option(TRANS_OPT_UPLOADPACK, upload_pack);
- if (keep)
- set_option(TRANS_OPT_KEEP, "yes");
- if (depth)
- set_option(TRANS_OPT_DEPTH, depth);
+ gtransport = prepare_transport(remote);
+
+ if (prune < 0) {
+ /* no command line request */
+ if (0 <= gtransport->remote->prune)
+ prune = gtransport->remote->prune;
+ else if (0 <= fetch_prune_config)
+ prune = fetch_prune_config;
+ else
+ prune = PRUNE_BY_DEFAULT;
+ }
if (argc > 0) {
int j = 0;
sigchain_push_common(unlock_pack_on_signal);
atexit(unlock_pack);
refspec = parse_fetch_refspec(ref_nr, refs);
- exit_code = do_fetch(transport, refspec, ref_nr);
+ exit_code = do_fetch(gtransport, refspec, ref_nr);
free_refspec(ref_nr, refspec);
- transport_disconnect(transport);
- transport = NULL;
+ transport_disconnect(gtransport);
+ gtransport = NULL;
return exit_code;
}
for (i = 1; i < argc; i++)
strbuf_addf(&default_rla, " %s", argv[i]);
+ git_config(git_fetch_config, NULL);
+
argc = parse_options(argc, argv, prefix,
builtin_fetch_options, builtin_fetch_usage, 0);
static void print_value(struct refinfo *ref, int atom, int quote_style)
{
struct atom_value *v;
+ struct strbuf sb = STRBUF_INIT;
get_value(ref, atom, &v);
switch (quote_style) {
case QUOTE_NONE:
fputs(v->s, stdout);
break;
case QUOTE_SHELL:
- sq_quote_print(stdout, v->s);
+ sq_quote_buf(&sb, v->s);
break;
case QUOTE_PERL:
- perl_quote_print(stdout, v->s);
+ perl_quote_buf(&sb, v->s);
break;
case QUOTE_PYTHON:
- python_quote_print(stdout, v->s);
+ python_quote_buf(&sb, v->s);
break;
case QUOTE_TCL:
- tcl_quote_print(stdout, v->s);
+ tcl_quote_buf(&sb, v->s);
break;
}
+ if (quote_style != QUOTE_NONE) {
+ fputs(sb.buf, stdout);
+ strbuf_release(&sb);
+ }
}
static int hex1(char ch)
#define REACHABLE 0x0001
#define SEEN 0x0002
+#define HAS_OBJ 0x0004
static int show_root;
static int show_tags;
if (obj->flags & REACHABLE)
return 0;
obj->flags |= REACHABLE;
- if (!obj->parsed) {
+ if (!(obj->flags & HAS_OBJ)) {
if (parent && !has_sha1_file(obj->sha1)) {
printf("broken link from %7s %s\n",
typename(parent->type), sha1_to_hex(parent->sha1));
struct tree *tree = NULL;
if (obj->type == OBJ_TREE) {
- obj->parsed = 0;
tree = (struct tree *)obj;
if (parse_tree(tree) < 0)
return 1; /* error already displayed */
}
result = fsck_walk(obj, mark_object, obj);
- if (tree) {
- free(tree->buffer);
- tree->buffer = NULL;
- }
+ if (tree)
+ free_tree_buffer(tree);
return result;
}
* except if it was in a pack-file and we didn't
* do a full fsck
*/
- if (!obj->parsed) {
+ if (!(obj->flags & HAS_OBJ)) {
if (has_sha1_pack(obj->sha1))
return; /* it is in pack - forget about it */
printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
if (obj->type == OBJ_TREE) {
struct tree *item = (struct tree *) obj;
- free(item->buffer);
- item->buffer = NULL;
+ free_tree_buffer(item);
}
if (obj->type == OBJ_COMMIT) {
return error("%s: object corrupt or missing",
sha1_to_hex(sha1));
}
+ obj->flags |= HAS_OBJ;
return fsck_obj(obj);
}
errors_found |= ERROR_OBJECT;
return error("%s: object corrupt or missing", sha1_to_hex(sha1));
}
+ obj->flags = HAS_OBJ;
return fsck_obj(obj);
}
static struct option fsck_opts[] = {
OPT__VERBOSE(&verbose, N_("be verbose")),
- OPT_BOOLEAN(0, "unreachable", &show_unreachable, N_("show unreachable objects")),
+ OPT_BOOL(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,
+ OPT_BOOL(0, "tags", &show_tags, N_("report tags")),
+ OPT_BOOL(0, "root", &show_root, N_("report root nodes")),
+ OPT_BOOL(0, "cache", &keep_cache_objects, N_("make index objects head nodes")),
+ OPT_BOOL(0, "reflogs", &include_reflogs, N_("make reflogs head nodes (default)")),
+ OPT_BOOL(0, "full", &check_full, N_("also consider packs and alternate objects")),
+ OPT_BOOL(0, "strict", &check_strict, N_("enable more strict checking")),
+ OPT_BOOL(0, "lost-found", &write_lost_and_found,
N_("write dangling objects in .git/lost-found")),
OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
OPT_END(),
#include "cache.h"
#include "parse-options.h"
#include "run-command.h"
+#include "sigchain.h"
#include "argv-array.h"
#define FAILED_RUN "failed to run %s"
static struct argv_array prune = ARGV_ARRAY_INIT;
static struct argv_array rerere = ARGV_ARRAY_INIT;
+static char *pidfile;
+
+static void remove_pidfile(void)
+{
+ if (pidfile)
+ unlink(pidfile);
+}
+
+static void remove_pidfile_on_signal(int signo)
+{
+ remove_pidfile();
+ sigchain_pop(signo);
+ raise(signo);
+}
+
static int gc_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "gc.packrefs")) {
return 1;
}
+/* return NULL on success, else hostname running the gc */
+static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
+{
+ static struct lock_file lock;
+ static char locking_host[128];
+ char my_host[128];
+ struct strbuf sb = STRBUF_INIT;
+ struct stat st;
+ uintmax_t pid;
+ FILE *fp;
+ int fd, should_exit;
+
+ if (pidfile)
+ /* already locked */
+ return NULL;
+
+ if (gethostname(my_host, sizeof(my_host)))
+ strcpy(my_host, "unknown");
+
+ fd = hold_lock_file_for_update(&lock, git_path("gc.pid"),
+ LOCK_DIE_ON_ERROR);
+ if (!force) {
+ fp = fopen(git_path("gc.pid"), "r");
+ memset(locking_host, 0, sizeof(locking_host));
+ should_exit =
+ fp != NULL &&
+ !fstat(fileno(fp), &st) &&
+ /*
+ * 12 hour limit is very generous as gc should
+ * never take that long. On the other hand we
+ * don't really need a strict limit here,
+ * running gc --auto one day late is not a big
+ * problem. --force can be used in manual gc
+ * after the user verifies that no gc is
+ * running.
+ */
+ time(NULL) - st.st_mtime <= 12 * 3600 &&
+ fscanf(fp, "%"PRIuMAX" %127c", &pid, locking_host) == 2 &&
+ /* be gentle to concurrent "gc" on remote hosts */
+ (strcmp(locking_host, my_host) || !kill(pid, 0));
+ if (fp != NULL)
+ fclose(fp);
+ if (should_exit) {
+ if (fd >= 0)
+ rollback_lock_file(&lock);
+ *ret_pid = pid;
+ return locking_host;
+ }
+ }
+
+ strbuf_addf(&sb, "%"PRIuMAX" %s",
+ (uintmax_t) getpid(), my_host);
+ write_in_full(fd, sb.buf, sb.len);
+ strbuf_release(&sb);
+ commit_lock_file(&lock);
+
+ pidfile = git_pathdup("gc.pid");
+ sigchain_push_common(remove_pidfile_on_signal);
+ atexit(remove_pidfile);
+
+ return NULL;
+}
+
int cmd_gc(int argc, const char **argv, const char *prefix)
{
int aggressive = 0;
int auto_gc = 0;
int quiet = 0;
+ int force = 0;
+ const char *name;
+ pid_t pid;
struct option builtin_gc_options[] = {
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, N_("be more thorough (increased runtime)")),
- OPT_BOOLEAN(0, "auto", &auto_gc, N_("enable auto-gc mode")),
+ OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
+ OPT_BOOL(0, "auto", &auto_gc, N_("enable auto-gc mode")),
+ OPT_BOOL(0, "force", &force, N_("force running gc even if there may be another gc running")),
OPT_END()
};
} else
add_repack_all_option();
+ name = lock_repo_for_gc(force, &pid);
+ if (name) {
+ if (auto_gc)
+ return 0; /* be quiet on --auto */
+ die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"),
+ name, (uintmax_t)pid);
+ }
+
if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
return error(FAILED_RUN, pack_refs_cmd.argv[0]);
#include "grep.h"
#include "quote.h"
#include "dir.h"
+#include "pathspec.h"
static char const * const grep_usage[] = {
N_("git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"),
}
static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
- struct object *obj, const char *name)
+ struct object *obj, const char *name, struct object_context *oc)
{
if (obj->type == OBJ_BLOB)
- return grep_sha1(opt, obj->sha1, name, 0, NULL);
+ return grep_sha1(opt, obj->sha1, name, 0, oc ? oc->path : NULL);
if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
struct tree_desc tree;
void *data;
for (i = 0; i < nr; i++) {
struct object *real_obj;
real_obj = deref_tag(list->objects[i].item, NULL, 0);
- if (grep_object(opt, pathspec, real_obj, list->objects[i].name)) {
+ if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].context)) {
hit = 1;
if (opt->status_only)
break;
if (exc_std)
setup_standard_excludes(&dir);
- fill_directory(&dir, pathspec->raw);
+ fill_directory(&dir, pathspec);
for (i = 0; i < dir.nr; i++) {
const char *name = dir.entries[i]->name;
int namelen = strlen(name);
const char *show_in_pager = NULL, *default_pager = "dummy";
struct grep_opt opt;
struct object_array list = OBJECT_ARRAY_INIT;
- const char **paths = NULL;
struct pathspec pathspec;
struct string_list path_list = STRING_LIST_INIT_NODUP;
int i;
int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;
struct option options[] = {
- OPT_BOOLEAN(0, "cached", &cached,
+ OPT_BOOL(0, "cached", &cached,
N_("search in index instead of in the work tree")),
OPT_NEGBIT(0, "no-index", &use_index,
N_("find in contents not managed by git"), 1),
- OPT_BOOLEAN(0, "untracked", &untracked,
+ OPT_BOOL(0, "untracked", &untracked,
N_("search in both tracked and untracked files")),
OPT_SET_INT(0, "exclude-standard", &opt_exclude,
N_("search also in ignored files"), 1),
OPT_GROUP(""),
- OPT_BOOLEAN('v', "invert-match", &opt.invert,
+ OPT_BOOL('v', "invert-match", &opt.invert,
N_("show non-matching lines")),
- OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case,
+ OPT_BOOL('i', "ignore-case", &opt.ignore_case,
N_("case insensitive matching")),
- OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp,
+ OPT_BOOL('w', "word-regexp", &opt.word_regexp,
N_("match patterns only at word boundaries")),
OPT_SET_INT('a', "text", &opt.binary,
N_("process binary files as text"), GREP_BINARY_TEXT),
OPT_SET_INT('I', NULL, &opt.binary,
N_("don't match patterns in binary files"),
GREP_BINARY_NOMATCH),
+ OPT_BOOL(0, "textconv", &opt.allow_textconv,
+ N_("process binary files with textconv filters")),
{ OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"),
N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
NULL, 1 },
N_("use Perl-compatible regular expressions"),
GREP_PATTERN_TYPE_PCRE),
OPT_GROUP(""),
- OPT_BOOLEAN('n', "line-number", &opt.linenum, N_("show line numbers")),
+ OPT_BOOL('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,
N_("show filenames relative to top directory"), 1),
- OPT_BOOLEAN('l', "files-with-matches", &opt.name_only,
+ OPT_BOOL('l', "files-with-matches", &opt.name_only,
N_("show only filenames instead of matching lines")),
- OPT_BOOLEAN(0, "name-only", &opt.name_only,
+ OPT_BOOL(0, "name-only", &opt.name_only,
N_("synonym for --files-with-matches")),
- OPT_BOOLEAN('L', "files-without-match",
+ OPT_BOOL('L', "files-without-match",
&opt.unmatch_name_only,
N_("show only the names of files without match")),
- OPT_BOOLEAN('z', "null", &opt.null_following_name,
+ OPT_BOOL('z', "null", &opt.null_following_name,
N_("print NUL after filenames")),
- OPT_BOOLEAN('c', "count", &opt.count,
+ OPT_BOOL('c', "count", &opt.count,
N_("show the number of matches instead of matching lines")),
OPT__COLOR(&opt.color, N_("highlight matches")),
- OPT_BOOLEAN(0, "break", &opt.file_break,
+ OPT_BOOL(0, "break", &opt.file_break,
N_("print empty line between matches from different files")),
- OPT_BOOLEAN(0, "heading", &opt.heading,
+ OPT_BOOL(0, "heading", &opt.heading,
N_("show filename only once above matches from same file")),
OPT_GROUP(""),
OPT_CALLBACK('C', "context", &opt, N_("n"),
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,
+ OPT_BOOL('p', "show-function", &opt.funcname,
N_("show a line with the function name before matches")),
- OPT_BOOLEAN('W', "function-context", &opt.funcbody,
+ OPT_BOOL('W', "function-context", &opt.funcbody,
N_("show the surrounding function")),
OPT_GROUP(""),
OPT_CALLBACK('f', NULL, &opt, N_("file"),
{ OPTION_CALLBACK, 0, "and", &opt, NULL,
N_("combine patterns specified with -e"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },
- OPT_BOOLEAN(0, "or", &dummy, ""),
+ OPT_BOOL(0, "or", &dummy, ""),
{ OPTION_CALLBACK, 0, "not", &opt, NULL, "",
PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback },
{ OPTION_CALLBACK, '(', NULL, &opt, NULL, "",
close_callback },
OPT__QUIET(&opt.status_only,
N_("indicate hit with exit status without output")),
- OPT_BOOLEAN(0, "all-match", &opt.all_match,
+ OPT_BOOL(0, "all-match", &opt.all_match,
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"),
{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_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,
- N_("allow calling of grep(1) (ignored by this build)")),
+ OPT_BOOL(0, "ext-grep", &external_grep_allowed__ignored,
+ 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()
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
unsigned char sha1[20];
+ struct object_context oc;
/* Is it a rev? */
- if (!get_sha1(arg, sha1)) {
+ if (!get_sha1_with_context(arg, 0, sha1, &oc)) {
struct object *object = parse_object_or_die(sha1, arg);
if (!seen_dashdash)
verify_non_filename(prefix, arg);
- add_object_array(object, arg, &list);
+ add_object_array_with_context(object, arg, &list, xmemdupz(&oc, sizeof(struct object_context)));
continue;
}
if (!strcmp(arg, "--")) {
verify_filename(prefix, argv[j], j == i);
}
- paths = get_pathspec(prefix, argv + i);
- init_pathspec(&pathspec, paths);
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_CWD |
+ (opt.max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0),
+ prefix, argv + i);
pathspec.max_depth = opt.max_depth;
pathspec.recursive = 1;
static const struct option hash_object_options[] = {
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_BOOL('w', NULL, &write_object, N_("write the object into the object database")),
+ OPT_COUNTUP( 0 , "stdin", &hashstdin, N_("read the object from stdin")),
+ OPT_BOOL( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")),
+ OPT_BOOL( 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()
};
if (obj->type == OBJ_TREE) {
struct tree *item = (struct tree *) obj;
item->buffer = NULL;
+ obj->parsed = 0;
}
if (obj->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *) obj;
if (default_date_mode)
rev->date_mode = parse_date_format(default_date_mode);
+ rev->diffopt.touched_flags = 0;
}
static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
static struct line_opt_callback_data line_cb = {NULL, NULL, STRING_LIST_INIT_DUP};
const struct option builtin_log_options[] = {
- OPT_BOOL(0, "quiet", &quiet, N_("suppress diff output")),
+ OPT__QUIET(&quiet, N_("suppress diff output")),
OPT_BOOL(0, "source", &source, N_("show source")),
OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")),
{ OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
strbuf_release(&out);
}
-static int show_blob_object(const unsigned char *sha1, struct rev_info *rev)
+static int show_blob_object(const unsigned char *sha1, struct rev_info *rev, const char *obj_name)
{
+ unsigned char sha1c[20];
+ struct object_context obj_context;
+ char *buf;
+ unsigned long size;
+
fflush(stdout);
- return stream_blob_to_fd(1, sha1, NULL, 0);
+ if (!DIFF_OPT_TOUCHED(&rev->diffopt, ALLOW_TEXTCONV) ||
+ !DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
+ return stream_blob_to_fd(1, sha1, NULL, 0);
+
+ if (get_sha1_with_context(obj_name, 0, sha1c, &obj_context))
+ die("Not a valid object name %s", obj_name);
+ if (!obj_context.path[0] ||
+ !textconv_object(obj_context.path, obj_context.mode, sha1c, 1, &buf, &size))
+ return stream_blob_to_fd(1, sha1, NULL, 0);
+
+ if (!buf)
+ die("git show %s: bad file", obj_name);
+
+ write_or_die(1, buf, size);
+ return 0;
}
static int show_tag_object(const unsigned char *sha1, struct rev_info *rev)
init_grep_defaults();
git_config(git_log_config, NULL);
- init_pathspec(&match_all, NULL);
+ memset(&match_all, 0, sizeof(match_all));
init_revisions(&rev, prefix);
rev.diff = 1;
rev.always_show_header = 1;
const char *name = objects[i].name;
switch (o->type) {
case OBJ_BLOB:
- ret = show_blob_object(o->sha1, NULL);
+ ret = show_blob_object(o->sha1, &rev, name);
break;
case OBJ_TAG: {
struct tag *t = (struct tag *)o;
{ OPTION_CALLBACK, 'k', "keep-subject", &rev, NULL,
N_("don't strip/add [PATCH]"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback },
- OPT_BOOLEAN(0, "no-binary", &no_binary_diff,
- N_("don't output binary diffs")),
- OPT_BOOLEAN(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
- N_("don't include a patch matching a commit upstream")),
- { OPTION_BOOLEAN, 'p', "no-stat", &use_patch_format, NULL,
+ OPT_BOOL(0, "no-binary", &no_binary_diff,
+ N_("don't output binary diffs")),
+ OPT_BOOL(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
+ N_("don't include a patch matching a commit upstream")),
+ { OPTION_SET_INT, 'p', "no-stat", &use_patch_format, NULL,
N_("show patch format instead of default (patch + stat)"),
- PARSE_OPT_NONEG | PARSE_OPT_NOARG },
+ PARSE_OPT_NONEG | PARSE_OPT_NOARG, NULL, 1},
OPT_GROUP(N_("Messaging")),
{ OPTION_CALLBACK, 0, "add-header", NULL, N_("header"),
N_("add email header"), 0, header_callback },
PARSE_OPT_OPTARG, thread_callback },
OPT_STRING(0, "signature", &signature, N_("signature"),
N_("add a signature")),
- OPT_BOOLEAN(0, "quiet", &quiet,
- N_("don't print the patch filenames")),
+ OPT__QUIET(&quiet, N_("don't print the patch filenames")),
OPT_END()
};
#include "parse-options.h"
#include "resolve-undo.h"
#include "string-list.h"
+#include "pathspec.h"
static int abbrev;
static int show_deleted;
static const char *prefix;
static int max_prefix_len;
static int prefix_len;
-static const char **pathspec;
+static struct pathspec pathspec;
static int error_unmatch;
static char *ps_matched;
static const char *with_tree;
if (len >= ent->len)
die("git ls-files: internal error - directory entry not superset of prefix");
- if (!match_pathspec(pathspec, ent->name, ent->len, len, ps_matched))
+ if (!match_pathspec_depth(&pathspec, ent->name, ent->len, len, ps_matched))
return;
fputs(tag, stdout);
if (len >= ce_namelen(ce))
die("git ls-files: internal error - cache entry not superset of prefix");
- if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), len, ps_matched))
+ if (!match_pathspec_depth(&pathspec, ce->name, ce_namelen(ce), len, ps_matched))
return;
if (tag && *tag && show_valid_bit &&
len = strlen(path);
if (len < max_prefix_len)
continue; /* outside of the prefix */
- if (!match_pathspec(pathspec, path, len, max_prefix_len, ps_matched))
+ if (!match_pathspec_depth(&pathspec, path, len, max_prefix_len, ps_matched))
continue; /* uninterested */
for (i = 0; i < 3; i++) {
if (!ui->mode[i])
/* For cached/deleted files we don't need to even do the readdir */
if (show_others || show_killed) {
- fill_directory(dir, pathspec);
+ if (!show_others)
+ dir->flags |= DIR_COLLECT_KILLED_ONLY;
+ fill_directory(dir, &pathspec);
if (show_others)
show_other_files(dir);
if (show_killed)
active_nr = last;
}
-static void strip_trailing_slash_from_submodules(void)
-{
- const char **p;
-
- for (p = pathspec; *p != NULL; p++) {
- int len = strlen(*p), pos;
-
- if (len < 1 || (*p)[len - 1] != '/')
- continue;
- pos = cache_name_pos(*p, len - 1);
- if (pos >= 0 && S_ISGITLINK(active_cache[pos]->ce_mode))
- *p = xstrndup(*p, len - 1);
- }
-}
-
/*
* Read the tree specified with --with-tree option
* (typically, HEAD) into stage #1 and then
}
if (prefix) {
- static const char *(matchbuf[2]);
- matchbuf[0] = prefix;
- matchbuf[1] = NULL;
- init_pathspec(&pathspec, matchbuf);
- pathspec.items[0].nowildcard_len = pathspec.items[0].len;
+ static const char *(matchbuf[1]);
+ matchbuf[0] = NULL;
+ parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC,
+ PATHSPEC_PREFER_CWD, prefix, matchbuf);
} else
- init_pathspec(&pathspec, NULL);
+ memset(&pathspec, 0, sizeof(pathspec));
if (read_tree(tree, 1, &pathspec))
die("unable to read tree entries %s", tree_name);
}
}
-int report_path_error(const char *ps_matched, const char **pathspec, const char *prefix)
+int report_path_error(const char *ps_matched,
+ const struct pathspec *pathspec,
+ const char *prefix)
{
/*
* Make sure all pathspec matched; otherwise it is an error.
*/
struct strbuf sb = STRBUF_INIT;
- const char *name;
int num, errors = 0;
- for (num = 0; pathspec[num]; num++) {
+ for (num = 0; num < pathspec->nr; num++) {
int other, found_dup;
if (ps_matched[num])
/*
* The caller might have fed identical pathspec
* twice. Do not barf on such a mistake.
+ * FIXME: parse_pathspec should have eliminated
+ * duplicate pathspec.
*/
for (found_dup = other = 0;
- !found_dup && pathspec[other];
+ !found_dup && other < pathspec->nr;
other++) {
if (other == num || !ps_matched[other])
continue;
- if (!strcmp(pathspec[other], pathspec[num]))
+ if (!strcmp(pathspec->items[other].original,
+ pathspec->items[num].original))
/*
* Ok, we have a match already.
*/
if (found_dup)
continue;
- name = quote_path_relative(pathspec[num], prefix, &sb);
error("pathspec '%s' did not match any file(s) known to git.",
- name);
+ pathspec->items[num].original);
errors++;
}
strbuf_release(&sb);
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
N_("paths are separated with NUL character"),
PARSE_OPT_NOARG, option_parse_z },
- OPT_BOOLEAN('t', NULL, &show_tag,
+ OPT_BOOL('t', NULL, &show_tag,
N_("identify the file status with tags")),
- OPT_BOOLEAN('v', NULL, &show_valid_bit,
+ OPT_BOOL('v', NULL, &show_valid_bit,
N_("use lowercase letters for 'assume unchanged' files")),
- OPT_BOOLEAN('c', "cached", &show_cached,
+ OPT_BOOL('c', "cached", &show_cached,
N_("show cached files in the output (default)")),
- OPT_BOOLEAN('d', "deleted", &show_deleted,
+ OPT_BOOL('d', "deleted", &show_deleted,
N_("show deleted files in the output")),
- OPT_BOOLEAN('m', "modified", &show_modified,
+ OPT_BOOL('m', "modified", &show_modified,
N_("show modified files in the output")),
- OPT_BOOLEAN('o', "others", &show_others,
+ OPT_BOOL('o', "others", &show_others,
N_("show other files in the output")),
OPT_BIT('i', "ignored", &dir.flags,
N_("show ignored files in the output"),
DIR_SHOW_IGNORED),
- OPT_BOOLEAN('s', "stage", &show_stage,
+ OPT_BOOL('s', "stage", &show_stage,
N_("show staged contents' object name in the output")),
- OPT_BOOLEAN('k', "killed", &show_killed,
+ OPT_BOOL('k', "killed", &show_killed,
N_("show files on the filesystem that need to be removed")),
OPT_BIT(0, "directory", &dir.flags,
N_("show 'other' directories' name only"),
OPT_NEGBIT(0, "empty-directory", &dir.flags,
N_("don't show empty directories"),
DIR_HIDE_EMPTY_DIRECTORIES),
- OPT_BOOLEAN('u', "unmerged", &show_unmerged,
+ OPT_BOOL('u', "unmerged", &show_unmerged,
N_("show unmerged files in the output")),
- OPT_BOOLEAN(0, "resolve-undo", &show_resolve_undo,
+ OPT_BOOL(0, "resolve-undo", &show_resolve_undo,
N_("show resolve-undo information")),
{ OPTION_CALLBACK, 'x', "exclude", &exclude_list, N_("pattern"),
N_("skip files matching pattern"),
{ OPTION_SET_INT, 0, "full-name", &prefix_len, NULL,
N_("make the output relative to the project top directory"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL },
- OPT_BOOLEAN(0, "error-unmatch", &error_unmatch,
+ OPT_BOOL(0, "error-unmatch", &error_unmatch,
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, N_("show debugging data")),
+ OPT_BOOL(0, "debug", &debug_mode, N_("show debugging data")),
OPT_END()
};
if (require_work_tree && !is_inside_work_tree())
setup_work_tree();
- pathspec = get_pathspec(prefix, argv);
-
- /* be nice with submodule paths ending in a slash */
- if (pathspec)
- strip_trailing_slash_from_submodules();
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_CWD |
+ PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
+ prefix, argv);
/* Find common prefix for all pathspec's */
- max_prefix = common_prefix(pathspec);
+ max_prefix = common_prefix(&pathspec);
max_prefix_len = max_prefix ? strlen(max_prefix) : 0;
/* Treat unmatching pathspec elements as errors */
- if (pathspec && error_unmatch) {
- int num;
- for (num = 0; pathspec[num]; num++)
- ;
- ps_matched = xcalloc(1, num);
- }
+ if (pathspec.nr && error_unmatch)
+ ps_matched = xcalloc(1, pathspec.nr);
if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given)
die("ls-files --ignored needs some exclude pattern");
if (ps_matched) {
int bad;
- bad = report_path_error(ps_matched, pathspec, prefix);
+ bad = report_path_error(ps_matched, &pathspec, prefix);
if (bad)
fprintf(stderr, "Did you forget to 'git add'?\n");
#include "quote.h"
#include "builtin.h"
#include "parse-options.h"
+#include "pathspec.h"
static int line_termination = '\n';
#define LS_RECURSIVE 1
if (ls_options & LS_RECURSIVE)
return 1;
- s = pathspec.raw;
+ s = pathspec._raw;
if (!s)
return 0;
LS_NAME_ONLY),
OPT_SET_INT(0, "full-name", &chomp_prefix,
N_("use full path names"), 0),
- OPT_BOOLEAN(0, "full-tree", &full_tree,
- N_("list entire tree; not just current directory "
- "(implies --full-name)")),
+ OPT_BOOL(0, "full-tree", &full_tree,
+ N_("list entire tree; not just current directory "
+ "(implies --full-name)")),
OPT__ABBREV(&abbrev),
OPT_END()
};
if (get_sha1(argv[0], sha1))
die("Not a valid object name %s", argv[0]);
- init_pathspec(&pathspec, get_pathspec(prefix, argv + 1));
+ /*
+ * show_recursive() rolls its own matching code and is
+ * generally ignorant of 'struct pathspec'. The magic mask
+ * cannot be lifted until it is converted to use
+ * match_pathspec_depth() or tree_entry_interesting()
+ */
+ parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE,
+ PATHSPEC_PREFER_CWD,
+ prefix, argv + 1);
for (i = 0; i < pathspec.nr; i++)
pathspec.items[i].nowildcard_len = pathspec.items[i].len;
pathspec.has_wildcard = 0;
int is_ancestor = 0;
struct option options[] = {
- 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_BOOL('a', "all", &show_all, N_("output all common ancestors")),
+ OPT_BOOL(0, "octopus", &octopus, N_("find ancestors for a single n-way merge")),
+ OPT_BOOL(0, "independent", &reduce, N_("list revs not reachable from others")),
+ OPT_BOOL(0, "is-ancestor", &is_ancestor,
+ N_("is the first one ancestor of the other?")),
OPT_END()
};
int quiet = 0;
int prefixlen = 0;
struct option options[] = {
- OPT_BOOLEAN('p', "stdout", &to_stdout, N_("send results to standard output")),
+ OPT_BOOL('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),
{ OPTION_CALLBACK, 'n', NULL, NULL, NULL,
N_("do not show a diffstat at the end of the merge"),
PARSE_OPT_NOARG, option_parse_n },
- OPT_BOOLEAN(0, "stat", &show_diffstat,
+ OPT_BOOL(0, "stat", &show_diffstat,
N_("show a diffstat at the end of the merge")),
- OPT_BOOLEAN(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
+ OPT_BOOL(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,
+ OPT_BOOL(0, "squash", &squash,
N_("create a single commit instead of doing a merge")),
- OPT_BOOLEAN(0, "commit", &option_commit,
+ OPT_BOOL(0, "commit", &option_commit,
N_("perform a commit if the merge succeeds (default)")),
OPT_BOOL('e', "edit", &option_edit,
N_("edit message before committing")),
N_("merge commit message (for a non-fast-forward merge)"),
option_parse_message),
OPT__VERBOSITY(&verbosity),
- OPT_BOOLEAN(0, "abort", &abort_current_merge,
+ OPT_BOOL(0, "abort", &abort_current_merge,
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_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
OPT_END()
};
* This could be traditional "merge <msg> HEAD <commit>..." and
* the way we can tell it is to see if the second token is HEAD,
* but some people might have misused the interface and used a
- * committish that is the same as HEAD there instead.
+ * commit-ish that is the same as HEAD there instead.
* Traditional format never would have "-m" so it is an
* additional safety measure to check for it.
*/
#include "cache-tree.h"
#include "string-list.h"
#include "parse-options.h"
+#include "submodule.h"
static const char * const builtin_mv_usage[] = {
N_("git mv [options] <source>... <destination>"),
NULL
};
-static const char **copy_pathspec(const char *prefix, const char **pathspec,
- int count, int base_name)
+static const char **internal_copy_pathspec(const char *prefix,
+ const char **pathspec,
+ int count, int base_name)
{
int i;
const char **result = xmalloc((count + 1) * sizeof(const char *));
}
static struct lock_file lock_file;
+#define SUBMODULE_WITH_GITDIR ((const char *)1)
int cmd_mv(int argc, const char **argv, const char *prefix)
{
- int i, newfd;
+ int i, newfd, gitmodules_modified = 0;
int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
struct option builtin_mv_options[] = {
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_BOOL('k', NULL, &ignore_errors, N_("skip move/rename errors")),
OPT_END(),
};
- const char **source, **destination, **dest_path;
+ const char **source, **destination, **dest_path, **submodule_gitfile;
enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
struct stat st;
struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
+ gitmodules_config();
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_mv_options,
if (read_cache() < 0)
die(_("index file corrupt"));
- source = copy_pathspec(prefix, argv, argc, 0);
+ source = internal_copy_pathspec(prefix, argv, argc, 0);
modes = xcalloc(argc, sizeof(enum update_mode));
- dest_path = copy_pathspec(prefix, argv + argc, 1, 0);
+ dest_path = internal_copy_pathspec(prefix, argv + argc, 1, 0);
+ submodule_gitfile = xcalloc(argc, sizeof(char *));
if (dest_path[0][0] == '\0')
/* special case: "." was normalized to "" */
- destination = copy_pathspec(dest_path[0], argv, argc, 1);
+ destination = internal_copy_pathspec(dest_path[0], argv, argc, 1);
else if (!lstat(dest_path[0], &st) &&
S_ISDIR(st.st_mode)) {
dest_path[0] = add_slash(dest_path[0]);
- destination = copy_pathspec(dest_path[0], argv, argc, 1);
+ destination = internal_copy_pathspec(dest_path[0], argv, argc, 1);
} else {
if (argc != 1)
die("destination '%s' is not a directory", dest_path[0]);
&& lstat(dst, &st) == 0)
bad = _("cannot move directory over file");
else if (src_is_dir) {
- const char *src_w_slash = add_slash(src);
- int len_w_slash = length + 1;
- int first, last;
-
- modes[i] = WORKING_DIRECTORY;
-
- first = cache_name_pos(src_w_slash, len_w_slash);
- if (first >= 0)
- die (_("Huh? %.*s is in index?"),
- len_w_slash, src_w_slash);
-
- first = -1 - first;
- for (last = first; last < active_nr; last++) {
- const char *path = active_cache[last]->name;
- if (strncmp(path, src_w_slash, len_w_slash))
- break;
- }
- free((char *)src_w_slash);
-
- if (last - first < 1)
- bad = _("source directory is empty");
- else {
- int j, dst_len;
-
- if (last - first > 0) {
- source = xrealloc(source,
- (argc + last - first)
- * sizeof(char *));
- destination = xrealloc(destination,
- (argc + last - first)
- * sizeof(char *));
- modes = xrealloc(modes,
- (argc + last - first)
- * sizeof(enum update_mode));
+ int first = cache_name_pos(src, length);
+ if (first >= 0) {
+ struct strbuf submodule_dotgit = STRBUF_INIT;
+ if (!S_ISGITLINK(active_cache[first]->ce_mode))
+ die (_("Huh? Directory %s is in index and no submodule?"), src);
+ if (!is_staging_gitmodules_ok())
+ die (_("Please, stage your changes to .gitmodules or stash them to proceed"));
+ strbuf_addf(&submodule_dotgit, "%s/.git", src);
+ submodule_gitfile[i] = read_gitfile(submodule_dotgit.buf);
+ if (submodule_gitfile[i])
+ submodule_gitfile[i] = xstrdup(submodule_gitfile[i]);
+ else
+ submodule_gitfile[i] = SUBMODULE_WITH_GITDIR;
+ strbuf_release(&submodule_dotgit);
+ } else {
+ const char *src_w_slash = add_slash(src);
+ int last, len_w_slash = length + 1;
+
+ modes[i] = WORKING_DIRECTORY;
+
+ first = cache_name_pos(src_w_slash, len_w_slash);
+ if (first >= 0)
+ die (_("Huh? %.*s is in index?"),
+ len_w_slash, src_w_slash);
+
+ first = -1 - first;
+ for (last = first; last < active_nr; last++) {
+ const char *path = active_cache[last]->name;
+ if (strncmp(path, src_w_slash, len_w_slash))
+ break;
}
+ free((char *)src_w_slash);
+
+ if (last - first < 1)
+ bad = _("source directory is empty");
+ else {
+ int j, dst_len;
- dst = add_slash(dst);
- dst_len = strlen(dst);
-
- for (j = 0; j < last - first; j++) {
- const char *path =
- active_cache[first + j]->name;
- source[argc + j] = path;
- destination[argc + j] =
- prefix_path(dst, dst_len,
- path + length + 1);
- modes[argc + j] = INDEX;
+ if (last - first > 0) {
+ source = xrealloc(source,
+ (argc + last - first)
+ * sizeof(char *));
+ destination = xrealloc(destination,
+ (argc + last - first)
+ * sizeof(char *));
+ modes = xrealloc(modes,
+ (argc + last - first)
+ * sizeof(enum update_mode));
+ }
+
+ dst = add_slash(dst);
+ dst_len = strlen(dst);
+
+ for (j = 0; j < last - first; j++) {
+ const char *path =
+ active_cache[first + j]->name;
+ source[argc + j] = path;
+ destination[argc + j] =
+ prefix_path(dst, dst_len,
+ path + length + 1);
+ modes[argc + j] = INDEX;
+ }
+ argc += last - first;
}
- argc += last - first;
}
} else if (cache_name_pos(src, length) < 0)
bad = _("not under version control");
int pos;
if (show_only || verbose)
printf(_("Renaming %s to %s\n"), src, dst);
- if (!show_only && mode != INDEX &&
- rename(src, dst) < 0 && !ignore_errors)
- die_errno (_("renaming '%s' failed"), src);
+ if (!show_only && mode != INDEX) {
+ if (rename(src, dst) < 0 && !ignore_errors)
+ die_errno (_("renaming '%s' failed"), src);
+ if (submodule_gitfile[i]) {
+ if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR)
+ connect_work_tree_and_git_dir(dst, submodule_gitfile[i]);
+ if (!update_path_in_gitmodules(src, dst))
+ gitmodules_modified = 1;
+ }
+ }
if (mode == WORKING_DIRECTORY)
continue;
rename_cache_entry_at(pos, dst);
}
+ if (gitmodules_modified)
+ stage_updated_gitmodules();
+
if (active_cache_changed) {
if (write_cache(newfd, active_cache, active_nr) ||
commit_locked_index(&lock_file))
int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
struct name_ref_data data = { 0, 0, NULL };
struct option opts[] = {
- 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_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
+ OPT_BOOL(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, 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,
+ OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
+ OPT_BOOL(0, "stdin", &transform_stdin, N_("read from stdin")),
+ OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")),
+ OPT_BOOL(0, "always", &always,
N_("show abbreviated commit object as fallback")),
{
/* A Hidden OPT_BOOL */
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0);
- if (!!all + !!transform_stdin + !!argc > 1) {
+ if (all + transform_stdin + !!argc > 1) {
error("Specify either a list, or --all, not both!");
usage_with_options(name_rev_usage, opts);
}
const char *rewrite_cmd = NULL;
struct option options[] = {
OPT__FORCE(&force, N_("replace existing notes")),
- OPT_BOOLEAN(0, "stdin", &from_stdin, N_("read objects from stdin")),
+ OPT_BOOL(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)")),
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,
+ { OPTION_SET_INT, 0, "commit", &do_commit, NULL,
N_("finalize notes merge by committing unmerged notes"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG },
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
OPT_GROUP(N_("Aborting notes merge resolution")),
- { OPTION_BOOLEAN, 0, "abort", &do_abort, NULL,
+ { OPTION_SET_INT, 0, "abort", &do_abort, NULL,
N_("abort notes merge"),
- PARSE_OPT_NOARG | PARSE_OPT_NONEG },
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
OPT_END()
};
OPT_BIT(0, "ignore-missing", &flag,
N_("attempt to remove non-existent note is not an error"),
IGNORE_MISSING),
- OPT_BOOLEAN(0, "stdin", &from_stdin,
+ OPT_BOOL(0, "stdin", &from_stdin,
N_("read object names from the standard input")),
OPT_END()
};
void *delta_data; /* cached delta (uncompressed) */
unsigned long delta_size; /* delta data size (uncompressed) */
unsigned long z_delta_size; /* delta data size (compressed) */
- unsigned int hash; /* name hint hash */
enum object_type type;
enum object_type in_pack_type; /* could be delta */
+ uint32_t hash; /* name hint hash */
unsigned char in_pack_header_size;
- unsigned char preferred_base; /* we do not pack this, but is available
- * to be used as the base object to delta
- * objects against.
- */
- unsigned char no_try_delta;
- unsigned char tagged; /* near the very tip of refs */
- unsigned char filled; /* assigned write-order */
+ unsigned preferred_base:1; /*
+ * we do not pack this, but is available
+ * to be used as the base object to delta
+ * objects against.
+ */
+ unsigned no_try_delta:1;
+ unsigned tagged:1; /* near the very tip of refs */
+ unsigned filled:1; /* assigned write-order */
};
/*
}
}
-static unsigned name_hash(const char *name)
+static uint32_t name_hash(const char *name)
{
- unsigned c, hash = 0;
+ uint32_t c, hash = 0;
if (!name)
return 0;
struct packed_git *p, *found_pack = NULL;
off_t found_offset = 0;
int ix;
- unsigned hash = name_hash(name);
+ uint32_t hash = name_hash(name);
ix = nr_objects ? locate_object_entry_hash(sha1) : -1;
if (ix >= 0) {
static void try_to_free_from_threads(size_t size)
{
read_lock();
- release_pack_memory(size, -1);
+ release_pack_memory(size);
read_unlock();
}
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
- mark_edges_uninteresting(revs.commits, &revs, show_edge);
+ mark_edges_uninteresting(&revs, show_edge);
traverse_commit_list(&revs, show_commit, show_object, NULL);
if (keep_unreachable)
NULL,
};
-static int thin;
+static int thin = 1;
static int deleterefs;
static const char *receivepack;
static int verbosity;
static int progress = -1;
+static struct push_cas_option cas;
+
static const char **refspec;
static int refspec_nr;
static int refspec_alloc;
if (receivepack)
transport_set_option(transport,
TRANS_OPT_RECEIVEPACK, receivepack);
- if (thin)
- transport_set_option(transport, TRANS_OPT_THIN, "yes");
+ transport_set_option(transport, TRANS_OPT_THIN, thin ? "yes" : NULL);
+
+ if (!is_empty_cas(&cas)) {
+ if (!transport->smart_options)
+ die("underlying transport does not support --%s option",
+ CAS_OPT_NAME);
+ transport->smart_options->cas = &cas;
+ }
if (verbosity > 0)
fprintf(stderr, _("Pushing to %s\n"), transport->url);
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, N_("delete refs")),
- OPT_BOOLEAN( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")),
+ OPT_BOOL( 0, "delete", &deleterefs, N_("delete refs")),
+ OPT_BOOL( 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, CAS_OPT_NAME, &cas, N_("refname>:<expect"),
+ N_("require old value of ref to be at this value"),
+ PARSE_OPT_OPTARG, parseopt_push_cas_option },
{ 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, N_("use thin pack")),
+ OPT_BOOL( 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"),
if (1 < opts.index_only + opts.update)
die("-u and -i at the same time makes no sense");
- if ((opts.update||opts.index_only) && !opts.merge)
+ if ((opts.update || opts.index_only) && !opts.merge)
die("%s is meaningless without -m, --reset, or --prefix",
opts.update ? "-u" : "-i");
if ((opts.dir && !opts.update))
#include "commit.h"
#include "object.h"
#include "remote.h"
+#include "connect.h"
#include "transport.h"
#include "string-list.h"
#include "sha1-array.h"
static int prefer_ofs_delta = 1;
static int auto_update_server_info;
static int auto_gc = 1;
+static int fix_thin = 1;
static const char *head_name;
static void *head_name_to_free;
static int sent_capabilities;
return NULL; /* good */
}
else {
- lock = lock_any_ref_for_update(namespaced_name, old_sha1, 0);
+ lock = lock_any_ref_for_update(namespaced_name, old_sha1,
+ 0, NULL);
if (!lock) {
rp_error("failed to lock %s", name);
return "failed to lock";
keeper[i++] = "--stdin";
if (fsck_objects)
keeper[i++] = "--strict";
- keeper[i++] = "--fix-thin";
+ if (fix_thin)
+ keeper[i++] = "--fix-thin";
keeper[i++] = hdr_arg;
keeper[i++] = keep_arg;
keeper[i++] = NULL;
stateless_rpc = 1;
continue;
}
+ if (!strcmp(arg, "--reject-thin-pack-for-testing")) {
+ fix_thin = 0;
+ continue;
+ }
usage(receive_pack_usage);
}
complete = 0;
}
}
- free(tree->buffer);
- tree->buffer = NULL;
+ free_tree_buffer(tree);
if (complete)
tree->object.flags |= SEEN;
* we take the lock for the ref itself to prevent it from
* getting updated.
*/
- lock = lock_any_ref_for_update(ref, sha1, 0);
+ lock = lock_any_ref_for_update(ref, sha1, 0, NULL);
if (!lock)
return error("cannot lock ref '%s'", ref);
log_file = git_pathdup("logs/%s", ref);
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 set-head <name> (-a | --auto | -d | --delete |<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>)...]"),
};
static const char * const builtin_remote_sethead_usage[] = {
- N_("git remote set-head <name> (-a | -d | <branch>)"),
+ N_("git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"),
NULL
};
int i;
struct option options[] = {
- OPT_BOOLEAN('f', "fetch", &fetch, N_("fetch the remote branches")),
+ OPT_BOOL('f', "fetch", &fetch, N_("fetch the remote branches")),
OPT_SET_INT(0, "tags", &fetch_tags,
N_("import all tags and associated objects when fetching"),
TAGS_SET),
{
int no_query = 0, result = 0, query_flag = 0;
struct option options[] = {
- OPT_BOOLEAN('n', NULL, &no_query, N_("do not query remotes")),
+ OPT_BOOL('n', NULL, &no_query, N_("do not query remotes")),
OPT_END()
};
struct ref_states states;
char *head_name = NULL;
struct option options[] = {
- OPT_BOOLEAN('a', "auto", &opt_a,
- N_("set refs/remotes/<name>/HEAD according to remote")),
- OPT_BOOLEAN('d', "delete", &opt_d,
- N_("delete refs/remotes/<name>/HEAD")),
+ OPT_BOOL('a', "auto", &opt_a,
+ N_("set refs/remotes/<name>/HEAD according to remote")),
+ OPT_BOOL('d', "delete", &opt_d,
+ N_("delete refs/remotes/<name>/HEAD")),
OPT_END()
};
argc = parse_options(argc, argv, NULL, options, builtin_remote_sethead_usage,
{
int i, prune = 0;
struct option options[] = {
- OPT_BOOLEAN('p', "prune", &prune,
- N_("prune remotes after fetching")),
+ OPT_BOOL('p', "prune", &prune,
+ N_("prune remotes after fetching")),
OPT_END()
};
const char **fetch_argv;
{
int add_mode = 0;
struct option options[] = {
- OPT_BOOLEAN('\0', "add", &add_mode, N_("add branch")),
+ OPT_BOOL('\0', "add", &add_mode, N_("add branch")),
OPT_END()
};
int urlset_nr;
struct strbuf name_buf = STRBUF_INIT;
struct option options[] = {
- OPT_BOOLEAN('\0', "push", &push_mode,
- N_("manipulate push URLs")),
- OPT_BOOLEAN('\0', "add", &add_mode,
- N_("add URL")),
- OPT_BOOLEAN('\0', "delete", &delete_mode,
+ OPT_BOOL('\0', "push", &push_mode,
+ N_("manipulate push URLs")),
+ OPT_BOOL('\0', "add", &add_mode,
+ N_("add URL")),
+ OPT_BOOL('\0', "delete", &delete_mode,
N_("delete URLs")),
OPT_END()
};
--- /dev/null
+#include "builtin.h"
+#include "cache.h"
+#include "dir.h"
+#include "parse-options.h"
+#include "run-command.h"
+#include "sigchain.h"
+#include "strbuf.h"
+#include "string-list.h"
+#include "argv-array.h"
+
+static int delta_base_offset = 1;
+static char *packdir, *packtmp;
+
+static const char *const git_repack_usage[] = {
+ N_("git repack [options]"),
+ NULL
+};
+
+static int repack_config(const char *var, const char *value, void *cb)
+{
+ if (!strcmp(var, "repack.usedeltabaseoffset")) {
+ delta_base_offset = git_config_bool(var, value);
+ return 0;
+ }
+ return git_default_config(var, value, cb);
+}
+
+/*
+ * Remove temporary $GIT_OBJECT_DIRECTORY/pack/.tmp-$$-pack-* files.
+ */
+static void remove_temporary_files(void)
+{
+ struct strbuf buf = STRBUF_INIT;
+ size_t dirlen, prefixlen;
+ DIR *dir;
+ struct dirent *e;
+
+ dir = opendir(packdir);
+ if (!dir)
+ return;
+
+ /* Point at the slash at the end of ".../objects/pack/" */
+ dirlen = strlen(packdir) + 1;
+ strbuf_addstr(&buf, packtmp);
+ /* Hold the length of ".tmp-%d-pack-" */
+ prefixlen = buf.len - dirlen;
+
+ while ((e = readdir(dir))) {
+ if (strncmp(e->d_name, buf.buf + dirlen, prefixlen))
+ continue;
+ strbuf_setlen(&buf, dirlen);
+ strbuf_addstr(&buf, e->d_name);
+ unlink(buf.buf);
+ }
+ closedir(dir);
+ strbuf_release(&buf);
+}
+
+static void remove_pack_on_signal(int signo)
+{
+ remove_temporary_files();
+ sigchain_pop(signo);
+ raise(signo);
+}
+
+/*
+ * Adds all packs hex strings to the fname list, which do not
+ * have a corresponding .keep file.
+ */
+static void get_non_kept_pack_filenames(struct string_list *fname_list)
+{
+ DIR *dir;
+ struct dirent *e;
+ char *fname;
+ size_t len;
+
+ if (!(dir = opendir(packdir)))
+ return;
+
+ while ((e = readdir(dir)) != NULL) {
+ if (suffixcmp(e->d_name, ".pack"))
+ continue;
+
+ len = strlen(e->d_name) - strlen(".pack");
+ fname = xmemdupz(e->d_name, len);
+
+ if (!file_exists(mkpath("%s/%s.keep", packdir, fname)))
+ string_list_append_nodup(fname_list, fname);
+ else
+ free(fname);
+ }
+ closedir(dir);
+}
+
+static void remove_redundant_pack(const char *dir_name, const char *base_name)
+{
+ const char *exts[] = {".pack", ".idx", ".keep"};
+ int i;
+ struct strbuf buf = STRBUF_INIT;
+ size_t plen;
+
+ strbuf_addf(&buf, "%s/%s", dir_name, base_name);
+ plen = buf.len;
+
+ for (i = 0; i < ARRAY_SIZE(exts); i++) {
+ strbuf_setlen(&buf, plen);
+ strbuf_addstr(&buf, exts[i]);
+ unlink(buf.buf);
+ }
+ strbuf_release(&buf);
+}
+
+#define ALL_INTO_ONE 1
+#define LOOSEN_UNREACHABLE 2
+
+int cmd_repack(int argc, const char **argv, const char *prefix)
+{
+ const char *exts[2] = {".pack", ".idx"};
+ struct child_process cmd;
+ struct string_list_item *item;
+ struct argv_array cmd_args = ARGV_ARRAY_INIT;
+ struct string_list names = STRING_LIST_INIT_DUP;
+ struct string_list rollback = STRING_LIST_INIT_NODUP;
+ struct string_list existing_packs = STRING_LIST_INIT_DUP;
+ struct strbuf line = STRBUF_INIT;
+ int nr_packs, ext, ret, failed;
+ FILE *out;
+
+ /* variables to be filled by option parsing */
+ int pack_everything = 0;
+ int delete_redundant = 0;
+ char *unpack_unreachable = NULL;
+ int window = 0, window_memory = 0;
+ int depth = 0;
+ int max_pack_size = 0;
+ int no_reuse_delta = 0, no_reuse_object = 0;
+ int no_update_server_info = 0;
+ int quiet = 0;
+ int local = 0;
+
+ struct option builtin_repack_options[] = {
+ OPT_BIT('a', NULL, &pack_everything,
+ N_("pack everything in a single pack"), ALL_INTO_ONE),
+ OPT_BIT('A', NULL, &pack_everything,
+ N_("same as -a, and turn unreachable objects loose"),
+ LOOSEN_UNREACHABLE | ALL_INTO_ONE),
+ OPT_BOOL('d', NULL, &delete_redundant,
+ N_("remove redundant packs, and run git-prune-packed")),
+ OPT_BOOL('f', NULL, &no_reuse_delta,
+ N_("pass --no-reuse-delta to git-pack-objects")),
+ OPT_BOOL('F', NULL, &no_reuse_object,
+ N_("pass --no-reuse-object to git-pack-objects")),
+ OPT_BOOL('n', NULL, &no_update_server_info,
+ N_("do not run git-update-server-info")),
+ OPT__QUIET(&quiet, N_("be quiet")),
+ OPT_BOOL('l', "local", &local,
+ N_("pass --local to git-pack-objects")),
+ OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"),
+ N_("with -A, do not loosen objects older than this")),
+ OPT_INTEGER(0, "window", &window,
+ N_("size of the window used for delta compression")),
+ OPT_INTEGER(0, "window-memory", &window_memory,
+ N_("same as the above, but limit memory size instead of entries count")),
+ OPT_INTEGER(0, "depth", &depth,
+ N_("limits the maximum delta depth")),
+ OPT_INTEGER(0, "max-pack-size", &max_pack_size,
+ N_("maximum size of each packfile")),
+ OPT_END()
+ };
+
+ git_config(repack_config, NULL);
+
+ argc = parse_options(argc, argv, prefix, builtin_repack_options,
+ git_repack_usage, 0);
+
+ packdir = mkpathdup("%s/pack", get_object_directory());
+ packtmp = mkpathdup("%s/.tmp-%d-pack", packdir, (int)getpid());
+
+ sigchain_push_common(remove_pack_on_signal);
+
+ argv_array_push(&cmd_args, "pack-objects");
+ argv_array_push(&cmd_args, "--keep-true-parents");
+ argv_array_push(&cmd_args, "--honor-pack-keep");
+ argv_array_push(&cmd_args, "--non-empty");
+ argv_array_push(&cmd_args, "--all");
+ argv_array_push(&cmd_args, "--reflog");
+ if (window)
+ argv_array_pushf(&cmd_args, "--window=%u", window);
+ if (window_memory)
+ argv_array_pushf(&cmd_args, "--window-memory=%u", window_memory);
+ if (depth)
+ argv_array_pushf(&cmd_args, "--depth=%u", depth);
+ if (max_pack_size)
+ argv_array_pushf(&cmd_args, "--max_pack_size=%u", max_pack_size);
+ if (no_reuse_delta)
+ argv_array_pushf(&cmd_args, "--no-reuse-delta");
+ if (no_reuse_object)
+ argv_array_pushf(&cmd_args, "--no-reuse-object");
+
+ if (pack_everything & ALL_INTO_ONE) {
+ get_non_kept_pack_filenames(&existing_packs);
+
+ if (existing_packs.nr && delete_redundant) {
+ if (unpack_unreachable)
+ argv_array_pushf(&cmd_args,
+ "--unpack-unreachable=%s",
+ unpack_unreachable);
+ else if (pack_everything & LOOSEN_UNREACHABLE)
+ argv_array_push(&cmd_args,
+ "--unpack-unreachable");
+ }
+ } else {
+ argv_array_push(&cmd_args, "--unpacked");
+ argv_array_push(&cmd_args, "--incremental");
+ }
+
+ if (local)
+ argv_array_push(&cmd_args, "--local");
+ if (quiet)
+ argv_array_push(&cmd_args, "--quiet");
+ if (delta_base_offset)
+ argv_array_push(&cmd_args, "--delta-base-offset");
+
+ argv_array_push(&cmd_args, packtmp);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.argv = cmd_args.argv;
+ cmd.git_cmd = 1;
+ cmd.out = -1;
+ cmd.no_stdin = 1;
+
+ ret = start_command(&cmd);
+ if (ret)
+ return ret;
+
+ nr_packs = 0;
+ out = xfdopen(cmd.out, "r");
+ while (strbuf_getline(&line, out, '\n') != EOF) {
+ if (line.len != 40)
+ die("repack: Expecting 40 character sha1 lines only from pack-objects.");
+ string_list_append(&names, line.buf);
+ nr_packs++;
+ }
+ fclose(out);
+ ret = finish_command(&cmd);
+ if (ret)
+ return ret;
+ argv_array_clear(&cmd_args);
+
+ if (!nr_packs && !quiet)
+ printf("Nothing new to pack.\n");
+
+ /*
+ * Ok we have prepared all new packfiles.
+ * First see if there are packs of the same name and if so
+ * if we can move them out of the way (this can happen if we
+ * repacked immediately after packing fully.
+ */
+ failed = 0;
+ for_each_string_list_item(item, &names) {
+ for (ext = 0; ext < 2; ext++) {
+ char *fname, *fname_old;
+ fname = mkpathdup("%s/%s%s", packdir,
+ item->string, exts[ext]);
+ if (!file_exists(fname)) {
+ free(fname);
+ continue;
+ }
+
+ fname_old = mkpath("%s/old-%s%s", packdir,
+ item->string, exts[ext]);
+ if (file_exists(fname_old))
+ if (unlink(fname_old))
+ failed = 1;
+
+ if (!failed && rename(fname, fname_old)) {
+ free(fname);
+ failed = 1;
+ break;
+ } else {
+ string_list_append(&rollback, fname);
+ }
+ }
+ if (failed)
+ break;
+ }
+ if (failed) {
+ struct string_list rollback_failure = STRING_LIST_INIT_DUP;
+ for_each_string_list_item(item, &rollback) {
+ char *fname, *fname_old;
+ fname = mkpathdup("%s/%s", packdir, item->string);
+ fname_old = mkpath("%s/old-%s", packdir, item->string);
+ if (rename(fname_old, fname))
+ string_list_append(&rollback_failure, fname);
+ free(fname);
+ }
+
+ if (rollback_failure.nr) {
+ int i;
+ fprintf(stderr,
+ "WARNING: Some packs in use have been renamed by\n"
+ "WARNING: prefixing old- to their name, in order to\n"
+ "WARNING: replace them with the new version of the\n"
+ "WARNING: file. But the operation failed, and the\n"
+ "WARNING: attempt to rename them back to their\n"
+ "WARNING: original names also failed.\n"
+ "WARNING: Please rename them in %s manually:\n", packdir);
+ for (i = 0; i < rollback_failure.nr; i++)
+ fprintf(stderr, "WARNING: old-%s -> %s\n",
+ rollback_failure.items[i].string,
+ rollback_failure.items[i].string);
+ }
+ exit(1);
+ }
+
+ /* Now the ones with the same name are out of the way... */
+ for_each_string_list_item(item, &names) {
+ for (ext = 0; ext < 2; ext++) {
+ char *fname, *fname_old;
+ struct stat statbuffer;
+ fname = mkpathdup("%s/pack-%s%s",
+ packdir, item->string, exts[ext]);
+ fname_old = mkpathdup("%s-%s%s",
+ packtmp, item->string, exts[ext]);
+ if (!stat(fname_old, &statbuffer)) {
+ statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+ chmod(fname_old, statbuffer.st_mode);
+ }
+ if (rename(fname_old, fname))
+ die_errno(_("renaming '%s' failed"), fname_old);
+ free(fname);
+ free(fname_old);
+ }
+ }
+
+ /* Remove the "old-" files */
+ for_each_string_list_item(item, &names) {
+ for (ext = 0; ext < 2; ext++) {
+ char *fname;
+ fname = mkpath("%s/old-pack-%s%s",
+ packdir,
+ item->string,
+ exts[ext]);
+ if (remove_path(fname))
+ warning(_("removing '%s' failed"), fname);
+ }
+ }
+
+ /* End of pack replacement. */
+
+ if (delete_redundant) {
+ sort_string_list(&names);
+ for_each_string_list_item(item, &existing_packs) {
+ char *sha1;
+ size_t len = strlen(item->string);
+ if (len < 40)
+ continue;
+ sha1 = item->string + len - 40;
+ if (!string_list_has_string(&names, sha1))
+ remove_redundant_pack(packdir, item->string);
+ }
+ argv_array_push(&cmd_args, "prune-packed");
+ if (quiet)
+ argv_array_push(&cmd_args, "--quiet");
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.argv = cmd_args.argv;
+ cmd.git_cmd = 1;
+ run_command(&cmd);
+ argv_array_clear(&cmd_args);
+ }
+
+ if (!no_update_server_info) {
+ argv_array_push(&cmd_args, "update-server-info");
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.argv = cmd_args.argv;
+ cmd.git_cmd = 1;
+ run_command(&cmd);
+ argv_array_clear(&cmd_args);
+ }
+ remove_temporary_files();
+ string_list_clear(&names, 0);
+ string_list_clear(&rollback, 0);
+ string_list_clear(&existing_packs, 0);
+ strbuf_release(&line);
+
+ return 0;
+}
int force)
{
unsigned char object[20], prev[20], repl[20];
+ enum object_type obj_type, repl_type;
char ref[PATH_MAX];
struct ref_lock *lock;
if (check_refname_format(ref, 0))
die("'%s' is not a valid ref name.", ref);
+ obj_type = sha1_object_info(object, NULL);
+ repl_type = sha1_object_info(repl, NULL);
+ if (!force && obj_type != repl_type)
+ die("Objects must be of the same type.\n"
+ "'%s' points to a replaced object of type '%s'\n"
+ "while '%s' points to a replacement object of type '%s'.",
+ object_ref, typename(obj_type),
+ replace_ref, typename(repl_type));
+
if (read_ref(ref, prev))
hashclr(prev);
else if (!force)
die("replace ref '%s' already exists", ref);
- lock = lock_any_ref_for_update(ref, prev, 0);
+ lock = lock_any_ref_for_update(ref, prev, 0, NULL);
if (!lock)
die("%s: cannot lock the ref", ref);
if (write_ref_sha1(lock, repl, NULL) < 0)
{
int list = 0, delete = 0, force = 0;
struct option options[] = {
- 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_BOOL('l', "list", &list, N_("list replace refs")),
+ OPT_BOOL('d', "delete", &delete, N_("delete replace refs")),
+ OPT_BOOL('f', "force", &force, N_("replace the ref if it exists")),
OPT_END()
};
#include "rerere.h"
#include "xdiff/xdiff.h"
#include "xdiff-interface.h"
+#include "pathspec.h"
static const char * const rerere_usage[] = {
N_("git rerere [clear | forget path... | status | remaining | diff | gc]"),
return rerere(flags);
if (!strcmp(argv[0], "forget")) {
- const char **pathspec;
+ struct pathspec pathspec;
if (argc < 2)
warning("'git rerere forget' without paths is deprecated");
- pathspec = get_pathspec(prefix, argv + 1);
- return rerere_forget(pathspec);
+ parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD,
+ prefix, argv + 1);
+ return rerere_forget(&pathspec);
}
fd = setup_rerere(&merge_rr, flags);
}
}
-static int read_from_tree(const char **pathspec, unsigned char *tree_sha1)
+static int read_from_tree(const struct pathspec *pathspec,
+ unsigned char *tree_sha1)
{
struct diff_options opt;
memset(&opt, 0, sizeof(opt));
- diff_tree_setup_paths(pathspec, &opt);
+ copy_pathspec(&opt.pathspec, pathspec);
opt.output_format = DIFF_FORMAT_CALLBACK;
opt.format_callback = update_index_from_diff;
- read_cache();
if (do_diff_cache(tree_sha1, &opt))
return 1;
diffcore_std(&opt);
diff_flush(&opt);
- diff_tree_release_paths(&opt);
+ free_pathspec(&opt.pathspec);
return 0;
}
static void die_if_unmerged_cache(int reset_type)
{
- if (is_merge() || read_cache() < 0 || unmerged_cache())
+ if (is_merge() || unmerged_cache())
die(_("Cannot do a %s reset in the middle of a merge."),
_(reset_type_names[reset_type]));
}
-static const char **parse_args(const char **argv, const char *prefix, const char **rev_ret)
+static void parse_args(struct pathspec *pathspec,
+ const char **argv, const char *prefix,
+ int patch_mode,
+ const char **rev_ret)
{
const char *rev = "HEAD";
unsigned char unused[20];
}
}
*rev_ret = rev;
- return argv[0] ? get_pathspec(prefix, argv) : NULL;
+
+ if (read_cache() < 0)
+ die(_("index file corrupt"));
+
+ parse_pathspec(pathspec, 0,
+ PATHSPEC_PREFER_FULL |
+ PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP |
+ (patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0),
+ prefix, argv);
}
-static int update_refs(const char *rev, const unsigned char *sha1)
+static int reset_refs(const char *rev, const unsigned char *sha1)
{
int update_ref_status;
struct strbuf msg = STRBUF_INIT;
int patch_mode = 0, unborn;
const char *rev;
unsigned char sha1[20];
- const char **pathspec = NULL;
+ struct pathspec pathspec;
const struct option options[] = {
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
OPT_SET_INT(0, "mixed", &reset_type,
N_("reset HEAD, index and working tree"), MERGE),
OPT_SET_INT(0, "keep", &reset_type,
N_("reset HEAD but keep local changes"), KEEP),
- OPT_BOOLEAN('p', "patch", &patch_mode, N_("select hunks interactively")),
+ OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
OPT_END()
};
argc = parse_options(argc, argv, prefix, options, git_reset_usage,
PARSE_OPT_KEEP_DASHDASH);
- pathspec = parse_args(argv, prefix, &rev);
+ parse_args(&pathspec, argv, prefix, patch_mode, &rev);
unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", sha1);
if (unborn) {
/* reset on unborn branch: treat as reset to empty tree */
hashcpy(sha1, EMPTY_TREE_SHA1_BIN);
- } else if (!pathspec) {
+ } else if (!pathspec.nr) {
struct commit *commit;
if (get_sha1_committish(rev, sha1))
die(_("Failed to resolve '%s' as a valid revision."), rev);
if (patch_mode) {
if (reset_type != NONE)
die(_("--patch is incompatible with --{hard,mixed,soft}"));
- return run_add_interactive(sha1_to_hex(sha1), "--patch=reset", pathspec);
+ return run_add_interactive(sha1_to_hex(sha1), "--patch=reset", &pathspec);
}
/* git reset tree [--] paths... can be used to
* load chosen paths from the tree into the index without
* affecting the working tree nor HEAD. */
- if (pathspec) {
+ if (pathspec.nr) {
if (reset_type == MIXED)
warning(_("--mixed with paths is deprecated; use 'git reset -- <paths>' instead."));
else if (reset_type != NONE)
die_if_unmerged_cache(reset_type);
if (reset_type != SOFT) {
- struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
+ struct lock_file *lock = xcalloc(1, sizeof(*lock));
int newfd = hold_locked_index(lock, 1);
if (reset_type == MIXED) {
- if (read_from_tree(pathspec, sha1))
+ int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
+ if (read_from_tree(&pathspec, sha1))
return 1;
+ refresh_index(&the_index, flags, NULL, NULL,
+ _("Unstaged changes after reset:"));
} else {
int err = reset_index(sha1, reset_type, quiet);
if (reset_type == KEEP && !err)
die(_("Could not reset index file to revision '%s'."), rev);
}
- if (reset_type == MIXED) { /* Report what has not been updated. */
- int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
- refresh_index(&the_index, flags, NULL, NULL,
- _("Unstaged changes after reset:"));
- }
-
if (write_cache(newfd, active_cache, active_nr) ||
commit_locked_index(lock))
die(_("Could not write new index file."));
}
- if (!pathspec && !unborn) {
+ if (!pathspec.nr && !unborn) {
/* Any resets without paths update HEAD to the head being
* switched to, saving the previous head in ORIG_HEAD before. */
- update_ref_status = update_refs(rev, sha1);
+ update_ref_status = reset_refs(rev, sha1);
if (reset_type == HARD && !update_ref_status && !quiet)
print_new_head_line(lookup_commit_reference(sha1));
}
- if (!pathspec)
+ if (!pathspec.nr)
remove_branch_state();
return update_ref_status;
revs.commit_format = CMIT_FMT_RAW;
if ((!revs.commits &&
- (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) &&
+ (!(revs.tag_objects || revs.tree_objects || revs.blob_objects) &&
!revs.pending.nr)) ||
revs.diff)
usage(rev_list_usage);
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
if (revs.tree_objects)
- mark_edges_uninteresting(revs.commits, &revs, show_edge);
+ mark_edges_uninteresting(&revs, show_edge);
if (bisect_list) {
int reaches = reaches, all = all;
NULL
};
static struct option parseopt_opts[] = {
- OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
+ OPT_BOOL(0, "keep-dashdash", &keep_dashdash,
N_("keep the `--` passed as an arg")),
- OPT_BOOLEAN(0, "stop-at-non-option", &stop_at_non_option,
+ OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
N_("stop parsing after the "
"first non-option argument")),
OPT_END(),
if (argc > 1 && !strcmp("--sq-quote", argv[1]))
return cmd_sq_quote(argc - 2, argv + 2);
- if (argc == 2 && !strcmp("--local-env-vars", argv[1])) {
- int i;
- for (i = 0; local_repo_env[i]; i++)
- printf("%s\n", local_repo_env[i]);
- return 0;
- }
-
- if (argc > 2 && !strcmp(argv[1], "--resolve-git-dir")) {
- const char *gitdir = resolve_gitdir(argv[2]);
- if (!gitdir)
- die("not a gitdir '%s'", argv[2]);
- puts(gitdir);
- return 0;
- }
-
if (argc > 1 && !strcmp("-h", argv[1]))
usage(builtin_rev_parse_usage);
for_each_remote_ref(show_reference, NULL);
continue;
}
+ if (!strcmp(arg, "--local-env-vars")) {
+ int i;
+ for (i = 0; local_repo_env[i]; i++)
+ printf("%s\n", local_repo_env[i]);
+ continue;
+ }
if (!strcmp(arg, "--show-toplevel")) {
const char *work_tree = get_git_work_tree();
if (work_tree)
printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : "");
continue;
}
+ if (!strcmp(arg, "--resolve-git-dir")) {
+ const char *gitdir = resolve_gitdir(argv[i+1]);
+ if (!gitdir)
+ die("not a gitdir '%s'", argv[i+1]);
+ puts(gitdir);
+ continue;
+ }
if (!strcmp(arg, "--is-inside-git-dir")) {
printf("%s\n", is_inside_git_dir() ? "true"
: "false");
die(_("%s: %s cannot be used with %s"), me, this_opt, base_opt);
}
-LAST_ARG_MUST_BE_NULL
-static void verify_opt_mutually_compatible(const char *me, ...)
-{
- const char *opt1, *opt2 = NULL;
- va_list ap;
-
- va_start(ap, me);
- while ((opt1 = va_arg(ap, const char *))) {
- if (va_arg(ap, int))
- break;
- }
- if (opt1) {
- while ((opt2 = va_arg(ap, const char *))) {
- if (va_arg(ap, int))
- break;
- }
- }
- va_end(ap);
-
- if (opt1 && opt2)
- die(_("%s: %s cannot be used with %s"), me, opt1, opt2);
-}
-
static void parse_args(int argc, const char **argv, struct replay_opts *opts)
{
const char * const * usage_str = revert_or_cherry_pick_usage(opts);
const char *me = action_name(opts);
- int remove_state = 0;
- int contin = 0;
- int rollback = 0;
+ int cmd = 0;
struct option options[] = {
- 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_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
+ OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
+ OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
+ OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
+ OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
OPT_NOOP_NOARG('r', NULL),
- OPT_BOOLEAN('s', "signoff", &opts->signoff, N_("add Signed-off-by:")),
+ OPT_BOOL('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, N_("strategy"), N_("merge strategy")),
if (opts->action == REPLAY_PICK) {
struct option cp_extra[] = {
- 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_BOOL('x', NULL, &opts->record_origin, N_("append commit name")),
+ OPT_BOOL(0, "ff", &opts->allow_ff, N_("allow fast-forward")),
+ OPT_BOOL(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")),
+ OPT_BOOL(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")),
+ OPT_BOOL(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))
PARSE_OPT_KEEP_ARGV0 |
PARSE_OPT_KEEP_UNKNOWN);
- /* Check for incompatible subcommands */
- verify_opt_mutually_compatible(me,
- "--quit", remove_state,
- "--continue", contin,
- "--abort", rollback,
- NULL);
-
/* implies allow_empty */
if (opts->keep_redundant_commits)
opts->allow_empty = 1;
/* Set the subcommand */
- if (remove_state)
+ if (cmd == 'q')
opts->subcommand = REPLAY_REMOVE_STATE;
- else if (contin)
+ else if (cmd == 'c')
opts->subcommand = REPLAY_CONTINUE;
- else if (rollback)
+ else if (cmd == 'a')
opts->subcommand = REPLAY_ROLLBACK;
else
opts->subcommand = REPLAY_NONE;
opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
if (argc < 2)
usage_with_options(usage_str, options);
+ if (!strcmp(argv[1], "-"))
+ argv[1] = "@{-1}";
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.assume_dashdash = 1;
argc = setup_revisions(argc, argv, opts->revs, &s_r_opt);
#include "parse-options.h"
#include "string-list.h"
#include "submodule.h"
+#include "pathspec.h"
static const char * const builtin_rm_usage[] = {
N_("git rm [options] [--] <file>..."),
static struct option builtin_rm_options[] = {
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_BOOL( 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,
+ OPT_BOOL('r', NULL, &recursive, N_("allow recursive removal")),
+ OPT_BOOL( 0 , "ignore-unmatch", &ignore_unmatch,
N_("exit with a zero status even if nothing matched")),
OPT_END(),
};
int cmd_rm(int argc, const char **argv, const char *prefix)
{
int i, newfd;
- const char **pathspec;
+ struct pathspec pathspec;
char *seen;
+ gitmodules_config();
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_rm_options,
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);
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_CWD |
+ PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
+ prefix, argv);
+ refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);
- seen = NULL;
- for (i = 0; pathspec[i] ; i++)
- /* nothing */;
- seen = xcalloc(i, 1);
+ seen = xcalloc(pathspec.nr, 1);
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
- if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
+ if (!match_pathspec_depth(&pathspec, ce->name, ce_namelen(ce), 0, seen))
continue;
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);
+ list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
+ if (list.entry[list.nr++].is_submodule &&
+ !is_staging_gitmodules_ok())
+ die (_("Please, stage your changes to .gitmodules or stash them to proceed"));
}
- if (pathspec) {
- const char *match;
+ if (pathspec.nr) {
+ const char *original;
int seen_any = 0;
- for (i = 0; (match = pathspec[i]) != NULL ; i++) {
+ for (i = 0; i < pathspec.nr; i++) {
+ original = pathspec.items[i].original;
if (!seen[i]) {
if (!ignore_unmatch) {
die(_("pathspec '%s' did not match any files"),
- match);
+ original);
}
}
else {
}
if (!recursive && seen[i] == MATCHED_RECURSIVELY)
die(_("not removing '%s' recursively without -r"),
- *match ? match : ".");
+ *original ? original : ".");
}
- if (! seen_any)
+ if (!seen_any)
exit(0);
}
* in the middle)
*/
if (!index_only) {
- int removed = 0;
+ int removed = 0, gitmodules_modified = 0;
for (i = 0; i < list.nr; i++) {
const char *path = list.entry[i].name;
if (list.entry[i].is_submodule) {
if (is_empty_dir(path)) {
if (!rmdir(path)) {
removed = 1;
+ if (!remove_path_from_gitmodules(path))
+ gitmodules_modified = 1;
continue;
}
} else {
strbuf_addstr(&buf, path);
if (!remove_dir_recursively(&buf, 0)) {
removed = 1;
+ if (!remove_path_from_gitmodules(path))
+ gitmodules_modified = 1;
strbuf_release(&buf);
continue;
- }
+ } else if (!file_exists(path))
+ /* Submodule was removed by user */
+ if (!remove_path_from_gitmodules(path))
+ gitmodules_modified = 1;
strbuf_release(&buf);
/* Fallthrough and let remove_path() fail. */
}
if (!removed)
die_errno("git rm: '%s'", path);
}
+ if (gitmodules_modified)
+ stage_updated_gitmodules();
}
if (active_cache_changed) {
#include "sideband.h"
#include "run-command.h"
#include "remote.h"
+#include "connect.h"
#include "send-pack.h"
#include "quote.h"
#include "transport.h"
msg = "needs force";
break;
+ case REF_STATUS_REJECT_STALE:
+ res = "error";
+ msg = "stale info";
+ break;
+
case REF_STATUS_REJECT_ALREADY_EXISTS:
res = "error";
msg = "already exists";
int flags;
unsigned int reject_reasons;
int progress = -1;
+ struct push_cas_option cas = {0};
argv++;
for (i = 1; i < argc; i++, argv++) {
helper_status = 1;
continue;
}
+ if (!strcmp(arg, "--" CAS_OPT_NAME)) {
+ if (parse_push_cas_option(&cas, NULL, 0) < 0)
+ exit(1);
+ continue;
+ }
+ if (!strcmp(arg, "--no-" CAS_OPT_NAME)) {
+ if (parse_push_cas_option(&cas, NULL, 1) < 0)
+ exit(1);
+ continue;
+ }
+ if (!prefixcmp(arg, "--" CAS_OPT_NAME "=")) {
+ if (parse_push_cas_option(&cas,
+ strchr(arg, '=') + 1, 0) < 0)
+ exit(1);
+ continue;
+ }
usage(send_pack_usage);
}
if (!dest) {
if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
return -1;
+ if (!is_empty_cas(&cas))
+ apply_push_cas(&cas, remote, remote_refs);
+
set_ref_status_for_push(remote_refs, args.send_mirror,
args.force_update);
author = buffer + 7;
buffer = eol;
}
- if (!author)
- die(_("Missing author: %s"),
+ if (!author) {
+ warning(_("Missing author: %s"),
sha1_to_hex(commit->object.sha1));
+ return;
+ }
if (log->user_format) {
struct pretty_print_context ctx = {0};
ctx.fmt = CMIT_FMT_USERFORMAT;
int nongit = !startup_info->have_repository;
static const struct option options[] = {
- OPT_BOOLEAN('n', "numbered", &log.sort_by_number,
- N_("sort output according to the number of commits per author")),
- OPT_BOOLEAN('s', "summary", &log.summary,
- N_("Suppress commit descriptions, only provides commit count")),
- OPT_BOOLEAN('e', "email", &log.email,
- N_("Show the email address of each author")),
+ OPT_BOOL('n', "numbered", &log.sort_by_number,
+ N_("sort output according to the number of commits per author")),
+ OPT_BOOL('s', "summary", &log.summary,
+ N_("Suppress commit descriptions, only provides commit count")),
+ OPT_BOOL('e', "email", &log.email,
+ 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(),
int dense = 1;
const char *reflog_base = NULL;
struct option builtin_show_branch_options[] = {
- OPT_BOOLEAN('a', "all", &all_heads,
- N_("show remote-tracking and local branches")),
- OPT_BOOLEAN('r', "remotes", &all_remotes,
- N_("show remote-tracking branches")),
+ OPT_BOOL('a', "all", &all_heads,
+ N_("show remote-tracking and local branches")),
+ OPT_BOOL('r', "remotes", &all_remotes,
+ N_("show remote-tracking branches")),
OPT__COLOR(&showbranch_use_color,
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, N_("synonym to more=-1"), -1),
- OPT_BOOLEAN(0, "no-name", &no_name, N_("suppress naming strings")),
- OPT_BOOLEAN(0, "current", &with_current_branch,
- N_("include the current branch")),
- OPT_BOOLEAN(0, "sha1-name", &sha1_name,
- N_("name commits with their object names")),
- OPT_BOOLEAN(0, "merge-base", &merge_base,
- N_("show possible merge bases")),
- OPT_BOOLEAN(0, "independent", &independent,
+ OPT_BOOL(0, "no-name", &no_name, N_("suppress naming strings")),
+ OPT_BOOL(0, "current", &with_current_branch,
+ N_("include the current branch")),
+ OPT_BOOL(0, "sha1-name", &sha1_name,
+ N_("name commits with their object names")),
+ OPT_BOOL(0, "merge-base", &merge_base,
+ N_("show possible merge bases")),
+ OPT_BOOL(0, "independent", &independent,
N_("show refs unreachable from any other ref")),
OPT_SET_INT(0, "topo-order", &sort_order,
N_("show commits in topological order"),
REV_SORT_IN_GRAPH_ORDER),
- OPT_BOOLEAN(0, "topics", &topics,
- N_("show only commits not on the first branch")),
+ OPT_BOOL(0, "topics", &topics,
+ N_("show only commits not on the first branch")),
OPT_SET_INT(0, "sparse", &dense,
N_("show merges reachable from only one tip"), 0),
OPT_SET_INT(0, "date-order", &sort_order,
}
static const struct option show_ref_options[] = {
- 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, "
+ OPT_BOOL(0, "tags", &tags_only, N_("only show tags (can be combined with heads)")),
+ OPT_BOOL(0, "heads", &heads_only, N_("only show heads (can be combined with tags)")),
+ OPT_BOOL(0, "verify", &verify, N_("stricter reference checking, "
"requires exact ref path")),
- { OPTION_BOOLEAN, 'h', NULL, &show_head, NULL,
- N_("show the HEAD reference, even if it would be filtered out"),
- PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
- OPT_BOOLEAN(0, "head", &show_head,
+ OPT_HIDDEN_BOOL('h', NULL, &show_head,
+ N_("show the HEAD reference, even if it would be filtered out")),
+ OPT_BOOL(0, "head", &show_head,
N_("show the HEAD reference, even if it would be filtered out")),
- OPT_BOOLEAN('d', "dereference", &deref_tags,
+ OPT_BOOL('d', "dereference", &deref_tags,
N_("dereference tags into object IDs")),
{ OPTION_CALLBACK, 's', "hash", &abbrev, N_("n"),
N_("only show SHA1 hash using <n> digits"),
if (argc == 2) {
if (!strcmp(argv[1], "-s") ||
- !strcmp(argv[1], "--strip-comments")) {
- strip_comments = 1;
+ !strcmp(argv[1], "--strip-comments")) {
+ strip_comments = 1;
} else if (!strcmp(argv[1], "-c") ||
- !strcmp(argv[1], "--comment-lines")) {
- mode = COMMENT_LINES;
+ !strcmp(argv[1], "--comment-lines")) {
+ mode = COMMENT_LINES;
} else {
mode = INVAL;
}
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options,
git_symbolic_ref_usage, 0);
- if (msg &&!*msg)
+ if (msg && !*msg)
die("Refusing to perform update with empty message");
if (delete) {
struct ref_lock *lock;
struct create_tag_options opt;
char *cleanup_arg = NULL;
- int annotate = 0, force = 0, lines = -1, list = 0,
- delete = 0, verify = 0;
+ int annotate = 0, force = 0, lines = -1;
+ int cmdmode = 0;
const char *msgfile = NULL, *keyid = NULL;
struct msg_arg msg = { 0, STRBUF_INIT };
struct commit_list *with_commit = NULL;
struct option options[] = {
- OPT_BOOLEAN('l', "list", &list, N_("list tag names")),
+ OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
{ 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, N_("delete tags")),
- OPT_BOOLEAN('v', "verify", &verify, N_("verify tags")),
+ OPT_CMDMODE('d', "delete", &cmdmode, N_("delete tags"), 'd'),
+ OPT_CMDMODE('v', "verify", &cmdmode, N_("verify tags"), 'v'),
OPT_GROUP(N_("Tag creation options")),
- OPT_BOOLEAN('a', "annotate", &annotate,
+ OPT_BOOL('a', "annotate", &annotate,
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_BOOL('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"),
}
if (opt.sign)
annotate = 1;
- if (argc == 0 && !(delete || verify))
- list = 1;
+ if (argc == 0 && !cmdmode)
+ cmdmode = 'l';
- if ((annotate || msg.given || msgfile || force) &&
- (list || delete || verify))
+ if ((annotate || msg.given || msgfile || force) && (cmdmode != 0))
usage_with_options(git_tag_usage, options);
- if (list + delete + verify > 1)
- usage_with_options(git_tag_usage, options);
finalize_colopts(&colopts, -1);
- if (list && lines != -1) {
+ if (cmdmode == 'l' && lines != -1) {
if (explicitly_enable_column(colopts))
die(_("--column and -n are incompatible"));
colopts = 0;
}
- if (list) {
+ if (cmdmode == 'l') {
int ret;
if (column_active(colopts)) {
struct column_options copts;
die(_("--contains option is only allowed with -l."));
if (points_at.nr)
die(_("--points-at option is only allowed with -l."));
- if (delete)
+ if (cmdmode == 'd')
return for_each_tag_name(argv, delete_tag);
- if (verify)
+ if (cmdmode == 'v')
return for_each_tag_name(argv, verify_tag);
if (msg.given || msgfile) {
if (annotate)
create_tag(object, tag, &buf, &opt, prev, object);
- lock = lock_any_ref_for_update(ref.buf, prev, 0);
+ lock = lock_any_ref_for_update(ref.buf, prev, 0, NULL);
if (!lock)
die(_("%s: cannot lock the ref"), ref.buf);
if (write_ref_sha1(lock, object, NULL) < 0)
* $0 tree-ish basedir ==>
* git archive --format-tar --prefix=basedir tree-ish
*/
- int i;
const char **nargv = xcalloc(sizeof(*nargv), argc + 3);
+ struct strbuf sb = STRBUF_INIT;
char *basedir_arg;
int nargc = 0;
fprintf(stderr,
"*** \"git tar-tree\" is now deprecated.\n"
"*** Running \"git archive\" instead.\n***");
- for (i = 0; i < nargc; i++) {
- fputc(' ', stderr);
- sq_quote_print(stderr, nargv[i]);
- }
- fputc('\n', stderr);
+ sq_quote_argv(&sb, nargv, 0);
+ strbuf_addch(&sb, '\n');
+ fputs(sb.buf, stderr);
+ strbuf_release(&sb);
return cmd_archive(nargc, nargv, prefix);
}
#include "refs.h"
#include "resolve-undo.h"
#include "parse-options.h"
+#include "pathspec.h"
/*
* Default to not allowing changes to the list of files. The
*/
int pos;
int has_head = 1;
- const char **paths = get_pathspec(prefix, av + 1);
struct pathspec pathspec;
- init_pathspec(&pathspec, paths);
+ parse_pathspec(&pathspec, 0,
+ PATHSPEC_PREFER_CWD,
+ prefix, av + 1);
if (read_ref("HEAD", head_sha1))
/* If there is no HEAD, that means it is an initial
#include "refs.h"
#include "builtin.h"
#include "parse-options.h"
+#include "quote.h"
+#include "argv-array.h"
static const char * const git_update_ref_usage[] = {
N_("git update-ref [options] -d <refname> [<oldval>]"),
N_("git update-ref [options] <refname> <newval> [<oldval>]"),
+ N_("git update-ref [options] --stdin [-z]"),
NULL
};
+static int updates_alloc;
+static int updates_count;
+static const struct ref_update **updates;
+
+static char line_termination = '\n';
+static int update_flags;
+
+static struct ref_update *update_alloc(void)
+{
+ struct ref_update *update;
+
+ /* Allocate and zero-init a struct ref_update */
+ update = xcalloc(1, sizeof(*update));
+ ALLOC_GROW(updates, updates_count + 1, updates_alloc);
+ updates[updates_count++] = update;
+
+ /* Store and reset accumulated options */
+ update->flags = update_flags;
+ update_flags = 0;
+
+ return update;
+}
+
+static void update_store_ref_name(struct ref_update *update,
+ const char *ref_name)
+{
+ if (check_refname_format(ref_name, REFNAME_ALLOW_ONELEVEL))
+ die("invalid ref format: %s", ref_name);
+ update->ref_name = xstrdup(ref_name);
+}
+
+static void update_store_new_sha1(struct ref_update *update,
+ const char *newvalue)
+{
+ if (*newvalue && get_sha1(newvalue, update->new_sha1))
+ die("invalid new value for ref %s: %s",
+ update->ref_name, newvalue);
+}
+
+static void update_store_old_sha1(struct ref_update *update,
+ const char *oldvalue)
+{
+ if (*oldvalue && get_sha1(oldvalue, update->old_sha1))
+ die("invalid old value for ref %s: %s",
+ update->ref_name, oldvalue);
+
+ /* We have an old value if non-empty, or if empty without -z */
+ update->have_old = *oldvalue || line_termination;
+}
+
+static const char *parse_arg(const char *next, struct strbuf *arg)
+{
+ /* Parse SP-terminated, possibly C-quoted argument */
+ if (*next != '"')
+ while (*next && !isspace(*next))
+ strbuf_addch(arg, *next++);
+ else if (unquote_c_style(arg, next, &next))
+ die("badly quoted argument: %s", next);
+
+ /* Return position after the argument */
+ return next;
+}
+
+static const char *parse_first_arg(const char *next, struct strbuf *arg)
+{
+ /* Parse argument immediately after "command SP" */
+ strbuf_reset(arg);
+ if (line_termination) {
+ /* Without -z, use the next argument */
+ next = parse_arg(next, arg);
+ } else {
+ /* With -z, use rest of first NUL-terminated line */
+ strbuf_addstr(arg, next);
+ next = next + arg->len;
+ }
+ return next;
+}
+
+static const char *parse_next_arg(const char *next, struct strbuf *arg)
+{
+ /* Parse next SP-terminated or NUL-terminated argument, if any */
+ strbuf_reset(arg);
+ if (line_termination) {
+ /* Without -z, consume SP and use next argument */
+ if (!*next)
+ return NULL;
+ if (*next != ' ')
+ die("expected SP but got: %s", next);
+ next = parse_arg(next + 1, arg);
+ } else {
+ /* With -z, read the next NUL-terminated line */
+ if (*next)
+ die("expected NUL but got: %s", next);
+ if (strbuf_getline(arg, stdin, '\0') == EOF)
+ return NULL;
+ next = arg->buf + arg->len;
+ }
+ return next;
+}
+
+static void parse_cmd_update(const char *next)
+{
+ struct strbuf ref = STRBUF_INIT;
+ struct strbuf newvalue = STRBUF_INIT;
+ struct strbuf oldvalue = STRBUF_INIT;
+ struct ref_update *update;
+
+ update = update_alloc();
+
+ if ((next = parse_first_arg(next, &ref)) != NULL && ref.buf[0])
+ update_store_ref_name(update, ref.buf);
+ else
+ die("update line missing <ref>");
+
+ if ((next = parse_next_arg(next, &newvalue)) != NULL)
+ update_store_new_sha1(update, newvalue.buf);
+ else
+ die("update %s missing <newvalue>", ref.buf);
+
+ if ((next = parse_next_arg(next, &oldvalue)) != NULL)
+ update_store_old_sha1(update, oldvalue.buf);
+ else if(!line_termination)
+ die("update %s missing [<oldvalue>] NUL", ref.buf);
+
+ if (next && *next)
+ die("update %s has extra input: %s", ref.buf, next);
+}
+
+static void parse_cmd_create(const char *next)
+{
+ struct strbuf ref = STRBUF_INIT;
+ struct strbuf newvalue = STRBUF_INIT;
+ struct ref_update *update;
+
+ update = update_alloc();
+
+ if ((next = parse_first_arg(next, &ref)) != NULL && ref.buf[0])
+ update_store_ref_name(update, ref.buf);
+ else
+ die("create line missing <ref>");
+
+ if ((next = parse_next_arg(next, &newvalue)) != NULL)
+ update_store_new_sha1(update, newvalue.buf);
+ else
+ die("create %s missing <newvalue>", ref.buf);
+ if (is_null_sha1(update->new_sha1))
+ die("create %s given zero new value", ref.buf);
+
+ if (next && *next)
+ die("create %s has extra input: %s", ref.buf, next);
+}
+
+static void parse_cmd_delete(const char *next)
+{
+ struct strbuf ref = STRBUF_INIT;
+ struct strbuf oldvalue = STRBUF_INIT;
+ struct ref_update *update;
+
+ update = update_alloc();
+
+ if ((next = parse_first_arg(next, &ref)) != NULL && ref.buf[0])
+ update_store_ref_name(update, ref.buf);
+ else
+ die("delete line missing <ref>");
+
+ if ((next = parse_next_arg(next, &oldvalue)) != NULL)
+ update_store_old_sha1(update, oldvalue.buf);
+ else if(!line_termination)
+ die("delete %s missing [<oldvalue>] NUL", ref.buf);
+ if (update->have_old && is_null_sha1(update->old_sha1))
+ die("delete %s given zero old value", ref.buf);
+
+ if (next && *next)
+ die("delete %s has extra input: %s", ref.buf, next);
+}
+
+static void parse_cmd_verify(const char *next)
+{
+ struct strbuf ref = STRBUF_INIT;
+ struct strbuf value = STRBUF_INIT;
+ struct ref_update *update;
+
+ update = update_alloc();
+
+ if ((next = parse_first_arg(next, &ref)) != NULL && ref.buf[0])
+ update_store_ref_name(update, ref.buf);
+ else
+ die("verify line missing <ref>");
+
+ if ((next = parse_next_arg(next, &value)) != NULL) {
+ update_store_old_sha1(update, value.buf);
+ update_store_new_sha1(update, value.buf);
+ } else if(!line_termination)
+ die("verify %s missing [<oldvalue>] NUL", ref.buf);
+
+ if (next && *next)
+ die("verify %s has extra input: %s", ref.buf, next);
+}
+
+static void parse_cmd_option(const char *next)
+{
+ if (!strcmp(next, "no-deref"))
+ update_flags |= REF_NODEREF;
+ else
+ die("option unknown: %s", next);
+}
+
+static void update_refs_stdin(void)
+{
+ struct strbuf cmd = STRBUF_INIT;
+
+ /* Read each line dispatch its command */
+ while (strbuf_getline(&cmd, stdin, line_termination) != EOF)
+ if (!cmd.buf[0])
+ die("empty command in input");
+ else if (isspace(*cmd.buf))
+ die("whitespace before command: %s", cmd.buf);
+ else if (!prefixcmp(cmd.buf, "update "))
+ parse_cmd_update(cmd.buf + 7);
+ else if (!prefixcmp(cmd.buf, "create "))
+ parse_cmd_create(cmd.buf + 7);
+ else if (!prefixcmp(cmd.buf, "delete "))
+ parse_cmd_delete(cmd.buf + 7);
+ else if (!prefixcmp(cmd.buf, "verify "))
+ parse_cmd_verify(cmd.buf + 7);
+ else if (!prefixcmp(cmd.buf, "option "))
+ parse_cmd_option(cmd.buf + 7);
+ else
+ die("unknown command: %s", cmd.buf);
+
+ strbuf_release(&cmd);
+}
+
int cmd_update_ref(int argc, const char **argv, const char *prefix)
{
const char *refname, *oldval, *msg = NULL;
unsigned char sha1[20], oldsha1[20];
- int delete = 0, no_deref = 0, flags = 0;
+ int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0, flags = 0;
struct option options[] = {
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,
+ OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
+ OPT_BOOL( 0 , "no-deref", &no_deref,
N_("update <refname> not the one it points to")),
+ OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")),
+ OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")),
OPT_END(),
};
if (msg && !*msg)
die("Refusing to perform update with empty message.");
+ if (read_stdin) {
+ if (delete || no_deref || argc > 0)
+ usage_with_options(git_update_ref_usage, options);
+ if (end_null)
+ line_termination = '\0';
+ update_refs_stdin();
+ return update_refs(msg, updates, updates_count, DIE_ON_ERR);
+ }
+
+ if (end_null)
+ usage_with_options(git_update_ref_usage, options);
+
if (delete) {
if (argc < 1 || argc > 2)
usage_with_options(git_update_ref_usage, options);
if (size && !s.avail_in) {
ssize_t rsize = size < sizeof(ibuf) ? size : sizeof(ibuf);
- if (xread(fd, ibuf, rsize) != rsize)
+ if (read_in_full(fd, ibuf, rsize) != rsize)
die("failed to read %d bytes from '%s'",
(int)rsize, path);
offset += rsize;
#define CACHE_SIGNATURE 0x44495243 /* "DIRC" */
struct cache_header {
- unsigned int hdr_signature;
- unsigned int hdr_version;
- unsigned int hdr_entries;
+ uint32_t hdr_signature;
+ uint32_t hdr_version;
+ uint32_t hdr_entries;
};
#define INDEX_FORMAT_LB 2
* check it for equality in the 32 bits we save.
*/
struct cache_time {
- unsigned int sec;
- unsigned int nsec;
+ uint32_t sec;
+ uint32_t nsec;
};
struct stat_data {
#error "CE_EXTENDED_FLAGS out of range"
#endif
+struct pathspec;
+
/*
* Copy the sha1 and stat state of a cache entry from one to
* another. But we never change the name, or the hash state!
#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL)
#define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
#define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
+#define cache_dir_exists(name, namelen) index_dir_exists(&the_index, (name), (namelen))
+#define cache_file_exists(name, namelen, igncase) index_file_exists(&the_index, (name), (namelen), (igncase))
#define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
#define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
#define resolve_undo_clear() resolve_undo_clear_index(&the_index)
#define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF"
#define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE"
#define GIT_LITERAL_PATHSPECS_ENVIRONMENT "GIT_LITERAL_PATHSPECS"
+#define GIT_GLOB_PATHSPECS_ENVIRONMENT "GIT_GLOB_PATHSPECS"
+#define GIT_NOGLOB_PATHSPECS_ENVIRONMENT "GIT_NOGLOB_PATHSPECS"
+#define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
/*
* This environment variable is expected to contain a boolean indicating
extern const char *setup_git_directory_gently(int *);
extern const char *setup_git_directory(void);
extern char *prefix_path(const char *prefix, int len, const char *path);
+extern char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path);
extern const char *prefix_filename(const char *prefix, int len, const char *path);
extern int check_filename(const char *prefix, const char *name);
extern void verify_filename(const char *prefix,
/* Initialize and use the cache information */
extern int read_index(struct index_state *);
-extern int read_index_preload(struct index_state *, const char **pathspec);
+extern int read_index_preload(struct index_state *, const struct pathspec *pathspec);
extern int read_index_from(struct index_state *, const char *path);
extern int is_index_unborn(struct index_state *);
extern int read_index_unmerged(struct index_state *);
extern int discard_index(struct index_state *);
extern int unmerged_index(const struct index_state *);
extern int verify_path(const char *path);
+extern struct cache_entry *index_dir_exists(struct index_state *istate, const char *name, int namelen);
+extern struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
extern struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int igncase);
extern int index_name_pos(const struct index_state *, const char *name, int namelen);
#define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */
extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
-#define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */
-
-struct pathspec {
- const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
- int nr;
- unsigned int has_wildcard:1;
- unsigned int recursive:1;
- int max_depth;
- struct pathspec_item {
- const char *match;
- int len;
- int nowildcard_len;
- int flags;
- } *items;
-};
-
-extern int init_pathspec(struct pathspec *, const char **);
-extern void free_pathspec(struct pathspec *);
extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
-extern int limit_pathspec_to_literal(void);
-
#define HASH_WRITE_OBJECT 1
#define HASH_FORMAT_CHECK 2
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
#define REFRESH_IGNORE_MISSING 0x0008 /* ignore non-existent */
#define REFRESH_IGNORE_SUBMODULES 0x0010 /* ignore submodules */
#define REFRESH_IN_PORCELAIN 0x0020 /* user friendly output, not "needs update" */
-extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, const char *header_msg);
+extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
struct lock_file {
struct lock_file *next;
const char *real_path(const char *path);
const char *real_path_if_valid(const char *path);
const char *absolute_path(const char *path);
+const char *remove_leading_path(const char *in, const char *prefix);
const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
+int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
int normalize_path_copy(char *dst, const char *src);
int longest_ancestor_length(const char *path, struct string_list *prefixes);
char *strip_path_suffix(const char *path, const char *suffix);
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
-extern int interpret_branch_name(const char *str, struct strbuf *);
+extern int interpret_branch_name(const char *str, int len, struct strbuf *);
extern int get_sha1_mb(const char *str, unsigned char *sha1);
extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
*/
extern int split_ident_line(struct ident_split *, const char *, int);
+/*
+ * Compare split idents for equality or strict ordering. Note that we
+ * compare only the ident part of the line, ignoring any timestamp.
+ *
+ * Because there are two fields, we must choose one as the primary key; we
+ * currently arbitrarily pick the email.
+ */
+extern int ident_cmp(const struct ident_split *, const struct ident_split *);
+
struct checkout {
const char *base_dir;
int base_dir_len;
refresh_cache:1;
};
+#define TEMPORARY_FILENAME_LENGTH 25
extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
struct cache_def {
struct packed_git *p;
};
-struct ref {
- struct ref *next;
- unsigned char old_sha1[20];
- unsigned char new_sha1[20];
- char *symref;
- unsigned int
- force:1,
- forced_update:1,
- deletion:1,
- matched:1;
-
- /*
- * Order is important here, as we write to FETCH_HEAD
- * in numeric order. And the default NOT_FOR_MERGE
- * should be 0, so that xcalloc'd structures get it
- * by default.
- */
- enum {
- FETCH_HEAD_MERGE = -1,
- FETCH_HEAD_NOT_FOR_MERGE = 0,
- FETCH_HEAD_IGNORE = 1
- } fetch_head_status;
-
- enum {
- REF_STATUS_NONE = 0,
- REF_STATUS_OK,
- REF_STATUS_REJECT_NONFASTFORWARD,
- REF_STATUS_REJECT_ALREADY_EXISTS,
- REF_STATUS_REJECT_NODELETE,
- REF_STATUS_REJECT_FETCH_FIRST,
- REF_STATUS_REJECT_NEEDS_FORCE,
- REF_STATUS_UPTODATE,
- REF_STATUS_REMOTE_REJECT,
- REF_STATUS_EXPECTING_REPORT
- } status;
- char *remote_status;
- struct ref *peer_ref; /* when renaming */
- char name[FLEX_ARRAY]; /* more */
-};
-
-#define REF_NORMAL (1u << 0)
-#define REF_HEADS (1u << 1)
-#define REF_TAGS (1u << 2)
-
-extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
-
-#define CONNECT_VERBOSE (1u << 0)
-extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
-extern int finish_connect(struct child_process *conn);
-extern int git_connection_is_socket(struct child_process *conn);
-struct extra_have_objects {
- int nr, alloc;
- unsigned char (*array)[20];
-};
-extern struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
- struct ref **list, unsigned int flags,
- struct extra_have_objects *);
-extern int server_supports(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);
/* A hook for count-objects to report invalid files in pack directory */
extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
extern int git_parse_ulong(const char *, unsigned long *);
extern int git_config_int(const char *, const char *);
+extern int64_t git_config_int64(const char *, const char *);
extern unsigned long git_config_ulong(const char *, const char *);
extern int git_config_bool_or_int(const char *, const char *, int *);
extern int git_config_bool(const char *, const char *);
* return 0 if success, 1 - if addition of a file failed and
* ADD_FILES_IGNORE_ERRORS was specified in flags
*/
-int add_files_to_cache(const char *prefix, const char **pathspec, int flags);
+int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags);
/* diff.c */
extern int diff_auto_refresh_index;
#define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK)
/* ls-files */
-int report_path_error(const char *ps_matched, const char **pathspec, const char *prefix);
+int report_path_error(const char *ps_matched, const struct pathspec *pathspec, const char *prefix);
void overlay_tree_on_cache(const char *tree_name, const char *prefix);
char *alias_lookup(const char *alias);
#include "refs.h"
#include "userdiff.h"
#include "sha1-array.h"
+#include "revision.h"
static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
{
int i, num_paths, needsep, show_log_first, num_parent = parents->nr;
diffopts = *opt;
- diff_tree_setup_paths(diffopts.pathspec.raw, &diffopts);
+ copy_pathspec(&diffopts.pathspec, &opt->pathspec);
diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
DIFF_OPT_SET(&diffopts, RECURSIVE);
DIFF_OPT_CLR(&diffopts, ALLOW_EXTERNAL);
free(tmp);
}
- diff_tree_release_paths(&diffopts);
+ free_pathspec(&diffopts.pathspec);
}
void diff_tree_combined_merge(const struct commit *commit, int dense,
struct rev_info *rev)
{
- struct commit_list *parent = commit->parents;
+ struct commit_list *parent = get_saved_parents(rev, commit);
struct sha1_array parents = SHA1_ARRAY_INIT;
while (parent) {
return c;
}
+struct commit_list *copy_commit_list(struct commit_list *list)
+{
+ struct commit_list *head = NULL;
+ struct commit_list **pp = &head;
+ while (list) {
+ struct commit_list *new;
+ new = xmalloc(sizeof(struct commit_list));
+ new->item = list->item;
+ new->next = NULL;
+ *pp = new;
+ pp = &new->next;
+ list = list->next;
+ }
+ return head;
+}
+
void free_commit_list(struct commit_list *list)
{
while (list) {
struct commit_list **list);
void commit_list_sort_by_date(struct commit_list **list);
+/* Shallow copy of the input list */
+struct commit_list *copy_commit_list(struct commit_list *list);
+
void free_commit_list(struct commit_list *list);
/* Commit formats */
int depth, int shallow_flag, int not_shallow_flag);
extern void check_shallow_file_for_update(void);
extern void set_alternate_shallow_file(const char *path);
+extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol);
+extern void setup_alternate_shallow(struct lock_file *shallow_lock,
+ const char **alternate_shallow_file);
+extern char *setup_temporary_shallow(void);
int is_descendant_of(struct commit *, struct commit_list *);
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,
- const char **pathspec);
+ const struct pathspec *pathspec);
static inline int single_parent(struct commit *commit)
{
--- /dev/null
+/* suppress inclusion of conflicting openssl functions */
+#define OPENSSL_NO_MD5
+#define HEADER_HMAC_H
+#define HEADER_SHA_H
+#include <CommonCrypto/CommonHMAC.h>
+#define HMAC_CTX CCHmacContext
+#define HMAC_Init(hmac, key, len, algo) CCHmacInit(hmac, algo, key, len)
+#define HMAC_Update CCHmacUpdate
+#define HMAC_Final(hmac, hash, ptr) CCHmacFinal(hmac, hash)
+#define HMAC_CTX_cleanup(ignore)
+#define EVP_md5(...) kCCHmacAlgMD5
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+#define APPLE_LION_OR_NEWER
+#include <Security/Security.h>
+/* Apple's TYPE_BOOL conflicts with config.c */
+#undef TYPE_BOOL
+#endif
+
+#ifdef APPLE_LION_OR_NEWER
+#define git_CC_error_check(pattern, err) \
+ do { \
+ if (err) { \
+ die(pattern, (long)CFErrorGetCode(err)); \
+ } \
+ } while(0)
+
+#define EVP_EncodeBlock git_CC_EVP_EncodeBlock
+static inline int git_CC_EVP_EncodeBlock(unsigned char *out,
+ const unsigned char *in, int inlen)
+{
+ CFErrorRef err;
+ SecTransformRef encoder;
+ CFDataRef input, output;
+ CFIndex length;
+
+ encoder = SecEncodeTransformCreate(kSecBase64Encoding, &err);
+ git_CC_error_check("SecEncodeTransformCreate failed: %ld", err);
+
+ input = CFDataCreate(kCFAllocatorDefault, in, inlen);
+ SecTransformSetAttribute(encoder, kSecTransformInputAttributeName,
+ input, &err);
+ git_CC_error_check("SecTransformSetAttribute failed: %ld", err);
+
+ output = SecTransformExecute(encoder, &err);
+ git_CC_error_check("SecTransformExecute failed: %ld", err);
+
+ length = CFDataGetLength(output);
+ CFDataGetBytes(output, CFRangeMake(0, length), out);
+
+ CFRelease(output);
+ CFRelease(input);
+ CFRelease(encoder);
+
+ return (int)strlen((const char *)out);
+}
+
+#define EVP_DecodeBlock git_CC_EVP_DecodeBlock
+static int inline git_CC_EVP_DecodeBlock(unsigned char *out,
+ const unsigned char *in, int inlen)
+{
+ CFErrorRef err;
+ SecTransformRef decoder;
+ CFDataRef input, output;
+ CFIndex length;
+
+ decoder = SecDecodeTransformCreate(kSecBase64Encoding, &err);
+ git_CC_error_check("SecEncodeTransformCreate failed: %ld", err);
+
+ input = CFDataCreate(kCFAllocatorDefault, in, inlen);
+ SecTransformSetAttribute(decoder, kSecTransformInputAttributeName,
+ input, &err);
+ git_CC_error_check("SecTransformSetAttribute failed: %ld", err);
+
+ output = SecTransformExecute(decoder, &err);
+ git_CC_error_check("SecTransformExecute failed: %ld", err);
+
+ length = CFDataGetLength(output);
+ CFDataGetBytes(output, CFRangeMake(0, length), out);
+
+ CFRelease(output);
+ CFRelease(input);
+ CFRelease(decoder);
+
+ return (int)strlen((const char *)out);
+}
+#endif /* APPLE_LION_OR_NEWER */
+++ /dev/null
-#include "../git-compat-util.h"
-#undef write
-
-/*
- * Version of write that will write at most INT_MAX bytes.
- * Workaround a xnu bug on Mac OS X
- */
-ssize_t clipped_write(int fildes, const void *buf, size_t nbyte)
-{
- if (nbyte > INT_MAX)
- nbyte = INT_MAX;
- return write(fildes, buf, nbyte);
-}
return do_stat_internal(1, file_name, buf);
}
-#undef fstat
int mingw_fstat(int fd, struct stat *buf)
{
HANDLE fh = (HANDLE)_get_osfhandle(fd);
errno = err_win_to_posix(GetLastError());
CloseHandle(h);
return -1;
+ } else if (pid > 0 && sig == 0) {
+ HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
+ if (h) {
+ CloseHandle(h);
+ return 0;
+ }
}
errno = EINVAL;
#define WEXITSTATUS(x) ((x) & 0xff)
#define WTERMSIG(x) SIGTERM
+#ifndef EWOULDBLOCK
#define EWOULDBLOCK EAGAIN
+#endif
#define SHUT_WR SD_SEND
#define SIGHUP 1
#define F_SETFD 2
#define FD_CLOEXEC 0x1
+#ifndef EAFNOSUPPORT
#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#endif
+#ifndef ECONNABORTED
#define ECONNABORTED WSAECONNABORTED
+#endif
struct passwd {
char *pw_name;
return 0;
}
-/* Use mingw_lstat() instead of lstat()/stat() and
- * mingw_fstat() instead of fstat() on Windows.
+/*
+ * Use mingw specific stat()/lstat()/fstat() implementations on Windows.
*/
#define off_t off64_t
#define lseek _lseeki64
-#ifndef ALREADY_DECLARED_STAT_FUNCS
+
+/* use struct stat with 64 bit st_size */
+#ifdef stat
+#undef stat
+#endif
#define stat _stati64
int mingw_lstat(const char *file_name, struct stat *buf);
int mingw_stat(const char *file_name, struct stat *buf);
int mingw_fstat(int fd, struct stat *buf);
+#ifdef fstat
+#undef fstat
+#endif
#define fstat mingw_fstat
+#ifdef lstat
+#undef lstat
+#endif
#define lstat mingw_lstat
-#define _stati64(x,y) mingw_stat(x,y)
+
+#ifndef _stati64
+# define _stati64(x,y) mingw_stat(x,y)
+#elif defined (_USE_32BIT_TIME_T)
+# define _stat32i64(x,y) mingw_stat(x,y)
+#else
+# define _stat64(x,y) mingw_stat(x,y)
#endif
int mingw_utime(const char *file_name, const struct utimbuf *times);
#define find_last_dir_sep mingw_find_last_dir_sep
#define PATH_SEP ';'
#define PRIuMAX "I64u"
+#define PRId64 "I64d"
void mingw_open_html(const char *path);
#define open_html mingw_open_html
#undef ERROR
-/* Use mingw_lstat() instead of lstat()/stat() and mingw_fstat() instead
- * of fstat(). We add the declaration of these functions here, suppressing
- * the corresponding declarations in mingw.h, so that we can use the
- * appropriate structure type (and function) names from the msvc headers.
- */
-#define stat _stat64
-int mingw_lstat(const char *file_name, struct stat *buf);
-int mingw_fstat(int fd, struct stat *buf);
-#define fstat mingw_fstat
-#define lstat mingw_lstat
-#define _stat64(x,y) mingw_lstat(x,y)
-#define ALREADY_DECLARED_STAT_FUNCS
-
#include "compat/mingw.h"
-#undef ALREADY_DECLARED_STAT_FUNCS
-
#endif
#endif /* WIN32 */
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
+#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x403
+#endif
#include <windows.h>
#define HAVE_MMAP 1
#define HAVE_MORECORE 0
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
# define WIN32_NATIVE
-# if defined (_MSC_VER)
+# if defined (_MSC_VER) && !defined(_WIN32_WINNT)
# define _WIN32_WINNT 0x0502
# endif
# include <winsock2.h>
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;
+ precomposed_unicode = access(path, R_OK) ? 0 : 1;
+ git_config_set("core.precomposeunicode", precomposed_unicode ? "true" : "false");
strcpy(path + len, auml_nfc);
if (unlink(path))
die_errno(_("failed to unlink '%s'"), path);
p = buf;
*p++ = dfa->nodes[node].opr.c;
while (++node < dfa->nodes_len
- && dfa->nodes[node].type == CHARACTER
+ && dfa->nodes[node].type == CHARACTER
&& dfa->nodes[node].mb_partial)
*p++ = dfa->nodes[node].opr.c;
memset (&state, '\0', sizeof (state));
struct strbuf value;
struct strbuf var;
- int (*fgetc)(struct config_source *c);
- int (*ungetc)(int c, struct config_source *conf);
- long (*ftell)(struct config_source *c);
+ int (*do_fgetc)(struct config_source *c);
+ int (*do_ungetc)(int c, struct config_source *conf);
+ long (*do_ftell)(struct config_source *c);
};
static struct config_source *cf;
static int get_next_char(void)
{
- int c = cf->fgetc(cf);
+ int c = cf->do_fgetc(cf);
if (c == '\r') {
/* DOS like systems */
- c = cf->fgetc(cf);
+ c = cf->do_fgetc(cf);
if (c != '\n') {
- cf->ungetc(c, cf);
+ cf->do_ungetc(c, cf);
c = '\r';
}
}
return 0;
}
-static int git_parse_long(const char *value, long *ret)
+static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
{
if (value && *value) {
char *end;
val = strtoimax(value, &end, 0);
if (errno == ERANGE)
return 0;
- if (!parse_unit_factor(end, &factor))
+ if (!parse_unit_factor(end, &factor)) {
+ errno = EINVAL;
return 0;
+ }
uval = abs(val);
uval *= factor;
- if ((uval > maximum_signed_value_of_type(long)) ||
- (abs(val) > uval))
+ if (uval > max || abs(val) > uval) {
+ errno = ERANGE;
return 0;
+ }
val *= factor;
*ret = val;
return 1;
}
+ errno = EINVAL;
return 0;
}
-int git_parse_ulong(const char *value, unsigned long *ret)
+static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
{
if (value && *value) {
char *end;
if (errno == ERANGE)
return 0;
oldval = val;
- if (!parse_unit_factor(end, &val))
+ if (!parse_unit_factor(end, &val)) {
+ errno = EINVAL;
return 0;
- if ((val > maximum_unsigned_value_of_type(long)) ||
- (oldval > val))
+ }
+ if (val > max || oldval > val) {
+ errno = ERANGE;
return 0;
+ }
*ret = val;
return 1;
}
+ errno = EINVAL;
return 0;
}
-static void die_bad_config(const char *name)
+static int git_parse_int(const char *value, int *ret)
{
+ intmax_t tmp;
+ if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
+ return 0;
+ *ret = tmp;
+ return 1;
+}
+
+static int git_parse_int64(const char *value, int64_t *ret)
+{
+ intmax_t tmp;
+ if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
+ return 0;
+ *ret = tmp;
+ return 1;
+}
+
+int git_parse_ulong(const char *value, unsigned long *ret)
+{
+ uintmax_t tmp;
+ if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
+ return 0;
+ *ret = tmp;
+ return 1;
+}
+
+static void die_bad_number(const char *name, const char *value)
+{
+ const char *reason = errno == ERANGE ?
+ "out of range" :
+ "invalid unit";
+ if (!value)
+ value = "";
+
if (cf && cf->name)
- die("bad config value for '%s' in %s", name, cf->name);
- die("bad config value for '%s'", name);
+ die("bad numeric config value '%s' for '%s' in %s: %s",
+ value, name, cf->name, reason);
+ die("bad numeric config value '%s' for '%s': %s", value, name, reason);
}
int git_config_int(const char *name, const char *value)
{
- long ret = 0;
- if (!git_parse_long(value, &ret))
- die_bad_config(name);
+ int ret;
+ if (!git_parse_int(value, &ret))
+ die_bad_number(name, value);
+ return ret;
+}
+
+int64_t git_config_int64(const char *name, const char *value)
+{
+ int64_t ret;
+ if (!git_parse_int64(value, &ret))
+ die_bad_number(name, value);
return ret;
}
{
unsigned long ret;
if (!git_parse_ulong(value, &ret))
- die_bad_config(name);
+ die_bad_number(name, value);
return ret;
}
int git_config_maybe_bool(const char *name, const char *value)
{
- long v = git_config_maybe_bool_text(name, value);
+ int v = git_config_maybe_bool_text(name, value);
if (0 <= v)
return v;
- if (git_parse_long(value, &v))
+ if (git_parse_int(value, &v))
return !!v;
return -1;
}
top.u.file = f;
top.name = filename;
top.die_on_error = 1;
- top.fgetc = config_file_fgetc;
- top.ungetc = config_file_ungetc;
- top.ftell = config_file_ftell;
+ top.do_fgetc = config_file_fgetc;
+ top.do_ungetc = config_file_ungetc;
+ top.do_ftell = config_file_ftell;
ret = do_config_from(&top, fn, data);
top.u.buf.pos = 0;
top.name = name;
top.die_on_error = 0;
- top.fgetc = config_buf_fgetc;
- top.ungetc = config_buf_ungetc;
- top.ftell = config_buf_ftell;
+ top.do_fgetc = config_buf_fgetc;
+ top.do_ungetc = config_buf_ungetc;
+ top.do_ftell = config_buf_ftell;
return do_config_from(&top, fn, data);
}
return 1;
}
- store.offset[store.seen] = cf->ftell(cf);
+ store.offset[store.seen] = cf->do_ftell(cf);
store.seen++;
}
break;
* Do not increment matches: this is no match, but we
* just made sure we are in the desired section.
*/
- store.offset[store.seen] = cf->ftell(cf);
+ store.offset[store.seen] = cf->do_ftell(cf);
/* fallthru */
case SECTION_END_SEEN:
case START:
if (matches(key, value)) {
- store.offset[store.seen] = cf->ftell(cf);
+ store.offset[store.seen] = cf->do_ftell(cf);
store.state = KEY_SEEN;
store.seen++;
} else {
if (strrchr(key, '.') - key == store.baselen &&
!strncmp(key, store.key, store.baselen)) {
store.state = SECTION_SEEN;
- store.offset[store.seen] = cf->ftell(cf);
+ store.offset[store.seen] = cf->do_ftell(cf);
}
}
}
NO_MEMMEM = YesPlease
USE_ST_TIMESPEC = YesPlease
HAVE_DEV_TTY = YesPlease
- NEEDS_CLIPPED_WRITE = YesPlease
COMPAT_OBJS += compat/precompose_utf8.o
BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
endif
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
NO_REGEX = YesPlease
NO_CURL = YesPlease
+ NO_GETTEXT = YesPlease
NO_PYTHON = YesPlease
BLK_SHA1 = YesPlease
ETAGS_TARGET = ETAGS
NO_INET_NTOP = YesPlease
NO_POSIX_GOODIES = UnfortunatelyYes
DEFAULT_HELP_FORMAT = html
- COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
+ COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -D_USE_32BIT_TIME_T -DNOGDI -Icompat -Icompat/win32
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
COMPAT_OBJS += compat/mingw.o compat/winansi.o \
compat/win32/pthread.o compat/win32/syslog.o \
#include "refs.h"
#include "run-command.h"
#include "remote.h"
+#include "connect.h"
#include "url.h"
+#include "string-list.h"
static char *server_capabilities;
+static const char *parse_feature_value(const char *, const char *, int *);
static int check_ref(const char *name, int len, unsigned int flags)
{
"and the repository exists.");
}
+static void parse_one_symref_info(struct string_list *symref, const char *val, int len)
+{
+ char *sym, *target;
+ struct string_list_item *item;
+
+ if (!len)
+ return; /* just "symref" */
+ /* e.g. "symref=HEAD:refs/heads/master" */
+ sym = xmalloc(len + 1);
+ memcpy(sym, val, len);
+ sym[len] = '\0';
+ target = strchr(sym, ':');
+ if (!target)
+ /* just "symref=something" */
+ goto reject;
+ *(target++) = '\0';
+ if (check_refname_format(sym, REFNAME_ALLOW_ONELEVEL) ||
+ check_refname_format(target, REFNAME_ALLOW_ONELEVEL))
+ /* "symref=bogus:pair */
+ goto reject;
+ item = string_list_append(symref, sym);
+ item->util = target;
+ return;
+reject:
+ free(sym);
+ return;
+}
+
+static void annotate_refs_with_symref_info(struct ref *ref)
+{
+ struct string_list symref = STRING_LIST_INIT_DUP;
+ const char *feature_list = server_capabilities;
+
+ while (feature_list) {
+ int len;
+ const char *val;
+
+ val = parse_feature_value(feature_list, "symref", &len);
+ if (!val)
+ break;
+ parse_one_symref_info(&symref, val, len);
+ feature_list = val + 1;
+ }
+ sort_string_list(&symref);
+
+ for (; ref; ref = ref->next) {
+ struct string_list_item *item;
+ item = string_list_lookup(&symref, ref->name);
+ if (!item)
+ continue;
+ ref->symref = xstrdup((char *)item->util);
+ }
+ string_list_clear(&symref, 0);
+}
+
/*
* Read all the refs from the other end
*/
struct ref **list, unsigned int flags,
struct extra_have_objects *extra_have)
{
+ struct ref **orig_list = list;
int got_at_least_one_head = 0;
*list = NULL;
list = &ref->next;
got_at_least_one_head = 1;
}
+
+ annotate_refs_with_symref_info(*orig_list);
+
return list;
}
-const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp)
+static const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp)
{
int len;
path = strchr(end, c);
if (path && !has_dos_drive_prefix(end)) {
if (c == ':') {
- if (path < strchrnul(host, '/')) {
+ if (host != url || path < strchrnul(host, '/')) {
protocol = PROTO_SSH;
*path++ = '\0';
} else /* '/' in the host part, assume local path */
--- /dev/null
+#ifndef CONNECT_H
+#define CONNECT_H
+
+#define CONNECT_VERBOSE (1u << 0)
+extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
+extern int finish_connect(struct child_process *conn);
+extern int git_connection_is_socket(struct child_process *conn);
+extern int server_supports(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);
+
+#endif
+++ /dev/null
-= Installation instructions =
-
-Two scripts are included. The Python one (ciabot.py) is faster and
-more capable; the shell one (ciabot.sh) is a fallback in case Python
-gives your git hosting site indigestion. (I know of no such sites.)
-
-It is no longer necessary to modify the script in order to put it
-in place; in fact, this is now discouraged. It is entirely
-configurable with the following git config variables:
-
-ciabot.project = name of the project
-ciabot.repo = name of the project repo for gitweb/cgit purposes
-ciabot.xmlrpc = if true, ship notifications via XML-RPC
-ciabot.revformat = format in which the revision is shown
-
-The revformat variable may have the following values
-raw -> full hex ID of commit
-short -> first 12 chars of hex ID
-describe -> describe relative to last tag, falling back to short
-
-ciabot.project defaults to the directory name of the repository toplevel.
-ciabot.repo defaults to ciabot.project lowercased.
-ciabot.xmlrpc defaults to True
-ciabot.revformat defaults to 'describe'.
-
-This means that in the normal case you need not do any configuration at all,
-however setting ciabot.project will allow the hook to run slightly faster.
-
-Once you've set these variables, try your script with -n to see the
-notification message dumped to stdout and verify that it looks sane.
-
-To live-test these scripts, your project needs to have been registered with
-the CIA site. Here are the steps:
-
-1. Open an IRC window on irc://freenode/commits or your registered
- project IRC channel.
-
-2. Run ciabot.py and/or ciabot.sh from any directory under git
- control.
-
-You should see a notification on the channel for your most recent commit.
-
-After verifying correct function, install one of these scripts either
-in a post-commit hook or in an update hook.
-
-In post-commit, run it without arguments. It will query for
-current HEAD and the latest commit ID to get the information it
-needs.
-
-In update, call it with a refname followed by a list of commits:
-You want to reverse the order git rev-list emits because it lists
-from most recent to oldest.
-
-/path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac)
+++ /dev/null
-These are hook scripts for the CIA notification service at <http://cia.vc/>
-
-They are maintained by Eric S. Raymond <esr@thyrsus.com>. There is an
-upstream resource page for them at <http://www.catb.org/esr/ciabot/>,
-but they are unlikely to change rapidly.
-
-You probably want the Python version; it's faster, more capable, and
-better documented. The shell version is maintained only as a fallback
-for use on hosting sites that don't permit Python hook scripts.
-
-See the file INSTALL for installation instructions.
+++ /dev/null
-#!/usr/bin/env python
-# Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com>
-# Distributed under BSD terms.
-#
-# This script contains porcelain and porcelain byproducts.
-# It's Python because the Python standard libraries avoid portability/security
-# issues raised by callouts in the ancestral Perl and sh scripts. It should
-# be compatible back to Python 2.1.5
-#
-# usage: ciabot.py [-V] [-n] [-p projectname] [refname [commits...]]
-#
-# This script is meant to be run either in a post-commit hook or in an
-# update hook. Try it with -n to see the notification mail dumped to
-# stdout and verify that it looks sane. With -V it dumps its version
-# and exits.
-#
-# In post-commit, run it without arguments. It will query for
-# current HEAD and the latest commit ID to get the information it
-# needs.
-#
-# In update, call it with a refname followed by a list of commits:
-# You want to reverse the order git rev-list emits because it lists
-# from most recent to oldest.
-#
-# /path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac)
-#
-# Configuration variables affecting this script:
-#
-# ciabot.project = name of the project
-# ciabot.repo = name of the project repo for gitweb/cgit purposes
-# ciabot.xmlrpc = if true (default), ship notifications via XML-RPC
-# ciabot.revformat = format in which the revision is shown
-#
-# ciabot.project defaults to the directory name of the repository toplevel.
-# ciabot.repo defaults to ciabot.project lowercased.
-#
-# This means that in the normal case you need not do any configuration at all,
-# but setting the project name will speed it up slightly.
-#
-# The revformat variable may have the following values
-# raw -> full hex ID of commit
-# short -> first 12 chars of hex ID
-# describe = -> describe relative to last tag, falling back to short
-# The default is 'describe'.
-#
-# Note: the CIA project now says only XML-RPC is reliable, so
-# we default to that.
-#
-
-import sys
-if sys.hexversion < 0x02000000:
- # The limiter is the xml.sax module
- sys.stderr.write("ciabot.py: requires Python 2.0.0 or later.\n")
- sys.exit(1)
-
-import os, commands, socket, urllib
-from xml.sax.saxutils import escape
-
-# Changeset URL prefix for your repo: when the commit ID is appended
-# to this, it should point at a CGI that will display the commit
-# through gitweb or something similar. The defaults will probably
-# work if you have a typical gitweb/cgit setup.
-#
-#urlprefix="http://%(host)s/cgi-bin/gitweb.cgi?p=%(repo)s;a=commit;h="
-urlprefix="http://%(host)s/cgi-bin/cgit.cgi/%(repo)s/commit/?id="
-
-# The service used to turn your gitwebbish URL into a tinyurl so it
-# will take up less space on the IRC notification line.
-tinyifier = "http://tinyurl.com/api-create.php?url="
-
-# The template used to generate the XML messages to CIA. You can make
-# visible changes to the IRC-bot notification lines by hacking this.
-# The default will produce a notification line that looks like this:
-#
-# ${project}: ${author} ${repo}:${branch} * ${rev} ${files}: ${logmsg} ${url}
-#
-# By omitting $files you can collapse the files part to a single slash.
-xml = '''\
-<message>
- <generator>
- <name>CIA Python client for Git</name>
- <version>%(version)s</version>
- <url>%(generator)s</url>
- </generator>
- <source>
- <project>%(project)s</project>
- <branch>%(repo)s:%(branch)s</branch>
- </source>
- <timestamp>%(ts)s</timestamp>
- <body>
- <commit>
- <author>%(author)s</author>
- <revision>%(rev)s</revision>
- <files>
- %(files)s
- </files>
- <log>%(logmsg)s %(url)s</log>
- <url>%(url)s</url>
- </commit>
- </body>
-</message>
-'''
-
-#
-# No user-serviceable parts below this line:
-#
-
-# Where to ship e-mail notifications.
-toaddr = "cia@cia.vc"
-
-# Identify the generator script.
-# Should only change when the script itself gets a new home and maintainer.
-generator = "http://www.catb.org/~esr/ciabot.py"
-version = "3.6"
-
-def do(command):
- return commands.getstatusoutput(command)[1]
-
-def report(refname, merged, xmlrpc=True):
- "Generate a commit notification to be reported to CIA"
-
- # Try to tinyfy a reference to a web view for this commit.
- try:
- url = open(urllib.urlretrieve(tinyifier + urlprefix + merged)[0]).read()
- except:
- url = urlprefix + merged
-
- branch = os.path.basename(refname)
-
- # Compute a description for the revision
- if revformat == 'raw':
- rev = merged
- elif revformat == 'short':
- rev = ''
- else: # revformat == 'describe'
- rev = do("git describe %s 2>/dev/null" % merged)
- if not rev:
- rev = merged[:12]
-
- # Extract the meta-information for the commit
- files=do("git diff-tree -r --name-only '"+ merged +"' | sed -e '1d' -e 's-.*-<file>&</file>-'")
- metainfo = do("git log -1 '--pretty=format:%an <%ae>%n%at%n%s' " + merged)
- (author, ts, logmsg) = metainfo.split("\n")
- logmsg = escape(logmsg)
-
- # This discards the part of the author's address after @.
- # Might be be nice to ship the full email address, if not
- # for spammers' address harvesters - getting this wrong
- # would make the freenode #commits channel into harvester heaven.
- author = escape(author.replace("<", "").split("@")[0].split()[-1])
-
- # This ignores the timezone. Not clear what to do with it...
- ts = ts.strip().split()[0]
-
- context = locals()
- context.update(globals())
-
- out = xml % context
- mail = '''\
-Message-ID: <%(merged)s.%(author)s@%(project)s>
-From: %(fromaddr)s
-To: %(toaddr)s
-Content-type: text/xml
-Subject: DeliverXML
-
-%(out)s''' % locals()
-
- if xmlrpc:
- return out
- else:
- return mail
-
-if __name__ == "__main__":
- import getopt
-
- # Get all config variables
- revformat = do("git config --get ciabot.revformat")
- project = do("git config --get ciabot.project")
- repo = do("git config --get ciabot.repo")
- xmlrpc = do("git config --get ciabot.xmlrpc")
- xmlrpc = not (xmlrpc and xmlrpc == "false")
-
- host = socket.getfqdn()
- fromaddr = "CIABOT-NOREPLY@" + host
-
- try:
- (options, arguments) = getopt.getopt(sys.argv[1:], "np:xV")
- except getopt.GetoptError, msg:
- print "ciabot.py: " + str(msg)
- raise SystemExit, 1
-
- notify = True
- for (switch, val) in options:
- if switch == '-p':
- project = val
- elif switch == '-n':
- notify = False
- elif switch == '-x':
- xmlrpc = True
- elif switch == '-V':
- print "ciabot.py: version", version
- sys.exit(0)
-
- # The project variable defaults to the name of the repository toplevel.
- if not project:
- here = os.getcwd()
- while True:
- if os.path.exists(os.path.join(here, ".git")):
- project = os.path.basename(here)
- break
- elif here == '/':
- sys.stderr.write("ciabot.py: no .git below root!\n")
- sys.exit(1)
- here = os.path.dirname(here)
-
- if not repo:
- repo = project.lower()
-
- urlprefix = urlprefix % globals()
-
- # The script wants a reference to head followed by the list of
- # commit ID to report about.
- if len(arguments) == 0:
- refname = do("git symbolic-ref HEAD 2>/dev/null")
- merges = [do("git rev-parse HEAD")]
- else:
- refname = arguments[0]
- merges = arguments[1:]
-
- if notify:
- if xmlrpc:
- import xmlrpclib
- server = xmlrpclib.Server('http://cia.vc/RPC2');
- else:
- import smtplib
- server = smtplib.SMTP('localhost')
-
- for merged in merges:
- message = report(refname, merged, xmlrpc)
- if not notify:
- print message
- elif xmlrpc:
- try:
- # RPC server is flaky, this can fail due to timeout.
- server.hub.deliver(message)
- except socket.error, e:
- sys.stderr.write("%s\n" % e)
- else:
- server.sendmail(fromaddr, [toaddr], message)
-
- if notify:
- if not xmlrpc:
- server.quit()
-
-#End
+++ /dev/null
-#!/bin/sh
-# Distributed under the terms of the GNU General Public License v2
-# Copyright (c) 2006 Fernando J. Pereda <ferdy@gentoo.org>
-# Copyright (c) 2008 Natanael Copa <natanael.copa@gmail.com>
-# Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com>
-# Assistance and review by Petr Baudis, author of ciabot.pl,
-# is gratefully acknowledged.
-#
-# This is a version 3.x of ciabot.sh; use -V to find the exact
-# version. Versions 1 and 2 were shipped in 2006 and 2008 and are not
-# version-stamped. The version 2 maintainer has passed the baton.
-#
-# Note: This script should be considered obsolete.
-# There is a faster, better-documented rewrite in Python: find it as ciabot.py
-# Use this only if your hosting site forbids Python hooks.
-# It requires: git(1), hostname(1), cut(1), sendmail(1), and wget(1).
-#
-# Originally based on Git ciabot.pl by Petr Baudis.
-# This script contains porcelain and porcelain byproducts.
-#
-# usage: ciabot.sh [-V] [-n] [-p projectname] [refname commit]
-#
-# This script is meant to be run either in a post-commit hook or in an
-# update hook. Try it with -n to see the notification mail dumped to
-# stdout and verify that it looks sane. With -V it dumps its version
-# and exits.
-#
-# In post-commit, run it without arguments. It will query for
-# current HEAD and the latest commit ID to get the information it
-# needs.
-#
-# In update, you have to call it once per merged commit:
-#
-# refname=$1
-# oldhead=$2
-# newhead=$3
-# for merged in $(git rev-list ${oldhead}..${newhead} | tac) ; do
-# /path/to/ciabot.sh ${refname} ${merged}
-# done
-#
-# The reason for the tac call is that git rev-list emits commits from
-# most recent to least - better to ship notifications from oldest to newest.
-#
-# Configuration variables affecting this script:
-#
-# ciabot.project = name of the project
-# ciabot.repo = name of the project repo for gitweb/cgit purposes
-# ciabot.revformat = format in which the revision is shown
-#
-# ciabot.project defaults to the directory name of the repository toplevel.
-# ciabot.repo defaults to ciabot.project lowercased.
-#
-# This means that in the normal case you need not do any configuration at all,
-# but setting the project name will speed it up slightly.
-#
-# The revformat variable may have the following values
-# raw -> full hex ID of commit
-# short -> first 12 chars of hex ID
-# describe = -> describe relative to last tag, falling back to short
-# The default is 'describe'.
-#
-# Note: the shell ancestors of this script used mail, not XML-RPC, in
-# order to avoid stalling until timeout when the CIA XML-RPC server is
-# down. It is unknown whether this is still an issue in 2010, but
-# XML-RPC would be annoying to do from sh in any case. (XML-RPC does
-# have the advantage that it guarantees notification of multiple commits
-# shipped from an update in their actual order.)
-#
-
-# The project as known to CIA. You can set this with a -p option,
-# or let it default to the directory name of the repo toplevel.
-project=$(git config --get ciabot.project)
-
-if [ -z $project ]
-then
- here=`pwd`;
- while :; do
- if [ -d $here/.git ]
- then
- project=`basename $here`
- break
- elif [ $here = '/' ]
- then
- echo "ciabot.sh: no .git below root!"
- exit 1
- fi
- here=`dirname $here`
- done
-fi
-
-# Name of the repo for gitweb/cgit purposes
-repo=$(git config --get ciabot.repo)
-[ -z $repo] && repo=$(echo "${project}" | tr '[A-Z]' '[a-z]')
-
-# What revision format do we want in the summary?
-revformat=$(git config --get ciabot.revformat)
-
-# Fully qualified domain name of the repo host. You can hardwire this
-# to make the script faster. The -f option works under Linux and FreeBSD,
-# but not OpenBSD and NetBSD. But under OpenBSD and NetBSD,
-# hostname without options gives the FQDN.
-if hostname -f >/dev/null 2>&1
-then
- hostname=`hostname -f`
-else
- hostname=`hostname`
-fi
-
-# Changeset URL prefix for your repo: when the commit ID is appended
-# to this, it should point at a CGI that will display the commit
-# through gitweb or something similar. The defaults will probably
-# work if you have a typical gitweb/cgit setup.
-#urlprefix="http://${host}/cgi-bin/gitweb.cgi?p=${repo};a=commit;h="
-urlprefix="http://${host}/cgi-bin/cgit.cgi/${repo}/commit/?id="
-
-#
-# You probably will not need to change the following:
-#
-
-# Identify the script. The 'generator' variable should change only
-# when the script itself gets a new home and maintainer.
-generator="http://www.catb.org/~esr/ciabot/ciabot.sh"
-version=3.5
-
-# Addresses for the e-mail
-from="CIABOT-NOREPLY@${hostname}"
-to="cia@cia.vc"
-
-# SMTP client to use - may need to edit the absolute pathname for your system
-sendmail="sendmail -t -f ${from}"
-
-#
-# No user-serviceable parts below this line:
-#
-
-# Should include all places sendmail is likely to lurk.
-PATH="$PATH:/usr/sbin/"
-
-mode=mailit
-while getopts pnV opt
-do
- case $opt in
- p) project=$2; shift ; shift ;;
- n) mode=dumpit; shift ;;
- V) echo "ciabot.sh: version $version"; exit 0; shift ;;
- esac
-done
-
-# Cough and die if user has not specified a project
-if [ -z "$project" ]
-then
- echo "ciabot.sh: no project specified, bailing out." >&2
- exit 1
-fi
-
-if [ $# -eq 0 ] ; then
- refname=$(git symbolic-ref HEAD 2>/dev/null)
- merged=$(git rev-parse HEAD)
-else
- refname=$1
- merged=$2
-fi
-
-# This tries to turn your gitwebbish URL into a tinyurl so it will take up
-# less space on the IRC notification line. Some repo sites (I'm looking at
-# you, berlios.de!) forbid wget calls for security reasons. On these,
-# the code will fall back to the full un-tinyfied URL.
-longurl=${urlprefix}${merged}
-url=$(wget -O - -q http://tinyurl.com/api-create.php?url=${longurl} 2>/dev/null)
-if [ -z "$url" ]; then
- url="${longurl}"
-fi
-
-refname=${refname##refs/heads/}
-
-case $revformat in
-raw) rev=$merged ;;
-short) rev='' ;;
-*) rev=$(git describe ${merged} 2>/dev/null) ;;
-esac
-[ -z ${rev} ] && rev=$(echo "$merged" | cut -c 1-12)
-
-# We discard the part of the author's address after @.
-# Might be nice to ship the full email address, if not
-# for spammers' address harvesters - getting this wrong
-# would make the freenode #commits channel into harvester heaven.
-author=$(git log -1 '--pretty=format:%an <%ae>' $merged)
-author=$(echo "$author" | sed -n -e '/^.*<\([^@]*\).*$/s--\1-p')
-
-logmessage=$(git log -1 '--pretty=format:%s' $merged)
-ts=$(git log -1 '--pretty=format:%at' $merged)
-files=$(git diff-tree -r --name-only ${merged} | sed -e '1d' -e 's-.*-<file>&</file>-')
-
-out="
-<message>
- <generator>
- <name>CIA Shell client for Git</name>
- <version>${version}</version>
- <url>${generator}</url>
- </generator>
- <source>
- <project>${project}</project>
- <branch>$repo:${refname}</branch>
- </source>
- <timestamp>${ts}</timestamp>
- <body>
- <commit>
- <author>${author}</author>
- <revision>${rev}</revision>
- <files>
- ${files}
- </files>
- <log>${logmessage} ${url}</log>
- <url>${url}</url>
- </commit>
- </body>
-</message>"
-
-if [ "$mode" = "dumpit" ]
-then
- sendmail=cat
-fi
-
-${sendmail} << EOM
-Message-ID: <${merged}.${author}@${project}>
-From: ${from}
-To: ${to}
-Content-type: text/xml
-Subject: DeliverXML
-${out}
-EOM
-
-# vim: set tw=70 :
esac
# XXX should we check for --update and --all options ?
- __git_complete_index_file "--others --modified"
+ __git_complete_index_file "--others --modified --directory --no-empty-directory"
}
_git_archive ()
esac
# XXX should we check for -x option ?
- __git_complete_index_file "--others"
+ __git_complete_index_file "--others --directory"
}
_git_clone ()
__git_complete_revlist_file
}
-__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
+__git_mergetools_common="diffuse diffmerge ecmerge emerge kdiff3 meld opendiff
tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 codecompare
"
--*=*|*.) ;;
*) c="$c " ;;
esac
- array[$#array+1]="$c"
+ array[${#array[@]}+1]="$c"
done
compset -P '*[=:]'
compadd -Q -S '' -p "${2-}" -a -- array && _ret=0
# of values:
#
# verbose show number of commits ahead/behind (+/-) upstream
+# name if verbose, then also show the upstream abbrev name
# legacy don't use the '--count' option available in recent
# versions of git-rev-list
# git always compare HEAD to @{upstream}
# the colored output of "git status -sb" and are available only when
# using __git_ps1 for PROMPT_COMMAND or precmd.
+# check whether printf supports -v
+__git_printf_supports_v=
+printf -v __git_printf_supports_v -- '%s' yes >/dev/null 2>&1
+
# 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=""
+ local upstream=git legacy="" verbose="" name=""
svn_remote=()
# get some config options from git-config
;;
svn-remote.*.url)
svn_remote[$((${#svn_remote[@]} + 1))]="$value"
- svn_url_pattern+="\\|$value"
+ svn_url_pattern="$svn_url_pattern\\|$value"
upstream=svn+git # default upstream is SVN if available, else git
;;
esac
git|svn) upstream="$option" ;;
verbose) verbose=1 ;;
legacy) legacy=1 ;;
+ name) name=1 ;;
esac
done
*) # diverged from upstream
p=" u+${count#* }-${count% *}" ;;
esac
+ if [[ -n "$count" && -n "$name" ]]; then
+ p="$p $(git rev-parse --abbrev-ref "$upstream" 2>/dev/null)"
+ fi
fi
}
local gitstring="$c${b##refs/heads/}${f:+$z$f}$r$p"
if [ $pcmode = yes ]; then
- if [[ -n ${ZSH_VERSION-} ]]; then
+ if [ "${__git_printf_supports_v-}" != yes ]; then
gitstring=$(printf -- "$printf_format" "$gitstring")
else
printf -v gitstring -- "$printf_format" "$gitstring"
}
sub get_blame {
- my ($commits, $source, $start, $len, $from) = @_;
- $len = 1 unless defined($len);
- return if $len == 0;
+ my ($commits, $source, $from, $ranges) = @_;
+ return unless @$ranges;
open my $f, '-|',
- qw(git blame --porcelain -C), '-L', "$start,+$len",
+ qw(git blame --porcelain -C),
+ map({"-L$_->[0],+$_->[1]"} @$ranges),
'--since', $since, "$from^", '--', $source or die;
while (<$f>) {
if (/^([0-9a-f]{40}) \d+ \d+ \d+$/) {
close $f;
}
+sub blame_sources {
+ my ($sources, $commits) = @_;
+ for my $s (keys %$sources) {
+ for my $id (keys %{$sources->{$s}}) {
+ get_blame($commits, $s, $id, $sources->{$s}{$id});
+ }
+ }
+}
+
sub scan_patches {
- my ($commits, $id, $f) = @_;
+ my ($sources, $id, $f) = @_;
my $source;
while (<$f>) {
if (/^From ([0-9a-f]{40}) Mon Sep 17 00:00:00 2001$/) {
} elsif (/^--- /) {
die "Cannot parse hunk source: $_\n";
} elsif (/^@@ -(\d+)(?:,(\d+))?/ && $source) {
- get_blame($commits, $source, $1, $2, $id);
+ my $len = defined($2) ? $2 : 1;
+ push @{$sources->{$source}{$id}}, [$1, $len] if $len;
}
}
}
}
}
-my %commits;
+my %sources;
for (@files) {
- scan_patch_file(\%commits, $_);
+ scan_patch_file(\%sources, $_);
}
if (@rev_args) {
- scan_rev_args(\%commits, \@rev_args)
+ scan_rev_args(\%sources, \@rev_args)
}
+
+my $toplevel = `git rev-parse --show-toplevel`;
+chomp $toplevel;
+chdir($toplevel) or die "chdir failure: $toplevel: $!\n";
+
+my %commits;
+blame_sources(\%sources, \%commits);
import_commits(\%commits);
my $contacts = {};
-include ../../../config.mak.autogen
-include ../../../config.mak
-INCS:=$(shell pkg-config --cflags gnome-keyring-1)
-LIBS:=$(shell pkg-config --libs gnome-keyring-1)
+INCS:=$(shell pkg-config --cflags gnome-keyring-1 glib-2.0)
+LIBS:=$(shell pkg-config --libs gnome-keyring-1 glib-2.0)
SRCS:=$(MAIN).c
OBJS:=$(SRCS:.c=.o)
#include <stdio.h>
#include <string.h>
-#include <stdarg.h>
#include <stdlib.h>
-#include <errno.h>
+#include <glib.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;
-};
+#ifdef GNOME_KEYRING_DEFAULT
-#define CREDENTIAL_INIT \
- { NULL,NULL,0,NULL,NULL,NULL }
+ /* Modern gnome-keyring */
-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);
+#include <gnome-keyring-memory.h>
-typedef int (*credential_op_cb)(struct credential*);
+#else
-struct credential_operation
-{
- char *name;
- credential_op_cb op;
-};
+ /*
+ * Support ancient gnome-keyring, circ. RHEL 5.X.
+ * GNOME_KEYRING_DEFAULT seems to have been introduced with Gnome 2.22,
+ * and the other features roughly around Gnome 2.20, 6 months before.
+ * Ubuntu 8.04 used Gnome 2.22 (I think). Not sure any distro used 2.20.
+ * So the existence/non-existence of GNOME_KEYRING_DEFAULT seems like
+ * a decent thing to use as an indicator.
+ */
-#define CREDENTIAL_OP_END \
- { NULL,NULL }
+#define GNOME_KEYRING_DEFAULT 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.
+ * ancient gnome-keyring returns DENIED when an entry is not found.
+ * Setting NO_MATCH to DENIED will prevent us from reporting DENIED
+ * errors during get and erase operations, but we will still report
+ * DENIED errors during a store.
*/
-struct credential_operation const credential_helper_ops[];
+#define GNOME_KEYRING_RESULT_NO_MATCH GNOME_KEYRING_RESULT_DENIED
-/* ---------------- common helper functions ----------------- */
+#define gnome_keyring_memory_alloc g_malloc
+#define gnome_keyring_memory_free gnome_keyring_free_password
+#define gnome_keyring_memory_strdup g_strdup
-static inline void free_password(char *password)
+static const char* gnome_keyring_result_to_message(GnomeKeyringResult result)
{
- char *c = password;
- if (!password)
- return;
-
- while (*c) *c++ = '\0';
- free(password);
+ switch (result) {
+ case GNOME_KEYRING_RESULT_OK:
+ return "OK";
+ case GNOME_KEYRING_RESULT_DENIED:
+ return "Denied";
+ case GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON:
+ return "No Keyring Daemon";
+ case GNOME_KEYRING_RESULT_ALREADY_UNLOCKED:
+ return "Already UnLocked";
+ case GNOME_KEYRING_RESULT_NO_SUCH_KEYRING:
+ return "No Such Keyring";
+ case GNOME_KEYRING_RESULT_BAD_ARGUMENTS:
+ return "Bad Arguments";
+ case GNOME_KEYRING_RESULT_IO_ERROR:
+ return "IO Error";
+ case GNOME_KEYRING_RESULT_CANCELLED:
+ return "Cancelled";
+ case GNOME_KEYRING_RESULT_ALREADY_EXISTS:
+ return "Already Exists";
+ default:
+ return "Unknown Error";
+ }
}
-static inline void warning(const char *fmt, ...)
+/*
+ * Support really ancient gnome-keyring, circ. RHEL 4.X.
+ * Just a guess for the Glib version. Glib 2.8 was roughly Gnome 2.12 ?
+ * Which was released with gnome-keyring 0.4.3 ??
+ */
+#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 8
+
+static void gnome_keyring_done_cb(GnomeKeyringResult result, gpointer user_data)
{
- va_list ap;
+ gpointer *data = (gpointer*) user_data;
+ int *done = (int*) data[0];
+ GnomeKeyringResult *r = (GnomeKeyringResult*) data[1];
- va_start(ap, fmt);
- fprintf(stderr, "warning: ");
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n" );
- va_end(ap);
+ *r = result;
+ *done = 1;
}
-static inline void error(const char *fmt, ...)
+static void wait_for_request_completion(int *done)
{
- va_list ap;
-
- va_start(ap, fmt);
- fprintf(stderr, "error: ");
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n" );
- va_end(ap);
+ GMainContext *mc = g_main_context_default();
+ while (!*done)
+ g_main_context_iteration(mc, TRUE);
}
-static inline void die(const char *fmt, ...)
+static GnomeKeyringResult gnome_keyring_item_delete_sync(const char *keyring, guint32 id)
{
- va_list ap;
+ int done = 0;
+ GnomeKeyringResult result;
+ gpointer data[] = { &done, &result };
+
+ gnome_keyring_item_delete(keyring, id, gnome_keyring_done_cb, data,
+ NULL);
+
+ wait_for_request_completion(&done);
- va_start(ap,fmt);
- error(fmt, ap);
- va_end(ap);
- exit(EXIT_FAILURE);
+ return result;
}
-static inline void die_errno(int err)
+#endif
+#endif
+
+/*
+ * This credential struct and API is simplified from git's credential.{h,c}
+ */
+struct credential
{
- error("%s", strerror(err));
- exit(EXIT_FAILURE);
-}
+ char *protocol;
+ char *host;
+ unsigned short port;
+ char *path;
+ char *username;
+ char *password;
+};
-static inline char *xstrdup(const char *str)
+#define CREDENTIAL_INIT \
+ { NULL,NULL,0,NULL,NULL,NULL }
+
+typedef int (*credential_op_cb)(struct credential*);
+
+struct credential_operation
{
- char *ret = strdup(str);
- if (!ret)
- die_errno(errno);
+ char *name;
+ credential_op_cb op;
+};
- return ret;
-}
+#define CREDENTIAL_OP_END \
+ { NULL,NULL }
/* ----------------- 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);
+ return NULL;
- if(c->port)
- sprintf(object,"%s:%hd/%s",c->host,c->port,c->path);
- else
- sprintf(object,"%s/%s",c->host,c->path);
+ if (c->port)
+ return g_strdup_printf("%s:%hd/%s", c->host, c->port, c->path);
- return object;
+ return g_strdup_printf("%s/%s", c->host, c->path);
}
-int keyring_get(struct credential *c)
+static int keyring_get(struct credential *c)
{
char* object = NULL;
GList *entries;
c->port,
&entries);
- free(object);
+ g_free(object);
if (result == GNOME_KEYRING_RESULT_NO_MATCH)
return EXIT_SUCCESS;
return EXIT_SUCCESS;
if (result != GNOME_KEYRING_RESULT_OK) {
- error("%s",gnome_keyring_result_to_message(result));
+ g_critical("%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);
+ gnome_keyring_memory_free(c->password);
+ c->password = gnome_keyring_memory_strdup(password_data->password);
if (!c->username)
- c->username = xstrdup(password_data->user);
+ c->username = g_strdup(password_data->user);
gnome_keyring_network_password_list_free(entries);
}
-int keyring_store(struct credential *c)
+static int keyring_store(struct credential *c)
{
guint32 item_id;
char *object = NULL;
+ GnomeKeyringResult result;
/*
* Sanity check that what we are storing is actually sensible.
object = keyring_object(c);
- gnome_keyring_set_network_password_sync(
+ result = gnome_keyring_set_network_password_sync(
GNOME_KEYRING_DEFAULT,
c->username,
NULL /* domain */,
c->password,
&item_id);
- free(object);
+ g_free(object);
+
+ if (result != GNOME_KEYRING_RESULT_OK &&
+ result != GNOME_KEYRING_RESULT_CANCELLED) {
+ g_critical("%s", gnome_keyring_result_to_message(result));
+ return EXIT_FAILURE;
+ }
+
return EXIT_SUCCESS;
}
-int keyring_erase(struct credential *c)
+static int keyring_erase(struct credential *c)
{
char *object = NULL;
GList *entries;
c->port,
&entries);
- free(object);
+ g_free(object);
if (result == GNOME_KEYRING_RESULT_NO_MATCH)
return EXIT_SUCCESS;
if (result != GNOME_KEYRING_RESULT_OK)
{
- error("%s",gnome_keyring_result_to_message(result));
+ g_critical("%s", gnome_keyring_result_to_message(result));
return EXIT_FAILURE;
}
if (result != GNOME_KEYRING_RESULT_OK)
{
- error("%s",gnome_keyring_result_to_message(result));
+ g_critical("%s", gnome_keyring_result_to_message(result));
return EXIT_FAILURE;
}
* Table with helper operation callbacks, used by generic
* credential helper main function.
*/
-struct credential_operation const credential_helper_ops[] =
+static struct credential_operation const credential_helper_ops[] =
{
{ "get", keyring_get },
{ "store", keyring_store },
/* ------------------ credential functions ------------------ */
-void credential_init(struct credential *c)
+static void credential_init(struct credential *c)
{
memset(c, 0, sizeof(*c));
}
-void credential_clear(struct credential *c)
+static void credential_clear(struct credential *c)
{
- free(c->protocol);
- free(c->host);
- free(c->path);
- free(c->username);
- free_password(c->password);
+ g_free(c->protocol);
+ g_free(c->host);
+ g_free(c->path);
+ g_free(c->username);
+ gnome_keyring_memory_free(c->password);
credential_init(c);
}
-int credential_read(struct credential *c)
+static int credential_read(struct credential *c)
{
- char buf[1024];
- ssize_t line_len = 0;
- char *key = buf;
+ char *buf;
+ size_t line_len;
+ char *key;
char *value;
- while (fgets(buf, sizeof(buf), stdin))
+ key = buf = gnome_keyring_memory_alloc(1024);
+
+ while (fgets(buf, 1024, stdin))
{
line_len = strlen(buf);
- if(buf[line_len-1]=='\n')
+ if (line_len && buf[line_len-1] == '\n')
buf[--line_len]='\0';
- if(!line_len)
+ if (!line_len)
break;
value = strchr(buf,'=');
- if(!value) {
- warning("invalid credential line: %s", key);
+ if (!value) {
+ g_warning("invalid credential line: %s", key);
+ gnome_keyring_memory_free(buf);
return -1;
}
*value++ = '\0';
if (!strcmp(key, "protocol")) {
- free(c->protocol);
- c->protocol = xstrdup(value);
+ g_free(c->protocol);
+ c->protocol = g_strdup(value);
} else if (!strcmp(key, "host")) {
- free(c->host);
- c->host = xstrdup(value);
+ g_free(c->host);
+ c->host = g_strdup(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);
+ g_free(c->path);
+ c->path = g_strdup(value);
} else if (!strcmp(key, "username")) {
- free(c->username);
- c->username = xstrdup(value);
+ g_free(c->username);
+ c->username = g_strdup(value);
} else if (!strcmp(key, "password")) {
- free_password(c->password);
- c->password = xstrdup(value);
+ gnome_keyring_memory_free(c->password);
+ c->password = gnome_keyring_memory_strdup(value);
while (*value) *value++ = '\0';
}
/*
* learn new lines, and the helpers are updated to match.
*/
}
+
+ gnome_keyring_memory_free(buf);
+
return 0;
}
-void credential_write_item(FILE *fp, const char *key, const char *value)
+static 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)
+static void credential_write(const struct credential *c)
{
/* only write username/password, if set */
credential_write_item(stdout, "username", c->username);
basename = (basename) ? basename + 1 : name;
fprintf(stderr, "usage: %s <", basename);
- while(try_op->name) {
+ while (try_op->name) {
fprintf(stderr,"%s",(try_op++)->name);
- if(try_op->name)
+ if (try_op->name)
fprintf(stderr,"%s","|");
}
fprintf(stderr,"%s",">\n");
if (!argv[1]) {
usage(argv[0]);
- goto out;
+ exit(EXIT_FAILURE);
}
+ g_set_application_name("Git Credential Helper");
+
/* lookup operation callback */
- while(try_op->name && strcmp(argv[1], try_op->name))
+ while (try_op->name && strcmp(argv[1], try_op->name))
try_op++;
/* unsupported operation given -- ignore silently */
- if(!try_op->name || !try_op->op)
+ if (!try_op->name || !try_op->op)
goto out;
ret = credential_read(&cred);
- if(ret)
+ if (ret)
goto out;
/* perform credential operation */
{
my $entry_text = join ', ', map { "$_=$entry->{$_}" } keys %$entry;
foreach my $check (sort keys %$query) {
- if (defined $query->{$check}) {
+ if (!defined $entry->{$check}) {
+ log_debug("OK: entry has no $check token, so any value satisfies check $check");
+ } elsif (defined $query->{$check}) {
log_debug("compare %s [%s] to [%s] (entry: %s)",
$check,
$entry->{$check},
--- /dev/null
+#!/bin/sh
+#
+# Copyright (c) 2005 Linus Torvalds
+#
+
+USAGE='[--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [git-rev-list options]'
+SUBDIRECTORY_OK='Yes'
+. git-sh-setup
+
+revs=$(git-rev-parse --revs-only --no-flags --default HEAD "$@") || exit
+[ "$revs" ] || {
+ die "No HEAD ref"
+}
+git-rev-list --pretty $(git-rev-parse --default HEAD "$@") |
+LESS=-S ${PAGER:-less}
# This could be traditional "merge <msg> HEAD <commit>..." and the
# way we can tell it is to see if the second token is HEAD, but some
-# people might have misused the interface and used a committish that
+# people might have misused the interface and used a commit-ish that
# is the same as HEAD there instead. Traditional format never would
# have "-m" so it is an additional safety measure to check for it.
--- /dev/null
+#!/bin/sh
+#
+# Copyright (c) 2005 Linus Torvalds
+#
+
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git repack [options]
+--
+a pack everything in a single pack
+A same as -a, and turn unreachable objects loose
+d remove redundant packs, and run git-prune-packed
+f pass --no-reuse-delta to git-pack-objects
+F pass --no-reuse-object to git-pack-objects
+n do not run git-update-server-info
+q,quiet be quiet
+l pass --local to git-pack-objects
+unpack-unreachable= with -A, do not loosen objects older than this
+ Packing constraints
+window= size of the window used for delta compression
+window-memory= same as the above, but limit memory size instead of entries count
+depth= limits the maximum delta depth
+max-pack-size= maximum size of each packfile
+"
+SUBDIRECTORY_OK='Yes'
+. git-sh-setup
+
+no_update_info= all_into_one= remove_redundant= unpack_unreachable=
+local= no_reuse= extra=
+while test $# != 0
+do
+ case "$1" in
+ -n) no_update_info=t ;;
+ -a) all_into_one=t ;;
+ -A) all_into_one=t
+ unpack_unreachable=--unpack-unreachable ;;
+ --unpack-unreachable)
+ unpack_unreachable="--unpack-unreachable=$2"; shift ;;
+ -d) remove_redundant=t ;;
+ -q) GIT_QUIET=t ;;
+ -f) no_reuse=--no-reuse-delta ;;
+ -F) no_reuse=--no-reuse-object ;;
+ -l) local=--local ;;
+ --max-pack-size|--window|--window-memory|--depth)
+ extra="$extra $1=$2"; shift ;;
+ --) shift; break;;
+ *) usage ;;
+ esac
+ shift
+done
+
+case "`git config --bool repack.usedeltabaseoffset || echo true`" in
+true)
+ extra="$extra --delta-base-offset" ;;
+esac
+
+PACKDIR="$GIT_OBJECT_DIRECTORY/pack"
+PACKTMP="$PACKDIR/.tmp-$$-pack"
+rm -f "$PACKTMP"-*
+trap 'rm -f "$PACKTMP"-*' 0 1 2 3 15
+
+# There will be more repacking strategies to come...
+case ",$all_into_one," in
+,,)
+ args='--unpacked --incremental'
+ ;;
+,t,)
+ args= existing=
+ if [ -d "$PACKDIR" ]; then
+ for e in `cd "$PACKDIR" && find . -type f -name '*.pack' \
+ | sed -e 's/^\.\///' -e 's/\.pack$//'`
+ do
+ if [ -e "$PACKDIR/$e.keep" ]; then
+ : keep
+ else
+ existing="$existing $e"
+ fi
+ done
+ if test -n "$existing" -a -n "$unpack_unreachable" -a \
+ -n "$remove_redundant"
+ then
+ # This may have arbitrary user arguments, so we
+ # have to protect it against whitespace splitting
+ # when it gets run as "pack-objects $args" later.
+ # Fortunately, we know it's an approxidate, so we
+ # can just use dots instead.
+ args="$args $(echo "$unpack_unreachable" | tr ' ' .)"
+ fi
+ fi
+ ;;
+esac
+
+mkdir -p "$PACKDIR" || exit
+
+args="$args $local ${GIT_QUIET:+-q} $no_reuse$extra"
+names=$(git pack-objects --keep-true-parents --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
+ exit 1
+if [ -z "$names" ]; then
+ say Nothing new to pack.
+fi
+
+# Ok we have prepared all new packfiles.
+
+# First see if there are packs of the same name and if so
+# if we can move them out of the way (this can happen if we
+# repacked immediately after packing fully.
+rollback=
+failed=
+for name in $names
+do
+ for sfx in pack idx
+ do
+ file=pack-$name.$sfx
+ test -f "$PACKDIR/$file" || continue
+ rm -f "$PACKDIR/old-$file" &&
+ mv "$PACKDIR/$file" "$PACKDIR/old-$file" || {
+ failed=t
+ break
+ }
+ rollback="$rollback $file"
+ done
+ test -z "$failed" || break
+done
+
+# If renaming failed for any of them, roll the ones we have
+# already renamed back to their original names.
+if test -n "$failed"
+then
+ rollback_failure=
+ for file in $rollback
+ do
+ mv "$PACKDIR/old-$file" "$PACKDIR/$file" ||
+ rollback_failure="$rollback_failure $file"
+ done
+ if test -n "$rollback_failure"
+ then
+ echo >&2 "WARNING: Some packs in use have been renamed by"
+ echo >&2 "WARNING: prefixing old- to their name, in order to"
+ echo >&2 "WARNING: replace them with the new version of the"
+ echo >&2 "WARNING: file. But the operation failed, and"
+ echo >&2 "WARNING: attempt to rename them back to their"
+ echo >&2 "WARNING: original names also failed."
+ echo >&2 "WARNING: Please rename them in $PACKDIR manually:"
+ for file in $rollback_failure
+ do
+ echo >&2 "WARNING: old-$file -> $file"
+ done
+ fi
+ exit 1
+fi
+
+# Now the ones with the same name are out of the way...
+fullbases=
+for name in $names
+do
+ fullbases="$fullbases pack-$name"
+ chmod a-w "$PACKTMP-$name.pack"
+ chmod a-w "$PACKTMP-$name.idx"
+ mv -f "$PACKTMP-$name.pack" "$PACKDIR/pack-$name.pack" &&
+ mv -f "$PACKTMP-$name.idx" "$PACKDIR/pack-$name.idx" ||
+ exit
+done
+
+# Remove the "old-" files
+for name in $names
+do
+ rm -f "$PACKDIR/old-pack-$name.idx"
+ rm -f "$PACKDIR/old-pack-$name.pack"
+done
+
+# End of pack replacement.
+
+if test "$remove_redundant" = t
+then
+ # We know $existing are all redundant.
+ if [ -n "$existing" ]
+ then
+ ( cd "$PACKDIR" &&
+ for e in $existing
+ do
+ case " $fullbases " in
+ *" $e "*) ;;
+ *) rm -f "$e.pack" "$e.idx" "$e.keep" ;;
+ esac
+ done
+ )
+ fi
+ git prune-packed ${GIT_QUIET:+-q}
+fi
+
+case "$no_update_info" in
+t) : ;;
+*) git update-server-info ;;
+esac
--- /dev/null
+#!/bin/sh
+
+USAGE='[-p] [--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [-m] [git-diff-tree options] [git-rev-list options]'
+SUBDIRECTORY_OK='Yes'
+. git-sh-setup
+
+diff_tree_flags=$(git-rev-parse --sq --no-revs --flags "$@") || exit
+case "$0" in
+*whatchanged)
+ count=
+ test -z "$diff_tree_flags" &&
+ diff_tree_flags=$(git-repo-config --get whatchanged.difftree)
+ diff_tree_default_flags='-c -M --abbrev' ;;
+*show)
+ count=-n1
+ test -z "$diff_tree_flags" &&
+ diff_tree_flags=$(git-repo-config --get show.difftree)
+ diff_tree_default_flags='--cc --always' ;;
+esac
+test -z "$diff_tree_flags" &&
+ diff_tree_flags="$diff_tree_default_flags"
+
+rev_list_args=$(git-rev-parse --sq --default HEAD --revs-only "$@") &&
+diff_tree_args=$(git-rev-parse --sq --no-revs --no-flags "$@") &&
+
+eval "git-rev-list $count $rev_list_args" |
+eval "git-diff-tree --stdin --pretty -r $diff_tree_flags $diff_tree_args" |
+LESS="$LESS -S" ${PAGER:-less}
cat <<-EOF
To: $recipients
Subject: ${emailprefix}$projectdesc $refname_type $short_refname ${change_type}d. $describe
+ MIME-Version: 1.0
+ Content-Type: text/plain; charset=utf-8
+ Content-Transfer-Encoding: 8bit
X-Git-Refname: $refname
X-Git-Reftype: $refname_type
X-Git-Oldrev: $oldrev
echo " was $oldrev"
echo ""
echo $LOGBEGIN
- git show -s --pretty=oneline $oldrev
+ git diff-tree -s --always --encoding=UTF-8 --pretty=oneline $oldrev
echo $LOGEND
}
# performed on them
if [ -n "$prevtag" ]; then
# Show changes since the previous release
- git rev-list --pretty=short "$prevtag..$newrev" | git shortlog
+ git shortlog "$prevtag..$newrev"
else
# No previous tag, show all the changes since time
# began
- git rev-list --pretty=short $newrev | git shortlog
+ git shortlog $newrev
fi
;;
*)
echo " was $oldrev"
echo ""
echo $LOGBEGIN
- git show -s --pretty=oneline $oldrev
+ git diff-tree -s --always --encoding=UTF-8 --pretty=oneline $oldrev
echo $LOGEND
}
echo ""
if [ "$newrev_type" = "commit" ]; then
echo $LOGBEGIN
- git show --no-color --root -s --pretty=medium $newrev
+ git diff-tree -s --always --encoding=UTF-8 --pretty=medium $newrev
echo $LOGEND
else
# What can we do here? The tag marks an object that is not
echo " was $oldrev"
echo ""
echo $LOGBEGIN
- git show -s --pretty=oneline $oldrev
+ git diff-tree -s --always --encoding=UTF-8 --pretty=oneline $oldrev
echo $LOGEND
}
all: build
+test: all
+ $(MAKE) -C t
+
+check: perlcritic test
+
install_pm:
install $(GIT_MEDIAWIKI_PM) $(INSTLIBDIR)/$(GIT_MEDIAWIKI_PM)
rm $(INSTLIBDIR)/$(GIT_MEDIAWIKI_PM)
perlcritic:
- perlcritic -2 *.perl
+ perlcritic -5 $(SCRIPT_PERL)
+ -perlcritic -2 $(SCRIPT_PERL)
+
+.PHONY: all test check install_pm install clean perlcritic
print {*STDOUT} "import\n";
print {*STDOUT} "list\n";
print {*STDOUT} "push\n";
+ if ($dumb_push) {
+ print {*STDOUT} "no-private-update\n";
+ }
print {*STDOUT} "\n";
return;
}
rvstartid => $fetch_from,
rvlimit => 500,
pageids => $id,
+
+ # Let MediaWiki know that we support the latest API.
+ continue => '',
};
my $revnum = 0;
push(@page_revs, $page_rev_ids);
$revnum++;
}
- last if (!$result->{'query-continue'});
- $query->{rvstartid} = $result->{'query-continue'}->{revisions}->{rvstartid};
+
+ if ($result->{'query-continue'}) { # For legacy APIs
+ $query->{rvstartid} = $result->{'query-continue'}->{revisions}->{rvstartid};
+ } elsif ($result->{continue}) { # For newer APIs
+ $query->{rvstartid} = $result->{continue}->{rvcontinue};
+ $query->{continue} = $result->{continue}->{continue};
+ } else {
+ last;
+ }
}
if ($shallow_import && @page_revs) {
print {*STDERR} " Found 1 revision (shallow import).\n";
}
if (!$dumb_push) {
run_git(qq(notes --ref=${remotename}/mediawiki add -f -m "mediawiki_revision: ${mw_revision}" ${sha1_commit}));
- run_git(qq(update-ref -m "Git-MediaWiki push" refs/mediawiki/${remotename}/master ${sha1_commit} ${sha1_child}));
}
}
--- /dev/null
+#!/bin/sh
+
+test_description='Test the Git Mediawiki remote helper: queries w/ more than 500 results'
+
+. ./test-gitmw-lib.sh
+. $TEST_DIRECTORY/test-lib.sh
+
+test_check_precond
+
+test_expect_success 'creating page w/ >500 revisions' '
+ wiki_reset &&
+ for i in `test_seq 501`
+ do
+ echo "creating revision $i" &&
+ wiki_editpage foo "revision $i<br/>" true
+ done
+'
+
+test_expect_success 'cloning page w/ >500 revisions' '
+ git clone mediawiki::'"$WIKI_URL"' mw_dir
+'
+
+test_done
# or
# % git clone bzr::lp:myrepo
#
-# If you want to specify which branches you want track (per repo):
-# git config remote-bzr.branches 'trunk, devel, test'
+# If you want to specify which branches you want to track (per repo):
+# % git config remote.origin.bzr-branches 'trunk, devel, test'
+#
+# Where 'origin' is the name of the repository you want to specify the
+# branches.
#
import sys
if not m:
return None
_, name, email, date, tz = m.groups()
+ name = name.decode('utf-8')
committer = '%s <%s>' % (name, email)
tz = int(tz)
tz = ((tz / 100) * 3600) + ((tz % 100) * 60)
return (committer, int(date), tz)
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 fixup_user(user):
return modified, removed
def export_files(tree, files):
- global marks, filenodes
-
final = []
for path, fid in files.iteritems():
kind = tree.kind(fid)
return final
def export_branch(repo, name):
- global prefix
-
ref = '%s/heads/%s' % (prefix, name)
tip = marks.get_tip(name)
marks.set_tip(name, revid)
def export_tag(repo, name):
- global tags, prefix
-
ref = '%s/tags/%s' % (prefix, name)
print "reset %s" % ref
print "from :%u" % rev_to_mark(tags[name])
print
def do_import(parser):
- global dirname
-
repo = parser.repo
path = os.path.join(dirname, 'marks-git')
sys.stdout.flush()
def parse_blob(parser):
- global blob_marks
-
parser.next()
mark = parser.get_mark()
parser.next()
class CustomTree():
def __init__(self, branch, revid, parents, files):
- global files_cache
-
self.updates = {}
self.branch = branch
add_entry(fid, dirname, 'directory')
return fid
- def add_entry(fid, path, kind, mode = None):
+ def add_entry(fid, path, kind, mode=None):
dirname, basename = os.path.split(path)
parent_fid = get_parent(dirname, basename)
self.files[path] = [change[0], None]
changes.append(change)
- def update_entry(fid, path, kind, mode = None):
+ def update_entry(fid, path, kind, mode=None):
dirname, basename = os.path.split(path)
parent_fid = get_parent(dirname, basename)
return string
def parse_commit(parser):
- global marks, blob_marks, parsed_refs
- global mode
-
parents = []
ref = parser[1]
marks.new_mark(revid, commit_mark)
def parse_reset(parser):
- global parsed_refs
-
ref = parser[1]
parser.next()
parsed_refs[ref] = mark_to_rev(from_mark)
def do_export(parser):
- global parsed_refs, dirname
-
parser.next()
for line in parser.each_block('done'):
branch.generate_revision_history(revid, marks.get_tip(name))
if name in peers:
- peer = bzrlib.branch.Branch.open(peers[name])
+ peer = bzrlib.branch.Branch.open(peers[name],
+ possible_transports=transports)
try:
peer.bzrdir.push_branch(branch, revision_id=revid)
except bzrlib.errors.DivergedBranches:
print
def do_capabilities(parser):
- global dirname
-
print "import"
print "export"
print "refspec refs/heads/*:%s/heads/*" % prefix
return not True in [c in name for c in '~^: \\']
def do_list(parser):
- global tags
-
master_branch = None
for name in branches:
def clone(path, remote_branch):
try:
- bdir = bzrlib.bzrdir.BzrDir.create(path)
+ bdir = bzrlib.bzrdir.BzrDir.create(path, possible_transports=transports)
except bzrlib.errors.AlreadyControlDirError:
- bdir = bzrlib.bzrdir.BzrDir.open(path)
+ bdir = bzrlib.bzrdir.BzrDir.open(path, possible_transports=transports)
repo = bdir.find_repository()
repo.fetch(remote_branch.repository)
return remote_branch.sprout(bdir, repository=repo)
def get_remote_branch(name):
- global dirname, branches
-
- remote_branch = bzrlib.branch.Branch.open(branches[name])
+ remote_branch = bzrlib.branch.Branch.open(branches[name],
+ possible_transports=transports)
if isinstance(remote_branch.user_transport, bzrlib.transport.local.LocalTransport):
return remote_branch
branch_path = os.path.join(dirname, 'clone', name)
try:
- branch = bzrlib.branch.Branch.open(branch_path)
+ branch = bzrlib.branch.Branch.open(branch_path,
+ possible_transports=transports)
except bzrlib.errors.NotBranchError:
# clone
branch = clone(branch_path, remote_branch)
yield name, branch.base
def get_repo(url, alias):
- global dirname, peer, branches
-
normal_url = bzrlib.urlutils.normalize_url(url)
- origin = bzrlib.bzrdir.BzrDir.open(url)
+ origin = bzrlib.bzrdir.BzrDir.open(url, possible_transports=transports)
is_local = isinstance(origin.transport, bzrlib.transport.local.LocalTransport)
shared_path = os.path.join(gitdir, 'bzr')
try:
- shared_dir = bzrlib.bzrdir.BzrDir.open(shared_path)
+ shared_dir = bzrlib.bzrdir.BzrDir.open(shared_path,
+ possible_transports=transports)
except bzrlib.errors.NotBranchError:
- shared_dir = bzrlib.bzrdir.BzrDir.create(shared_path)
+ shared_dir = bzrlib.bzrdir.BzrDir.create(shared_path,
+ possible_transports=transports)
try:
shared_repo = shared_dir.open_repository()
except bzrlib.errors.NoRepositoryPresent:
else:
# check and remove old organization
try:
- bdir = bzrlib.bzrdir.BzrDir.open(clone_path)
+ bdir = bzrlib.bzrdir.BzrDir.open(clone_path,
+ possible_transports=transports)
bdir.destroy_repository()
except bzrlib.errors.NotBranchError:
pass
except bzrlib.errors.NoRepositoryPresent:
pass
- wanted = get_config('remote-bzr.branches').rstrip().split(', ')
+ wanted = get_config('remote.%s.bzr-branches' % alias).rstrip().split(', ')
# stupid python
wanted = [e for e in wanted if e]
+ if not wanted:
+ wanted = get_config('remote-bzr.branches').rstrip().split(', ')
+ # stupid python
+ wanted = [e for e in wanted if e]
if not wanted:
try:
global files_cache
global is_tmp
global branches, peers
+ global transports
alias = args[1]
url = args[2]
marks = None
branches = {}
peers = {}
+ transports = []
if alias[5:] == url:
is_tmp = True
import urllib
import atexit
import urlparse, hashlib
+import time as ptime
+#
+# If you want to see Mercurial revisions as Git commit notes:
+# git config core.notesRef refs/notes/hg
#
# If you are not in hg-git-compat mode and want to disable the tracking of
# named branches:
self.rev_marks = {}
self.last_mark = 0
self.version = 0
+ self.last_note = 0
def load(self):
if not os.path.exists(self.path):
self.marks = tmp['marks']
self.last_mark = tmp['last-mark']
self.version = tmp.get('version', 1)
+ self.last_note = tmp.get('last-note', 0)
for rev, mark in self.marks.iteritems():
self.rev_marks[mark] = rev
self.version = 2
def dict(self):
- return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark, 'version' : self.version }
+ return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark, 'version' : self.version, 'last-note' : self.last_note }
def store(self):
json.dump(self.dict(), open(self.path, 'w'))
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 os.path.relpath(path, '/')
def export_files(files):
- global marks, filenodes
-
final = []
for f in files:
fid = node.hex(f.filenode())
return (name, mail)
def fixup_user(user):
- global mode, bad_mail
-
if mode == 'git':
name, mail = fixup_user_git(user)
else:
bookmarks.write(repo)
def get_repo(url, alias):
- global dirname, peer
+ global peer
myui = ui.ui()
myui.setconfig('ui', 'interactive', 'off')
os.makedirs(dirname)
else:
shared_path = os.path.join(gitdir, 'hg')
- if not os.path.exists(shared_path):
- try:
- hg.clone(myui, {}, url, shared_path, update=False, pull=True)
- except:
- die('Repository error')
+
+ # check and upgrade old organization
+ hg_path = os.path.join(shared_path, '.hg')
+ if os.path.exists(shared_path) and not os.path.exists(hg_path):
+ repos = os.listdir(shared_path)
+ for x in repos:
+ local_hg = os.path.join(shared_path, x, 'clone', '.hg')
+ if not os.path.exists(local_hg):
+ continue
+ if not os.path.exists(hg_path):
+ shutil.move(local_hg, hg_path)
+ shutil.rmtree(os.path.join(shared_path, x, 'clone'))
+
+ # setup shared repo (if not there)
+ try:
+ hg.peer(myui, {}, shared_path, create=True)
+ except error.RepoError:
+ pass
if not os.path.exists(dirname):
os.makedirs(dirname)
return repo
def rev_to_mark(rev):
- global marks
return marks.from_rev(rev.hex())
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)
try:
tip = marks.get_tip(ename)
print "from :%u" % rev_to_mark(head)
print
+ pending_revs = set(revs) - notes
+ if pending_revs:
+ note_mark = marks.next_mark()
+ ref = "refs/notes/hg"
+
+ print "commit %s" % ref
+ print "mark :%d" % (note_mark)
+ print "committer remote-hg <> %s" % (ptime.strftime('%s %z'))
+ desc = "Notes for %s\n" % (name)
+ print "data %d" % (len(desc))
+ print desc
+ if marks.last_note:
+ print "from :%u" % marks.last_note
+
+ for rev in pending_revs:
+ notes.add(rev)
+ c = repo[rev]
+ print "N inline :%u" % rev_to_mark(c)
+ msg = c.hex()
+ print "data %d" % (len(msg))
+ print msg
+ print
+
+ marks.last_note = note_mark
+
marks.set_tip(ename, head.hex())
def export_tag(repo, tag):
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
return branches[branch][-1]
def get_branch_tip(repo, branch):
- global branches
-
heads = branches.get(hgref(branch), None)
if not heads:
return None
return heads[0]
def list_head(repo, cur):
- global g_head, bmarks, fake_bmark
+ global g_head, fake_bmark
if 'default' not in branches:
# empty repo
g_head = (head, node)
def do_list(parser):
- global branches, bmarks, track_branches
-
repo = parser.repo
for bmark, node in bookmarks.listbookmarks(repo).iteritems():
bmarks[bmark] = repo[node]
print 'done'
def parse_blob(parser):
- global blob_marks
-
parser.next()
mark = parser.get_mark()
parser.next()
f = { 'ctx' : repo[p1][e] }
files[e] = f
-def parse_commit(parser):
- global marks, blob_marks, parsed_refs
- global mode
+def c_style_unescape(string):
+ if string[0] == string[-1] == '"':
+ return string.decode('string-escape')[1:-1]
+ return string
+def parse_commit(parser):
from_mark = merge_mark = None
ref = parser[1]
f = { 'deleted' : True }
else:
die('Unknown file command: %s' % line)
+ path = c_style_unescape(path).decode('utf-8')
files[path] = f
# only export the commits if we are on an internal proxy repo
marks.new_mark(node, commit_mark)
def parse_reset(parser):
- global parsed_refs
-
ref = parser[1]
parser.next()
# ugh
return tip in heads
def do_export(parser):
- global parsed_refs, bmarks, peer
-
p_bmarks = []
p_revs = {}
author, msg = parsed_tags.get(tag, (None, None))
if mode == 'git':
if not msg:
- msg = 'Added tag %s for changeset %s' % (tag, node[:12]);
+ msg = 'Added tag %s for changeset %s' % (tag, node[:12])
tagnode, branch = write_tag(parser.repo, tag, node, msg, author)
p_revs[tagnode] = 'refs/heads/branches/' + gitref(branch)
else:
def fix_path(alias, repo, orig_url):
url = urlparse.urlparse(orig_url, 'file')
- if url.scheme != 'file' or os.path.isabs(url.path):
+ if url.scheme != 'file' or os.path.isabs(os.path.expanduser(url.path)):
return
abs_url = urlparse.urljoin("%s/" % os.getcwd(), orig_url)
cmd = ['git', 'config', 'remote.%s.url' % alias, "hg::%s" % abs_url]
global filenodes
global fake_bmark, hg_version
global dry_run
+ global notes, alias
alias = args[1]
url = args[2]
except:
hg_version = None
dry_run = False
+ notes = set()
repo = get_repo(url, alias)
prefix = 'refs/hg/%s' % alias
. ./test-lib.sh
-if ! test_have_prereq PYTHON; then
+if ! test_have_prereq PYTHON
+then
skip_all='skipping remote-bzr tests; python not available'
test_done
fi
-if ! python -c 'import bzrlib'; then
+if ! python -c 'import bzrlib'
+then
skip_all='skipping remote-bzr tests; bzr not available'
test_done
fi
check () {
- echo $3 > expected &&
- git --git-dir=$1/.git log --format='%s' -1 $2 > actual
+ echo $3 >expected &&
+ git --git-dir=$1/.git log --format='%s' -1 $2 >actual
test_cmp expected actual
}
(
bzr init bzrrepo &&
cd bzrrepo &&
- echo one > content &&
+ echo one >content &&
bzr add content &&
bzr commit -m one
) &&
test_expect_success 'pulling' '
(
cd bzrrepo &&
- echo two > content &&
+ echo two >content &&
bzr commit -m two
) &&
test_expect_success 'pushing' '
(
cd gitrepo &&
- echo three > content &&
+ echo three >content &&
git commit -a -m three &&
git push
) &&
- echo three > expected &&
- cat bzrrepo/content > actual &&
+ echo three >expected &&
+ cat bzrrepo/content >actual &&
test_cmp expected actual
'
(
cd gitrepo &&
git pull &&
- git log --format="%s" -1 origin/master > actual
+ git log --format="%s" -1 origin/master >actual
) &&
- echo three > expected &&
+ echo three >expected &&
test_cmp expected actual &&
(cd gitrepo && git push && git pull) &&
(
cd bzrrepo &&
- echo four > content &&
+ echo four >content &&
bzr commit -m four
) &&
(
cd gitrepo &&
- echo five > content &&
+ echo five >content &&
git commit -a -m five &&
git push && git pull
) &&
(cd bzrrepo && bzr revert) &&
- echo five > expected &&
- cat bzrrepo/content > actual &&
+ echo five >expected &&
+ cat bzrrepo/content >actual &&
test_cmp expected actual
'
-cat > expected <<EOF
+cat >expected <<\EOF
100644 blob 54f9d6da5c91d556e6b54340b1327573073030af content
100755 blob 68769579c3eaadbe555379b9c3538e6628bae1eb executable
120000 blob 6b584e8ece562ebffc15d38808cd6b98fc3d97ea link
test_expect_success 'special modes' '
(
cd bzrrepo &&
- echo exec > executable
+ echo exec >executable
chmod +x executable &&
bzr add executable
bzr commit -m exec &&
(
cd gitrepo &&
git pull
- git ls-tree HEAD > ../actual
+ git ls-tree HEAD >../actual
) &&
test_cmp expected actual &&
(
cd gitrepo &&
- git cat-file -p HEAD:link > ../actual
+ git cat-file -p HEAD:link >../actual
) &&
- printf content > expected &&
+ printf content >expected &&
test_cmp expected actual
'
-cat > expected <<EOF
+cat >expected <<\EOF
100644 blob 54f9d6da5c91d556e6b54340b1327573073030af content
100755 blob 68769579c3eaadbe555379b9c3538e6628bae1eb executable
120000 blob 6b584e8ece562ebffc15d38808cd6b98fc3d97ea link
(
cd bzrrepo &&
mkdir movedir &&
- echo one > movedir/one &&
- echo two > movedir/two &&
+ echo one >movedir/one &&
+ echo two >movedir/two &&
bzr add movedir &&
bzr commit -m movedir &&
bzr mv movedir movedir-new &&
(
cd gitrepo &&
git pull &&
- git ls-tree HEAD > ../actual
+ git ls-tree HEAD >../actual
) &&
test_cmp expected actual
test_expect_success 'different authors' '
(
cd bzrrepo &&
- echo john >> content &&
+ echo john >>content &&
bzr commit -m john \
--author "Jane Rey <jrey@example.com>" \
--author "John Doe <jdoe@example.com>"
(
cd gitrepo &&
git pull &&
- git show --format="%an <%ae>, %cn <%ce>" --quiet > ../actual
+ git show --format="%an <%ae>, %cn <%ce>" --quiet >../actual
) &&
- echo "Jane Rey <jrey@example.com>, A U Thor <author@example.com>" > expected &&
+ echo "Jane Rey <jrey@example.com>, A U Thor <author@example.com>" >expected &&
test_cmp expected actual
'
bzr init bzrrepo &&
cd bzrrepo &&
- echo test >> "ærø" &&
+ echo test >>"ærø" &&
bzr add "ærø" &&
- echo test >> "ø~?" &&
+ echo test >>"ø~?" &&
bzr add "ø~?" &&
bzr commit -m add-utf-8 &&
- echo test >> "ærø" &&
+ echo test >>"ærø" &&
bzr commit -m test-utf-8 &&
bzr rm "ø~?" &&
bzr mv "ærø" "ø~?" &&
(
git clone "bzr::bzrrepo" gitrepo &&
cd gitrepo &&
- git -c core.quotepath=false ls-files > ../actual
+ git -c core.quotepath=false ls-files >../actual
) &&
- echo "ø~?" > expected &&
+ echo "ø~?" >expected &&
test_cmp expected actual
'
bzr init bzrrepo &&
cd bzrrepo &&
- echo one >> content &&
+ echo one >>content &&
bzr add content &&
bzr commit -m one
) &&
git clone "bzr::bzrrepo" gitrepo &&
cd gitrepo &&
- echo test >> "ærø" &&
+ echo test >>"ærø" &&
git add "ærø" &&
git commit -m utf-8 &&
git push
) &&
- (cd bzrrepo && bzr ls > ../actual) &&
- printf "content\nærø\n" > expected &&
+ (cd bzrrepo && bzr ls >../actual) &&
+ printf "content\nærø\n" >expected &&
test_cmp expected actual
'
(
bzr init bzrrepo &&
cd bzrrepo &&
- echo one > content &&
+ echo one >content &&
bzr add content &&
bzr commit -m one
) &&
(
cd bzrrepo &&
- echo two > content &&
+ echo two >content &&
bzr commit -m two
) &&
(
cd gitrepo &&
- echo three > content &&
+ echo three >content &&
git commit -a -m three &&
git fetch &&
git merge origin/master || true &&
- echo three > content &&
+ echo three >content &&
git commit -a --no-edit &&
git push
) &&
- echo three > expected &&
- cat bzrrepo/content > actual &&
+ echo three >expected &&
+ cat bzrrepo/content >actual &&
test_cmp expected actual
'
-cat > expected <<EOF
+cat >expected <<\EOF
origin/HEAD
origin/branch
origin/trunk
(
bzr init bzrrepo/trunk &&
cd bzrrepo/trunk &&
- echo one >> content &&
+ echo one >>content &&
bzr add content &&
bzr commit -m one
) &&
(
bzr branch bzrrepo/trunk bzrrepo/branch &&
cd bzrrepo/branch &&
- echo two >> content &&
+ echo two >>content &&
bzr commit -m one
) &&
(
git clone "bzr::bzrrepo" gitrepo &&
cd gitrepo &&
- git for-each-ref --format "%(refname:short)" refs/remotes/origin > ../actual
+ git for-each-ref --format "%(refname:short)" refs/remotes/origin >../actual
) &&
test_cmp expected actual
bzr init bzrrepo &&
cd bzrrepo &&
- echo one >> content &&
+ echo one >>content &&
bzr add content &&
bzr commit -m one &&
- echo two >> content &&
+ echo two >>content &&
bzr commit -m two
) &&
cd bzrrepo &&
bzr uncommit --force &&
- echo three >> content &&
+ echo three >>content &&
bzr commit -m three &&
- echo four >> content &&
+ echo four >>content &&
bzr commit -m four &&
- bzr log --line | sed -e "s/^[0-9][0-9]*: //" > ../expected
+ bzr log --line | sed -e "s/^[0-9][0-9]*: //" >../expected
) &&
(
cd gitrepo &&
git fetch &&
- git log --format="%an %ad %s" --date=short origin/master > ../actual
+ git log --format="%an %ad %s" --date=short origin/master >../actual
) &&
test_cmp expected actual
'
+test_expect_success 'export utf-8 authors' '
+ test_when_finished "rm -rf bzrrepo gitrepo && LC_ALL=C && unset GIT_COMMITTER_NAME" &&
+
+ LC_ALL=en_US.UTF-8
+ export LC_ALL
+
+ GIT_COMMITTER_NAME="Grégoire"
+ export GIT_COMMITTER_NAME
+
+ bzr init bzrrepo &&
+
+ (
+ git init gitrepo &&
+ cd gitrepo &&
+ echo greg >>content &&
+ git add content &&
+ git commit -m one &&
+ git remote add bzr "bzr::../bzrrepo" &&
+ git push bzr
+ ) &&
+
+ (
+ cd bzrrepo &&
+ bzr log | grep "^committer: " >../actual
+ ) &&
+
+ echo "committer: Grégoire <committer@example.com>" >expected &&
+ test_cmp expected actual
+'
+
test_done
. ./test-lib.sh
-if ! test_have_prereq PYTHON; then
+if ! test_have_prereq PYTHON
+then
skip_all='skipping remote-hg tests; python not available'
test_done
fi
-if ! python -c 'import mercurial'; then
+if ! python -c 'import mercurial'
+then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
fi
git checkout -q -b tmp &&
git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
git checkout -q @{-1} &&
- git branch -q -D tmp 2> /dev/null || true
+ git branch -q -D tmp 2>/dev/null || true
)
}
echo "tag = -d \"0 0\""
echo "[extensions]"
echo "graphlog ="
- ) >> "$HOME"/.hgrc &&
+ ) >>"$HOME"/.hgrc &&
git config --global remote-hg.hg-git-compat true
git config --global remote-hg.track-branches true
git init -q gitrepo &&
cd gitrepo &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
git add alpha &&
git commit -m "add älphà" &&
GIT_AUTHOR_NAME="tést èncödîng" &&
export GIT_AUTHOR_NAME &&
- echo beta > beta &&
+ echo beta >beta &&
git add beta &&
git commit -m "add beta" &&
- echo gamma > gamma &&
+ echo gamma >gamma &&
git add gamma &&
git commit -m "add gämmâ" &&
: TODO git config i18n.commitencoding latin-1 &&
- echo delta > delta &&
+ echo delta >delta &&
git add delta &&
git commit -m "add déltà"
) &&
git_clone hgrepo gitrepo2 &&
hg_clone gitrepo2 hgrepo2 &&
- HGENCODING=utf-8 hg_log hgrepo > expected &&
- HGENCODING=utf-8 hg_log hgrepo2 > actual &&
+ HGENCODING=utf-8 hg_log hgrepo >expected &&
+ HGENCODING=utf-8 hg_log hgrepo2 >actual &&
test_cmp expected actual
'
(
git init -q gitrepo &&
cd gitrepo &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
git add alpha &&
git commit -m "add alpha" &&
- echo beta > beta &&
+ echo beta >beta &&
git add beta &&
git commit -m "add beta"
mkdir foo &&
- echo blah > foo/bar &&
+ echo blah >foo/bar &&
git add foo &&
git commit -m "add foo" &&
git rm alpha &&
git_clone hgrepo gitrepo2 &&
hg_clone gitrepo2 hgrepo2 &&
- hg_log hgrepo > expected &&
- hg_log hgrepo2 > actual &&
+ hg_log hgrepo >expected &&
+ hg_log hgrepo2 >actual &&
test_cmp expected actual
'
git init -q gitrepo &&
cd gitrepo &&
git config receive.denyCurrentBranch ignore &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
git add alpha &&
git commit -m "add alpha" &&
git tag alpha &&
- echo beta > beta &&
+ echo beta >beta &&
git add beta &&
git commit -m "add beta" &&
git tag -a -m "added tag beta" beta
git_clone hgrepo gitrepo2 &&
hg_clone gitrepo2 hgrepo2 &&
- hg_log hgrepo > expected &&
- hg_log hgrepo2 > actual &&
+ hg_log hgrepo >expected &&
+ hg_log hgrepo2 >actual &&
test_cmp expected actual
'
git init -q gitrepo &&
cd gitrepo &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
git add alpha &&
git commit -q -m "add alpha" &&
git checkout -q -b not-master
: Back to the common revision &&
(cd hgrepo && hg checkout default) &&
- hg_log hgrepo > expected &&
- hg_log hgrepo2 > actual &&
+ hg_log hgrepo >expected &&
+ hg_log hgrepo2 >actual &&
test_cmp expected actual
'
git init -q gitrepo &&
cd gitrepo &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
git add alpha &&
git commit -m "add alpha" &&
git checkout -q -b not-master
hg_push hgrepo gitrepo &&
hg_clone gitrepo hgrepo2 &&
- hg_log hgrepo > expected &&
- hg_log hgrepo2 > actual &&
+ hg_log hgrepo >expected &&
+ hg_log hgrepo2 >actual &&
test_cmp expected actual
'
. ./test-lib.sh
-if ! test_have_prereq PYTHON; then
+if ! test_have_prereq PYTHON
+then
skip_all='skipping remote-hg tests; python not available'
test_done
fi
-if ! python -c 'import mercurial'; then
+if ! python -c 'import mercurial'
+then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
fi
-if ! python -c 'import hggit'; then
+if ! python -c 'import hggit'
+then
skip_all='skipping remote-hg tests; hg-git not available'
test_done
fi
git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
git branch -D default &&
git checkout -q @{-1} &&
- git branch -q -D tmp 2> /dev/null || true
+ git branch -q -D tmp 2>/dev/null || true
)
}
echo "hgext.bookmarks ="
echo "hggit ="
echo "graphlog ="
- ) >> "$HOME"/.hgrc &&
+ ) >>"$HOME"/.hgrc &&
git config --global receive.denycurrentbranch warn
git config --global remote-hg.hg-git-compat true
git config --global remote-hg.track-branches false
(
git init -q gitrepo &&
cd gitrepo &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
chmod 0644 alpha &&
git add alpha &&
git commit -m "add alpha" &&
git commit -m "clear executable bit"
) &&
- for x in hg git; do
+ for x in hg git
+ do
(
hg_clone_$x gitrepo hgrepo-$x &&
cd hgrepo-$x &&
hg_log . &&
hg manifest -r 1 -v &&
hg manifest -v
- ) > output-$x &&
+ ) >"output-$x" &&
git_clone_$x hgrepo-$x gitrepo2-$x &&
- git_log gitrepo2-$x > log-$x
+ git_log gitrepo2-$x >"log-$x"
done &&
test_cmp output-hg output-git &&
(
git init -q gitrepo &&
cd gitrepo &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
git add alpha &&
git commit -m "add alpha" &&
ln -s alpha beta &&
git commit -m "add beta"
) &&
- for x in hg git; do
+ for x in hg git
+ do
(
hg_clone_$x gitrepo hgrepo-$x &&
cd hgrepo-$x &&
hg_log . &&
hg manifest -v
- ) > output-$x &&
+ ) >"output-$x" &&
git_clone_$x hgrepo-$x gitrepo2-$x &&
- git_log gitrepo2-$x > log-$x
+ git_log gitrepo2-$x >"log-$x"
done &&
test_cmp output-hg output-git &&
(
hg init hgrepo1 &&
cd hgrepo1 &&
- echo A > afile &&
+ echo A >afile &&
hg add afile &&
hg ci -m "origin" &&
- echo B > afile &&
+ echo B >afile &&
hg ci -m "A->B" &&
hg up -r0 &&
- echo C > afile &&
+ echo C >afile &&
hg ci -m "A->C" &&
hg merge -r1 &&
- echo C > afile &&
+ echo C >afile &&
hg resolve -m afile &&
hg ci -m "merge to C"
) &&
- for x in hg git; do
+ 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
+ hg_log hgrepo2-$x >"hg-log-$x" &&
+ git_log gitrepo-$x >"git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
(
hg init hgrepo1 &&
cd hgrepo1 &&
- echo A > afile &&
+ echo A >afile &&
hg add afile &&
hg ci -m "origin" &&
- echo B > afile &&
+ echo B >afile &&
hg ci -m "A->B" &&
hg up -r0 &&
- echo C > afile &&
+ echo C >afile &&
hg ci -m "A->C" &&
hg merge -r1 || true &&
- echo B > afile &&
+ echo B >afile &&
hg resolve -m afile &&
hg ci -m "merge to B"
) &&
- for x in hg git; do
+ 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
+ hg_log hgrepo2-$x >"hg-log-$x" &&
+ git_log gitrepo-$x >"git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
(
hg init hgrepo1 &&
cd hgrepo1 &&
- echo A > afile &&
+ echo A >afile &&
hg add afile &&
hg ci -m "origin" &&
- echo B > afile &&
+ echo B >afile &&
hg ci -m "A->B" &&
- echo C > afile &&
+ echo C >afile &&
hg ci -m "B->C" &&
hg up -r0 &&
- echo C > afile &&
+ echo C >afile &&
hg ci -m "A->C" &&
hg merge -r2 || true &&
hg ci -m "merge"
) &&
- for x in hg git; do
+ 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
+ hg_log hgrepo2-$x >"hg-log-$x" &&
+ git_log gitrepo-$x >"git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
git init -q gitrepo &&
cd gitrepo &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
git add alpha &&
git commit -m "add älphà" &&
GIT_AUTHOR_NAME="tést èncödîng" &&
export GIT_AUTHOR_NAME &&
- echo beta > beta &&
+ echo beta >beta &&
git add beta &&
git commit -m "add beta" &&
- echo gamma > gamma &&
+ echo gamma >gamma &&
git add gamma &&
git commit -m "add gämmâ" &&
: TODO git config i18n.commitencoding latin-1 &&
- echo delta > delta &&
+ echo delta >delta &&
git add delta &&
git commit -m "add déltà"
) &&
- for x in hg git; do
+ 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
+ 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 &&
(
git init -q gitrepo &&
cd gitrepo &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
git add alpha &&
git commit -m "add alpha" &&
- echo beta > beta &&
+ echo beta >beta &&
git add beta &&
git commit -m "add beta"
mkdir foo &&
- echo blah > foo/bar &&
+ echo blah >foo/bar &&
git add foo &&
git commit -m "add foo" &&
git rm alpha &&
git commit -m "remove foo/bar"
) &&
- for x in hg git; do
+ 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 &&
+ ) >"output-$x" &&
git_clone_$x hgrepo-$x gitrepo2-$x &&
- git_log gitrepo2-$x > log-$x
+ git_log gitrepo2-$x >"log-$x"
done &&
test_cmp output-hg output-git &&
git init -q gitrepo &&
cd gitrepo &&
git config receive.denyCurrentBranch ignore &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
git add alpha &&
git commit -m "add alpha" &&
git tag alpha &&
- echo beta > beta &&
+ 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
+ for x in hg git
+ do
hg_clone_$x gitrepo hgrepo-$x &&
- hg_log hgrepo-$x > log-$x
+ hg_log hgrepo-$x >"log-$x"
done &&
test_cmp log-hg log-git
test_expect_success 'hg author' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
- for x in hg git; do
+ for x in hg git
+ do
(
git init -q gitrepo-$x &&
cd gitrepo-$x &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
git add alpha &&
git commit -m "add alpha" &&
git checkout -q -b not-master
cd hgrepo-$x &&
hg co master &&
- echo beta > beta &&
+ echo beta >beta &&
hg add beta &&
hg commit -u "test" -m "add beta" &&
- echo gamma >> beta &&
+ echo gamma >>beta &&
hg commit -u "test <test@example.com> (comment)" -m "modify beta" &&
- echo gamma > gamma &&
+ echo gamma >gamma &&
hg add gamma &&
hg commit -u "<test@example.com>" -m "add gamma" &&
- echo delta > delta &&
+ echo delta >delta &&
hg add delta &&
hg commit -u "name<test@example.com>" -m "add delta" &&
- echo epsilon > epsilon &&
+ echo epsilon >epsilon &&
hg add epsilon &&
hg commit -u "name <test@example.com" -m "add epsilon" &&
- echo zeta > zeta &&
+ echo zeta >zeta &&
hg add zeta &&
hg commit -u " test " -m "add zeta" &&
- echo eta > eta &&
+ echo eta >eta &&
hg add eta &&
hg commit -u "test < test@example.com >" -m "add eta" &&
- echo theta > theta &&
+ echo theta >theta &&
hg add theta &&
hg commit -u "test >test@example.com>" -m "add theta" &&
- echo iota > iota &&
+ 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
+ hg_log hgrepo2-$x >"hg-log-$x" &&
+ git_log gitrepo-$x >"git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
test_expect_success 'hg branch' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
- for x in hg git; do
+ for x in hg git
+ do
(
git init -q gitrepo-$x &&
cd gitrepo-$x &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
git add alpha &&
git commit -q -m "add alpha" &&
git checkout -q -b not-master
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
+ hg_log hgrepo2-$x >"hg-log-$x" &&
+ git_log gitrepo-$x >"git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
test_expect_success 'hg tags' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
- for x in hg git; do
+ for x in hg git
+ do
(
git init -q gitrepo-$x &&
cd gitrepo-$x &&
- echo alpha > alpha &&
+ echo alpha >alpha &&
git add alpha &&
git commit -m "add alpha" &&
git checkout -q -b not-master
git --git-dir=gitrepo-$x/.git tag -l &&
hg_log hgrepo2-$x &&
cat hgrepo2-$x/.hgtags
- ) > output-$x
+ ) >"output-$x"
done &&
test_cmp output-hg output-git
. ./test-lib.sh
-if ! test_have_prereq PYTHON; then
+if ! test_have_prereq PYTHON
+then
skip_all='skipping remote-hg tests; python not available'
test_done
fi
-if ! python -c 'import mercurial'; then
+if ! python -c 'import mercurial'
+then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
fi
check () {
- echo $3 > expected &&
- git --git-dir=$1/.git log --format='%s' -1 $2 > actual
+ echo $3 >expected &&
+ git --git-dir=$1/.git log --format='%s' -1 $2 >actual
test_cmp expected actual
}
check_branch () {
- if [ -n "$3" ]; then
- echo $3 > expected &&
- hg -R $1 log -r $2 --template '{desc}\n' > actual &&
+ if test -n "$3"
+ then
+ echo $3 >expected &&
+ hg -R $1 log -r $2 --template '{desc}\n' >actual &&
test_cmp expected actual
else
- hg -R $1 branches > out &&
+ hg -R $1 branches >out &&
! grep $2 out
fi
}
check_bookmark () {
- if [ -n "$3" ]; then
- echo $3 > expected &&
- hg -R $1 log -r "bookmark('$2')" --template '{desc}\n' > actual &&
+ if test -n "$3"
+ then
+ echo $3 >expected &&
+ hg -R $1 log -r "bookmark('$2')" --template '{desc}\n' >actual &&
test_cmp expected actual
else
- hg -R $1 bookmarks > out &&
+ hg -R $1 bookmarks >out &&
! grep $2 out
fi
}
local expected_ret=$1 ret=0 ref_ret=0 IFS=':'
shift
- git push origin "$@" 2> error
+ git push origin "$@" 2>error
ret=$?
cat error
grep "^ [a-f0-9]*\.\.[a-f0-9]* *${branch} -> ${branch}$" error || ref_ret=1
;;
esac
- let 'ref_ret' && echo "match for '$branch' failed" && break
+ test $ref_ret -ne 0 && echo "match for '$branch' failed" && break
done
- if let 'expected_ret != ret || ref_ret'
+ if test $expected_ret -ne $ret -o $ref_ret -ne 0
then
return 1
fi
echo "username = H G Wells <wells@example.com>"
echo "[extensions]"
echo "mq ="
- ) >> "$HOME"/.hgrc &&
+ ) >>"$HOME"/.hgrc &&
GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" &&
GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" &&
(
hg init hgrepo &&
cd hgrepo &&
- echo zero > content &&
+ echo zero >content &&
hg add content &&
hg commit -m zero
) &&
(
cd hgrepo &&
hg branch next &&
- echo next > content &&
+ echo next >content &&
hg commit -m next
) &&
cd hgrepo &&
hg checkout default &&
hg bookmark feature-a &&
- echo feature-a > content &&
+ echo feature-a >content &&
hg commit -m feature-a
) &&
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet devel &&
- echo devel > content &&
+ echo devel >content &&
git commit -a -m devel &&
git push --quiet
) &&
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet -b feature-b &&
- echo feature-b > content &&
+ echo feature-b >content &&
git commit -a -m feature-b &&
git push --quiet origin feature-b
) &&
rm -rf hgrepo
author_test () {
- echo $1 >> content &&
+ echo $1 >>content &&
hg commit -u "$2" -m "add $1" &&
- echo "$3" >> ../expected
+ echo "$3" >>../expected
}
test_expect_success 'authors' '
touch content &&
hg add content &&
- > ../expected &&
+ >../expected &&
author_test alpha "" "H G Wells <wells@example.com>" &&
author_test beta "test" "test <unknown>" &&
author_test beta "test <test@example.com> (comment)" "test <test@example.com>" &&
) &&
git clone "hg::hgrepo" gitrepo &&
- git --git-dir=gitrepo/.git log --reverse --format="%an <%ae>" > actual &&
+ git --git-dir=gitrepo/.git log --reverse --format="%an <%ae>" >actual &&
test_cmp expected actual
'
hg init hgrepo &&
cd hgrepo &&
- echo one >> content &&
+ echo one >>content &&
hg add content &&
hg commit -m one &&
- echo two >> content &&
+ echo two >>content &&
hg commit -m two
) &&
cd hgrepo &&
hg strip 1 &&
- echo three >> content &&
+ echo three >>content &&
hg commit -m three &&
- echo four >> content &&
+ echo four >>content &&
hg commit -m four
) &&
(
cd gitrepo &&
git fetch &&
- git log --format="%s" origin/master > ../actual
+ git log --format="%s" origin/master >../actual
) &&
- hg -R hgrepo log --template "{desc}\n" > expected &&
+ hg -R hgrepo log --template "{desc}\n" >expected &&
test_cmp actual expected
'
(
hg init hgrepo &&
cd hgrepo &&
- echo zero > content &&
+ echo zero >content &&
hg add content &&
hg commit -m zero &&
hg bookmark master &&
- echo one > content &&
+ echo one >content &&
hg commit -m one
) &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
- echo two > content &&
+ echo two >content &&
git commit -a -m two &&
git push
) &&
check_branch hgrepo default two
'
-cat > expected <<EOF
+cat >expected <<\EOF
changeset: 0:6e2126489d3d
tag: tip
user: A U Thor <author@example.com>
git init gitrepo &&
cd gitrepo &&
git remote add origin "hg::../hgrepo" &&
- echo one > content &&
+ echo one >content &&
git add content &&
git commit -a -m one &&
git push origin master
) &&
- hg -R hgrepo log > actual &&
+ hg -R hgrepo log >actual &&
cat actual &&
test_cmp expected actual &&
(
hg init hgrepo &&
cd hgrepo &&
- echo zero > content &&
+ echo zero >content &&
hg add content &&
hg commit -m zero
) &&
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet devel &&
- echo devel > content &&
+ echo devel >content &&
git commit -a -m devel &&
git push --quiet
) &&
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet -b feature-b &&
- echo feature-b > content &&
+ echo feature-b >content &&
git commit -a -m feature-b &&
git push --quiet origin feature-b
) &&
(
cd hgrepo &&
hg checkout default &&
- echo bump > content &&
+ echo bump >content &&
hg commit -m bump
) &&
(
cd gitrepo &&
- echo diverge > content &&
+ echo diverge >content &&
git commit -a -m diverged &&
- check_push 1 <<-EOF
+ check_push 1 <<-\EOF
master:non-fast-forward
EOF
) &&
(
cd hgrepo &&
- echo "bump bookmark" > content &&
+ echo "bump bookmark" >content &&
hg commit -m "bump bookmark"
) &&
(
cd gitrepo &&
git checkout --quiet diverge &&
- echo diverge > content &&
+ echo diverge >content &&
git commit -a -m diverge &&
- check_push 1 <<-EOF
+ check_push 1 <<-\EOF
diverge:fetch-first
EOF
) &&
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet -b feature-c HEAD^ &&
- echo feature-c > content &&
+ echo feature-c >content &&
git commit -a -m feature-c &&
git push --quiet origin feature-c
) &&
(
hg init hgrepo &&
cd hgrepo &&
- echo zero > content &&
+ echo zero >content &&
hg add content &&
hg commit -m zero &&
hg bookmark bad_bmark1 &&
- echo one > content &&
+ echo one >content &&
hg commit -m one &&
hg bookmark bad_bmark2 &&
hg bookmark good_bmark &&
hg bookmark -i good_bmark &&
hg -q branch good_branch &&
- echo "good branch" > content &&
+ echo "good branch" >content &&
hg commit -m "good branch" &&
hg -q branch bad_branch &&
- echo "bad branch" > content &&
+ echo "bad branch" >content &&
hg commit -m "bad branch"
) &&
(
cd gitrepo &&
- echo two > content &&
+ echo two >content &&
git commit -q -a -m two &&
git checkout -q good_bmark &&
- echo three > content &&
+ echo three >content &&
git commit -q -a -m three &&
git checkout -q bad_bmark1 &&
git reset --hard HEAD^ &&
- echo four > content &&
+ echo four >content &&
git commit -q -a -m four &&
git checkout -q bad_bmark2 &&
git reset --hard HEAD^ &&
- echo five > content &&
+ echo five >content &&
git commit -q -a -m five &&
git checkout -q -b new_bmark master &&
- echo six > content &&
+ echo six >content &&
git commit -q -a -m six &&
git checkout -q branches/good_branch &&
- echo seven > content &&
+ echo seven >content &&
git commit -q -a -m seven &&
- echo eight > content &&
+ echo eight >content &&
git commit -q -a -m eight &&
git checkout -q branches/bad_branch &&
git reset --hard HEAD^ &&
- echo nine > content &&
+ echo nine >content &&
git commit -q -a -m nine &&
git checkout -q -b branches/new_branch master &&
- echo ten > content &&
+ echo ten >content &&
git commit -q -a -m ten
)
}
(
cd gitrepo &&
- check_push 1 --all <<-EOF
+ check_push 1 --all <<-\EOF
master
good_bmark
branches/good_branch
(
hg init hgrepo &&
cd hgrepo &&
- echo zero > content &&
+ echo zero >content &&
hg add content &&
hg commit -m zero &&
hg bookmark bad_bmark &&
hg bookmark good_bmark &&
hg bookmark -i good_bmark &&
hg -q branch good_branch &&
- echo "good branch" > content &&
+ echo "good branch" >content &&
hg commit -m "good branch" &&
hg -q branch bad_branch &&
- echo "bad branch" > content &&
+ echo "bad branch" >content &&
hg commit -m "bad branch"
) &&
(
cd hgrepo &&
hg bookmark -f bad_bmark &&
- echo update_bmark > content &&
+ echo update_bmark >content &&
hg commit -m "update bmark"
) &&
(
cd gitrepo &&
- echo two > content &&
+ echo two >content &&
git commit -q -a -m two &&
git checkout -q good_bmark &&
- echo three > content &&
+ echo three >content &&
git commit -q -a -m three &&
git checkout -q bad_bmark &&
- echo four > content &&
+ echo four >content &&
git commit -q -a -m four &&
git checkout -q branches/bad_branch &&
- echo five > content &&
+ echo five >content &&
git commit -q -a -m five &&
- check_push 1 --all <<-EOF
+ check_push 1 --all <<-\EOF &&
master
good_bmark
- new_bmark:new
- new_branch:new
bad_bmark:fetch-first
branches/bad_branch:festch-first
EOF
git fetch &&
- check_push 1 --all <<-EOF
+ check_push 1 --all <<-\EOF
master
good_bmark
bad_bmark:non-fast-forward
(
cd gitrepo &&
- check_push 0 --force --all <<-EOF
+ check_push 0 --force --all <<-\EOF
master
good_bmark
branches/good_branch
(
cd gitrepo &&
- check_push 0 --dry-run --all <<-EOF
+ check_push 1 --dry-run --all <<-\EOF &&
master
good_bmark
branches/good_branch
branches/bad_branch:non-fast-forward
EOF
- check_push 0 --dry-run master good_bmark new_bmark branches/good_branch branches/new_branch <<-EOF
+ check_push 0 --dry-run master good_bmark new_bmark branches/good_branch branches/new_branch <<-\EOF
master
good_bmark
branches/good_branch
(
hg init hgrepo &&
cd hgrepo &&
- echo zero > content &&
+ echo zero >content &&
hg add content &&
hg commit -m zero &&
- echo one > content &&
+ echo one >content &&
hg commit -m one
) &&
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git reset --hard HEAD^ &&
- echo two > content &&
+ echo two >content &&
git commit -a -m two &&
test_expect_code 1 git push &&
test_expect_code 1 git push
const char *end = date;
int i;
- while (isalpha(*++end));
+ while (isalpha(*++end))
;
for (i = 0; i < 12; i++) {
entries = 0xfffffffeU / RABIN_WINDOW;
}
hsize = entries / 4;
- for (i = 4; (1u << i) < hsize && i < 31; i++);
+ for (i = 4; (1u << i) < hsize; i++);
hsize = 1 << i;
hmask = hsize - 1;
{
int entries, i;
int diff_unmerged_stage = revs->max_count;
- int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
? CE_MATCH_RACY_IS_DIRTY : 0);
+ if (option & DIFF_SILENT_ON_REMOVED)
+ handle_deprecated_show_diff_q(&revs->diffopt);
+
diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");
if (diff_unmerged_stage < 0)
perror(ce->name);
continue;
}
- if (silent_on_removed)
- continue;
wt_mode = 0;
}
dpath->mode = wt_mode;
perror(ce->name);
continue;
}
- if (silent_on_removed)
- continue;
diff_addremove(&revs->diffopt, '-', ce->ce_mode,
ce->sha1, !is_null_sha1(ce->sha1),
ce->name, 0);
opts.dst_index = NULL;
opts.pathspec = &revs->diffopt.pathspec;
opts.pathspec->recursive = 1;
- opts.pathspec->max_depth = -1;
init_tree_desc(&t, tree->buffer, tree->size);
return unpack_trees(1, &t, &opts);
struct rev_info revs;
init_revisions(&revs, NULL);
- init_pathspec(&revs.prune_data, opt->pathspec.raw);
+ copy_pathspec(&revs.prune_data, &opt->pathspec);
revs.diffopt = *opt;
if (diff_cache(&revs, tree_sha1, NULL, 1))
{
int i, prefixlen;
int no_index = 0;
- unsigned options = 0;
+ unsigned deprecated_show_diff_q_option_used = 0;
const char *paths[2];
/* Were we asked to do --no-index explicitly? */
path_inside_repo(prefix, argv[i+1])))
return;
}
- if (argc != i + 2)
+ if (argc != i + 2) {
+ if (!no_index) {
+ /*
+ * There was no --no-index and there were not two
+ * paths. It is possible that the user intended
+ * to do an inside-repository operation.
+ */
+ fprintf(stderr, "Not a git repository\n");
+ fprintf(stderr,
+ "To compare two paths outside a working tree:\n");
+ }
+ /* Give the usage message for non-repository usage and exit. */
usagef("git diff %s <path> <path>",
no_index ? "--no-index" : "[--no-index]");
+ }
diff_setup(&revs->diffopt);
for (i = 1; i < argc - 2; ) {
if (!strcmp(argv[i], "--no-index"))
i++;
else if (!strcmp(argv[i], "-q")) {
- options |= DIFF_SILENT_ON_REMOVED;
+ deprecated_show_diff_q_option_used = 1;
i++;
}
else if (!strcmp(argv[i], "--"))
revs->max_count = -2;
diff_setup_done(&revs->diffopt);
+ if (deprecated_show_diff_q_option_used)
+ handle_deprecated_show_diff_q(&revs->diffopt);
+
setup_diff_pager(&revs->diffopt);
DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
memset(&ecbdata, 0, sizeof(ecbdata));
ecbdata.color_diff = want_color(o->use_color);
ecbdata.found_changesp = &o->found_changes;
- ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
+ ecbdata.ws_rule = whitespace_rule(name_b);
ecbdata.opt = o;
if (ecbdata.ws_rule & WS_BLANK_AT_EOF) {
mmfile_t mf1, mf2;
(!two->mode || S_ISGITLINK(two->mode))) {
const char *del = diff_get_color_opt(o, DIFF_FILE_OLD);
const char *add = diff_get_color_opt(o, DIFF_FILE_NEW);
- show_submodule_summary(o->file, one ? one->path : two->path,
+ show_submodule_summary(o->file, one->path ? one->path : two->path,
line_prefix,
one->sha1, two->sha1, two->dirty_submodule,
meta, del, add, reset);
ecbdata.label_path = lbl;
ecbdata.color_diff = want_color(o->use_color);
ecbdata.found_changesp = &o->found_changes;
- ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
+ ecbdata.ws_rule = whitespace_rule(name_b);
if (ecbdata.ws_rule & WS_BLANK_AT_EOF)
check_blank_at_eof(&mf1, &mf2, &ecbdata);
ecbdata.opt = o;
{
int count = 0;
+ if (options->set_default)
+ options->set_default(options);
+
if (options->output_format & DIFF_FORMAT_NAME)
count++;
if (options->output_format & DIFF_FORMAT_NAME_STATUS)
return 1;
}
+static const char diff_status_letters[] = {
+ DIFF_STATUS_ADDED,
+ DIFF_STATUS_COPIED,
+ DIFF_STATUS_DELETED,
+ DIFF_STATUS_MODIFIED,
+ DIFF_STATUS_RENAMED,
+ DIFF_STATUS_TYPE_CHANGED,
+ DIFF_STATUS_UNKNOWN,
+ DIFF_STATUS_UNMERGED,
+ DIFF_STATUS_FILTER_AON,
+ DIFF_STATUS_FILTER_BROKEN,
+ '\0',
+};
+
+static unsigned int filter_bit['Z' + 1];
+
+static void prepare_filter_bits(void)
+{
+ int i;
+
+ if (!filter_bit[DIFF_STATUS_ADDED]) {
+ for (i = 0; diff_status_letters[i]; i++)
+ filter_bit[(int) diff_status_letters[i]] = (1 << i);
+ }
+}
+
+static unsigned filter_bit_tst(char status, const struct diff_options *opt)
+{
+ return opt->filter & filter_bit[(int) status];
+}
+
+static int parse_diff_filter_opt(const char *optarg, struct diff_options *opt)
+{
+ int i, optch;
+
+ prepare_filter_bits();
+
+ /*
+ * If there is a negation e.g. 'd' in the input, and we haven't
+ * initialized the filter field with another --diff-filter, start
+ * from full set of bits, except for AON.
+ */
+ if (!opt->filter) {
+ for (i = 0; (optch = optarg[i]) != '\0'; i++) {
+ if (optch < 'a' || 'z' < optch)
+ continue;
+ opt->filter = (1 << (ARRAY_SIZE(diff_status_letters) - 1)) - 1;
+ opt->filter &= ~filter_bit[DIFF_STATUS_FILTER_AON];
+ break;
+ }
+ }
+
+ for (i = 0; (optch = optarg[i]) != '\0'; i++) {
+ unsigned int bit;
+ int negate;
+
+ if ('a' <= optch && optch <= 'z') {
+ negate = 1;
+ optch = toupper(optch);
+ } else {
+ negate = 0;
+ }
+
+ bit = (0 <= optch && optch <= 'Z') ? filter_bit[optch] : 0;
+ if (!bit)
+ return optarg[i];
+ if (negate)
+ opt->filter &= ~bit;
+ else
+ opt->filter |= bit;
+ }
+ return 0;
+}
+
+/* Used only by "diff-files" and "diff --no-index" */
+void handle_deprecated_show_diff_q(struct diff_options *opt)
+{
+ warning("'diff -q' and 'diff-files -q' are deprecated.");
+ warning("Use 'diff --diff-filter=d' instead to ignore deleted filepairs.");
+ parse_diff_filter_opt("d", opt);
+}
+
static void enable_patch_output(int *fmt) {
*fmt &= ~DIFF_FORMAT_NO_OUTPUT;
*fmt |= DIFF_FORMAT_PATCH;
return argcount;
}
else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) {
- options->filter = optarg;
+ int offending = parse_diff_filter_opt(optarg, options);
+ if (offending)
+ die("unknown change class '%c' in --diff-filter=%s",
+ offending, optarg);
return argcount;
}
else if (!strcmp(arg, "--abbrev"))
}
}
-static void diffcore_apply_filter(const char *filter)
+static int match_filter(const struct diff_options *options, const struct diff_filepair *p)
+{
+ return (((p->status == DIFF_STATUS_MODIFIED) &&
+ ((p->score &&
+ filter_bit_tst(DIFF_STATUS_FILTER_BROKEN, options)) ||
+ (!p->score &&
+ filter_bit_tst(DIFF_STATUS_MODIFIED, options)))) ||
+ ((p->status != DIFF_STATUS_MODIFIED) &&
+ filter_bit_tst(p->status, options)));
+}
+
+static void diffcore_apply_filter(struct diff_options *options)
{
int i;
struct diff_queue_struct *q = &diff_queued_diff;
struct diff_queue_struct outq;
+
DIFF_QUEUE_CLEAR(&outq);
- if (!filter)
+ if (!options->filter)
return;
- if (strchr(filter, DIFF_STATUS_FILTER_AON)) {
+ if (filter_bit_tst(DIFF_STATUS_FILTER_AON, options)) {
int found;
for (i = found = 0; !found && i < q->nr; i++) {
- struct diff_filepair *p = q->queue[i];
- if (((p->status == DIFF_STATUS_MODIFIED) &&
- ((p->score &&
- strchr(filter, DIFF_STATUS_FILTER_BROKEN)) ||
- (!p->score &&
- strchr(filter, DIFF_STATUS_MODIFIED)))) ||
- ((p->status != DIFF_STATUS_MODIFIED) &&
- strchr(filter, p->status)))
+ if (match_filter(options, q->queue[i]))
found++;
}
if (found)
/* Only the matching ones */
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
-
- if (((p->status == DIFF_STATUS_MODIFIED) &&
- ((p->score &&
- strchr(filter, DIFF_STATUS_FILTER_BROKEN)) ||
- (!p->score &&
- strchr(filter, DIFF_STATUS_MODIFIED)))) ||
- ((p->status != DIFF_STATUS_MODIFIED) &&
- strchr(filter, p->status)))
+ if (match_filter(options, p))
diff_q(&outq, p);
else
diff_free_filepair(p);
if (!options->found_follow)
/* See try_to_follow_renames() in tree-diff.c */
diff_resolve_rename_copy();
- diffcore_apply_filter(options->filter);
+ diffcore_apply_filter(options);
if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
DIFF_OPT_SET(options, HAS_CHANGES);
#define DIFF_H
#include "tree-walk.h"
+#include "pathspec.h"
struct rev_info;
struct diff_options;
#define DIFF_OPT_PICKAXE_IGNORE_CASE (1 << 30)
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
-#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
-#define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag)
+#define DIFF_OPT_TOUCHED(opts, flag) ((opts)->touched_flags & DIFF_OPT_##flag)
+#define DIFF_OPT_SET(opts, flag) (((opts)->flags |= DIFF_OPT_##flag),((opts)->touched_flags |= DIFF_OPT_##flag))
+#define DIFF_OPT_CLR(opts, flag) (((opts)->flags &= ~DIFF_OPT_##flag),((opts)->touched_flags |= DIFF_OPT_##flag))
#define DIFF_XDL_TST(opts, flag) ((opts)->xdl_opts & XDF_##flag)
#define DIFF_XDL_SET(opts, flag) ((opts)->xdl_opts |= XDF_##flag)
#define DIFF_XDL_CLR(opts, flag) ((opts)->xdl_opts &= ~XDF_##flag)
};
struct diff_options {
- const char *filter;
const char *orderfile;
const char *pickaxe;
const char *single_follow;
const char *a_prefix, *b_prefix;
unsigned flags;
+ unsigned touched_flags;
+
+ /* diff-filter bits */
+ unsigned int filter;
+
int use_color;
int context;
int interhunkcontext;
/* to support internal diff recursion by --follow hack*/
int found_follow;
+ void (*set_default)(struct diff_options *);
+
FILE *file;
int close_file;
extern const char mime_boundary_leader[];
-extern void diff_tree_setup_paths(const char **paths, struct diff_options *);
-extern void diff_tree_release_paths(struct diff_options *);
extern int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
const char *base, struct diff_options *opt);
extern int diff_tree_sha1(const unsigned char *old, const unsigned char *new,
extern long parse_algorithm_value(const char *value);
+extern void handle_deprecated_show_diff_q(struct diff_options *);
+
extern int print_stat_summary(FILE *fp, int files,
int insertions, int deletions);
extern void setup_diff_pager(struct diff_options *);
#include "dir.h"
#include "refs.h"
#include "wildmatch.h"
+#include "pathspec.h"
struct path_simplify {
int len;
return fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0));
}
-inline int git_fnmatch(const char *pattern, const char *string,
- int flags, int prefix)
+inline int git_fnmatch(const struct pathspec_item *item,
+ const char *pattern, const char *string,
+ int prefix)
{
- int fnm_flags = 0;
- if (flags & GFNM_PATHNAME)
- fnm_flags |= FNM_PATHNAME;
if (prefix > 0) {
- if (strncmp(pattern, string, prefix))
+ if (ps_strncmp(item, pattern, string, prefix))
return FNM_NOMATCH;
pattern += prefix;
string += prefix;
}
- if (flags & GFNM_ONESTAR) {
+ if (item->flags & PATHSPEC_ONESTAR) {
int pattern_len = strlen(++pattern);
int string_len = strlen(string);
return string_len < pattern_len ||
- strcmp(pattern,
- string + string_len - pattern_len);
+ ps_strcmp(item, pattern,
+ string + string_len - pattern_len);
}
- return fnmatch(pattern, string, fnm_flags);
+ if (item->magic & PATHSPEC_GLOB)
+ return wildmatch(pattern, string,
+ WM_PATHNAME |
+ (item->magic & PATHSPEC_ICASE ? WM_CASEFOLD : 0),
+ NULL);
+ else
+ /* wildmatch has not learned no FNM_PATHNAME mode yet */
+ return fnmatch(pattern, string,
+ item->magic & PATHSPEC_ICASE ? FNM_CASEFOLD : 0);
}
static int fnmatch_icase_mem(const char *pattern, int patternlen,
return match_status;
}
-static size_t common_prefix_len(const char **pathspec)
+static size_t common_prefix_len(const struct pathspec *pathspec)
{
- const char *n, *first;
+ int n;
size_t max = 0;
- int literal = limit_pathspec_to_literal();
- if (!pathspec)
- return max;
-
- first = *pathspec;
- while ((n = *pathspec++)) {
- size_t i, len = 0;
- for (i = 0; first == n || i < max; i++) {
- char c = n[i];
- if (!c || c != first[i] || (!literal && is_glob_special(c)))
+ /*
+ * ":(icase)path" is treated as a pathspec full of
+ * wildcard. In other words, only prefix is considered common
+ * prefix. If the pathspec is abc/foo abc/bar, running in
+ * subdir xyz, the common prefix is still xyz, not xuz/abc as
+ * in non-:(icase).
+ */
+ GUARD_PATHSPEC(pathspec,
+ PATHSPEC_FROMTOP |
+ PATHSPEC_MAXDEPTH |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ICASE);
+
+ for (n = 0; n < pathspec->nr; n++) {
+ size_t i = 0, len = 0, item_len;
+ if (pathspec->items[n].magic & PATHSPEC_ICASE)
+ item_len = pathspec->items[n].prefix;
+ else
+ item_len = pathspec->items[n].nowildcard_len;
+ while (i < item_len && (n == 0 || i < max)) {
+ char c = pathspec->items[n].match[i];
+ if (c != pathspec->items[0].match[i])
break;
if (c == '/')
len = i + 1;
+ i++;
}
- if (first == n || len < max) {
+ if (n == 0 || len < max) {
max = len;
if (!max)
break;
* Returns a copy of the longest leading path common among all
* pathspecs.
*/
-char *common_prefix(const char **pathspec)
+char *common_prefix(const struct pathspec *pathspec)
{
unsigned long len = common_prefix_len(pathspec);
- return len ? xmemdupz(*pathspec, len) : NULL;
+ return len ? xmemdupz(pathspec->items[0].match, len) : NULL;
}
-int fill_directory(struct dir_struct *dir, const char **pathspec)
+int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
{
size_t len;
len = common_prefix_len(pathspec);
/* Read the directory and prune it */
- read_directory(dir, pathspec ? *pathspec : "", len, pathspec);
+ read_directory(dir, pathspec->nr ? pathspec->_raw[0] : "", len, pathspec);
return len;
}
return 1;
}
-/*
- * Does 'match' match the given name?
- * A match is found if
- *
- * (1) the 'match' string is leading directory of 'name', or
- * (2) the 'match' string is a wildcard and matches 'name', or
- * (3) the 'match' string is exactly the same as 'name'.
- *
- * and the return value tells which case it was.
- *
- * It returns 0 when there is no match.
- */
-static int match_one(const char *match, const char *name, int namelen)
-{
- int matchlen;
- int literal = limit_pathspec_to_literal();
-
- /* If the match was just the prefix, we matched */
- if (!*match)
- return MATCHED_RECURSIVELY;
-
- if (ignore_case) {
- for (;;) {
- unsigned char c1 = tolower(*match);
- unsigned char c2 = tolower(*name);
- if (c1 == '\0' || (!literal && is_glob_special(c1)))
- break;
- if (c1 != c2)
- return 0;
- match++;
- name++;
- namelen--;
- }
- } else {
- for (;;) {
- unsigned char c1 = *match;
- unsigned char c2 = *name;
- if (c1 == '\0' || (!literal && is_glob_special(c1)))
- break;
- if (c1 != c2)
- return 0;
- match++;
- name++;
- namelen--;
- }
- }
-
- /*
- * If we don't match the matchstring exactly,
- * we need to match by fnmatch
- */
- matchlen = strlen(match);
- if (strncmp_icase(match, name, matchlen)) {
- if (literal)
- return 0;
- return !fnmatch_icase(match, name, 0) ? MATCHED_FNMATCH : 0;
- }
-
- if (namelen == matchlen)
- return MATCHED_EXACTLY;
- if (match[matchlen-1] == '/' || name[matchlen] == '/')
- return MATCHED_RECURSIVELY;
- return 0;
-}
-
-/*
- * Given a name and a list of pathspecs, returns the nature of the
- * closest (i.e. most specific) match of the name to any of the
- * pathspecs.
- *
- * The caller typically calls this multiple times with the same
- * pathspec and seen[] array but with different name/namelen
- * (e.g. entries from the index) and is interested in seeing if and
- * how each pathspec matches all the names it calls this function
- * with. A mark is left in the seen[] array for each pathspec element
- * indicating the closest type of match that element achieved, so if
- * seen[n] remains zero after multiple invocations, that means the nth
- * pathspec did not match any names, which could indicate that the
- * user mistyped the nth pathspec.
- */
-int match_pathspec(const char **pathspec, const char *name, int namelen,
- int prefix, char *seen)
-{
- int i, retval = 0;
-
- if (!pathspec)
- return 1;
-
- name += prefix;
- namelen -= prefix;
-
- for (i = 0; pathspec[i] != NULL; i++) {
- int how;
- const char *match = pathspec[i] + prefix;
- if (seen && seen[i] == MATCHED_EXACTLY)
- continue;
- how = match_one(match, name, namelen);
- if (how) {
- if (retval < how)
- retval = how;
- if (seen && seen[i] < how)
- seen[i] = how;
- }
- }
- return retval;
-}
-
/*
* Does 'match' match the given name?
* A match is found if
const char *match = item->match + prefix;
int matchlen = item->len - prefix;
+ /*
+ * The normal call pattern is:
+ * 1. prefix = common_prefix_len(ps);
+ * 2. prune something, or fill_directory
+ * 3. match_pathspec_depth()
+ *
+ * 'prefix' at #1 may be shorter than the command's prefix and
+ * it's ok for #2 to match extra files. Those extras will be
+ * trimmed at #3.
+ *
+ * Suppose the pathspec is 'foo' and '../bar' running from
+ * subdir 'xyz'. The common prefix at #1 will be empty, thanks
+ * to "../". We may have xyz/foo _and_ XYZ/foo after #2. The
+ * user does not want XYZ/foo, only the "foo" part should be
+ * case-insensitive. We need to filter out XYZ/foo here. In
+ * other words, we do not trust the caller on comparing the
+ * prefix part when :(icase) is involved. We do exact
+ * comparison ourselves.
+ *
+ * Normally the caller (common_prefix_len() in fact) does
+ * _exact_ matching on name[-prefix+1..-1] and we do not need
+ * to check that part. Be defensive and check it anyway, in
+ * case common_prefix_len is changed, or a new caller is
+ * introduced that does not use common_prefix_len.
+ *
+ * If the penalty turns out too high when prefix is really
+ * long, maybe change it to
+ * strncmp(match, name, item->prefix - prefix)
+ */
+ if (item->prefix && (item->magic & PATHSPEC_ICASE) &&
+ strncmp(item->match, name - prefix, item->prefix))
+ return 0;
+
/* If the match was just the prefix, we matched */
if (!*match)
return MATCHED_RECURSIVELY;
- if (matchlen <= namelen && !strncmp(match, name, matchlen)) {
+ if (matchlen <= namelen && !ps_strncmp(item, match, name, matchlen)) {
if (matchlen == namelen)
return MATCHED_EXACTLY;
}
if (item->nowildcard_len < item->len &&
- !git_fnmatch(match, name,
- item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,
+ !git_fnmatch(item, match, name,
item->nowildcard_len - prefix))
return MATCHED_FNMATCH;
{
int i, retval = 0;
+ GUARD_PATHSPEC(ps,
+ PATHSPEC_FROMTOP |
+ PATHSPEC_MAXDEPTH |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ICASE);
+
if (!ps->nr) {
- if (!ps->recursive || ps->max_depth == -1)
+ if (!ps->recursive ||
+ !(ps->magic & PATHSPEC_MAXDEPTH) ||
+ ps->max_depth == -1)
return MATCHED_RECURSIVELY;
if (within_depth(name, namelen, 0, ps->max_depth))
if (seen && seen[i] == MATCHED_EXACTLY)
continue;
how = match_pathspec_item(ps->items+i, prefix, name, namelen);
- if (ps->recursive && ps->max_depth != -1 &&
+ if (ps->recursive &&
+ (ps->magic & PATHSPEC_MAXDEPTH) &&
+ ps->max_depth != -1 &&
how && how != MATCHED_FNMATCH) {
int len = ps->items[i].len;
if (name[len] == '/')
/*
* Return the length of the "simple" part of a path match limiter.
*/
-static int simple_length(const char *match)
+int simple_length(const char *match)
{
int len = -1;
}
}
-static int no_wildcard(const char *string)
+int no_wildcard(const char *string)
{
return string[simple_length(string)] == '\0';
}
unsigned long sz;
enum object_type type;
void *data;
- struct index_state *istate = &the_index;
len = strlen(path);
- pos = index_name_pos(istate, path, len);
+ pos = cache_name_pos(path, len);
if (pos < 0)
return NULL;
- if (!ce_skip_worktree(istate->cache[pos]))
+ if (!ce_skip_worktree(active_cache[pos]))
return NULL;
- data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
+ data = read_sha1_file(active_cache[pos]->sha1, &type, &sz);
if (!data || type != OBJ_BLOB) {
free(data);
return NULL;
static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
{
- if (cache_name_exists(pathname, len, ignore_case))
+ if (cache_file_exists(pathname, len, ignore_case))
return NULL;
ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
};
/*
- * Do not use the alphabetically stored index to look up
+ * Do not use the alphabetically sorted index to look up
* the directory name; instead, use the case insensitive
- * name hash.
+ * directory hash.
*/
static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
{
- const struct cache_entry *ce = index_name_exists(&the_index, dirname, len + 1, ignore_case);
+ const struct cache_entry *ce = cache_dir_exists(dirname, len);
unsigned char endchar;
if (!ce)
int pos;
const struct cache_entry *ce;
- ce = cache_name_exists(path, len, 0);
+ ce = cache_file_exists(path, len, 0);
if (ce) {
if (!ce_uptodate(ce))
return DT_UNKNOWN;
int dtype, struct dirent *de)
{
int exclude;
+ int has_path_in_index = !!cache_file_exists(path->buf, path->len, ignore_case);
+
if (dtype == DT_UNKNOWN)
dtype = get_dtype(de, path->buf, path->len);
/* Always exclude indexed files */
- if (dtype != DT_DIR &&
- cache_name_exists(path->buf, path->len, ignore_case))
+ if (dtype != DT_DIR && has_path_in_index)
+ return path_none;
+
+ /*
+ * When we are looking at a directory P in the working tree,
+ * there are three cases:
+ *
+ * (1) P exists in the index. Everything inside the directory P in
+ * the working tree needs to go when P is checked out from the
+ * index.
+ *
+ * (2) P does not exist in the index, but there is P/Q in the index.
+ * We know P will stay a directory when we check out the contents
+ * of the index, but we do not know yet if there is a directory
+ * P/Q in the working tree to be killed, so we need to recurse.
+ *
+ * (3) P does not exist in the index, and there is no P/Q in the index
+ * to require P to be a directory, either. Only in this case, we
+ * know that everything inside P will not be killed without
+ * recursing.
+ */
+ if ((dir->flags & DIR_COLLECT_KILLED_ONLY) &&
+ (dtype == DT_DIR) &&
+ !has_path_in_index &&
+ (directory_exists_in_index(path->buf, path->len) == index_nonexistent))
return path_none;
exclude = is_excluded(dir, path->buf, &dtype);
return rc;
}
-int read_directory(struct dir_struct *dir, const char *path, int len, const char **pathspec)
+int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)
{
struct path_simplify *simplify;
+ /*
+ * Check out create_simplify()
+ */
+ if (pathspec)
+ GUARD_PATHSPEC(pathspec,
+ PATHSPEC_FROMTOP |
+ PATHSPEC_MAXDEPTH |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ICASE);
+
if (has_symlink_leading_path(path, len))
return dir->nr;
- simplify = create_simplify(pathspec);
+ simplify = create_simplify(pathspec ? pathspec->_raw : NULL);
if (!len || treat_leading_path(dir, path, len, simplify))
read_directory_recursive(dir, path, len, 0, simplify);
free_simplify(simplify);
return 0;
}
-static int pathspec_item_cmp(const void *a_, const void *b_)
-{
- struct pathspec_item *a, *b;
-
- a = (struct pathspec_item *)a_;
- b = (struct pathspec_item *)b_;
- return strcmp(a->match, b->match);
-}
-
-int init_pathspec(struct pathspec *pathspec, const char **paths)
-{
- const char **p = paths;
- int i;
-
- memset(pathspec, 0, sizeof(*pathspec));
- if (!p)
- return 0;
- while (*p)
- p++;
- pathspec->raw = paths;
- pathspec->nr = p - paths;
- if (!pathspec->nr)
- return 0;
-
- pathspec->items = xmalloc(sizeof(struct pathspec_item)*pathspec->nr);
- for (i = 0; i < pathspec->nr; i++) {
- struct pathspec_item *item = pathspec->items+i;
- const char *path = paths[i];
-
- item->match = path;
- item->len = strlen(path);
- item->flags = 0;
- if (limit_pathspec_to_literal()) {
- item->nowildcard_len = item->len;
- } else {
- item->nowildcard_len = simple_length(path);
- if (item->nowildcard_len < item->len) {
- pathspec->has_wildcard = 1;
- if (path[item->nowildcard_len] == '*' &&
- no_wildcard(path + item->nowildcard_len + 1))
- item->flags |= PATHSPEC_ONESTAR;
- }
- }
- }
-
- qsort(pathspec->items, pathspec->nr,
- sizeof(struct pathspec_item), pathspec_item_cmp);
-
- return 0;
-}
-
-void free_pathspec(struct pathspec *pathspec)
-{
- free(pathspec->items);
- pathspec->items = NULL;
-}
-
-int limit_pathspec_to_literal(void)
-{
- static int flag = -1;
- if (flag < 0)
- flag = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
- return flag;
-}
-
/*
* Frees memory within dir which was allocated for exclude lists and
* the exclude_stack. Does not free dir itself.
DIR_HIDE_EMPTY_DIRECTORIES = 1<<2,
DIR_NO_GITLINKS = 1<<3,
DIR_COLLECT_IGNORED = 1<<4,
- DIR_SHOW_IGNORED_TOO = 1<<5
+ DIR_SHOW_IGNORED_TOO = 1<<5,
+ DIR_COLLECT_KILLED_ONLY = 1<<6
} flags;
struct dir_entry **entries;
struct dir_entry **ignored;
#define MATCHED_RECURSIVELY 1
#define MATCHED_FNMATCH 2
#define MATCHED_EXACTLY 3
-extern char *common_prefix(const char **pathspec);
-extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
+extern int simple_length(const char *match);
+extern int no_wildcard(const char *string);
+extern char *common_prefix(const struct pathspec *pathspec);
extern int match_pathspec_depth(const struct pathspec *pathspec,
const char *name, int namelen,
int prefix, char *seen);
extern int within_depth(const char *name, int namelen, int depth, int max_depth);
-extern int fill_directory(struct dir_struct *dir, const char **pathspec);
-extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);
+extern int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec);
+extern int read_directory(struct dir_struct *, const char *path, int len, const struct pathspec *pathspec);
extern int is_excluded_from_list(const char *pathname, int pathlen, const char *basename,
int *dtype, struct exclude_list *el);
/*
* The prefix part of pattern must not contains wildcards.
*/
-#define GFNM_PATHNAME 1 /* similar to FNM_PATHNAME */
-#define GFNM_ONESTAR 2 /* there is only _one_ wildcard, a star */
-
-extern int git_fnmatch(const char *pattern, const char *string,
- int flags, int prefix);
+struct pathspec_item;
+extern int git_fnmatch(const struct pathspec_item *item,
+ const char *pattern, const char *string,
+ int prefix);
#endif
return error("Terminal is dumb, but EDITOR unset");
if (strcmp(editor, ":")) {
- const char *args[] = { editor, path, NULL };
+ const char *args[] = { editor, real_path(path), NULL };
struct child_process p;
int ret, sig;
return lstat(path, st);
}
+/*
+ * Write the contents from ce out to the working tree.
+ *
+ * When topath[] is not NULL, instead of writing to the working tree
+ * file named by ce, a temporary file is created by this function and
+ * its name is returned in topath[], which must be able to hold at
+ * least TEMPORARY_FILENAME_LENGTH bytes long.
+ */
int checkout_entry(struct cache_entry *ce,
const struct checkout *state, char *topath)
{
- static char path[PATH_MAX + 1];
+ static struct strbuf path_buf = STRBUF_INIT;
+ char *path;
struct stat st;
- int len = state->base_dir_len;
+ int len;
if (topath)
return write_entry(ce, topath, state, 1);
- memcpy(path, state->base_dir, len);
- strcpy(path + len, ce->name);
- len += ce_namelen(ce);
+ strbuf_reset(&path_buf);
+ strbuf_add(&path_buf, state->base_dir, state->base_dir_len);
+ strbuf_add(&path_buf, ce->name, ce_namelen(ce));
+ path = path_buf.buf;
+ len = path_buf.len;
if (!check_path(path, len, &st, state->base_dir_len)) {
unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
static void setup_git_env(void)
{
+ const char *gitfile;
+
git_dir = getenv(GIT_DIR_ENVIRONMENT);
- git_dir = git_dir ? xstrdup(git_dir) : NULL;
- if (!git_dir) {
- git_dir = read_gitfile(DEFAULT_GIT_DIR_ENVIRONMENT);
- git_dir = git_dir ? xstrdup(git_dir) : NULL;
- }
if (!git_dir)
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
+ gitfile = read_gitfile(git_dir);
+ git_dir = xstrdup(gitfile ? gitfile : git_dir);
git_object_dir = getenv(DB_ENVIRONMENT);
if (!git_object_dir) {
git_object_dir = xmalloc(strlen(git_dir) + 9);
('author' (sp name)? sp '<' email '>' sp when lf)?
'committer' (sp name)? sp '<' email '>' sp when lf
commit_msg
- ('from' sp committish lf)?
- ('merge' sp committish lf)*
+ ('from' sp commit-ish lf)?
+ ('merge' sp commit-ish lf)*
(file_change | ls)*
lf?;
commit_msg ::= data;
file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
data;
- note_obm ::= 'N' sp (hexsha1 | idnum) sp committish lf;
- note_inm ::= 'N' sp 'inline' sp committish lf
+ note_obm ::= 'N' sp (hexsha1 | idnum) sp commit-ish lf;
+ note_inm ::= 'N' sp 'inline' sp commit-ish lf
data;
new_tag ::= 'tag' sp tag_str lf
- 'from' sp committish lf
+ 'from' sp commit-ish lf
('tagger' (sp name)? sp '<' email '>' sp when lf)?
tag_msg;
tag_msg ::= data;
reset_branch ::= 'reset' sp ref_str lf
- ('from' sp committish lf)?
+ ('from' sp commit-ish lf)?
lf?;
checkpoint ::= 'checkpoint' lf
# stream formatting is: \, " and LF. Otherwise these values
# are UTF8.
#
- committish ::= (ref_str | hexsha1 | sha1exp_str | idnum);
+ commit-ish ::= (ref_str | hexsha1 | sha1exp_str | idnum);
ref_str ::= ref;
sha1exp_str ::= sha1exp;
tag_str ::= tag;
static int tree_content_remove(
struct tree_entry *root,
const char *p,
- struct tree_entry *backup_leaf)
+ struct tree_entry *backup_leaf,
+ int allow_root)
{
struct tree_content *t;
const char *slash1;
if (!root->tree)
load_tree(root);
+
+ if (!*p && allow_root) {
+ e = root;
+ goto del_entry;
+ }
+
t = root->tree;
for (i = 0; i < t->entry_count; i++) {
e = t->entries[i];
goto del_entry;
if (!e->tree)
load_tree(e);
- if (tree_content_remove(e, slash1 + 1, backup_leaf)) {
+ if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) {
for (n = 0; n < e->tree->entry_count; n++) {
if (e->tree->entries[n]->versions[1].mode) {
hashclr(root->versions[1].sha1);
static int tree_content_get(
struct tree_entry *root,
const char *p,
- struct tree_entry *leaf)
+ struct tree_entry *leaf,
+ int allow_root)
{
struct tree_content *t;
const char *slash1;
n = slash1 - p;
else
n = strlen(p);
- if (!n)
+ if (!n && !allow_root)
die("Empty path component found in input");
if (!root->tree)
load_tree(root);
+
+ if (!n) {
+ e = root;
+ goto found_entry;
+ }
+
t = root->tree;
for (i = 0; i < t->entry_count; i++) {
e = t->entries[i];
if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
- if (!slash1) {
- memcpy(leaf, e, sizeof(*leaf));
- if (e->tree && is_null_sha1(e->versions[1].sha1))
- leaf->tree = dup_tree_content(e->tree);
- else
- leaf->tree = NULL;
- return 1;
- }
+ if (!slash1)
+ goto found_entry;
if (!S_ISDIR(e->versions[1].mode))
return 0;
if (!e->tree)
load_tree(e);
- return tree_content_get(e, slash1 + 1, leaf);
+ return tree_content_get(e, slash1 + 1, leaf, 0);
}
}
return 0;
+
+found_entry:
+ memcpy(leaf, e, sizeof(*leaf));
+ if (e->tree && is_null_sha1(e->versions[1].sha1))
+ leaf->tree = dup_tree_content(e->tree);
+ else
+ leaf->tree = NULL;
+ return 1;
}
static int update_branch(struct branch *b)
return 0;
if (read_ref(b->name, old_sha1))
hashclr(old_sha1);
- lock = lock_any_ref_for_update(b->name, old_sha1, 0);
+ lock = lock_any_ref_for_update(b->name, old_sha1, 0, NULL);
if (!lock)
return error("Unable to lock %s", b->name);
if (!force_update && !is_null_sha1(old_sha1)) {
}
/* Rename fullpath to realpath */
- if (!tree_content_remove(orig_root, fullpath, &leaf))
+ if (!tree_content_remove(orig_root, fullpath, &leaf, 0))
die("Failed to remove path %s", fullpath);
tree_content_set(orig_root, realpath,
leaf.versions[1].sha1,
/* Git does not track empty, non-toplevel directories. */
if (S_ISDIR(mode) && !memcmp(sha1, EMPTY_TREE_SHA1_BIN, 20) && *p) {
- tree_content_remove(&b->branch_tree, p, NULL);
+ tree_content_remove(&b->branch_tree, p, NULL, 0);
return;
}
die("Garbage after path in: %s", command_buf.buf);
p = uq.buf;
}
- tree_content_remove(&b->branch_tree, p, NULL);
+ tree_content_remove(&b->branch_tree, p, NULL, 1);
}
static void file_change_cr(struct branch *b, int rename)
memset(&leaf, 0, sizeof(leaf));
if (rename)
- tree_content_remove(&b->branch_tree, s, &leaf);
+ tree_content_remove(&b->branch_tree, s, &leaf, 1);
else
- tree_content_get(&b->branch_tree, s, &leaf);
+ tree_content_get(&b->branch_tree, s, &leaf, 1);
if (!leaf.versions[1].mode)
die("Path %s not in branch", s);
if (!*d) { /* C "path/to/subdir" "" */
assert(*p == ' ');
p++; /* skip space */
- /* <committish> */
+ /* <commit-ish> */
s = lookup_branch(p);
if (s) {
if (is_null_sha1(s->sha1))
}
construct_path_with_fanout(sha1_to_hex(commit_sha1), *old_fanout, path);
- if (tree_content_remove(&b->branch_tree, path, NULL))
+ if (tree_content_remove(&b->branch_tree, path, NULL, 0))
b->num_notes--;
if (is_null_sha1(sha1))
case OBJ_TAG:
break;
default:
- die("Not a treeish: %s", command_buf.buf);
+ die("Not a tree-ish: %s", command_buf.buf);
}
if (oe->pack_id != MAX_PACK_ID) { /* in a pack being written */
struct tree_entry *root = NULL;
struct tree_entry leaf = {NULL};
- /* ls SP (<treeish> SP)? <path> */
+ /* ls SP (<tree-ish> SP)? <path> */
p = command_buf.buf + strlen("ls ");
if (*p == '"') {
if (!b)
struct object_entry *e = parse_treeish_dataref(&p);
root = new_tree_entry();
hashcpy(root->versions[1].sha1, e->idx.sha1);
+ if (!is_null_sha1(root->versions[1].sha1))
+ root->versions[1].mode = S_IFDIR;
load_tree(root);
if (*p++ != ' ')
die("Missing space after tree-ish: %s", command_buf.buf);
die("Garbage after path in: %s", command_buf.buf);
p = uq.buf;
}
- tree_content_get(root, p, &leaf);
+ tree_content_get(root, p, &leaf, 1);
/*
* A directory in preparation would have a sha1 of zero
* until it is saved. Save, for simplicity.
#include "fetch-pack.h"
#include "remote.h"
#include "run-command.h"
+#include "connect.h"
#include "transport.h"
#include "version.h"
#include "prio-queue.h"
}
}
-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)
{
int len;
const char *argv[22];
char keep_arg[256];
char hdr_arg[256];
- const char **av;
+ const char **av, *cmd_name;
int do_keep = args->keep_pack;
struct child_process cmd;
int ret;
if (do_keep) {
if (pack_lockfile)
cmd.out = -1;
- *av++ = "index-pack";
+ *av++ = cmd_name = "index-pack";
*av++ = "--stdin";
if (!args->quiet && !args->no_progress)
*av++ = "-v";
*av++ = "--check-self-contained-and-connected";
}
else {
- *av++ = "unpack-objects";
+ *av++ = cmd_name = "unpack-objects";
if (args->quiet || args->no_progress)
*av++ = "-q";
args->check_self_contained_and_connected = 0;
cmd.in = demux.out;
cmd.git_cmd = 1;
if (start_command(&cmd))
- die("fetch-pack: unable to fork off %s", argv[0]);
+ die("fetch-pack: unable to fork off %s", cmd_name);
if (do_keep && pack_lockfile) {
*pack_lockfile = index_pack_lockfile(cmd.out);
close(cmd.out);
}
+ if (!use_sideband)
+ /* Closed by start_command() */
+ xd[0] = -1;
+
ret = finish_command(&cmd);
if (!ret || (args->check_self_contained_and_connected && ret == 1))
args->self_contained_and_connected =
args->check_self_contained_and_connected &&
ret == 0;
else
- die("%s failed", argv[0]);
+ die("%s failed", cmd_name);
if (use_sideband && finish_async(&demux))
die("error in sideband demultiplexer");
return 0;
return strcmp(a->name, b->name);
}
-static void setup_alternate_shallow(void)
-{
- struct strbuf sb = STRBUF_INIT;
- int fd;
-
- check_shallow_file_for_update();
- fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
- LOCK_DIE_ON_ERROR);
- if (write_shallow_commits(&sb, 0)) {
- if (write_in_full(fd, sb.buf, sb.len) != sb.len)
- die_errno("failed to write to %s", shallow_lock.filename);
- alternate_shallow_file = shallow_lock.filename;
- } else
- /*
- * is_repository_shallow() sees empty string as "no
- * shallow file".
- */
- alternate_shallow_file = "";
- strbuf_release(&sb);
-}
-
static struct ref *do_fetch_pack(struct fetch_pack_args *args,
int fd[2],
const struct ref *orig_ref,
if (args->stateless_rpc)
packet_flush(fd[1]);
if (args->depth > 0)
- setup_alternate_shallow();
+ setup_alternate_shallow(&shallow_lock, &alternate_shallow_file);
+ else
+ alternate_shallow_file = NULL;
if (get_pack(args, fd, pack_lockfile))
die("git fetch-pack: fetch failed.");
}
ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, pack_lockfile);
- if (alternate_shallow_file) {
+ if (args->depth > 0 && alternate_shallow_file) {
if (*alternate_shallow_file == '\0') { /* --unshallow */
unlink_or_warn(git_path("shallow"));
rollback_lock_file(&shallow_lock);
#define FETCH_PACK_H
#include "string-list.h"
+#include "run-command.h"
struct fetch_pack_args {
const char *uploadpack;
my %patch_mode_flavour = %{$patch_modes{stage}};
sub run_cmd_pipe {
- if ($^O eq 'MSWin32' || $^O eq 'msys') {
+ if ($^O eq 'MSWin32') {
my @invalid = grep {m/[":*]/} @_;
die "$^O does not support: @invalid\n" if @invalid;
my @args = map { m/ /o ? "\"$_\"": $_ } @_;
#define _SGI_SOURCE 1
#if defined(WIN32) && !defined(__CYGWIN__) /* Both MinGW and MSVC */
-# if defined (_MSC_VER)
+# if defined (_MSC_VER) && !defined(_WIN32_WINNT)
# define _WIN32_WINNT 0x0502
# endif
#define WIN32_LEAN_AND_MEAN /* stops windows.h including winsock.h */
#define probe_utf8_pathname_composition(a,b)
#endif
-#ifdef NEEDS_CLIPPED_WRITE
-ssize_t clipped_write(int fildes, const void *buf, size_t nbyte);
-#define write(x,y,z) clipped_write((x),(y),(z))
-#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);
extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
+#ifndef NO_OPENSSL
+#ifdef APPLE_COMMON_CRYPTO
+#include "compat/apple-common-crypto.h"
+#else
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#endif /* APPLE_COMMON_CRYPTO */
+#include <openssl/x509v3.h>
+#endif /* NO_OPENSSL */
+
/*
* Let callers be aware of the constant return value; this can help
* gcc with -Wuninitialized analysis. We restrict this trick to gcc, though,
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
#endif
-extern void release_pack_memory(size_t, int);
+extern void release_pack_memory(size_t);
typedef void (*try_to_free_t)(size_t);
extern try_to_free_t set_try_to_free_routine(try_to_free_t);
# this half-converted form, but it isn't currently worth the
# backwards compatibility headaches.
- $mode=~/^\d\d(\d)\d{3}$/;
+ $mode=~/^\d{3}(\d)\d\d$/;
my $userBits=$1;
my $dbMode = "";
=head2 getRevisionDirMap
A "revision dir map" contains all the plain-file filenames associated
-with a particular revision (treeish), organized by directory:
+with a particular revision (tree-ish), organized by directory:
$type = $out->{$dir}{$fullName}
remap_to_ancestor=t
fi
-rev_args=$(git rev-parse --revs-only "$@")
+git rev-parse --revs-only "$@" >../parse
case "$filter_subdir" in
"")
esac
git rev-list --reverse --topo-order --default HEAD \
- --parents --simplify-merges $rev_args "$@" > ../revs ||
+ --parents --simplify-merges --stdin "$@" <../parse >../revs ||
die "Could not get the commits"
commits=$(wc -l <../revs | tr -d " ")
case "$filter_subdir" in
"")
- git read-tree -i -m $commit
+ GIT_ALLOW_NULL_SHA1=1 git read-tree -i -m $commit
;;
*)
# The commit may not have the subdirectory at all
- err=$(git read-tree -i -m $commit:"$filter_subdir" 2>&1) || {
+ err=$(GIT_ALLOW_NULL_SHA1=1 \
+ git read-tree -i -m $commit:"$filter_subdir" 2>&1) || {
if ! git rev-parse -q --verify $commit:"$filter_subdir"
then
rm -f "$GIT_INDEX_FILE"
else
tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
fi
- tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3 codecompare"
+ tools="$tools gvimdiff diffuse diffmerge ecmerge"
+ tools="$tools p4merge araxis bc3 codecompare"
fi
case "${VISUAL:-$EDITOR}" in
*vim*)
}
show_tool_help () {
- tool_opt="'git ${TOOL_MODE}tool --tool-<tool>'"
+ tool_opt="'git ${TOOL_MODE}tool --tool=<tool>'"
tab=' '
LF='
# dictionary of all client parameters
entry = specList[0]
+ # the //client/ name
+ client_name = entry["Client"]
+
# just the keys that start with "View"
view_keys = [ k for k in entry.keys() if k.startswith("View") ]
# hold this new View
- view = View()
+ view = View(client_name)
# append the lines, in order, to the view
for view_num in range(len(view_keys)):
for b in body:
labelTemplate += "\t" + b + "\n"
labelTemplate += "View:\n"
- for mapping in clientSpec.mappings:
- labelTemplate += "\t%s\n" % mapping.depot_side.path
+ for depot_side in clientSpec.mappings:
+ labelTemplate += "\t%s\n" % depot_side
if self.dry_run:
print "Would create p4 label %s for tag" % name
# Use the label
p4_system(["tag", "-l", name] +
- ["%s@%s" % (mapping.depot_side.path, changelist) for mapping in clientSpec.mappings])
+ ["%s@%s" % (depot_side, changelist) for depot_side in clientSpec.mappings])
if verbose:
print "created p4 label for tag %s" % name
"""Represent a p4 view ("p4 help views"), and map files in a
repo according to the view."""
- class Path(object):
- """A depot or client path, possibly containing wildcards.
- The only one supported is ... at the end, currently.
- Initialize with the full path, with //depot or //client."""
-
- def __init__(self, path, is_depot):
- self.path = path
- self.is_depot = is_depot
- self.find_wildcards()
- # remember the prefix bit, useful for relative mappings
- m = re.match("(//[^/]+/)", self.path)
- if not m:
- die("Path %s does not start with //prefix/" % self.path)
- prefix = m.group(1)
- if not self.is_depot:
- # strip //client/ on client paths
- self.path = self.path[len(prefix):]
-
- def find_wildcards(self):
- """Make sure wildcards are valid, and set up internal
- variables."""
-
- self.ends_triple_dot = False
- # There are three wildcards allowed in p4 views
- # (see "p4 help views"). This code knows how to
- # handle "..." (only at the end), but cannot deal with
- # "%%n" or "*". Only check the depot_side, as p4 should
- # validate that the client_side matches too.
- if re.search(r'%%[1-9]', self.path):
- die("Can't handle %%n wildcards in view: %s" % self.path)
- if self.path.find("*") >= 0:
- die("Can't handle * wildcards in view: %s" % self.path)
- triple_dot_index = self.path.find("...")
- if triple_dot_index >= 0:
- if triple_dot_index != len(self.path) - 3:
- die("Can handle only single ... wildcard, at end: %s" %
- self.path)
- self.ends_triple_dot = True
-
- def ensure_compatible(self, other_path):
- """Make sure the wildcards agree."""
- if self.ends_triple_dot != other_path.ends_triple_dot:
- die("Both paths must end with ... if either does;\n" +
- "paths: %s %s" % (self.path, other_path.path))
-
- def match_wildcards(self, test_path):
- """See if this test_path matches us, and fill in the value
- of the wildcards if so. Returns a tuple of
- (True|False, wildcards[]). For now, only the ... at end
- is supported, so at most one wildcard."""
- if self.ends_triple_dot:
- dotless = self.path[:-3]
- if test_path.startswith(dotless):
- wildcard = test_path[len(dotless):]
- return (True, [ wildcard ])
- else:
- if test_path == self.path:
- return (True, [])
- return (False, [])
-
- def match(self, test_path):
- """Just return if it matches; don't bother with the wildcards."""
- b, _ = self.match_wildcards(test_path)
- return b
-
- def fill_in_wildcards(self, wildcards):
- """Return the relative path, with the wildcards filled in
- if there are any."""
- if self.ends_triple_dot:
- return self.path[:-3] + wildcards[0]
- else:
- return self.path
-
- class Mapping(object):
- def __init__(self, depot_side, client_side, overlay, exclude):
- # depot_side is without the trailing /... if it had one
- self.depot_side = View.Path(depot_side, is_depot=True)
- self.client_side = View.Path(client_side, is_depot=False)
- self.overlay = overlay # started with "+"
- self.exclude = exclude # started with "-"
- assert not (self.overlay and self.exclude)
- self.depot_side.ensure_compatible(self.client_side)
-
- def __str__(self):
- c = " "
- if self.overlay:
- c = "+"
- if self.exclude:
- c = "-"
- return "View.Mapping: %s%s -> %s" % \
- (c, self.depot_side.path, self.client_side.path)
-
- def map_depot_to_client(self, depot_path):
- """Calculate the client path if using this mapping on the
- given depot path; does not consider the effect of other
- mappings in a view. Even excluded mappings are returned."""
- matches, wildcards = self.depot_side.match_wildcards(depot_path)
- if not matches:
- return ""
- client_path = self.client_side.fill_in_wildcards(wildcards)
- return client_path
-
- #
- # View methods
- #
- def __init__(self):
+ def __init__(self, client_name):
self.mappings = []
+ self.client_prefix = "//%s/" % client_name
+ # cache results of "p4 where" to lookup client file locations
+ self.client_spec_path_cache = {}
def append(self, view_line):
"""Parse a view line, splitting it into depot and client
- sides. Append to self.mappings, preserving order."""
+ sides. Append to self.mappings, preserving order. This
+ is only needed for tag creation."""
# Split the view line into exactly two words. P4 enforces
# structure on these lines that simplifies this quite a bit.
depot_side = view_line[0:space_index]
rhs_index = space_index + 1
- if view_line[rhs_index] == '"':
- # Second word is double quoted. Make sure there is a
- # double quote at the end too.
- if not view_line.endswith('"'):
- die("View line with rhs quote should end with one: %s" %
- view_line)
- # skip the quotes
- client_side = view_line[rhs_index+1:-1]
- else:
- client_side = view_line[rhs_index:]
-
# prefix + means overlay on previous mapping
- overlay = False
if depot_side.startswith("+"):
- overlay = True
depot_side = depot_side[1:]
- # prefix - means exclude this path
+ # prefix - means exclude this path, leave out of mappings
exclude = False
if depot_side.startswith("-"):
exclude = True
depot_side = depot_side[1:]
- m = View.Mapping(depot_side, client_side, overlay, exclude)
- self.mappings.append(m)
+ if not exclude:
+ self.mappings.append(depot_side)
- def map_in_client(self, depot_path):
- """Return the relative location in the client where this
- depot file should live. Returns "" if the file should
- not be mapped in the client."""
+ def convert_client_path(self, clientFile):
+ # chop off //client/ part to make it relative
+ if not clientFile.startswith(self.client_prefix):
+ die("No prefix '%s' on clientFile '%s'" %
+ (self.client_prefix, clientFile))
+ return clientFile[len(self.client_prefix):]
- paths_filled = []
- client_path = ""
+ def update_client_spec_path_cache(self, files):
+ """ Caching file paths by "p4 where" batch query """
- # look at later entries first
- for m in self.mappings[::-1]:
+ # List depot file paths exclude that already cached
+ fileArgs = [f['path'] for f in files if f['path'] not in self.client_spec_path_cache]
- # see where will this path end up in the client
- p = m.map_depot_to_client(depot_path)
+ if len(fileArgs) == 0:
+ return # All files in cache
- if p == "":
- # Depot path does not belong in client. Must remember
- # this, as previous items should not cause files to
- # exist in this path either. Remember that the list is
- # being walked from the end, which has higher precedence.
- # Overlap mappings do not exclude previous mappings.
- if not m.overlay:
- paths_filled.append(m.client_side)
+ where_result = p4CmdList(["-x", "-", "where"], stdin=fileArgs)
+ for res in where_result:
+ if "code" in res and res["code"] == "error":
+ # assume error is "... file(s) not in client view"
+ continue
+ if "clientFile" not in res:
+ die("No clientFile from 'p4 where %s'" % depot_path)
+ if "unmap" in res:
+ # it will list all of them, but only one not unmap-ped
+ continue
+ self.client_spec_path_cache[res['depotFile']] = self.convert_client_path(res["clientFile"])
- else:
- # This mapping matched; no need to search any further.
- # But, the mapping could be rejected if the client path
- # has already been claimed by an earlier mapping (i.e.
- # one later in the list, which we are walking backwards).
- already_mapped_in_client = False
- for f in paths_filled:
- # this is View.Path.match
- if f.match(p):
- already_mapped_in_client = True
- break
- if not already_mapped_in_client:
- # Include this file, unless it is from a line that
- # explicitly said to exclude it.
- if not m.exclude:
- client_path = p
+ # not found files or unmap files set to ""
+ for depotFile in fileArgs:
+ if depotFile not in self.client_spec_path_cache:
+ self.client_spec_path_cache[depotFile] = ""
- # a match, even if rejected, always stops the search
- break
+ def map_in_client(self, depot_path):
+ """Return the relative location in the client where this
+ depot file should live. Returns "" if the file should
+ not be mapped in the client."""
- return client_path
+ if depot_path in self.client_spec_path_cache:
+ return self.client_spec_path_cache[depot_path]
+
+ die( "Error: %s is not found in client spec path" % depot_path )
+ return ""
class P4Sync(Command, P4UserMap):
delete_actions = ( "delete", "move/delete", "purge" )
"""Look at each depotFile in the commit to figure out to what
branch it belongs."""
+ if self.clientSpecDirs:
+ files = self.extractFilesFromCommit(commit)
+ self.clientSpecDirs.update_client_spec_path_cache(files)
+
branches = {}
fnum = 0
while commit.has_key("depotFile%s" % fnum):
git_mode = "100755"
if type_base == "symlink":
git_mode = "120000"
- # p4 print on a symlink contains "target\n"; remove the newline
+ # p4 print on a symlink sometimes contains "target\n";
+ # if it does, remove the newline
data = ''.join(contents)
- contents = [data[:-1]]
+ if data[-1] == '\n':
+ contents = [data[:-1]]
+ else:
+ contents = [data]
if type_base == "utf16":
# p4 delivers different text in the python output to -G
else:
sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path'])
+ if self.clientSpecDirs:
+ self.clientSpecDirs.update_client_spec_path_cache(files)
+
self.gitStream.write("commit %s\n" % branch)
# gitStream.write("mark :%s\n" % details["change"])
self.committedChanges.add(int(details["change"]))
#
# Fetch one or more remote refs and merge it/them into the current HEAD.
-USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff] [-s strategy]... [<fetch-options>] <repo> <head>...'
+USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff] [--[no-]rebase|--rebase=preserve] [-s strategy]... [<fetch-options>] <repo> <head>...'
LONG_USAGE='Fetch one or more remote refs and integrate it/them with the current HEAD.'
SUBDIRECTORY_OK=Yes
OPTIONS_SPEC=
test -z "$(git ls-files -u)" || die_conflict
test -f "$GIT_DIR/MERGE_HEAD" && die_merge
+bool_or_string_config () {
+ git config --bool "$1" 2>/dev/null || git config "$1"
+}
+
strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
log_arg= verbosity= progress= recurse_submodules= verify_signatures=
-merge_args= edit=
+merge_args= edit= rebase_args=
curr_branch=$(git symbolic-ref -q HEAD)
curr_branch_short="${curr_branch#refs/heads/}"
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+rebase=$(bool_or_string_config branch.$curr_branch_short.rebase)
if test -z "$rebase"
then
- rebase=$(git config --bool pull.rebase)
+ rebase=$(bool_or_string_config pull.rebase)
fi
dry_run=
while :
esac
merge_args="$merge_args$xx "
;;
+ -r=*|--r=*|--re=*|--reb=*|--reba=*|--rebas=*|--rebase=*)
+ rebase="${1#*=}"
+ ;;
-r|--r|--re|--reb|--reba|--rebas|--rebase)
rebase=true
;;
shift
done
+case "$rebase" in
+preserve)
+ rebase=true
+ rebase_args=--preserve-merges
+ ;;
+true|false|'')
+ ;;
+*)
+ echo "Invalid value for --rebase, should be true, false, or preserve"
+ usage
+ exit 1
+ ;;
+esac
+
error_on_no_merge_candidates () {
exec >&2
for opt
op_prep=with
fi
- curr_branch=${curr_branch#refs/heads/}
- upstream=$(git config "branch.$curr_branch.merge")
- remote=$(git config "branch.$curr_branch.remote")
+ upstream=$(git config "branch.$curr_branch_short.merge")
+ remote=$(git config "branch.$curr_branch_short.remote")
if [ $# -gt 1 ]; then
if [ "$rebase" = true ]; then
merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
case "$rebase" in
true)
- eval="git-rebase $diffstat $strategy_args $merge_args $verbosity"
+ eval="git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity"
eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
;;
*)
msg_content="$(commit_message $sha1)"
# No point in merging the first parent, that's HEAD
new_parents=${new_parents# $first_parent}
+ merge_args="--no-log --no-ff"
if ! do_with_author output eval \
- 'git merge --no-ff $strategy_args -m "$msg_content" $new_parents'
+ 'git merge $merge_args $strategy_args -m "$msg_content" $new_parents'
then
printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
die_with_patch $sha1 "Error redoing merge $sha1"
;;
esac
;;
- 3,#*|3,)
+ 3,"$comment_char"*|3,)
# copy comments
;;
*)
die "Could not skip unnecessary pick commands"
}
+transform_todo_ids () {
+ while read -r command rest
+ do
+ case "$command" in
+ "$comment_char"* | exec)
+ # Be careful for oddball commands like 'exec'
+ # that do not have a SHA-1 at the beginning of $rest.
+ ;;
+ *)
+ sha1=$(git rev-parse --verify --quiet "$@" ${rest%% *}) &&
+ rest="$sha1 ${rest#* }"
+ ;;
+ esac
+ printf '%s\n' "$command${rest:+ }$rest"
+ done <"$todo" >"$todo.new" &&
+ mv -f "$todo.new" "$todo"
+}
+
+expand_todo_ids() {
+ transform_todo_ids
+}
+
+collapse_todo_ids() {
+ transform_todo_ids --short
+}
+
# Rearrange the todo list that has both "pick sha1 msg" and
# "pick sha1 fixup!/squash! msg" appears in it so that the latter
# comes immediately after the former, and change "pick" to
edit-todo)
git stripspace --strip-comments <"$todo" >"$todo".new
mv -f "$todo".new "$todo"
+ collapse_todo_ids
append_todo_help
git stripspace --comment-lines >>"$todo" <<\EOF
git_sequence_editor "$todo" ||
die "Could not execute editor"
+ expand_todo_ids
exit
;;
has_action "$todo" ||
die_abort "Nothing to do"
+expand_todo_ids
+
test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
rm -rf "$state_dir"
}
-run_specific_rebase () {
+run_specific_rebase_internal () {
if [ "$interactive_rebase" = implied ]; then
GIT_EDITOR=:
export GIT_EDITOR
autosquash=
fi
+ # On FreeBSD, the shell's "return" returns from the current
+ # function, not from the current file inclusion.
+ # run_specific_rebase_internal has the file inclusion as a
+ # last statement, so POSIX and FreeBSD's return will do the
+ # same thing.
. git-rebase--$type
+}
+
+run_specific_rebase () {
+ run_specific_rebase_internal
ret=$?
if test $ret -eq 0
then
echo "*export-marks $gitmarks"
fi
test -n "$GIT_REMOTE_TESTGIT_SIGNED_TAGS" && echo "signed-tags"
+ test -n "$GIT_REMOTE_TESTGIT_NO_PRIVATE_UPDATE" && echo "no-private-update"
echo
;;
list)
+++ /dev/null
-#!/usr/bin/env python
-
-# This command is a simple remote-helper, that is used both as a
-# testcase for the remote-helper functionality, and as an example to
-# show remote-helper authors one possible implementation.
-#
-# This is a Git <-> Git importer/exporter, that simply uses git
-# fast-import and git fast-export to consume and produce fast-import
-# streams.
-#
-# To understand better the way things work, one can activate debug
-# traces by setting (to any value) the environment variables
-# GIT_TRANSPORT_HELPER_DEBUG and GIT_DEBUG_TESTGIT, to see messages
-# from the transport-helper side, or from this example remote-helper.
-
-# hashlib is only available in python >= 2.5
-try:
- import hashlib
- _digest = hashlib.sha1
-except ImportError:
- import sha
- _digest = sha.new
-import sys
-import os
-import time
-sys.path.insert(0, os.getenv("GITPYTHONLIB","."))
-
-from git_remote_helpers.util import die, debug, warn
-from git_remote_helpers.git.repo import GitRepo
-from git_remote_helpers.git.exporter import GitExporter
-from git_remote_helpers.git.importer import GitImporter
-from git_remote_helpers.git.non_local import NonLocalGit
-
-if sys.hexversion < 0x02000000:
- # string.encode() is the limiter
- sys.stderr.write("git-remote-testgit: requires Python 2.0 or later.\n")
- sys.exit(1)
-
-
-def encode_filepath(path):
- """Encodes a Unicode file path to a byte string.
-
- On Python 2 this is a no-op; on Python 3 we encode the string as
- suggested by [1] which allows an exact round-trip from the command line
- to the filesystem.
-
- [1] http://docs.python.org/3/c-api/unicode.html#file-system-encoding
-
- """
- if sys.hexversion < 0x03000000:
- return path
- return path.encode(sys.getfilesystemencoding(), 'surrogateescape')
-
-
-def get_repo(alias, url):
- """Returns a git repository object initialized for usage.
- """
-
- repo = GitRepo(url)
- repo.get_revs()
- repo.get_head()
-
- hasher = _digest()
- hasher.update(encode_filepath(repo.path))
- repo.hash = hasher.hexdigest()
-
- repo.get_base_path = lambda base: os.path.join(
- base, 'info', 'fast-import', repo.hash)
-
- prefix = 'refs/testgit/%s/' % alias
- debug("prefix: '%s'", prefix)
-
- repo.gitdir = os.environ["GIT_DIR"]
- repo.alias = alias
- repo.prefix = prefix
-
- repo.exporter = GitExporter(repo)
- repo.importer = GitImporter(repo)
- repo.non_local = NonLocalGit(repo)
-
- return repo
-
-
-def local_repo(repo, path):
- """Returns a git repository object initalized for usage.
- """
-
- local = GitRepo(path)
-
- local.non_local = None
- local.gitdir = repo.gitdir
- local.alias = repo.alias
- local.prefix = repo.prefix
- local.hash = repo.hash
- local.get_base_path = repo.get_base_path
- local.exporter = GitExporter(local)
- local.importer = GitImporter(local)
-
- return local
-
-
-def do_capabilities(repo, args):
- """Prints the supported capabilities.
- """
-
- print("import")
- print("export")
- print("refspec refs/heads/*:%s*" % repo.prefix)
-
- dirname = repo.get_base_path(repo.gitdir)
-
- if not os.path.exists(dirname):
- os.makedirs(dirname)
-
- path = os.path.join(dirname, 'git.marks')
-
- print("*export-marks %s" % path)
- if os.path.exists(path):
- print("*import-marks %s" % path)
-
- print('') # end capabilities
-
-
-def do_list(repo, args):
- """Lists all known references.
-
- Bug: This will always set the remote head to master for non-local
- repositories, since we have no way of determining what the remote
- head is at clone time.
- """
-
- for ref in repo.revs:
- debug("? refs/heads/%s", ref)
- print("? refs/heads/%s" % ref)
-
- if repo.head:
- debug("@refs/heads/%s HEAD" % repo.head)
- print("@refs/heads/%s HEAD" % repo.head)
- else:
- debug("@refs/heads/master HEAD")
- print("@refs/heads/master HEAD")
-
- print('') # end list
-
-
-def update_local_repo(repo):
- """Updates (or clones) a local repo.
- """
-
- if repo.local:
- return repo
-
- path = repo.non_local.clone(repo.gitdir)
- repo.non_local.update(repo.gitdir)
- repo = local_repo(repo, path)
- return repo
-
-
-def do_import(repo, args):
- """Exports a fast-import stream from testgit for git to import.
- """
-
- if len(args) != 1:
- die("Import needs exactly one ref")
-
- if not repo.gitdir:
- die("Need gitdir to import")
-
- ref = args[0]
- refs = [ref]
-
- while True:
- line = sys.stdin.readline().decode()
- if line == '\n':
- break
- if not line.startswith('import '):
- die("Expected import line.")
-
- # strip of leading 'import '
- ref = line[7:].strip()
- refs.append(ref)
-
- print("feature done")
-
- if os.environ.get("GIT_REMOTE_TESTGIT_FAILURE"):
- die('Told to fail')
-
- repo = update_local_repo(repo)
- repo.exporter.export_repo(repo.gitdir, refs)
-
- print("done")
-
-
-def do_export(repo, args):
- """Imports a fast-import stream from git to testgit.
- """
-
- if not repo.gitdir:
- die("Need gitdir to export")
-
- if os.environ.get("GIT_REMOTE_TESTGIT_FAILURE"):
- die('Told to fail')
-
- update_local_repo(repo)
- changed = repo.importer.do_import(repo.gitdir)
-
- if not repo.local:
- repo.non_local.push(repo.gitdir)
-
- for ref in changed:
- print("ok %s" % ref)
- print('')
-
-
-COMMANDS = {
- 'capabilities': do_capabilities,
- 'list': do_list,
- 'import': do_import,
- 'export': do_export,
-}
-
-
-def sanitize(value):
- """Cleans up the url.
- """
-
- if value.startswith('testgit::'):
- value = value[9:]
-
- return value
-
-
-def read_one_line(repo):
- """Reads and processes one command.
- """
-
- sleepy = os.environ.get("GIT_REMOTE_TESTGIT_SLEEPY")
- if sleepy:
- debug("Sleeping %d sec before readline" % int(sleepy))
- time.sleep(int(sleepy))
-
- line = sys.stdin.readline()
-
- cmdline = line.decode()
-
- if not cmdline:
- warn("Unexpected EOF")
- return False
-
- cmdline = cmdline.strip().split()
- if not cmdline:
- # Blank line means we're about to quit
- return False
-
- cmd = cmdline.pop(0)
- debug("Got command '%s' with args '%s'", cmd, ' '.join(cmdline))
-
- if cmd not in COMMANDS:
- die("Unknown command, %s", cmd)
-
- func = COMMANDS[cmd]
- func(repo, cmdline)
- sys.stdout.flush()
-
- return True
-
-
-def main(args):
- """Starts a new remote helper for the specified repository.
- """
-
- if len(args) != 3:
- die("Expecting exactly three arguments.")
- sys.exit(1)
-
- if os.getenv("GIT_DEBUG_TESTGIT"):
- import git_remote_helpers.util
- git_remote_helpers.util.DEBUG = True
-
- alias = sanitize(args[1])
- url = sanitize(args[2])
-
- if not alias.isalnum():
- warn("non-alnum alias '%s'", alias)
- alias = "tmp"
-
- args[1] = alias
- args[2] = url
-
- repo = get_repo(alias, url)
-
- debug("Got arguments %s", args[1:])
-
- more = True
-
- # Use binary mode since Python 3 does not permit unbuffered I/O in text
- # mode. Unbuffered I/O is required to avoid data that should be going
- # to git-fast-import after an "export" command getting caught in our
- # stdin buffer instead.
- sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0)
- while (more):
- more = read_one_line(repo)
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv))
+++ /dev/null
-#!/bin/sh
-#
-# Copyright (c) 2005 Linus Torvalds
-#
-
-OPTIONS_KEEPDASHDASH=
-OPTIONS_SPEC="\
-git repack [options]
---
-a pack everything in a single pack
-A same as -a, and turn unreachable objects loose
-d remove redundant packs, and run git-prune-packed
-f pass --no-reuse-delta to git-pack-objects
-F pass --no-reuse-object to git-pack-objects
-n do not run git-update-server-info
-q,quiet be quiet
-l pass --local to git-pack-objects
-unpack-unreachable= with -A, do not loosen objects older than this
- Packing constraints
-window= size of the window used for delta compression
-window-memory= same as the above, but limit memory size instead of entries count
-depth= limits the maximum delta depth
-max-pack-size= maximum size of each packfile
-"
-SUBDIRECTORY_OK='Yes'
-. git-sh-setup
-
-no_update_info= all_into_one= remove_redundant= unpack_unreachable=
-local= no_reuse= extra=
-while test $# != 0
-do
- case "$1" in
- -n) no_update_info=t ;;
- -a) all_into_one=t ;;
- -A) all_into_one=t
- unpack_unreachable=--unpack-unreachable ;;
- --unpack-unreachable)
- unpack_unreachable="--unpack-unreachable=$2"; shift ;;
- -d) remove_redundant=t ;;
- -q) GIT_QUIET=t ;;
- -f) no_reuse=--no-reuse-delta ;;
- -F) no_reuse=--no-reuse-object ;;
- -l) local=--local ;;
- --max-pack-size|--window|--window-memory|--depth)
- extra="$extra $1=$2"; shift ;;
- --) shift; break;;
- *) usage ;;
- esac
- shift
-done
-
-case "`git config --bool repack.usedeltabaseoffset || echo true`" in
-true)
- extra="$extra --delta-base-offset" ;;
-esac
-
-PACKDIR="$GIT_OBJECT_DIRECTORY/pack"
-PACKTMP="$PACKDIR/.tmp-$$-pack"
-rm -f "$PACKTMP"-*
-trap 'rm -f "$PACKTMP"-*' 0 1 2 3 15
-
-# There will be more repacking strategies to come...
-case ",$all_into_one," in
-,,)
- args='--unpacked --incremental'
- ;;
-,t,)
- args= existing=
- if [ -d "$PACKDIR" ]; then
- for e in `cd "$PACKDIR" && find . -type f -name '*.pack' \
- | sed -e 's/^\.\///' -e 's/\.pack$//'`
- do
- if [ -e "$PACKDIR/$e.keep" ]; then
- : keep
- else
- existing="$existing $e"
- fi
- done
- if test -n "$existing" -a -n "$unpack_unreachable" -a \
- -n "$remove_redundant"
- then
- # This may have arbitrary user arguments, so we
- # have to protect it against whitespace splitting
- # when it gets run as "pack-objects $args" later.
- # Fortunately, we know it's an approxidate, so we
- # can just use dots instead.
- args="$args $(echo "$unpack_unreachable" | tr ' ' .)"
- fi
- fi
- ;;
-esac
-
-mkdir -p "$PACKDIR" || exit
-
-args="$args $local ${GIT_QUIET:+-q} $no_reuse$extra"
-names=$(git pack-objects --keep-true-parents --honor-pack-keep --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
- exit 1
-if [ -z "$names" ]; then
- say Nothing new to pack.
-fi
-
-# Ok we have prepared all new packfiles.
-
-# First see if there are packs of the same name and if so
-# if we can move them out of the way (this can happen if we
-# repacked immediately after packing fully.
-rollback=
-failed=
-for name in $names
-do
- for sfx in pack idx
- do
- file=pack-$name.$sfx
- test -f "$PACKDIR/$file" || continue
- rm -f "$PACKDIR/old-$file" &&
- mv "$PACKDIR/$file" "$PACKDIR/old-$file" || {
- failed=t
- break
- }
- rollback="$rollback $file"
- done
- test -z "$failed" || break
-done
-
-# If renaming failed for any of them, roll the ones we have
-# already renamed back to their original names.
-if test -n "$failed"
-then
- rollback_failure=
- for file in $rollback
- do
- mv "$PACKDIR/old-$file" "$PACKDIR/$file" ||
- rollback_failure="$rollback_failure $file"
- done
- if test -n "$rollback_failure"
- then
- echo >&2 "WARNING: Some packs in use have been renamed by"
- echo >&2 "WARNING: prefixing old- to their name, in order to"
- echo >&2 "WARNING: replace them with the new version of the"
- echo >&2 "WARNING: file. But the operation failed, and"
- echo >&2 "WARNING: attempt to rename them back to their"
- echo >&2 "WARNING: original names also failed."
- echo >&2 "WARNING: Please rename them in $PACKDIR manually:"
- for file in $rollback_failure
- do
- echo >&2 "WARNING: old-$file -> $file"
- done
- fi
- exit 1
-fi
-
-# Now the ones with the same name are out of the way...
-fullbases=
-for name in $names
-do
- fullbases="$fullbases pack-$name"
- chmod a-w "$PACKTMP-$name.pack"
- chmod a-w "$PACKTMP-$name.idx"
- mv -f "$PACKTMP-$name.pack" "$PACKDIR/pack-$name.pack" &&
- mv -f "$PACKTMP-$name.idx" "$PACKDIR/pack-$name.idx" ||
- exit
-done
-
-# Remove the "old-" files
-for name in $names
-do
- rm -f "$PACKDIR/old-pack-$name.idx"
- rm -f "$PACKDIR/old-pack-$name.pack"
-done
-
-# End of pack replacement.
-
-if test "$remove_redundant" = t
-then
- # We know $existing are all redundant.
- if [ -n "$existing" ]
- then
- ( cd "$PACKDIR" &&
- for e in $existing
- do
- case " $fullbases " in
- *" $e "*) ;;
- *) rm -f "$e.pack" "$e.idx" "$e.keep" ;;
- esac
- done
- )
- fi
- git prune-packed ${GIT_QUIET:+-q}
-fi
-
-case "$no_update_info" in
-t) : ;;
-*) git update-server-info ;;
-esac
if ($smtp->code == 220) {
$smtp = Net::SMTP::SSL->start_SSL($smtp,
ssl_verify_params())
- or die "STARTTLS failed! ".$smtp->message;
+ or die "STARTTLS failed! ".IO::Socket::SSL::errstr();
$smtp_encryption = '';
# Send EHLO again to receive fresh
# supported commands
die_with_status () {
status=$1
shift
- echo >&2 "$*"
+ printf >&2 '%s\n' "$*"
exit "$status"
}
esac
fi
+# Set the name of the end-user facing command in the reflog when the
+# script may update refs. When GIT_REFLOG_ACTION is already set, this
+# will not overwrite it, so that a scripted Porcelain (e.g. "git
+# rebase") can set it to its own name (e.g. "rebase") and then call
+# another scripted Porcelain (e.g. "git am") and a call to this
+# function in the latter will keep the name of the end-user facing
+# program (e.g. "rebase") in GIT_REFLOG_ACTION, ensuring whatever it
+# does will be record as actions done as part of the end-user facing
+# operation (e.g. "rebase").
+#
+# NOTE NOTE NOTE: consequently, after assigning a specific message to
+# GIT_REFLOG_ACTION when calling a "git" command to record a custom
+# reflog message, do not leave that custom value in GIT_REFLOG_ACTION,
+# after you are done. Other callers of "git" commands that rely on
+# writing the default "program name" in reflog expect the variable to
+# contain the value set by this function.
+#
+# To use a custom reflog message, do either one of these three:
+#
+# (a) use a single-shot export form:
+# GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: preparing frotz" \
+# git command-that-updates-a-ref
+#
+# (b) save the original away and restore:
+# SAVED_ACTION=$GIT_REFLOG_ACTION
+# GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: preparing frotz"
+# git command-that-updates-a-ref
+# GIT_REFLOG_ACITON=$SAVED_ACTION
+#
+# (c) assign the variable in a subshell:
+# (
+# GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: preparing frotz"
+# git command-that-updates-a-ref
+# )
set_reflog_action() {
if [ -z "${GIT_REFLOG_ACTION:+set}" ]
then
# Get modified modules cared by user
modules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- "$@" |
sane_egrep '^:([0-7]* )?160000' |
- while read mod_src mod_dst sha1_src sha1_dst status name
+ while read mod_src mod_dst sha1_src sha1_dst status sm_path
do
# Always show modules deleted or type-changed (blob<->module)
- test $status = D -o $status = T && echo "$name" && continue
+ test $status = D -o $status = T && echo "$sm_path" && continue
+ # Respect the ignore setting for --for-status.
+ if test -n "$for_status"
+ then
+ name=$(module_name "$sm_path")
+ ignore_config=$(get_submodule_config "$name" ignore none)
+ test $status != A -a $ignore_config = all && continue
+ fi
# Also show added or modified modules which are checked out
- GIT_DIR="$name/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
- echo "$name"
+ GIT_DIR="$sm_path/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
+ echo "$sm_path"
done
)
echo
fi
echo
- done |
- if test -n "$for_status"; then
- if [ -n "$files" ]; then
- gettextln "Submodules changed but not updated:" | git stripspace -c
- else
- gettextln "Submodule changes to be committed:" | git stripspace -c
- fi
- printf "\n" | git stripspace -c
- git stripspace -c
- else
- cat
- fi
+ done
}
#
# List all submodules, prefixed with:
usage(1);
}
- $_prefix = '' unless defined $_prefix;
+ unless (defined $_prefix) {
+ $_prefix = '';
+ warn <<EOF
+WARNING: --prefix is not given, defaulting to empty prefix.
+ This is probably not what you want! In order to stay compatible
+ with regular remote-tracking refs, provide a prefix like
+ --prefix=origin/ (remember the trailing slash), which will cause
+ the SVN-tracking refs to be placed at refs/remotes/origin/*.
+NOTE: In Git v2.0, the default prefix will change from empty to 'origin/'.
+EOF
+ }
if (defined $url) {
$url = canonicalize_url($url);
init_subdir(@_);
my $msgbuf = "";
while (<$msg_fh>) {
if (!$in_msg) {
- $in_msg = 1 if (/^\s*$/);
+ $in_msg = 1 if (/^$/);
$author = $1 if (/^author (.*>)/);
} elsif (/^git-svn-id: /) {
# skip this for now, we regenerate the
#include "commit.h"
const char git_usage_string[] =
- "git [--version] [--help] [-c name=value]\n"
+ "git [--version] [--help] [-C <path>] [-c name=value]\n"
" [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
" [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n"
" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "0", 1);
if (envchanged)
*envchanged = 1;
+ } else if (!strcmp(cmd, "--glob-pathspecs")) {
+ setenv(GIT_GLOB_PATHSPECS_ENVIRONMENT, "1", 1);
+ if (envchanged)
+ *envchanged = 1;
+ } else if (!strcmp(cmd, "--noglob-pathspecs")) {
+ setenv(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, "1", 1);
+ if (envchanged)
+ *envchanged = 1;
+ } else if (!strcmp(cmd, "--icase-pathspecs")) {
+ setenv(GIT_ICASE_PATHSPECS_ENVIRONMENT, "1", 1);
+ if (envchanged)
+ *envchanged = 1;
} else if (!strcmp(cmd, "--shallow-file")) {
(*argv)++;
(*argc)--;
set_alternate_shallow_file((*argv)[0]);
if (envchanged)
*envchanged = 1;
+ } else if (!strcmp(cmd, "-C")) {
+ if (*argc < 2) {
+ fprintf(stderr, "No directory given for -C.\n" );
+ usage(git_usage_string);
+ }
+ if (chdir((*argv)[1]))
+ die_errno("Cannot change to '%s'", (*argv)[1]);
+ if (envchanged)
+ *envchanged = 1;
+ (*argv)++;
+ (*argc)--;
} else {
fprintf(stderr, "Unknown option: %s\n", cmd);
usage(git_usage_string);
{ "remote", cmd_remote, RUN_SETUP },
{ "remote-ext", cmd_remote_ext },
{ "remote-fd", cmd_remote_fd },
+ { "repack", cmd_repack, RUN_SETUP },
{ "replace", cmd_replace, RUN_SETUP },
{ "repo-config", cmd_repo_config, RUN_SETUP_GENTLY },
{ "rerere", cmd_rerere, RUN_SETUP },
+++ /dev/null
-/GIT-PYTHON-VERSION
-/build
-/dist
+++ /dev/null
-#
-# Makefile for the git_remote_helpers python support modules
-#
-pysetupfile:=setup.py
-
-# Shell quote (do not use $(call) to accommodate ancient setups);
-DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
-
-ifndef PYTHON_PATH
- ifeq ($(uname_S),FreeBSD)
- PYTHON_PATH = /usr/local/bin/python
- else
- PYTHON_PATH = /usr/bin/python
- endif
-endif
-ifndef prefix
- prefix = $(HOME)
-endif
-ifndef V
- QUIET = @
- QUIETSETUP = --quiet
-endif
-
-PYLIBDIR=$(shell $(PYTHON_PATH) -c \
- "import sys; \
- print('lib/python%i.%i/site-packages' % sys.version_info[:2])")
-
-py_version=$(shell $(PYTHON_PATH) -c \
- 'import sys; print("%i.%i" % sys.version_info[:2])')
-
-all: $(pysetupfile)
- $(QUIET)test "$$(cat GIT-PYTHON-VERSION 2>/dev/null)" = "$(py_version)" || \
- flags=--force; \
- $(PYTHON_PATH) $(pysetupfile) $(QUIETSETUP) build $$flags
- $(QUIET)echo "$(py_version)" >GIT-PYTHON-VERSION
-
-install: $(pysetupfile)
- $(PYTHON_PATH) $(pysetupfile) install --prefix $(DESTDIR_SQ)$(prefix)
-
-instlibdir: $(pysetupfile)
- @echo "$(DESTDIR_SQ)$(prefix)/$(PYLIBDIR)"
-
-clean:
- $(QUIET)$(PYTHON_PATH) $(pysetupfile) $(QUIETSETUP) clean -a
- $(RM) *.pyo *.pyc GIT-PYTHON-VERSION
+++ /dev/null
-#!/usr/bin/env python
-
-"""Support library package for git remote helpers.
-
-Git remote helpers are helper commands that interfaces with a non-git
-repository to provide automatic import of non-git history into a Git
-repository.
-
-This package provides the support library needed by these helpers..
-The following modules are included:
-
-- git.git - Interaction with Git repositories
-
-- util - General utility functionality use by the other modules in
- this package, and also used directly by the helpers.
-"""
+++ /dev/null
-import sys
-if sys.hexversion < 0x02040000:
- # The limiter is the subprocess module
- sys.stderr.write("git_remote_helpers: requires Python 2.4 or later.\n")
- sys.exit(1)
+++ /dev/null
-import os
-import subprocess
-import sys
-
-from git_remote_helpers.util import check_call
-
-
-class GitExporter(object):
- """An exporter for testgit repositories.
-
- The exporter simply delegates to git fast-export.
- """
-
- def __init__(self, repo):
- """Creates a new exporter for the specified repo.
- """
-
- self.repo = repo
-
- def export_repo(self, base, refs=None):
- """Exports a fast-export stream for the given directory.
-
- Simply delegates to git fast-epxort and pipes it through sed
- to make the refs show up under the prefix rather than the
- default refs/heads. This is to demonstrate how the export
- data can be stored under it's own ref (using the refspec
- capability).
-
- If None, refs defaults to ["HEAD"].
- """
-
- if not refs:
- refs = ["HEAD"]
-
- dirname = self.repo.get_base_path(base)
- path = os.path.abspath(os.path.join(dirname, 'testgit.marks'))
-
- if not os.path.exists(dirname):
- os.makedirs(dirname)
-
- print "feature relative-marks"
- if os.path.exists(os.path.join(dirname, 'git.marks')):
- print "feature import-marks=%s/git.marks" % self.repo.hash
- print "feature export-marks=%s/git.marks" % self.repo.hash
- sys.stdout.flush()
-
- args = ["git", "--git-dir=" + self.repo.gitpath, "fast-export", "--export-marks=" + path]
-
- if os.path.exists(path):
- args.append("--import-marks=" + path)
-
- args.extend(refs)
-
- p1 = subprocess.Popen(args, stdout=subprocess.PIPE)
-
- args = ["sed", "s_refs/heads/_" + self.repo.prefix + "_g"]
-
- check_call(args, stdin=p1.stdout)
+++ /dev/null
-#!/usr/bin/env python
-
-"""Functionality for interacting with Git repositories.
-
-This module provides classes for interfacing with a Git repository.
-"""
-
-import os
-import re
-import time
-from binascii import hexlify
-from cStringIO import StringIO
-import unittest
-
-from git_remote_helpers.util import debug, error, die, start_command, run_command
-
-
-def get_git_dir ():
- """Return the path to the GIT_DIR for this repo."""
- args = ("git", "rev-parse", "--git-dir")
- exit_code, output, errors = run_command(args)
- if exit_code:
- die("Failed to retrieve git dir")
- assert not errors
- return output.strip()
-
-
-def parse_git_config ():
- """Return a dict containing the parsed version of 'git config -l'."""
- exit_code, output, errors = run_command(("git", "config", "-z", "-l"))
- if exit_code:
- die("Failed to retrieve git configuration")
- assert not errors
- return dict([e.split('\n', 1) for e in output.split("\0") if e])
-
-
-def git_config_bool (value):
- """Convert the given git config string value to True or False.
-
- Raise ValueError if the given string was not recognized as a
- boolean value.
-
- """
- norm_value = str(value).strip().lower()
- if norm_value in ("true", "1", "yes", "on", ""):
- return True
- if norm_value in ("false", "0", "no", "off", "none"):
- return False
- raise ValueError("Failed to parse '%s' into a boolean value" % (value))
-
-
-def valid_git_ref (ref_name):
- """Return True iff the given ref name is a valid git ref name."""
- # The following is a reimplementation of the git check-ref-format
- # command. The rules were derived from the git check-ref-format(1)
- # manual page. This code should be replaced by a call to
- # check_refname_format() in the git library, when such is available.
- if ref_name.endswith('/') or \
- ref_name.startswith('.') or \
- ref_name.count('/.') or \
- ref_name.count('..') or \
- ref_name.endswith('.lock'):
- return False
- for c in ref_name:
- if ord(c) < 0x20 or ord(c) == 0x7f or c in " ~^:?*[":
- return False
- return True
-
-
-class GitObjectFetcher(object):
-
- """Provide parsed access to 'git cat-file --batch'.
-
- This provides a read-only interface to the Git object database.
-
- """
-
- def __init__ (self):
- """Initiate a 'git cat-file --batch' session."""
- self.queue = [] # List of object names to be submitted
- self.in_transit = None # Object name currently in transit
-
- # 'git cat-file --batch' produces binary output which is likely
- # to be corrupted by the default "rU"-mode pipe opened by
- # start_command. (Mode == "rU" does universal new-line
- # conversion, which mangles carriage returns.) Therefore, we
- # open an explicitly binary-safe pipe for transferring the
- # output from 'git cat-file --batch'.
- pipe_r_fd, pipe_w_fd = os.pipe()
- pipe_r = os.fdopen(pipe_r_fd, "rb")
- pipe_w = os.fdopen(pipe_w_fd, "wb")
- self.proc = start_command(("git", "cat-file", "--batch"),
- stdout = pipe_w)
- self.f = pipe_r
-
- def __del__ (self):
- """Verify completed communication with 'git cat-file --batch'."""
- assert not self.queue
- assert self.in_transit is None
- self.proc.stdin.close()
- assert self.proc.wait() == 0 # Zero exit code
- assert self.f.read() == "" # No remaining output
-
- def _submit_next_object (self):
- """Submit queue items to the 'git cat-file --batch' process.
-
- If there are items in the queue, and there is currently no item
- currently in 'transit', then pop the first item off the queue,
- and submit it.
-
- """
- if self.queue and self.in_transit is None:
- self.in_transit = self.queue.pop(0)
- print >> self.proc.stdin, self.in_transit[0]
-
- def push (self, obj, callback):
- """Push the given object name onto the queue.
-
- The given callback function will at some point in the future
- be called exactly once with the following arguments:
- - self - this GitObjectFetcher instance
- - obj - the object name provided to push()
- - sha1 - the SHA1 of the object, if 'None' obj is missing
- - t - the type of the object (tag/commit/tree/blob)
- - size - the size of the object in bytes
- - data - the object contents
-
- """
- self.queue.append((obj, callback))
- self._submit_next_object() # (Re)start queue processing
-
- def process_next_entry (self):
- """Read the next entry off the queue and invoke callback."""
- obj, cb = self.in_transit
- self.in_transit = None
- header = self.f.readline()
- if header == "%s missing\n" % (obj):
- cb(self, obj, None, None, None, None)
- return
- sha1, t, size = header.split(" ")
- assert len(sha1) == 40
- assert t in ("tag", "commit", "tree", "blob")
- assert size.endswith("\n")
- size = int(size.strip())
- data = self.f.read(size)
- assert self.f.read(1) == "\n"
- cb(self, obj, sha1, t, size, data)
- self._submit_next_object()
-
- def process (self):
- """Process the current queue until empty."""
- while self.in_transit is not None:
- self.process_next_entry()
-
- # High-level convenience methods:
-
- def get_sha1 (self, objspec):
- """Return the SHA1 of the object specified by 'objspec'.
-
- Return None if 'objspec' does not specify an existing object.
-
- """
- class _ObjHandler(object):
- """Helper class for getting the returned SHA1."""
- def __init__ (self, parser):
- self.parser = parser
- self.sha1 = None
-
- def __call__ (self, parser, obj, sha1, t, size, data):
- # FIXME: Many unused arguments. Could this be cheaper?
- assert parser == self.parser
- self.sha1 = sha1
-
- handler = _ObjHandler(self)
- self.push(objspec, handler)
- self.process()
- return handler.sha1
-
- def open_obj (self, objspec):
- """Return a file object wrapping the contents of a named object.
-
- The caller is responsible for calling .close() on the returned
- file object.
-
- Raise KeyError if 'objspec' does not exist in the repo.
-
- """
- class _ObjHandler(object):
- """Helper class for parsing the returned git object."""
- def __init__ (self, parser):
- """Set up helper."""
- self.parser = parser
- self.contents = StringIO()
- self.err = None
-
- def __call__ (self, parser, obj, sha1, t, size, data):
- """Git object callback (see GitObjectFetcher documentation)."""
- assert parser == self.parser
- if not sha1: # Missing object
- self.err = "Missing object '%s'" % obj
- else:
- assert size == len(data)
- self.contents.write(data)
-
- handler = _ObjHandler(self)
- self.push(objspec, handler)
- self.process()
- if handler.err:
- raise KeyError(handler.err)
- handler.contents.seek(0)
- return handler.contents
-
- def walk_tree (self, tree_objspec, callback, prefix = ""):
- """Recursively walk the given Git tree object.
-
- Recursively walk all subtrees of the given tree object, and
- invoke the given callback passing three arguments:
- (path, mode, data) with the path, permission bits, and contents
- of all the blobs found in the entire tree structure.
-
- """
- class _ObjHandler(object):
- """Helper class for walking a git tree structure."""
- def __init__ (self, parser, cb, path, mode = None):
- """Set up helper."""
- self.parser = parser
- self.cb = cb
- self.path = path
- self.mode = mode
- self.err = None
-
- def parse_tree (self, treedata):
- """Parse tree object data, yield tree entries.
-
- Each tree entry is a 3-tuple (mode, sha1, path)
-
- self.path is prepended to all paths yielded
- from this method.
-
- """
- while treedata:
- mode = int(treedata[:6], 10)
- # Turn 100xxx into xxx
- if mode > 100000:
- mode -= 100000
- assert treedata[6] == " "
- i = treedata.find("\0", 7)
- assert i > 0
- path = treedata[7:i]
- sha1 = hexlify(treedata[i + 1: i + 21])
- yield (mode, sha1, self.path + path)
- treedata = treedata[i + 21:]
-
- def __call__ (self, parser, obj, sha1, t, size, data):
- """Git object callback (see GitObjectFetcher documentation)."""
- assert parser == self.parser
- if not sha1: # Missing object
- self.err = "Missing object '%s'" % (obj)
- return
- assert size == len(data)
- if t == "tree":
- if self.path:
- self.path += "/"
- # Recurse into all blobs and subtrees
- for m, s, p in self.parse_tree(data):
- parser.push(s,
- self.__class__(self.parser, self.cb, p, m))
- elif t == "blob":
- self.cb(self.path, self.mode, data)
- else:
- raise ValueError("Unknown object type '%s'" % (t))
-
- self.push(tree_objspec, _ObjHandler(self, callback, prefix))
- self.process()
-
-
-class GitRefMap(object):
-
- """Map Git ref names to the Git object names they currently point to.
-
- Behaves like a dictionary of Git ref names -> Git object names.
-
- """
-
- def __init__ (self, obj_fetcher):
- """Create a new Git ref -> object map."""
- self.obj_fetcher = obj_fetcher
- self._cache = {} # dict: refname -> objname
-
- def _load (self, ref):
- """Retrieve the object currently bound to the given ref.
-
- The name of the object pointed to by the given ref is stored
- into this mapping, and also returned.
-
- """
- if ref not in self._cache:
- self._cache[ref] = self.obj_fetcher.get_sha1(ref)
- return self._cache[ref]
-
- def __contains__ (self, refname):
- """Return True if the given refname is present in this cache."""
- return bool(self._load(refname))
-
- def __getitem__ (self, refname):
- """Return the git object name pointed to by the given refname."""
- commit = self._load(refname)
- if commit is None:
- raise KeyError("Unknown ref '%s'" % (refname))
- return commit
-
- def get (self, refname, default = None):
- """Return the git object name pointed to by the given refname."""
- commit = self._load(refname)
- if commit is None:
- return default
- return commit
-
-
-class GitFICommit(object):
-
- """Encapsulate the data in a Git fast-import commit command."""
-
- SHA1RE = re.compile(r'^[0-9a-f]{40}$')
-
- @classmethod
- def parse_mode (cls, mode):
- """Verify the given git file mode, and return it as a string."""
- assert mode in (644, 755, 100644, 100755, 120000)
- return "%i" % (mode)
-
- @classmethod
- def parse_objname (cls, objname):
- """Return the given object name (or mark number) as a string."""
- if isinstance(objname, int): # Object name is a mark number
- assert objname > 0
- return ":%i" % (objname)
-
- # No existence check is done, only checks for valid format
- assert cls.SHA1RE.match(objname) # Object name is valid SHA1
- return objname
-
- @classmethod
- def quote_path (cls, path):
- """Return a quoted version of the given path."""
- path = path.replace("\\", "\\\\")
- path = path.replace("\n", "\\n")
- path = path.replace('"', '\\"')
- return '"%s"' % (path)
-
- @classmethod
- def parse_path (cls, path):
- """Verify that the given path is valid, and quote it, if needed."""
- assert not isinstance(path, int) # Cannot be a mark number
-
- # These checks verify the rules on the fast-import man page
- assert not path.count("//")
- assert not path.endswith("/")
- assert not path.startswith("/")
- assert not path.count("/./")
- assert not path.count("/../")
- assert not path.endswith("/.")
- assert not path.endswith("/..")
- assert not path.startswith("./")
- assert not path.startswith("../")
-
- if path.count('"') + path.count('\n') + path.count('\\'):
- return cls.quote_path(path)
- return path
-
- def __init__ (self, name, email, timestamp, timezone, message):
- """Create a new Git fast-import commit, with the given metadata."""
- self.name = name
- self.email = email
- self.timestamp = timestamp
- self.timezone = timezone
- self.message = message
- self.pathops = [] # List of path operations in this commit
-
- def modify (self, mode, blobname, path):
- """Add a file modification to this Git fast-import commit."""
- self.pathops.append(("M",
- self.parse_mode(mode),
- self.parse_objname(blobname),
- self.parse_path(path)))
-
- def delete (self, path):
- """Add a file deletion to this Git fast-import commit."""
- self.pathops.append(("D", self.parse_path(path)))
-
- def copy (self, path, newpath):
- """Add a file copy to this Git fast-import commit."""
- self.pathops.append(("C",
- self.parse_path(path),
- self.parse_path(newpath)))
-
- def rename (self, path, newpath):
- """Add a file rename to this Git fast-import commit."""
- self.pathops.append(("R",
- self.parse_path(path),
- self.parse_path(newpath)))
-
- def note (self, blobname, commit):
- """Add a note object to this Git fast-import commit."""
- self.pathops.append(("N",
- self.parse_objname(blobname),
- self.parse_objname(commit)))
-
- def deleteall (self):
- """Delete all files in this Git fast-import commit."""
- self.pathops.append("deleteall")
-
-
-class TestGitFICommit(unittest.TestCase):
-
- """GitFICommit selftests."""
-
- def test_basic (self):
- """GitFICommit basic selftests."""
-
- def expect_fail (method, data):
- """Verify that the method(data) raises an AssertionError."""
- try:
- method(data)
- except AssertionError:
- return
- raise AssertionError("Failed test for invalid data '%s(%s)'" %
- (method.__name__, repr(data)))
-
- def test_parse_mode (self):
- """GitFICommit.parse_mode() selftests."""
- self.assertEqual(GitFICommit.parse_mode(644), "644")
- self.assertEqual(GitFICommit.parse_mode(755), "755")
- self.assertEqual(GitFICommit.parse_mode(100644), "100644")
- self.assertEqual(GitFICommit.parse_mode(100755), "100755")
- self.assertEqual(GitFICommit.parse_mode(120000), "120000")
- self.assertRaises(AssertionError, GitFICommit.parse_mode, 0)
- self.assertRaises(AssertionError, GitFICommit.parse_mode, 123)
- self.assertRaises(AssertionError, GitFICommit.parse_mode, 600)
- self.assertRaises(AssertionError, GitFICommit.parse_mode, "644")
- self.assertRaises(AssertionError, GitFICommit.parse_mode, "abc")
-
- def test_parse_objname (self):
- """GitFICommit.parse_objname() selftests."""
- self.assertEqual(GitFICommit.parse_objname(1), ":1")
- self.assertRaises(AssertionError, GitFICommit.parse_objname, 0)
- self.assertRaises(AssertionError, GitFICommit.parse_objname, -1)
- self.assertEqual(GitFICommit.parse_objname("0123456789" * 4),
- "0123456789" * 4)
- self.assertEqual(GitFICommit.parse_objname("2468abcdef" * 4),
- "2468abcdef" * 4)
- self.assertRaises(AssertionError, GitFICommit.parse_objname,
- "abcdefghij" * 4)
-
- def test_parse_path (self):
- """GitFICommit.parse_path() selftests."""
- self.assertEqual(GitFICommit.parse_path("foo/bar"), "foo/bar")
- self.assertEqual(GitFICommit.parse_path("path/with\n and \" in it"),
- '"path/with\\n and \\" in it"')
- self.assertRaises(AssertionError, GitFICommit.parse_path, 1)
- self.assertRaises(AssertionError, GitFICommit.parse_path, 0)
- self.assertRaises(AssertionError, GitFICommit.parse_path, -1)
- self.assertRaises(AssertionError, GitFICommit.parse_path, "foo//bar")
- self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/bar/")
- self.assertRaises(AssertionError, GitFICommit.parse_path, "/foo/bar")
- self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/./bar")
- self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/../bar")
- self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/bar/.")
- self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/bar/..")
- self.assertRaises(AssertionError, GitFICommit.parse_path, "./foo/bar")
- self.assertRaises(AssertionError, GitFICommit.parse_path, "../foo/bar")
-
-
-class GitFastImport(object):
-
- """Encapsulate communication with git fast-import."""
-
- def __init__ (self, f, obj_fetcher, last_mark = 0):
- """Set up self to communicate with a fast-import process through f."""
- self.f = f # File object where fast-import stream is written
- self.obj_fetcher = obj_fetcher # GitObjectFetcher instance
- self.next_mark = last_mark + 1 # Next mark number
- self.refs = set() # Keep track of the refnames we've seen
-
- def comment (self, s):
- """Write the given comment in the fast-import stream."""
- assert "\n" not in s, "Malformed comment: '%s'" % (s)
- self.f.write("# %s\n" % (s))
-
- def commit (self, ref, commitdata):
- """Make a commit on the given ref, with the given GitFICommit.
-
- Return the mark number identifying this commit.
-
- """
- self.f.write("""\
-commit %(ref)s
-mark :%(mark)i
-committer %(name)s <%(email)s> %(timestamp)i %(timezone)s
-data %(msgLength)i
-%(msg)s
-""" % {
- 'ref': ref,
- 'mark': self.next_mark,
- 'name': commitdata.name,
- 'email': commitdata.email,
- 'timestamp': commitdata.timestamp,
- 'timezone': commitdata.timezone,
- 'msgLength': len(commitdata.message),
- 'msg': commitdata.message,
-})
-
- if ref not in self.refs:
- self.refs.add(ref)
- parent = ref + "^0"
- if self.obj_fetcher.get_sha1(parent):
- self.f.write("from %s\n" % (parent))
-
- for op in commitdata.pathops:
- self.f.write(" ".join(op))
- self.f.write("\n")
- self.f.write("\n")
- retval = self.next_mark
- self.next_mark += 1
- return retval
-
- def blob (self, data):
- """Import the given blob.
-
- Return the mark number identifying this blob.
-
- """
- self.f.write("blob\nmark :%i\ndata %i\n%s\n" %
- (self.next_mark, len(data), data))
- retval = self.next_mark
- self.next_mark += 1
- return retval
-
- def reset (self, ref, objname):
- """Reset the given ref to point at the given Git object."""
- self.f.write("reset %s\nfrom %s\n\n" %
- (ref, GitFICommit.parse_objname(objname)))
- if ref not in self.refs:
- self.refs.add(ref)
-
-
-class GitNotes(object):
-
- """Encapsulate access to Git notes.
-
- Simulates a dictionary of object name (SHA1) -> Git note mappings.
-
- """
-
- def __init__ (self, notes_ref, obj_fetcher):
- """Create a new Git notes interface, bound to the given notes ref."""
- self.notes_ref = notes_ref
- self.obj_fetcher = obj_fetcher # Used to get objects from repo
- self.imports = [] # list: (objname, note data blob name) tuples
-
- def __del__ (self):
- """Verify that self.commit_notes() was called before destruction."""
- if self.imports:
- error("Missing call to self.commit_notes().")
- error("%i notes are not committed!", len(self.imports))
-
- def _load (self, objname):
- """Return the note data associated with the given git object.
-
- The note data is returned in string form. If no note is found
- for the given object, None is returned.
-
- """
- try:
- f = self.obj_fetcher.open_obj("%s:%s" % (self.notes_ref, objname))
- ret = f.read()
- f.close()
- except KeyError:
- ret = None
- return ret
-
- def __getitem__ (self, objname):
- """Return the note contents associated with the given object.
-
- Raise KeyError if given object has no associated note.
-
- """
- blobdata = self._load(objname)
- if blobdata is None:
- raise KeyError("Object '%s' has no note" % (objname))
- return blobdata
-
- def get (self, objname, default = None):
- """Return the note contents associated with the given object.
-
- Return given default if given object has no associated note.
-
- """
- blobdata = self._load(objname)
- if blobdata is None:
- return default
- return blobdata
-
- def import_note (self, objname, data, gfi):
- """Tell git fast-import to store data as a note for objname.
-
- This method uses the given GitFastImport object to create a
- blob containing the given note data. Also an entry mapping the
- given object name to the created blob is stored until
- commit_notes() is called.
-
- Note that this method only works if it is later followed by a
- call to self.commit_notes() (which produces the note commit
- that refers to the blob produced here).
-
- """
- if not data.endswith("\n"):
- data += "\n"
- gfi.comment("Importing note for object %s" % (objname))
- mark = gfi.blob(data)
- self.imports.append((objname, mark))
-
- def commit_notes (self, gfi, author, message):
- """Produce a git fast-import note commit for the imported notes.
-
- This method uses the given GitFastImport object to create a
- commit on the notes ref, introducing the notes previously
- submitted to import_note().
-
- """
- if not self.imports:
- return
- commitdata = GitFICommit(author[0], author[1],
- time.time(), "0000", message)
- for objname, blobname in self.imports:
- assert isinstance(objname, int) and objname > 0
- assert isinstance(blobname, int) and blobname > 0
- commitdata.note(blobname, objname)
- gfi.commit(self.notes_ref, commitdata)
- self.imports = []
-
-
-class GitCachedNotes(GitNotes):
-
- """Encapsulate access to Git notes (cached version).
-
- Only use this class if no caching is done at a higher level.
-
- Simulates a dictionary of object name (SHA1) -> Git note mappings.
-
- """
-
- def __init__ (self, notes_ref, obj_fetcher):
- """Set up a caching wrapper around GitNotes."""
- GitNotes.__init__(self, notes_ref, obj_fetcher)
- self._cache = {} # Cache: object name -> note data
-
- def __del__ (self):
- """Verify that GitNotes' destructor is called."""
- GitNotes.__del__(self)
-
- def _load (self, objname):
- """Extend GitNotes._load() with a local objname -> note cache."""
- if objname not in self._cache:
- self._cache[objname] = GitNotes._load(self, objname)
- return self._cache[objname]
-
- def import_note (self, objname, data, gfi):
- """Extend GitNotes.import_note() with a local objname -> note cache."""
- if not data.endswith("\n"):
- data += "\n"
- assert objname not in self._cache
- self._cache[objname] = data
- GitNotes.import_note(self, objname, data, gfi)
-
-
-if __name__ == '__main__':
- unittest.main()
+++ /dev/null
-import os
-import subprocess
-
-from git_remote_helpers.util import check_call, check_output
-
-
-class GitImporter(object):
- """An importer for testgit repositories.
-
- This importer simply delegates to git fast-import.
- """
-
- def __init__(self, repo):
- """Creates a new importer for the specified repo.
- """
-
- self.repo = repo
-
- def get_refs(self, gitdir):
- """Returns a dictionary with refs.
-
- Note that the keys in the returned dictionary are byte strings as
- read from git.
- """
- args = ["git", "--git-dir=" + gitdir, "for-each-ref", "refs/heads"]
- lines = check_output(args).strip().split('\n'.encode('ascii'))
- refs = {}
- for line in lines:
- value, name = line.split(' '.encode('ascii'))
- name = name.strip('commit\t'.encode('ascii'))
- refs[name] = value
- return refs
-
- def do_import(self, base):
- """Imports a fast-import stream to the given directory.
-
- Simply delegates to git fast-import.
- """
-
- dirname = self.repo.get_base_path(base)
- if self.repo.local:
- gitdir = self.repo.gitpath
- else:
- gitdir = os.path.abspath(os.path.join(dirname, '.git'))
- path = os.path.abspath(os.path.join(dirname, 'testgit.marks'))
-
- if not os.path.exists(dirname):
- os.makedirs(dirname)
-
- refs_before = self.get_refs(gitdir)
-
- args = ["git", "--git-dir=" + gitdir, "fast-import", "--quiet", "--export-marks=" + path]
-
- if os.path.exists(path):
- args.append("--import-marks=" + path)
-
- check_call(args)
-
- refs_after = self.get_refs(gitdir)
-
- changed = {}
-
- for name, value in refs_after.iteritems():
- if refs_before.get(name) == value:
- continue
-
- changed[name] = value
-
- return changed
+++ /dev/null
-import os
-import subprocess
-
-from git_remote_helpers.util import check_call, die, warn
-
-
-class NonLocalGit(object):
- """Handler to interact with non-local repos.
- """
-
- def __init__(self, repo):
- """Creates a new non-local handler for the specified repo.
- """
-
- self.repo = repo
-
- def clone(self, base):
- """Clones the non-local repo to base.
-
- Does nothing if a clone already exists.
- """
-
- path = os.path.join(self.repo.get_base_path(base), '.git')
-
- # already cloned
- if os.path.exists(path):
- return path
-
- os.makedirs(path)
- args = ["git", "clone", "--bare", "--quiet", self.repo.gitpath, path]
-
- check_call(args)
-
- return path
-
- def update(self, base):
- """Updates checkout of the non-local repo in base.
- """
-
- path = os.path.join(self.repo.get_base_path(base), '.git')
-
- if not os.path.exists(path):
- die("could not find repo at %s", path)
-
- args = ["git", "--git-dir=" + path, "fetch", "--quiet", self.repo.gitpath]
- check_call(args)
-
- args = ["git", "--git-dir=" + path, "update-ref", "refs/heads/master", "FETCH_HEAD"]
- child = check_call(args)
-
- def push(self, base):
- """Pushes from the non-local repo to base.
- """
-
- path = os.path.join(self.repo.get_base_path(base), '.git')
-
- if not os.path.exists(path):
- die("could not find repo at %s", path)
-
- args = ["git", "--git-dir=" + path, "push", "--quiet", self.repo.gitpath, "--all"]
- child = check_call(args)
+++ /dev/null
-import os
-import subprocess
-
-from git_remote_helpers.util import check_call
-
-
-def sanitize(rev, sep='\t'):
- """Converts a for-each-ref line to a name/value pair.
- """
-
- splitrev = rev.split(sep)
- branchval = splitrev[0]
- branchname = splitrev[1].strip()
- if branchname.startswith("refs/heads/"):
- branchname = branchname[11:]
-
- return branchname, branchval
-
-def is_remote(url):
- """Checks whether the specified value is a remote url.
- """
-
- prefixes = ["http", "file", "git"]
-
- for prefix in prefixes:
- if url.startswith(prefix):
- return True
- return False
-
-class GitRepo(object):
- """Repo object representing a repo.
- """
-
- def __init__(self, path):
- """Initializes a new repo at the given path.
- """
-
- self.path = path
- self.head = None
- self.revmap = {}
- self.local = not is_remote(self.path)
-
- if(self.path.endswith('.git')):
- self.gitpath = self.path
- else:
- self.gitpath = os.path.join(self.path, '.git')
-
- if self.local and not os.path.exists(self.gitpath):
- os.makedirs(self.gitpath)
-
- def get_revs(self):
- """Fetches all revs from the remote.
- """
-
- args = ["git", "ls-remote", self.gitpath]
- path = ".cached_revs"
- ofile = open(path, "w")
-
- check_call(args, stdout=ofile)
- output = open(path).readlines()
- self.revmap = dict(sanitize(i) for i in output)
- if "HEAD" in self.revmap:
- del self.revmap["HEAD"]
- self.revs = self.revmap.keys()
- ofile.close()
-
- def get_head(self):
- """Determines the head of a local repo.
- """
-
- if not self.local:
- return
-
- path = os.path.join(self.gitpath, "HEAD")
- head = open(path).readline()
- self.head, _ = sanitize(head, ' ')
+++ /dev/null
-[build]
-build_purelib = build/lib
-build_platlib = build/lib
+++ /dev/null
-#!/usr/bin/env python
-
-"""Distutils build/install script for the git_remote_helpers package."""
-
-from distutils.core import setup
-
-# If building under Python3 we need to run 2to3 on the code, do this by
-# trying to import distutils' 2to3 builder, which is only available in
-# Python3.
-try:
- from distutils.command.build_py import build_py_2to3 as build_py
-except ImportError:
- # 2.x
- from distutils.command.build_py import build_py
-
-setup(
- name = 'git_remote_helpers',
- version = '0.1.0',
- description = 'Git remote helper program for non-git repositories',
- license = 'GPLv2',
- author = 'The Git Community',
- author_email = 'git@vger.kernel.org',
- url = 'http://www.git-scm.com/',
- package_dir = {'git_remote_helpers': ''},
- packages = ['git_remote_helpers', 'git_remote_helpers.git'],
- cmdclass = {'build_py': build_py},
-)
+++ /dev/null
-#!/usr/bin/env python
-
-"""Misc. useful functionality used by the rest of this package.
-
-This module provides common functionality used by the other modules in
-this package.
-
-"""
-
-import sys
-import os
-import subprocess
-
-try:
- from subprocess import CalledProcessError
-except ImportError:
- # from python2.7:subprocess.py
- # Exception classes used by this module.
- class CalledProcessError(Exception):
- """This exception is raised when a process run by check_call() returns
- a non-zero exit status. The exit status will be stored in the
- returncode attribute."""
- def __init__(self, returncode, cmd):
- self.returncode = returncode
- self.cmd = cmd
- def __str__(self):
- return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
-
-
-# Whether or not to show debug messages
-DEBUG = False
-
-def notify(msg, *args):
- """Print a message to stderr."""
- print >> sys.stderr, msg % args
-
-def debug (msg, *args):
- """Print a debug message to stderr when DEBUG is enabled."""
- if DEBUG:
- print >> sys.stderr, msg % args
-
-def error (msg, *args):
- """Print an error message to stderr."""
- print >> sys.stderr, "ERROR:", msg % args
-
-def warn(msg, *args):
- """Print a warning message to stderr."""
- print >> sys.stderr, "warning:", msg % args
-
-def die (msg, *args):
- """Print as error message to stderr and exit the program."""
- error(msg, *args)
- sys.exit(1)
-
-
-class ProgressIndicator(object):
-
- """Simple progress indicator.
-
- Displayed as a spinning character by default, but can be customized
- by passing custom messages that overrides the spinning character.
-
- """
-
- States = ("|", "/", "-", "\\")
-
- def __init__ (self, prefix = "", f = sys.stdout):
- """Create a new ProgressIndicator, bound to the given file object."""
- self.n = 0 # Simple progress counter
- self.f = f # Progress is written to this file object
- self.prev_len = 0 # Length of previous msg (to be overwritten)
- self.prefix = prefix # Prefix prepended to each progress message
- self.prefix_lens = [] # Stack of prefix string lengths
-
- def pushprefix (self, prefix):
- """Append the given prefix onto the prefix stack."""
- self.prefix_lens.append(len(self.prefix))
- self.prefix += prefix
-
- def popprefix (self):
- """Remove the last prefix from the prefix stack."""
- prev_len = self.prefix_lens.pop()
- self.prefix = self.prefix[:prev_len]
-
- def __call__ (self, msg = None, lf = False):
- """Indicate progress, possibly with a custom message."""
- if msg is None:
- msg = self.States[self.n % len(self.States)]
- msg = self.prefix + msg
- print >> self.f, "\r%-*s" % (self.prev_len, msg),
- self.prev_len = len(msg.expandtabs())
- if lf:
- print >> self.f
- self.prev_len = 0
- self.n += 1
-
- def finish (self, msg = "done", noprefix = False):
- """Finalize progress indication with the given message."""
- if noprefix:
- self.prefix = ""
- self(msg, True)
-
-
-def start_command (args, cwd = None, shell = False, add_env = None,
- stdin = subprocess.PIPE, stdout = subprocess.PIPE,
- stderr = subprocess.PIPE):
- """Start the given command, and return a subprocess object.
-
- This provides a simpler interface to the subprocess module.
-
- """
- env = None
- if add_env is not None:
- env = os.environ.copy()
- env.update(add_env)
- return subprocess.Popen(args, bufsize = 1, stdin = stdin, stdout = stdout,
- stderr = stderr, cwd = cwd, shell = shell,
- env = env, universal_newlines = True)
-
-
-def run_command (args, cwd = None, shell = False, add_env = None,
- flag_error = True):
- """Run the given command to completion, and return its results.
-
- This provides a simpler interface to the subprocess module.
-
- The results are formatted as a 3-tuple: (exit_code, output, errors)
-
- If flag_error is enabled, Error messages will be produced if the
- subprocess terminated with a non-zero exit code and/or stderr
- output.
-
- The other arguments are passed on to start_command().
-
- """
- process = start_command(args, cwd, shell, add_env)
- (output, errors) = process.communicate()
- exit_code = process.returncode
- if flag_error and errors:
- error("'%s' returned errors:\n---\n%s---", " ".join(args), errors)
- if flag_error and exit_code:
- error("'%s' returned exit code %i", " ".join(args), exit_code)
- return (exit_code, output, errors)
-
-
-# from python2.7:subprocess.py
-def call(*popenargs, **kwargs):
- """Run command with arguments. Wait for command to complete, then
- return the returncode attribute.
-
- The arguments are the same as for the Popen constructor. Example:
-
- retcode = call(["ls", "-l"])
- """
- return subprocess.Popen(*popenargs, **kwargs).wait()
-
-
-# from python2.7:subprocess.py
-def check_call(*popenargs, **kwargs):
- """Run command with arguments. Wait for command to complete. If
- the exit code was zero then return, otherwise raise
- CalledProcessError. The CalledProcessError object will have the
- return code in the returncode attribute.
-
- The arguments are the same as for the Popen constructor. Example:
-
- check_call(["ls", "-l"])
- """
- retcode = call(*popenargs, **kwargs)
- if retcode:
- cmd = kwargs.get("args")
- if cmd is None:
- cmd = popenargs[0]
- raise CalledProcessError(retcode, cmd)
- return 0
-
-
-# from python2.7:subprocess.py
-def check_output(*popenargs, **kwargs):
- r"""Run command with arguments and return its output as a byte string.
-
- If the exit code was non-zero it raises a CalledProcessError. The
- CalledProcessError object will have the return code in the returncode
- attribute and output in the output attribute.
-
- The arguments are the same as for the Popen constructor. Example:
-
- >>> check_output(["ls", "-l", "/dev/null"])
- 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
-
- The stdout argument is not allowed as it is used internally.
- To capture standard error in the result, use stderr=STDOUT.
-
- >>> check_output(["/bin/sh", "-c",
- ... "ls -l non_existent_file ; exit 0"],
- ... stderr=STDOUT)
- 'ls: non_existent_file: No such file or directory\n'
- """
- if 'stdout' in kwargs:
- raise ValueError('stdout argument not allowed, it will be overridden.')
- process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
- output, unused_err = process.communicate()
- retcode = process.poll()
- if retcode:
- cmd = kwargs.get("args")
- if cmd is None:
- cmd = popenargs[0]
- raise subprocess.CalledProcessError(retcode, cmd)
- return output
-
-
-def file_reader_method (missing_ok = False):
- """Decorator for simplifying reading of files.
-
- If missing_ok is True, a failure to open a file for reading will
- not raise the usual IOError, but instead the wrapped method will be
- called with f == None. The method must in this case properly
- handle f == None.
-
- """
- def _wrap (method):
- """Teach given method to handle both filenames and file objects.
-
- The given method must take a file object as its second argument
- (the first argument being 'self', of course). This decorator
- will take a filename given as the second argument and promote
- it to a file object.
-
- """
- def _wrapped_method (self, filename, *args, **kwargs):
- if isinstance(filename, file):
- f = filename
- else:
- try:
- f = open(filename, 'r')
- except IOError:
- if missing_ok:
- f = None
- else:
- raise
- try:
- return method(self, f, *args, **kwargs)
- finally:
- if not isinstance(filename, file) and f:
- f.close()
- return _wrapped_method
- return _wrap
-
-
-def file_writer_method (method):
- """Decorator for simplifying writing of files.
-
- Enables the given method to handle both filenames and file objects.
-
- The given method must take a file object as its second argument
- (the first argument being 'self', of course). This decorator will
- take a filename given as the second argument and promote it to a
- file object.
-
- """
- def _new_method (self, filename, *args, **kwargs):
- if isinstance(filename, file):
- f = filename
- else:
- # Make sure the containing directory exists
- parent_dir = os.path.dirname(filename)
- if not os.path.isdir(parent_dir):
- os.makedirs(parent_dir)
- f = open(filename, 'w')
- try:
- return method(self, f, *args, **kwargs)
- finally:
- if not isinstance(filename, file):
- f.close()
- return _new_method
$cgi->input({-name=>"h", -value=>$search_hash, -type=>"hidden"}) . "\n" .
$cgi->popup_menu(-name => 'st', -default => 'commit',
-values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) .
- $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) .
- " search:\n",
+ " " . $cgi->a({-href => href(action=>"search_help"),
+ -title => "search help" }, "?") . " search:\n",
$cgi->textfield(-name => "s", -value => $searchtext, -override => 1) . "\n" .
"<span title=\"Extended regular expression\">" .
$cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
print "<div class=\"title\"> </div>\n";
print "<table class=\"projects_list\">\n" .
"<tr id=\"metadata_desc\"><td>description</td><td>" . esc_html($descr) . "</td></tr>\n";
- unless ($omit_owner) {
+ if ($owner and not $omit_owner) {
print "<tr id=\"metadata_owner\"><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
}
if (defined $cd{'rfc2822'}) {
$hash_base, '--', $file_name
or die_error(500, "Open git-blame --porcelain failed");
}
+ binmode $fd, ':utf8';
# incremental blame data returns early
if ($format eq 'data') {
}
div.page_footer {
- height: 17px;
+ height: 22px;
padding: 4px 8px;
background-color: #d9d8d1;
}
div.page_footer_text {
+ line-height: 22px;
float: left;
color: #555555;
font-style: italic;
a.rss_logo {
float: right;
- padding: 3px 0px;
- width: 35px;
+ padding: 3px 5px;
line-height: 10px;
border: 1px solid;
border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
int num_dashes =
((graph->num_parents - dashless_commits) * 2) - 1;
for (i = 0; i < num_dashes; i++) {
- col_num = (i / 2) + dashless_commits;
+ col_num = (i / 2) + dashless_commits + graph->commit_index;
strbuf_write_column(sb, &graph->new_columns[col_num], '-');
}
- col_num = (i / 2) + dashless_commits;
+ col_num = (i / 2) + dashless_commits + graph->commit_index;
strbuf_write_column(sb, &graph->new_columns[col_num], '.');
return num_dashes + 1;
}
#include "grep.h"
#include "userdiff.h"
#include "xdiff-interface.h"
+#include "diff.h"
+#include "diffcore.h"
static int grep_source_load(struct grep_source *gs);
static int grep_source_is_binary(struct grep_source *gs);
fwrite(buf, size, 1, stdout);
}
+static int fill_textconv_grep(struct userdiff_driver *driver,
+ struct grep_source *gs)
+{
+ struct diff_filespec *df;
+ char *buf;
+ size_t size;
+
+ if (!driver || !driver->textconv)
+ return grep_source_load(gs);
+
+ /*
+ * The textconv interface is intimately tied to diff_filespecs, so we
+ * have to pretend to be one. If we could unify the grep_source
+ * and diff_filespec structs, this mess could just go away.
+ */
+ df = alloc_filespec(gs->path);
+ switch (gs->type) {
+ case GREP_SOURCE_SHA1:
+ fill_filespec(df, gs->identifier, 1, 0100644);
+ break;
+ case GREP_SOURCE_FILE:
+ fill_filespec(df, null_sha1, 0, 0100644);
+ break;
+ default:
+ die("BUG: attempt to textconv something without a path?");
+ }
+
+ /*
+ * fill_textconv is not remotely thread-safe; it may load objects
+ * behind the scenes, and it modifies the global diff tempfile
+ * structure.
+ */
+ grep_read_lock();
+ size = fill_textconv(driver, df, &buf);
+ grep_read_unlock();
+ free_filespec(df);
+
+ /*
+ * The normal fill_textconv usage by the diff machinery would just keep
+ * the textconv'd buf separate from the diff_filespec. But much of the
+ * grep code passes around a grep_source and assumes that its "buf"
+ * pointer is the beginning of the thing we are searching. So let's
+ * install our textconv'd version into the grep_source, taking care not
+ * to leak any existing buffer.
+ */
+ grep_source_clear_data(gs);
+ gs->buf = buf;
+ gs->size = size;
+
+ return 0;
+}
+
static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int collect_hits)
{
char *bol;
unsigned count = 0;
int try_lookahead = 0;
int show_function = 0;
+ struct userdiff_driver *textconv = NULL;
enum grep_context ctx = GREP_CONTEXT_HEAD;
xdemitconf_t xecfg;
}
opt->last_shown = 0;
- switch (opt->binary) {
- case GREP_BINARY_DEFAULT:
- if (grep_source_is_binary(gs))
- binary_match_only = 1;
- break;
- case GREP_BINARY_NOMATCH:
- if (grep_source_is_binary(gs))
- return 0; /* Assume unmatch */
- break;
- case GREP_BINARY_TEXT:
- break;
- default:
- die("bug: unknown binary handling mode");
+ if (opt->allow_textconv) {
+ grep_source_load_driver(gs);
+ /*
+ * We might set up the shared textconv cache data here, which
+ * is not thread-safe.
+ */
+ grep_attr_lock();
+ textconv = userdiff_get_textconv(gs->driver);
+ grep_attr_unlock();
+ }
+
+ /*
+ * We know the result of a textconv is text, so we only have to care
+ * about binary handling if we are not using it.
+ */
+ if (!textconv) {
+ switch (opt->binary) {
+ case GREP_BINARY_DEFAULT:
+ if (grep_source_is_binary(gs))
+ binary_match_only = 1;
+ break;
+ case GREP_BINARY_NOMATCH:
+ if (grep_source_is_binary(gs))
+ return 0; /* Assume unmatch */
+ break;
+ case GREP_BINARY_TEXT:
+ break;
+ default:
+ die("bug: unknown binary handling mode");
+ }
}
memset(&xecfg, 0, sizeof(xecfg));
try_lookahead = should_lookahead(opt);
- if (grep_source_load(gs) < 0)
+ if (fill_textconv_grep(textconv, gs) < 0)
return 0;
bol = gs->buf;
#define GREP_BINARY_NOMATCH 1
#define GREP_BINARY_TEXT 2
int binary;
+ int allow_textconv;
int extended;
int use_reflog_filter;
int pcre;
if (strcmp(method, c->method)) {
const char *proto = getenv("SERVER_PROTOCOL");
- if (proto && !strcmp(proto, "HTTP/1.1"))
+ if (proto && !strcmp(proto, "HTTP/1.1")) {
http_status(405, "Method Not Allowed");
- else
+ hdr_str("Allow", !strcmp(c->method, "GET") ?
+ "GET, HEAD" : c->method);
+ } else
http_status(400, "Bad Request");
hdr_nocache();
end_headers();
break;
}
- free(tree->buffer);
- tree->buffer = NULL;
+ free_tree_buffer(tree);
return p;
}
sprintf(url, "%s%s", repo->url, path);
- switch (http_get_strbuf(url, NULL, NULL, 0)) {
+ switch (http_get_strbuf(url, NULL, NULL)) {
case HTTP_OK:
ret = 1;
break;
url = xmalloc(strlen(repo->url) + strlen(path) + 1);
sprintf(url, "%s%s", repo->url, path);
- if (http_get_strbuf(url, NULL, &buffer, 0) != HTTP_OK)
+ if (http_get_strbuf(url, &buffer, NULL) != HTTP_OK)
die("Couldn't get %s for remote symref\n%s", url,
curl_errorstr);
free(url);
pushing = 0;
if (prepare_revision_walk(&revs))
die("revision walk setup failed");
- mark_edges_uninteresting(revs.commits, &revs, NULL);
+ mark_edges_uninteresting(&revs, NULL);
objects_to_send = get_delta(&revs, ref_lock);
finish_all_active_slots();
#include "sideband.h"
#include "run-command.h"
#include "url.h"
+#include "urlmatch.h"
#include "credential.h"
#include "version.h"
#include "pkt-line.h"
static int curl_ftp_no_epsv;
static const char *curl_http_proxy;
static const char *curl_cookie_file;
-static struct credential http_auth = CREDENTIAL_INIT;
+static int curl_save_cookies;
+struct credential http_auth = CREDENTIAL_INIT;
static int http_proactive_auth;
static const char *user_agent;
if (!strcmp("http.sslcainfo", var))
return git_config_string(&ssl_cainfo, var, value);
if (!strcmp("http.sslcertpasswordprotected", var)) {
- if (git_config_bool(var, value))
- ssl_cert_password_required = 1;
+ ssl_cert_password_required = git_config_bool(var, value);
return 0;
}
if (!strcmp("http.ssltry", var)) {
if (!strcmp("http.cookiefile", var))
return git_config_string(&curl_cookie_file, var, value);
+ if (!strcmp("http.savecookies", var)) {
+ curl_save_cookies = git_config_bool(var, value);
+ return 0;
+ }
if (!strcmp("http.postbuffer", var)) {
http_post_buffer = git_config_int(var, value);
return 1;
}
+#if LIBCURL_VERSION_NUM >= 0x071900
+static void set_curl_keepalive(CURL *c)
+{
+ curl_easy_setopt(c, CURLOPT_TCP_KEEPALIVE, 1);
+}
+
+#elif LIBCURL_VERSION_NUM >= 0x071000
+static int sockopt_callback(void *client, curl_socket_t fd, curlsocktype type)
+{
+ int ka = 1;
+ int rc;
+ socklen_t len = (socklen_t)sizeof(ka);
+
+ if (type != CURLSOCKTYPE_IPCXN)
+ return 0;
+
+ rc = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&ka, len);
+ if (rc < 0)
+ warning("unable to set SO_KEEPALIVE on socket %s",
+ strerror(errno));
+
+ return 0; /* CURL_SOCKOPT_OK only exists since curl 7.21.5 */
+}
+
+static void set_curl_keepalive(CURL *c)
+{
+ curl_easy_setopt(c, CURLOPT_SOCKOPTFUNCTION, sockopt_callback);
+}
+
+#else
+static void set_curl_keepalive(CURL *c)
+{
+ /* not supported on older curl versions */
+}
+#endif
+
static CURL *get_curl_handle(void)
{
CURL *result = curl_easy_init();
curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
}
+ set_curl_keepalive(result);
+
return result;
}
{
char *low_speed_limit;
char *low_speed_time;
+ char *normalized_url;
+ struct urlmatch_config config = { STRING_LIST_INIT_DUP };
+
+ config.section = "http";
+ config.key = NULL;
+ config.collect_fn = http_options;
+ config.cascade_fn = git_default_config;
+ config.cb = NULL;
http_is_verbose = 0;
+ normalized_url = url_normalize(url, &config.url);
- git_config(http_options, NULL);
+ git_config(urlmatch_config_entry, &config);
+ free(normalized_url);
curl_global_init(CURL_GLOBAL_ALL);
slot->callback_data = NULL;
slot->callback_func = NULL;
curl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file);
+ if (curl_save_cookies)
+ curl_easy_setopt(slot->curl, CURLOPT_COOKIEJAR, curl_cookie_file);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL);
credential_reject(&http_auth);
return HTTP_NOAUTH;
} else {
- credential_fill(&http_auth);
return HTTP_REAUTH;
}
} else {
}
}
+static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf)
+{
+ char *ptr;
+ CURLcode ret;
+
+ strbuf_reset(buf);
+ ret = curl_easy_getinfo(curl, info, &ptr);
+ if (!ret && ptr)
+ strbuf_addstr(buf, ptr);
+ return ret;
+}
+
/* http_request() targets */
#define HTTP_REQUEST_STRBUF 0
#define HTTP_REQUEST_FILE 1
-static int http_request(const char *url, struct strbuf *type,
- void *result, int target, int options)
+static int http_request(const char *url,
+ void *result, int target,
+ const struct http_get_options *options)
{
struct active_request_slot *slot;
struct slot_results results;
}
strbuf_addstr(&buf, "Pragma:");
- if (options & HTTP_NO_CACHE)
+ if (options && options->no_cache)
strbuf_addstr(&buf, " no-cache");
- if (options & HTTP_KEEP_ERROR)
+ if (options && options->keep_error)
curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 0);
headers = curl_slist_append(headers, buf.buf);
ret = HTTP_START_FAILED;
}
- if (type) {
- char *t;
- strbuf_reset(type);
- curl_easy_getinfo(slot->curl, CURLINFO_CONTENT_TYPE, &t);
- if (t)
- strbuf_addstr(type, t);
- }
+ if (options && options->content_type)
+ curlinfo_strbuf(slot->curl, CURLINFO_CONTENT_TYPE,
+ options->content_type);
+
+ if (options && options->effective_url)
+ curlinfo_strbuf(slot->curl, CURLINFO_EFFECTIVE_URL,
+ options->effective_url);
curl_slist_free_all(headers);
strbuf_release(&buf);
return ret;
}
+/*
+ * Update the "base" url to a more appropriate value, as deduced by
+ * redirects seen when requesting a URL starting with "url".
+ *
+ * The "asked" parameter is a URL that we asked curl to access, and must begin
+ * with "base".
+ *
+ * The "got" parameter is the URL that curl reported to us as where we ended
+ * up.
+ *
+ * Returns 1 if we updated the base url, 0 otherwise.
+ *
+ * Our basic strategy is to compare "base" and "asked" to find the bits
+ * specific to our request. We then strip those bits off of "got" to yield the
+ * new base. So for example, if our base is "http://example.com/foo.git",
+ * and we ask for "http://example.com/foo.git/info/refs", we might end up
+ * with "https://other.example.com/foo.git/info/refs". We would want the
+ * new URL to become "https://other.example.com/foo.git".
+ *
+ * Note that this assumes a sane redirect scheme. It's entirely possible
+ * in the example above to end up at a URL that does not even end in
+ * "info/refs". In such a case we simply punt, as there is not much we can
+ * do (and such a scheme is unlikely to represent a real git repository,
+ * which means we are likely about to abort anyway).
+ */
+static int update_url_from_redirect(struct strbuf *base,
+ const char *asked,
+ const struct strbuf *got)
+{
+ const char *tail;
+ size_t tail_len;
+
+ if (!strcmp(asked, got->buf))
+ return 0;
+
+ if (prefixcmp(asked, base->buf))
+ die("BUG: update_url_from_redirect: %s is not a superset of %s",
+ asked, base->buf);
+
+ tail = asked + base->len;
+ tail_len = strlen(tail);
+
+ if (got->len < tail_len ||
+ strcmp(tail, got->buf + got->len - tail_len))
+ return 0; /* insane redirect scheme */
+
+ strbuf_reset(base);
+ strbuf_add(base, got->buf, got->len - tail_len);
+ return 1;
+}
+
static int http_request_reauth(const char *url,
- struct strbuf *type,
void *result, int target,
- int options)
+ struct http_get_options *options)
{
- int ret = http_request(url, type, result, target, options);
+ int ret = http_request(url, result, target, options);
+
+ if (options && options->effective_url && options->base_url) {
+ if (update_url_from_redirect(options->base_url,
+ url, options->effective_url)) {
+ credential_from_url(&http_auth, options->base_url->buf);
+ url = options->effective_url->buf;
+ }
+ }
+
if (ret != HTTP_REAUTH)
return ret;
* making our next request. We only know how to do this for
* the strbuf case, but that is enough to satisfy current callers.
*/
- if (options & HTTP_KEEP_ERROR) {
+ if (options && options->keep_error) {
switch (target) {
case HTTP_REQUEST_STRBUF:
strbuf_reset(result);
die("BUG: HTTP_KEEP_ERROR is only supported with strbufs");
}
}
- return http_request(url, type, result, target, options);
+
+ credential_fill(&http_auth);
+
+ return http_request(url, result, target, options);
}
int http_get_strbuf(const char *url,
- struct strbuf *type,
- struct strbuf *result, int options)
+ struct strbuf *result,
+ struct http_get_options *options)
{
- return http_request_reauth(url, type, result,
- HTTP_REQUEST_STRBUF, options);
+ return http_request_reauth(url, result, HTTP_REQUEST_STRBUF, options);
}
/*
* If a previous interrupted download is detected (i.e. a previous temporary
* file is still around) the download is resumed.
*/
-static int http_get_file(const char *url, const char *filename, int options)
+static int http_get_file(const char *url, const char *filename,
+ struct http_get_options *options)
{
int ret;
struct strbuf tmpfile = STRBUF_INIT;
strbuf_addf(&tmpfile, "%s.temp", filename);
result = fopen(tmpfile.buf, "a");
- if (! result) {
+ if (!result) {
error("Unable to open local file %s", tmpfile.buf);
ret = HTTP_ERROR;
goto cleanup;
}
- ret = http_request_reauth(url, NULL, result, HTTP_REQUEST_FILE, options);
+ ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options);
fclose(result);
- if ((ret == HTTP_OK) && move_temp_to_file(tmpfile.buf, filename))
+ if (ret == HTTP_OK && move_temp_to_file(tmpfile.buf, filename))
ret = HTTP_ERROR;
cleanup:
strbuf_release(&tmpfile);
int http_fetch_ref(const char *base, struct ref *ref)
{
+ struct http_get_options options = {0};
char *url;
struct strbuf buffer = STRBUF_INIT;
int ret = -1;
+ options.no_cache = 1;
+
url = quote_ref_url(base, ref->name);
- if (http_get_strbuf(url, NULL, &buffer, HTTP_NO_CACHE) == HTTP_OK) {
+ if (http_get_strbuf(url, &buffer, &options) == HTTP_OK) {
strbuf_rtrim(&buffer);
if (buffer.len == 40)
ret = get_sha1_hex(buffer.buf, ref->old_sha1);
strbuf_addf(&buf, "%s.temp", sha1_pack_index_name(sha1));
tmp = strbuf_detach(&buf, NULL);
- if (http_get_file(url, tmp, 0) != HTTP_OK) {
+ if (http_get_file(url, tmp, NULL) != HTTP_OK) {
error("Unable to get pack index %s", url);
free(tmp);
tmp = NULL;
int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
{
+ struct http_get_options options = {0};
int ret = 0, i = 0;
char *url, *data;
struct strbuf buf = STRBUF_INIT;
strbuf_addstr(&buf, "objects/info/packs");
url = strbuf_detach(&buf, NULL);
- ret = http_get_strbuf(url, NULL, &buf, HTTP_NO_CACHE);
+ options.no_cache = 1;
+ ret = http_get_strbuf(url, &buf, &options);
if (ret != HTTP_OK)
goto cleanup;
extern int active_requests;
extern int http_is_verbose;
extern size_t http_post_buffer;
+extern struct credential http_auth;
extern char curl_errorstr[CURL_ERROR_SIZE];
extern char *get_remote_object_url(const char *url, const char *hex,
int only_two_digit_prefix);
-/* Options for http_request_*() */
-#define HTTP_NO_CACHE 1
-#define HTTP_KEEP_ERROR 2
+/* Options for http_get_*() */
+struct http_get_options {
+ unsigned no_cache:1,
+ keep_error:1;
+
+ /* If non-NULL, returns the content-type of the response. */
+ struct strbuf *content_type;
+
+ /*
+ * If non-NULL, returns the URL we ended up at, including any
+ * redirects we followed.
+ */
+ struct strbuf *effective_url;
+
+ /*
+ * If both base_url and effective_url are non-NULL, the base URL will
+ * be munged to reflect any redirections going from the requested url
+ * to effective_url. See the definition of update_url_from_redirect
+ * for details.
+ */
+ struct strbuf *base_url;
+};
-/* Return values for http_request_*() */
+/* Return values for http_get_*() */
#define HTTP_OK 0
#define HTTP_MISSING_TARGET 1
#define HTTP_ERROR 2
*
* If the result pointer is NULL, a HTTP HEAD request is made instead of GET.
*/
-int http_get_strbuf(const char *url, struct strbuf *content_type, struct strbuf *result, int options);
+int http_get_strbuf(const char *url, struct strbuf *result, struct http_get_options *options);
extern int http_fetch_ref(const char *base, struct ref *ref);
if (!split->mail_end)
return status;
- for (cp = split->mail_end + 1; cp < line + len && isspace(*cp); cp++)
+ /*
+ * Look from the end-of-line to find the trailing ">" of the mail
+ * address, even though we should already know it as split->mail_end.
+ * This can help in cases of broken idents with an extra ">" somewhere
+ * in the email address. Note that we are assuming the timestamp will
+ * never have a ">" in it.
+ *
+ * Note that we will always find some ">" before going off the front of
+ * the string, because will always hit the split->mail_end closing
+ * bracket.
+ */
+ for (cp = line + len - 1; *cp != '>'; cp--)
+ ;
+
+ for (cp = cp + 1; cp < line + len && isspace(*cp); cp++)
;
if (line + len <= cp)
goto person_only;
return 0;
}
+
+static int buf_cmp(const char *a_begin, const char *a_end,
+ const char *b_begin, const char *b_end)
+{
+ int a_len = a_end - a_begin;
+ int b_len = b_end - b_begin;
+ int min = a_len < b_len ? a_len : b_len;
+ int cmp;
+
+ cmp = memcmp(a_begin, b_begin, min);
+ if (cmp)
+ return cmp;
+
+ return a_len - b_len;
+}
+
+int ident_cmp(const struct ident_split *a,
+ const struct ident_split *b)
+{
+ int cmp;
+
+ cmp = buf_cmp(a->mail_begin, a->mail_end,
+ b->mail_begin, b->mail_end);
+ if (cmp)
+ return cmp;
+
+ return buf_cmp(a->name_begin, a->name_end,
+ b->name_begin, b->name_end);
+}
#include "prompt.h"
#ifdef NO_OPENSSL
typedef void *SSL;
-#else
-#ifdef APPLE_COMMON_CRYPTO
-#include <CommonCrypto/CommonHMAC.h>
-#define HMAC_CTX CCHmacContext
-#define HMAC_Init(hmac, key, len, algo) CCHmacInit(hmac, algo, key, len)
-#define HMAC_Update CCHmacUpdate
-#define HMAC_Final(hmac, hash, ptr) CCHmacFinal(hmac, hash)
-#define HMAC_CTX_cleanup(ignore)
-#define EVP_md5() kCCHmacAlgMD5
-#else
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-#endif
-#include <openssl/x509v3.h>
#endif
static const char imap_send_usage[] = "git imap-send < <mbox>";
/* Either initialization would be fine */
#define RANGE_SET_INIT {0}
-static void range_set_init(struct range_set *rs, size_t prealloc)
+void range_set_init(struct range_set *rs, size_t prealloc)
{
rs->alloc = rs->nr = 0;
rs->ranges = NULL;
range_set_grow(rs, prealloc);
}
-static void range_set_release(struct range_set *rs)
+void range_set_release(struct range_set *rs)
{
free(rs->ranges);
rs->alloc = rs->nr = 0;
}
/* tack on a _new_ range _at the end_ */
-static void range_set_append_unsafe(struct range_set *rs, long a, long b)
+void range_set_append_unsafe(struct range_set *rs, long a, long b)
{
assert(a <= b);
range_set_grow(rs, 1);
rs->nr++;
}
-static void range_set_append(struct range_set *rs, long a, long b)
+void range_set_append(struct range_set *rs, long a, long b)
{
assert(rs->nr == 0 || rs->ranges[rs->nr-1].end <= a);
range_set_append_unsafe(rs, a, b);
* In-place pass of sorting and merging the ranges in the range set,
* to establish the invariants when we get the ranges from the user
*/
-static void sort_and_merge_range_set(struct range_set *rs)
+void sort_and_merge_range_set(struct range_set *rs)
{
int i;
int o = 0; /* output cursor */
if (p) {
range_set_append_unsafe(&p->ranges, begin, end);
- sort_and_merge_range_set(&p->ranges);
free(path);
return;
}
p = xcalloc(1, sizeof(struct line_log_data));
p->path = path;
range_set_append(&p->ranges, begin, end);
- sort_and_merge_range_set(&p->ranges);
if (ip) {
p->next = ip->next;
ip->next = p;
struct nth_line_cb cb_data;
struct string_list_item *item;
struct line_log_data *ranges = NULL;
+ struct line_log_data *p;
for_each_string_list_item(item, args) {
const char *name_part, *range_part;
char *full_name;
struct diff_filespec *spec;
long begin = 0, end = 0;
+ long anchor;
name_part = skip_range_arg(item->string);
if (!name_part || *name_part != ':' || !name_part[1])
cb_data.lines = lines;
cb_data.line_ends = ends;
+ p = search_line_log_data(ranges, full_name, NULL);
+ if (p && p->ranges.nr)
+ anchor = p->ranges.ranges[p->ranges.nr - 1].end + 1;
+ else
+ anchor = 1;
+
if (parse_range_arg(range_part, nth_line, &cb_data,
- lines, &begin, &end,
+ lines, anchor, &begin, &end,
full_name))
die("malformed -L argument '%s'", range_part);
+ if (lines < end || ((lines || begin) && lines < begin))
+ die("file %s has only %lu lines", name_part, lines);
if (begin < 1)
begin = 1;
if (end < 1)
end = lines;
begin--;
- if (lines < end || lines < begin)
- die("file %s has only %ld lines", name_part, lines);
line_log_data_insert(&ranges, full_name, begin, end);
free_filespec(spec);
ends = NULL;
}
+ for (p = ranges; p; p = p->next)
+ sort_and_merge_range_set(&p->ranges);
+
return ranges;
}
r = r->next;
}
paths[count] = NULL;
- init_pathspec(&rev->diffopt.pathspec, paths);
+ parse_pathspec(&rev->diffopt.pathspec, 0,
+ PATHSPEC_PREFER_FULL, "", paths);
free(paths);
}
}
struct range_set target;
};
+extern void range_set_init(struct range_set *, size_t prealloc);
+extern void range_set_release(struct range_set *);
+/* Range includes start; excludes end */
+extern void range_set_append_unsafe(struct range_set *, long start, long end);
+/* New range must begin at or after end of last added range */
+extern void range_set_append(struct range_set *, long start, long end);
+/*
+ * In-place pass of sorting and merging the ranges in the range set,
+ * to sort and make the ranges disjoint.
+ */
+extern void sort_and_merge_range_set(struct range_set *);
+
/* Linked list of interesting files and their associated ranges. The
* list must be kept sorted by path.
*
/*
* Parse one item in the -L option
+ *
+ * 'begin' is applicable only to relative range anchors. Absolute anchors
+ * ignore this value.
+ *
+ * When parsing "-L A,B", parse_loc() is called once for A and once for B.
+ *
+ * When parsing A, 'begin' must be a negative number, the absolute value of
+ * which is the line at which relative start-of-range anchors should be
+ * based. Beginning of file is represented by -1.
+ *
+ * When parsing B, 'begin' must be the positive line number immediately
+ * following the line computed for 'A'.
*/
static const char *parse_loc(const char *spec, nth_line_fn_t nth_line,
void *data, long lines, long begin, long *ret)
* for 20 lines, or "-L <something>,-5" for 5 lines ending at
* <something>.
*/
- if (1 < begin && (spec[0] == '+' || spec[0] == '-')) {
+ if (1 <= begin && (spec[0] == '+' || spec[0] == '-')) {
num = strtol(spec + 1, &term, 10);
if (term != spec + 1) {
if (!ret)
return term;
+ if (num == 0)
+ die("-L invalid empty range");
if (spec[0] == '-')
num = 0 - num;
if (0 < num)
}
num = strtol(spec, &term, 10);
if (term != spec) {
- if (ret)
+ if (ret) {
+ if (num <= 0)
+ die("-L invalid line number: %ld", num);
*ret = num;
+ }
return term;
}
+
+ if (begin < 0) {
+ if (spec[0] != '^')
+ begin = -begin;
+ else {
+ begin = 1;
+ spec++;
+ }
+ }
+
if (spec[0] != '/')
return spec;
else {
char errbuf[1024];
regerror(reg_error, ®exp, errbuf, 1024);
- die("-L parameter '%s': %s", spec + 1, errbuf);
+ die("-L parameter '%s' starting at line %ld: %s",
+ spec + 1, begin + 1, errbuf);
}
}
}
static const char *parse_range_funcname(const char *arg, nth_line_fn_t nth_line_cb,
- void *cb_data, long lines, long *begin, long *end,
+ void *cb_data, long lines, long anchor, long *begin, long *end,
const char *path)
{
char *pattern;
int reg_error;
regex_t regexp;
+ if (*arg == '^') {
+ anchor = 1;
+ arg++;
+ }
+
assert(*arg == ':');
term = arg+1;
while (*term && *term != ':') {
pattern = xstrndup(arg+1, term-(arg+1));
- start = nth_line_cb(cb_data, 0);
+ anchor--; /* input is in human terms */
+ start = nth_line_cb(cb_data, anchor);
drv = userdiff_find_by_path(path);
if (drv && drv->funcname.pattern) {
p = find_funcname_matching_regexp(xecfg, (char*) start, ®exp);
if (!p)
- die("-L parameter '%s': no match", pattern);
+ die("-L parameter '%s' starting at line %ld: no match",
+ pattern, anchor + 1);
*begin = 0;
while (p > nth_line_cb(cb_data, *begin))
(*begin)++;
}
int parse_range_arg(const char *arg, nth_line_fn_t nth_line_cb,
- void *cb_data, long lines, long *begin, long *end,
- const char *path)
+ void *cb_data, long lines, long anchor,
+ long *begin, long *end, const char *path)
{
*begin = *end = 0;
- if (*arg == ':') {
- arg = parse_range_funcname(arg, nth_line_cb, cb_data, lines, begin, end, path);
+ if (anchor < 1)
+ anchor = 1;
+ if (anchor > lines)
+ anchor = lines + 1;
+
+ if (*arg == ':' || (*arg == '^' && *(arg + 1) == ':')) {
+ arg = parse_range_funcname(arg, nth_line_cb, cb_data, lines, anchor, begin, end, path);
if (!arg || *arg)
return -1;
return 0;
}
- arg = parse_loc(arg, nth_line_cb, cb_data, lines, 1, begin);
+ arg = parse_loc(arg, nth_line_cb, cb_data, lines, -anchor, begin);
if (*arg == ',')
arg = parse_loc(arg + 1, nth_line_cb, cb_data, lines, *begin + 1, end);
const char *skip_range_arg(const char *arg)
{
- if (*arg == ':')
- return parse_range_funcname(arg, NULL, NULL, 0, NULL, NULL, NULL);
+ if (*arg == ':' || (*arg == '^' && *(arg + 1) == ':'))
+ return parse_range_funcname(arg, NULL, NULL, 0, 0, NULL, NULL, NULL);
arg = parse_loc(arg, NULL, NULL, 0, -1, NULL);
* line 'lno' inside the 'cb_data'. The caller is expected to already
* have a suitable map at hand to make this a constant-time lookup.
*
+ * 'anchor' is the 1-based line at which relative range specifications
+ * should be anchored. Absolute ranges are unaffected by this value.
+ *
* Returns 0 in case of success and -1 if there was an error. The
* actual range is stored in *begin and *end. The counting starts
* at 1! In case of error, the caller should show usage message.
extern int parse_range_arg(const char *arg,
nth_line_fn_t nth_line_cb,
- void *cb_data, long lines,
+ void *cb_data, long lines, long anchor,
long *begin, long *end,
const char *path);
cb_data);
}
strbuf_setlen(base, baselen);
- free(tree->buffer);
- tree->buffer = NULL;
+ free_tree_buffer(tree);
}
static void mark_edge_parents_uninteresting(struct commit *commit,
}
}
-void mark_edges_uninteresting(struct commit_list *list,
- struct rev_info *revs,
- show_edge_fn show_edge)
+void mark_edges_uninteresting(struct rev_info *revs, show_edge_fn show_edge)
{
- for ( ; list; list = list->next) {
+ struct commit_list *list;
+ int i;
+
+ for (list = revs->commits; list; list = list->next) {
struct commit *commit = list->item;
if (commit->object.flags & UNINTERESTING) {
mark_tree_uninteresting(commit->tree);
+ if (revs->edge_hint && !(commit->object.flags & SHOWN)) {
+ commit->object.flags |= SHOWN;
+ show_edge(commit);
+ }
continue;
}
mark_edge_parents_uninteresting(commit, revs, show_edge);
}
+ for (i = 0; i < revs->cmdline.nr; i++) {
+ struct object *obj = revs->cmdline.rev[i].item;
+ struct commit *commit = (struct commit *)obj;
+ if (obj->type != OBJ_COMMIT || !(obj->flags & UNINTERESTING))
+ continue;
+ mark_tree_uninteresting(commit->tree);
+ if (revs->edge_hint && !(obj->flags & SHOWN)) {
+ obj->flags |= SHOWN;
+ show_edge(commit);
+ }
+ }
}
static void add_pending_tree(struct rev_info *revs, struct tree *tree)
void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *);
typedef void (*show_edge_fn)(struct commit *);
-void mark_edges_uninteresting(struct commit_list *, struct rev_info *, show_edge_fn);
+void mark_edges_uninteresting(struct rev_info *, show_edge_fn);
#endif
sha1 = commit->tree->object.sha1;
/* Root commit? */
- parents = commit->parents;
+ parents = get_saved_parents(opt, commit);
if (!parents) {
if (opt->show_root_diff) {
diff_root_tree_sha1(sha1, "", &opt->diffopt);
string_list_clear_func(&me->namemap, free_mailmap_info);
}
+/*
+ * On some systems (e.g. MinGW 4.0), string.h has _only_ inline
+ * definition of strcasecmp and no non-inline implementation is
+ * supplied anywhere, which is, eh, "unusual"; we cannot take an
+ * address of such a function to store it in namemap.cmp. This is
+ * here as a workaround---do not assign strcasecmp directly to
+ * namemap.cmp until we know no systems that matter have such an
+ * "unusual" string.h.
+ */
+static int namemap_cmp(const char *a, const char *b)
+{
+ return strcasecmp(a, b);
+}
+
static void add_mapping(struct string_list *map,
char *new_name, char *new_email,
char *old_name, char *old_email)
item = string_list_insert_at_index(map, index, old_email);
me = xcalloc(1, sizeof(struct mailmap_entry));
me->namemap.strdup_strings = 1;
- me->namemap.cmp = strcasecmp;
+ me->namemap.cmp = namemap_cmp;
item->util = me;
}
if (!strncmp(buffer, abbrev, abblen)) {
char *cp;
- if (repo_abbrev)
- free(*repo_abbrev);
+ free(*repo_abbrev);
*repo_abbrev = xmalloc(len);
for (cp = buffer + abblen; isspace(*cp); cp++)
return 0;
}
-static void read_mailmap_buf(struct string_list *map,
- const char *buf, unsigned long len,
- char **repo_abbrev)
+static void read_mailmap_string(struct string_list *map, char *buf,
+ char **repo_abbrev)
{
- while (len) {
- const char *end = strchrnul(buf, '\n');
- unsigned long linelen = end - buf + 1;
- char *line = xmemdupz(buf, linelen);
+ while (*buf) {
+ char *end = strchrnul(buf, '\n');
- read_mailmap_line(map, line, repo_abbrev);
+ if (*end)
+ *end++ = '\0';
- free(line);
- buf += linelen;
- len -= linelen;
+ read_mailmap_line(map, buf, repo_abbrev);
+ buf = end;
}
}
if (type != OBJ_BLOB)
return error("mailmap is not a blob: %s", name);
- read_mailmap_buf(map, buf, size, repo_abbrev);
+ read_mailmap_string(map, buf, repo_abbrev);
free(buf);
return 0;
int err = 0;
map->strdup_strings = 1;
- map->cmp = strcasecmp;
+ map->cmp = namemap_cmp;
if (!git_mailmap_blob && is_bare_repository())
git_mailmap_blob = "HEAD:.mailmap";
{
int n;
struct pathspec match_all;
- init_pathspec(&match_all, NULL);
+ memset(&match_all, 0, sizeof(match_all));
if (read_tree_recursive(tree, "", 0, 0, &match_all, save_files_dirs, o))
return 0;
n = o->current_file_set.nr + o->current_directory_set.nr;
o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF);
else if (!strcmp(s, "histogram"))
o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF);
- else if (!strcmp(s, "diff-algorithm=")) {
- long value = parse_algorithm_value(s+15);
+ else if (!prefixcmp(s, "diff-algorithm=")) {
+ long value = parse_algorithm_value(s + strlen("diff-algorithm="));
if (value < 0)
return -1;
/* clear out previous settings */
--- /dev/null
+diff_cmd () {
+ "$merge_tool_path" "$LOCAL" "$REMOTE" >/dev/null 2>&1
+}
+
+merge_cmd () {
+ if $base_present
+ then
+ "$merge_tool_path" --merge --result="$MERGED" \
+ "$LOCAL" "$BASE" "$REMOTE"
+ else
+ "$merge_tool_path" --merge \
+ --result="$MERGED" "$LOCAL" "$REMOTE"
+ fi
+ status=$?
+}
{
/*
* Throw each directory component in the hash for quick lookup
- * during a git status. Directory components are stored with their
+ * during a git status. Directory components are stored without their
* closing slash. Despite submodules being a directory, they never
- * reach this point, because they are stored without a closing slash
+ * reach this point, because they are stored
* in index_state.name_hash (as ordinary cache_entries).
*
* Note that the cache_entry stored with the dir_entry merely
namelen--;
if (namelen <= 0)
return NULL;
+ namelen--;
/* lookup existing entry for that directory */
dir = find_dir_entry(istate, ce->name, namelen);
}
/* recursively add missing parent directories */
- dir->parent = hash_dir_entry(istate, ce, namelen - 1);
+ dir->parent = hash_dir_entry(istate, ce, namelen);
}
return dir;
}
return slow_same_name(name, namelen, ce->name, len);
}
-struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase)
+struct cache_entry *index_dir_exists(struct index_state *istate, const char *name, int namelen)
+{
+ struct cache_entry *ce;
+ struct dir_entry *dir;
+
+ lazy_init_name_hash(istate);
+ dir = find_dir_entry(istate, name, namelen);
+ if (dir && dir->nr)
+ return dir->ce;
+
+ /*
+ * It might be a submodule. Unlike plain directories, which are stored
+ * in the dir-hash, submodules are stored in the name-hash, so check
+ * there, as well.
+ */
+ ce = index_file_exists(istate, name, namelen, 1);
+ if (ce && S_ISGITLINK(ce->ce_mode))
+ return ce;
+
+ return NULL;
+}
+
+struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase)
{
unsigned int hash = hash_name(name, namelen);
struct cache_entry *ce;
}
ce = ce->next;
}
-
- /*
- * When looking for a directory (trailing '/'), it might be a
- * submodule or a directory. Despite submodules being directories,
- * they are stored in the name hash without a closing slash.
- * When ignore_case is 1, directories are stored in a separate hash
- * table *with* their closing slash.
- *
- * The side effect of this storage technique is we have need to
- * lookup the directory in a separate hash table, and if not found
- * remove the slash from name and perform the lookup again without
- * the slash. If a match is made, S_ISGITLINK(ce->mode) will be
- * true.
- */
- if (icase && name[namelen - 1] == '/') {
- struct dir_entry *dir = find_dir_entry(istate, name, namelen);
- if (dir && dir->nr)
- return dir->ce;
-
- ce = index_name_exists(istate, name, namelen - 1, icase);
- if (ce && S_ISGITLINK(ce->ce_mode))
- return ce;
- }
return NULL;
}
+struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase)
+{
+ if (namelen > 0 && name[namelen - 1] == '/')
+ return index_dir_exists(istate, name, namelen - 1);
+ return index_file_exists(istate, name, namelen, icase);
+}
+
static int free_dir_entry(void *entry, void *unused)
{
struct dir_entry *dir = entry;
sha1_to_hex(mp->remote));
}
diff_flush(&opt);
- diff_tree_release_paths(&opt);
+ free_pathspec(&opt.pathspec);
*num_changes = len;
return changes;
sha1_to_hex(mp->local));
}
diff_flush(&opt);
- diff_tree_release_paths(&opt);
+ free_pathspec(&opt.pathspec);
}
static void check_notes_merge_worktree(struct notes_merge_options *o)
* Properties of the created commit:
* - tree: the result of converting t to a tree object with write_notes_tree().
* - parents: the given parents OR (if NULL) the commit referenced by t->ref.
- * - author/committer: the default determined by commmit_tree().
+ * - author/committer: the default determined by commit_tree().
* - commit message: msg
*
* The resulting commit SHA1 is stored in result_sha1.
die("invalid object type \"%s\"", str);
}
-static unsigned int hash_obj(struct object *obj, unsigned int n)
+static unsigned int hash_obj(const unsigned char *sha1, unsigned int n)
{
unsigned int hash;
- memcpy(&hash, obj->sha1, sizeof(unsigned int));
- return hash % n;
+ memcpy(&hash, sha1, sizeof(unsigned int));
+ /* Assumes power-of-2 hash sizes in grow_object_hash */
+ return hash & (n - 1);
}
static void insert_obj_hash(struct object *obj, struct object **hash, unsigned int size)
{
- unsigned int j = hash_obj(obj, size);
+ unsigned int j = hash_obj(obj->sha1, size);
while (hash[j]) {
j++;
hash[j] = obj;
}
-static unsigned int hashtable_index(const unsigned char *sha1)
-{
- unsigned int i;
- memcpy(&i, sha1, sizeof(unsigned int));
- return i % obj_hash_size;
-}
-
struct object *lookup_object(const unsigned char *sha1)
{
unsigned int i, first;
if (!obj_hash)
return NULL;
- first = i = hashtable_index(sha1);
+ first = i = hash_obj(sha1, obj_hash_size);
while ((obj = obj_hash[i]) != NULL) {
if (!hashcmp(sha1, obj->sha1))
break;
static void grow_object_hash(void)
{
int i;
+ /*
+ * Note that this size must always be power-of-2 to match hash_obj
+ * above.
+ */
int new_hash_size = obj_hash_size < 32 ? 32 : 2 * obj_hash_size;
struct object **new_hash;
return 0;
}
-void add_object_array(struct object *obj, const char *name, struct object_array *array)
-{
- add_object_array_with_mode(obj, name, array, S_IFINVALID);
-}
-
/*
* A zero-length string to which object_array_entry::name can be
* initialized without requiring a malloc/free.
*/
static char object_array_slopbuf[1];
-void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode)
+static void add_object_array_with_mode_context(struct object *obj, const char *name,
+ struct object_array *array,
+ unsigned mode,
+ struct object_context *context)
{
unsigned nr = array->nr;
unsigned alloc = array->alloc;
else
entry->name = xstrdup(name);
entry->mode = mode;
+ entry->context = context;
array->nr = ++nr;
}
+void add_object_array(struct object *obj, const char *name, struct object_array *array)
+{
+ add_object_array_with_mode(obj, name, array, S_IFINVALID);
+}
+
+void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode)
+{
+ add_object_array_with_mode_context(obj, name, array, mode, NULL);
+}
+
+void add_object_array_with_context(struct object *obj, const char *name, struct object_array *array, struct object_context *context)
+{
+ if (context)
+ add_object_array_with_mode_context(obj, name, array, context->mode, context);
+ else
+ add_object_array_with_mode_context(obj, name, array, S_IFINVALID, context);
+}
+
void object_array_filter(struct object_array *array,
object_array_each_func_t want, void *cb_data)
{
*/
char *name;
unsigned mode;
+ struct object_context *context;
} *objects;
};
/* Object array handling .. */
void add_object_array(struct object *obj, const char *name, struct object_array *array);
void add_object_array_with_mode(struct object *obj, const char *name, struct object_array *array, unsigned mode);
+void add_object_array_with_context(struct object *obj, const char *name, struct object_array *array, struct object_context *context);
typedef int (*object_array_each_func_t)(struct object_array_entry *, void *);
pager = getenv("PAGER");
if (!pager)
pager = DEFAULT_PAGER;
- else if (!*pager || !strcmp(pager, "cat"))
+ if (!*pager || !strcmp(pager, "cat"))
pager = NULL;
return pager;
*file = xstrdup(prefix_filename(prefix, strlen(prefix), *file));
}
+static int opt_command_mode_error(const struct option *opt,
+ const struct option *all_opts,
+ int flags)
+{
+ const struct option *that;
+ struct strbuf message = STRBUF_INIT;
+ struct strbuf that_name = STRBUF_INIT;
+
+ /*
+ * Find the other option that was used to set the variable
+ * already, and report that this is not compatible with it.
+ */
+ for (that = all_opts; that->type != OPTION_END; that++) {
+ if (that == opt ||
+ that->type != OPTION_CMDMODE ||
+ that->value != opt->value ||
+ that->defval != *(int *)opt->value)
+ continue;
+
+ if (that->long_name)
+ strbuf_addf(&that_name, "--%s", that->long_name);
+ else
+ strbuf_addf(&that_name, "-%c", that->short_name);
+ strbuf_addf(&message, ": incompatible with %s", that_name.buf);
+ strbuf_release(&that_name);
+ opterror(opt, message.buf, flags);
+ strbuf_release(&message);
+ return -1;
+ }
+ return opterror(opt, ": incompatible with something else", flags);
+}
+
static int get_value(struct parse_opt_ctx_t *p,
- const struct option *opt, int flags)
+ const struct option *opt,
+ const struct option *all_opts,
+ int flags)
{
const char *s, *arg;
const int unset = flags & OPT_UNSET;
*(int *)opt->value = unset ? 0 : opt->defval;
return 0;
+ case OPTION_CMDMODE:
+ /*
+ * Giving the same mode option twice, although is unnecessary,
+ * is not a grave error, so let it pass.
+ */
+ if (*(int *)opt->value && *(int *)opt->value != opt->defval)
+ return opt_command_mode_error(opt, all_opts, flags);
+ *(int *)opt->value = opt->defval;
+ return 0;
+
case OPTION_SET_PTR:
*(void **)opt->value = unset ? NULL : (void *)opt->defval;
return 0;
static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
{
+ const struct option *all_opts = options;
const struct option *numopt = NULL;
for (; options->type != OPTION_END; options++) {
if (options->short_name == *p->opt) {
p->opt = p->opt[1] ? p->opt + 1 : NULL;
- return get_value(p, options, OPT_SHORT);
+ return get_value(p, options, all_opts, OPT_SHORT);
}
/*
static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
const struct option *options)
{
+ const struct option *all_opts = options;
const char *arg_end = strchr(arg, '=');
const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
int abbrev_flags = 0, ambiguous_flags = 0;
continue;
p->opt = rest + 1;
}
- return get_value(p, options, flags ^ opt_flags);
+ return get_value(p, options, all_opts, flags ^ opt_flags);
}
if (ambiguous_option)
(abbrev_flags & OPT_UNSET) ? "no-" : "",
abbrev_option->long_name);
if (abbrev_option)
- return get_value(p, abbrev_option, abbrev_flags);
+ return get_value(p, abbrev_option, all_opts, abbrev_flags);
return -2;
}
static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg,
const struct option *options)
{
+ const struct option *all_opts = options;
+
for (; options->type != OPTION_END; options++) {
if (!(options->flags & PARSE_OPT_NODASH))
continue;
if (options->short_name == arg[0] && arg[1] == '\0')
- return get_value(p, options, OPT_SHORT);
+ return get_value(p, options, all_opts, OPT_SHORT);
}
return -2;
}
OPTION_COUNTUP,
OPTION_SET_INT,
OPTION_SET_PTR,
+ OPTION_CMDMODE,
/* options with arguments (usually) */
OPTION_STRING,
OPTION_INTEGER,
OPTION_FILENAME
};
-/* Deprecated synonym */
-#define OPTION_BOOLEAN OPTION_COUNTUP
-
enum parse_opt_flags {
PARSE_OPT_KEEP_DASHDASH = 1,
PARSE_OPT_STOP_AT_NON_OPTION = 2,
#define OPT_SET_INT(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, \
(h), PARSE_OPT_NOARG, NULL, (i) }
#define OPT_BOOL(s, l, v, h) OPT_SET_INT(s, l, v, h, 1)
+#define OPT_HIDDEN_BOOL(s, l, v, h) { OPTION_SET_INT, (s), (l), (v), NULL, \
+ (h), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, NULL, 1}
#define OPT_SET_PTR(s, l, v, h, p) { OPTION_SET_PTR, (s), (l), (v), NULL, \
(h), PARSE_OPT_NOARG, NULL, (p) }
+#define OPT_CMDMODE(s, l, v, h, i) { OPTION_CMDMODE, (s), (l), (v), NULL, \
+ (h), PARSE_OPT_NOARG|PARSE_OPT_NONEG, NULL, (i) }
#define OPT_INTEGER(s, l, v, h) { OPTION_INTEGER, (s), (l), (v), N_("n"), (h) }
#define OPT_STRING(s, l, v, a, h) { OPTION_STRING, (s), (l), (v), (a), (h) }
#define OPT_STRING_LIST(s, l, v, a, h) \
return 0;
}
+static int have_same_root(const char *path1, const char *path2)
+{
+ int is_abs1, is_abs2;
+
+ is_abs1 = is_absolute_path(path1);
+ is_abs2 = is_absolute_path(path2);
+ return (is_abs1 && is_abs2 && tolower(path1[0]) == tolower(path2[0])) ||
+ (!is_abs1 && !is_abs2);
+}
+
/*
* Give path as relative to prefix.
*
else if (!prefix_len)
return in;
+ if (have_same_root(in, prefix)) {
+ /* bypass dos_drive, for "c:" is identical to "C:" */
+ if (has_dos_drive_prefix(in)) {
+ i = 2;
+ j = 2;
+ }
+ } else {
+ return in;
+ }
+
while (i < prefix_len && j < in_len && prefix[i] == in[j]) {
if (is_dir_sep(prefix[i])) {
while (is_dir_sep(prefix[i]))
return sb->buf;
}
+/*
+ * A simpler implementation of relative_path
+ *
+ * Get relative path by removing "prefix" from "in". This function
+ * first appears in v1.5.6-1-g044bbbc, and makes git_dir shorter
+ * to increase performance when traversing the path to work_tree.
+ */
+const char *remove_leading_path(const char *in, const char *prefix)
+{
+ static char buf[PATH_MAX + 1];
+ int i = 0, j = 0;
+
+ if (!prefix || !prefix[0])
+ return in;
+ while (prefix[i]) {
+ if (is_dir_sep(prefix[i])) {
+ if (!is_dir_sep(in[j]))
+ return in;
+ while (is_dir_sep(prefix[i]))
+ i++;
+ while (is_dir_sep(in[j]))
+ j++;
+ continue;
+ } else if (in[j] != prefix[i]) {
+ return in;
+ }
+ i++;
+ j++;
+ }
+ if (
+ /* "/foo" is a prefix of "/foo" */
+ in[j] &&
+ /* "/foo" is not a prefix of "/foobar" */
+ !is_dir_sep(prefix[i-1]) && !is_dir_sep(in[j])
+ )
+ return in;
+ while (is_dir_sep(in[j]))
+ j++;
+ if (!in[j])
+ strcpy(buf, ".");
+ else
+ strcpy(buf, in + j);
+ return buf;
+}
+
/*
* It is okay if dst == src, but they should not overlap otherwise.
*
*
* Note that this function is purely textual. It does not follow symlinks,
* verify the existence of the path, or make any system calls.
+ *
+ * prefix_len != NULL is for a specific case of prefix_pathspec():
+ * assume that src == dst and src[0..prefix_len-1] is already
+ * normalized, any time "../" eats up to the prefix_len part,
+ * prefix_len is reduced. In the end prefix_len is the remaining
+ * prefix that has not been overridden by user pathspec.
*/
-int normalize_path_copy(char *dst, const char *src)
+int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
{
char *dst0;
/* Windows: dst[-1] cannot be backslash anymore */
while (dst0 < dst && dst[-1] != '/')
dst--;
+ if (prefix_len && *prefix_len > dst - dst0)
+ *prefix_len = dst - dst0;
}
*dst = '\0';
return 0;
}
+int normalize_path_copy(char *dst, const char *src)
+{
+ return normalize_path_copy_len(dst, src, NULL);
+}
+
/*
* path = Canonical absolute path
* prefixes = string_list containing normalized, absolute paths without
* If seen[] has not already been written to, it may make sense
* to use find_pathspecs_matching_against_index() instead.
*/
-void add_pathspec_matches_against_index(const char **pathspec,
- char *seen, int specs)
+void add_pathspec_matches_against_index(const struct pathspec *pathspec,
+ char *seen)
{
int num_unmatched = 0, i;
* mistakenly think that the user gave a pathspec that did not match
* anything.
*/
- for (i = 0; i < specs; i++)
+ for (i = 0; i < pathspec->nr; i++)
if (!seen[i])
num_unmatched++;
if (!num_unmatched)
return;
for (i = 0; i < active_nr; i++) {
const struct cache_entry *ce = active_cache[i];
- match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen);
+ match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, seen);
}
}
* nature of the "closest" (i.e. most specific) matches which each of the
* given pathspecs achieves against all items in the index.
*/
-char *find_pathspecs_matching_against_index(const char **pathspec)
+char *find_pathspecs_matching_against_index(const struct pathspec *pathspec)
{
- char *seen;
- int i;
-
- for (i = 0; pathspec[i]; i++)
- ; /* just counting */
- seen = xcalloc(i, 1);
- add_pathspec_matches_against_index(pathspec, seen, i);
+ char *seen = xcalloc(pathspec->nr, 1);
+ add_pathspec_matches_against_index(pathspec, seen);
return seen;
}
/*
- * Check the index to see whether path refers to a submodule, or
- * something inside a submodule. If the former, returns the path with
- * any trailing slash stripped. If the latter, dies with an error
- * message.
+ * Magic pathspec
+ *
+ * Possible future magic semantics include stuff like:
+ *
+ * { PATHSPEC_RECURSIVE, '*', "recursive" },
+ * { PATHSPEC_REGEXP, '\0', "regexp" },
+ *
+ */
+
+static struct pathspec_magic {
+ unsigned bit;
+ char mnemonic; /* this cannot be ':'! */
+ const char *name;
+} pathspec_magic[] = {
+ { PATHSPEC_FROMTOP, '/', "top" },
+ { PATHSPEC_LITERAL, 0, "literal" },
+ { PATHSPEC_GLOB, '\0', "glob" },
+ { PATHSPEC_ICASE, '\0', "icase" },
+};
+
+/*
+ * Take an element of a pathspec and check for magic signatures.
+ * Append the result to the prefix. Return the magic bitmap.
+ *
+ * For now, we only parse the syntax and throw out anything other than
+ * "top" magic.
+ *
+ * NEEDSWORK: This needs to be rewritten when we start migrating
+ * get_pathspec() users to use the "struct pathspec" interface. For
+ * example, a pathspec element may be marked as case-insensitive, but
+ * the prefix part must always match literally, and a single stupid
+ * string cannot express such a case.
*/
-const char *check_path_for_gitlink(const char *path)
+static unsigned prefix_pathspec(struct pathspec_item *item,
+ unsigned *p_short_magic,
+ const char **raw, unsigned flags,
+ const char *prefix, int prefixlen,
+ const char *elt)
{
- int i, path_len = strlen(path);
- for (i = 0; i < active_nr; i++) {
- const struct cache_entry *ce = active_cache[i];
- if (S_ISGITLINK(ce->ce_mode)) {
- int ce_len = ce_namelen(ce);
- if (path_len <= ce_len || path[ce_len] != '/' ||
- memcmp(ce->name, path, ce_len))
- /* path does not refer to this
- * submodule or anything inside it */
+ static int literal_global = -1;
+ static int glob_global = -1;
+ static int noglob_global = -1;
+ static int icase_global = -1;
+ unsigned magic = 0, short_magic = 0, global_magic = 0;
+ const char *copyfrom = elt, *long_magic_end = NULL;
+ char *match;
+ int i, pathspec_prefix = -1;
+
+ if (literal_global < 0)
+ literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
+ if (literal_global)
+ global_magic |= PATHSPEC_LITERAL;
+
+ if (glob_global < 0)
+ glob_global = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);
+ if (glob_global)
+ global_magic |= PATHSPEC_GLOB;
+
+ if (noglob_global < 0)
+ noglob_global = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);
+
+ if (glob_global && noglob_global)
+ die(_("global 'glob' and 'noglob' pathspec settings are incompatible"));
+
+
+ if (icase_global < 0)
+ icase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);
+ if (icase_global)
+ global_magic |= PATHSPEC_ICASE;
+
+ if ((global_magic & PATHSPEC_LITERAL) &&
+ (global_magic & ~PATHSPEC_LITERAL))
+ die(_("global 'literal' pathspec setting is incompatible "
+ "with all other global pathspec settings"));
+
+ if (elt[0] != ':' || literal_global) {
+ ; /* nothing to do */
+ } else if (elt[1] == '(') {
+ /* longhand */
+ const char *nextat;
+ for (copyfrom = elt + 2;
+ *copyfrom && *copyfrom != ')';
+ copyfrom = nextat) {
+ size_t len = strcspn(copyfrom, ",)");
+ if (copyfrom[len] == ',')
+ nextat = copyfrom + len + 1;
+ else
+ /* handle ')' and '\0' */
+ nextat = copyfrom + len;
+ if (!len)
continue;
- if (path_len == ce_len + 1) {
- /* path refers to submodule;
- * strip trailing slash */
- return xstrndup(ce->name, ce_len);
+ for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
+ if (strlen(pathspec_magic[i].name) == len &&
+ !strncmp(pathspec_magic[i].name, copyfrom, len)) {
+ magic |= pathspec_magic[i].bit;
+ break;
+ }
+ if (!prefixcmp(copyfrom, "prefix:")) {
+ char *endptr;
+ pathspec_prefix = strtol(copyfrom + 7,
+ &endptr, 10);
+ if (endptr - copyfrom != len)
+ die(_("invalid parameter for pathspec magic 'prefix'"));
+ /* "i" would be wrong, but it does not matter */
+ break;
+ }
+ }
+ if (ARRAY_SIZE(pathspec_magic) <= i)
+ die(_("Invalid pathspec magic '%.*s' in '%s'"),
+ (int) len, copyfrom, elt);
+ }
+ if (*copyfrom != ')')
+ die(_("Missing ')' at the end of pathspec magic in '%s'"), elt);
+ long_magic_end = copyfrom;
+ copyfrom++;
+ } else {
+ /* shorthand */
+ for (copyfrom = elt + 1;
+ *copyfrom && *copyfrom != ':';
+ copyfrom++) {
+ char ch = *copyfrom;
+
+ if (!is_pathspec_magic(ch))
+ break;
+ for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
+ if (pathspec_magic[i].mnemonic == ch) {
+ short_magic |= pathspec_magic[i].bit;
+ break;
+ }
+ if (ARRAY_SIZE(pathspec_magic) <= i)
+ die(_("Unimplemented pathspec magic '%c' in '%s'"),
+ ch, elt);
+ }
+ if (*copyfrom == ':')
+ copyfrom++;
+ }
+
+ magic |= short_magic;
+ *p_short_magic = short_magic;
+
+ /* --noglob-pathspec adds :(literal) _unless_ :(glob) is specifed */
+ if (noglob_global && !(magic & PATHSPEC_GLOB))
+ global_magic |= PATHSPEC_LITERAL;
+
+ /* --glob-pathspec is overriden by :(literal) */
+ if ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL))
+ global_magic &= ~PATHSPEC_GLOB;
+
+ magic |= global_magic;
+
+ if (pathspec_prefix >= 0 &&
+ (prefixlen || (prefix && *prefix)))
+ die("BUG: 'prefix' magic is supposed to be used at worktree's root");
+
+ if ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))
+ die(_("%s: 'literal' and 'glob' are incompatible"), elt);
+
+ if (pathspec_prefix >= 0) {
+ match = xstrdup(copyfrom);
+ prefixlen = pathspec_prefix;
+ } else if (magic & PATHSPEC_FROMTOP) {
+ match = xstrdup(copyfrom);
+ prefixlen = 0;
+ } else {
+ match = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);
+ if (!match)
+ die(_("%s: '%s' is outside repository"), elt, copyfrom);
+ }
+ *raw = item->match = match;
+ /*
+ * Prefix the pathspec (keep all magic) and assign to
+ * original. Useful for passing to another command.
+ */
+ if (flags & PATHSPEC_PREFIX_ORIGIN) {
+ struct strbuf sb = STRBUF_INIT;
+ const char *start = elt;
+ if (prefixlen && !literal_global) {
+ /* Preserve the actual prefix length of each pattern */
+ if (short_magic)
+ die("BUG: prefixing on short magic is not supported");
+ else if (long_magic_end) {
+ strbuf_add(&sb, start, long_magic_end - start);
+ strbuf_addf(&sb, ",prefix:%d", prefixlen);
+ start = long_magic_end;
} else {
- die (_("Path '%s' is in submodule '%.*s'"),
- path, ce_len, ce->name);
+ if (*start == ':')
+ start++;
+ strbuf_addf(&sb, ":(prefix:%d)", prefixlen);
}
}
+ strbuf_add(&sb, start, copyfrom - start);
+ strbuf_addstr(&sb, match);
+ item->original = strbuf_detach(&sb, NULL);
+ } else
+ item->original = elt;
+ item->len = strlen(item->match);
+ item->prefix = prefixlen;
+
+ if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&
+ (item->len >= 1 && item->match[item->len - 1] == '/') &&
+ (i = cache_name_pos(item->match, item->len - 1)) >= 0 &&
+ S_ISGITLINK(active_cache[i]->ce_mode)) {
+ item->len--;
+ match[item->len] = '\0';
+ }
+
+ if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *ce = active_cache[i];
+ int ce_len = ce_namelen(ce);
+
+ if (!S_ISGITLINK(ce->ce_mode))
+ continue;
+
+ if (item->len <= ce_len || match[ce_len] != '/' ||
+ memcmp(ce->name, match, ce_len))
+ continue;
+ if (item->len == ce_len + 1) {
+ /* strip trailing slash */
+ item->len--;
+ match[item->len] = '\0';
+ } else
+ die (_("Pathspec '%s' is in submodule '%.*s'"),
+ elt, ce_len, ce->name);
+ }
+
+ if (magic & PATHSPEC_LITERAL)
+ item->nowildcard_len = item->len;
+ else {
+ item->nowildcard_len = simple_length(item->match);
+ if (item->nowildcard_len < prefixlen)
+ item->nowildcard_len = prefixlen;
+ }
+ item->flags = 0;
+ if (magic & PATHSPEC_GLOB) {
+ /*
+ * FIXME: should we enable ONESTAR in _GLOB for
+ * pattern "* * / * . c"?
+ */
+ } else {
+ if (item->nowildcard_len < item->len &&
+ item->match[item->nowildcard_len] == '*' &&
+ no_wildcard(item->match + item->nowildcard_len + 1))
+ item->flags |= PATHSPEC_ONESTAR;
}
- return path;
+
+ /* sanity checks, pathspec matchers assume these are sane */
+ assert(item->nowildcard_len <= item->len &&
+ item->prefix <= item->len);
+ return magic;
+}
+
+static int pathspec_item_cmp(const void *a_, const void *b_)
+{
+ struct pathspec_item *a, *b;
+
+ a = (struct pathspec_item *)a_;
+ b = (struct pathspec_item *)b_;
+ return strcmp(a->match, b->match);
+}
+
+static void NORETURN unsupported_magic(const char *pattern,
+ unsigned magic,
+ unsigned short_magic)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int i, n;
+ for (n = i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
+ const struct pathspec_magic *m = pathspec_magic + i;
+ if (!(magic & m->bit))
+ continue;
+ if (sb.len)
+ strbuf_addstr(&sb, " ");
+ if (short_magic & m->bit)
+ strbuf_addf(&sb, "'%c'", m->mnemonic);
+ else
+ strbuf_addf(&sb, "'%s'", m->name);
+ n++;
+ }
+ /*
+ * We may want to substitute "this command" with a command
+ * name. E.g. when add--interactive dies when running
+ * "checkout -p"
+ */
+ die(_("%s: pathspec magic not supported by this command: %s"),
+ pattern, sb.buf);
}
/*
- * Dies if the given path refers to a file inside a symlinked
- * directory in the index.
+ * Given command line arguments and a prefix, convert the input to
+ * pathspec. die() if any magic in magic_mask is used.
*/
-void die_if_path_beyond_symlink(const char *path, const char *prefix)
+void parse_pathspec(struct pathspec *pathspec,
+ unsigned magic_mask, unsigned flags,
+ const char *prefix, const char **argv)
{
- if (has_symlink_leading_path(path, strlen(path))) {
- int len = prefix ? strlen(prefix) : 0;
- die(_("'%s' is beyond a symbolic link"), path + len);
+ struct pathspec_item *item;
+ const char *entry = argv ? *argv : NULL;
+ int i, n, prefixlen;
+
+ memset(pathspec, 0, sizeof(*pathspec));
+
+ if (flags & PATHSPEC_MAXDEPTH_VALID)
+ pathspec->magic |= PATHSPEC_MAXDEPTH;
+
+ /* No arguments, no prefix -> no pathspec */
+ if (!entry && !prefix)
+ return;
+
+ if ((flags & PATHSPEC_PREFER_CWD) &&
+ (flags & PATHSPEC_PREFER_FULL))
+ die("BUG: PATHSPEC_PREFER_CWD and PATHSPEC_PREFER_FULL are incompatible");
+
+ /* No arguments with prefix -> prefix pathspec */
+ if (!entry) {
+ static const char *raw[2];
+
+ if (flags & PATHSPEC_PREFER_FULL)
+ return;
+
+ if (!(flags & PATHSPEC_PREFER_CWD))
+ die("BUG: PATHSPEC_PREFER_CWD requires arguments");
+
+ pathspec->items = item = xmalloc(sizeof(*item));
+ memset(item, 0, sizeof(*item));
+ item->match = prefix;
+ item->original = prefix;
+ item->nowildcard_len = item->len = strlen(prefix);
+ item->prefix = item->len;
+ raw[0] = prefix;
+ raw[1] = NULL;
+ pathspec->nr = 1;
+ pathspec->_raw = raw;
+ return;
}
+
+ n = 0;
+ while (argv[n])
+ n++;
+
+ pathspec->nr = n;
+ pathspec->items = item = xmalloc(sizeof(*item) * n);
+ pathspec->_raw = argv;
+ prefixlen = prefix ? strlen(prefix) : 0;
+
+ for (i = 0; i < n; i++) {
+ unsigned short_magic;
+ entry = argv[i];
+
+ item[i].magic = prefix_pathspec(item + i, &short_magic,
+ argv + i, flags,
+ prefix, prefixlen, entry);
+ if (item[i].magic & magic_mask)
+ unsupported_magic(entry,
+ item[i].magic & magic_mask,
+ short_magic);
+
+ if ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&
+ has_symlink_leading_path(item[i].match, item[i].len)) {
+ die(_("pathspec '%s' is beyond a symbolic link"), entry);
+ }
+
+ if (item[i].nowildcard_len < item[i].len)
+ pathspec->has_wildcard = 1;
+ pathspec->magic |= item[i].magic;
+ }
+
+
+ if (pathspec->magic & PATHSPEC_MAXDEPTH) {
+ if (flags & PATHSPEC_KEEP_ORDER)
+ die("BUG: PATHSPEC_MAXDEPTH_VALID and PATHSPEC_KEEP_ORDER are incompatible");
+ qsort(pathspec->items, pathspec->nr,
+ sizeof(struct pathspec_item), pathspec_item_cmp);
+ }
+}
+
+/*
+ * N.B. get_pathspec() is deprecated in favor of the "struct pathspec"
+ * based interface - see pathspec.c:parse_pathspec().
+ *
+ * Arguments:
+ * - prefix - a path relative to the root of the working tree
+ * - pathspec - a list of paths underneath the prefix path
+ *
+ * Iterates over pathspec, prepending each path with prefix,
+ * and return the resulting list.
+ *
+ * If pathspec is empty, return a singleton list containing prefix.
+ *
+ * If pathspec and prefix are both empty, return an empty list.
+ *
+ * This is typically used by built-in commands such as add.c, in order
+ * to normalize argv arguments provided to the built-in into a list of
+ * paths to process, all relative to the root of the working tree.
+ */
+const char **get_pathspec(const char *prefix, const char **pathspec)
+{
+ struct pathspec ps;
+ parse_pathspec(&ps,
+ PATHSPEC_ALL_MAGIC &
+ ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
+ PATHSPEC_PREFER_CWD,
+ prefix, pathspec);
+ return ps._raw;
+}
+
+void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
+{
+ *dst = *src;
+ dst->items = xmalloc(sizeof(struct pathspec_item) * dst->nr);
+ memcpy(dst->items, src->items,
+ sizeof(struct pathspec_item) * dst->nr);
+}
+
+void free_pathspec(struct pathspec *pathspec)
+{
+ free(pathspec->items);
+ pathspec->items = NULL;
}
#ifndef PATHSPEC_H
#define PATHSPEC_H
-extern char *find_pathspecs_matching_against_index(const char **pathspec);
-extern void add_pathspec_matches_against_index(const char **pathspec, char *seen, int specs);
+/* Pathspec magic */
+#define PATHSPEC_FROMTOP (1<<0)
+#define PATHSPEC_MAXDEPTH (1<<1)
+#define PATHSPEC_LITERAL (1<<2)
+#define PATHSPEC_GLOB (1<<3)
+#define PATHSPEC_ICASE (1<<4)
+#define PATHSPEC_ALL_MAGIC \
+ (PATHSPEC_FROMTOP | \
+ PATHSPEC_MAXDEPTH | \
+ PATHSPEC_LITERAL | \
+ PATHSPEC_GLOB | \
+ PATHSPEC_ICASE)
+
+#define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */
+
+struct pathspec {
+ const char **_raw; /* get_pathspec() result, not freed by free_pathspec() */
+ int nr;
+ unsigned int has_wildcard:1;
+ unsigned int recursive:1;
+ unsigned magic;
+ int max_depth;
+ struct pathspec_item {
+ const char *match;
+ const char *original;
+ unsigned magic;
+ int len, prefix;
+ int nowildcard_len;
+ int flags;
+ } *items;
+};
+
+#define GUARD_PATHSPEC(ps, mask) \
+ do { \
+ if ((ps)->magic & ~(mask)) \
+ die("BUG:%s:%d: unsupported magic %x", \
+ __FILE__, __LINE__, (ps)->magic & ~(mask)); \
+ } while (0)
+
+/* parse_pathspec flags */
+#define PATHSPEC_PREFER_CWD (1<<0) /* No args means match cwd */
+#define PATHSPEC_PREFER_FULL (1<<1) /* No args means match everything */
+#define PATHSPEC_MAXDEPTH_VALID (1<<2) /* max_depth field is valid */
+/* strip the trailing slash if the given path is a gitlink */
+#define PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP (1<<3)
+/* die if a symlink is part of the given path's directory */
+#define PATHSPEC_SYMLINK_LEADING_PATH (1<<4)
+/*
+ * This is like a combination of ..LEADING_PATH and .._SLASH_CHEAP
+ * (but not the same): it strips the trailing slash if the given path
+ * is a gitlink but also checks and dies if gitlink is part of the
+ * leading path (i.e. the given path goes beyond a submodule). It's
+ * safer than _SLASH_CHEAP and also more expensive.
+ */
+#define PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE (1<<5)
+#define PATHSPEC_PREFIX_ORIGIN (1<<6)
+#define PATHSPEC_KEEP_ORDER (1<<7)
+
+extern void parse_pathspec(struct pathspec *pathspec,
+ unsigned magic_mask,
+ unsigned flags,
+ const char *prefix,
+ const char **args);
+extern void copy_pathspec(struct pathspec *dst, const struct pathspec *src);
+extern void free_pathspec(struct pathspec *);
+
+static inline int ps_strncmp(const struct pathspec_item *item,
+ const char *s1, const char *s2, size_t n)
+{
+ if (item->magic & PATHSPEC_ICASE)
+ return strncasecmp(s1, s2, n);
+ else
+ return strncmp(s1, s2, n);
+}
+
+static inline int ps_strcmp(const struct pathspec_item *item,
+ const char *s1, const char *s2)
+{
+ if (item->magic & PATHSPEC_ICASE)
+ return strcasecmp(s1, s2);
+ else
+ return strcmp(s1, s2);
+}
+
+extern char *find_pathspecs_matching_against_index(const struct pathspec *pathspec);
+extern void add_pathspec_matches_against_index(const struct pathspec *pathspec, char *seen);
extern const char *check_path_for_gitlink(const char *path);
extern void die_if_path_beyond_symlink(const char *path, const char *prefix);
remote_refs prompt
get_tz_offset
credential credential_read credential_write
- temp_acquire temp_release temp_reset temp_path);
+ temp_acquire temp_is_locked temp_release temp_reset temp_path);
=head1 DESCRIPTION
$temp_fd;
}
+=item temp_is_locked ( NAME )
+
+Returns true if the internal lock created by a previous C<temp_acquire()>
+call with C<NAME> is still in effect.
+
+When temp_acquire is called on a C<NAME>, it internally locks the temporary
+file mapped to C<NAME>. That lock will not be released until C<temp_release()>
+is called with either the original C<NAME> or the L<File::Handle> that was
+returned from the original call to temp_acquire.
+
+Subsequent attempts to call C<temp_acquire()> with the same C<NAME> will fail
+unless there has been an intervening C<temp_release()> call for that C<NAME>
+(or its corresponding L<File::Handle> that was returned by the original
+C<temp_acquire()> call).
+
+If true is returned by C<temp_is_locked()> for a C<NAME>, an attempt to
+C<temp_acquire()> the same C<NAME> will cause an error unless
+C<temp_release> is first called on that C<NAME> (or its corresponding
+L<File::Handle> that was returned by the original C<temp_acquire()> call).
+
+=cut
+
+sub temp_is_locked {
+ my ($self, $name) = _maybe_self(@_);
+ my $temp_fd = \$TEMP_FILEMAP{$name};
+
+ defined $$temp_fd && $$temp_fd->opened && $TEMP_FILES{$$temp_fd}{locked};
+}
+
=item temp_release ( NAME )
=item temp_release ( FILEHANDLE )
sub apply_textdelta {
my ($self, $fb, $exp) = @_;
return undef if $self->is_path_ignored($fb->{path});
- my $fh = $::_repository->temp_acquire('svn_delta');
+ my $suffix = 0;
+ ++$suffix while $::_repository->temp_is_locked("svn_delta_${$}_$suffix");
+ my $fh = $::_repository->temp_acquire("svn_delta_${$}_$suffix");
# $fh gets auto-closed() by SVN::TxDelta::apply(),
# (but $base does not,) so dup() it for reading in close_file
open my $dup, '<&', $fh or croak $!;
- my $base = $::_repository->temp_acquire('git_blob');
+ my $base = $::_repository->temp_acquire("git_blob_${$}_$suffix");
if ($fb->{blob}) {
my ($base_is_link, $size);
}
}
+# serf has a bug that leads to a coredump upon termination if the
+# remote access object is left around (not fixed yet in serf 1.3.1).
+# Explicitly free it to work around the issue.
+END {
+ $RA = undef;
+ $ra_invalid = 1;
+}
+
sub _auth_providers () {
my @rv = (
SVN::Client::get_simple_provider(),
Language: fr (French)
Repository: https://github.com/jnavila/git
Leader: Jean-Noël Avila <jn.avila@free.fr>
+Members: Sébastien Helleu <flashcode@flashtux.org>
Language: is (Icelandic)
Leader: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
msgstr ""
#: builtin/describe.c:482
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
msgstr ""
#: builtin/diff.c:77
msgstr "gibt Größenangaben in menschenlesbaren Format aus"
#: builtin/describe.c:16
-msgid "git describe [options] <committish>*"
-msgstr "git describe [Optionen] <committish>*"
+msgid "git describe [options] <commit-ish>*"
+msgstr "git describe [Optionen] <commit-ish>*"
#: builtin/describe.c:17
msgid "git describe [options] --dirty"
#: builtin/describe.c:237
#, c-format
msgid "annotated tag %s not available"
-msgstr "annotierter Tag %s ist nicht verfügbar"
+msgstr "annotiertes Tag %s ist nicht verfügbar"
#: builtin/describe.c:241
#, c-format
msgid "annotated tag %s has no embedded name"
-msgstr "annotierter Tag %s hat keinen eingebetteten Namen"
+msgstr "annotiertes Tag %s hat keinen eingebetteten Namen"
#: builtin/describe.c:243
#, c-format
#: builtin/describe.c:409
msgid "find the tag that comes after the commit"
-msgstr "findet den Tag, die nach Commit kommt"
+msgstr "findet das Tag, das nach Commit kommt"
#: builtin/describe.c:410
msgid "debug search strategy on stderr"
#: builtin/describe.c:412
msgid "use any tag, even unannotated"
-msgstr "verwendet jeden Tag, auch nicht-annotierte"
+msgstr "verwendet jedes Tag, auch nicht-annotierte"
#: builtin/describe.c:413
msgid "always use long format"
msgstr "Keine Namen gefunden, kann nichts beschreiben."
#: builtin/describe.c:489
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
msgstr "Die Option --dirty kann nicht mit Commits verwendet werden."
#: builtin/diff.c:79
#: builtin/fast-export.c:678
msgid "Fake a tagger when tags lack one"
-msgstr "erzeugt künstlich einen Tag-Ersteller, wenn der Tag keinen hat"
+msgstr "erzeugt künstlich einen Tag-Ersteller, wenn das Tag keinen hat"
#: builtin/fast-export.c:680
msgid "Output full tree for each commit"
#: builtin/fetch.c:324
msgid "[new tag]"
-msgstr "[neuer Tag]"
+msgstr "[neues Tag]"
#: builtin/fetch.c:327
msgid "[new branch]"
#: builtin/push.c:257
msgid "Updates were rejected because the tag already exists in the remote."
msgstr ""
-"Aktualisierungen wurden zurückgewiesen, weil der Tag bereits\n"
+"Aktualisierungen wurden zurückgewiesen, weil das Tag bereits\n"
"im Remote-Repository existiert."
#: builtin/push.c:260
#: builtin/tag.c:454
msgid "annotated tag, needs a message"
-msgstr "annotierter Tag, benötigt eine Beschreibung"
+msgstr "annotiertes Tag, benötigt eine Beschreibung"
#: builtin/tag.c:456
msgid "tag message"
#: builtin/tag.c:458
msgid "annotated and GPG-signed tag"
-msgstr "annotierter und GPG-signierter Tag"
+msgstr "annotiertes und GPG-signiertes Tag"
#: builtin/tag.c:462
msgid "use another key to sign the tag"
-msgstr "verwendet einen anderen Schlüssel um den Tag zu signieren"
+msgstr "verwendet einen anderen Schlüssel um das Tag zu signieren"
#: builtin/tag.c:463
msgid "replace the tag if exists"
-msgstr "ersetzt den Tag, wenn er existiert"
+msgstr "ersetzt das Tag, wenn es existiert"
#: builtin/tag.c:464
msgid "show tag list in columns"
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# French translations for Git.
+# Copyright (C) 2013 Jean-Noël Avila <jn.avila@free.fr>
+# This file is distributed under the same license as the Git package.
+# Jean-Noël Avila <jn.avila@free.fr>, 2013.
+# Sébastien Helleu <flashcode@flashtux.org>, 2013.
+#
+# French translations of common Git words used in this file:
+#
+# English | French
+# -----------------+---------------------------------
+# 3-way merge | fusion à 3 points
+# #NN | n°NN
+# a commit | un commit
+# backward |
+# compatibility | rétrocompatibilité
+# bare repository | dépôt nu
+# bisect | bissection
+# blob | blob
+# bug | bogue
+# bundle | colis
+# bypass | éviter d'utiliser
+# to checkout | extraire
+# cherry-pick | picorer
+# to commit | valider
+# commit-ish | commit ou apparenté
+# config file | fichier de configuration
+# dangling | en suspens
+# to debug | déboguer
+# debugging | débogage
+# to deflate | compresser
+# email | e-mail
+# entry | élément
+# fast-forward | avance rapide
+# fast-forwarded | mis à jour en avance rapide
+# to fetch | rapatrier
+# fix conflicts | réglez les conflits
+# to format | formater
+# glob | glob
+# hash | hachage
+# HEAD | HEAD (genre féminin)
+# hook | crochet
+# hunk | section
+# to inflate | décompresser
+# to list | afficher
+# mapping | mise en correspondance
+# merge | fusion
+# pack | paquet
+# patches | patchs
+# pattern | motif
+# to prune | éliminer
+# to push | pousser
+# to rebase | rebaser
+# repository | dépôt
+# remote | distante (ou serveur distant)
+# revision | révision
+# shell | interpréteur de commandes
+# stash | remisage
+# to stash | remiser
+# tag | étiquette
+# template | modèle
+# thread | fil
+# to track | suivre
+# tree | arbre
+# tree-ish | arbre ou apparenté
+# to unstage | désindexer
+# upstream | amont
+# viewer | visualiseur
+# worktree / |
+# work(ing) tree | copie de travail
#
msgid ""
-msgstr "Project-Id-Version: git\n"
+msgstr ""
+"Project-Id-Version: git\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2013-04-30 08:25+0800\n"
-"PO-Revision-Date: 2013-07-02 22:28+0100\n"
-"Last-Translator: Jean-Noël Avila <jn.avila@free.fr>\n"
+"POT-Creation-Date: 2013-08-06 14:10+0800\n"
+"PO-Revision-Date: 2013-10-05 21:17+0200\n"
+"Last-Translator: Sébastien Helleu <flashcode@flashtux.org>\n"
"Language-Team: Jean-Noël Avila <jn.avila@free.fr>\n"
+"Language: fr\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 ?0 : 1;\n"
"X-Generator: Poedit 1.5.4\n"
-#: advice.c:53
+#: advice.c:57
#, c-format
msgid "hint: %.*s\n"
-msgstr "astuce: %*s\n"
+msgstr "astuce: %.*s\n"
#.
#. * Message used both when 'git commit' fails and when
#. * other commands doing a merge do.
#.
-#: advice.c:83
+#: advice.c:87
msgid ""
"Fix them up in the work tree,\n"
"and then use 'git add/rm <file>' as\n"
"appropriate to mark resolution and make a commit,\n"
"or use 'git commit -a'."
-msgstr "Corrigez-les dans l'espace de travail,\n"
-"et utilisez 'git add/rm <fichier>' comme\n"
+msgstr ""
+"Corrigez-les dans la copie de travail,\n"
+"et utilisez 'git add/rm <fichier>' si\n"
"nécessaire pour marquer la résolution et valider,\n"
"ou utilisez 'git commit -a'."
#: archive.c:10
msgid "git archive [options] <tree-ish> [<path>...]"
-msgstr "git archive [options] <arbre> [<chemin>...]"
+msgstr "git archive [options] <arbre ou apparenté> [<chemin>...]"
#: archive.c:11
msgid "git archive --list"
#: archive.c:12
msgid ""
"git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"
-msgstr "git archive --remote <dépot> [--exec <commande>] [options] <arbre> [<chemin>...]"
+msgstr ""
+"git archive --remote <dépôt> [--exec <commande>] [options] <arbre ou "
+"apparenté> [<chemin>...]"
#: archive.c:13
msgid "git archive --remote <repo> [--exec <cmd>] --list"
msgid "archive format"
msgstr "format d'archive"
-#: archive.c:324 builtin/log.c:1126
+#: archive.c:324 builtin/log.c:1173
msgid "prefix"
msgstr "préfixe"
#: archive.c:325
msgid "prepend prefix to each pathname in the archive"
-msgstr "Préfixer chaque chemin de fichier dans l'archive"
+msgstr "préfixer chaque chemin de fichier dans l'archive"
-#: archive.c:326 builtin/archive.c:88 builtin/blame.c:2371
-#: builtin/blame.c:2372 builtin/config.c:55 builtin/fast-export.c:665
-#: builtin/fast-export.c:667 builtin/grep.c:715 builtin/hash-object.c:77
-#: builtin/ls-files.c:490 builtin/ls-files.c:493 builtin/notes.c:536
-#: builtin/notes.c:693 builtin/read-tree.c:107 parse-options.h:149
+#: archive.c:326 builtin/archive.c:88 builtin/blame.c:2292
+#: builtin/blame.c:2293 builtin/config.c:56 builtin/fast-export.c:673
+#: builtin/fast-export.c:675 builtin/grep.c:714 builtin/hash-object.c:77
+#: builtin/ls-files.c:496 builtin/ls-files.c:499 builtin/notes.c:408
+#: builtin/notes.c:565 builtin/read-tree.c:108 parse-options.h:152
msgid "file"
msgstr "fichier"
#: archive.c:327 builtin/archive.c:89
msgid "write the archive to this file"
-msgstr "Ã\89crire l'archive dans ce fichier"
+msgstr "écrire l'archive dans ce fichier"
#: archive.c:329
msgid "read .gitattributes in working directory"
#: archive.c:343
msgid "list supported archive formats"
-msgstr "lister les formats d'archive supportés"
+msgstr "afficher les formats d'archive supportés"
-#: archive.c:345 builtin/archive.c:90 builtin/clone.c:86
+#: archive.c:345 builtin/archive.c:90 builtin/clone.c:85
msgid "repo"
msgstr "dépôt"
msgid "retrieve the archive from remote repository <repo>"
msgstr "récupérer l'archive depuis le dépôt distant <dépôt>"
-#: archive.c:347 builtin/archive.c:92 builtin/notes.c:615
+#: archive.c:347 builtin/archive.c:92 builtin/notes.c:487
msgid "command"
msgstr "commande"
msgid ""
"Negative patterns are ignored in git attributes\n"
"Use '\\!' for literal leading exclamation."
-msgstr "Les patrons négatifs sont ignorés dans les attributs git\n"
-"Utilisez '\\!' pour un point d'exclamation littéral"
+msgstr ""
+"Les motifs de négation sont ignorés dans les attributs git\n"
+"Utilisez '\\!' pour un point d'exclamation littéral."
#: branch.c:60
#, c-format
#: branch.c:82
#, c-format
msgid "Branch %s set up to track remote branch %s from %s by rebasing."
-msgstr "La branche %s est paramétrée pour suivre la branche distante %s de %s en rebasant."
+msgstr ""
+"La branche %s est paramétrée pour suivre la branche distante %s de %s en "
+"rebasant."
#: branch.c:83
#, c-format
msgid "Branch %s set up to track remote branch %s from %s."
-msgstr "La branche %s est paramétrée pour suivre la branche distante %s depuis %s."
+msgstr ""
+"La branche %s est paramétrée pour suivre la branche distante %s depuis %s."
#: branch.c:87
#, c-format
msgid "Branch %s set up to track local branch %s by rebasing."
-msgstr "La branche %s est paramétrée pour suivre la branche locale %s en rebasant."
+msgstr ""
+"La branche %s est paramétrée pour suivre la branche locale %s en rebasant."
#: branch.c:88
#, c-format
#: branch.c:92
#, c-format
msgid "Branch %s set up to track remote ref %s by rebasing."
-msgstr "La branche %s est paramétrée pour suivre la référence distante %s en rebasant."
+msgstr ""
+"La branche %s est paramétrée pour suivre la référence distante %s en "
+"rebasant."
#: branch.c:93
#, c-format
#: branch.c:97
#, c-format
msgid "Branch %s set up to track local ref %s by rebasing."
-msgstr "La branche %s est paramétrée pour suivre la référence locale %s en rebasant."
+msgstr ""
+"La branche %s est paramétrée pour suivre la référence locale %s en rebasant."
#: branch.c:98
#, c-format
msgid "Cannot force update the current branch."
msgstr "Impossible de forcer la mise à jour de la branche courante."
-#: branch.c:201
+#: branch.c:216
#, c-format
msgid "Cannot setup tracking information; starting point '%s' is not a branch."
-msgstr "Impossible de paramétrer le suivi de branche ; le point de départ '%s' n'est pas une branche."
+msgstr ""
+"Impossible de paramétrer le suivi de branche ; le point de départ '%s' n'est "
+"pas une branche."
-#: branch.c:203
+#: branch.c:218
#, c-format
msgid "the requested upstream branch '%s' does not exist"
msgstr "la branche amont demandée '%s' n'existe pas"
-#: branch.c:205
+#: branch.c:220
msgid ""
"\n"
"If you are planning on basing your work on an upstream\n"
"If you are planning to push out a new local branch that\n"
"will track its remote counterpart, you may want to use\n"
"\"git push -u\" to set the upstream config as you push."
-msgstr "\n"
+msgstr ""
+"\n"
"Si vous comptez baser votre travail sur une branche\n"
"amont qui existe déjà sur le serveur distant, vous pourriez\n"
"devoir lancer \"git fetch\" pour la récupérer.\n"
"\n"
-"Si vous comptez pousser une nouvelle branche locale\n"
-"qui suivra sa jumelle distante, vous souhaiterez utiliser\n"
-"\"git push -u\" pour paramétrer le suivi distant en même\n"
-"temps que vous poussez."
+"Si vous comptez pousser une nouvelle branche locale qui suivra\n"
+"sa jumelle distante, vous souhaiterez utiliser \"git push -u\"\n"
+"pour paramétrer le suivi distant en même temps que vous poussez."
-#: branch.c:250
+#: branch.c:265
#, c-format
msgid "Not a valid object name: '%s'."
-msgstr "Nom d'objet invalide : '%s'"
+msgstr "Nom d'objet invalide : '%s'."
-#: branch.c:270
+#: branch.c:285
#, c-format
msgid "Ambiguous object name: '%s'."
-msgstr "Nom d'objet ambigu : '%s'"
+msgstr "Nom d'objet ambigu : '%s'."
-#: branch.c:275
+#: branch.c:290
#, c-format
msgid "Not a valid branch point: '%s'."
-msgstr "Point d'embranchement invalide : '%s'"
+msgstr "Point d'embranchement invalide : '%s'."
-#: branch.c:281
+#: branch.c:296
msgid "Failed to lock ref for update"
msgstr "Échec du verrouillage de la référence pour mise à jour"
-#: branch.c:299
+#: branch.c:314
msgid "Failed to write ref"
msgstr "Échec de l'écriture de la référence"
#: bundle.c:63
#, c-format
msgid "unrecognized header: %s%s (%d)"
-msgstr "entête non reconnu : %s %s (%d)"
+msgstr "en-tête non reconnu : %s%s (%d)"
-#: bundle.c:89 builtin/commit.c:676
+#: bundle.c:89 builtin/commit.c:697
#, c-format
msgid "could not open '%s'"
msgstr "impossible d'ouvrir '%s'"
msgid "Repository lacks these prerequisite commits:"
msgstr "Le dépôt ne dispose pas des commits prérequis :"
-#: bundle.c:164 sequencer.c:651 sequencer.c:1101 builtin/log.c:300
-#: builtin/log.c:770 builtin/log.c:1344 builtin/log.c:1570 builtin/merge.c:349
-#: builtin/shortlog.c:155
+#: bundle.c:164 sequencer.c:661 sequencer.c:1111 builtin/log.c:331
+#: builtin/log.c:801 builtin/log.c:1399 builtin/log.c:1625 builtin/merge.c:364
+#: builtin/shortlog.c:156
msgid "revision walk setup failed"
msgstr "échec de la préparation du parcours des révisions"
#: bundle.c:193
msgid "The bundle records a complete history."
-msgstr "Le bundle enregistre l'historique complet."
+msgstr "Le colis enregistre l'historique complet."
#: bundle.c:195
#, c-format
msgid "The bundle requires this ref:"
msgid_plural "The bundle requires these %d refs:"
-msgstr[0] "Le colis exige cette référence"
+msgstr[0] "Le colis exige cette référence :"
msgstr[1] "Le colis exige ces %d références :"
#: bundle.c:294
msgid "rev-list died"
msgstr "rev-list a disparu"
-#: bundle.c:300 builtin/log.c:1255 builtin/shortlog.c:258
+#: bundle.c:300 builtin/log.c:1310 builtin/shortlog.c:259
#, c-format
msgid "unrecognized argument: %s"
msgstr "argument non reconnu : %s"
#: bundle.c:335
#, c-format
msgid "ref '%s' is excluded by the rev-list options"
-msgstr "ref '%s' est exclus par les options de rev-list"
+msgstr "la référence '%s' est exclue par les options de rev-list"
#: bundle.c:380
msgid "Refusing to create empty bundle."
-msgstr "Refus de créer un bundle vide"
+msgstr "Refus de créer un colis vide."
#: bundle.c:398
msgid "Could not spawn pack-objects"
msgid "index-pack died"
msgstr "l'index de groupe a disparu"
-#: commit.c:50
+#: commit.c:53
#, c-format
msgid "could not parse %s"
msgstr "impossible d'analyser %s"
-#: commit.c:52
+#: commit.c:55
#, c-format
msgid "%s %s is not a commit!"
msgstr "%s %s n'est pas un commit !"
#: compat/obstack.c:406 compat/obstack.c:408
msgid "memory exhausted"
-msgstr "Plus de mémoire"
+msgstr "plus de mémoire"
-#: connected.c:39
+#: connected.c:60
msgid "Could not run 'git rev-list'"
-msgstr "impossible de lancer 'git rev-list'"
+msgstr "Impossible de lancer 'git rev-list'"
-#: connected.c:48
+#: connected.c:80
#, c-format
msgid "failed write to rev-list: %s"
-msgstr "impossible d'écrire la rev-list : %s"
+msgstr "impossible d'écrire dans la rev-list : %s"
-#: connected.c:56
+#: connected.c:88
#, c-format
msgid "failed to close rev-list's stdin: %s"
-msgstr "impossible de fermer le stdin du rev-list : %s"
+msgstr "impossible de fermer l'entrée standard du rev-list : %s"
#: date.c:95
msgid "in the future"
#: diff.c:112
#, c-format
msgid " Failed to parse dirstat cut-off percentage '%s'\n"
-msgstr " Impossible d'analyser le pourcentage de modification de dirstat '%s'\n"
+msgstr ""
+" Impossible d'analyser le pourcentage de modification de dirstat '%s'\n"
#: diff.c:117
#, c-format
#: diff.c:210
#, c-format
msgid "Unknown value for 'diff.submodule' config variable: '%s'"
-msgstr "Valeur inconnue pour la variable de configuration 'diff.submodule' : '%s'"
+msgstr ""
+"Valeur inconnue pour la variable de configuration 'diff.submodule' : '%s'"
#: diff.c:260
#, c-format
msgid ""
"Found errors in 'diff.dirstat' config variable:\n"
"%s"
-msgstr "Erreurs dans la variable de configuration 'diff.dirstat' :\n"
+msgstr ""
+"Erreurs dans la variable de configuration 'diff.dirstat' :\n"
"%s"
-#: diff.c:3481
+#: diff.c:3487
#, c-format
msgid ""
"Failed to parse --dirstat/-X option parameter:\n"
"%s"
-msgstr "Impossible d'analyser le paramètre de l'option --dirstat/-X :\n"
+msgstr ""
+"Impossible d'analyser le paramètre de l'option --dirstat/-X :\n"
"%s"
-#: diff.c:3495
+#: diff.c:3501
#, c-format
msgid "Failed to parse --submodule option parameter: '%s'"
msgstr "Impossible d'analyser le paramètre de l'option --submodule : '%s'"
msgid "'%s': short read %s"
msgstr "'%s' : lecture tronquée %s"
-#: help.c:212
+#: help.c:210
#, c-format
msgid "available git commands in '%s'"
msgstr "commandes git disponibles dans '%s'"
-#: help.c:219
+#: help.c:217
msgid "git commands available from elsewhere on your $PATH"
msgstr "commandes git disponibles depuis un autre endroit de votre $PATH"
-#: help.c:235
+#: help.c:233
msgid "The most commonly used git commands are:"
-msgstr "Les commandes git les plus usitées sont :"
+msgstr "Les commandes git les plus utilisées sont :"
-#: help.c:292
+#: help.c:290
#, 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' semble être une commande git, mais elle n'a pas pu être éxecutée. Peut-être git-%s est-il cassé ?"
+msgstr ""
+"'%s' semble être une commande git, mais elle n'a pas pu\n"
+"être exécutée. Peut-être git-%s est-elle cassée ?"
-#: help.c:349
+#: help.c:347
msgid "Uh oh. Your system reports no Git commands at all."
msgstr "Ahem. Votre système n'indique aucune commande Git."
-#: help.c:371
+#: help.c:369
#, 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 "ATTENTION : vous avez invoqué une commande Git nommée '%s' qui n'existe pas.\n"
-"Poursuite avec l'hypothèse que vous avez voulu dire '%s'"
+msgstr ""
+"ATTENTION : vous avez invoqué une commande Git nommée '%s' qui n'existe "
+"pas.\n"
+"Poursuite en supposant que vous avez voulu dire '%s'"
-#: help.c:376
+#: help.c:374
#, c-format
msgid "in %0.1f seconds automatically..."
-msgstr "dans %01f secondes automatiquement..."
+msgstr "dans %0.1f secondes automatiquement..."
-#: help.c:383
+#: help.c:381
#, c-format
msgid "git: '%s' is not a git command. See 'git --help'."
-msgstr "git : '%s' n'est pas une commande git. Référez-vous à 'git --help'"
+msgstr "git : '%s' n'est pas une commande git. Voir 'git --help'."
-#: help.c:387
+#: help.c:385 help.c:444
msgid ""
"\n"
"Did you mean this?"
msgid_plural ""
"\n"
"Did you mean one of these?"
-msgstr[0] "\n"
+msgstr[0] ""
+"\n"
"Vouliez-vous dire cela ?"
-msgstr[1] "\n"
-"Vouliez-vous dire un de cela ?"
+msgstr[1] ""
+"\n"
+"Vouliez-vous dire un de ceux-là ?"
+
+#: help.c:440
+#, c-format
+msgid "%s: %s - %s"
+msgstr "%s: %s - %s"
#: merge.c:56
msgid "failed to read the cache"
msgstr "impossible de lire le cache"
#: merge.c:110 builtin/checkout.c:365 builtin/checkout.c:566
-#: builtin/clone.c:645
+#: builtin/clone.c:656
msgid "unable to write new index file"
msgstr "impossible d'écrire le nouveau fichier d'index"
#: merge-recursive.c:206
#, c-format
msgid "addinfo_cache failed for path '%s'"
-msgstr "Ã\89chec de addinfo_cache pour le chemin '%s'"
+msgstr "échec de addinfo_cache pour le chemin '%s'"
-#: merge-recursive.c:268
+#: merge-recursive.c:269
msgid "error building trees"
-msgstr "Erreur à la construction des arbres"
+msgstr "erreur de construction des arbres"
-#: merge-recursive.c:672
+#: merge-recursive.c:673
#, c-format
msgid "failed to create path '%s'%s"
msgstr "impossible de créer le chemin '%s' %s"
-#: merge-recursive.c:683
+#: merge-recursive.c:684
#, c-format
msgid "Removing %s to make room for subdirectory\n"
msgstr "Suppression de %s pour faire de la place pour le sous-répertoire\n"
#. something else exists
#. .. but not some other error (who really cares what?)
-#: merge-recursive.c:697 merge-recursive.c:718
+#: merge-recursive.c:698 merge-recursive.c:719
msgid ": perhaps a D/F conflict?"
msgstr ": peut-être un conflit D/F ?"
-#: merge-recursive.c:708
+#: merge-recursive.c:709
#, c-format
msgid "refusing to lose untracked file at '%s'"
msgstr "refus de perdre le fichier non suivi '%s'"
-#: merge-recursive.c:748
+#: merge-recursive.c:749
#, c-format
msgid "cannot read object %s '%s'"
msgstr "impossible de lire l'objet %s '%s'"
-#: merge-recursive.c:750
+#: merge-recursive.c:751
#, c-format
msgid "blob expected for %s '%s'"
msgstr "blob attendu pour %s '%s'"
-#: merge-recursive.c:773 builtin/clone.c:313
+#: merge-recursive.c:774 builtin/clone.c:312
#, c-format
msgid "failed to open '%s'"
-msgstr "Ã\89chec à l'ouverture de '%s'"
+msgstr "échec à l'ouverture de '%s'"
-#: merge-recursive.c:781
+#: merge-recursive.c:782
#, c-format
msgid "failed to symlink '%s'"
-msgstr "Ã\89chec à la création du lien symbolique '%s'"
+msgstr "échec à la création du lien symbolique '%s'"
-#: merge-recursive.c:784
+#: merge-recursive.c:785
#, c-format
msgid "do not know what to do with %06o %s '%s'"
msgstr "ne sait pas traiter %06o %s '%s'"
-#: merge-recursive.c:922
+#: merge-recursive.c:923
msgid "Failed to execute internal merge"
msgstr "Échec à l'exécution de la fusion interne"
-#: merge-recursive.c:926
+#: merge-recursive.c:927
#, c-format
msgid "Unable to add %s to database"
msgstr "Impossible d'ajouter %s à la base de données"
-#: merge-recursive.c:942
+#: merge-recursive.c:943
msgid "unsupported object type in the tree"
msgstr "type d'objet non supporté dans l'arbre"
-#: merge-recursive.c:1021 merge-recursive.c:1035
+#: merge-recursive.c:1022 merge-recursive.c:1036
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
"in tree."
-msgstr "CONFLIT (%s/suppression) : %s supprimé dans %s et %s dans %s. Version %s de %s laissée dans l'arbre."
+msgstr ""
+"CONFLIT (%s/suppression) : %s supprimé dans %s et %s dans %s. Version %s de "
+"%s laissée dans l'arbre."
-#: merge-recursive.c:1027 merge-recursive.c:1040
+#: merge-recursive.c:1028 merge-recursive.c:1041
#, c-format
msgid ""
"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left "
"in tree at %s."
-msgstr "CONFLIT (%s/suppression) : %s supprimé dans %s et %s dans%s. Version %s de %s laissée dans l'arbre dans le fichier %s."
+msgstr ""
+"CONFLIT (%s/suppression) : %s supprimé dans %s et %s dans %s. Version %s de "
+"%s laissée dans l'arbre dans le fichier %s."
-#: merge-recursive.c:1081
+#: merge-recursive.c:1082
msgid "rename"
msgstr "renommage"
-#: merge-recursive.c:1081
+#: merge-recursive.c:1082
msgid "renamed"
msgstr "renommé"
-#: merge-recursive.c:1137
+#: merge-recursive.c:1138
#, c-format
msgid "%s is a directory in %s adding as %s instead"
msgstr "%s est un répertoire dans %s ajouté plutôt comme %s"
-#: merge-recursive.c:1159
+#: merge-recursive.c:1160
#, c-format
msgid ""
"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s"
"\"->\"%s\" in \"%s\"%s"
-msgstr "CONFLIT (renommage/renommage) : Renommage de '%s'->'%s' dans la branche '%s' et renommage '%s'->'%s' dans '%s'%s"
+msgstr ""
+"CONFLIT (renommage/renommage) : Renommage de \"%s\"->\"%s\" dans la branche "
+"\"%s\" et renommage \"%s\"->\"%s\" dans \"%s\"%s"
-#: merge-recursive.c:1164
+#: merge-recursive.c:1165
msgid " (left unresolved)"
msgstr " (laissé non résolu)"
-#: merge-recursive.c:1218
+#: merge-recursive.c:1219
#, c-format
msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s"
-msgstr "CONFLIT (renommage/renommage) : renommage '%s'->'%s' dans %s. Renommage '%s'->'%s' dans %s"
+msgstr ""
+"CONFLIT (renommage/renommage) : renommage '%s'->'%s' dans %s. Renommage '%s'-"
+">'%s' dans %s"
-#: merge-recursive.c:1248
+#: merge-recursive.c:1249
#, c-format
msgid "Renaming %s to %s and %s to %s instead"
-msgstr "Renommage préféré de %s en %s et de %s en %s"
+msgstr "Renommage de %s en %s et de %s en %s à la place"
-#: merge-recursive.c:1447
+#: merge-recursive.c:1448
#, c-format
msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s"
-msgstr "CONFLIT (renommage/ajout) : renommage de '%s'->'%s' dans ' %s. %s ajouté dans %s"
+msgstr ""
+"CONFLIT (renommage/ajout) : Renommage de %s->%s dans %s. %s ajouté dans %s"
-#: merge-recursive.c:1457
+#: merge-recursive.c:1458
#, c-format
msgid "Adding merged %s"
msgstr "Ajout de %s fusionné"
-#: merge-recursive.c:1462 merge-recursive.c:1660
+#: merge-recursive.c:1463 merge-recursive.c:1661
#, c-format
msgid "Adding as %s instead"
msgstr "Ajout plutôt comme %s"
-#: merge-recursive.c:1513
+#: merge-recursive.c:1514
#, c-format
msgid "cannot read object %s"
msgstr "impossible de lire l'objet %s"
-#: merge-recursive.c:1516
+#: merge-recursive.c:1517
#, c-format
msgid "object %s is not a blob"
msgstr "l'objet %s n'est pas un blob"
-#: merge-recursive.c:1564
+#: merge-recursive.c:1565
msgid "modify"
msgstr "modification"
-#: merge-recursive.c:1564
+#: merge-recursive.c:1565
msgid "modified"
msgstr "modifié"
-#: merge-recursive.c:1574
+#: merge-recursive.c:1575
msgid "content"
msgstr "contenu"
-#: merge-recursive.c:1581
+#: merge-recursive.c:1582
msgid "add/add"
msgstr "ajout/ajout"
-#: merge-recursive.c:1615
+#: merge-recursive.c:1616
#, c-format
msgid "Skipped %s (merged same as existing)"
-msgstr "%s ignoré (fusion identique à l'existant)"
+msgstr "%s sauté (fusion identique à l'existant)"
-#: merge-recursive.c:1629
+#: merge-recursive.c:1630
#, c-format
msgid "Auto-merging %s"
-msgstr "fusion automatique de %s"
+msgstr "Fusion automatique de %s"
-#: merge-recursive.c:1633 git-submodule.sh:1029
+#: merge-recursive.c:1634 git-submodule.sh:1118
msgid "submodule"
msgstr "sous-module"
-#: merge-recursive.c:1634
+#: merge-recursive.c:1635
#, c-format
msgid "CONFLICT (%s): Merge conflict in %s"
-msgstr "CONFLIT (%s) : conflit de fusion dans %s"
+msgstr "CONFLIT (%s) : Conflit de fusion dans %s"
-#: merge-recursive.c:1724
+#: merge-recursive.c:1725
#, c-format
msgid "Removing %s"
msgstr "Suppression de %s"
-#: merge-recursive.c:1749
+#: merge-recursive.c:1750
msgid "file/directory"
msgstr "fichier/répertoire"
-#: merge-recursive.c:1755
+#: merge-recursive.c:1756
msgid "directory/file"
msgstr "répertoire/fichier"
-#: merge-recursive.c:1760
+#: merge-recursive.c:1761
#, c-format
msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s"
-msgstr "CONFLIT (%s) : Il y a un répertoire nommé %s dans %s. Ajout de %s comme %s"
+msgstr ""
+"CONFLIT (%s) : Il y a un répertoire nommé %s dans %s. Ajout de %s comme %s"
-#: merge-recursive.c:1770
+#: merge-recursive.c:1771
#, c-format
msgid "Adding %s"
msgstr "Ajout de %s"
-#: merge-recursive.c:1787
+#: merge-recursive.c:1788
msgid "Fatal merge failure, shouldn't happen."
msgstr "Échec fatal de fusion, qui ne devrait jamais arriver."
-#: merge-recursive.c:1806
+#: merge-recursive.c:1807
msgid "Already up-to-date!"
msgstr "Déjà à jour !"
-#: merge-recursive.c:1815
+#: merge-recursive.c:1816
#, c-format
msgid "merging of trees %s and %s failed"
-msgstr "Ã\89chec de fusion des arbres %s et %s"
+msgstr "échec de fusion des arbres %s et %s"
-#: merge-recursive.c:1845
+#: merge-recursive.c:1846
#, c-format
msgid "Unprocessed path??? %s"
msgstr "Chemin non traité ??? %s"
-#: merge-recursive.c:1890
+#: merge-recursive.c:1891
msgid "Merging:"
msgstr "Fusion :"
-#: merge-recursive.c:1903
+#: merge-recursive.c:1904
#, c-format
msgid "found %u common ancestor:"
msgid_plural "found %u common ancestors:"
msgstr[0] "%u ancêtre commun trouvé :"
msgstr[1] "%u ancêtres communs trouvés :"
-#: merge-recursive.c:1940
+#: merge-recursive.c:1941
msgid "merge returned no commit"
msgstr "la fusion n'a pas retourné de commit"
-#: merge-recursive.c:1997
+#: merge-recursive.c:1998
#, c-format
msgid "Could not parse object '%s'"
msgstr "Impossible d'analyser l'objet '%s'"
-#: merge-recursive.c:2009 builtin/merge.c:658
+#: merge-recursive.c:2010 builtin/merge.c:672
msgid "Unable to write index."
msgstr "Impossible d'écrire l'index."
-#: object.c:195
+#: notes-utils.c:40
+msgid "Cannot commit uninitialized/unreferenced notes tree"
+msgstr "Impossible de valider un arbre de notes non initialisé/référencé"
+
+#: notes-utils.c:81
+#, c-format
+msgid "Bad notes.rewriteMode value: '%s'"
+msgstr "Mauvaise valeur de notes.rewriteMode : '%s'"
+
+#: notes-utils.c:91
+#, c-format
+msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
+msgstr "Refus de réécrire des notes dans %s (hors de refs/notes/)"
+
+#. TRANSLATORS: The first %s is the name of the
+#. environment variable, the second %s is its value
+#: notes-utils.c:118
+#, c-format
+msgid "Bad %s value: '%s'"
+msgstr "Mauvaise valeur de %s : '%s'"
+
+#: object.c:204
#, c-format
msgid "unable to parse object: %s"
-msgstr "Impossible d'analyser l'objet '%s'"
+msgstr "impossible d'analyser l'objet : %s"
#: parse-options.c:489
msgid "..."
msgid "'%s' is beyond a symbolic link"
msgstr "'%s' est au delà d'un lien symbolique"
-#: remote.c:1781
+#: remote.c:1788
#, 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] "Votre branche est en avance sur '%s' par %d commit.\n"
-msgstr[1] "Votre branche est en avance sur '%s' par %d commits.\n"
+msgstr[0] "Votre branche est en avance sur '%s' de %d commit.\n"
+msgstr[1] "Votre branche est en avance sur '%s' de %d commits.\n"
-#: remote.c:1787
+#: remote.c:1794
msgid " (use \"git push\" to publish your local commits)\n"
-msgstr " (utilisez 'git push' pour publier vos commits locaux)\n"
+msgstr " (utilisez \"git push\" pour publier vos commits locaux)\n"
-#: remote.c:1790
+#: remote.c:1797
#, 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] "Votre branche est en retard sur '%s' par %d commit, et peut être mise à jour en avance rapide.\n"
-msgstr[1] "Votre branche est en retard sur '%s' par %d commits, et peut être mise à jour en avance rapide.\n"
+msgstr[0] ""
+"Votre branche est en retard sur '%s' de %d commit, et peut être mise à jour "
+"en avance rapide.\n"
+msgstr[1] ""
+"Votre branche est en retard sur '%s' de %d commits, et peut être mise à jour "
+"en avance rapide.\n"
-#: remote.c:1798
+#: remote.c:1805
msgid " (use \"git pull\" to update your local branch)\n"
-msgstr " ( utilisez 'git pull' pour mettre à jour votre branche locale)\n"
+msgstr " (utilisez \"git pull\" pour mettre à jour votre branche locale)\n"
-#: remote.c:1801
+#: remote.c:1808
#, c-format
msgid ""
"Your branch and '%s' have diverged,\n"
msgid_plural ""
"Your branch and '%s' have diverged,\n"
"and have %d and %d different commits each, respectively.\n"
-msgstr[0] "Votre branche et '%s' ont divergé,\n"
+msgstr[0] ""
+"Votre branche et '%s' ont divergé,\n"
"et ont %d et %d commit différent chacune respectivement.\n"
-msgstr[1] "Votre branche et '%s' ont divergé,\n"
+msgstr[1] ""
+"Votre branche et '%s' ont divergé,\n"
"et ont %d et %d commits différents chacune respectivement.\n"
-#: remote.c:1811
+#: remote.c:1818
msgid " (use \"git pull\" to merge the remote branch into yours)\n"
-msgstr " (utilisez \"git pull\" pour fusionner la branche distante dans la vôtre)\n"
+msgstr ""
+" (utilisez \"git pull\" pour fusionner la branche distante dans la vôtre)\n"
+
+#: run-command.c:80
+msgid "open /dev/null failed"
+msgstr "échec de l'ouverture de /dev/null"
-#: sequencer.c:206 builtin/merge.c:776 builtin/merge.c:889 builtin/merge.c:999
-#: builtin/merge.c:1009
+#: run-command.c:82
+#, c-format
+msgid "dup2(%d,%d) failed"
+msgstr "échec de dup2(%d,%d)"
+
+#: sequencer.c:206 builtin/merge.c:790 builtin/merge.c:903
+#: builtin/merge.c:1013 builtin/merge.c:1023
#, c-format
msgid "Could not open '%s' for writing"
msgstr "Impossible d'ouvrir '%s' en écriture"
-#: sequencer.c:208 builtin/merge.c:335 builtin/merge.c:779
-#: builtin/merge.c:1001 builtin/merge.c:1014
+#: sequencer.c:208 builtin/merge.c:350 builtin/merge.c:793
+#: builtin/merge.c:1015 builtin/merge.c:1028
#, c-format
msgid "Could not write to '%s'"
msgstr "Impossible d'écrire dans '%s'"
msgid ""
"after resolving the conflicts, mark the corrected paths\n"
"with 'git add <paths>' or 'git rm <paths>'"
-msgstr "après résolution des conflits, marquez les chemins corrigés\n"
+msgstr ""
+"après résolution des conflits, marquez les chemins corrigés\n"
"avec 'git add <chemins>' ou 'git rm <chemins>'"
#: sequencer.c:232
"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 "après résolution des conflits, marquez les chemins corrigés\n"
+msgstr ""
+"après résolution des conflits, marquez les chemins corrigés\n"
"avec 'git add <chemins>' ou 'git rm <chemins>'\n"
"puis validez le résultat avec 'git commit'"
-#: sequencer.c:245 sequencer.c:859 sequencer.c:942
+#: sequencer.c:245 sequencer.c:869 sequencer.c:952
#, c-format
msgid "Could not write to %s"
msgstr "Impossible d'écrire dans %s"
#: sequencer.c:263
msgid "Your local changes would be overwritten by cherry-pick."
-msgstr "Vos modifications locales serait écrasées par cherry-pick."
+msgstr "Vos modifications locales seraient écrasées par cherry-pick."
#: sequencer.c:265
msgid "Your local changes would be overwritten by revert."
msgstr "Validez vos modifications ou remisez-les pour continuer."
#. TRANSLATORS: %s will be "revert" or "cherry-pick"
-#: sequencer.c:319
+#: sequencer.c:324
#, c-format
msgid "%s: Unable to write new index file"
-msgstr "%s: impossiblde d'écrire le nouveau fichier index"
+msgstr "%s: Impossible d'écrire le nouveau fichier index"
-#: sequencer.c:350
+#: sequencer.c:355
msgid "Could not resolve HEAD commit\n"
msgstr "Impossible de résoudre le commit HEAD\n"
-#: sequencer.c:371
+#: sequencer.c:377
msgid "Unable to update cache tree\n"
msgstr "Impossible de mettre à jour l'arbre de cache\n"
-#: sequencer.c:416
+#: sequencer.c:422
#, c-format
msgid "Could not parse commit %s\n"
msgstr "Impossible d'analyser le commit %s\n"
-#: sequencer.c:421
+#: sequencer.c:427
#, c-format
msgid "Could not parse parent commit %s\n"
msgstr "Impossible d'analyser le commit parent %s\n"
-#: sequencer.c:487
+#: sequencer.c:493
msgid "Your index file is unmerged."
msgstr "Votre fichier d'index n'est pas fusionné."
-#: sequencer.c:506
+#: sequencer.c:512
#, c-format
msgid "Commit %s is a merge but no -m option was given."
msgstr "Le commit %s est une fusion mais l'option -m n'a pas été spécifiée."
-#: sequencer.c:514
+#: sequencer.c:520
#, c-format
msgid "Commit %s does not have parent %d"
-msgstr "Le commit %s n'a pas %d pour parent"
+msgstr "Le commit %s n'a pas le parent %d"
-#: sequencer.c:518
+#: sequencer.c:524
#, c-format
msgid "Mainline was specified but commit %s is not a merge."
-msgstr "Une branche principale a été spécifiée mais le commit %s n'est pas une fusion."
+msgstr ""
+"Une branche principale a été spécifiée mais le commit %s n'est pas une "
+"fusion."
#. TRANSLATORS: The first %s will be "revert" or
#. "cherry-pick", the second %s a SHA1
-#: sequencer.c:531
+#: sequencer.c:537
#, c-format
msgid "%s: cannot parse parent commit %s"
msgstr "%s : impossible d'analyser le commit parent %s"
-#: sequencer.c:535
+#: sequencer.c:541
#, c-format
msgid "Cannot get commit message for %s"
msgstr "Impossible d'obtenir un message de validation pour %s"
-#: sequencer.c:621
+#: sequencer.c:627
#, c-format
msgid "could not revert %s... %s"
msgstr "impossible d'annuler %s... %s"
-#: sequencer.c:622
+#: sequencer.c:628
#, c-format
msgid "could not apply %s... %s"
msgstr "impossible d'appliquer %s... %s"
-#: sequencer.c:654
+#: sequencer.c:664
msgid "empty commit set passed"
-msgstr "l'ensemble de commits spéficifié est vide"
+msgstr "l'ensemble de commits spécifié est vide"
-#: sequencer.c:662
+#: sequencer.c:672
#, c-format
msgid "git %s: failed to read the index"
msgstr "git %s : échec à la lecture de l'index"
-#: sequencer.c:667
+#: sequencer.c:677
#, c-format
msgid "git %s: failed to refresh the index"
-msgstr "git %s : échec du raffraîchissement de l'index"
+msgstr "git %s : échec du rafraîchissement de l'index"
-#: sequencer.c:725
+#: sequencer.c:735
#, c-format
msgid "Cannot %s during a %s"
msgstr "Impossible de %s pendant un %s"
-#: sequencer.c:747
+#: sequencer.c:757
#, c-format
msgid "Could not parse line %d."
msgstr "Impossible d'analyser la ligne %d."
-#: sequencer.c:752
+#: sequencer.c:762
msgid "No commits parsed."
msgstr "Aucun commit analysé."
-#: sequencer.c:765
+#: sequencer.c:775
#, c-format
msgid "Could not open %s"
msgstr "Impossible d'ouvrir %s"
-#: sequencer.c:769
+#: sequencer.c:779
#, c-format
msgid "Could not read %s."
msgstr "Impossible de lire %s."
-#: sequencer.c:776
+#: sequencer.c:786
#, c-format
msgid "Unusable instruction sheet: %s"
msgstr "Feuille d'instruction inutilisable : %s"
-#: sequencer.c:804
+#: sequencer.c:814
#, c-format
msgid "Invalid key: %s"
msgstr "Clé invalide: %s"
-#: sequencer.c:807
+#: sequencer.c:817
#, c-format
msgid "Invalid value for %s: %s"
msgstr "Valeur invalide pour %s : %s"
-#: sequencer.c:819
+#: sequencer.c:829
#, c-format
msgid "Malformed options sheet: %s"
msgstr "Feuille d'options malformée : %s"
-#: sequencer.c:840
+#: sequencer.c:850
msgid "a cherry-pick or revert is already in progress"
-msgstr "Un picorage ou un retour est déjà en cours"
+msgstr "un picorage ou un retour est déjà en cours"
-#: sequencer.c:841
+#: sequencer.c:851
msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
msgstr "essayez \"git cherry-pick (--continue|--quit|-- abort)\""
-#: sequencer.c:845
+#: sequencer.c:855
#, c-format
msgid "Could not create sequencer directory %s"
msgstr "Impossible de créer le répertoire de séquenceur %s"
-#: sequencer.c:861 sequencer.c:946
+#: sequencer.c:871 sequencer.c:956
#, c-format
msgid "Error wrapping up %s."
msgstr "Erreur lors de l'emballage de %s."
-#: sequencer.c:880 sequencer.c:1014
+#: sequencer.c:890 sequencer.c:1024
msgid "no cherry-pick or revert in progress"
msgstr "aucun picorage ou retour en cours"
-#: sequencer.c:882
+#: sequencer.c:892
msgid "cannot resolve HEAD"
msgstr "impossible de résoudre HEAD"
-#: sequencer.c:884
+#: sequencer.c:894
msgid "cannot abort from a branch yet to be born"
msgstr "impossible d'abandonner depuis une branche non encore créée"
-#: sequencer.c:906 builtin/apply.c:4060
+#: sequencer.c:916 builtin/apply.c:4061
#, c-format
msgid "cannot open %s: %s"
msgstr "impossible d'ouvrir %s : %s"
-#: sequencer.c:909
+#: sequencer.c:919
#, c-format
msgid "cannot read %s: %s"
msgstr "impossible de lire %s : %s"
-#: sequencer.c:910
+#: sequencer.c:920
msgid "unexpected end of file"
msgstr "fin de fichier inattendue"
-#: sequencer.c:916
+#: sequencer.c:926
#, c-format
msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
-msgstr "Le fichier HEAD de préparation de picorage '%s' est corrompu"
+msgstr "le fichier HEAD de préparation de picorage '%s' est corrompu"
-#: sequencer.c:939
+#: sequencer.c:949
#, c-format
msgid "Could not format %s."
msgstr "Impossible de formater %s."
-#: sequencer.c:1083
+#: sequencer.c:1092
#, c-format
msgid "%s: can't cherry-pick a %s"
msgstr "%s : impossible de picorer un %s"
-#: sequencer.c:1085
+#: sequencer.c:1095
#, c-format
msgid "%s: bad revision"
-msgstr "%s: mauvaise révision"
+msgstr "%s : mauvaise révision"
-#: sequencer.c:1119
+#: sequencer.c:1129
msgid "Can't revert as initial commit"
msgstr "Impossible d'annuler en tant que commit initial"
-#: sequencer.c:1120
+#: sequencer.c:1130
msgid "Can't cherry-pick into empty head"
-msgstr "Impossible de picorer vers un HEAD vide"
+msgstr "Impossible de picorer vers une HEAD vide"
+
+#: sha1_name.c:440
+msgid ""
+"Git normally never creates a ref that ends with 40 hex characters\n"
+"because it will be ignored when you just specify 40-hex. These refs\n"
+"may be created by mistake. For example,\n"
+"\n"
+" git checkout -b $br $(git rev-parse ...)\n"
+"\n"
+"where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
+"examine these refs and maybe delete them. Turn this message off by\n"
+"running \"git config advice.objectNameWarning false\""
+msgstr ""
+"Git ne créé normalement jamais de référence qui se termine par 40 caractères "
+"hexa\n"
+"car elle serait ignorée si vous spécifiiez 40-hexa. Ces références\n"
+"peuvent être créées par erreur. Par exemple,\n"
+"\n"
+" git checkout -b $br $(git rev-parse ...)\n"
+"\n"
+"où \"$br\" est d'une manière ou d'une autre vide et une référence 40-hexa "
+"est créée.\n"
+"Veuillez examiner ces références et peut-être les supprimer. Désactivez ce "
+"message\n"
+"en lançant \"git config advice.objectNameWarning false\""
-#: sha1_name.c:1036
+#: sha1_name.c:1097
msgid "HEAD does not point to a branch"
msgstr "HEAD ne pointe pas sur une branche"
-#: sha1_name.c:1039
+#: sha1_name.c:1100
#, c-format
msgid "No such branch: '%s'"
msgstr "Branche inconnue : '%s'"
-#: sha1_name.c:1041
+#: sha1_name.c:1102
#, c-format
msgid "No upstream configured for branch '%s'"
msgstr "Aucune branche amont configurée pour la branche '%s'"
-#: sha1_name.c:1044
+#: sha1_name.c:1106
#, c-format
msgid "Upstream branch '%s' not stored as a remote-tracking branch"
msgstr "La branche amont '%s' n'est pas stockée comme branche de suivi"
msgid "unable to access '%s': %s"
msgstr "impossible d'accéder à '%s' : %s"
-#: wrapper.c:423
+#: wrapper.c:429
#, c-format
msgid "unable to access '%s'"
msgstr "impossible d'accéder à '%s'"
-#: wrapper.c:434
+#: wrapper.c:440
#, c-format
msgid "unable to look up current user in the passwd file: %s"
-msgstr "impossible de rechercher l'utilisateur actuel dans le fichier de mots de passe : %s"
+msgstr ""
+"impossible de rechercher l'utilisateur actuel dans le fichier de mots de "
+"passe : %s"
-#: wrapper.c:435
+#: wrapper.c:441
msgid "no such user"
msgstr "utilisateur inconnu"
-#: wt-status.c:140
+#: wt-status.c:141
msgid "Unmerged paths:"
msgstr "Chemins non fusionnés :"
-#: wt-status.c:167 wt-status.c:194
+#: wt-status.c:168 wt-status.c:195
#, c-format
msgid " (use \"git reset %s <file>...\" to unstage)"
msgstr " (utilisez \"git reset %s <fichier>...\" pour désindexer)"
-#: wt-status.c:169 wt-status.c:196
+#: wt-status.c:170 wt-status.c:197
msgid " (use \"git rm --cached <file>...\" to unstage)"
msgstr " (utilisez \"git rm --cached <fichier>...\" pour désindexer)"
-#: wt-status.c:173
+#: wt-status.c:174
msgid " (use \"git add <file>...\" to mark resolution)"
-msgstr " (utilisez \"git add <fichier>...\" pour marquer résolu)"
+msgstr " (utilisez \"git add <fichier>...\" pour marquer comme résolu)"
-#: wt-status.c:175 wt-status.c:179
+#: wt-status.c:176 wt-status.c:180
msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)"
-msgstr " (utilisez \"git add/rm <fichier>...\" selon le cas pour marquer résolu)"
+msgstr ""
+" (utilisez \"git add/rm <fichier>...\" si nécessaire pour marquer comme "
+"résolu)"
-#: wt-status.c:177
+#: wt-status.c:178
msgid " (use \"git rm <file>...\" to mark resolution)"
-msgstr " (utilisez \"git rm <fichier>...\" pour marquer résolu)"
+msgstr " (utilisez \"git rm <fichier>...\" pour marquer comme résolu)"
-#: wt-status.c:188
+#: wt-status.c:189
msgid "Changes to be committed:"
msgstr "Modifications qui seront validées :"
-#: wt-status.c:206
+#: wt-status.c:207
msgid "Changes not staged for commit:"
msgstr "Modifications qui ne seront pas validées :"
-#: wt-status.c:210
+#: wt-status.c:211
msgid " (use \"git add <file>...\" to update what will be committed)"
-msgstr " (utilisez \"git add <fichier>...\" pour mettre à jour ce qui sera validé)"
+msgstr ""
+" (utilisez \"git add <fichier>...\" pour mettre à jour ce qui sera validé)"
-#: wt-status.c:212
+#: wt-status.c:213
msgid " (use \"git add/rm <file>...\" to update what will be committed)"
-msgstr " (utilisez \"git add/rm <fichier>...\" pour mettre à jour ce qui sera validé)"
+msgstr ""
+" (utilisez \"git add/rm <fichier>...\" pour mettre à jour ce qui sera "
+"validé)"
-#: wt-status.c:213
+#: wt-status.c:214
msgid ""
" (use \"git checkout -- <file>...\" to discard changes in working directory)"
-msgstr " (utilisez \"git checkout -- <fichier>...\" pour annuler les modifications dans la copie de travail)"
+msgstr ""
+" (utilisez \"git checkout -- <fichier>...\" pour annuler les modifications "
+"dans la copie de travail)"
-#: wt-status.c:215
+#: wt-status.c:216
msgid " (commit or discard the untracked or modified content in submodules)"
-msgstr " (valider out annuler le contenu non suivi our modifié dans les sous-modules)"
+msgstr ""
+" (valider ou annuler le contenu non suivi ou modifié dans les sous-modules)"
-#: wt-status.c:227
+#: wt-status.c:228
#, c-format
msgid " (use \"git %s <file>...\" to include in what will be committed)"
-msgstr " (utilisez \"git %s <fichier>...\" pour inclure dans ce qui sera validé)"
+msgstr ""
+" (utilisez \"git %s <fichier>...\" pour inclure dans ce qui sera validé)"
-#: wt-status.c:244
+#: wt-status.c:245
msgid "bug"
msgstr "bogue"
-#: wt-status.c:249
+#: wt-status.c:250
msgid "both deleted:"
-msgstr "effacé des deux côtés :"
+msgstr "supprimé des deux côtés :"
-#: wt-status.c:250
+#: wt-status.c:251
msgid "added by us:"
msgstr "ajouté par nous :"
-#: wt-status.c:251
+#: wt-status.c:252
msgid "deleted by them:"
-msgstr "effacé par eux :"
+msgstr "supprimé par eux :"
-#: wt-status.c:252
+#: wt-status.c:253
msgid "added by them:"
msgstr "ajouté par eux :"
-#: wt-status.c:253
+#: wt-status.c:254
msgid "deleted by us:"
-msgstr "effacé par nous :"
+msgstr "supprimé par nous :"
-#: wt-status.c:254
+#: wt-status.c:255
msgid "both added:"
-msgstr "Ajouté de deux côtés :"
+msgstr "ajouté de deux côtés :"
-#: wt-status.c:255
+#: wt-status.c:256
msgid "both modified:"
msgstr "modifié des deux côtés :"
-#: wt-status.c:285
+#: wt-status.c:286
msgid "new commits, "
msgstr "nouveaux commits, "
-#: wt-status.c:287
+#: wt-status.c:288
msgid "modified content, "
msgstr "contenu modifié, "
-#: wt-status.c:289
+#: wt-status.c:290
msgid "untracked content, "
msgstr "contenu non suivi, "
-#: wt-status.c:306
+#: wt-status.c:307
#, c-format
msgid "new file: %s"
-msgstr "nouveau : %s"
+msgstr "nouveau : %s"
-#: wt-status.c:309
+#: wt-status.c:310
#, c-format
msgid "copied: %s -> %s"
-msgstr "copié : %s->%s"
+msgstr "copié : %s -> %s"
-#: wt-status.c:312
+#: wt-status.c:313
#, c-format
msgid "deleted: %s"
-msgstr "effacé : %s"
+msgstr "supprimé : %s"
-#: wt-status.c:315
+#: wt-status.c:316
#, c-format
msgid "modified: %s"
-msgstr "modifié : %s"
+msgstr "modifié : %s"
-#: wt-status.c:318
+#: wt-status.c:319
#, c-format
msgid "renamed: %s -> %s"
-msgstr "renommé : %s -> %s"
+msgstr "renommé : %s -> %s"
-#: wt-status.c:321
+#: wt-status.c:322
#, c-format
msgid "typechange: %s"
-msgstr "nv type : %s"
+msgstr "nv type : %s"
-#: wt-status.c:324
+#: wt-status.c:325
#, c-format
msgid "unknown: %s"
-msgstr "inconnu : %s"
+msgstr "inconnu : %s"
-#: wt-status.c:327
+#: wt-status.c:328
#, c-format
msgid "unmerged: %s"
-msgstr "non fus : %s"
+msgstr "non fus. : %s"
-#: wt-status.c:330
+#: wt-status.c:331
#, c-format
msgid "bug: unhandled diff status %c"
msgstr "bogue : état de diff non géré %c"
msgid "You have unmerged paths."
msgstr "Vous avez des chemins non fusionnés."
-#: wt-status.c:806 wt-status.c:958
+#: wt-status.c:806
msgid " (fix conflicts and run \"git commit\")"
-msgstr " (réglez les conflits et lancez \"git commit\")"
+msgstr " (réglez les conflits puis lancez \"git commit\")"
#: wt-status.c:809
msgid "All conflicts fixed but you are still merging."
msgstr "Le patch actuel est vide."
#: wt-status.c:829
-msgid " (fix conflicts and then run \"git am --resolved\")"
-msgstr " (réglez les conflits puis lancez \"git am --resolved\")"
+msgid " (fix conflicts and then run \"git am --continue\")"
+msgstr " (réglez les conflits puis lancez \"git am --continue\")"
#: wt-status.c:831
msgid " (use \"git am --skip\" to skip this patch)"
#: wt-status.c:833
msgid " (use \"git am --abort\" to restore the original branch)"
-msgstr " (utilisez \"git am --abort\" pour restaurer la branche originelle)"
+msgstr " (utilisez \"git am --abort\" pour restaurer la branche d'origine)"
#: wt-status.c:893 wt-status.c:910
#, c-format
#: wt-status.c:901
msgid " (fix conflicts and then run \"git rebase --continue\")"
-msgstr " (résolvez les conflits puis lancez \"git rebase --continue\")"
+msgstr " (réglez les conflits puis lancez \"git rebase --continue\")"
#: wt-status.c:903
msgid " (use \"git rebase --skip\" to skip this patch)"
#: wt-status.c:918
msgid " (all conflicts fixed: run \"git rebase --continue\")"
-msgstr " (tous les conflits sont résolus : lancez \"git rebase --continue\")"
+msgstr " (tous les conflits sont réglés : lancez \"git rebase --continue\")"
#: wt-status.c:922
#, c-format
msgid ""
"You are currently splitting a commit while rebasing branch '%s' on '%s'."
-msgstr "Vous êtes actuellement en train de fractionner un commit pendant un rebasage de la branche '%s' sur '%s'."
+msgstr ""
+"Vous êtes actuellement en train de fractionner un commit pendant un rebasage "
+"de la branche '%s' sur '%s'."
#: wt-status.c:927
msgid "You are currently splitting a commit during a rebase."
-msgstr "Vous êtes actuellement en train de fractionner un commit pendant un rebasage."
+msgstr ""
+"Vous êtes actuellement en train de fractionner un commit pendant un rebasage."
#: wt-status.c:930
msgid " (Once your working directory is clean, run \"git rebase --continue\")"
-msgstr " (Une fois la copie de travail nettoyée, lancez \"git rebase --continue\")"
+msgstr ""
+" (Une fois la copie de travail nettoyée, lancez \"git rebase --continue\")"
#: wt-status.c:934
#, c-format
msgid "You are currently editing a commit while rebasing branch '%s' on '%s'."
-msgstr "Vous êtes actuellement en train d'éditer un commit pendant un rebasage de la branche '%s' sur '%s'."
+msgstr ""
+"Vous êtes actuellement en train d'éditer un commit pendant un rebasage de la "
+"branche '%s' sur '%s'."
#: wt-status.c:939
msgid "You are currently editing a commit during a rebase."
-msgstr "Vous êtes actuellement en train d'éditer un commit pendant un rebasage."
+msgstr ""
+"Vous êtes actuellement en train d'éditer un commit pendant un rebasage."
#: wt-status.c:942
msgid " (use \"git commit --amend\" to amend the current commit)"
#: wt-status.c:944
msgid ""
" (use \"git rebase --continue\" once you are satisfied with your changes)"
-msgstr " (utilisez \"git rebase --continue\" quand vous êtes satisfait de vos modifications)"
+msgstr ""
+" (utilisez \"git rebase --continue\" quand vous êtes satisfait de vos "
+"modifications)"
#: wt-status.c:954
msgid "You are currently cherry-picking."
msgstr "Vous êtes actuellement en train de picorer."
+#: wt-status.c:958
+msgid " (fix conflicts and run \"git cherry-pick --continue\")"
+msgstr " (réglez les conflits puis lancez \"git cherry-pick --continue\")"
+
#: wt-status.c:961
-msgid " (all conflicts fixed: run \"git commit\")"
-msgstr " (tous les conflits sont résolus : lancez \"git commit\")"
+msgid " (all conflicts fixed: run \"git cherry-pick --continue\")"
+msgstr ""
+" (tous les conflits sont réglés : lancez \"git cherry-pick --continue\")"
-#: wt-status.c:970
+#: wt-status.c:963
+msgid " (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)"
+msgstr " (utilisez \"git cherry-pick --abort\" pour annuler le picorage)"
+
+#: wt-status.c:972
#, c-format
msgid "You are currently reverting commit %s."
-msgstr "Vous êtes actuellement en train de rétablir un commit %s."
+msgstr "Vous êtes actuellement en train de rétablir le commit %s."
-#: wt-status.c:975
+#: wt-status.c:977
msgid " (fix conflicts and run \"git revert --continue\")"
-msgstr " (résolvez les conflits et lancez \"git revert --continue\")"
+msgstr " (réglez les conflits puis lancez \"git revert --continue\")"
-#: wt-status.c:978
+#: wt-status.c:980
msgid " (all conflicts fixed: run \"git revert --continue\")"
-msgstr " (tous les conflits sont résolus : lancez \"git revert --continue\")"
+msgstr " (tous les conflits sont réglés : lancez \"git revert --continue\")"
-#: wt-status.c:980
+#: wt-status.c:982
msgid " (use \"git revert --abort\" to cancel the revert operation)"
msgstr " (utilisez \"git revert --abort\" pour annuler le rétablissement)"
-#: wt-status.c:991
+#: wt-status.c:993
#, c-format
msgid "You are currently bisecting, started from branch '%s'."
msgstr "Vous êtes en cours de bissection, depuis la branche '%s'."
-#: wt-status.c:995
+#: wt-status.c:997
msgid "You are currently bisecting."
msgstr "Vous êtes en cours de bissection."
-#: wt-status.c:998
+#: wt-status.c:1000
msgid " (use \"git bisect reset\" to get back to the original branch)"
-msgstr " (utilisez \"git bisect reset\" pour revenir à la branche de départ)"
+msgstr " (utilisez \"git bisect reset\" pour revenir à la branche d'origine)"
#: wt-status.c:1173
msgid "On branch "
msgstr "Sur la branche "
-#: wt-status.c:1184
+#: wt-status.c:1180
+msgid "rebase in progress; onto "
+msgstr "rebasage en cours ; sur "
+
+#: wt-status.c:1187
msgid "HEAD detached at "
-msgstr "HEAD détaché sur "
+msgstr "HEAD détachée sur "
-#: wt-status.c:1186
+#: wt-status.c:1189
msgid "HEAD detached from "
-msgstr "HEAD détaché depuis "
+msgstr "HEAD détachée depuis "
-#: wt-status.c:1189
+#: wt-status.c:1192
msgid "Not currently on any branch."
msgstr "Actuellement sur aucun branche."
-#: wt-status.c:1206
+#: wt-status.c:1209
msgid "Initial commit"
-msgstr "Validation initiale."
+msgstr "Validation initiale"
-#: wt-status.c:1220
+#: wt-status.c:1223
msgid "Untracked files"
msgstr "Fichiers non suivis"
-#: wt-status.c:1222
+#: wt-status.c:1225
msgid "Ignored files"
msgstr "Fichiers ignorés"
-#: wt-status.c:1226
+#: wt-status.c:1229
#, c-format
msgid ""
"It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
"may speed it up, but you have to be careful not to forget to add\n"
"new files yourself (see 'git help status')."
-msgstr "L'énumération des fichiers non suivis a duré %.2f secondes. 'status -uno'\n"
-"peut l'accélerer, mais vous devez alors faire attention à ne pas\n"
-"oublier d'ajouter les nouveaux fichiers par vous-même (voir 'git help status')."
+msgstr ""
+"L'énumération des fichiers non suivis a duré %.2f secondes. 'status -uno'\n"
+"peut l'accélérer, mais vous devez alors faire attention à ne pas\n"
+"oublier d'ajouter les nouveaux fichiers par vous-même (voir 'git help "
+"status')."
-#: wt-status.c:1232
+#: wt-status.c:1235
#, c-format
msgid "Untracked files not listed%s"
-msgstr "Les fichiers non suivis ne sont pas listés %s"
+msgstr "Fichiers non suivis non affichés%s"
-#: wt-status.c:1234
+#: wt-status.c:1237
msgid " (use -u option to show untracked files)"
msgstr " (utilisez -u pour afficher les fichiers non suivis)"
-#: wt-status.c:1240
+#: wt-status.c:1243
msgid "No changes"
msgstr "Aucune modification"
-#: wt-status.c:1245
+#: wt-status.c:1248
#, c-format
msgid "no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"
-msgstr "aucune modification n'a été ajoutée au commit (utilisez \"git add\" ou \"git commit -a\")\n"
+msgstr ""
+"aucune modification n'a été ajoutée à la validation (utilisez \"git add\" ou "
+"\"git commit -a\")\n"
-#: wt-status.c:1248
+#: wt-status.c:1251
#, c-format
msgid "no changes added to commit\n"
-msgstr "aucune modification indexée\n"
+msgstr "aucune modification ajoutée à la validation\n"
-#: wt-status.c:1251
+#: wt-status.c:1254
#, c-format
msgid ""
"nothing added to commit but untracked files present (use \"git add\" to "
"track)\n"
-msgstr "Aucune modification indexée mais des fichiers non suivis sont présents (utilisez \"git add\" pour les suivre)\n"
+msgstr ""
+"aucune modification ajoutée à la validation mais des fichiers non suivis "
+"sont présents (utilisez \"git add\" pour les suivre)\n"
-#: wt-status.c:1254
+#: wt-status.c:1257
#, c-format
msgid "nothing added to commit but untracked files present\n"
-msgstr "Aucune modification indexée mais des fichiers non-suivis sont présents\n"
+msgstr ""
+"aucune modification ajoutée à la validation mais des fichiers non suivis "
+"sont présents\n"
-#: wt-status.c:1257
+#: wt-status.c:1260
#, c-format
msgid "nothing to commit (create/copy files and use \"git add\" to track)\n"
-msgstr "rien à valider (créez/copiez des fichiers et utilisez \"git add\" pour le suivre)\n"
+msgstr ""
+"rien à valider (créez/copiez des fichiers et utilisez \"git add\" pour les "
+"suivre)\n"
-#: wt-status.c:1260 wt-status.c:1265
+#: wt-status.c:1263 wt-status.c:1268
#, c-format
msgid "nothing to commit\n"
msgstr "rien à valider\n"
-#: wt-status.c:1263
+#: wt-status.c:1266
#, c-format
msgid "nothing to commit (use -u to show untracked files)\n"
msgstr "rien à valider (utilisez -u pour afficher les fichiers non suivis)\n"
-#: wt-status.c:1267
+#: wt-status.c:1270
#, c-format
msgid "nothing to commit, working directory clean\n"
msgstr "rien à valider, la copie de travail est propre\n"
-#: wt-status.c:1375
+#: wt-status.c:1378
msgid "HEAD (no branch)"
msgstr "HEAD (aucune branche)"
-#: wt-status.c:1381
+#: wt-status.c:1384
msgid "Initial commit on "
msgstr "Validation initiale sur "
-#: wt-status.c:1396
+#: wt-status.c:1399
msgid "behind "
msgstr "derrière "
-#: wt-status.c:1399 wt-status.c:1402
+#: wt-status.c:1402 wt-status.c:1405
msgid "ahead "
msgstr "devant "
-#: wt-status.c:1404
+#: wt-status.c:1407
msgid ", behind "
msgstr ", derrière "
-#: compat/precompose_utf8.c:58 builtin/clone.c:352
+#: compat/precompose_utf8.c:58 builtin/clone.c:351
#, c-format
msgid "failed to unlink '%s'"
-msgstr "echec lors de l'unlink de '%s'"
+msgstr "échec lors de l'unlink de '%s'"
#: builtin/add.c:20
msgid "git add [options] [--] <pathspec>..."
"\n"
"With the current Git version, the command is restricted to the current "
"directory.\n"
-msgstr "Le comportement de 'git add %s (ou %s)' sans argument de chemin\n"
-"depuis un sous-répertoire du projet va changer dans Git 2.0. Cet usage\n"
-"est déconseillé.\n"
-"Pour ajouter du contenu pour tout le projet, lancez :\n"
+msgstr ""
+"Le comportement de 'git add %s (ou %s)' sans argument de chemin depuis un\n"
+"sous-répertoire du projet va changer dans Git 2.0 et ne doit plus être "
+"utilisé.\n"
+"Pour ajouter le contenu de toute l'arborescence, lancez :\n"
"\n"
" git add %s :/\n"
" (ou git add %s :/)\n"
" git add %s .\n"
" (ou git add %s .)\n"
"\n"
-"Avec la version actuelle de Git, la commande est restreinte au répertoire courant.\n"
+"Avec la version actuelle de Git, la commande est restreinte au répertoire "
+"courant.\n"
#: builtin/add.c:100
#, c-format
"* 'git add --all <pathspec>' will let you also record the removals.\n"
"\n"
"Run 'git status' to check the paths you removed from your working tree.\n"
-msgstr "Vous avez lancé 'git add' sans '-A (--all)' ni '--ignore-removal',\n"
-"Le comportement vis à vis des fichiers supprimés va changer dans Git 2.0.\n"
-"Les chemins tels que '%s' qui ont été retirés de votre copie de travail sont\n"
-"actuellement ignorés.\n"
+msgstr ""
+"Vous avez lancé 'git add' sans '-A (--all)' ni '--ignore-removal',\n"
+"dont le comportement va changer dans Git 2.0 avec le respect des chemins que "
+"vous supprimez.\n"
+"Les chemins tels que '%s' qui ont été\n"
+"retirés de votre copie de travail sont ignorés avec cette version de Git.\n"
"\n"
-" 'git add --ignore-removal <chemin>', est l'option par défaut actuelle qui\n"
-" ignore les chemins que vous avez supprimé de votre copie de travail.\n"
+"* 'git add --ignore-removal <chemin>', qui est l'option par défaut "
+"actuelle,\n"
+" ignore les chemins que vous avez supprimés de votre copie de travail.\n"
"\n"
"* 'git add --all <chemin>' permet d'enregistrer aussi les suppressions.\n"
+"\n"
+"Lancez 'git status' pour vérifier les chemins que vous avez supprimés de "
+"votre copie de travail.\n"
#: builtin/add.c:144
#, c-format
msgid "unexpected diff status %c"
msgstr "status de diff inattendu %c"
-#: builtin/add.c:149 builtin/commit.c:233
+#: builtin/add.c:149 builtin/commit.c:252
msgid "updating files failed"
-msgstr "echec de la mise à jour des fichiers"
+msgstr "échec de la mise à jour des fichiers"
#: builtin/add.c:163
#, c-format
msgid "remove '%s'\n"
-msgstr "retrait de '%s'\n"
+msgstr "suppression de '%s'\n"
#: builtin/add.c:253
msgid "Unstaged changes after refreshing the index:"
-msgstr "Modifications non indexées après rafraîchissement de l'index"
+msgstr "Modifications non indexées après rafraîchissement de l'index :"
-#: builtin/add.c:256 builtin/add.c:572 builtin/rm.c:275
+#: builtin/add.c:256 builtin/add.c:573 builtin/rm.c:337
#, c-format
msgid "pathspec '%s' did not match any files"
msgstr "le chemin '%s' ne correspond à aucun fichier"
msgid "Could not read the index"
msgstr "Impossible de lire l'index"
-#: builtin/add.c:349
+#: builtin/add.c:350
#, c-format
msgid "Could not open '%s' for writing."
msgstr "Impossible d'ouvrir '%s' en écriture."
-#: builtin/add.c:353
+#: builtin/add.c:354
msgid "Could not write patch"
msgstr "Impossible d'écrire le patch"
-#: builtin/add.c:358
+#: builtin/add.c:359
#, c-format
msgid "Could not stat '%s'"
msgstr "Stat de '%s' impossible"
-#: builtin/add.c:360
+#: builtin/add.c:361
msgid "Empty patch. Aborted."
msgstr "Patch vide. Abandon."
-#: builtin/add.c:366
+#: builtin/add.c:367
#, c-format
msgid "Could not apply '%s'"
msgstr "Impossible d'appliquer '%s'"
-#: builtin/add.c:376
+#: builtin/add.c:377
msgid "The following paths are ignored by one of your .gitignore files:\n"
-msgstr "Les chemins suivants sont ignorés par un de vos fichiers .gitignore :\n"
+msgstr ""
+"Les chemins suivants sont ignorés par un de vos fichiers .gitignore :\n"
-#: builtin/add.c:393 builtin/clean.c:161 builtin/fetch.c:78 builtin/mv.c:63
-#: builtin/prune-packed.c:76 builtin/push.c:425 builtin/remote.c:1253
-#: builtin/rm.c:206
+#: builtin/add.c:394 builtin/clean.c:875 builtin/fetch.c:78 builtin/mv.c:63
+#: builtin/prune-packed.c:73 builtin/push.c:451 builtin/remote.c:1253
+#: builtin/rm.c:268
msgid "dry run"
-msgstr "à vide"
+msgstr "simuler l'action"
-#: builtin/add.c:394 builtin/apply.c:4409 builtin/check-ignore.c:19
-#: builtin/commit.c:1152 builtin/count-objects.c:95 builtin/fsck.c:613
-#: builtin/log.c:1518 builtin/mv.c:62 builtin/read-tree.c:112
+#: builtin/add.c:395 builtin/apply.c:4410 builtin/check-ignore.c:19
+#: builtin/commit.c:1220 builtin/count-objects.c:95 builtin/fsck.c:613
+#: builtin/log.c:1573 builtin/mv.c:62 builtin/read-tree.c:113
msgid "be verbose"
msgstr "mode verbeux"
-#: builtin/add.c:396
+#: builtin/add.c:397
msgid "interactive picking"
msgstr "sélection interactive"
-#: builtin/add.c:397 builtin/checkout.c:1063 builtin/reset.c:258
+#: builtin/add.c:398 builtin/checkout.c:1073 builtin/reset.c:261
msgid "select hunks interactively"
msgstr "sélection interactive des sections"
-#: builtin/add.c:398
+#: builtin/add.c:399
msgid "edit current diff and apply"
msgstr "édition du diff actuel et application"
-#: builtin/add.c:399
+#: builtin/add.c:400
msgid "allow adding otherwise ignored files"
msgstr "permettre l'ajout de fichiers ignorés"
-#: builtin/add.c:400
+#: builtin/add.c:401
msgid "update tracked files"
-msgstr "mise à jour des fichiers suivis"
+msgstr "mettre à jour les fichiers suivis"
-#: builtin/add.c:401
+#: builtin/add.c:402
msgid "record only the fact that the path will be added later"
msgstr "enregistrer seulement le fait que le chemin sera ajouté plus tard"
-#: builtin/add.c:402
+#: builtin/add.c:403
msgid "add changes from all tracked and untracked files"
-msgstr "ajouter les modifications de tous les fichiers suivis et non-suivis"
+msgstr "ajouter les modifications de tous les fichiers suivis et non suivis"
#. takes no arguments
-#: builtin/add.c:405
+#: builtin/add.c:406
msgid "ignore paths removed in the working tree (same as --no-all)"
-msgstr "ignorer les chemins effacés dans la copie de travail (identique à --no-all)"
+msgstr ""
+"ignorer les chemins effacés dans la copie de travail (identique à --no-all)"
-#: builtin/add.c:407
+#: builtin/add.c:408
msgid "don't add, only refresh the index"
msgstr "ne pas ajouter, juste rafraîchir l'index"
-#: builtin/add.c:408
+#: builtin/add.c:409
msgid "just skip files which cannot be added because of errors"
-msgstr "sauter seulement les fichiers qui ne peuvent pas être ajoutés du fait d'erreurs"
+msgstr ""
+"sauter seulement les fichiers qui ne peuvent pas être ajoutés du fait "
+"d'erreurs"
-#: builtin/add.c:409
+#: builtin/add.c:410
msgid "check if - even missing - files are ignored in dry run"
-msgstr "vérifier à vide si des fichiers, même manquants, sont ignorés"
+msgstr "vérifier si des fichiers - même manquants - sont ignorés, à vide"
-#: builtin/add.c:431
+#: builtin/add.c:432
#, c-format
msgid "Use -f if you really want to add them.\n"
msgstr "Utilisez -f si vous voulez réellement les ajouter.\n"
-#: builtin/add.c:432
+#: builtin/add.c:433
msgid "no files added"
msgstr "aucun fichier ajouté"
-#: builtin/add.c:438
+#: builtin/add.c:439
msgid "adding files failed"
-msgstr "echec de l'ajout de fichiers"
+msgstr "échec de l'ajout de fichiers"
-#: builtin/add.c:477
+#: builtin/add.c:478
msgid "-A and -u are mutually incompatible"
msgstr "-A et -u sont mutuellement incompatibles"
-#: builtin/add.c:495
+#: builtin/add.c:496
msgid "Option --ignore-missing can only be used together with --dry-run"
-msgstr "L'option --ignore-missing ne peut être utilisée qu'en complément de --dry-run"
+msgstr ""
+"L'option --ignore-missing ne peut être utilisée qu'en complément de --dry-run"
-#: builtin/add.c:525
+#: builtin/add.c:526
#, c-format
msgid "Nothing specified, nothing added.\n"
-msgstr "Spécification vide, riien à ajouter.\n"
+msgstr "Rien de spécifié, rien n'a été ajouté.\n"
-#: builtin/add.c:526
+#: builtin/add.c:527
#, c-format
msgid "Maybe you wanted to say 'git add .'?\n"
-msgstr "Vous voulez sûrement dire 'git add .' ?\n"
+msgstr "Vous vouliez sûrement dire 'git add .' ?\n"
-#: builtin/add.c:532 builtin/check-ignore.c:66 builtin/clean.c:204
-#: builtin/commit.c:293 builtin/mv.c:82 builtin/rm.c:235
+#: builtin/add.c:533 builtin/check-ignore.c:161 builtin/clean.c:919
+#: builtin/commit.c:312 builtin/mv.c:82 builtin/rm.c:297
msgid "index file corrupt"
msgstr "fichier d'index corrompu"
-#: builtin/add.c:604 builtin/apply.c:4505 builtin/mv.c:229 builtin/rm.c:370
+#: builtin/add.c:605 builtin/apply.c:4506 builtin/mv.c:229 builtin/rm.c:432
msgid "Unable to write new index file"
msgstr "Impossible d'écrire le nouveau fichier d'index"
#: builtin/apply.c:57
msgid "git apply [options] [<patch>...]"
-msgstr "git apply [option] [<patch>...]"
+msgstr "git apply [options] [<patch>...]"
#: builtin/apply.c:110
#, c-format
msgid "unrecognized whitespace option '%s'"
-msgstr "option d'espaces non reconnue '%s'"
+msgstr "option d'espace non reconnue '%s'"
#: builtin/apply.c:125
#, c-format
msgid "unrecognized whitespace ignore option '%s'"
-msgstr "option d'espaces ignorés non reconnue '%s'"
+msgstr "option d'ignorance d'espace non reconnue '%s'"
#: builtin/apply.c:823
#, c-format
#: builtin/apply.c:832
#, c-format
msgid "regexec returned %d for input: %s"
-msgstr "regexec a retourné %d pour l'entrée %s"
+msgstr "regexec a retourné %d pour l'entrée : %s"
#: builtin/apply.c:913
#, c-format
msgid "unable to find filename in patch at line %d"
-msgstr "nom de fichier du patch introuvable ligne %d"
+msgstr "nom de fichier du patch introuvable à la ligne %d"
#: builtin/apply.c:945
#, c-format
msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d"
-msgstr "git apply : mauvais format de git-diff - /dev/null attendu, %s trouvé ligne %d"
+msgstr ""
+"git apply : mauvais format de git-diff - /dev/null attendu, %s trouvé à la "
+"ligne %d"
#: builtin/apply.c:949
#, c-format
msgid "git apply: bad git-diff - inconsistent new filename on line %d"
-msgstr "git apply : mauvais format de git-diff - nouveau nom de fichier inconsistant ligne %d"
+msgstr ""
+"git apply : mauvais format de git-diff - nouveau nom de fichier inconsistant "
+"à la ligne %d"
#: builtin/apply.c:950
#, c-format
msgid "git apply: bad git-diff - inconsistent old filename on line %d"
-msgstr "git apply : mauvais format de git-diff - ancien nom de fichier inconsistant ligne %d"
+msgstr ""
+"git apply : mauvais format de git-diff - ancien nom de fichier inconsistant "
+"à la ligne %d"
#: builtin/apply.c:957
#, c-format
msgid "git apply: bad git-diff - expected /dev/null on line %d"
-msgstr "git apply : mauvais format de git-diff - /dev/null attendu ligne %d"
+msgstr ""
+"git apply : mauvais format de git-diff - /dev/null attendu à la ligne %d"
#: builtin/apply.c:1422
#, c-format
msgid "recount: unexpected line: %.*s"
-msgstr "recount : ligne inattendue : %.*s"
+msgstr "recomptage : ligne inattendue : %.*s"
#: builtin/apply.c:1479
#, c-format
msgid "patch fragment without header at line %d: %.*s"
-msgstr "fragment de patch sans entête ligne %d : %.*s"
+msgstr "fragment de patch sans en-tête à la ligne %d : %.*s"
#: builtin/apply.c:1496
#, c-format
msgid_plural ""
"git diff header lacks filename information when removing %d leading pathname "
"components (line %d)"
-msgstr[0] "information de nom de fichier manquante dans l'entête de git diff lors de la suppression de %d composant de préfix de chemin (ligne %d)"
-msgstr[1] "information de nom de fichier manquante dans l'entête de git diff lors de la suppression de %d composants de préfix de chemin (ligne %d)"
+msgstr[0] ""
+"information de nom de fichier manquante dans l'en-tête de git diff lors de "
+"la suppression de %d composant de préfixe de chemin (ligne %d)"
+msgstr[1] ""
+"information de nom de fichier manquante dans l'en-tête de git diff lors de "
+"la suppression de %d composants de préfixe de chemin (ligne %d)"
#: builtin/apply.c:1656
msgid "new file depends on old contents"
#: builtin/apply.c:1725
#, c-format
msgid "** warning: file %s becomes empty but is not deleted"
-msgstr "** attention : le fichier %s devient vide mais n'est pas effacé"
+msgstr "** attention : le fichier %s devient vide mais n'est pas supprimé"
#: builtin/apply.c:1871
#, c-format
msgid "corrupt binary patch at line %d: %.*s"
-msgstr "patch binaire corrompu ligne %d : %.*s"
+msgstr "patch binaire corrompu à la ligne %d : %.*s"
#. there has to be one hunk (forward hunk)
#: builtin/apply.c:1900
#, c-format
msgid "unrecognized binary patch at line %d"
-msgstr "patch binaire non reconnu ligne %d"
+msgstr "patch binaire non reconnu à la ligne %d"
#: builtin/apply.c:1986
#, c-format
msgid "patch with only garbage at line %d"
-msgstr "patch totalement incompréhensible ligne %d"
+msgstr "patch totalement incompréhensible à la ligne %d"
#: builtin/apply.c:2076
#, c-format
msgid "unable to read symlink %s"
-msgstr "lecture du symlink %s impossible"
+msgstr "lecture du lien symbolique %s impossible"
#: builtin/apply.c:2080
#, c-format
#, c-format
msgid "Hunk #%d succeeded at %d (offset %d line)."
msgid_plural "Hunk #%d succeeded at %d (offset %d lines)."
-msgstr[0] "La section #%d a réussi à la ligne %d (offset %d ligne)"
-msgstr[1] "La section #%d a réussi à la ligne %d (offset %d lignes)"
+msgstr[0] "La section n°%d a réussi à la ligne %d (offset %d ligne)."
+msgstr[1] "La section n°%d a réussi à la ligne %d (offset %d lignes)."
#: builtin/apply.c:2818
#, c-format
msgid ""
"while searching for:\n"
"%.*s"
-msgstr "pendant la recherche de :\n"
+msgstr ""
+"pendant la recherche de :\n"
"%.*s"
#: builtin/apply.c:2843
#: builtin/apply.c:2952
#, c-format
msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)"
-msgstr "le patch binaire sur '%s' crée un résultat incorrect (%s attendu, mais %s trouvé)"
+msgstr ""
+"le patch binaire sur '%s' crée un résultat incorrect (%s attendu, mais %s "
+"trouvé)"
#: builtin/apply.c:2973
#, c-format
msgid "patch failed: %s:%ld"
-msgstr "le patch a échoué : %s : %ld"
+msgstr "le patch a échoué : %s:%ld"
#: builtin/apply.c:3095
#, c-format
msgid "cannot checkout %s"
msgstr "extraction de %s impossible"
-#: builtin/apply.c:3140 builtin/apply.c:3149 builtin/apply.c:3193
+#: builtin/apply.c:3140 builtin/apply.c:3149 builtin/apply.c:3194
#, c-format
msgid "read of %s failed"
-msgstr "echec de la lecture de %s"
+msgstr "échec de la lecture de %s"
-#: builtin/apply.c:3173 builtin/apply.c:3395
+#: builtin/apply.c:3174 builtin/apply.c:3396
#, c-format
msgid "path %s has been renamed/deleted"
-msgstr "le fichier %s a été renommé/supprimé"
+msgstr "le chemin %s a été renommé/supprimé"
-#: builtin/apply.c:3254 builtin/apply.c:3409
+#: builtin/apply.c:3255 builtin/apply.c:3410
#, c-format
msgid "%s: does not exist in index"
msgstr "%s : n'existe pas dans l'index"
-#: builtin/apply.c:3258 builtin/apply.c:3401 builtin/apply.c:3423
+#: builtin/apply.c:3259 builtin/apply.c:3402 builtin/apply.c:3424
#, c-format
msgid "%s: %s"
msgstr "%s : %s"
-#: builtin/apply.c:3263 builtin/apply.c:3417
+#: builtin/apply.c:3264 builtin/apply.c:3418
#, c-format
msgid "%s: does not match index"
msgstr "%s : ne correspond pas à l'index"
-#: builtin/apply.c:3365
+#: builtin/apply.c:3366
msgid "removal patch leaves file contents"
msgstr "le patch de suppression laisse un contenu dans le fichier"
-#: builtin/apply.c:3434
+#: builtin/apply.c:3435
#, c-format
msgid "%s: wrong type"
msgstr "%s : type erroné"
-#: builtin/apply.c:3436
+#: builtin/apply.c:3437
#, c-format
msgid "%s has type %o, expected %o"
msgstr "%s est de type %o, mais %o attendu"
-#: builtin/apply.c:3537
+#: builtin/apply.c:3538
#, c-format
msgid "%s: already exists in index"
msgstr "%s : existe déjà dans l'index"
-#: builtin/apply.c:3540
+#: builtin/apply.c:3541
#, c-format
msgid "%s: already exists in working directory"
msgstr "%s : existe déjà dans la copie de travail"
-#: builtin/apply.c:3560
+#: builtin/apply.c:3561
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o)"
msgstr "le nouveau mode (%o) de %s ne correspond pas à l'ancien mode (%o)"
-#: builtin/apply.c:3565
+#: builtin/apply.c:3566
#, c-format
msgid "new mode (%o) of %s does not match old mode (%o) of %s"
-msgstr "le nouveau mode (%o) de %s ne correspond pas à l'ancien mode (%o) de %s"
+msgstr ""
+"le nouveau mode (%o) de %s ne correspond pas à l'ancien mode (%o) de %s"
-#: builtin/apply.c:3573
+#: builtin/apply.c:3574
#, c-format
msgid "%s: patch does not apply"
msgstr "%s : le patch ne s'applique pas"
-#: builtin/apply.c:3586
+#: builtin/apply.c:3587
#, c-format
msgid "Checking patch %s..."
msgstr "Vérification du patch %s..."
-#: builtin/apply.c:3679 builtin/checkout.c:216 builtin/reset.c:124
+#: builtin/apply.c:3680 builtin/checkout.c:216 builtin/reset.c:127
#, c-format
msgid "make_cache_entry failed for path '%s'"
-msgstr "echec de make_cache_entry pour le chemin '%s'"
+msgstr "échec de make_cache_entry pour le chemin '%s'"
-#: builtin/apply.c:3822
+#: builtin/apply.c:3823
#, c-format
msgid "unable to remove %s from index"
msgstr "suppression de %s dans l'index impossible"
-#: builtin/apply.c:3850
+#: builtin/apply.c:3851
#, c-format
-msgid "corrupt patch for subproject %s"
-msgstr "patch corrompu pour le sous-projet %s"
+msgid "corrupt patch for submodule %s"
+msgstr "patch corrompu pour le sous-module %s"
-#: builtin/apply.c:3854
+#: builtin/apply.c:3855
#, c-format
msgid "unable to stat newly created file '%s'"
msgstr "stat du fichier nouvellement créé '%s' impossible"
-#: builtin/apply.c:3859
+#: builtin/apply.c:3860
#, c-format
msgid "unable to create backing store for newly created file %s"
-msgstr "création du magasin de sauvegard pour le fichier nouvellement créé %s impossible"
+msgstr ""
+"création du magasin de stockage pour le fichier nouvellement créé %s "
+"impossible"
-#: builtin/apply.c:3862 builtin/apply.c:3970
+#: builtin/apply.c:3863 builtin/apply.c:3971
#, c-format
msgid "unable to add cache entry for %s"
-msgstr "ajout de l'entrée de cache %s impossible"
+msgstr "ajout de l'élément de cache %s impossible"
-#: builtin/apply.c:3895
+#: builtin/apply.c:3896
#, c-format
msgid "closing file '%s'"
-msgstr "fermeture du ficheir '%s'"
+msgstr "fermeture du fichier '%s'"
-#: builtin/apply.c:3944
+#: builtin/apply.c:3945
#, c-format
msgid "unable to write file '%s' mode %o"
msgstr "écriture du fichier '%s' mode %o impossible"
-#: builtin/apply.c:4031
+#: builtin/apply.c:4032
#, c-format
msgid "Applied patch %s cleanly."
msgstr "Patch %s appliqué proprement."
-#: builtin/apply.c:4039
+#: builtin/apply.c:4040
msgid "internal error"
msgstr "erreur interne"
#. Say this even without --verbose
-#: builtin/apply.c:4042
+#: builtin/apply.c:4043
#, c-format
msgid "Applying patch %%s with %d reject..."
msgid_plural "Applying patch %%s with %d rejects..."
msgstr[0] "Application du patch %%s avec %d rejet..."
msgstr[1] "Application du patch %%s avec %d rejets..."
-#: builtin/apply.c:4052
+#: builtin/apply.c:4053
#, c-format
msgid "truncating .rej filename to %.*s.rej"
msgstr "troncature du nom de fichier .rej en %.*s.rej"
-#: builtin/apply.c:4073
+#: builtin/apply.c:4074
#, c-format
msgid "Hunk #%d applied cleanly."
-msgstr "Section no %d appliqué proprement."
+msgstr "Section n°%d appliquée proprement."
-#: builtin/apply.c:4076
+#: builtin/apply.c:4077
#, c-format
msgid "Rejected hunk #%d."
-msgstr "Section no %d rejetée."
+msgstr "Section n°%d rejetée."
-#: builtin/apply.c:4226
+#: builtin/apply.c:4227
msgid "unrecognized input"
msgstr "entrée non reconnue"
-#: builtin/apply.c:4237
+#: builtin/apply.c:4238
msgid "unable to read index file"
msgstr "lecture du fichier d'index impossible"
-#: builtin/apply.c:4356 builtin/apply.c:4359 builtin/clone.c:92
+#: builtin/apply.c:4357 builtin/apply.c:4360 builtin/clone.c:91
#: builtin/fetch.c:63
msgid "path"
msgstr "chemin"
-#: builtin/apply.c:4357
+#: builtin/apply.c:4358
msgid "don't apply changes matching the given path"
msgstr "ne pas appliquer les modifications qui correspondent au chemin donné"
-#: builtin/apply.c:4360
+#: builtin/apply.c:4361
msgid "apply changes matching the given path"
msgstr "appliquer les modifications qui correspondent au chemin donné"
-#: builtin/apply.c:4362
+#: builtin/apply.c:4363
msgid "num"
msgstr "num"
-#: builtin/apply.c:4363
+#: builtin/apply.c:4364
msgid "remove <num> leading slashes from traditional diff paths"
msgstr "supprimer <num> barres obliques des chemins traditionnels de diff"
-#: builtin/apply.c:4366
+#: builtin/apply.c:4367
msgid "ignore additions made by the patch"
msgstr "ignorer les additions réalisées par le patch"
-#: builtin/apply.c:4368
+#: builtin/apply.c:4369
msgid "instead of applying the patch, output diffstat for the input"
msgstr "au lieu d'appliquer le patch, afficher le diffstat de l'entrée"
-#: builtin/apply.c:4372
+#: builtin/apply.c:4373
msgid "show number of added and deleted lines in decimal notation"
-msgstr "afficher le nombre de lignes ajoutées et supprimées en notation décimale"
+msgstr ""
+"afficher le nombre de lignes ajoutées et supprimées en notation décimale"
-#: builtin/apply.c:4374
+#: builtin/apply.c:4375
msgid "instead of applying the patch, output a summary for the input"
msgstr "au lieu d'appliquer le patch, afficher un résumer de l'entrée"
-#: builtin/apply.c:4376
+#: builtin/apply.c:4377
msgid "instead of applying the patch, see if the patch is applicable"
msgstr "au lieu d'appliquer le patch, voir si le patch est applicable"
-#: builtin/apply.c:4378
+#: builtin/apply.c:4379
msgid "make sure the patch is applicable to the current index"
msgstr "s'assurer que le patch est applicable sur l'index actuel"
-#: builtin/apply.c:4380
+#: builtin/apply.c:4381
msgid "apply a patch without touching the working tree"
msgstr "appliquer les patch sans toucher à la copie de travail"
-#: builtin/apply.c:4382
+#: builtin/apply.c:4383
msgid "also apply the patch (use with --stat/--summary/--check)"
msgstr "appliquer aussi le patch (à utiliser avec ---stat/--summary/--check)"
-#: builtin/apply.c:4384
+#: builtin/apply.c:4385
msgid "attempt three-way merge if a patch does not apply"
msgstr "tenter une fusion à 3 points si le patch ne s'applique pas proprement"
-#: builtin/apply.c:4386
+#: builtin/apply.c:4387
msgid "build a temporary index based on embedded index information"
-msgstr "construire une index temporaire fondé sur l'information de l'index embarqué"
+msgstr ""
+"construire un index temporaire fondé sur l'information de l'index embarqué"
-#: builtin/apply.c:4388 builtin/checkout-index.c:197 builtin/ls-files.c:456
+#: builtin/apply.c:4389 builtin/checkout-index.c:197 builtin/ls-files.c:462
msgid "paths are separated with NUL character"
msgstr "les chemins sont séparés par un caractère NUL"
-#: builtin/apply.c:4391
+#: builtin/apply.c:4392
msgid "ensure at least <n> lines of context match"
msgstr "s'assurer d'au moins <n> lignes de correspondance de contexte"
-#: builtin/apply.c:4392
+#: builtin/apply.c:4393
msgid "action"
msgstr "action"
-#: builtin/apply.c:4393
+#: builtin/apply.c:4394
msgid "detect new or modified lines that have whitespace errors"
-msgstr "détecter des lignes nouvelles ou modifiées qui contiennent des erreurs d'espace"
+msgstr ""
+"détecter des lignes nouvelles ou modifiées qui contiennent des erreurs "
+"d'espace"
-#: builtin/apply.c:4396 builtin/apply.c:4399
+#: builtin/apply.c:4397 builtin/apply.c:4400
msgid "ignore changes in whitespace when finding context"
-msgstr "ignorer des modifications d'espaces lors de la recherche de contexte"
+msgstr "ignorer des modifications d'espace lors de la recherche de contexte"
-#: builtin/apply.c:4402
+#: builtin/apply.c:4403
msgid "apply the patch in reverse"
-msgstr "appliquer le patch en inverse"
+msgstr "appliquer le patch en sens inverse"
-#: builtin/apply.c:4404
+#: builtin/apply.c:4405
msgid "don't expect at least one line of context"
-msgstr "accepter moins d'une ligne de contexte"
+msgstr "ne pas s'attendre à au moins une ligne de contexte"
-#: builtin/apply.c:4406
+#: builtin/apply.c:4407
msgid "leave the rejected hunks in corresponding *.rej files"
msgstr "laisser les sections rejetées dans les fichiers *.rej correspondants"
-#: builtin/apply.c:4408
+#: builtin/apply.c:4409
msgid "allow overlapping hunks"
msgstr "accepter les recouvrements de sections"
-#: builtin/apply.c:4411
+#: builtin/apply.c:4412
msgid "tolerate incorrectly detected missing new-line at the end of file"
-msgstr "tolérer faux positifs de retours chariot manquant en fin de fichier"
+msgstr ""
+"tolérer des erreurs de détection de retours chariot manquants en fin de "
+"fichier"
-#: builtin/apply.c:4414
+#: builtin/apply.c:4415
msgid "do not trust the line counts in the hunk headers"
-msgstr "ne pas se fier au comptes de lignes dans les entêtes de section"
+msgstr "ne pas se fier au compte de lignes dans les en-têtes de section"
-#: builtin/apply.c:4416
+#: builtin/apply.c:4417
msgid "root"
msgstr "racine"
-#: builtin/apply.c:4417
+#: builtin/apply.c:4418
msgid "prepend <root> to all filenames"
msgstr "préfixer tous les noms de fichier avec <root>"
-#: builtin/apply.c:4439
+#: builtin/apply.c:4440
msgid "--3way outside a repository"
msgstr "--3way hors d'un dépôt"
-#: builtin/apply.c:4447
+#: builtin/apply.c:4448
msgid "--index outside a repository"
-msgstr "--index hors d'une dépôt"
+msgstr "--index hors d'un dépôt"
-#: builtin/apply.c:4450
+#: builtin/apply.c:4451
msgid "--cached outside a repository"
msgstr "--cached hors d'un dépôt"
-#: builtin/apply.c:4466
+#: builtin/apply.c:4467
#, c-format
msgid "can't open patch '%s'"
msgstr "ouverture impossible du patch '%s'"
-#: builtin/apply.c:4480
+#: builtin/apply.c:4481
#, c-format
msgid "squelched %d whitespace error"
msgid_plural "squelched %d whitespace errors"
msgstr[0] "%d erreur d'espace ignorée"
msgstr[1] "%d erreurs d'espace ignorées"
-#: builtin/apply.c:4486 builtin/apply.c:4496
+#: builtin/apply.c:4487 builtin/apply.c:4497
#, c-format
msgid "%d line adds whitespace errors."
msgid_plural "%d lines add whitespace errors."
-msgstr[0] "%d ligne ont ajouté des erreurs d'espace."
+msgstr[0] "%d ligne a ajouté des erreurs d'espace."
msgstr[1] "%d lignes ont ajouté des erreurs d'espace."
#: builtin/archive.c:17
msgid "update BISECT_HEAD instead of checking out the current commit"
msgstr "mettre à jour BISECT_HEAD au lieu d'extraire le commit actuel"
-#: builtin/blame.c:25
+#: builtin/blame.c:26
msgid "git blame [options] [rev-opts] [rev] [--] file"
-msgstr "git blame [options] [option de révision] [rev] [--] file"
+msgstr "git blame [options] [options-de-révision] [rev] [--] fichier"
-#: builtin/blame.c:30
+#: builtin/blame.c:31
msgid "[rev-opts] are documented in git-rev-list(1)"
-msgstr "[rev-opts] sont documentés dans git-rev-list(1)"
+msgstr "[options-de-révision] sont documentés dans git-rev-list(1)"
-#: builtin/blame.c:2355
+#: builtin/blame.c:2276
msgid "Show blame entries as we find them, incrementally"
-msgstr "Montrer les entrée de blame au fur et à mesure de leur découverte, incrémentalement"
+msgstr ""
+"Montrer les éléments de blâme au fur et à mesure de leur découverte, de "
+"manière incrémentale"
-#: builtin/blame.c:2356
+#: builtin/blame.c:2277
msgid "Show blank SHA-1 for boundary commits (Default: off)"
-msgstr "Montrer un SHA-1 blanc pour les commits de limite (défaut : désactivé)"
+msgstr "Montrer un SHA-1 blanc pour les commits de limite (Défaut : désactivé)"
-#: builtin/blame.c:2357
+#: builtin/blame.c:2278
msgid "Do not treat root commits as boundaries (Default: off)"
-msgstr "Ne pas traiter les commits racine comme des limites (défaut : désactivé)"
+msgstr ""
+"Ne pas traiter les commits racine comme des limites (Défaut : désactivé)"
-#: builtin/blame.c:2358
+#: builtin/blame.c:2279
msgid "Show work cost statistics"
msgstr "Montrer les statistiques de coût d'activité"
-#: builtin/blame.c:2359
+#: builtin/blame.c:2280
msgid "Show output score for blame entries"
-msgstr "Montrer le score de sortie pour les entrées de blâme"
+msgstr "Montrer le score de sortie pour les éléments de blâme"
-#: builtin/blame.c:2360
+#: builtin/blame.c:2281
msgid "Show original filename (Default: auto)"
-msgstr "Montrer les noms de fichier originaux (défaut : auto)"
+msgstr "Montrer les noms de fichier originaux (Défaut : auto)"
-#: builtin/blame.c:2361
+#: builtin/blame.c:2282
msgid "Show original linenumber (Default: off)"
-msgstr "Montrer les numéros de lignes originaux (défaut : désactivé)"
+msgstr "Montrer les numéros de lignes originaux (Défaut : désactivé)"
-#: builtin/blame.c:2362
+#: builtin/blame.c:2283
msgid "Show in a format designed for machine consumption"
msgstr "Afficher dans un format propice à la consommation par machine"
-#: builtin/blame.c:2363
+#: builtin/blame.c:2284
msgid "Show porcelain format with per-line commit information"
msgstr "Afficher en format porcelaine avec l'information de commit par ligne"
-#: builtin/blame.c:2364
+#: builtin/blame.c:2285
msgid "Use the same output mode as git-annotate (Default: off)"
-msgstr "Utiliser le même mode de sortie que git-annotate (défaut : désactivé)"
+msgstr "Utiliser le même mode de sortie que git-annotate (Défaut : désactivé)"
-#: builtin/blame.c:2365
+#: builtin/blame.c:2286
msgid "Show raw timestamp (Default: off)"
-msgstr "Afficher les horodatages bruts (défaut: désactivé)"
+msgstr "Afficher les horodatages bruts (Défaut : désactivé)"
-#: builtin/blame.c:2366
+#: builtin/blame.c:2287
msgid "Show long commit SHA1 (Default: off)"
-msgstr "Afficher les SHA1 longs (defaut : désactivé)"
+msgstr "Afficher les longs SHA1 de commits (Défaut : désactivé)"
-#: builtin/blame.c:2367
+#: builtin/blame.c:2288
msgid "Suppress author name and timestamp (Default: off)"
-msgstr "Supprimer le nom de l'auteur et l'horodatage (défaut : désactivé)"
+msgstr "Supprimer le nom de l'auteur et l'horodatage (Défaut : désactivé)"
-#: builtin/blame.c:2368
+#: builtin/blame.c:2289
msgid "Show author email instead of name (Default: off)"
-msgstr "Afficher l'e-mail de l'auteur au lieu du nom (défaut : désactivé)"
+msgstr "Afficher l'e-mail de l'auteur au lieu du nom (Défaut : désactivé)"
-#: builtin/blame.c:2369
+#: builtin/blame.c:2290
msgid "Ignore whitespace differences"
msgstr "Ignorer les différences d'espace"
-#: builtin/blame.c:2370
+#: builtin/blame.c:2291
msgid "Spend extra cycles to find better match"
-msgstr "Dépenser des cycles supplémentaires pour trouver une meilleure correspondance"
+msgstr ""
+"Dépenser des cycles supplémentaires pour trouver une meilleure correspondance"
-#: builtin/blame.c:2371
+#: builtin/blame.c:2292
msgid "Use revisions from <file> instead of calling git-rev-list"
-msgstr "Utiliser les révisions du fichier <fichier> au lieu d'appeler git-rev-list"
+msgstr ""
+"Utiliser les révisions du fichier <fichier> au lieu d'appeler git-rev-list"
-#: builtin/blame.c:2372
+#: builtin/blame.c:2293
msgid "Use <file>'s contents as the final image"
msgstr "Utiliser le contenu de <fichier> comme image finale"
-#: builtin/blame.c:2373 builtin/blame.c:2374
+#: builtin/blame.c:2294 builtin/blame.c:2295
msgid "score"
msgstr "score"
-#: builtin/blame.c:2373
+#: builtin/blame.c:2294
msgid "Find line copies within and across files"
msgstr "Trouver les copies de ligne dans et entre les fichiers"
-#: builtin/blame.c:2374
+#: builtin/blame.c:2295
msgid "Find line movements within and across files"
-msgstr "Trouver les mouvements dans et entre les fichiers"
+msgstr "Trouver les mouvements de ligne dans et entre les fichiers"
-#: builtin/blame.c:2375
+#: builtin/blame.c:2296
msgid "n,m"
msgstr "n,m"
-#: builtin/blame.c:2375
+#: builtin/blame.c:2296
msgid "Process only line range n,m, counting from 1"
-msgstr "Traiter seulement l'intervalle de ligne n,m en commençant le compte à 1"
+msgstr ""
+"Traiter seulement l'intervalle de ligne n,m en commençant le compte à 1"
#: builtin/branch.c:24
msgid "git branch [options] [-r | -a] [--merged | --no-merged]"
#: builtin/branch.c:25
msgid "git branch [options] [-l] [-f] <branchname> [<start-point>]"
-msgstr "git branch [options] [-l] [-f] <nomdebranch> [<point-de-départ>]"
+msgstr "git branch [options] [-l] [-f] <nomdebranche> [<point-de-départ>]"
#: builtin/branch.c:26
msgid "git branch [options] [-r] (-d | -D) <branchname>..."
#: builtin/branch.c:27
msgid "git branch [options] (-m | -M) [<oldbranch>] <newbranch>"
-msgstr "git branch [options] (-m | -M) [<anciennebranch>] <nouvellebranch>"
+msgstr "git branch [options] (-m | -M) [<anciennebranche>] <nouvellebranche>"
#: builtin/branch.c:150
#, c-format
msgid ""
"deleting branch '%s' that has been merged to\n"
" '%s', but not yet merged to HEAD."
-msgstr "suppression de la branche '%s' qui a été fusionnée dans\n"
-" '%s', mais pas dans HEAD."
+msgstr ""
+"suppression de la branche '%s' qui a été fusionnée dans\n"
+" '%s', mais pas dans HEAD."
#: builtin/branch.c:154
#, c-format
msgid ""
"not deleting branch '%s' that is not yet merged to\n"
" '%s', even though it is merged to HEAD."
-msgstr "branche '%s' non supprimée car elle n'a pas été fusionnée dans\n"
-" '%s', mais dans HEAD."
+msgstr ""
+"branche '%s' non supprimée car elle n'a pas été fusionnée dans\n"
+" '%s', même si elle est fusionnée dans HEAD."
#: builtin/branch.c:168
#, 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 "La branche '%s' n'est pas totalement fusionnée.\n"
-"Si vous êtes sur que vous voulez la supprimer, lancez 'git branch -D %s'"
+msgstr ""
+"La branche '%s' n'est pas totalement fusionnée.\n"
+"Si vous êtes sur que vous voulez la supprimer, lancez 'git branch -D %s'."
#: builtin/branch.c:185
msgid "Update of config-file failed"
-msgstr "Echec de la mise à jour du fichier config"
+msgstr "Échec de la mise à jour du fichier de configuration"
#: builtin/branch.c:213
msgid "cannot use -a with -d"
#: builtin/branch.c:227
#, c-format
msgid "Cannot delete the branch '%s' which you are currently on."
-msgstr "Impossible d'effacer la branche '%s' qui est actuellement extraite"
+msgstr "Impossible de supprimer la branche '%s' sur laquelle vous êtes."
#: builtin/branch.c:240
#, c-format
#: builtin/branch.c:263
#, c-format
msgid "Deleted remote branch %s (was %s).\n"
-msgstr "Branche distante %s supprimée (précédemment %s)\n"
+msgstr "Branche distante %s supprimée (précédemment %s).\n"
#: builtin/branch.c:264
#, c-format
msgid "Deleted branch %s (was %s).\n"
-msgstr "Branche %s supprimée (précédemment %s)\n"
+msgstr "Branche %s supprimée (précédemment %s).\n"
#: builtin/branch.c:366
#, c-format
#: builtin/branch.c:707
msgid "Branch rename failed"
-msgstr "Echec de renommage de la branche"
+msgstr "Échec de renommage de la branche"
#: builtin/branch.c:711
#, c-format
#: builtin/branch.c:715
#, c-format
msgid "Branch renamed to %s, but HEAD is not updated!"
-msgstr "La branche a été renommée '%s', mais HEAD n'est pas mis à jour !"
+msgstr "La branche a été renommée en %s, mais HEAD n'est pas mise à jour !"
#: builtin/branch.c:722
msgid "Branch is renamed, but update of config-file failed"
-msgstr "La branche est renommée, mais echec de la mise à jour du fichier de config"
+msgstr ""
+"La branche est renommée, mais la mise à jour du fichier de configuration a "
+"échoué"
#: builtin/branch.c:737
#, c-format
#: builtin/branch.c:793
msgid "show hash and subject, give twice for upstream branch"
-msgstr "afficher le condensé et le sujet, doublé pour la branche amont"
+msgstr "afficher le hachage et le sujet, doublé pour la branche amont"
#: builtin/branch.c:794
msgid "suppress informational messages"
#: builtin/branch.c:802
msgid "act on remote-tracking branches"
-msgstr "agir sur les branches de suivi distant"
+msgstr "agir sur les branches de suivi distantes"
#: builtin/branch.c:805 builtin/branch.c:811 builtin/branch.c:832
-#: builtin/branch.c:838 builtin/commit.c:1368 builtin/commit.c:1369
-#: builtin/commit.c:1370 builtin/commit.c:1371 builtin/tag.c:468
+#: builtin/branch.c:838 builtin/commit.c:1433 builtin/commit.c:1434
+#: builtin/commit.c:1435 builtin/commit.c:1436 builtin/tag.c:468
msgid "commit"
-msgstr "valider"
+msgstr "commit"
#: builtin/branch.c:806 builtin/branch.c:812
msgid "print only branches that contain the commit"
#: builtin/branch.c:855
msgid "Failed to resolve HEAD as a valid ref."
-msgstr "Echec de résolution de HEAD comme référence valide."
+msgstr "Échec de résolution de HEAD comme référence valide."
-#: builtin/branch.c:860 builtin/clone.c:619
+#: builtin/branch.c:860 builtin/clone.c:630
msgid "HEAD not found below refs/heads!"
-msgstr "HEAD non trouvé sous refs/heads !"
+msgstr "HEAD non trouvée sous refs/heads !"
#: builtin/branch.c:883
msgid "--column and --verbose are incompatible"
#: builtin/branch.c:889 builtin/branch.c:928
msgid "branch name required"
-msgstr "nom de branche exigé"
+msgstr "le nom de branche est requis"
#: builtin/branch.c:904
msgid "Cannot give description to detached HEAD"
-msgstr "Impossible de décrire HEAD détaché"
+msgstr "Impossible de décrire une HEAD détachée"
#: builtin/branch.c:909
msgid "cannot edit description of more than one branch"
#: builtin/branch.c:916
#, c-format
msgid "No commit on branch '%s' yet."
-msgstr "Aucun commit sur la branche '%s'"
+msgstr "Aucun commit sur la branche '%s'."
#: builtin/branch.c:919
#, c-format
#, c-format
msgid ""
"could not set upstream of HEAD to %s when it does not point to any branch."
-msgstr "impossible de spécifier une branche amont de HEAD par %s qui ne pointe sur aucune branche."
+msgstr ""
+"impossible de spécifier une branche amont de HEAD par %s qui ne pointe sur "
+"aucune branche."
#: builtin/branch.c:946 builtin/branch.c:968 builtin/branch.c:990
#, c-format
msgid "no such branch '%s'"
-msgstr "branche inexistante '%s'"
+msgstr "pas de branche '%s'"
#: builtin/branch.c:950
#, c-format
msgid "branch '%s' does not exist"
-msgstr "branche inexistante '%s'"
+msgstr "la branche '%s' n'existe pas"
#: builtin/branch.c:962
msgid "too many branches to unset upstream"
#: builtin/branch.c:966
msgid "could not unset upstream of HEAD when it does not point to any branch."
-msgstr "impossible de désactiver une branche amont de HEAD qu'elle ne pointe sur aucune branche."
+msgstr ""
+"impossible de désactiver une branche amont de HEAD quand elle ne pointe sur "
+"aucune branche."
#: builtin/branch.c:972
#, c-format
#: builtin/branch.c:987
msgid "it does not make sense to create 'HEAD' manually"
-msgstr "créer manuellement 'HEAD' n'a aucun sens"
+msgstr "créer manuellement 'HEAD' n'a pas de sens"
#: builtin/branch.c:993
msgid "-a and -r options to 'git branch' do not make sense with a branch name"
-msgstr "les options -a et -r de 'git branch' n'ont pas de sens avec un nom de branche"
+msgstr ""
+"les options -a et -r de 'git branch' n'ont pas de sens avec un nom de branche"
#: builtin/branch.c:996
#, c-format
msgid ""
"The --set-upstream flag is deprecated and will be removed. Consider using --"
"track or --set-upstream-to\n"
-msgstr "l'option --set-upstream est obsolète et va disparaître. Utilisez plutôt --track ou --set-upstream-to\n"
+msgstr ""
+"l'option --set-upstream est obsolète et va disparaître. Utilisez plutôt --"
+"track ou --set-upstream-to\n"
#: builtin/branch.c:1013
#, c-format
"\n"
"If you wanted to make '%s' track '%s', do this:\n"
"\n"
-msgstr "\n"
+msgstr ""
+"\n"
"Si vous vouliez que '%s' suive '%s', faîtes ceci :\n"
"\n"
#: builtin/bundle.c:47
#, c-format
msgid "%s is okay\n"
-msgstr "%s convient\n"
+msgstr "%s est correct\n"
#: builtin/bundle.c:56
msgid "Need a repository to create a bundle."
-msgstr "La création d'un bundle requiert un dépôt."
+msgstr "La création d'un colis requiert un dépôt."
#: builtin/bundle.c:60
msgid "Need a repository to unbundle."
-msgstr "Le dépaquetage d'un bundle requiert un dépôt."
+msgstr "Le dépaquetage d'un colis requiert un dépôt."
-#: builtin/cat-file.c:176
+#: builtin/cat-file.c:285
msgid "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"
msgstr "git cat-file (-t|-s|-e|-p|<type>|--textconv) <objet>"
-#: builtin/cat-file.c:177
+#: builtin/cat-file.c:286
msgid "git cat-file (--batch|--batch-check) < <list_of_objects>"
msgstr "git cat-file (--batch|--batch-check) < <liste_d_objets>"
-#: builtin/cat-file.c:195
+#: builtin/cat-file.c:323
msgid "<type> can be one of: blob, tree, commit, tag"
msgstr "<type> peut être : blob, tree, commit ou tag"
-#: builtin/cat-file.c:196
+#: builtin/cat-file.c:324
msgid "show object type"
msgstr "afficher le type de l'objet"
-#: builtin/cat-file.c:197
+#: builtin/cat-file.c:325
msgid "show object size"
-msgstr "affichier la taille de l'objet"
+msgstr "afficher la taille de l'objet"
-#: builtin/cat-file.c:199
+#: builtin/cat-file.c:327
msgid "exit with zero when there's no error"
msgstr "sortir avec un code d'erreur nul quand il n'y a aucune erreur"
-#: builtin/cat-file.c:200
+#: builtin/cat-file.c:328
msgid "pretty-print object's content"
msgstr "afficher avec mise en forme le contenu de l'objet"
-#: builtin/cat-file.c:202
+#: builtin/cat-file.c:330
msgid "for blob objects, run textconv on object's content"
msgstr "pour les objets blob, lancer textconv sur le contenu de l'objet"
-#: builtin/cat-file.c:204
+#: builtin/cat-file.c:332
msgid "show info and content of objects fed from the standard input"
-msgstr "afficher l'information et le contenu des objets passé en entrée standard"
+msgstr ""
+"afficher l'information et le contenu des objets passés en entrée standard"
-#: builtin/cat-file.c:207
+#: builtin/cat-file.c:335
msgid "show info about objects fed from the standard input"
msgstr "afficher l'information des objets passés en entrée standard"
#: 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...] < <liste-de-chemins>"
+msgstr ""
+"git check-attr --stdin [-z] [-a | --all | attr...] < <liste-de-chemins>"
#: builtin/check-attr.c:19
msgid "report all attributes set on file"
#: builtin/check-attr.c:21 builtin/check-ignore.c:22 builtin/hash-object.c:75
msgid "read file names from stdin"
-msgstr "lire les noms de fichier depuis stdin"
+msgstr "lire les noms de fichier depuis l'entrée standard"
#: builtin/check-attr.c:23 builtin/check-ignore.c:24
msgid "input paths are terminated by a null character"
msgstr "les chemins en entrée sont terminés par le caractère nul"
-#: builtin/check-ignore.c:18 builtin/checkout.c:1044 builtin/gc.c:177
+#: builtin/check-ignore.c:18 builtin/checkout.c:1054 builtin/gc.c:177
msgid "suppress progress reporting"
-msgstr "supprimer le rapport de progrès"
+msgstr "supprimer l'état d'avancement"
-#: builtin/check-ignore.c:146
+#: builtin/check-ignore.c:26
+msgid "show non-matching input paths"
+msgstr "afficher les chemins en entrée qui ne correspondent pas"
+
+#: builtin/check-ignore.c:143
msgid "cannot specify pathnames with --stdin"
-msgstr "l'option --stdin et la spécification de chemin sont incompatibles"
+msgstr "impossible de spécifier les chemins avec --stdin"
-#: builtin/check-ignore.c:149
+#: builtin/check-ignore.c:146
msgid "-z only makes sense with --stdin"
msgstr "-z n'a de sens qu'avec l'option --stdin"
-#: builtin/check-ignore.c:151
+#: builtin/check-ignore.c:148
msgid "no path specified"
msgstr "aucun chemin spécifié"
-#: builtin/check-ignore.c:155
+#: builtin/check-ignore.c:152
msgid "--quiet is only valid with a single pathname"
msgstr "--quiet n'est valide qu'avec un seul chemin"
-#: builtin/check-ignore.c:157
+#: builtin/check-ignore.c:154
msgid "cannot have both --quiet and --verbose"
-msgstr "les options --quiet et --verbose sont incompatibles"
+msgstr "impossible d'avoir --quiet et --verbose"
+
+#: builtin/check-ignore.c:157
+msgid "--non-matching is only valid with --verbose"
+msgstr "--non-matching n'est valide qu'avec --verbose"
+
+#: builtin/check-mailmap.c:8
+msgid "git check-mailmap [options] <contact>..."
+msgstr "git check-mailmap [options] <contact>..."
+
+#: builtin/check-mailmap.c:13
+msgid "also read contacts from stdin"
+msgstr "lire aussi les contacts depuis l'entrée standard"
+
+#: builtin/check-mailmap.c:24
+#, c-format
+msgid "unable to parse contact: %s"
+msgstr "impossible d'analyser le contact : %s"
+
+#: builtin/check-mailmap.c:47
+msgid "no contacts specified"
+msgstr "aucun contact spécifié"
#: builtin/checkout-index.c:126
msgid "git checkout-index [options] [--] [<file>...]"
#: builtin/checkout-index.c:188
msgid "force overwrite of existing files"
-msgstr "forcer l'écrasement des fichiers existant"
+msgstr "forcer l'écrasement des fichiers existants"
#: builtin/checkout-index.c:190
msgid "no warning for existing files and files not in index"
-msgstr "éliminer les alertes pour les fichiers existant et les fichiers absents de l'index"
+msgstr ""
+"pas d'avertissement pour les fichiers existants et les fichiers absents de "
+"l'index"
#: builtin/checkout-index.c:192
msgid "don't checkout new files"
#: builtin/checkout-index.c:204
msgid "when creating files, prepend <string>"
-msgstr "lors de la création de fichiers, préfixer <chaîne>"
+msgstr "lors de la création de fichiers, préfixer par <chaîne>"
#: builtin/checkout-index.c:207
msgid "copy out the files from named stage"
#: builtin/checkout.c:196
#, c-format
msgid "path '%s': cannot merge"
-msgstr "impossible de fusionner le chemin '%s'"
+msgstr "chemin '%s' : impossible de fusionner"
#: builtin/checkout.c:213
#, c-format
#: builtin/checkout.c:255
#, c-format
msgid "Cannot update paths and switch to branch '%s' at the same time."
-msgstr "Impossible de mettre à jour les chemins et basculer sur la branche '%s' en même temps."
+msgstr ""
+"Impossible de mettre à jour les chemins et basculer sur la branche '%s' en "
+"même temps."
#: builtin/checkout.c:266 builtin/checkout.c:458
msgid "corrupt index file"
msgid "Can not do reflog for '%s'\n"
msgstr "Impossible de faire un reflog pour '%s'\n"
-#: builtin/checkout.c:634
+#: builtin/checkout.c:639
msgid "HEAD is now at"
-msgstr "HEAD est maintenant sur "
+msgstr "HEAD est maintenant sur"
-#: builtin/checkout.c:641
+#: builtin/checkout.c:646
#, c-format
msgid "Reset branch '%s'\n"
msgstr "Remise à zéro de la branche '%s'\n"
-#: builtin/checkout.c:644
+#: builtin/checkout.c:649
#, c-format
msgid "Already on '%s'\n"
msgstr "Déjà sur '%s'\n"
-#: builtin/checkout.c:648
+#: builtin/checkout.c:653
#, c-format
msgid "Switched to and reset branch '%s'\n"
msgstr "Basculement et remise à zéro de la branche '%s'\n"
-#: builtin/checkout.c:650 builtin/checkout.c:987
+#: builtin/checkout.c:655 builtin/checkout.c:997
#, c-format
msgid "Switched to a new branch '%s'\n"
msgstr "Basculement sur la nouvelle branche '%s'\n"
-#: builtin/checkout.c:652
+#: builtin/checkout.c:657
#, c-format
msgid "Switched to branch '%s'\n"
msgstr "Basculement sur la branche '%s'\n"
-#: builtin/checkout.c:708
+#: builtin/checkout.c:713
#, c-format
msgid " ... and %d more.\n"
msgstr " ... et %d en plus.\n"
#. The singular version
-#: builtin/checkout.c:714
+#: builtin/checkout.c:719
#, c-format
msgid ""
"Warning: you are leaving %d commit behind, not connected to\n"
"any of your branches:\n"
"\n"
"%s\n"
-msgstr[0] "Attention : vous laissez %d commit en retard, connectés à aucune de vos\n"
-"branches :\n"
+msgstr[0] ""
+"Attention : vous laissez %d commit en retard, non connectés à\n"
+"une branche :\n"
"\n"
"%s\n"
-msgstr[1] "Attention : vous laissez %d commits en retard, connectés à aucune de vos\n"
-"branches :\n"
+msgstr[1] ""
+"Attention : vous laissez %d commits en retard, non connectés à\n"
+"une branche :\n"
"\n"
"%s\n"
-#: builtin/checkout.c:732
+#: builtin/checkout.c:737
#, c-format
msgid ""
"If you want to keep them by creating a new branch, this may be a good time\n"
"\n"
" git branch new_branch_name %s\n"
"\n"
-msgstr "Si vous souhaitez les garder en créant une nouvelle branches, c'est le bon moment avec :\n"
+msgstr ""
+"Si vous souhaitez les garder en créant une nouvelle branche, c'est le bon "
+"moment\n"
+"de le faire avec :\n"
"\n"
"git branche nouvelle_branche %s\n"
"\n"
-#: builtin/checkout.c:762
+#: builtin/checkout.c:767
msgid "internal error in revision walk"
msgstr "erreur interne lors du parcours des révisions"
-#: builtin/checkout.c:766
+#: builtin/checkout.c:771
msgid "Previous HEAD position was"
-msgstr "Lo position précédente de HEAD était "
+msgstr "La position précédente de HEAD était"
-#: builtin/checkout.c:793 builtin/checkout.c:982
+#: builtin/checkout.c:798 builtin/checkout.c:992
msgid "You are on a branch yet to be born"
msgstr "Vous êtes sur une branche qui doit encore naître"
#. case (1)
-#: builtin/checkout.c:918
+#: builtin/checkout.c:928
#, c-format
msgid "invalid reference: %s"
msgstr "référence invalide : %s"
#. case (1): want a tree
-#: builtin/checkout.c:957
+#: builtin/checkout.c:967
#, c-format
msgid "reference is not a tree: %s"
msgstr "la référence n'est pas un arbre : %s"
-#: builtin/checkout.c:996
+#: builtin/checkout.c:1006
msgid "paths cannot be used with switching branches"
msgstr "impossible d'utiliser des chemins avec un basculement de branches"
-#: builtin/checkout.c:999 builtin/checkout.c:1003
+#: builtin/checkout.c:1009 builtin/checkout.c:1013
#, c-format
msgid "'%s' cannot be used with switching branches"
-msgstr "impossible d'utiliser '%s' avec un basculement de branches "
+msgstr "'%s' ne peut pas être utilisé avec un basculement de branches"
-#: builtin/checkout.c:1007 builtin/checkout.c:1010 builtin/checkout.c:1015
-#: builtin/checkout.c:1018
+#: builtin/checkout.c:1017 builtin/checkout.c:1020 builtin/checkout.c:1025
+#: builtin/checkout.c:1028
#, c-format
msgid "'%s' cannot be used with '%s'"
-msgstr "impossible d'utiliser '%s' avec '%s'"
+msgstr "'%s' ne peut pas être utilisé avec '%s'"
-#: builtin/checkout.c:1023
+#: builtin/checkout.c:1033
#, c-format
msgid "Cannot switch branch to a non-commit '%s'"
msgstr "Impossible de basculer de branche vers '%s' qui n'est pas un commit"
-#: builtin/checkout.c:1045 builtin/checkout.c:1047 builtin/clone.c:90
+#: builtin/checkout.c:1055 builtin/checkout.c:1057 builtin/clone.c:89
#: builtin/remote.c:169 builtin/remote.c:171
msgid "branch"
msgstr "branche"
-#: builtin/checkout.c:1046
+#: builtin/checkout.c:1056
msgid "create and checkout a new branch"
-msgstr "créer et extrait une nouvelle branche"
+msgstr "créer et extraire une nouvelle branche"
-#: builtin/checkout.c:1048
+#: builtin/checkout.c:1058
msgid "create/reset and checkout a branch"
-msgstr "créer/reinitialise et extrait une branche"
+msgstr "créer/réinitialiser et extraire une branche"
-#: builtin/checkout.c:1049
+#: builtin/checkout.c:1059
msgid "create reflog for new branch"
-msgstr "créer un refog pour une nouvelle branche"
+msgstr "créer un reflog pour une nouvelle branche"
-#: builtin/checkout.c:1050
+#: builtin/checkout.c:1060
msgid "detach the HEAD at named commit"
-msgstr "détacher le HEAD au commit nommé"
+msgstr "détacher la HEAD à la validation nommée"
-#: builtin/checkout.c:1051
+#: builtin/checkout.c:1061
msgid "set upstream info for new branch"
-msgstr "paramètrer l'information de branche amont pour une nouvelle branche"
+msgstr "paramétrer l'information de branche amont pour une nouvelle branche"
-#: builtin/checkout.c:1053
+#: builtin/checkout.c:1063
msgid "new branch"
msgstr "nouvelle branche"
-#: builtin/checkout.c:1053
+#: builtin/checkout.c:1063
msgid "new unparented branch"
msgstr "nouvelle branche sans parent"
-#: builtin/checkout.c:1054
+#: builtin/checkout.c:1064
msgid "checkout our version for unmerged files"
msgstr "extraire notre version pour les fichiers non fusionnés"
-#: builtin/checkout.c:1056
+#: builtin/checkout.c:1066
msgid "checkout their version for unmerged files"
msgstr "extraire leur version pour les fichiers non fusionnés"
-#: builtin/checkout.c:1058
+#: builtin/checkout.c:1068
msgid "force checkout (throw away local modifications)"
-msgstr "forcer l'extraction (écraser les modifications locales)"
+msgstr "forcer l'extraction (laisser tomber les modifications locales)"
-#: builtin/checkout.c:1059
+#: builtin/checkout.c:1069
msgid "perform a 3-way merge with the new branch"
-msgstr "réaliser une fusion à 3 points avec la nouvelle branche"
+msgstr "effectuer une fusion à 3 points avec la nouvelle branche"
-#: builtin/checkout.c:1060 builtin/merge.c:217
+#: builtin/checkout.c:1070 builtin/merge.c:232
msgid "update ignored files (default)"
msgstr "mettre à jour les fichiers ignorés (par défaut)"
-#: builtin/checkout.c:1061 builtin/log.c:1158 parse-options.h:245
+#: builtin/checkout.c:1071 builtin/log.c:1208 parse-options.h:249
msgid "style"
msgstr "style"
-#: builtin/checkout.c:1062
+#: builtin/checkout.c:1072
msgid "conflict style (merge or diff3)"
msgstr "style de conflit (fusion ou diff3)"
-#: builtin/checkout.c:1065
+#: builtin/checkout.c:1075
msgid "do not limit pathspecs to sparse entries only"
-msgstr "ne pas limiter les spécificateurs de chemins aux seules entrées creuses"
+msgstr "ne pas limiter les spécificateurs de chemins aux seuls éléments creux"
-#: builtin/checkout.c:1067
+#: builtin/checkout.c:1077
msgid "second guess 'git checkout no-such-branch'"
msgstr "deuxième chance 'git checkout branche-inexistante'"
-#: builtin/checkout.c:1091
+#: builtin/checkout.c:1101
msgid "-b, -B and --orphan are mutually exclusive"
msgstr "-b, -B et --orphan sont mutuellement exclusifs"
-#: builtin/checkout.c:1108
+#: builtin/checkout.c:1118
msgid "--track needs a branch name"
-msgstr "un nom de branche est nécessaire pour --track"
+msgstr "--track requiert un nom de branche"
-#: builtin/checkout.c:1115
+#: builtin/checkout.c:1125
msgid "Missing branch name; try -b"
-msgstr "Nom de branche manquant ; essayez avec -b"
+msgstr "Nom de branche manquant ; essayez -b"
-#: builtin/checkout.c:1150
+#: builtin/checkout.c:1160
msgid "invalid path specification"
msgstr "spécification de chemin invalide"
-#: builtin/checkout.c:1157
+#: builtin/checkout.c:1167
#, c-format
msgid ""
"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 "Impossible e mettre à jour les chemins et de basculer sur la branche '%s' en même temps.\n"
+msgstr ""
+"Impossible de mettre à jour les chemins et de basculer sur la branche '%s' "
+"en même temps.\n"
"Souhaitiez-vous extraire '%s' qui ne peut être résolu comme commit ?"
-#: builtin/checkout.c:1162
+#: builtin/checkout.c:1172
#, c-format
msgid "git checkout: --detach does not take a path argument '%s'"
-msgstr "git checkout: --detach d'accepte pas un argument de chemin '%s'"
+msgstr "git checkout: --detach n'accepte pas un argument de chemin '%s'"
-#: builtin/checkout.c:1166
+#: builtin/checkout.c:1176
msgid ""
"git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
"checking out of the index."
-msgstr "git checkout: --ours/--theirs, --force et --merge sont incompatible lors\n"
+msgstr ""
+"git checkout: --ours/--theirs, --force et --merge sont incompatibles lors\n"
"de l'extraction de l'index."
-#: builtin/clean.c:20
-msgid "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
-msgstr "git clean [-d] [-f] [-n] [-q] [-e <expression>] [-x | -X] [--] <chemins>..."
+#: builtin/clean.c:25
+msgid ""
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."
+msgstr ""
+"git clean [-d] [-f] [-i] [-n] [-q] [-e <motif>] [-x | -X] [--] <chemins>..."
-#: builtin/clean.c:24
+#: builtin/clean.c:29
#, c-format
msgid "Removing %s\n"
msgstr "Suppression de %s\n"
-#: builtin/clean.c:25
+#: builtin/clean.c:30
#, c-format
msgid "Would remove %s\n"
msgstr "Supprimerait %s\n"
-#: builtin/clean.c:26
+#: builtin/clean.c:31
#, c-format
msgid "Skipping repository %s\n"
-msgstr "Dépôt %s ignoré\n"
+msgstr "Ignore le dépôt %s\n"
-#: builtin/clean.c:27
+#: builtin/clean.c:32
#, c-format
msgid "Would skip repository %s\n"
msgstr "Ignorerait le dépôt %s\n"
-#: builtin/clean.c:28
+#: builtin/clean.c:33
#, c-format
msgid "failed to remove %s"
-msgstr "echec de la suppression de %s"
+msgstr "échec de la suppression de %s"
+
+#: builtin/clean.c:293
+msgid ""
+"Prompt help:\n"
+"1 - select a numbered item\n"
+"foo - select item based on unique prefix\n"
+" - (empty) select nothing"
+msgstr ""
+"Aide en ligne :\n"
+"1 - sélectionner un élément numéroté\n"
+"foo - sélectionner un élément par un préfixe unique\n"
+" - (vide) ne rien sélectionner"
+
+#: builtin/clean.c:297
+msgid ""
+"Prompt help:\n"
+"1 - select a single item\n"
+"3-5 - select a range of items\n"
+"2-3,6-9 - select multiple ranges\n"
+"foo - select item based on unique prefix\n"
+"-... - unselect specified items\n"
+"* - choose all items\n"
+" - (empty) finish selecting"
+msgstr ""
+"Aide en ligne :\n"
+"1 - sélectionner un seul élément\n"
+"3-5 - sélectionner une plage d'éléments\n"
+"2-3,6-9 - sélectionner plusieurs plages\n"
+"foo - sélectionner un élément par un préfixe unique\n"
+"-... - désélectionner les éléments spécifiés\n"
+"* - choisir tous les éléments\n"
+" - (vide) terminer la sélection"
+
+#: builtin/clean.c:515
+#, c-format
+msgid "Huh (%s)?"
+msgstr "Hein (%s) ?"
+
+#: builtin/clean.c:658
+#, c-format
+msgid "Input ignore patterns>> "
+msgstr "Entrez les motifs à ignorer>> "
+
+#: builtin/clean.c:695
+#, c-format
+msgid "WARNING: Cannot find items matched by: %s"
+msgstr "ATTENTION : Impossible de trouver les éléments correspondant à : %s"
+
+#: builtin/clean.c:716
+msgid "Select items to delete"
+msgstr "Sélectionner les éléments à supprimer"
+
+#: builtin/clean.c:756
+#, c-format
+msgid "remove %s? "
+msgstr "supprimer %s ? "
+
+#: builtin/clean.c:781
+msgid "Bye."
+msgstr "Au revoir."
+
+#: builtin/clean.c:789
+msgid ""
+"clean - start cleaning\n"
+"filter by pattern - exclude items from deletion\n"
+"select by numbers - select items to be deleted by numbers\n"
+"ask each - confirm each deletion (like \"rm -i\")\n"
+"quit - stop cleaning\n"
+"help - this screen\n"
+"? - help for prompt selection"
+msgstr ""
+"clean - démarrer le nettoyage\n"
+"filter by pattern - exclure des éléments par motif\n"
+"select by numbers - sélectionner les éléments à supprimer par numéros\n"
+"ask each - confirmer chaque suppression (comme \"rm -i\")\n"
+"quit - arrêter le nettoyage\n"
+"help - cet écran\n"
+"? - aide pour la sélection en ligne"
+
+#: builtin/clean.c:816
+msgid "*** Commands ***"
+msgstr "*** Commandes ***"
+
+#: builtin/clean.c:817
+msgid "What now"
+msgstr "Et maintenant ?"
+
+#: builtin/clean.c:825
+msgid "Would remove the following item:"
+msgid_plural "Would remove the following items:"
+msgstr[0] "Supprimerait l'élément suivant :"
+msgstr[1] "Supprimerait les éléments suivants :"
+
+#: builtin/clean.c:842
+msgid "No more files to clean, exiting."
+msgstr "Plus de fichier à nettoyer, sortie."
-#: builtin/clean.c:160
+#: builtin/clean.c:874
msgid "do not print names of files removed"
msgstr "ne pas afficher les noms des fichiers supprimés"
-#: builtin/clean.c:162
+#: builtin/clean.c:876
msgid "force"
msgstr "forcer"
-#: builtin/clean.c:164
+#: builtin/clean.c:877
+msgid "interactive cleaning"
+msgstr "nettoyage interactif"
+
+#: builtin/clean.c:879
msgid "remove whole directories"
-msgstr "supprimer des répertoires entiers"
+msgstr "supprimer les répertoires entiers"
-#: builtin/clean.c:165 builtin/describe.c:412 builtin/grep.c:717
-#: builtin/ls-files.c:487 builtin/name-rev.c:231 builtin/show-ref.c:182
+#: builtin/clean.c:880 builtin/describe.c:420 builtin/grep.c:716
+#: builtin/ls-files.c:493 builtin/name-rev.c:315 builtin/show-ref.c:186
msgid "pattern"
-msgstr "expression"
+msgstr "motif"
-#: builtin/clean.c:166
+#: builtin/clean.c:881
msgid "add <pattern> to ignore rules"
-msgstr "ajouter <expression> aux règles ignore"
+msgstr "ajouter <motif> aux règles ignore"
-#: builtin/clean.c:167
+#: builtin/clean.c:882
msgid "remove ignored files, too"
msgstr "supprimer les fichiers ignorés, aussi"
-#: builtin/clean.c:169
+#: builtin/clean.c:884
msgid "remove only ignored files"
msgstr "supprimer seulement les fichiers ignorés"
-#: builtin/clean.c:187
+#: builtin/clean.c:902
msgid "-x and -X cannot be used together"
-msgstr "-x et -X sont mutuellement exclusifs"
+msgstr "-x et -X ne peuvent pas être utilisés ensemble"
-#: builtin/clean.c:191
+#: builtin/clean.c:906
msgid ""
-"clean.requireForce set to true and neither -n nor -f given; refusing to clean"
-msgstr "clean.requireForce positionné à true et ni -n ni -f fourni ; refus de nettoyer"
+"clean.requireForce set to true and neither -i, -n nor -f given; refusing to "
+"clean"
+msgstr ""
+"clean.requireForce positionné à true et ni -i, -n ou -f fourni ; refus de "
+"nettoyer"
-#: builtin/clean.c:194
+#: builtin/clean.c:909
msgid ""
-"clean.requireForce defaults to true and neither -n nor -f given; refusing to "
-"clean"
-msgstr "clean.requireForce à true par défaut et ni -n ni -f fourni ; refus de nettoyer"
+"clean.requireForce defaults to true and neither -i, -n nor -f given; "
+"refusing to clean"
+msgstr ""
+"clean.requireForce à true par défaut et ni -i, -n ou -f fourni ; refus de "
+"nettoyer"
-#: builtin/clone.c:37
+#: builtin/clone.c:36
msgid "git clone [options] [--] <repo> [<dir>]"
msgstr "git clone [options] [--] <dépôt> [<répertoire>]"
-#: builtin/clone.c:65 builtin/fetch.c:82 builtin/merge.c:214
-#: builtin/push.c:436
+#: builtin/clone.c:64 builtin/fetch.c:82 builtin/merge.c:229
+#: builtin/push.c:462
msgid "force progress reporting"
-msgstr "forcer l'affichage du progrès"
+msgstr "forcer l'état d'avancement"
-#: builtin/clone.c:67
+#: builtin/clone.c:66
msgid "don't create a checkout"
msgstr "ne pas créer d'extraction"
-#: builtin/clone.c:68 builtin/clone.c:70 builtin/init-db.c:488
+#: builtin/clone.c:67 builtin/clone.c:69 builtin/init-db.c:488
msgid "create a bare repository"
msgstr "créer un dépôt nu"
-#: builtin/clone.c:73
+#: builtin/clone.c:72
msgid "create a mirror repository (implies bare)"
msgstr "créer un dépôt miroir (implique dépôt nu)"
-#: builtin/clone.c:75
+#: builtin/clone.c:74
msgid "to clone from a local repository"
msgstr "pour cloner depuis un dépôt local"
-#: builtin/clone.c:77
+#: builtin/clone.c:76
msgid "don't use local hardlinks, always copy"
-msgstr "ne pas utiliser de liens durs locaux, mais toujours copier"
+msgstr "ne pas utiliser de liens durs locaux, toujours copier"
-#: builtin/clone.c:79
+#: builtin/clone.c:78
msgid "setup as shared repository"
-msgstr "régler comme dépôt partager"
+msgstr "régler comme dépôt partagé"
-#: builtin/clone.c:81 builtin/clone.c:83
+#: builtin/clone.c:80 builtin/clone.c:82
msgid "initialize submodules in the clone"
msgstr "initialiser les sous-modules dans le clone"
-#: builtin/clone.c:84 builtin/init-db.c:485
+#: builtin/clone.c:83 builtin/init-db.c:485
msgid "template-directory"
msgstr "répertoire-modèle"
-#: builtin/clone.c:85 builtin/init-db.c:486
+#: builtin/clone.c:84 builtin/init-db.c:486
msgid "directory from which templates will be used"
msgstr "répertoire depuis lequel les modèles vont être utilisés"
-#: builtin/clone.c:87
+#: builtin/clone.c:86
msgid "reference repository"
msgstr "dépôt de référence"
-#: builtin/clone.c:88 builtin/column.c:26 builtin/merge-file.c:44
+#: builtin/clone.c:87 builtin/column.c:26 builtin/merge-file.c:44
msgid "name"
msgstr "nom"
-#: builtin/clone.c:89
+#: builtin/clone.c:88
msgid "use <name> instead of 'origin' to track upstream"
-msgstr "utiliser <nom> au lieu de 'origin' pour traquer la branche amont"
+msgstr "utiliser <nom> au lieu de 'origin' pour suivre la branche amont"
-#: builtin/clone.c:91
+#: builtin/clone.c:90
msgid "checkout <branch> instead of the remote's HEAD"
-msgstr "extraire <branche> au lieu du HEAD du répertoire distant"
+msgstr "extraire <branche> au lieu de la HEAD du répertoire distant"
-#: builtin/clone.c:93
+#: builtin/clone.c:92
msgid "path to git-upload-pack on the remote"
msgstr "chemin vers git-upload-pack sur le serveur distant"
-#: builtin/clone.c:94 builtin/fetch.c:83 builtin/grep.c:662
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:661
msgid "depth"
msgstr "profondeur"
-#: builtin/clone.c:95
+#: builtin/clone.c:94
msgid "create a shallow clone of that depth"
msgstr "créer un clone superficiel de cette profondeur"
-#: builtin/clone.c:97
+#: builtin/clone.c:96
msgid "clone only one branch, HEAD or --branch"
-msgstr "clonez seulement une branche, HEAD ou --branch"
+msgstr "cloner seulement une branche, HEAD ou --branch"
-#: builtin/clone.c:98 builtin/init-db.c:494
+#: builtin/clone.c:97 builtin/init-db.c:494
msgid "gitdir"
msgstr "gitdir"
-#: builtin/clone.c:99 builtin/init-db.c:495
+#: builtin/clone.c:98 builtin/init-db.c:495
msgid "separate git dir from working tree"
msgstr "séparer le répertoire git de la copie de travail"
-#: builtin/clone.c:100
+#: builtin/clone.c:99
msgid "key=value"
msgstr "clé=valeur"
-#: builtin/clone.c:101
+#: builtin/clone.c:100
msgid "set config inside the new repository"
msgstr "régler la configuration dans le nouveau dépôt"
-#: builtin/clone.c:254
+#: builtin/clone.c:253
#, c-format
msgid "reference repository '%s' is not a local repository."
-msgstr "le dépôt de référence '%s' n'est pas un dépôt local"
+msgstr "le dépôt de référence '%s' n'est pas un dépôt local."
-#: builtin/clone.c:317
+#: builtin/clone.c:316
#, c-format
msgid "failed to create directory '%s'"
-msgstr "echec de la création du répertoire '%s'"
+msgstr "échec de la création du répertoire '%s'"
-#: builtin/clone.c:319 builtin/diff.c:77
+#: builtin/clone.c:318 builtin/diff.c:77
#, c-format
msgid "failed to stat '%s'"
-msgstr "echec du stat de '%s'"
+msgstr "échec du stat de '%s'"
-#: builtin/clone.c:321
+#: builtin/clone.c:320
#, c-format
msgid "%s exists and is not a directory"
-msgstr "%s existe et n'est pas un répertoire"
+msgstr "%s existe et n'est pas un répertoire"
-#: builtin/clone.c:335
+#: builtin/clone.c:334
#, c-format
msgid "failed to stat %s\n"
-msgstr "echec du stat de %s\n"
+msgstr "échec du stat de %s\n"
-#: builtin/clone.c:357
+#: builtin/clone.c:356
#, c-format
msgid "failed to create link '%s'"
-msgstr "echec de la création du lien '%s'"
+msgstr "échec de la création du lien '%s'"
-#: builtin/clone.c:361
+#: builtin/clone.c:360
#, c-format
msgid "failed to copy file to '%s'"
-msgstr "echec de la copie vers '%s'"
+msgstr "échec de la copie vers '%s'"
-#: builtin/clone.c:384
+#: builtin/clone.c:383
#, c-format
msgid "done.\n"
msgstr "fait.\n"
-#: builtin/clone.c:397
+#: builtin/clone.c:396
msgid ""
"Clone succeeded, but checkout failed.\n"
"You can inspect what was checked out with 'git status'\n"
"and retry the checkout with 'git checkout -f HEAD'\n"
-msgstr "Le clone a réussi, mais l'extraction a échoué.\n"
+msgstr ""
+"Le clone a réussi, mais l'extraction a échoué.\n"
"Vous pouvez inspecter ce qui a été extrait avec 'git status'\n"
"et réessayer l'extraction avec 'git checkout -f HEAD'\n"
-#: builtin/clone.c:476
+#: builtin/clone.c:475
#, c-format
msgid "Could not find remote branch %s to clone."
msgstr "Impossible de trouver la branche distante '%s' à cloner."
-#: builtin/clone.c:550
+#: builtin/clone.c:555
+#, c-format
+msgid "Checking connectivity... "
+msgstr "Vérification de la connectivité... "
+
+#: builtin/clone.c:558
msgid "remote did not send all necessary objects"
msgstr "le serveur distant n'a pas envoyé tous les objets nécessaires"
-#: builtin/clone.c:610
+#: builtin/clone.c:560
+#, c-format
+msgid "done\n"
+msgstr "fait\n"
+
+#: builtin/clone.c:621
msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
-msgstr "le HEAD distant réfère à une référence non existante, impossible de l'extraire.\n"
+msgstr ""
+"la HEAD distante réfère à une référence non existante, impossible de "
+"l'extraire.\n"
-#: builtin/clone.c:641
+#: builtin/clone.c:652
msgid "unable to checkout working tree"
-msgstr "incapable d'extraire la copie de travail"
+msgstr "impossible d'extraire la copie de travail"
-#: builtin/clone.c:749
+#: builtin/clone.c:760
msgid "Too many arguments."
-msgstr "Trop d'arguments"
+msgstr "Trop d'arguments."
-#: builtin/clone.c:753
+#: builtin/clone.c:764
msgid "You must specify a repository to clone."
msgstr "Vous devez spécifier un dépôt à cloner."
-#: builtin/clone.c:764
+#: builtin/clone.c:775
#, c-format
msgid "--bare and --origin %s options are incompatible."
-msgstr "les options --bare et --origin %s sont incompatibles"
+msgstr "les options --bare et --origin %s sont incompatibles."
-#: builtin/clone.c:767
+#: builtin/clone.c:778
msgid "--bare and --separate-git-dir are incompatible."
-msgstr "les option --bare --separate-git-dir sont incompatibles."
+msgstr "--bare et --separate-git-dir sont incompatibles."
-#: builtin/clone.c:780
+#: builtin/clone.c:791
#, c-format
msgid "repository '%s' does not exist"
msgstr "le dépôt '%s' n'existe pas"
-#: builtin/clone.c:785
+#: builtin/clone.c:796
msgid "--depth is ignored in local clones; use file:// instead."
-msgstr "--depth est ignoré dans les clones locaux : utilisez plutôt file://"
+msgstr ""
+"--depth est ignoré dans les clones locaux : utilisez plutôt \"file://\"."
-#: builtin/clone.c:795
+#: builtin/clone.c:798
+msgid "--local is ignored"
+msgstr "--local est ignoré"
+
+#: builtin/clone.c:808
#, c-format
msgid "destination path '%s' already exists and is not an empty directory."
-msgstr "le chemin de destination '%s' existe déjà et n'est pas un répertoire vide."
+msgstr ""
+"le chemin de destination '%s' existe déjà et n'est pas un répertoire vide."
-#: builtin/clone.c:805
+#: builtin/clone.c:818
#, c-format
msgid "working tree '%s' already exists."
msgstr "la copie de travail '%s' existe déjà."
-#: builtin/clone.c:818 builtin/clone.c:830
+#: builtin/clone.c:831 builtin/clone.c:843
#, c-format
msgid "could not create leading directories of '%s'"
msgstr "impossible de créer les répertoires de premier niveau dans '%s'"
-#: builtin/clone.c:821
+#: builtin/clone.c:834
#, c-format
msgid "could not create work tree dir '%s'."
-msgstr "impossible de créer le répertoire de la copie de travail '%s'"
+msgstr "impossible de créer le répertoire de la copie de travail '%s'."
-#: builtin/clone.c:840
+#: builtin/clone.c:853
#, c-format
msgid "Cloning into bare repository '%s'...\n"
msgstr "Clonage dans le dépôt nu '%s'\n"
-#: builtin/clone.c:842
+#: builtin/clone.c:855
#, c-format
msgid "Cloning into '%s'...\n"
-msgstr "Clonage dans '%s'\n"
+msgstr "Clonage dans '%s'...\n"
-#: builtin/clone.c:877
+#: builtin/clone.c:890
#, c-format
msgid "Don't know how to clone %s"
-msgstr "Je ne sais pas cloner '%s'"
+msgstr "Je ne sais pas cloner %s"
-#: builtin/clone.c:926
+#: builtin/clone.c:942
#, c-format
msgid "Remote branch %s not found in upstream %s"
msgstr "La branche distante %s n'a pas été trouvée dans le dépôt amont %s"
-#: builtin/clone.c:933
+#: builtin/clone.c:949
msgid "You appear to have cloned an empty repository."
msgstr "Vous semblez avoir cloné un dépôt vide."
#: builtin/column.c:30
msgid "Padding space on left border"
-msgstr "Tabulation sur le côté gauche"
+msgstr "Remplissage d'espace sur la bordure gauche"
#: builtin/column.c:31
msgid "Padding space on right border"
-msgstr "Tabulation sur le côté droit"
+msgstr "Remplissage d'espace sur le côté droit"
#: builtin/column.c:32
msgid "Padding space between columns"
-msgstr "Tabulation entre colonnes"
+msgstr "Remplissage d'espace entre les colonnes"
#: builtin/column.c:51
msgid "--command must be the first argument"
msgstr "--command doit être le premier argument"
-#: builtin/commit.c:34
+#: builtin/commit.c:35
msgid "git commit [options] [--] <pathspec>..."
-msgstr "git commit [options] [--] <spécification de chemin>..."
+msgstr "git commit [options] [--] <spécification-de-chemin>..."
-#: builtin/commit.c:39
+#: builtin/commit.c:40
msgid "git status [options] [--] <pathspec>..."
-msgstr "git status [options] [--] <spécification de chemin>..."
+msgstr "git status [options] [--] <spécification-de-chemin>..."
-#: builtin/commit.c:44
+#: builtin/commit.c:45
msgid ""
"Your name and email address were configured automatically based\n"
"on your username and hostname. Please check that they are accurate.\n"
"After doing this, you may fix the identity used for this commit with:\n"
"\n"
" git commit --amend --reset-author\n"
-msgstr "Votre nom et votre adresse e-mail ont été configurés automatiquement en se fondant\n"
-"sur votre nom d'utilisateur et votre nom d'ordinateur. Veuillez vérifier qu'ils sont corrects.\n"
+msgstr ""
+"Votre nom et votre adresse e-mail ont été configurés automatiquement en se "
+"fondant\n"
+"sur votre nom d'utilisateur et votre nom d'ordinateur. Veuillez vérifier "
+"qu'ils sont corrects.\n"
"Vous pouvez supprimer ce message en les paramétrant explicitement :\n"
"\n"
" git config --global user.name \"Votre Nom\"\n"
-" git config --global user.email \"vous@exemple.com\n"
+" git config --global user.email vous@exemple.com\n"
"\n"
"Après ceci, vous pouvez corriger l'identité utilisée pour ce commit avec :\n"
"\n"
" git commit --amend --reset-author\n"
-#: builtin/commit.c:56
+#: builtin/commit.c:57
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 "Vous avez demandé de corriger le commit le plus récent, mais le faire le rendrait\n"
+msgstr ""
+"Vous avez demandé de corriger le commit le plus récent, mais le faire le "
+"rendrait\n"
"vide. Vous pouvez répéter votre commande avec --allow-empty, ou vous pouvez\n"
"supprimer complètement le commit avec \"git reset HEAD^\".\n"
-#: builtin/commit.c:61
+#: builtin/commit.c:62
msgid ""
"The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
"If you wish to commit it anyway, use:\n"
"\n"
" git commit --allow-empty\n"
"\n"
-"Otherwise, please use 'git reset'\n"
-msgstr "Le picorage précédent est à présent vide, vraisemblablement du à une résolution de conflit.\n"
+msgstr ""
+"Le picorage précédent est à présent vide, vraisemblablement dû à une "
+"résolution de conflit.\n"
"Si vous souhaitez tout de même le valider, utilisez :\n"
"\n"
" git commit --allow-empty\n"
"\n"
-"Sinon, utilisez 'git reset'\n"
-#: builtin/commit.c:260
+#: builtin/commit.c:69
+msgid "Otherwise, please use 'git reset'\n"
+msgstr "Sinon, veuillez utiliser 'git reset'\n"
+
+#: builtin/commit.c:72
+msgid ""
+"If you wish to skip this commit, use:\n"
+"\n"
+" git reset\n"
+"\n"
+"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
+"the remaining commits.\n"
+msgstr ""
+"Si vous souhaitez sauter ce commit, utilisez :\n"
+"\n"
+" git reset\n"
+"\n"
+"Puis \"git cherry-pick --continue\" continuera le picorage \n"
+"des commits restants.\n"
+
+#: builtin/commit.c:279
msgid "failed to unpack HEAD tree object"
-msgstr "echec du dépaquetage de l'objet arbre HEAD"
+msgstr "échec du dépaquetage de l'objet arbre HEAD"
-#: builtin/commit.c:302
+#: builtin/commit.c:321
msgid "unable to create temporary index"
msgstr "impossible de créer l'index temporaire"
-#: builtin/commit.c:308
+#: builtin/commit.c:327
msgid "interactive add failed"
-msgstr "echec de l'ajout interactif"
+msgstr "échec de l'ajout interactif"
-#: builtin/commit.c:341 builtin/commit.c:362 builtin/commit.c:412
+#: builtin/commit.c:360 builtin/commit.c:381 builtin/commit.c:431
msgid "unable to write new_index file"
msgstr "impossible d'écrire le fichier new_index"
-#: builtin/commit.c:393
+#: builtin/commit.c:412
msgid "cannot do a partial commit during a merge."
msgstr "impossible de faire une validation partielle pendant une fusion."
-#: builtin/commit.c:395
+#: builtin/commit.c:414
msgid "cannot do a partial commit during a cherry-pick."
msgstr "impossible de faire une validation partielle pendant un picorage."
-#: builtin/commit.c:405
+#: builtin/commit.c:424
msgid "cannot read the index"
msgstr "impossible de lire l'index"
-#: builtin/commit.c:425
+#: builtin/commit.c:444
msgid "unable to write temporary index file"
msgstr "impossible d'écrire le fichier d'index temporaire"
-#: builtin/commit.c:513 builtin/commit.c:519
+#: builtin/commit.c:535 builtin/commit.c:541
#, c-format
msgid "invalid commit: %s"
msgstr "commit invalide : %s"
-#: builtin/commit.c:542
+#: builtin/commit.c:563
msgid "malformed --author parameter"
msgstr "paramètre --author mal formé"
-#: builtin/commit.c:562
+#: builtin/commit.c:583
#, c-format
msgid "Malformed ident string: '%s'"
-msgstr "chaîne ident mal formée : '%s'"
+msgstr "Chaîne ident mal formée : '%s'"
-#: builtin/commit.c:600 builtin/commit.c:633 builtin/commit.c:956
+#: builtin/commit.c:621 builtin/commit.c:654 builtin/commit.c:982
#, c-format
msgid "could not lookup commit %s"
msgstr "impossible de rechercher le commit %s"
-#: builtin/commit.c:612 builtin/shortlog.c:270
+#: builtin/commit.c:633 builtin/shortlog.c:271
#, c-format
msgid "(reading log message from standard input)\n"
msgstr "(lecture du message de journal depuis l'entrée standard)\n"
-#: builtin/commit.c:614
+#: builtin/commit.c:635
msgid "could not read log from standard input"
msgstr "impossible de lire le journal depuis l'entrée standard"
-#: builtin/commit.c:618
+#: builtin/commit.c:639
#, c-format
msgid "could not read log file '%s'"
msgstr "impossible de lire le fichier de journal '%s'"
-#: builtin/commit.c:624
+#: builtin/commit.c:645
msgid "commit has empty message"
msgstr "le commit a un message vide"
-#: builtin/commit.c:640
+#: builtin/commit.c:661
msgid "could not read MERGE_MSG"
msgstr "impossible de lire MERGE_MSG"
-#: builtin/commit.c:644
+#: builtin/commit.c:665
msgid "could not read SQUASH_MSG"
msgstr "impossible de lire SQUASH_MSG"
-#: builtin/commit.c:648
+#: builtin/commit.c:669
#, c-format
msgid "could not read '%s'"
msgstr "impossible de lire '%s'"
-#: builtin/commit.c:709
+#: builtin/commit.c:730
msgid "could not write commit template"
msgstr "impossible d'écrire le modèle de commit"
-#: builtin/commit.c:720
+#: builtin/commit.c:741
#, c-format
msgid ""
"\n"
"If this is not correct, please remove the file\n"
"\t%s\n"
"and try again.\n"
-msgstr "\n"
+msgstr ""
+"\n"
"Il semble que vous validiez une fusion.\n"
"Si ce n'est pas le cas, veuillez supprimer le fichier\n"
"\t%s\n"
"et essayez à nouveau.\n"
-#: builtin/commit.c:725
+#: builtin/commit.c:746
#, c-format
msgid ""
"\n"
"If this is not correct, please remove the file\n"
"\t%s\n"
"and try again.\n"
-msgstr "\n"
-"Il semble que vous validiez un picorage.\n"
+msgstr ""
+"\n"
+"Il semble que vous validiez un picorage.\n"
"Si ce n'est pas le cas, veuillez supprimer le fichier\n"
"\t%s\n"
"et essayez à nouveau.\n"
-#: builtin/commit.c:737
+#: builtin/commit.c:758
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '%c' will be ignored, and an empty message aborts the commit.\n"
-msgstr "Veuillez saisir le message de validation pour vos modifications. Les lignes\n"
-"commençant par '%c' seront ignorées, et un message vide abandonne la\n"
+msgstr ""
+"Veuillez saisir le message de validation pour vos modifications. Les lignes\n"
+"commençant par '%c' seront ignorées, et un message vide abandonne la "
"validation.\n"
-#: builtin/commit.c:742
+#: builtin/commit.c:763
#, c-format
msgid ""
"Please enter the commit message for your changes. Lines starting\n"
"with '%c' will be kept; you may remove them yourself if you want to.\n"
"An empty message aborts the commit.\n"
-msgstr "Veuillez saisir le message de validation pour vos modifications. Les lignes\n"
-"commençant par '%c' seront conservées ; vous pouvez les supprimer vous-\n"
-"même si vous le souhaitez. Un message vide abandonne la validation.\n"
+msgstr ""
+"Veuillez saisir le message de validation pour vos modifications. Les lignes\n"
+"commençant par '%c' seront conservées ; vous pouvez les supprimer vous-même\n"
+"si vous le souhaitez. Un message vide abandonne la validation.\n"
-#: builtin/commit.c:755
+#: builtin/commit.c:776
#, c-format
msgid "%sAuthor: %s"
-msgstr "%sAuteur : %s"
+msgstr "%sAuteur : %s"
-#: builtin/commit.c:762
+#: builtin/commit.c:783
#, c-format
msgid "%sCommitter: %s"
-msgstr "%s Validateur: %s"
+msgstr "%sValidateur : %s"
-#: builtin/commit.c:782
+#: builtin/commit.c:803
msgid "Cannot read index"
msgstr "Impossible de lire l'index"
-#: builtin/commit.c:819
+#: builtin/commit.c:845
msgid "Error building trees"
msgstr "Erreur lors de la construction des arbres"
-#: builtin/commit.c:834 builtin/tag.c:359
+#: builtin/commit.c:860 builtin/tag.c:359
#, c-format
msgid "Please supply the message using either -m or -F option.\n"
msgstr "Veuillez fournir le message en utilisant l'option -m ou -F.\n"
-#: builtin/commit.c:931
+#: builtin/commit.c:957
#, c-format
msgid "No existing author found with '%s'"
msgstr "Aucun auteur existant trouvé avec '%s'"
-#: builtin/commit.c:946 builtin/commit.c:1140
+#: builtin/commit.c:972 builtin/commit.c:1208
#, c-format
msgid "Invalid untracked files mode '%s'"
msgstr "Mode de fichier non suivi invalide '%s'"
-#: builtin/commit.c:976
+#: builtin/commit.c:1009
+msgid "--long and -z are incompatible"
+msgstr "--long et -z sont incompatibles"
+
+#: builtin/commit.c:1039
msgid "Using both --reset-author and --author does not make sense"
-msgstr "L'utilisation concurrente de --reset-author et --author n'a pas de sens"
+msgstr "L'utilisation simultanée de --reset-author et --author n'a pas de sens"
-#: builtin/commit.c:987
+#: builtin/commit.c:1050
msgid "You have nothing to amend."
msgstr "Il n'y a rien à corriger."
-#: builtin/commit.c:990
+#: builtin/commit.c:1053
msgid "You are in the middle of a merge -- cannot amend."
msgstr "Vous êtes en pleine fusion -- impossible de corriger (amend)."
-#: builtin/commit.c:992
+#: builtin/commit.c:1055
msgid "You are in the middle of a cherry-pick -- cannot amend."
msgstr "Vous êtes en plein picorage -- impossible de corriger (amend)."
-#: builtin/commit.c:995
+#: builtin/commit.c:1058
msgid "Options --squash and --fixup cannot be used together"
-msgstr "Les options --squash et --fixup sont incompatibles"
+msgstr "Les options --squash et --fixup ne peuvent pas être utilisées ensemble"
-#: builtin/commit.c:1005
+#: builtin/commit.c:1068
msgid "Only one of -c/-C/-F/--fixup can be used."
msgstr "Une seule option parmi -c/-C/-F/--fixup peut être utilisée."
-#: builtin/commit.c:1007
+#: builtin/commit.c:1070
msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
msgstr "L'option -m ne peut pas être combinée avec -c/-C/-F/--fixup."
-#: builtin/commit.c:1015
+#: builtin/commit.c:1078
msgid "--reset-author can be used only with -C, -c or --amend."
msgstr "--reset-author ne peut être utilisé qu'avec -C, -c ou --amend."
-#: builtin/commit.c:1032
+#: builtin/commit.c:1095
msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
-msgstr "Une seule option parmi --include/--only/--all/--interactive/--patch peut être utilisée."
+msgstr ""
+"Une seule option parmi --include/--only/--all/--interactive/--patch peut "
+"être utilisée."
-#: builtin/commit.c:1034
+#: builtin/commit.c:1097
msgid "No paths with --include/--only does not make sense."
msgstr "Aucun chemin avec les options --include/--only n'a pas de sens."
-#: builtin/commit.c:1036
+#: builtin/commit.c:1099
msgid "Clever... amending the last one with dirty index."
-msgstr "Malin... correction du dernier commit avec un index sale."
+msgstr "Malin... correction du dernier avec un index sale."
-#: builtin/commit.c:1038
+#: builtin/commit.c:1101
msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
-msgstr ""
+msgstr "Chemins explicites spécifiés sans -i ni -o ; --only supposé..."
-#: builtin/commit.c:1048 builtin/tag.c:575
+#: builtin/commit.c:1111 builtin/tag.c:575
#, c-format
msgid "Invalid cleanup mode %s"
-msgstr ""
+msgstr "Mode de nettoyage invalide %s"
-#: builtin/commit.c:1053
+#: builtin/commit.c:1116
msgid "Paths with -a does not make sense."
-msgstr ""
+msgstr "Spécifier des chemins avec l'option -a n'a pas de sens."
-#: builtin/commit.c:1059 builtin/commit.c:1194
-msgid "--long and -z are incompatible"
-msgstr ""
-
-#: builtin/commit.c:1154 builtin/commit.c:1390
+#: builtin/commit.c:1222 builtin/commit.c:1455
msgid "show status concisely"
-msgstr ""
+msgstr "afficher le statut avec concision"
-#: builtin/commit.c:1156 builtin/commit.c:1392
+#: builtin/commit.c:1224 builtin/commit.c:1457
msgid "show branch information"
-msgstr ""
+msgstr "afficher l'information de branche"
-#: builtin/commit.c:1158 builtin/commit.c:1394 builtin/push.c:426
+#: builtin/commit.c:1226 builtin/commit.c:1459 builtin/push.c:452
msgid "machine-readable output"
-msgstr ""
+msgstr "sortie pour traitement automatique"
-#: builtin/commit.c:1161 builtin/commit.c:1396
+#: builtin/commit.c:1229 builtin/commit.c:1461
msgid "show status in long format (default)"
-msgstr ""
+msgstr "afficher le statut en format long (par défaut)"
-#: builtin/commit.c:1164 builtin/commit.c:1399
+#: builtin/commit.c:1232 builtin/commit.c:1464
msgid "terminate entries with NUL"
-msgstr ""
+msgstr "terminer les éléments par NUL"
-#: builtin/commit.c:1166 builtin/commit.c:1402 builtin/fast-export.c:659
-#: builtin/fast-export.c:662 builtin/tag.c:459
+#: builtin/commit.c:1234 builtin/commit.c:1467 builtin/fast-export.c:667
+#: builtin/fast-export.c:670 builtin/tag.c:459
msgid "mode"
-msgstr ""
+msgstr "mode"
-#: builtin/commit.c:1167 builtin/commit.c:1402
+#: builtin/commit.c:1235 builtin/commit.c:1467
msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
msgstr ""
+"afficher les fichiers non suivis, \"mode\" facultatif : all (tous), normal, "
+"no. (Défaut : all)"
-#: builtin/commit.c:1170
+#: builtin/commit.c:1238
msgid "show ignored files"
-msgstr ""
+msgstr "afficher les fichiers ignorés"
-#: builtin/commit.c:1171 parse-options.h:151
+#: builtin/commit.c:1239 parse-options.h:154
msgid "when"
-msgstr ""
+msgstr "quand"
-#: builtin/commit.c:1172
+#: builtin/commit.c:1240
msgid ""
"ignore changes to submodules, optional when: all, dirty, untracked. "
"(Default: all)"
msgstr ""
+"ignorer les modifications dans les sous-modules, \"quand\" facultatif : all "
+"(tous), dirty (sale), untracked (non suivi). (Défaut : all)"
-#: builtin/commit.c:1174
+#: builtin/commit.c:1242
msgid "list untracked files in columns"
-msgstr ""
+msgstr "afficher les fichiers non suivis en colonnes"
-#: builtin/commit.c:1248
+#: builtin/commit.c:1313
msgid "couldn't look up newly created commit"
-msgstr ""
+msgstr "impossible de retrouver le commit nouvellement créé"
-#: builtin/commit.c:1250
+#: builtin/commit.c:1315
msgid "could not parse newly created commit"
-msgstr ""
+msgstr "impossible d'analyser le commit nouvellement créé"
-#: builtin/commit.c:1291
+#: builtin/commit.c:1356
msgid "detached HEAD"
-msgstr ""
+msgstr "HEAD détachée"
-#: builtin/commit.c:1293
+#: builtin/commit.c:1358
msgid " (root-commit)"
-msgstr ""
+msgstr " (commit racine)"
-#: builtin/commit.c:1360
+#: builtin/commit.c:1425
msgid "suppress summary after successful commit"
-msgstr ""
+msgstr "supprimer le résumé après une validation réussie"
-#: builtin/commit.c:1361
+#: builtin/commit.c:1426
msgid "show diff in commit message template"
-msgstr ""
+msgstr "afficher les diff dans le modèle de message de validation"
-#: builtin/commit.c:1363
+#: builtin/commit.c:1428
msgid "Commit message options"
-msgstr ""
+msgstr "Options du message de validation"
-#: builtin/commit.c:1364 builtin/tag.c:457
+#: builtin/commit.c:1429 builtin/tag.c:457
msgid "read message from file"
-msgstr ""
+msgstr "lire le message depuis un fichier"
-#: builtin/commit.c:1365
+#: builtin/commit.c:1430
msgid "author"
-msgstr ""
+msgstr "auteur"
-#: builtin/commit.c:1365
+#: builtin/commit.c:1430
msgid "override author for commit"
-msgstr ""
+msgstr "remplacer l'auteur pour la validation"
-#: builtin/commit.c:1366 builtin/gc.c:178
+#: builtin/commit.c:1431 builtin/gc.c:178
msgid "date"
-msgstr ""
+msgstr "date"
-#: builtin/commit.c:1366
+#: builtin/commit.c:1431
msgid "override date for commit"
-msgstr ""
+msgstr "remplacer la date pour la validation"
-#: builtin/commit.c:1367 builtin/merge.c:208 builtin/notes.c:533
-#: builtin/notes.c:690 builtin/tag.c:455
+#: builtin/commit.c:1432 builtin/merge.c:223 builtin/notes.c:405
+#: builtin/notes.c:562 builtin/tag.c:455
msgid "message"
-msgstr ""
+msgstr "message"
-#: builtin/commit.c:1367
+#: builtin/commit.c:1432
msgid "commit message"
-msgstr ""
+msgstr "message de validation"
-#: builtin/commit.c:1368
+#: builtin/commit.c:1433
msgid "reuse and edit message from specified commit"
-msgstr ""
+msgstr "réutiliser et éditer le message du commit spécifié"
-#: builtin/commit.c:1369
+#: builtin/commit.c:1434
msgid "reuse message from specified commit"
-msgstr ""
+msgstr "réutiliser le message du commit spécifié"
-#: builtin/commit.c:1370
+#: builtin/commit.c:1435
msgid "use autosquash formatted message to fixup specified commit"
msgstr ""
+"utiliser un message formaté par autosquash pour corriger le commit spécifié"
-#: builtin/commit.c:1371
+#: builtin/commit.c:1436
msgid "use autosquash formatted message to squash specified commit"
msgstr ""
+"utiliser un message formaté par autosquash pour compresser le commit spécifié"
-#: builtin/commit.c:1372
+#: builtin/commit.c:1437
msgid "the commit is authored by me now (used with -C/-c/--amend)"
msgstr ""
+"à présent je suis l'auteur de la validation (utilisé avec -C/-c/--amend)"
-#: builtin/commit.c:1373 builtin/log.c:1113 builtin/revert.c:109
+#: builtin/commit.c:1438 builtin/log.c:1160 builtin/revert.c:111
msgid "add Signed-off-by:"
-msgstr ""
+msgstr "ajouter une entrée Signed-off-by :"
-#: builtin/commit.c:1374
+#: builtin/commit.c:1439
msgid "use specified template file"
-msgstr ""
+msgstr "utiliser le fichier de modèle spécifié"
-#: builtin/commit.c:1375
+#: builtin/commit.c:1440
msgid "force edit of commit"
-msgstr ""
+msgstr "forcer l'édition du commit"
-#: builtin/commit.c:1376
+#: builtin/commit.c:1441
msgid "default"
-msgstr ""
+msgstr "défaut"
-#: builtin/commit.c:1376 builtin/tag.c:460
+#: builtin/commit.c:1441 builtin/tag.c:460
msgid "how to strip spaces and #comments from message"
-msgstr ""
+msgstr "comment éliminer les espaces et les commentaires # du message"
-#: builtin/commit.c:1377
+#: builtin/commit.c:1442
msgid "include status in commit message template"
-msgstr ""
+msgstr "inclure le statut dans le modèle de message de validation"
-#: builtin/commit.c:1378 builtin/merge.c:215 builtin/tag.c:461
+#: builtin/commit.c:1443 builtin/merge.c:230 builtin/tag.c:461
msgid "key id"
-msgstr ""
+msgstr "identifiant de clé"
-#: builtin/commit.c:1379 builtin/merge.c:216
+#: builtin/commit.c:1444 builtin/merge.c:231
msgid "GPG sign commit"
-msgstr ""
+msgstr "signer la validation avec GPG"
#. end commit message options
-#: builtin/commit.c:1382
+#: builtin/commit.c:1447
msgid "Commit contents options"
-msgstr ""
+msgstr "Valider les options des contenus"
-#: builtin/commit.c:1383
+#: builtin/commit.c:1448
msgid "commit all changed files"
-msgstr ""
+msgstr "valider tous les fichiers modifiés"
-#: builtin/commit.c:1384
+#: builtin/commit.c:1449
msgid "add specified files to index for commit"
-msgstr ""
+msgstr "ajouter les fichiers spécifiés à l'index pour la validation"
-#: builtin/commit.c:1385
+#: builtin/commit.c:1450
msgid "interactively add files"
-msgstr ""
+msgstr "ajouter des fichiers en mode interactif"
-#: builtin/commit.c:1386
+#: builtin/commit.c:1451
msgid "interactively add changes"
-msgstr ""
+msgstr "ajouter les modifications en mode interactif"
-#: builtin/commit.c:1387
+#: builtin/commit.c:1452
msgid "commit only specified files"
-msgstr ""
+msgstr "valider seulement les fichiers spécifiés"
-#: builtin/commit.c:1388
+#: builtin/commit.c:1453
msgid "bypass pre-commit hook"
-msgstr ""
+msgstr "éviter d'utiliser le crochet pre-commit"
-#: builtin/commit.c:1389
+#: builtin/commit.c:1454
msgid "show what would be committed"
-msgstr ""
+msgstr "afficher ce qui serait validé"
-#: builtin/commit.c:1400
+#: builtin/commit.c:1465
msgid "amend previous commit"
-msgstr ""
+msgstr "corriger la validation précédente"
-#: builtin/commit.c:1401
+#: builtin/commit.c:1466
msgid "bypass post-rewrite hook"
-msgstr ""
+msgstr "éviter d'utiliser le crochet post-rewrite"
-#: builtin/commit.c:1406
+#: builtin/commit.c:1471
msgid "ok to record an empty change"
-msgstr ""
+msgstr "accepter d'enregistrer une modification vide"
-#: builtin/commit.c:1409
+#: builtin/commit.c:1474
msgid "ok to record a change with an empty message"
-msgstr ""
+msgstr "accepter d'enregistrer une modification avec un message vide"
-#: builtin/commit.c:1441
+#: builtin/commit.c:1507
msgid "could not parse HEAD commit"
-msgstr ""
+msgstr "impossible d'analyser le commit HEAD"
-#: builtin/commit.c:1479 builtin/merge.c:510
+#: builtin/commit.c:1545 builtin/merge.c:525
#, c-format
msgid "could not open '%s' for reading"
-msgstr ""
+msgstr "impossible d'ouvrir '%s' en lecture"
-#: builtin/commit.c:1486
+#: builtin/commit.c:1552
#, c-format
msgid "Corrupt MERGE_HEAD file (%s)"
-msgstr ""
+msgstr "Fichier MERGE_HEAD corrompu (%s)"
-#: builtin/commit.c:1493
+#: builtin/commit.c:1559
msgid "could not read MERGE_MODE"
-msgstr ""
+msgstr "impossible de lire MERGE_MODE"
-#: builtin/commit.c:1512
+#: builtin/commit.c:1578
#, c-format
msgid "could not read commit message: %s"
-msgstr ""
+msgstr "impossible de lire le message de validation : %s"
-#: builtin/commit.c:1526
+#: builtin/commit.c:1592
#, c-format
msgid "Aborting commit; you did not edit the message.\n"
-msgstr ""
+msgstr "Abandon de la validation ; vous n'avez pas édité le message\n"
-#: builtin/commit.c:1531
+#: builtin/commit.c:1597
#, c-format
msgid "Aborting commit due to empty commit message.\n"
-msgstr ""
+msgstr "Abandon de la validation du à un message de validation vide\n"
-#: builtin/commit.c:1546 builtin/merge.c:847 builtin/merge.c:872
+#: builtin/commit.c:1612 builtin/merge.c:861 builtin/merge.c:886
msgid "failed to write commit object"
-msgstr ""
+msgstr "échec de l'écriture de l'objet commit"
-#: builtin/commit.c:1567
+#: builtin/commit.c:1633
msgid "cannot lock HEAD ref"
-msgstr ""
+msgstr "impossible de verrouiller la référence HEAD"
-#: builtin/commit.c:1571
+#: builtin/commit.c:1637
msgid "cannot update HEAD ref"
-msgstr ""
+msgstr "impossible de mettre à jour la référence HEAD"
-#: builtin/commit.c:1582
+#: builtin/commit.c:1648
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 ""
+"Le dépôt a été mis à jour, mais impossible d'écrire le fichier\n"
+"new_index. Vérifiez que le disque n'est pas plein ou que le quota\n"
+"n'a pas été dépassé, puis lancez \"git reset HEAD\" pour réparer."
#: builtin/config.c:7
msgid "git config [options]"
-msgstr ""
+msgstr "git config [options]"
-#: builtin/config.c:51
+#: builtin/config.c:52
msgid "Config file location"
-msgstr ""
+msgstr "Emplacement du fichier de configuration"
-#: builtin/config.c:52
+#: builtin/config.c:53
msgid "use global config file"
-msgstr ""
+msgstr "utiliser les fichier de configuration global"
-#: builtin/config.c:53
+#: builtin/config.c:54
msgid "use system config file"
-msgstr ""
+msgstr "utiliser le fichier de configuration du système"
-#: builtin/config.c:54
+#: builtin/config.c:55
msgid "use repository config file"
-msgstr ""
+msgstr "utiliser le fichier de configuration du dépôt"
-#: builtin/config.c:55
+#: builtin/config.c:56
msgid "use given config file"
-msgstr ""
+msgstr "utiliser le fichier de configuration spécifié"
-#: builtin/config.c:56
-msgid "Action"
-msgstr ""
+#: builtin/config.c:57
+msgid "blob-id"
+msgstr "blob-id"
#: builtin/config.c:57
-msgid "get value: name [value-regex]"
-msgstr ""
+msgid "read config from given blob object"
+msgstr "lire la configuration depuis l'objet blob fourni"
#: builtin/config.c:58
-msgid "get all values: key [value-regex]"
-msgstr ""
+msgid "Action"
+msgstr "Action"
#: builtin/config.c:59
-msgid "get values for regexp: name-regex [value-regex]"
-msgstr ""
+msgid "get value: name [value-regex]"
+msgstr "obtenir la valeur : nom [regex-de-valeur]"
#: builtin/config.c:60
-msgid "replace all matching variables: name value [value_regex]"
-msgstr ""
+msgid "get all values: key [value-regex]"
+msgstr "obtenir toutes le valeurs : clé [regex-de-valeur]"
#: builtin/config.c:61
-msgid "add a new variable: name value"
-msgstr ""
+msgid "get values for regexp: name-regex [value-regex]"
+msgstr "obtenir les valeur pour la regexp : regex-de-nom [regex-de-valeur]"
#: builtin/config.c:62
-msgid "remove a variable: name [value-regex]"
+msgid "replace all matching variables: name value [value_regex]"
msgstr ""
+"remplacer toutes les variables correspondant : nom valeur [regex-de-valeur]"
#: builtin/config.c:63
-msgid "remove all matches: name [value-regex]"
-msgstr ""
+msgid "add a new variable: name value"
+msgstr "ajouter une nouvelle variable : nom valeur"
#: builtin/config.c:64
-msgid "rename section: old-name new-name"
-msgstr ""
+msgid "remove a variable: name [value-regex]"
+msgstr "supprimer une variable : nom [regex-de-valeur]"
#: builtin/config.c:65
-msgid "remove a section: name"
-msgstr ""
+msgid "remove all matches: name [value-regex]"
+msgstr "supprimer toutes les correspondances nom [regex-de-valeur]"
#: builtin/config.c:66
-msgid "list all"
-msgstr ""
+msgid "rename section: old-name new-name"
+msgstr "renommer une section : ancien-nom nouveau-nom"
#: builtin/config.c:67
+msgid "remove a section: name"
+msgstr "supprimer une section : nom"
+
+#: builtin/config.c:68
+msgid "list all"
+msgstr "afficher tout"
+
+#: builtin/config.c:69
msgid "open an editor"
-msgstr ""
+msgstr "ouvrir un éditeur"
-#: builtin/config.c:68 builtin/config.c:69
+#: builtin/config.c:70 builtin/config.c:71
msgid "slot"
-msgstr ""
+msgstr "emplacement"
-#: builtin/config.c:68
+#: builtin/config.c:70
msgid "find the color configured: [default]"
-msgstr ""
+msgstr "trouver la couleur configurée : [par défaut]"
-#: builtin/config.c:69
+#: builtin/config.c:71
msgid "find the color setting: [stdout-is-tty]"
-msgstr ""
+msgstr "trouver le réglage de la couleur : [stdout-est-tty]"
-#: builtin/config.c:70
+#: builtin/config.c:72
msgid "Type"
-msgstr ""
+msgstr "Type"
-#: builtin/config.c:71
+#: builtin/config.c:73
msgid "value is \"true\" or \"false\""
-msgstr ""
+msgstr "la valeur est \"true\" (vrai) our \"false\" (faux)"
-#: builtin/config.c:72
+#: builtin/config.c:74
msgid "value is decimal number"
-msgstr ""
+msgstr "la valeur est un nombre décimal"
-#: builtin/config.c:73
+#: builtin/config.c:75
msgid "value is --bool or --int"
-msgstr ""
+msgstr "la valeur est --bool ou --int"
-#: builtin/config.c:74
+#: builtin/config.c:76
msgid "value is a path (file or directory name)"
-msgstr ""
+msgstr "la valeur est un chemin (vers un fichier ou un répertoire)"
-#: builtin/config.c:75
+#: builtin/config.c:77
msgid "Other"
-msgstr ""
+msgstr "Autre"
-#: builtin/config.c:76
+#: builtin/config.c:78
msgid "terminate values with NUL byte"
-msgstr ""
+msgstr "terminer les valeurs avec un caractère NUL"
-#: builtin/config.c:77
+#: builtin/config.c:79
msgid "respect include directives on lookup"
-msgstr ""
+msgstr "respecter les directives d'inclusion lors de la recherche"
#: builtin/count-objects.c:82
msgid "git count-objects [-v] [-H | --human-readable]"
-msgstr ""
+msgstr "git count-objects [-v] [-H | --human-readable]"
#: builtin/count-objects.c:97
msgid "print sizes in human readable format"
-msgstr ""
+msgstr "affiche les tailles dans un format humainement lisible"
#: builtin/describe.c:15
-msgid "git describe [options] <committish>*"
-msgstr ""
+msgid "git describe [options] <commit-ish>*"
+msgstr "git describe [options] <commit ou apparenté>*"
-#: builtin/describe.c:16
+#: builtin/describe.c:17
msgid "git describe [options] --dirty"
-msgstr ""
+msgstr "git describe [options] --dirty"
-#: builtin/describe.c:233
+#: builtin/describe.c:237
#, c-format
msgid "annotated tag %s not available"
-msgstr ""
+msgstr "l'étiquette annotée %s n'est pas disponible"
-#: builtin/describe.c:237
+#: builtin/describe.c:241
#, c-format
msgid "annotated tag %s has no embedded name"
-msgstr ""
+msgstr "l'étiquette annotée %s n'a pas de nom embarqué"
-#: builtin/describe.c:239
+#: builtin/describe.c:243
#, c-format
msgid "tag '%s' is really '%s' here"
-msgstr ""
+msgstr "l'étiquette '%s' est en fait '%s'"
-#: builtin/describe.c:266
+#: builtin/describe.c:270
#, c-format
msgid "Not a valid object name %s"
-msgstr ""
+msgstr "%s n'est pas un nom d'objet valide"
-#: builtin/describe.c:269
+#: builtin/describe.c:273
#, c-format
msgid "%s is not a valid '%s' object"
msgstr "%s n'est pas un objet '%s' valide"
-#: builtin/describe.c:286
+#: builtin/describe.c:290
#, c-format
msgid "no tag exactly matches '%s'"
-msgstr ""
+msgstr "aucune étiquette ne correspond parfaitement à '%s'"
-#: builtin/describe.c:288
+#: builtin/describe.c:292
#, c-format
msgid "searching to describe %s\n"
-msgstr ""
+msgstr "recherche de la description de %s\n"
-#: builtin/describe.c:328
+#: builtin/describe.c:332
#, c-format
msgid "finished search at %s\n"
-msgstr ""
+msgstr "recherche terminée à %s\n"
-#: builtin/describe.c:352
+#: builtin/describe.c:359
#, c-format
msgid ""
"No annotated tags can describe '%s'.\n"
"However, there were unannotated tags: try --tags."
msgstr ""
+"Aucune étiquette annotée ne peut décrire '%s'.\n"
+"Cependant, il existe des étiquettes non-annotées : essayez avec --tags."
-#: builtin/describe.c:356
+#: builtin/describe.c:363
#, c-format
msgid ""
"No tags can describe '%s'.\n"
"Try --always, or create some tags."
msgstr ""
+"Aucune étiquette ne peut décrire '%s'.\n"
+"Essayez --always, ou créez des étiquettes."
-#: builtin/describe.c:377
+#: builtin/describe.c:384
#, c-format
msgid "traversed %lu commits\n"
-msgstr ""
+msgstr "%lu commits parcourus\n"
-#: builtin/describe.c:380
+#: builtin/describe.c:387
#, c-format
msgid ""
"more than %i tags found; listed %i most recent\n"
"gave up search at %s\n"
msgstr ""
+"plus de %i étiquettes ont été trouvées; seules les %i plus récentes sont "
+"affichées\n"
+"abandon de la recherche à %s\n"
-#: builtin/describe.c:402
+#: builtin/describe.c:409
msgid "find the tag that comes after the commit"
-msgstr ""
+msgstr "rechercher l'étiquette qui suit le commit"
-#: builtin/describe.c:403
+#: builtin/describe.c:410
msgid "debug search strategy on stderr"
-msgstr ""
+msgstr "déboguer la stratégie de recherche sur stderr"
-#: builtin/describe.c:404
+#: builtin/describe.c:411
msgid "use any ref"
-msgstr ""
+msgstr "utiliser n'importe quelle référence"
-#: builtin/describe.c:405
+#: builtin/describe.c:412
msgid "use any tag, even unannotated"
-msgstr ""
+msgstr "utiliser n'importe quelle étiquette, même non-annotée"
-#: builtin/describe.c:406
+#: builtin/describe.c:413
msgid "always use long format"
-msgstr ""
+msgstr "toujours utiliser le format long"
-#: builtin/describe.c:409
+#: builtin/describe.c:414
+msgid "only follow first parent"
+msgstr "ne suivre que le premier parent"
+
+#: builtin/describe.c:417
msgid "only output exact matches"
-msgstr ""
+msgstr "n'afficher que les correspondances exactes"
-#: builtin/describe.c:411
+#: builtin/describe.c:419
msgid "consider <n> most recent tags (default: 10)"
msgstr ""
+"considérer uniquement les <n> étiquettes le plus récentes (défaut : 10)"
-#: builtin/describe.c:413
+#: builtin/describe.c:421
msgid "only consider tags matching <pattern>"
-msgstr ""
+msgstr "ne considérer que les étiquettes correspondant à <motif>"
-#: builtin/describe.c:415 builtin/name-rev.c:238
+#: builtin/describe.c:423 builtin/name-rev.c:322
msgid "show abbreviated commit object as fallback"
-msgstr ""
+msgstr "afficher les objets commits abrégés en dernier recours"
-#: builtin/describe.c:416
+#: builtin/describe.c:424
msgid "mark"
-msgstr ""
+msgstr "marque"
-#: builtin/describe.c:417
+#: builtin/describe.c:425
msgid "append <mark> on dirty working tree (default: \"-dirty\")"
-msgstr ""
+msgstr "ajouter <marque> si la copie de travail est sale (défaut : \"-dirty\")"
-#: builtin/describe.c:435
+#: builtin/describe.c:443
msgid "--long is incompatible with --abbrev=0"
-msgstr ""
+msgstr "--long et --abbrev=0 sont incompatibles"
-#: builtin/describe.c:461
+#: builtin/describe.c:469
msgid "No names found, cannot describe anything."
-msgstr ""
+msgstr "aucun nom trouvé, impossible de décrire quoi que ce soit."
#: builtin/describe.c:481
-msgid "--dirty is incompatible with committishes"
-msgstr ""
+msgid "--dirty is incompatible with commit-ishes"
+msgstr "--dirty est incompatible avec la spécification de commits ou assimilés"
#: builtin/diff.c:79
#, c-format
msgid "'%s': not a regular file or symlink"
-msgstr ""
+msgstr "'%s' : n'est pas un fichier régulier ni un lien symbolique"
-#: builtin/diff.c:228
+#: builtin/diff.c:230
#, c-format
msgid "invalid option: %s"
-msgstr ""
+msgstr "option invalide : %s"
-#: builtin/diff.c:305
+#: builtin/diff.c:307
msgid "Not a git repository"
-msgstr ""
+msgstr "Ce n'est pas un dépôt git !"
-#: builtin/diff.c:348
+#: builtin/diff.c:350
#, c-format
msgid "invalid object '%s' given."
-msgstr ""
+msgstr "objet spécifié '%s' invalide."
-#: builtin/diff.c:353
-#, c-format
-msgid "more than %d trees given: '%s'"
-msgstr ""
-
-#: builtin/diff.c:363
+#: builtin/diff.c:359
#, c-format
msgid "more than two blobs given: '%s'"
-msgstr ""
+msgstr "plus de deux blobs spécifiés : '%s'"
-#: builtin/diff.c:371
+#: builtin/diff.c:366
#, c-format
msgid "unhandled object '%s' given."
-msgstr ""
+msgstr "objet non géré '%s' spécifié."
#: builtin/fast-export.c:22
msgid "git fast-export [rev-list-opts]"
-msgstr ""
+msgstr "git fast-export [options-de-liste-de-révisions]"
-#: builtin/fast-export.c:658
+#: builtin/fast-export.c:666
msgid "show progress after <n> objects"
-msgstr ""
+msgstr "afficher la progression après <n> objets"
-#: builtin/fast-export.c:660
+#: builtin/fast-export.c:668
msgid "select handling of signed tags"
-msgstr ""
+msgstr "sélectionner la gestion des étiquettes signées"
-#: builtin/fast-export.c:663
+#: builtin/fast-export.c:671
msgid "select handling of tags that tag filtered objects"
msgstr ""
+"sélectionner la gestion des étiquettes qui pointent sur des objets filtrés"
-#: builtin/fast-export.c:666
+#: builtin/fast-export.c:674
msgid "Dump marks to this file"
-msgstr ""
+msgstr "Enregistrer les marques dans ce fichier"
-#: builtin/fast-export.c:668
+#: builtin/fast-export.c:676
msgid "Import marks from this file"
-msgstr ""
+msgstr "importer les marques depuis ce fichier"
-#: builtin/fast-export.c:670
+#: builtin/fast-export.c:678
msgid "Fake a tagger when tags lack one"
-msgstr ""
+msgstr "falsifier un auteur d'étiquette si l'étiquette n'en présente pas"
-#: builtin/fast-export.c:672
+#: builtin/fast-export.c:680
msgid "Output full tree for each commit"
-msgstr ""
+msgstr "Afficher l'arbre complet pour chaque commit"
-#: builtin/fast-export.c:674
+#: builtin/fast-export.c:682
msgid "Use the done feature to terminate the stream"
-msgstr ""
+msgstr "Utiliser la fonction \"done\" pour terminer le flux"
-#: builtin/fast-export.c:675
+#: builtin/fast-export.c:683
msgid "Skip output of blob data"
-msgstr ""
+msgstr "Sauter l'affichage de données de blob"
#: builtin/fetch.c:20
msgid "git fetch [<options>] [<repository> [<refspec>...]]"
-msgstr ""
+msgstr "git fetch [<options>] [<dépôt> [<spécification-de-référence>...]]"
#: builtin/fetch.c:21
msgid "git fetch [<options>] <group>"
-msgstr ""
+msgstr "git fetch [<options>] <groupe>"
#: builtin/fetch.c:22
msgid "git fetch --multiple [<options>] [(<repository> | <group>)...]"
-msgstr ""
+msgstr "git fetch --multiple [<options>] [(<dépôt> | <groupe>)...]"
#: builtin/fetch.c:23
msgid "git fetch --all [<options>]"
-msgstr ""
+msgstr "git fetch --all [<options>]"
#: builtin/fetch.c:60
msgid "fetch from all remotes"
-msgstr ""
+msgstr "récupérer depuis tous le dépôts distants"
#: builtin/fetch.c:62
msgid "append to .git/FETCH_HEAD instead of overwriting"
-msgstr ""
+msgstr "ajouter à .git/FETCH_HEAD au lieu de l'écraser"
#: builtin/fetch.c:64
msgid "path to upload pack on remote end"
-msgstr ""
+msgstr "chemin vers lequel télécharger le paquet sur le poste distant"
#: builtin/fetch.c:65
msgid "force overwrite of local branch"
-msgstr ""
+msgstr "forcer l'écrasement de la branche locale"
#: builtin/fetch.c:67
msgid "fetch from multiple remotes"
-msgstr ""
+msgstr "récupérer depuis plusieurs dépôts distants"
#: builtin/fetch.c:69
msgid "fetch all tags and associated objects"
-msgstr ""
+msgstr "récupérer toutes les étiquettes et leurs objets associés"
#: builtin/fetch.c:71
msgid "do not fetch all tags (--no-tags)"
-msgstr ""
+msgstr "ne pas récupérer toutes les étiquettes (--no-tags)"
#: builtin/fetch.c:73
msgid "prune remote-tracking branches no longer on remote"
msgstr ""
+"éliminer les branches de suivi distant si la branche n'existe plus dans le "
+"dépôt distant"
#: builtin/fetch.c:74
msgid "on-demand"
-msgstr ""
+msgstr "à la demande"
#: builtin/fetch.c:75
msgid "control recursive fetching of submodules"
-msgstr ""
+msgstr "contrôler la récupération récursive dans les sous-modules"
#: builtin/fetch.c:79
msgid "keep downloaded pack"
-msgstr ""
+msgstr "conserver le paquet téléchargé"
#: builtin/fetch.c:81
msgid "allow updating of HEAD ref"
-msgstr ""
+msgstr "permettre la mise à jour de la référence HEAD"
#: builtin/fetch.c:84
msgid "deepen history of shallow clone"
-msgstr ""
+msgstr "approfondir l'historique d'un clone superficiel"
#: builtin/fetch.c:86
msgid "convert to a complete repository"
-msgstr ""
+msgstr "convertir en un dépôt complet"
-#: builtin/fetch.c:88 builtin/log.c:1130
+#: builtin/fetch.c:88 builtin/log.c:1177
msgid "dir"
-msgstr ""
+msgstr "dir"
#: builtin/fetch.c:89
msgid "prepend this to submodule path output"
-msgstr ""
+msgstr "préfixer ceci à la sortie du chemin du sous-module"
#: builtin/fetch.c:92
msgid "default mode for recursion"
-msgstr ""
+msgstr "mode par défaut pour la récursion"
-#: builtin/fetch.c:204
+#: builtin/fetch.c:220
msgid "Couldn't find remote ref HEAD"
-msgstr ""
+msgstr "impossible de trouver la référence HEAD distante"
-#: builtin/fetch.c:257
+#: builtin/fetch.c:273
#, c-format
msgid "object %s not found"
-msgstr ""
+msgstr "objet %s non trouvé"
-#: builtin/fetch.c:262
+#: builtin/fetch.c:278
msgid "[up to date]"
-msgstr ""
+msgstr "[à jour]"
-#: builtin/fetch.c:276
+#: builtin/fetch.c:292
#, c-format
msgid "! %-*s %-*s -> %s (can't fetch in current branch)"
-msgstr ""
+msgstr "! %-*s %-*s -> %s (impossible de récupérer la branche actuelle)"
-#: builtin/fetch.c:277 builtin/fetch.c:363
+#: builtin/fetch.c:293 builtin/fetch.c:379
msgid "[rejected]"
-msgstr ""
+msgstr "[rejeté]"
-#: builtin/fetch.c:288
+#: builtin/fetch.c:304
msgid "[tag update]"
-msgstr ""
+msgstr "[mise à jour de l'étiquette]"
-#: builtin/fetch.c:290 builtin/fetch.c:325 builtin/fetch.c:343
+#: builtin/fetch.c:306 builtin/fetch.c:341 builtin/fetch.c:359
msgid " (unable to update local ref)"
-msgstr ""
+msgstr " (impossible de mettre à jour la référence locale)"
-#: builtin/fetch.c:308
+#: builtin/fetch.c:324
msgid "[new tag]"
-msgstr ""
+msgstr "[nouvelle étiquette]"
-#: builtin/fetch.c:311
+#: builtin/fetch.c:327
msgid "[new branch]"
-msgstr ""
+msgstr "[nouvelle branche]"
-#: builtin/fetch.c:314
+#: builtin/fetch.c:330
msgid "[new ref]"
-msgstr ""
+msgstr "[nouvelle référence]"
-#: builtin/fetch.c:359
+#: builtin/fetch.c:375
msgid "unable to update local ref"
-msgstr ""
+msgstr "impossible de mettre à jour la référence locale"
-#: builtin/fetch.c:359
+#: builtin/fetch.c:375
msgid "forced update"
-msgstr ""
+msgstr "mise à jour forcée"
-#: builtin/fetch.c:365
+#: builtin/fetch.c:381
msgid "(non-fast-forward)"
-msgstr ""
+msgstr "(pas d'avance rapide)"
-#: builtin/fetch.c:396 builtin/fetch.c:688
+#: builtin/fetch.c:412 builtin/fetch.c:718
#, c-format
msgid "cannot open %s: %s\n"
msgstr "impossible d'ouvrir %s : %s\n"
-#: builtin/fetch.c:405
+#: builtin/fetch.c:421
#, c-format
msgid "%s did not send all necessary objects\n"
msgstr "%s n'a pas envoyé tous les objets nécessaires\n"
-#: builtin/fetch.c:491
+#: builtin/fetch.c:520
#, c-format
msgid "From %.*s\n"
-msgstr ""
+msgstr "Depuis %.*s\n"
-#: builtin/fetch.c:502
+#: builtin/fetch.c:531
#, c-format
msgid ""
"some local refs could not be updated; try running\n"
" 'git remote prune %s' to remove any old, conflicting branches"
msgstr ""
+"des références locales n'ont pas pu être mises à jour ; essayez de lancer\n"
+" 'git remote prune %s' pour supprimer des branches anciennes en conflit"
-#: builtin/fetch.c:552
+#: builtin/fetch.c:581
#, c-format
msgid " (%s will become dangling)"
-msgstr ""
+msgstr " (%s sera en suspens)"
-#: builtin/fetch.c:553
+#: builtin/fetch.c:582
#, c-format
msgid " (%s has become dangling)"
-msgstr ""
+msgstr " (%s est devenu en suspens)"
-#: builtin/fetch.c:560
+#: builtin/fetch.c:589
msgid "[deleted]"
-msgstr ""
+msgstr "[supprimé]"
-#: builtin/fetch.c:561 builtin/remote.c:1055
+#: builtin/fetch.c:590 builtin/remote.c:1055
msgid "(none)"
-msgstr ""
+msgstr "(aucun(e))"
-#: builtin/fetch.c:678
+#: builtin/fetch.c:708
#, c-format
msgid "Refusing to fetch into current branch %s of non-bare repository"
-msgstr ""
+msgstr "Refus de récupérer dans la branche courant %s d'un dépôt non nu"
-#: builtin/fetch.c:712
+#: builtin/fetch.c:742
#, c-format
msgid "Don't know how to fetch from %s"
-msgstr ""
+msgstr "Je ne sais pas récupérer depuis %s"
-#: builtin/fetch.c:789
+#: builtin/fetch.c:823
#, c-format
msgid "Option \"%s\" value \"%s\" is not valid for %s"
-msgstr ""
+msgstr "La valeur \"%2$s\" de l'option \"%1$s\" est invalide pour %3$s"
-#: builtin/fetch.c:792
+#: builtin/fetch.c:826
#, c-format
msgid "Option \"%s\" is ignored for %s\n"
-msgstr ""
+msgstr "L'option \"%s\" est ignorée pour %s\n"
-#: builtin/fetch.c:894
+#: builtin/fetch.c:928
#, c-format
msgid "Fetching %s\n"
-msgstr ""
+msgstr "Récupération de %s\n"
-#: builtin/fetch.c:896 builtin/remote.c:100
+#: builtin/fetch.c:930 builtin/remote.c:100
#, c-format
msgid "Could not fetch %s"
-msgstr ""
+msgstr "Impossible de récupérer %s"
-#: builtin/fetch.c:915
+#: builtin/fetch.c:949
msgid ""
"No remote repository specified. Please, specify either a URL or a\n"
"remote name from which new revisions should be fetched."
msgstr ""
+"Aucun dépôt distant spécifié. Veuillez spécifier une URL ou un nom\n"
+"distant depuis lesquels les nouvelles révisions devraient être récupérées."
-#: builtin/fetch.c:935
+#: builtin/fetch.c:969
msgid "You need to specify a tag name."
-msgstr ""
+msgstr "Vous devez spécifier un nom d'étiquette."
-#: builtin/fetch.c:981
+#: builtin/fetch.c:1015
msgid "--depth and --unshallow cannot be used together"
-msgstr ""
+msgstr "--depth et --unshallow ne peuvent pas être utilisés ensemble"
-#: builtin/fetch.c:983
+#: builtin/fetch.c:1017
msgid "--unshallow on a complete repository does not make sense"
-msgstr ""
+msgstr "--unshallow sur un dépôt complet n'a pas de sens"
-#: builtin/fetch.c:1002
+#: builtin/fetch.c:1036
msgid "fetch --all does not take a repository argument"
-msgstr ""
+msgstr "fetch --all n'accepte pas d'argument de dépôt"
-#: builtin/fetch.c:1004
+#: builtin/fetch.c:1038
msgid "fetch --all does not make sense with refspecs"
-msgstr ""
+msgstr "fetch --all n'a pas de sens avec des spécifications de référence"
-#: builtin/fetch.c:1015
+#: builtin/fetch.c:1049
#, c-format
msgid "No such remote or remote group: %s"
-msgstr ""
+msgstr "distant ou groupe distant inexistant : %s"
-#: builtin/fetch.c:1023
+#: builtin/fetch.c:1057
msgid "Fetching a group and specifying refspecs does not make sense"
msgstr ""
+"La récupération d'un groupe et les spécifications de référence n'ont pas de "
+"sens"
#: 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 <message>] [--log[=<n>]|--no-log] [--file <fichier>]"
-#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:701
-#: builtin/merge.c:188 builtin/show-branch.c:655 builtin/show-ref.c:175
-#: builtin/tag.c:446 parse-options.h:133 parse-options.h:239
+#: builtin/fmt-merge-msg.c:663 builtin/fmt-merge-msg.c:666 builtin/grep.c:700
+#: builtin/merge.c:203 builtin/show-branch.c:655 builtin/show-ref.c:179
+#: builtin/tag.c:446 parse-options.h:133 parse-options.h:243
msgid "n"
-msgstr ""
+msgstr "n"
#: builtin/fmt-merge-msg.c:664
msgid "populate log with at most <n> entries from shortlog"
-msgstr ""
+msgstr "peupler le journal avec au plus <n> éléments depuis le journal court"
#: builtin/fmt-merge-msg.c:667
msgid "alias for --log (deprecated)"
-msgstr ""
+msgstr "alias pour --log (obsolète)"
#: builtin/fmt-merge-msg.c:670
msgid "text"
-msgstr ""
+msgstr "texte"
#: builtin/fmt-merge-msg.c:671
msgid "use <text> as start of message"
-msgstr ""
+msgstr "utiliser <texte> comme début de message"
#: builtin/fmt-merge-msg.c:672
msgid "file to read from"
-msgstr ""
+msgstr "fichier d'où lire"
#: builtin/for-each-ref.c:979
msgid "git for-each-ref [options] [<pattern>]"
-msgstr ""
+msgstr "git for-each-ref [options] [<motif>]"
#: builtin/for-each-ref.c:994
msgid "quote placeholders suitably for shells"
-msgstr ""
+msgstr "échapper les champs réservés pour les interpréteurs de commandes"
#: builtin/for-each-ref.c:996
msgid "quote placeholders suitably for perl"
-msgstr ""
+msgstr "échapper les champs réservés pour perl"
#: builtin/for-each-ref.c:998
msgid "quote placeholders suitably for python"
-msgstr ""
+msgstr "échapper les champs réservés pour python"
#: builtin/for-each-ref.c:1000
msgid "quote placeholders suitably for tcl"
-msgstr ""
+msgstr "échapper les champs réservés pour tcl"
#: builtin/for-each-ref.c:1003
msgid "show only <n> matched refs"
-msgstr ""
+msgstr "n'afficher que <n> références correspondant"
#: builtin/for-each-ref.c:1004
msgid "format"
-msgstr ""
+msgstr "format"
#: builtin/for-each-ref.c:1004
msgid "format to use for the output"
-msgstr ""
+msgstr "format à utiliser pour la sortie"
#: builtin/for-each-ref.c:1005
msgid "key"
-msgstr ""
+msgstr "clé"
#: builtin/for-each-ref.c:1006
msgid "field name to sort on"
-msgstr ""
+msgstr "nom du champ servant à trier"
#: builtin/fsck.c:608
msgid "git fsck [options] [<object>...]"
-msgstr ""
+msgstr "git fsck [options] [<objet>...]"
#: builtin/fsck.c:614
msgid "show unreachable objects"
-msgstr ""
+msgstr "afficher les objets inaccessibles"
#: builtin/fsck.c:615
msgid "show dangling objects"
-msgstr ""
+msgstr "afficher les objets en suspens"
#: builtin/fsck.c:616
msgid "report tags"
-msgstr ""
+msgstr "afficher les étiquettes"
#: builtin/fsck.c:617
msgid "report root nodes"
-msgstr ""
+msgstr "signaler les nœuds racines"
#: builtin/fsck.c:618
msgid "make index objects head nodes"
-msgstr ""
+msgstr "considérer les objets de l'index comme nœuds tête"
+# translated from man page
#: builtin/fsck.c:619
msgid "make reflogs head nodes (default)"
-msgstr ""
+msgstr "considérer les reflogs comme nœuds tête (par défaut)"
#: builtin/fsck.c:620
msgid "also consider packs and alternate objects"
-msgstr ""
+msgstr "inspecter aussi les objets pack et alternatifs"
#: builtin/fsck.c:621
msgid "enable more strict checking"
-msgstr ""
+msgstr "activer une vérification plus strict"
#: builtin/fsck.c:623
msgid "write dangling objects in .git/lost-found"
-msgstr ""
+msgstr "écrire les objets en suspens dans .git/lost-found"
#: builtin/fsck.c:624 builtin/prune.c:134
msgid "show progress"
-msgstr ""
+msgstr "afficher la progression"
#: builtin/gc.c:22
msgid "git gc [options]"
-msgstr ""
+msgstr "git gc [options]"
#: builtin/gc.c:63
#, c-format
msgid "Invalid %s: '%s'"
-msgstr ""
+msgstr "%s invalide : '%s'"
#: builtin/gc.c:90
#, c-format
msgid "insanely long object directory %.*s"
-msgstr ""
+msgstr "objet répertoire démentiellement long %.*s"
#: builtin/gc.c:179
msgid "prune unreferenced objects"
-msgstr ""
+msgstr "éliminer les objets non référencés"
#: builtin/gc.c:181
msgid "be more thorough (increased runtime)"
-msgstr ""
+msgstr "être plus consciencieux (durée de traitement allongée)"
#: builtin/gc.c:182
msgid "enable auto-gc mode"
-msgstr ""
+msgstr "activer le mode auto-gc"
#: builtin/gc.c:222
#, c-format
"Auto packing the repository for optimum performance. You may also\n"
"run \"git gc\" manually. See \"git help gc\" for more information.\n"
msgstr ""
+"Compression automatique du dépôt pour une performance optimum. Vous pouvez "
+"aussi\n"
+"lancer \"git gc\" manuellement. Voir \"git help gc\" pour plus "
+"d'information.\n"
#: builtin/gc.c:249
msgid ""
"There are too many unreachable loose objects; run 'git prune' to remove them."
msgstr ""
+"Il y a trop d'objets seuls inaccessibles ; lancez 'git prune' pour les "
+"supprimer."
#: builtin/grep.c:22
msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
-msgstr ""
+msgstr "git grep [options] [-e] <motif> [<révision>...] [[--] <chemin>...]"
#: builtin/grep.c:217
#, c-format
msgid "grep: failed to create thread: %s"
-msgstr ""
+msgstr "grep : échec de création du fil: %s"
-#: builtin/grep.c:365
+#: builtin/grep.c:364
#, c-format
msgid "Failed to chdir: %s"
-msgstr ""
+msgstr "Échec de chdir: %s"
-#: builtin/grep.c:443 builtin/grep.c:478
+#: builtin/grep.c:442 builtin/grep.c:477
#, c-format
msgid "unable to read tree (%s)"
-msgstr ""
+msgstr "impossible de lire l'arbre (%s)"
-#: builtin/grep.c:493
+#: builtin/grep.c:492
#, c-format
msgid "unable to grep from object of type %s"
-msgstr ""
+msgstr "impossible de faire un grep sur un objet de type %s"
-#: builtin/grep.c:551
+#: builtin/grep.c:550
#, c-format
msgid "switch `%c' expects a numerical value"
-msgstr ""
+msgstr "l'option '%c' attend un valeur numérique"
-#: builtin/grep.c:568
+#: builtin/grep.c:567
#, c-format
msgid "cannot open '%s'"
-msgstr ""
+msgstr "impossible d'ouvrir '%s'"
-#: builtin/grep.c:643
+#: builtin/grep.c:642
msgid "search in index instead of in the work tree"
-msgstr ""
+msgstr "rechercher dans l'index plutôt que dans la copie de travail"
-#: builtin/grep.c:645
+#: builtin/grep.c:644
msgid "find in contents not managed by git"
-msgstr ""
+msgstr "rechercher dans les contenus non gérés par git"
-#: builtin/grep.c:647
+#: builtin/grep.c:646
msgid "search in both tracked and untracked files"
-msgstr ""
+msgstr "rechercher dans les fichiers suivis et non-suivis"
-#: builtin/grep.c:649
+#: builtin/grep.c:648
msgid "search also in ignored files"
-msgstr ""
+msgstr "rechercher aussi dans les fichiers ignorés"
-#: builtin/grep.c:652
+#: builtin/grep.c:651
msgid "show non-matching lines"
-msgstr ""
+msgstr "afficher les lignes qui ne correspondent pas"
-#: builtin/grep.c:654
+#: builtin/grep.c:653
msgid "case insensitive matching"
-msgstr ""
+msgstr "correspondance insensible à la casse"
-#: builtin/grep.c:656
+#: builtin/grep.c:655
msgid "match patterns only at word boundaries"
-msgstr ""
+msgstr "rechercher les motifs aux séparateurs de mots"
-#: builtin/grep.c:658
+#: builtin/grep.c:657
msgid "process binary files as text"
-msgstr ""
+msgstr "traiter les fichiers binaires comme texte"
-#: builtin/grep.c:660
+#: builtin/grep.c:659
msgid "don't match patterns in binary files"
-msgstr ""
+msgstr "ne pas chercher les motifs dans les fichiers binaires"
-#: builtin/grep.c:663
+#: builtin/grep.c:662
msgid "descend at most <depth> levels"
-msgstr ""
+msgstr "descendre au plus de <profondeur> dans l'arborescence"
-#: builtin/grep.c:667
+#: builtin/grep.c:666
msgid "use extended POSIX regular expressions"
-msgstr ""
+msgstr "utiliser des expressions régulières étendues POSIX"
-#: builtin/grep.c:670
+#: builtin/grep.c:669
msgid "use basic POSIX regular expressions (default)"
-msgstr ""
+msgstr "utiliser des expressions régulières basiques POSIX (par défaut)"
-#: builtin/grep.c:673
+#: builtin/grep.c:672
msgid "interpret patterns as fixed strings"
-msgstr ""
+msgstr "interpréter les motifs comme de chaînes fixes"
-#: builtin/grep.c:676
+#: builtin/grep.c:675
msgid "use Perl-compatible regular expressions"
-msgstr ""
+msgstr "utiliser des expressions régulières compatibles avec Perl"
-#: builtin/grep.c:679
+#: builtin/grep.c:678
msgid "show line numbers"
-msgstr ""
+msgstr "afficher les numéros de ligne"
-#: builtin/grep.c:680
+#: builtin/grep.c:679
msgid "don't show filenames"
-msgstr ""
+msgstr "ne pas pas afficher les noms de fichier"
-#: builtin/grep.c:681
+#: builtin/grep.c:680
msgid "show filenames"
-msgstr ""
+msgstr "afficher les noms de fichier"
-#: builtin/grep.c:683
+#: builtin/grep.c:682
msgid "show filenames relative to top directory"
-msgstr ""
+msgstr "afficher les noms de fichiers relativement au répertoire de base"
-#: builtin/grep.c:685
+#: builtin/grep.c:684
msgid "show only filenames instead of matching lines"
-msgstr ""
+msgstr "n'afficher que les noms de fichiers au lieu des lignes correspondant"
-#: builtin/grep.c:687
+#: builtin/grep.c:686
msgid "synonym for --files-with-matches"
-msgstr ""
+msgstr "synonyme pour --files-with-matches"
-#: builtin/grep.c:690
+#: builtin/grep.c:689
msgid "show only the names of files without match"
-msgstr ""
+msgstr "n'afficher que les noms des fichiers sans correspondance"
-#: builtin/grep.c:692
+#: builtin/grep.c:691
msgid "print NUL after filenames"
-msgstr ""
+msgstr "imprimer une caractère NUL après le noms de fichier"
-#: builtin/grep.c:694
+#: builtin/grep.c:693
msgid "show the number of matches instead of matching lines"
-msgstr ""
+msgstr "afficher le nombre de correspondances au lieu des lignes correspondant"
-#: builtin/grep.c:695
+#: builtin/grep.c:694
msgid "highlight matches"
-msgstr ""
+msgstr "mettre en évidence les correspondances"
-#: builtin/grep.c:697
+#: builtin/grep.c:696
msgid "print empty line between matches from different files"
msgstr ""
+"imprimer une ligne vide entre les correspondances de fichiers différents"
-#: builtin/grep.c:699
+#: builtin/grep.c:698
msgid "show filename only once above matches from same file"
msgstr ""
+"afficher le nom de fichier une fois au dessus des correspondances du même "
+"fichier"
-#: builtin/grep.c:702
+#: builtin/grep.c:701
msgid "show <n> context lines before and after matches"
-msgstr ""
+msgstr "afficher <n> lignes de contexte avant et après les correspondances"
-#: builtin/grep.c:705
+#: builtin/grep.c:704
msgid "show <n> context lines before matches"
-msgstr ""
+msgstr "afficher <n> lignes de contexte avant les correspondances"
-#: builtin/grep.c:707
+#: builtin/grep.c:706
msgid "show <n> context lines after matches"
-msgstr ""
+msgstr "afficher <n> lignes de contexte après les correspondances"
-#: builtin/grep.c:708
+#: builtin/grep.c:707
msgid "shortcut for -C NUM"
-msgstr ""
+msgstr "raccourci pour -C NUM"
-#: builtin/grep.c:711
+#: builtin/grep.c:710
msgid "show a line with the function name before matches"
msgstr ""
+"afficher une ligne avec le nom de la fonction avant les correspondances"
-#: builtin/grep.c:713
+#: builtin/grep.c:712
msgid "show the surrounding function"
-msgstr ""
+msgstr "afficher la fonction contenante"
-#: builtin/grep.c:716
+#: builtin/grep.c:715
msgid "read patterns from file"
-msgstr ""
+msgstr "lire les motifs depuis fichier"
-#: builtin/grep.c:718
+#: builtin/grep.c:717
msgid "match <pattern>"
-msgstr ""
+msgstr "rechercher <motif>"
-#: builtin/grep.c:720
+#: builtin/grep.c:719
msgid "combine patterns specified with -e"
-msgstr ""
+msgstr "combiner les motifs spécifiés par -e"
-#: builtin/grep.c:732
+#: builtin/grep.c:731
msgid "indicate hit with exit status without output"
msgstr ""
+"indiquer des correspondances avec le code de sortie mais sans rien afficher"
-#: builtin/grep.c:734
+#: builtin/grep.c:733
msgid "show only matches from files that match all patterns"
msgstr ""
+"n'afficher que les correspondances de fichiers qui correspondent à tous les "
+"motifs"
-#: builtin/grep.c:736
+#: builtin/grep.c:735
msgid "show parse tree for grep expression"
-msgstr ""
+msgstr "afficher l'arbre d'analyse pour le motif grep"
-#: builtin/grep.c:740
+#: builtin/grep.c:739
msgid "pager"
-msgstr ""
+msgstr "pagineur"
-#: builtin/grep.c:740
+#: builtin/grep.c:739
msgid "show matching files in the pager"
-msgstr ""
+msgstr "afficher les fichiers correspondant dans le pagineur"
-#: builtin/grep.c:743
+#: builtin/grep.c:742
msgid "allow calling of grep(1) (ignored by this build)"
-msgstr ""
+msgstr "permettre l'appel de grep(1) (ignoré par ce build)"
-#: builtin/grep.c:744 builtin/show-ref.c:184
+#: builtin/grep.c:743 builtin/show-ref.c:188
msgid "show usage"
-msgstr ""
+msgstr "afficher l'usage"
-#: builtin/grep.c:811
+#: builtin/grep.c:810
msgid "no pattern given."
-msgstr ""
+msgstr "aucun motif fourni."
-#: builtin/grep.c:866
+#: builtin/grep.c:865
msgid "--open-files-in-pager only works on the worktree"
-msgstr ""
+msgstr "--open-files-in-pager ne fonctionne que sur la copie de travail"
-#: builtin/grep.c:889
+#: builtin/grep.c:888
msgid "--cached or --untracked cannot be used with --no-index."
-msgstr ""
+msgstr "--cached ou --untracked ne peuvent pas être utilisés avec --no-index."
-#: builtin/grep.c:894
+#: builtin/grep.c:893
msgid "--no-index or --untracked cannot be used with revs."
msgstr ""
+"--no-index ou --untracked ne peuvent pas être utilisés avec des révisions."
-#: builtin/grep.c:897
+#: builtin/grep.c:896
msgid "--[no-]exclude-standard cannot be used for tracked contents."
msgstr ""
+"--[no-]exclude-standard ne peut pas être utilisé avec du contenu suivi."
-#: builtin/grep.c:905
+#: builtin/grep.c:904
msgid "both --cached and trees are given."
-msgstr ""
+msgstr "--cached et des arbres sont fournis en même temps."
#: builtin/hash-object.c:60
msgid ""
"git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] "
"<file>..."
msgstr ""
+"git hash-object [-t <type>] [-w] [--path=<fichier>|--no-filters] [--stdin] "
+"[--] <fichier>..."
#: builtin/hash-object.c:61
msgid "git hash-object --stdin-paths < <list-of-paths>"
-msgstr ""
+msgstr "git hash-object --stdin-paths < <liste-de-chemins>"
#: builtin/hash-object.c:72
msgid "type"
-msgstr ""
+msgstr "type"
#: builtin/hash-object.c:72
msgid "object type"
-msgstr ""
+msgstr "type d'objet"
#: builtin/hash-object.c:73
msgid "write the object into the object database"
-msgstr ""
+msgstr "écrire l'objet dans la base de donnée d'objets"
#: builtin/hash-object.c:74
msgid "read the object from stdin"
-msgstr ""
+msgstr "lire l'objet depuis l'entrée standard"
#: builtin/hash-object.c:76
msgid "store file as is without filters"
-msgstr ""
+msgstr "stocker le fichier tel quel sans filtrage"
#: builtin/hash-object.c:77
msgid "process file as it were from this path"
-msgstr ""
+msgstr "traiter le fichier comme s'il venait de ce chemin"
-#: builtin/help.c:43
+#: builtin/help.c:41
msgid "print all available commands"
-msgstr ""
+msgstr "afficher toutes les commandes disponibles"
-#: builtin/help.c:44
+#: builtin/help.c:42
msgid "print list of useful guides"
-msgstr ""
+msgstr "afficher une liste de guides utiles"
-#: builtin/help.c:45
+#: builtin/help.c:43
msgid "show man page"
-msgstr ""
+msgstr "afficher la page de manuel"
-#: builtin/help.c:46
+#: builtin/help.c:44
msgid "show manual in web browser"
-msgstr ""
+msgstr "afficher le manuel dans un navigateur web"
-#: builtin/help.c:48
+#: builtin/help.c:46
msgid "show info page"
-msgstr ""
+msgstr "afficher la page info"
-#: builtin/help.c:54
+#: builtin/help.c:52
msgid "git help [--all] [--guides] [--man|--web|--info] [command]"
-msgstr ""
+msgstr "git help [--all] [--guides] [--man|--web|--info] [commande]"
-#: builtin/help.c:66
+#: builtin/help.c:64
#, c-format
msgid "unrecognized help format '%s'"
-msgstr ""
+msgstr "format d'aide non reconnu '%s'"
-#: builtin/help.c:94
+#: builtin/help.c:92
msgid "Failed to start emacsclient."
-msgstr ""
+msgstr "échec de démarrage d'emacsclient."
-#: builtin/help.c:107
+#: builtin/help.c:105
msgid "Failed to parse emacsclient version."
-msgstr ""
+msgstr "échec d'analyse de la version d'emacsclient."
-#: builtin/help.c:115
+#: builtin/help.c:113
#, c-format
msgid "emacsclient version '%d' too old (< 22)."
-msgstr ""
+msgstr "la version d'emacsclient '%d' est trop ancienne (<22)."
-#: builtin/help.c:133 builtin/help.c:161 builtin/help.c:170 builtin/help.c:178
+#: builtin/help.c:131 builtin/help.c:159 builtin/help.c:168 builtin/help.c:176
#, c-format
msgid "failed to exec '%s': %s"
-msgstr ""
+msgstr "échec de l'exécution de '%s' : %s"
-#: builtin/help.c:218
+#: builtin/help.c:216
#, c-format
msgid ""
"'%s': path for unsupported man viewer.\n"
"Please consider using 'man.<tool>.cmd' instead."
msgstr ""
+"'%s' : chemin pour l'utilitaire de visualisation de manuel non supporté.\n"
+"Veuillez utiliser plutôt 'man.<outil>.cmd'."
-#: builtin/help.c:230
+#: builtin/help.c:228
#, c-format
msgid ""
"'%s': cmd for supported man viewer.\n"
"Please consider using 'man.<tool>.path' instead."
msgstr ""
+"'%s' : chemin pour l'utilitaire de visualisation de manuel supporté.\n"
+"Veuillez utiliser plutôt 'man.<outil>.cmd'."
-#: builtin/help.c:351
+#: builtin/help.c:349
#, c-format
msgid "'%s': unknown man viewer."
-msgstr ""
+msgstr "'%s' : visualiseur de manuel inconnu."
-#: builtin/help.c:368
+#: builtin/help.c:366
msgid "no man viewer handled the request"
-msgstr ""
+msgstr "aucun visualiseur de manuel n'a pris en charge la demande"
-#: builtin/help.c:376
+#: builtin/help.c:374
msgid "no info viewer handled the request"
-msgstr ""
+msgstr "aucun visualiseur de 'info' n'a pris en charge la demande"
-#: builtin/help.c:422
+#: builtin/help.c:420
msgid "Defining attributes per path"
-msgstr ""
+msgstr "Définition des attributs par chemin"
-#: builtin/help.c:423
+#: builtin/help.c:421
msgid "A Git glossary"
-msgstr ""
+msgstr "Un glossaire Git"
-#: builtin/help.c:424
+#: builtin/help.c:422
msgid "Specifies intentionally untracked files to ignore"
-msgstr ""
+msgstr "Spécifie les fichiers non-suivis à ignorer intentionnellement"
-#: builtin/help.c:425
+#: builtin/help.c:423
msgid "Defining submodule properties"
-msgstr ""
+msgstr "Définition des propriétés de sous-module"
-#: builtin/help.c:426
+#: builtin/help.c:424
msgid "Specifying revisions and ranges for Git"
-msgstr ""
+msgstr "Spécification des révisions et portées pour Git"
-#: builtin/help.c:427
+#: builtin/help.c:425
msgid "A tutorial introduction to Git (for version 1.5.1 or newer)"
msgstr ""
+"Une introduction pratique à Git (pour les versions 1.5.1 et supérieures)"
-#: builtin/help.c:428
+#: builtin/help.c:426
msgid "An overview of recommended workflows with Git"
-msgstr ""
+msgstr "Un aperçu des flux de travail recommandés avec Git"
-#: builtin/help.c:440
+#: builtin/help.c:438
msgid "The common Git guides are:\n"
-msgstr ""
+msgstr "Les guides Git populaires sont : \n"
-#: builtin/help.c:462 builtin/help.c:478
+#: builtin/help.c:460 builtin/help.c:476
#, c-format
msgid "usage: %s%s"
-msgstr ""
+msgstr "usage : %s%s"
-#: builtin/help.c:494
+#: builtin/help.c:492
#, c-format
msgid "`git %s' is aliased to `%s'"
-msgstr ""
+msgstr "`git %s\" est un alias de `%s'"
-#: builtin/index-pack.c:182
+#: builtin/index-pack.c:184
#, c-format
msgid "object type mismatch at %s"
-msgstr ""
+msgstr "type d'objet non correspondant à %s"
-#: builtin/index-pack.c:202
+#: builtin/index-pack.c:204
msgid "object of unexpected type"
-msgstr ""
+msgstr "objet de type inattendu"
-#: builtin/index-pack.c:239
+#: builtin/index-pack.c:244
#, c-format
msgid "cannot fill %d byte"
msgid_plural "cannot fill %d bytes"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "impossible de remplir %d octet"
+msgstr[1] "impossible de remplir %d octets"
-#: builtin/index-pack.c:249
+#: builtin/index-pack.c:254
msgid "early EOF"
-msgstr ""
+msgstr "fin de fichier prématurée"
-#: builtin/index-pack.c:250
+#: builtin/index-pack.c:255
msgid "read error on input"
-msgstr ""
+msgstr "erreur de lecture sur l'entrée"
-#: builtin/index-pack.c:262
+#: builtin/index-pack.c:267
msgid "used more bytes than were available"
-msgstr ""
+msgstr "plus d'octets utilisés que disponibles"
-#: builtin/index-pack.c:269
+#: builtin/index-pack.c:274
msgid "pack too large for current definition of off_t"
-msgstr ""
+msgstr "le paquet est trop grand pour la définition actuelle de off_t"
-#: builtin/index-pack.c:285
+#: builtin/index-pack.c:290
#, c-format
msgid "unable to create '%s'"
-msgstr ""
+msgstr "impossible de créer '%s'"
-#: builtin/index-pack.c:290
+#: builtin/index-pack.c:295
#, c-format
msgid "cannot open packfile '%s'"
-msgstr ""
+msgstr "impossible d'ouvrir le fichier paquet '%s'"
-#: builtin/index-pack.c:304
+#: builtin/index-pack.c:309
msgid "pack signature mismatch"
-msgstr ""
+msgstr "la signature du paquet ne correspond pas"
-#: builtin/index-pack.c:306
+#: builtin/index-pack.c:311
#, c-format
msgid "pack version %<PRIu32> unsupported"
-msgstr ""
+msgstr "la version de paquet %<PRIu32> non supportée"
-#: builtin/index-pack.c:324
+#: builtin/index-pack.c:329
#, c-format
msgid "pack has bad object at offset %lu: %s"
-msgstr ""
+msgstr "le paquet a un mauvais objet à l'offset %lu: %s"
-#: builtin/index-pack.c:446
+#: builtin/index-pack.c:451
#, c-format
msgid "inflate returned %d"
-msgstr ""
+msgstr "la décompression (inflate) a retourné %d"
-#: builtin/index-pack.c:495
+#: builtin/index-pack.c:500
msgid "offset value overflow for delta base object"
-msgstr ""
+msgstr "dépassement de la valeur d'offset pour l'objet delta de base"
-#: builtin/index-pack.c:503
+#: builtin/index-pack.c:508
msgid "delta base offset is out of bound"
-msgstr ""
+msgstr "l'objet delta de base est hors limite"
-#: builtin/index-pack.c:511
+#: builtin/index-pack.c:516
#, c-format
msgid "unknown object type %d"
-msgstr ""
+msgstr "type d'objet inconnu %d"
-#: builtin/index-pack.c:542
+#: builtin/index-pack.c:547
msgid "cannot pread pack file"
-msgstr ""
+msgstr "impossible de lire (pread) le fichier paquet"
-#: builtin/index-pack.c:544
+#: builtin/index-pack.c:549
#, 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] ""
+msgstr[0] "fin prématurée du fichier paquet, %lu octet lu"
+msgstr[1] "fin prématurée du fichier paquet, %lu octets lus"
-#: builtin/index-pack.c:570
+#: builtin/index-pack.c:575
msgid "serious inflate inconsistency"
-msgstr ""
+msgstr "grave incohérence dans la décompression (inflate)"
-#: builtin/index-pack.c:661 builtin/index-pack.c:667 builtin/index-pack.c:690
-#: builtin/index-pack.c:724 builtin/index-pack.c:733
+#: builtin/index-pack.c:666 builtin/index-pack.c:672 builtin/index-pack.c:695
+#: builtin/index-pack.c:729 builtin/index-pack.c:738
#, c-format
msgid "SHA1 COLLISION FOUND WITH %s !"
-msgstr ""
+msgstr "COLLISION SHA1 TROUVÉE AVEC %s !"
-#: builtin/index-pack.c:664 builtin/pack-objects.c:170
+#: builtin/index-pack.c:669 builtin/pack-objects.c:170
#: builtin/pack-objects.c:262
#, c-format
msgid "unable to read %s"
-msgstr ""
+msgstr "impossible de lire %s"
-#: builtin/index-pack.c:730
+#: builtin/index-pack.c:735
#, c-format
msgid "cannot read existing object %s"
-msgstr ""
+msgstr "impossible de lire l'objet existant %s"
-#: builtin/index-pack.c:744
+#: builtin/index-pack.c:749
#, c-format
msgid "invalid blob object %s"
-msgstr ""
+msgstr "objet blob invalide %s"
-#: builtin/index-pack.c:759
+#: builtin/index-pack.c:763
#, c-format
msgid "invalid %s"
-msgstr ""
+msgstr "%s invalide"
-#: builtin/index-pack.c:761
+#: builtin/index-pack.c:766
msgid "Error in object"
-msgstr ""
+msgstr "Erreur dans l'objet"
-#: builtin/index-pack.c:763
+#: builtin/index-pack.c:768
#, c-format
msgid "Not all child objects of %s are reachable"
-msgstr ""
+msgstr "Tous les objets enfants de %s ne sont pas accessibles"
-#: builtin/index-pack.c:833 builtin/index-pack.c:863
+#: builtin/index-pack.c:838 builtin/index-pack.c:868
msgid "failed to apply delta"
-msgstr ""
+msgstr "échec d'application du delta"
-#: builtin/index-pack.c:1004
+#: builtin/index-pack.c:1009
msgid "Receiving objects"
-msgstr ""
+msgstr "Réception d'objets"
-#: builtin/index-pack.c:1004
+#: builtin/index-pack.c:1009
msgid "Indexing objects"
-msgstr ""
+msgstr "Indexation d'objets"
-#: builtin/index-pack.c:1030
+#: builtin/index-pack.c:1035
msgid "pack is corrupted (SHA1 mismatch)"
-msgstr ""
+msgstr "le paquet est corrompu (SHA1 ne correspond pas)"
-#: builtin/index-pack.c:1035
+#: builtin/index-pack.c:1040
msgid "cannot fstat packfile"
-msgstr ""
+msgstr "impossible d'obtenir le statut (fstat) du fichier paquet"
-#: builtin/index-pack.c:1038
+#: builtin/index-pack.c:1043
msgid "pack has junk at the end"
-msgstr ""
+msgstr "le paquet est invalide à la fin"
-#: builtin/index-pack.c:1049
+#: builtin/index-pack.c:1054
msgid "confusion beyond insanity in parse_pack_objects()"
-msgstr ""
+msgstr "confusion extrême dans parse_pack_objects()"
-#: builtin/index-pack.c:1072
+#: builtin/index-pack.c:1077
msgid "Resolving deltas"
-msgstr ""
+msgstr "Résolution des deltas"
-#: builtin/index-pack.c:1082
+#: builtin/index-pack.c:1087
#, c-format
msgid "unable to create thread: %s"
-msgstr ""
+msgstr "impossible de créer le fil : %s"
-#: builtin/index-pack.c:1124
+#: builtin/index-pack.c:1129
msgid "confusion beyond insanity"
-msgstr ""
+msgstr "confusion extrême"
-#: builtin/index-pack.c:1132
+#: builtin/index-pack.c:1137
#, c-format
msgid "completed with %d local objects"
-msgstr ""
+msgstr "complété avec %d objets locaux"
-#: builtin/index-pack.c:1142
+#: builtin/index-pack.c:1147
#, c-format
msgid "Unexpected tail checksum for %s (disk corruption?)"
msgstr ""
+"Somme de contrôle de fin inattendue pour %s (corruption sur le disque ?)"
-#: builtin/index-pack.c:1146
+#: builtin/index-pack.c:1151
#, c-format
msgid "pack has %d unresolved delta"
msgid_plural "pack has %d unresolved deltas"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "le paquet a %d delta non résolu"
+msgstr[1] "le paquet a %d deltas non résolus"
-#: builtin/index-pack.c:1171
+#: builtin/index-pack.c:1176
#, c-format
msgid "unable to deflate appended object (%d)"
-msgstr ""
+msgstr "impossible de compresser l'objet ajouté (%d)"
-#: builtin/index-pack.c:1250
+#: builtin/index-pack.c:1255
#, c-format
msgid "local object %s is corrupt"
-msgstr ""
+msgstr "l'objet local %s est corrompu"
-#: builtin/index-pack.c:1274
+#: builtin/index-pack.c:1279
msgid "error while closing pack file"
-msgstr ""
+msgstr "erreur en fermeture du fichier paquet"
-#: builtin/index-pack.c:1287
+#: builtin/index-pack.c:1292
#, c-format
msgid "cannot write keep file '%s'"
-msgstr ""
+msgstr "impossible d'écrire le fichier \"keep\" '%s'"
-#: builtin/index-pack.c:1295
+#: builtin/index-pack.c:1300
#, c-format
msgid "cannot close written keep file '%s'"
-msgstr ""
+msgstr "impossible de fermer le fichier \"keep\" '%s'"
-#: builtin/index-pack.c:1308
+#: builtin/index-pack.c:1313
msgid "cannot store pack file"
-msgstr ""
+msgstr "impossible de stocker le fichier paquet"
-#: builtin/index-pack.c:1319
+#: builtin/index-pack.c:1324
msgid "cannot store index file"
-msgstr ""
+msgstr "impossible de stocker le fichier d'index"
-#: builtin/index-pack.c:1352
+#: builtin/index-pack.c:1357
#, c-format
msgid "bad pack.indexversion=%<PRIu32>"
-msgstr ""
+msgstr "mauvais pack.indexversion=%<PRIu32>"
-#: builtin/index-pack.c:1358
+#: builtin/index-pack.c:1363
#, c-format
msgid "invalid number of threads specified (%d)"
-msgstr ""
+msgstr "nombre de fils spécifié invalide (%d)"
-#: builtin/index-pack.c:1362 builtin/index-pack.c:1535
+#: builtin/index-pack.c:1367 builtin/index-pack.c:1545
#, c-format
msgid "no threads support, ignoring %s"
-msgstr ""
+msgstr "pas de support des fils, ignore %s"
-#: builtin/index-pack.c:1420
+#: builtin/index-pack.c:1425
#, c-format
msgid "Cannot open existing pack file '%s'"
-msgstr ""
+msgstr "Impossible d'ouvrir le fichier paquet existant '%s'"
-#: builtin/index-pack.c:1422
+#: builtin/index-pack.c:1427
#, c-format
msgid "Cannot open existing pack idx file for '%s'"
-msgstr ""
+msgstr "Impossible d'ouvrir le fichier paquet d'index existant pour '%s'"
-#: builtin/index-pack.c:1469
+#: builtin/index-pack.c:1474
#, c-format
msgid "non delta: %d object"
msgid_plural "non delta: %d objects"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "pas un delta : %d objet"
+msgstr[1] "pas un delta : %d objets"
-#: builtin/index-pack.c:1476
+#: builtin/index-pack.c:1481
#, c-format
msgid "chain length = %d: %lu object"
msgid_plural "chain length = %d: %lu objects"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "longueur chaînée = %d : %lu objet"
+msgstr[1] "longueur chaînée = %d : %lu objets"
-#: builtin/index-pack.c:1503
+#: builtin/index-pack.c:1509
msgid "Cannot come back to cwd"
-msgstr ""
+msgstr "Impossible de revenir au répertoire de travail courant"
-#: builtin/index-pack.c:1547 builtin/index-pack.c:1550
-#: builtin/index-pack.c:1562 builtin/index-pack.c:1566
+#: builtin/index-pack.c:1557 builtin/index-pack.c:1560
+#: builtin/index-pack.c:1572 builtin/index-pack.c:1576
#, c-format
msgid "bad %s"
-msgstr ""
+msgstr "mauvais %s"
-#: builtin/index-pack.c:1580
+#: builtin/index-pack.c:1590
msgid "--fix-thin cannot be used without --stdin"
-msgstr ""
+msgstr "--fix-thin ne peut pas être utilisé sans --stdin"
-#: builtin/index-pack.c:1584 builtin/index-pack.c:1594
+#: builtin/index-pack.c:1594 builtin/index-pack.c:1604
#, c-format
msgid "packfile name '%s' does not end with '.pack'"
-msgstr ""
+msgstr "le nom de fichier paquet '%s' ne se termine pas par '.pack'"
-#: builtin/index-pack.c:1603
+#: builtin/index-pack.c:1613
msgid "--verify with no packfile name given"
-msgstr ""
+msgstr "--verify sans nom de fichier paquet donné"
#: builtin/init-db.c:35
#, c-format
msgid "Could not make %s writable by group"
-msgstr ""
+msgstr "Impossible de rendre %s inscriptible pour le groupe"
#: builtin/init-db.c:62
#, c-format
msgid "insanely long template name %s"
-msgstr ""
+msgstr "nom de modèle démentiellement long %s"
#: builtin/init-db.c:67
#, c-format
msgid "cannot stat '%s'"
-msgstr ""
+msgstr "impossible de faire un stat de '%s'"
#: builtin/init-db.c:73
#, c-format
msgid "cannot stat template '%s'"
-msgstr ""
+msgstr "impossible de faire un stat du modèle '%s'"
#: builtin/init-db.c:80
#, c-format
msgid "cannot opendir '%s'"
-msgstr ""
+msgstr "impossible d'ouvrir (opendir) '%s'"
#: builtin/init-db.c:97
#, c-format
msgid "cannot readlink '%s'"
-msgstr ""
+msgstr "impossible de readlink '%s'"
#: builtin/init-db.c:99
#, c-format
msgid "insanely long symlink %s"
-msgstr ""
+msgstr "lien symbolique démentiellement long %s"
#: builtin/init-db.c:102
#, c-format
msgid "cannot symlink '%s' '%s'"
-msgstr ""
+msgstr "impossible de créer un lien symbolique de '%s' '%s'"
#: builtin/init-db.c:106
#, c-format
msgid "cannot copy '%s' to '%s'"
-msgstr ""
+msgstr "impossible de copier '%s' vers '%s'"
#: builtin/init-db.c:110
#, c-format
msgid "ignoring template %s"
-msgstr ""
+msgstr "modèle %s ignoré"
#: builtin/init-db.c:133
#, c-format
msgid "insanely long template path %s"
-msgstr ""
+msgstr "chemin de modèle %s démentiellement long"
#: builtin/init-db.c:141
#, c-format
msgid "templates not found %s"
-msgstr ""
+msgstr "modèles non trouvés %s"
#: builtin/init-db.c:154
#, c-format
msgid "not copying templates of a wrong format version %d from '%s'"
msgstr ""
+"pas de copie des modèles étant dans une mauvaise version du format %d de '%s'"
#: builtin/init-db.c:192
#, c-format
msgid "insane git directory %s"
-msgstr ""
+msgstr "répertoire git démentiel %s"
#: builtin/init-db.c:323 builtin/init-db.c:326
#, c-format
#: builtin/init-db.c:355
#, c-format
msgid "unable to handle file type %d"
-msgstr ""
+msgstr "impossible de traiter le fichier de type %d"
#: builtin/init-db.c:358
#, c-format
msgid "unable to move %s to %s"
-msgstr ""
+msgstr "impossible de déplacer %s vers %s"
#: builtin/init-db.c:363
#, c-format
msgid "Could not create git link %s"
-msgstr ""
+msgstr "Impossible de créer le lien git %s"
#.
#. * TRANSLATORS: The first '%s' is either "Reinitialized
#: builtin/init-db.c:420
#, c-format
msgid "%s%s Git repository in %s%s\n"
-msgstr "%s%s Dépôt git dans %s%s\n"
+msgstr "Dépôt Git%2$s %1$s dans %3$s%4$s\n"
#: builtin/init-db.c:421
msgid "Reinitialized existing"
-msgstr ""
+msgstr "existant réinitialisé"
#: builtin/init-db.c:421
msgid "Initialized empty"
-msgstr ""
+msgstr "vide initialisé"
#: builtin/init-db.c:422
msgid " shared"
-msgstr ""
+msgstr " partagé"
#: builtin/init-db.c:441
msgid "cannot tell cwd"
-msgstr ""
+msgstr "impossible de déterminer le répertoire de travail courant"
#: builtin/init-db.c:467
msgid ""
"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--"
"shared[=<permissions>]] [directory]"
msgstr ""
+"git init [-q | --quiet] [--bare] [--template=<répertoire-modèle>] [--"
+"shared[=<permissions>]] [répertoire]"
#: builtin/init-db.c:490
msgid "permissions"
-msgstr ""
+msgstr "permissions"
#: builtin/init-db.c:491
msgid "specify that the git repository is to be shared amongst several users"
-msgstr ""
+msgstr "spécifier que le dépôt git sera partagé entre plusieurs utilisateurs"
-#: builtin/init-db.c:493 builtin/prune-packed.c:77
+#: builtin/init-db.c:493 builtin/prune-packed.c:75
msgid "be quiet"
-msgstr ""
+msgstr "être silencieux"
#: builtin/init-db.c:522 builtin/init-db.c:529
#, c-format
msgid "cannot mkdir %s"
-msgstr ""
+msgstr "impossible de créer le répertoire (mkdir) %s"
#: builtin/init-db.c:533
#, c-format
msgid "cannot chdir to %s"
-msgstr ""
+msgstr "impossible de se déplacer vers le répertoire (chdir) %s"
#: builtin/init-db.c:555
#, c-format
"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-"
"dir=<directory>)"
msgstr ""
+"%s (ou --work-tree=<répertoire>) n'est pas autorisé sans spécifier %s (ou --"
+"git-dir=<répertoire>)"
#: builtin/init-db.c:579
msgid "Cannot access current working directory"
-msgstr ""
+msgstr "Impossible d'accéder au répertoire de travail courant"
#: builtin/init-db.c:586
#, c-format
msgid "Cannot access work tree '%s'"
-msgstr ""
+msgstr "Impossible d'accéder à l'arbre de travail '%s'"
-#: builtin/log.c:40
+#: builtin/log.c:41
msgid "git log [<options>] [<revision range>] [[--] <path>...]\n"
-msgstr ""
+msgstr "git log [<options>] [<page de révisions>] [[--] <chemin>...]\n"
-#: builtin/log.c:41
+#: builtin/log.c:42
msgid " or: git show [options] <object>..."
-msgstr ""
+msgstr " ou : git show [options] <objet>..."
-#: builtin/log.c:103
+#: builtin/log.c:124
msgid "suppress diff output"
-msgstr ""
+msgstr "supprimer la sortie des différences"
-#: builtin/log.c:104
+#: builtin/log.c:125
msgid "show source"
-msgstr ""
+msgstr "afficher la source"
-#: builtin/log.c:105
+#: builtin/log.c:126
msgid "Use mail map file"
-msgstr ""
+msgstr "Utiliser le fichier de correspondance de mail"
-#: builtin/log.c:106
+#: builtin/log.c:127
msgid "decorate options"
-msgstr ""
+msgstr "décorer les options"
-#: builtin/log.c:199
+#: builtin/log.c:230
#, c-format
msgid "Final output: %d %s\n"
-msgstr ""
+msgstr "Sortie finale : %d %s\n"
-#: builtin/log.c:422 builtin/log.c:514
+#: builtin/log.c:453 builtin/log.c:545
#, c-format
msgid "Could not read object %s"
-msgstr ""
+msgstr "Impossible de lire l'objet %s"
-#: builtin/log.c:538
+#: builtin/log.c:569
#, c-format
msgid "Unknown type: %d"
-msgstr ""
+msgstr "Type inconnu : %d"
-#: builtin/log.c:638
+#: builtin/log.c:669
msgid "format.headers without value"
-msgstr ""
+msgstr "format.headers sans valeur"
-#: builtin/log.c:720
+#: builtin/log.c:751
msgid "name of output directory is too long"
-msgstr ""
+msgstr "le nom du répertoire de sortie est trop long"
-#: builtin/log.c:736
+#: builtin/log.c:767
#, c-format
msgid "Cannot open patch file %s"
-msgstr ""
+msgstr "Impossible d'ouvrir le fichier correctif %s"
-#: builtin/log.c:750
+#: builtin/log.c:781
msgid "Need exactly one range."
-msgstr ""
+msgstr "Exactement une plage nécessaire."
-#: builtin/log.c:758
+#: builtin/log.c:789
msgid "Not a range."
-msgstr ""
+msgstr "Pas une plage."
-#: builtin/log.c:860
+#: builtin/log.c:891
msgid "Cover letter needs email format"
-msgstr ""
+msgstr "La lettre de motivation doit être au format e-mail"
-#: builtin/log.c:936
+#: builtin/log.c:967
#, c-format
msgid "insane in-reply-to: %s"
-msgstr ""
+msgstr "in-reply-to aberrant : %s"
-#: builtin/log.c:964
+#: builtin/log.c:995
msgid "git format-patch [options] [<since> | <revision range>]"
-msgstr ""
+msgstr "git format-patch [options] [<depuis> | <plage de révisions>]"
-#: builtin/log.c:1009
+#: builtin/log.c:1040
msgid "Two output directories?"
-msgstr ""
+msgstr "Deux répertoires de sortie ?"
-#: builtin/log.c:1108
+#: builtin/log.c:1155
msgid "use [PATCH n/m] even with a single patch"
-msgstr ""
+msgstr "utiliser [PATCH n/m] même avec un patch unique"
-#: builtin/log.c:1111
+#: builtin/log.c:1158
msgid "use [PATCH] even with multiple patches"
-msgstr ""
+msgstr "utiliser [PATCH] même avec des patchs multiples"
-#: builtin/log.c:1115
+#: builtin/log.c:1162
msgid "print patches to standard out"
-msgstr ""
+msgstr "afficher les patchs sur la sortie standard"
-#: builtin/log.c:1117
+#: builtin/log.c:1164
msgid "generate a cover letter"
-msgstr ""
+msgstr "générer une lettre de motivation"
-#: builtin/log.c:1119
+#: builtin/log.c:1166
msgid "use simple number sequence for output file names"
msgstr ""
+"utiliser une séquence simple de nombres pour les nom des fichiers de sortie"
-#: builtin/log.c:1120
+#: builtin/log.c:1167
msgid "sfx"
-msgstr ""
+msgstr "sfx"
-#: builtin/log.c:1121
+#: builtin/log.c:1168
msgid "use <sfx> instead of '.patch'"
-msgstr ""
+msgstr "utiliser <sfx> au lieu de '.patch'"
-#: builtin/log.c:1123
+#: builtin/log.c:1170
msgid "start numbering patches at <n> instead of 1"
-msgstr ""
+msgstr "démarrer la numérotation des patchs à <n> au lieu de 1"
-#: builtin/log.c:1125
+#: builtin/log.c:1172
msgid "mark the series as Nth re-roll"
-msgstr ""
+msgstr "marquer la série comme une Nième réédition"
-#: builtin/log.c:1127
+#: builtin/log.c:1174
msgid "Use [<prefix>] instead of [PATCH]"
-msgstr ""
+msgstr "utiliser [<préfixe>] au lieu de [PATCH]"
-#: builtin/log.c:1130
+#: builtin/log.c:1177
msgid "store resulting files in <dir>"
-msgstr ""
+msgstr "stocker les fichiers résultats dans <répertoire>"
-#: builtin/log.c:1133
+#: builtin/log.c:1180
msgid "don't strip/add [PATCH]"
-msgstr ""
+msgstr "ne pas retirer/ajouter [PATCH]"
-#: builtin/log.c:1136
+#: builtin/log.c:1183
msgid "don't output binary diffs"
-msgstr ""
+msgstr "ne pas imprimer les diffs binaires"
-#: builtin/log.c:1138
+#: builtin/log.c:1185
msgid "don't include a patch matching a commit upstream"
-msgstr ""
+msgstr "ne pas inclure un patch correspondant à un commit amont"
-#: builtin/log.c:1140
+#: builtin/log.c:1187
msgid "show patch format instead of default (patch + stat)"
-msgstr ""
+msgstr "afficher le format du patch au lieu du défaut (patch + stat)"
-#: builtin/log.c:1142
+#: builtin/log.c:1189
msgid "Messaging"
-msgstr ""
+msgstr "Communication"
-#: builtin/log.c:1143
+#: builtin/log.c:1190
msgid "header"
-msgstr ""
+msgstr "en-tête"
-#: builtin/log.c:1144
+#: builtin/log.c:1191
msgid "add email header"
-msgstr ""
+msgstr "ajouter l'en-tête d'e-mail"
-#: builtin/log.c:1145 builtin/log.c:1147
+#: builtin/log.c:1192 builtin/log.c:1194
msgid "email"
-msgstr ""
+msgstr "e-mail"
-#: builtin/log.c:1145
+#: builtin/log.c:1192
msgid "add To: header"
-msgstr ""
+msgstr "ajouter l'en-tête \"To:\""
-#: builtin/log.c:1147
+#: builtin/log.c:1194
msgid "add Cc: header"
-msgstr ""
+msgstr "ajouter l'en-tête \"Cc:\""
+
+#: builtin/log.c:1196
+msgid "ident"
+msgstr "ident"
+
+#: builtin/log.c:1197
+msgid "set From address to <ident> (or committer ident if absent)"
+msgstr "Renseigner l'adresse From à <ident> (ou à l'ident du validateur si absent)"
-#: builtin/log.c:1149
+#: builtin/log.c:1199
msgid "message-id"
-msgstr ""
+msgstr "id-message"
-#: builtin/log.c:1150
+#: builtin/log.c:1200
msgid "make first mail a reply to <message-id>"
-msgstr ""
+msgstr "répondre dans le premier message à <id-message>"
-#: builtin/log.c:1151 builtin/log.c:1154
+#: builtin/log.c:1201 builtin/log.c:1204
msgid "boundary"
-msgstr ""
+msgstr "frontière"
-#: builtin/log.c:1152
+#: builtin/log.c:1202
msgid "attach the patch"
-msgstr ""
+msgstr "attacher le patch"
-#: builtin/log.c:1155
+#: builtin/log.c:1205
msgid "inline the patch"
-msgstr ""
+msgstr "patch à l'intérieur"
-#: builtin/log.c:1159
+#: builtin/log.c:1209
msgid "enable message threading, styles: shallow, deep"
msgstr ""
+"activer l'enfilage de message, styles : shallow (superficiel), deep (profond)"
-#: builtin/log.c:1161
+#: builtin/log.c:1211
msgid "signature"
-msgstr ""
+msgstr "signature"
-#: builtin/log.c:1162
+#: builtin/log.c:1212
msgid "add a signature"
-msgstr ""
+msgstr "ajouter une signature"
-#: builtin/log.c:1164
+#: builtin/log.c:1214
msgid "don't print the patch filenames"
-msgstr ""
+msgstr "ne pas afficher les noms de fichiers des patchs"
+
+#: builtin/log.c:1288
+#, c-format
+msgid "invalid ident line: %s"
+msgstr "ligne d'identification invalide : %s"
-#: builtin/log.c:1248
+#: builtin/log.c:1303
msgid "-n and -k are mutually exclusive."
-msgstr ""
+msgstr "-n et -k sont mutuellement exclusifs."
-#: builtin/log.c:1250
+#: builtin/log.c:1305
msgid "--subject-prefix and -k are mutually exclusive."
-msgstr ""
+msgstr "--subject-prefix et -k sont mutuellement exclusifs."
-#: builtin/log.c:1258
+#: builtin/log.c:1313
msgid "--name-only does not make sense"
-msgstr ""
+msgstr "--name-only n'a pas de sens"
-#: builtin/log.c:1260
+#: builtin/log.c:1315
msgid "--name-status does not make sense"
-msgstr ""
+msgstr "--name-status n'a pas de sens"
-#: builtin/log.c:1262
+#: builtin/log.c:1317
msgid "--check does not make sense"
-msgstr ""
+msgstr "--check n'a pas de sens"
-#: builtin/log.c:1285
+#: builtin/log.c:1340
msgid "standard output, or directory, which one?"
-msgstr ""
+msgstr "sortie standard, ou répertoire, lequel ?"
-#: builtin/log.c:1287
+#: builtin/log.c:1342
#, c-format
msgid "Could not create directory '%s'"
-msgstr ""
+msgstr "Impossible de créer le répertoire '%s'"
-#: builtin/log.c:1435
+#: builtin/log.c:1490
msgid "Failed to create output files"
-msgstr ""
+msgstr "Échec de création des fichiers en sortie"
-#: builtin/log.c:1484
+#: builtin/log.c:1539
msgid "git cherry [-v] [<upstream> [<head> [<limit>]]]"
-msgstr ""
+msgstr "git cherry [-v] [<branche_amont> [<head> [<limite>]]]"
-#: builtin/log.c:1539
+#: builtin/log.c:1594
#, c-format
msgid ""
"Could not find a tracked remote branch, please specify <upstream> manually.\n"
msgstr ""
+"Impossible de trouver une branche distante suivie, merci de spécifier "
+"<branche_amont> manuellement.\n"
-#: builtin/log.c:1552 builtin/log.c:1554 builtin/log.c:1566
+#: builtin/log.c:1607 builtin/log.c:1609 builtin/log.c:1621
#, c-format
msgid "Unknown commit %s"
-msgstr ""
+msgstr "Commit inconnu %s"
-#: builtin/ls-files.c:402
+#: builtin/ls-files.c:408
msgid "git ls-files [options] [<file>...]"
-msgstr ""
+msgstr "git ls-files [options] [<fichier>...]"
-#: builtin/ls-files.c:459
+#: builtin/ls-files.c:465
msgid "identify the file status with tags"
-msgstr ""
+msgstr "identifier le statut de fichier avec les étiquettes"
-#: builtin/ls-files.c:461
+#: builtin/ls-files.c:467
msgid "use lowercase letters for 'assume unchanged' files"
-msgstr ""
+msgstr "utiliser des minuscules pour les fichier 'assumés inchangés'"
-#: builtin/ls-files.c:463
+#: builtin/ls-files.c:469
msgid "show cached files in the output (default)"
-msgstr ""
+msgstr "afficher les fichiers mis en cache dans la sortie (défaut)"
-#: builtin/ls-files.c:465
+#: builtin/ls-files.c:471
msgid "show deleted files in the output"
-msgstr ""
+msgstr "afficher les fichiers supprimés dans la sortie"
-#: builtin/ls-files.c:467
+#: builtin/ls-files.c:473
msgid "show modified files in the output"
-msgstr ""
+msgstr "afficher les fichiers modifiés dans la sortie"
-#: builtin/ls-files.c:469
+#: builtin/ls-files.c:475
msgid "show other files in the output"
-msgstr ""
+msgstr "afficher les autres fichiers dans la sortie"
-#: builtin/ls-files.c:471
+#: builtin/ls-files.c:477
msgid "show ignored files in the output"
-msgstr ""
+msgstr "afficher les fichiers ignorés dans la sortie"
-#: builtin/ls-files.c:474
+#: builtin/ls-files.c:480
msgid "show staged contents' object name in the output"
-msgstr ""
+msgstr "afficher les nom des objets indexés dans la sortie"
-#: builtin/ls-files.c:476
+#: builtin/ls-files.c:482
msgid "show files on the filesystem that need to be removed"
msgstr ""
+"afficher les fichiers du système de fichiers qui ont besoin d'être supprimés"
-#: builtin/ls-files.c:478
+#: builtin/ls-files.c:484
msgid "show 'other' directories' name only"
-msgstr ""
+msgstr "afficher seulement les noms des répertoires 'other'"
-#: builtin/ls-files.c:481
+#: builtin/ls-files.c:487
msgid "don't show empty directories"
-msgstr ""
+msgstr "ne pas afficher les répertoires vides"
-#: builtin/ls-files.c:484
+#: builtin/ls-files.c:490
msgid "show unmerged files in the output"
-msgstr ""
+msgstr "afficher les fichiers non fusionnés dans la sortie"
-#: builtin/ls-files.c:486
+#: builtin/ls-files.c:492
msgid "show resolve-undo information"
-msgstr ""
+msgstr "afficher l'information resolv-undo"
-#: builtin/ls-files.c:488
+#: builtin/ls-files.c:494
msgid "skip files matching pattern"
-msgstr ""
+msgstr "sauter les fichiers correspondant au motif"
-#: builtin/ls-files.c:491
+#: builtin/ls-files.c:497
msgid "exclude patterns are read from <file>"
-msgstr ""
+msgstr "les motifs d'exclusion sont lus depuis <fichier>"
-#: builtin/ls-files.c:494
+#: builtin/ls-files.c:500
msgid "read additional per-directory exclude patterns in <file>"
-msgstr ""
+msgstr "lire des motifs d'exclusion additionnels par répertoire dans <fichier>"
-#: builtin/ls-files.c:496
+#: builtin/ls-files.c:502
msgid "add the standard git exclusions"
-msgstr ""
+msgstr "ajouter les exclusions git standard"
-#: builtin/ls-files.c:499
+#: builtin/ls-files.c:505
msgid "make the output relative to the project top directory"
-msgstr ""
+msgstr "afficher en relatif par rapport au répertoire racine du projet"
-#: builtin/ls-files.c:502
+#: builtin/ls-files.c:508
msgid "if any <file> is not in the index, treat this as an error"
-msgstr ""
+msgstr "si un <fichier> n'est pas dans l'index, traiter cela comme une erreur"
-#: builtin/ls-files.c:503
+#: builtin/ls-files.c:509
msgid "tree-ish"
-msgstr ""
+msgstr "arbre ou apparenté"
-#: builtin/ls-files.c:504
+#: builtin/ls-files.c:510
msgid "pretend that paths removed since <tree-ish> are still present"
msgstr ""
+"considérer que les chemins supprimés depuis <arbre ou apparenté> sont "
+"toujours présents"
-#: builtin/ls-files.c:506
+#: builtin/ls-files.c:512
msgid "show debugging data"
-msgstr ""
+msgstr "afficher les données de débogage"
#: builtin/ls-tree.c:27
msgid "git ls-tree [<options>] <tree-ish> [<path>...]"
-msgstr ""
+msgstr "git ls-tree [<options>] <arbre ou apparenté> [<chemin>...]"
#: builtin/ls-tree.c:125
msgid "only show trees"
-msgstr ""
+msgstr "afficher seulement les arbres"
#: builtin/ls-tree.c:127
msgid "recurse into subtrees"
-msgstr ""
+msgstr "parcourir les sous-arbres"
#: builtin/ls-tree.c:129
msgid "show trees when recursing"
-msgstr ""
+msgstr "afficher les arbres en les parcourant"
#: builtin/ls-tree.c:132
msgid "terminate entries with NUL byte"
-msgstr ""
+msgstr "terminer les éléments avec un octet NUL"
#: builtin/ls-tree.c:133
msgid "include object size"
-msgstr ""
+msgstr "inclure la taille d'objet"
#: builtin/ls-tree.c:135 builtin/ls-tree.c:137
msgid "list only filenames"
-msgstr ""
+msgstr "afficher seulement les noms de fichiers"
#: builtin/ls-tree.c:140
msgid "use full path names"
-msgstr ""
+msgstr "utiliser les noms de chemins complets"
#: builtin/ls-tree.c:142
msgid "list entire tree; not just current directory (implies --full-name)"
msgstr ""
+"afficher l'arbre entier ; pas seulement le répertoire courant (implique --"
+"full-name)"
#: builtin/merge.c:43
msgid "git merge [options] [<commit>...]"
-msgstr ""
+msgstr "git merge [options] [<commit>...]"
#: builtin/merge.c:44
msgid "git merge [options] <msg> HEAD <commit>"
-msgstr ""
+msgstr "git merge [options] <message> HEAD <commit>"
#: builtin/merge.c:45
msgid "git merge --abort"
-msgstr ""
+msgstr "git merge --abort"
-#: builtin/merge.c:90
+#: builtin/merge.c:98
msgid "switch `m' requires a value"
-msgstr ""
+msgstr "le commutateur `m' a besoin d'une valeur"
-#: builtin/merge.c:127
+#: builtin/merge.c:135
#, c-format
msgid "Could not find merge strategy '%s'.\n"
-msgstr ""
+msgstr "Impossible de trouver la stratégie de fusion '%s'.\n"
-#: builtin/merge.c:128
+#: builtin/merge.c:136
#, c-format
msgid "Available strategies are:"
-msgstr ""
+msgstr "Les stratégies disponibles sont :"
-#: builtin/merge.c:133
+#: builtin/merge.c:141
#, c-format
msgid "Available custom strategies are:"
-msgstr ""
+msgstr "Les stratégies personnalisées sont :"
-#: builtin/merge.c:183
+#: builtin/merge.c:198
msgid "do not show a diffstat at the end of the merge"
-msgstr ""
+msgstr "ne pas afficher un diffstat à la fin de la fusion"
-#: builtin/merge.c:186
+#: builtin/merge.c:201
msgid "show a diffstat at the end of the merge"
-msgstr ""
+msgstr "afficher un diffstat à la fin de la fusion"
-#: builtin/merge.c:187
+#: builtin/merge.c:202
msgid "(synonym to --stat)"
-msgstr ""
+msgstr "(synonyme de --stat)"
-#: builtin/merge.c:189
+#: builtin/merge.c:204
msgid "add (at most <n>) entries from shortlog to merge commit message"
msgstr ""
+"ajouter (au plus <n>) éléments du journal court au message de validation de "
+"la fusion"
-#: builtin/merge.c:192
+#: builtin/merge.c:207
msgid "create a single commit instead of doing a merge"
-msgstr ""
+msgstr "créer une validation unique au lieu de faire une fusion"
-#: builtin/merge.c:194
+#: builtin/merge.c:209
msgid "perform a commit if the merge succeeds (default)"
-msgstr ""
+msgstr "effectuer une validation si la fusion réussit (défaut)"
-#: builtin/merge.c:196
+#: builtin/merge.c:211
msgid "edit message before committing"
-msgstr ""
+msgstr "éditer le message avant la validation"
-#: builtin/merge.c:198
+#: builtin/merge.c:212
msgid "allow fast-forward (default)"
-msgstr ""
+msgstr "autoriser l'avance rapide (défaut)"
-#: builtin/merge.c:200
+#: builtin/merge.c:214
msgid "abort if fast-forward is not possible"
-msgstr ""
+msgstr "abandonner si l'avance rapide n'est pas possible"
-#: builtin/merge.c:203
+#: builtin/merge.c:218
msgid "Verify that the named commit has a valid GPG signature"
-msgstr ""
+msgstr "Vérifier que la validation a une signature GPG valide"
-#: builtin/merge.c:204 builtin/notes.c:866 builtin/revert.c:112
+#: builtin/merge.c:219 builtin/notes.c:738 builtin/revert.c:114
msgid "strategy"
-msgstr ""
+msgstr "stratégie"
-#: builtin/merge.c:205
+#: builtin/merge.c:220
msgid "merge strategy to use"
-msgstr ""
+msgstr "stratégie de fusion à utiliser"
-#: builtin/merge.c:206
+#: builtin/merge.c:221
msgid "option=value"
-msgstr ""
+msgstr "option=valeur"
-#: builtin/merge.c:207
+#: builtin/merge.c:222
msgid "option for selected merge strategy"
-msgstr ""
+msgstr "option pour la stratégie de fusion sélectionnée"
-#: builtin/merge.c:209
+#: builtin/merge.c:224
msgid "merge commit message (for a non-fast-forward merge)"
msgstr ""
+"message de validation de la fusion (pour une fusion sans avance rapide)"
-#: builtin/merge.c:213
+#: builtin/merge.c:228
msgid "abort the current in-progress merge"
-msgstr ""
+msgstr "abandonner la fusion en cours"
-#: builtin/merge.c:242
+#: builtin/merge.c:257
msgid "could not run stash."
-msgstr ""
+msgstr "impossible de lancer le remisage."
-#: builtin/merge.c:247
+#: builtin/merge.c:262
msgid "stash failed"
-msgstr ""
+msgstr "échec du remisage"
-#: builtin/merge.c:252
+#: builtin/merge.c:267
#, c-format
msgid "not a valid object: %s"
-msgstr ""
+msgstr "pas un objet valide : %s"
-#: builtin/merge.c:271 builtin/merge.c:288
+#: builtin/merge.c:286 builtin/merge.c:303
msgid "read-tree failed"
-msgstr ""
+msgstr "read-tree a échoué"
-#: builtin/merge.c:318
+#: builtin/merge.c:333
msgid " (nothing to squash)"
msgstr " (rien à compresser)"
-#: builtin/merge.c:331
+#: builtin/merge.c:346
#, c-format
msgid "Squash commit -- not updating HEAD\n"
-msgstr ""
+msgstr "Validation compressée -- HEAD non mise à jour\n"
-#: builtin/merge.c:363
+#: builtin/merge.c:378
msgid "Writing SQUASH_MSG"
-msgstr ""
+msgstr "Écriture de SQUASH_MSG"
-#: builtin/merge.c:365
+#: builtin/merge.c:380
msgid "Finishing SQUASH_MSG"
-msgstr ""
+msgstr "Finition de SQUASH_MSG"
-#: builtin/merge.c:388
+#: builtin/merge.c:403
#, c-format
msgid "No merge message -- not updating HEAD\n"
-msgstr ""
+msgstr "Pas de message de fusion -- pas de mise à jour de HEAD\n"
-#: builtin/merge.c:438
+#: builtin/merge.c:453
#, c-format
msgid "'%s' does not point to a commit"
-msgstr ""
+msgstr "'%s' ne pointe pas sur un commit"
-#: builtin/merge.c:550
+#: builtin/merge.c:565
#, c-format
msgid "Bad branch.%s.mergeoptions string: %s"
-msgstr ""
+msgstr "Mauvaise chaîne branch.%s.mergeoptions : %s"
-#: builtin/merge.c:643
+#: builtin/merge.c:657
msgid "git write-tree failed to write a tree"
-msgstr ""
+msgstr "git write-tree a échoué à écrire un arbre"
-#: builtin/merge.c:671
+#: builtin/merge.c:685
msgid "Not handling anything other than two heads merge."
-msgstr ""
+msgstr "Impossible de gérer autre chose que la fusion de deux têtes."
-#: builtin/merge.c:685
+#: builtin/merge.c:699
#, c-format
msgid "Unknown option for merge-recursive: -X%s"
-msgstr ""
+msgstr "Options inconnue pour merge-recursive : -X%s"
-#: builtin/merge.c:699
+#: builtin/merge.c:713
#, c-format
msgid "unable to write %s"
-msgstr ""
+msgstr "impossible d'écrire %s"
-#: builtin/merge.c:788
+#: builtin/merge.c:802
#, c-format
msgid "Could not read from '%s'"
-msgstr ""
+msgstr "Impossible de lire depuis '%s'"
-#: builtin/merge.c:797
+#: builtin/merge.c:811
#, c-format
msgid "Not committing merge; use 'git commit' to complete the merge.\n"
msgstr ""
+"Pas de validation de la fusion ; utilisez 'git commit' pour terminer la "
+"fusion.\n"
-#: builtin/merge.c:803
+#: builtin/merge.c:817
#, c-format
msgid ""
"Please enter a commit message to explain why this merge is necessary,\n"
"Lines starting with '%c' will be ignored, and an empty message aborts\n"
"the commit.\n"
msgstr ""
+"Veuillez entrer un message de validation pour expliquer en quoi cette fusion "
+"est\n"
+"nécessaire, surtout si cela fusionne une branche amont mise à jour dans une "
+"branche de sujet.\n"
+"\n"
+"Les lignes commençant par '%c' seront ignorées, et un message vide\n"
+"abandonne la validation.\n"
-#: builtin/merge.c:827
+#: builtin/merge.c:841
msgid "Empty commit message."
-msgstr ""
+msgstr "Message de validation vide."
-#: builtin/merge.c:839
+#: builtin/merge.c:853
#, c-format
msgid "Wonderful.\n"
-msgstr ""
+msgstr "Merveilleux.\n"
-#: builtin/merge.c:904
+#: builtin/merge.c:918
#, c-format
msgid "Automatic merge failed; fix conflicts and then commit the result.\n"
msgstr ""
+"La fusion automatique a échoué ; réglez les conflits et validez le "
+"résultat.\n"
-#: builtin/merge.c:920
+#: builtin/merge.c:934
#, c-format
msgid "'%s' is not a commit"
-msgstr ""
+msgstr "'%s' n'est pas une validation"
-#: builtin/merge.c:961
+#: builtin/merge.c:975
msgid "No current branch."
-msgstr ""
+msgstr "Pas de branche courante."
-#: builtin/merge.c:963
+#: builtin/merge.c:977
msgid "No remote for the current branch."
-msgstr ""
+msgstr "Pas de branche distante pour la branche courante."
-#: builtin/merge.c:965
+#: builtin/merge.c:979
msgid "No default upstream defined for the current branch."
-msgstr ""
-
-#: builtin/merge.c:970
-#, c-format
-msgid "No remote tracking branch for %s from %s"
-msgstr ""
+msgstr "Pas de branche amont par défaut définie pour la branche courante."
-#: builtin/merge.c:1057 builtin/merge.c:1214
+#: builtin/merge.c:984
#, c-format
-msgid "%s - not something we can merge"
-msgstr ""
+msgid "No remote-tracking branch for %s from %s"
+msgstr "Pas de branche de suivi pour %s depuis %s"
-#: builtin/merge.c:1125
+#: builtin/merge.c:1140
msgid "There is no merge to abort (MERGE_HEAD missing)."
-msgstr ""
+msgstr "Il n'y a pas de fusion à abandonner (MERGE_HEAD manquant)."
-#: builtin/merge.c:1141 git-pull.sh:31
+#: builtin/merge.c:1156 git-pull.sh:31
msgid ""
"You have not concluded your merge (MERGE_HEAD exists).\n"
"Please, commit your changes before you can merge."
msgstr ""
+"Vous n'avez pas terminé votre fusion (MERGE_HEAD existe).\n"
+"Veuillez valider vos changements avant de pouvoir fusionner."
-#: builtin/merge.c:1144 git-pull.sh:34
+#: builtin/merge.c:1159 git-pull.sh:34
msgid "You have not concluded your merge (MERGE_HEAD exists)."
-msgstr ""
+msgstr "Vous n'avez pas terminé votre fusion (MERGE_HEAD existe)."
-#: builtin/merge.c:1148
+#: builtin/merge.c:1163
msgid ""
"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
"Please, commit your changes before you can merge."
msgstr ""
+"Vous n'avez pas terminé votre picorage (CHERRY_PICK_HEAD existe).\n"
+"Veuillez valider vos changements avant de pouvoir fusionner."
-#: builtin/merge.c:1151
+#: builtin/merge.c:1166
msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."
-msgstr ""
+msgstr "Vous n'avez pas terminé votre picorage (CHERRY_PICK_HEAD existe)."
-#: builtin/merge.c:1160
+#: builtin/merge.c:1175
msgid "You cannot combine --squash with --no-ff."
-msgstr ""
-
-#: builtin/merge.c:1165
-msgid "You cannot combine --no-ff with --ff-only."
-msgstr ""
+msgstr "Vous ne pouvez pas combiner --squash avec --no-ff."
-#: builtin/merge.c:1172
+#: builtin/merge.c:1184
msgid "No commit specified and merge.defaultToUpstream not set."
msgstr ""
+"Pas de validation spécifiée et merge.defaultToUpstream n'est pas défini."
-#: builtin/merge.c:1204
+#: builtin/merge.c:1216
msgid "Can merge only exactly one commit into empty head"
msgstr ""
+"Possible de fusionner exactement une seule validation dans une tête vide"
-#: builtin/merge.c:1207
+#: builtin/merge.c:1219
msgid "Squash commit into empty head not supported yet"
-msgstr ""
+msgstr "La validation compressée vers une tête vide n'est pas encore supportée"
-#: builtin/merge.c:1209
+#: builtin/merge.c:1221
msgid "Non-fast-forward commit does not make sense into an empty head"
-msgstr ""
+msgstr "Une validation sans avance rapide n'a pas de sens dans une tête vide"
+
+#: builtin/merge.c:1226
+#, c-format
+msgid "%s - not something we can merge"
+msgstr "%s - pas possible de fusionner ceci"
-#: builtin/merge.c:1265
+#: builtin/merge.c:1277
#, c-format
msgid "Commit %s has an untrusted GPG signature, allegedly by %s."
-msgstr ""
+msgstr "La validation %s a une signature GPG non fiable, prétendument par %s."
-#: builtin/merge.c:1268
+#: builtin/merge.c:1280
#, c-format
msgid "Commit %s has a bad GPG signature allegedly by %s."
-msgstr ""
+msgstr "La validation %s a une mauvaise signature GPG prétendument par %s."
#. 'N'
-#: builtin/merge.c:1271
+#: builtin/merge.c:1283
#, c-format
msgid "Commit %s does not have a GPG signature."
-msgstr ""
+msgstr "La validation %s n'a pas de signature GPG."
-#: builtin/merge.c:1274
+#: builtin/merge.c:1286
#, c-format
msgid "Commit %s has a good GPG signature by %s\n"
-msgstr ""
+msgstr "La validation %s a une signature GPG correcte par %s\n"
-#: builtin/merge.c:1358
+#: builtin/merge.c:1370
#, c-format
msgid "Updating %s..%s\n"
-msgstr ""
+msgstr "Mise à jour %s..%s\n"
-#: builtin/merge.c:1397
+#: builtin/merge.c:1409
#, c-format
msgid "Trying really trivial in-index merge...\n"
-msgstr ""
+msgstr "Essai de fusion vraiment triviale dans l'index...\n"
-#: builtin/merge.c:1404
+#: builtin/merge.c:1416
#, c-format
msgid "Nope.\n"
-msgstr ""
+msgstr "Non.\n"
-#: builtin/merge.c:1436
+#: builtin/merge.c:1448
msgid "Not possible to fast-forward, aborting."
-msgstr ""
+msgstr "Pas possible d'avancer rapidement, abandon."
-#: builtin/merge.c:1459 builtin/merge.c:1538
+#: builtin/merge.c:1471 builtin/merge.c:1550
#, c-format
msgid "Rewinding the tree to pristine...\n"
-msgstr ""
+msgstr "Retour de l'arbre à l'original...\n"
-#: builtin/merge.c:1463
+#: builtin/merge.c:1475
#, c-format
msgid "Trying merge strategy %s...\n"
-msgstr ""
+msgstr "Essai de la stratégie de fusion %s...\n"
-#: builtin/merge.c:1529
+#: builtin/merge.c:1541
#, c-format
msgid "No merge strategy handled the merge.\n"
-msgstr ""
+msgstr "Aucune stratégie de fusion n'a pris en charge la fusion.\n"
-#: builtin/merge.c:1531
+#: builtin/merge.c:1543
#, c-format
msgid "Merge with strategy %s failed.\n"
-msgstr ""
+msgstr "La fusion avec la stratégie %s a échoué.\n"
-#: builtin/merge.c:1540
+#: builtin/merge.c:1552
#, c-format
msgid "Using the %s to prepare resolving by hand.\n"
-msgstr ""
+msgstr "Utilisation de %s pour préparer la résolution à la main.\n"
-#: builtin/merge.c:1552
+#: builtin/merge.c:1564
#, c-format
msgid "Automatic merge went well; stopped before committing as requested\n"
msgstr ""
+"La fusion automatique a réussi ; stoppée avant la validation comme demandé\n"
#: builtin/merge-base.c:26
msgid "git merge-base [-a|--all] <commit> <commit>..."
-msgstr ""
+msgstr "git merge-base [-a|--all] <validation> <validation>..."
#: builtin/merge-base.c:27
msgid "git merge-base [-a|--all] --octopus <commit>..."
-msgstr ""
+msgstr "git merge-base [-a|--all] --octopus <validation>..."
#: builtin/merge-base.c:28
msgid "git merge-base --independent <commit>..."
-msgstr ""
+msgstr "git merge-base --independent <validation>..."
#: builtin/merge-base.c:29
msgid "git merge-base --is-ancestor <commit> <commit>"
-msgstr ""
+msgstr "git merge-base --is-ancestor <validation> <validation>"
#: builtin/merge-base.c:98
msgid "output all common ancestors"
-msgstr ""
+msgstr "afficher tous les ancêtres communs"
#: builtin/merge-base.c:99
msgid "find ancestors for a single n-way merge"
-msgstr ""
+msgstr "trouver les ancêtres pour une fusion simple à n points"
#: builtin/merge-base.c:100
msgid "list revs not reachable from others"
-msgstr ""
+msgstr "afficher les révisions inaccessibles depuis les autres"
#: builtin/merge-base.c:102
msgid "is the first one ancestor of the other?"
-msgstr ""
+msgstr "est le premier ancêtre de l'autre ?"
#: builtin/merge-file.c:8
msgid ""
"git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file "
"file2"
msgstr ""
+"git merge-file [options] [-L nom1 [-L orig [-L nom2]]] fichier1 orig_file "
+"fichier2"
#: builtin/merge-file.c:33
msgid "send results to standard output"
-msgstr ""
+msgstr "envoyer les résultats sur la sortie standard"
#: builtin/merge-file.c:34
msgid "use a diff3 based merge"
-msgstr ""
+msgstr "utiliser une fusion basée sur diff3"
#: builtin/merge-file.c:35
msgid "for conflicts, use our version"
-msgstr ""
+msgstr "pour les conflits, utiliser notre version (our)"
#: builtin/merge-file.c:37
msgid "for conflicts, use their version"
-msgstr ""
+msgstr "pour les conflits, utiliser leur version (their)"
#: builtin/merge-file.c:39
msgid "for conflicts, use a union version"
-msgstr ""
+msgstr "pour les conflits, utiliser l'ensemble des versions"
#: builtin/merge-file.c:42
msgid "for conflicts, use this marker size"
-msgstr ""
+msgstr "pour les conflits, utiliser cette taille de marqueur"
#: builtin/merge-file.c:43
msgid "do not warn about conflicts"
-msgstr ""
+msgstr "ne pas avertir à propos des conflits"
#: builtin/merge-file.c:45
msgid "set labels for file1/orig_file/file2"
-msgstr ""
+msgstr "définir les labels pour fichier1/orig_file/fichier2"
#: builtin/mktree.c:67
msgid "git mktree [-z] [--missing] [--batch]"
-msgstr ""
+msgstr "git mktree [-z] [--missing] [--batch]"
#: builtin/mktree.c:153
msgid "input is NUL terminated"
-msgstr ""
+msgstr "l'entrée se termine par NUL"
#: builtin/mktree.c:154 builtin/write-tree.c:24
msgid "allow missing objects"
-msgstr ""
+msgstr "autoriser les objets manquants"
#: builtin/mktree.c:155
msgid "allow creation of more than one tree"
-msgstr ""
+msgstr "autoriser la création de plus d'un arbre"
#: builtin/mv.c:14
msgid "git mv [options] <source>... <destination>"
-msgstr ""
+msgstr "git mv [options] <source>... <destination>"
#: builtin/mv.c:64
msgid "force move/rename even if target exists"
-msgstr ""
+msgstr "forcer le déplacement/renommage même si la cible existe"
#: builtin/mv.c:65
msgid "skip move/rename errors"
-msgstr ""
+msgstr "sauter les erreurs de déplacement/renommage"
#: builtin/mv.c:108
#, c-format
msgid "Checking rename of '%s' to '%s'\n"
-msgstr ""
+msgstr "Vérification du renommage de '%s' en '%s'\n"
#: builtin/mv.c:112
msgid "bad source"
-msgstr ""
+msgstr "mauvaise source"
#: builtin/mv.c:115
msgid "can not move directory into itself"
-msgstr ""
+msgstr "impossible de déplacer un répertoire dans lui-même"
#: builtin/mv.c:118
msgid "cannot move directory over file"
-msgstr ""
+msgstr "impossible de déplacer un répertoire sur un fichier"
#: builtin/mv.c:128
#, c-format
msgid "Huh? %.*s is in index?"
-msgstr ""
+msgstr "Hein ? %.*s est dans l'index ?"
#: builtin/mv.c:140
msgid "source directory is empty"
-msgstr ""
+msgstr "le répertoire source est vide"
#: builtin/mv.c:171
msgid "not under version control"
-msgstr ""
+msgstr "pas sous le contrôle de version"
#: builtin/mv.c:173
msgid "destination exists"
-msgstr ""
+msgstr "la destination existe"
#: builtin/mv.c:181
#, c-format
msgid "overwriting '%s'"
-msgstr ""
+msgstr "écrasement de '%s'"
#: builtin/mv.c:184
msgid "Cannot overwrite"
-msgstr ""
+msgstr "Impossible d'écraser"
#: builtin/mv.c:187
msgid "multiple sources for the same target"
-msgstr ""
+msgstr "multiples sources pour la même destination"
#: builtin/mv.c:202
#, c-format
#: builtin/mv.c:212
#, c-format
msgid "Renaming %s to %s\n"
-msgstr ""
+msgstr "Renommage de %s en %s\n"
#: builtin/mv.c:215 builtin/remote.c:731
#, c-format
msgid "renaming '%s' failed"
-msgstr ""
+msgstr "le renommage de '%s' a échoué"
-#: builtin/name-rev.c:175
+#: builtin/name-rev.c:259
msgid "git name-rev [options] <commit>..."
-msgstr ""
+msgstr "git name-rev [options] <validation>..."
-#: builtin/name-rev.c:176
+#: builtin/name-rev.c:260
msgid "git name-rev [options] --all"
-msgstr ""
+msgstr "git name-rev [options] --all"
-#: builtin/name-rev.c:177
+#: builtin/name-rev.c:261
msgid "git name-rev [options] --stdin"
-msgstr ""
+msgstr "git name-rev [options] --stdin"
-#: builtin/name-rev.c:229
+#: builtin/name-rev.c:313
msgid "print only names (no SHA-1)"
-msgstr ""
+msgstr "afficher seulement les noms (pas de SHA-1)"
-#: builtin/name-rev.c:230
+#: builtin/name-rev.c:314
msgid "only use tags to name the commits"
-msgstr ""
+msgstr "utiliser seulement les étiquettes pour nommer les validations"
-#: builtin/name-rev.c:232
+#: builtin/name-rev.c:316
msgid "only use refs matching <pattern>"
-msgstr ""
+msgstr "utiliser seulement les références correspondant à <motif>"
-#: builtin/name-rev.c:234
+#: builtin/name-rev.c:318
msgid "list all commits reachable from all refs"
msgstr ""
+"afficher toutes les validations accessibles depuis toutes les références"
-#: builtin/name-rev.c:235
+#: builtin/name-rev.c:319
msgid "read from stdin"
-msgstr ""
+msgstr "lire depuis l'entrée standard"
-#: builtin/name-rev.c:236
+#: builtin/name-rev.c:320
msgid "allow to print `undefined` names"
-msgstr ""
+msgstr "autoriser l'affichage des noms `non définis`"
-#: builtin/notes.c:26
+#: builtin/name-rev.c:326
+msgid "dereference tags in the input (internal use)"
+msgstr "déréférencer les étiquettes en entrée (usage interne)"
+
+#: builtin/notes.c:24
msgid "git notes [--ref <notes_ref>] [list [<object>]]"
-msgstr ""
+msgstr "git notes [--ref <références_notes>] [list [<object>]]"
-#: builtin/notes.c:27
+#: builtin/notes.c:25
msgid ""
"git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
"<object>] [<object>]"
msgstr ""
+"git notes [--ref <références_notes>] add [-f] [-m <message> | -F <fichier> | "
+"(-c | -C) <objet>] [<objet>]"
-#: builtin/notes.c:28
+#: builtin/notes.c:26
msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
msgstr ""
+"git notes [--ref <références_notes>] copy [-f] <depuis-objet> <vers-objet>"
-#: builtin/notes.c:29
+#: builtin/notes.c:27
msgid ""
"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
"<object>] [<object>]"
msgstr ""
+"git notes [--ref <références_notes>] append [-m <message> | -F <fichier> | (-"
+"c | -C) <objet>] [<objet>]"
-#: builtin/notes.c:30
+#: builtin/notes.c:28
msgid "git notes [--ref <notes_ref>] edit [<object>]"
-msgstr ""
+msgstr "git notes [--ref <références_notes>] edit [<objet>]"
-#: builtin/notes.c:31
+#: builtin/notes.c:29
msgid "git notes [--ref <notes_ref>] show [<object>]"
-msgstr ""
+msgstr "git notes [--ref <références_notes>] show [<objet>]"
-#: builtin/notes.c:32
+#: builtin/notes.c:30
msgid ""
"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
msgstr ""
+"git notes [--ref <références_notes>] merge [-v | -q] [-s <stratégie> ] "
+"<références_notes>"
-#: builtin/notes.c:33
+#: builtin/notes.c:31
msgid "git notes merge --commit [-v | -q]"
-msgstr ""
+msgstr "git notes merge --commit [-v | -q]"
-#: builtin/notes.c:34
+#: builtin/notes.c:32
msgid "git notes merge --abort [-v | -q]"
-msgstr ""
+msgstr "git notes merge --abort [-v | -q]"
-#: builtin/notes.c:35
+#: builtin/notes.c:33
msgid "git notes [--ref <notes_ref>] remove [<object>...]"
-msgstr ""
+msgstr "git notes [--ref <références_notes>] remove [<objet>...]"
-#: builtin/notes.c:36
+#: builtin/notes.c:34
msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
-msgstr ""
+msgstr "git notes [--ref <références_notes>] prune [-n | -v]"
-#: builtin/notes.c:37
+#: builtin/notes.c:35
msgid "git notes [--ref <notes_ref>] get-ref"
-msgstr ""
+msgstr "git notes [--ref <références_notes>] get-ref"
-#: builtin/notes.c:42
+#: builtin/notes.c:40
msgid "git notes [list [<object>]]"
-msgstr ""
+msgstr "git notes [list [<objet>]]"
-#: builtin/notes.c:47
+#: builtin/notes.c:45
msgid "git notes add [<options>] [<object>]"
-msgstr ""
+msgstr "git notes add [<options>] [<objet>]"
-#: builtin/notes.c:52
+#: builtin/notes.c:50
msgid "git notes copy [<options>] <from-object> <to-object>"
-msgstr ""
+msgstr "git notes copy [<options>] <depuis-objet> <vers-objet>"
-#: builtin/notes.c:53
+#: builtin/notes.c:51
msgid "git notes copy --stdin [<from-object> <to-object>]..."
-msgstr ""
+msgstr "git notes copy --stdin [<depuis-objet> <vers-objet>]..."
-#: builtin/notes.c:58
+#: builtin/notes.c:56
msgid "git notes append [<options>] [<object>]"
-msgstr ""
+msgstr "git notes append [<options>] [<objet>]"
-#: builtin/notes.c:63
+#: builtin/notes.c:61
msgid "git notes edit [<object>]"
-msgstr ""
+msgstr "git notes edit [<objet>]"
-#: builtin/notes.c:68
+#: builtin/notes.c:66
msgid "git notes show [<object>]"
-msgstr ""
+msgstr "git notes show [<objet>]"
-#: builtin/notes.c:73
+#: builtin/notes.c:71
msgid "git notes merge [<options>] <notes_ref>"
-msgstr ""
+msgstr "git notes merge [<options>] <références_notes>"
-#: builtin/notes.c:74
+#: builtin/notes.c:72
msgid "git notes merge --commit [<options>]"
-msgstr ""
+msgstr "git notes merge --commit [<options>]"
-#: builtin/notes.c:75
+#: builtin/notes.c:73
msgid "git notes merge --abort [<options>]"
-msgstr ""
+msgstr "git notes merge --abort [<options>]"
-#: builtin/notes.c:80
+#: builtin/notes.c:78
msgid "git notes remove [<object>]"
-msgstr ""
+msgstr "git notes remove [<objet>]"
-#: builtin/notes.c:85
+#: builtin/notes.c:83
msgid "git notes prune [<options>]"
-msgstr ""
+msgstr "git notes prune [<options>]"
-#: builtin/notes.c:90
+#: builtin/notes.c:88
msgid "git notes get-ref"
-msgstr ""
+msgstr "git notes get-ref"
-#: builtin/notes.c:139
+#: builtin/notes.c:137
#, c-format
msgid "unable to start 'show' for object '%s'"
-msgstr ""
+msgstr "impossible de démarrer 'show' pour l'objet '%s'"
-#: builtin/notes.c:143
+#: builtin/notes.c:141
msgid "could not read 'show' output"
-msgstr ""
+msgstr "impossible de lire la sortie de 'show'"
-#: builtin/notes.c:151
+#: builtin/notes.c:149
#, c-format
msgid "failed to finish 'show' for object '%s'"
-msgstr ""
+msgstr "impossible de finir 'show' pour l'objet '%s'"
-#: builtin/notes.c:169 builtin/tag.c:341
+#: builtin/notes.c:167 builtin/tag.c:341
#, c-format
msgid "could not create file '%s'"
-msgstr ""
+msgstr "impossible de créer le fichier '%s'"
-#: builtin/notes.c:188
+#: builtin/notes.c:186
msgid "Please supply the note contents using either -m or -F option"
-msgstr ""
+msgstr "Veuillez fournir le contenu de la note en utilisant l'option -m ou -F"
-#: builtin/notes.c:209 builtin/notes.c:972
+#: builtin/notes.c:207 builtin/notes.c:844
#, c-format
msgid "Removing note for object %s\n"
-msgstr ""
+msgstr "Suppression de la note pour l'objet %s\n"
-#: builtin/notes.c:214
+#: builtin/notes.c:212
msgid "unable to write note object"
-msgstr ""
+msgstr "impossible d'écrire l'objet note"
-#: builtin/notes.c:216
+#: builtin/notes.c:214
#, c-format
msgid "The note contents has been left in %s"
-msgstr ""
+msgstr "Le contenu de la note a été laissé dans %s"
-#: builtin/notes.c:250 builtin/tag.c:540
+#: builtin/notes.c:248 builtin/tag.c:540
#, c-format
msgid "cannot read '%s'"
-msgstr ""
+msgstr "impossible de lire '%s'"
-#: builtin/notes.c:252 builtin/tag.c:543
+#: builtin/notes.c:250 builtin/tag.c:543
#, c-format
msgid "could not open or read '%s'"
-msgstr ""
+msgstr "impossible d'ouvrir ou lire '%s'"
-#: builtin/notes.c:271 builtin/notes.c:444 builtin/notes.c:446
-#: builtin/notes.c:506 builtin/notes.c:560 builtin/notes.c:643
-#: builtin/notes.c:648 builtin/notes.c:723 builtin/notes.c:765
-#: builtin/notes.c:967 builtin/tag.c:556
+#: builtin/notes.c:269 builtin/notes.c:316 builtin/notes.c:318
+#: builtin/notes.c:378 builtin/notes.c:432 builtin/notes.c:515
+#: builtin/notes.c:520 builtin/notes.c:595 builtin/notes.c:637
+#: builtin/notes.c:839 builtin/tag.c:556
#, c-format
msgid "Failed to resolve '%s' as a valid ref."
-msgstr ""
+msgstr "Impossible de résoudre '%s' comme une référence valide."
-#: builtin/notes.c:274
+#: builtin/notes.c:272
#, c-format
msgid "Failed to read object '%s'."
-msgstr ""
-
-#: builtin/notes.c:298
-msgid "Cannot commit uninitialized/unreferenced notes tree"
-msgstr ""
-
-#: builtin/notes.c:339
-#, c-format
-msgid "Bad notes.rewriteMode value: '%s'"
-msgstr ""
-
-#: builtin/notes.c:349
-#, 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:376
-#, c-format
-msgid "Bad %s value: '%s'"
-msgstr ""
+msgstr "Impossible de lire l'objet '%s'."
-#: builtin/notes.c:440
+#: builtin/notes.c:312
#, c-format
msgid "Malformed input line: '%s'."
-msgstr ""
+msgstr "Ligne en entrée malformée : '%s'."
-#: builtin/notes.c:455
+#: builtin/notes.c:327
#, c-format
msgid "Failed to copy notes from '%s' to '%s'"
-msgstr ""
+msgstr "Impossible de copier les notes de '%s' vers '%s'"
-#: builtin/notes.c:499 builtin/notes.c:553 builtin/notes.c:626
-#: builtin/notes.c:638 builtin/notes.c:711 builtin/notes.c:758
-#: builtin/notes.c:1032
+#: builtin/notes.c:371 builtin/notes.c:425 builtin/notes.c:498
+#: builtin/notes.c:510 builtin/notes.c:583 builtin/notes.c:630
+#: builtin/notes.c:904
msgid "too many parameters"
-msgstr ""
+msgstr "trop de paramètres"
-#: builtin/notes.c:512 builtin/notes.c:771
+#: builtin/notes.c:384 builtin/notes.c:643
#, c-format
msgid "No note found for object %s."
-msgstr ""
+msgstr "Pas de note trouvée pour l'objet %s."
-#: builtin/notes.c:534 builtin/notes.c:691
+#: builtin/notes.c:406 builtin/notes.c:563
msgid "note contents as a string"
-msgstr ""
+msgstr "contenu de la note sous forme de chaîne"
-#: builtin/notes.c:537 builtin/notes.c:694
+#: builtin/notes.c:409 builtin/notes.c:566
msgid "note contents in a file"
-msgstr ""
+msgstr "contenu de la note dans un fichier"
-#: builtin/notes.c:539 builtin/notes.c:542 builtin/notes.c:696
-#: builtin/notes.c:699 builtin/tag.c:474
+#: builtin/notes.c:411 builtin/notes.c:414 builtin/notes.c:568
+#: builtin/notes.c:571 builtin/tag.c:474
msgid "object"
-msgstr ""
+msgstr "objet"
-#: builtin/notes.c:540 builtin/notes.c:697
+#: builtin/notes.c:412 builtin/notes.c:569
msgid "reuse and edit specified note object"
-msgstr ""
+msgstr "réutiliser et éditer l'objet de note spécifié"
-#: builtin/notes.c:543 builtin/notes.c:700
+#: builtin/notes.c:415 builtin/notes.c:572
msgid "reuse specified note object"
-msgstr ""
+msgstr "réutiliser l'objet de note spécifié"
-#: builtin/notes.c:545 builtin/notes.c:613
+#: builtin/notes.c:417 builtin/notes.c:485
msgid "replace existing notes"
-msgstr ""
+msgstr "remplacer les notes existantes"
-#: builtin/notes.c:579
+#: builtin/notes.c:451
#, c-format
msgid ""
"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
"existing notes"
msgstr ""
+"Impossible d'ajouter des notes. Des notes ont été trouvées pour l'objet %s. "
+"Utilisez '-f' pour écraser les notes existantes"
-#: builtin/notes.c:584 builtin/notes.c:661
+#: builtin/notes.c:456 builtin/notes.c:533
#, c-format
msgid "Overwriting existing notes for object %s\n"
-msgstr ""
+msgstr "Écrasement des notes existantes pour l'objet %s\n"
-#: builtin/notes.c:614
+#: builtin/notes.c:486
msgid "read objects from stdin"
-msgstr ""
+msgstr "lire les objets depuis l'entrée standard"
-#: builtin/notes.c:616
+#: builtin/notes.c:488
msgid "load rewriting config for <command> (implies --stdin)"
msgstr ""
+"charger la configuration de réécriture pour <commande> (implique --stdin)"
-#: builtin/notes.c:634
+#: builtin/notes.c:506
msgid "too few parameters"
-msgstr ""
+msgstr "pas assez de paramètres"
-#: builtin/notes.c:655
+#: builtin/notes.c:527
#, c-format
msgid ""
"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
"existing notes"
msgstr ""
+"Impossible de copier des notes. Des notes ont été trouvées pour l'objet %s. "
+"Utilisez '-f' pour écraser les notes existantes"
-#: builtin/notes.c:667
+#: builtin/notes.c:539
#, c-format
msgid "Missing notes on source object %s. Cannot copy."
-msgstr ""
+msgstr "Notes manquantes sur l'objet source %s. Impossible de copier."
-#: builtin/notes.c:716
+#: builtin/notes.c:588
#, 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 ""
+"Les options -m/-F/-c/-C sont obsolètes pour la sous-commande 'edit'.\n"
+"Veuillez utiliser 'git notes add -f -m/-F/-c/-C' à la place.\n"
-#: builtin/notes.c:863
+#: builtin/notes.c:735
msgid "General options"
-msgstr ""
+msgstr "Options générales"
-#: builtin/notes.c:865
+#: builtin/notes.c:737
msgid "Merge options"
-msgstr ""
+msgstr "Options de fusion"
-#: builtin/notes.c:867
+#: builtin/notes.c:739
msgid ""
"resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
"cat_sort_uniq)"
msgstr ""
+"résoudre les conflits de notes en utilisant la stratégie donnée (manual/ours/"
+"theirs/union/cat_sort_uniq)"
-#: builtin/notes.c:869
+#: builtin/notes.c:741
msgid "Committing unmerged notes"
-msgstr ""
+msgstr "Validation des notes non fusionnées"
-#: builtin/notes.c:871
+#: builtin/notes.c:743
msgid "finalize notes merge by committing unmerged notes"
-msgstr ""
+msgstr "finaliser la fusion de notes en validant les notes non fusionnées"
-#: builtin/notes.c:873
+#: builtin/notes.c:745
msgid "Aborting notes merge resolution"
-msgstr ""
+msgstr "Abandon de la résolution de fusion des notes"
-#: builtin/notes.c:875
+#: builtin/notes.c:747
msgid "abort notes merge"
-msgstr ""
+msgstr "abandonner la fusion de notes"
-#: builtin/notes.c:970
+#: builtin/notes.c:842
#, c-format
msgid "Object %s has no note\n"
-msgstr ""
+msgstr "L'objet %s n'a pas de note\n"
-#: builtin/notes.c:982
+#: builtin/notes.c:854
msgid "attempt to remove non-existent note is not an error"
msgstr ""
+"la tentative de suppression d'une note non existante n'est pas une erreur"
-#: builtin/notes.c:985
+#: builtin/notes.c:857
msgid "read object names from the standard input"
-msgstr ""
+msgstr "lire les noms d'objet depuis l'entrée standard"
-#: builtin/notes.c:1066
+#: builtin/notes.c:938
msgid "notes_ref"
-msgstr ""
+msgstr "références_notes"
-#: builtin/notes.c:1067
+#: builtin/notes.c:939
msgid "use notes from <notes_ref>"
-msgstr ""
+msgstr "utiliser les notes depuis <références_notes>"
-#: builtin/notes.c:1102 builtin/remote.c:1598
+#: builtin/notes.c:974 builtin/remote.c:1598
#, c-format
msgid "Unknown subcommand: %s"
-msgstr ""
+msgstr "Sous-commande inconnue : %s"
#: builtin/pack-objects.c:23
msgid "git pack-objects --stdout [options...] [< ref-list | < object-list]"
msgstr ""
+"git pack-objects --stdout [options...] [< liste-références | < liste-objets]"
#: builtin/pack-objects.c:24
msgid "git pack-objects [options...] base-name [< ref-list | < object-list]"
msgstr ""
+"git pack-objects [options...] base-name [< liste-références | < liste-objets]"
#: builtin/pack-objects.c:183 builtin/pack-objects.c:186
#, c-format
msgid "deflate error (%d)"
-msgstr ""
+msgstr "erreur de compression (%d)"
#: builtin/pack-objects.c:2397
#, c-format
msgid "unsupported index version %s"
-msgstr ""
+msgstr "version d'index non supportée %s"
#: builtin/pack-objects.c:2401
#, c-format
msgid "bad index version '%s'"
-msgstr ""
+msgstr "mauvaise version d'index '%s'"
#: builtin/pack-objects.c:2424
#, c-format
msgid "option %s does not accept negative form"
-msgstr ""
+msgstr "l'option %s n'accepte pas de valeur négative"
#: builtin/pack-objects.c:2428
#, c-format
msgid "unable to parse value '%s' for option %s"
-msgstr ""
+msgstr "impossible d'analyser la valeur '%s' pour l'option %s"
#: builtin/pack-objects.c:2447
msgid "do not show progress meter"
-msgstr ""
+msgstr "ne pas afficher la barre de progression"
#: builtin/pack-objects.c:2449
msgid "show progress meter"
-msgstr ""
+msgstr "afficher la barre de progression"
#: builtin/pack-objects.c:2451
msgid "show progress meter during object writing phase"
-msgstr ""
+msgstr "afficher la barre de progression durant la phase d'écrite des objets"
#: builtin/pack-objects.c:2454
msgid "similar to --all-progress when progress meter is shown"
-msgstr ""
+msgstr "similaire à --all-progress quand la barre de progression est affichée"
#: builtin/pack-objects.c:2455
msgid "version[,offset]"
-msgstr ""
+msgstr "version[,offset]"
#: builtin/pack-objects.c:2456
msgid "write the pack index file in the specified idx format version"
msgstr ""
+"écrire le fichier d'index du paquet dans le format d'index de version "
+"spécifié"
#: builtin/pack-objects.c:2459
msgid "maximum size of each output pack file"
-msgstr ""
+msgstr "taille maximum de chaque fichier paquet en sortie"
#: builtin/pack-objects.c:2461
msgid "ignore borrowed objects from alternate object store"
-msgstr ""
+msgstr "ignorer les objets empruntés à un autre magasin d'objets"
#: builtin/pack-objects.c:2463
msgid "ignore packed objects"
-msgstr ""
+msgstr "ignorer les objets empaquetés"
#: builtin/pack-objects.c:2465
msgid "limit pack window by objects"
-msgstr ""
+msgstr "limiter la fenêtre d'empaquetage par objets"
#: builtin/pack-objects.c:2467
msgid "limit pack window by memory in addition to object limit"
msgstr ""
+"limiter la fenêtre d'empaquetage par mémoire en plus de la limite d'objets"
#: builtin/pack-objects.c:2469
msgid "maximum length of delta chain allowed in the resulting pack"
msgstr ""
+"longueur maximum de la chaîne de delta autorisée dans le paquet résultant"
#: builtin/pack-objects.c:2471
msgid "reuse existing deltas"
-msgstr ""
+msgstr "réutiliser les deltas existants"
#: builtin/pack-objects.c:2473
msgid "reuse existing objects"
-msgstr ""
+msgstr "réutiliser les objets existants"
#: builtin/pack-objects.c:2475
msgid "use OFS_DELTA objects"
-msgstr ""
+msgstr "utiliser les objets OFS_DELTA"
#: builtin/pack-objects.c:2477
msgid "use threads when searching for best delta matches"
msgstr ""
+"utiliser des fils lors de la recherche pour une meilleurs correspondance des "
+"deltas"
#: builtin/pack-objects.c:2479
msgid "do not create an empty pack output"
-msgstr ""
+msgstr "ne pas créer un paquet vide"
#: builtin/pack-objects.c:2481
msgid "read revision arguments from standard input"
-msgstr ""
+msgstr "lire les paramètres de révision depuis l'entrée standard"
#: builtin/pack-objects.c:2483
msgid "limit the objects to those that are not yet packed"
-msgstr ""
+msgstr "limiter les objets à ceux qui ne sont pas encore empaquetés"
#: builtin/pack-objects.c:2486
msgid "include objects reachable from any reference"
-msgstr ""
+msgstr "inclure les objets accessibles depuis toute référence"
#: builtin/pack-objects.c:2489
msgid "include objects referred by reflog entries"
-msgstr ""
+msgstr "inclure les objets référencés par les éléments de reflog"
#: builtin/pack-objects.c:2492
msgid "output pack to stdout"
-msgstr ""
+msgstr "afficher l'empaquetage sur la sortie standard"
#: builtin/pack-objects.c:2494
msgid "include tag objects that refer to objects to be packed"
-msgstr ""
+msgstr "inclure les objets d'étiquettes qui réfèrent à des objets à empaqueter"
#: builtin/pack-objects.c:2496
msgid "keep unreachable objects"
-msgstr ""
+msgstr "garder les objets inaccessibles"
#: builtin/pack-objects.c:2497 parse-options.h:141
msgid "time"
-msgstr ""
+msgstr "heure"
#: builtin/pack-objects.c:2498
msgid "unpack unreachable objects newer than <time>"
-msgstr ""
+msgstr "dépaqueter les objets inaccessibles plus récents que <heure>"
#: builtin/pack-objects.c:2501
msgid "create thin packs"
-msgstr ""
+msgstr "créer des paquets légers"
#: builtin/pack-objects.c:2503
msgid "ignore packs that have companion .keep file"
-msgstr ""
+msgstr "ignorer les paquets qui ont un fichier .keep"
#: builtin/pack-objects.c:2505
msgid "pack compression level"
-msgstr ""
+msgstr "niveau de compression du paquet"
#: builtin/pack-objects.c:2507
msgid "do not hide commits by grafts"
-msgstr ""
+msgstr "ne pas cacher les validations par greffes"
#: builtin/pack-refs.c:6
msgid "git pack-refs [options]"
-msgstr ""
+msgstr "git pack-refs [options]"
#: builtin/pack-refs.c:14
msgid "pack everything"
-msgstr ""
+msgstr "empaqueter tout"
#: builtin/pack-refs.c:15
msgid "prune loose refs (default)"
-msgstr ""
+msgstr "éliminer les références perdues (défaut)"
#: builtin/prune-packed.c:7
msgid "git prune-packed [-n|--dry-run] [-q|--quiet]"
-msgstr ""
+msgstr "git prune-packed [-n|--dry-run] [-q|--quiet]"
#: builtin/prune.c:12
msgid "git prune [-n] [-v] [--expire <time>] [--] [<head>...]"
-msgstr ""
+msgstr "git prune [-n] [-v] [--expire <heure>] [--] [<head>...]"
#: builtin/prune.c:132
msgid "do not remove, show only"
-msgstr ""
+msgstr "ne pas supprimer, afficher seulement"
#: builtin/prune.c:133
msgid "report pruned objects"
-msgstr ""
+msgstr "afficher les objets éliminés"
#: builtin/prune.c:136
msgid "expire objects older than <time>"
-msgstr ""
+msgstr "faire expirer les objets plus vieux que <heure>"
#: builtin/push.c:14
msgid "git push [<options>] [<repository> [<refspec>...]]"
-msgstr ""
+msgstr "git push [<options>] [<dépôt> [<spécification-de-référence>...]]"
#: builtin/push.c:45
msgid "tag shorthand without <tag>"
-msgstr ""
+msgstr "raccourci d'étiquette sans <étiquette>"
#: builtin/push.c:64
msgid "--delete only accepts plain target ref names"
-msgstr ""
+msgstr "--delete accepte seulement des noms entiers de références cibles"
#: builtin/push.c:99
msgid ""
"\n"
"To choose either option permanently, see push.default in 'git help config'."
msgstr ""
+"\n"
+"Pour choisir l'option de manière permanente, voir push.default dans 'git "
+"help config'."
#: builtin/push.c:102
#, c-format
" git push %s %s\n"
"%s"
msgstr ""
+"La branche amont de votre branche courante ne correspond pas\n"
+"au nom de votre branche courante. Pour pousser vers la branche amont\n"
+"sur le serveur distant, utilisez\n"
+"\n"
+" git push %s HEAD:%s\n"
+"\n"
+"Pour pousser vers la branche du même nom sur le serveur distant, utilisez\n"
+"\n"
+" git push %s %s\n"
+"%s"
-#: builtin/push.c:121
+#: builtin/push.c:117
#, c-format
msgid ""
"You are not currently on a branch.\n"
"\n"
" git push %s HEAD:<name-of-remote-branch>\n"
msgstr ""
+"Vous n'êtes actuellement sur aucune branche.\n"
+"Pour pousser l'historique menant à l'état actuel (HEAD détachée),\n"
+"utilisez\n"
+"\n"
+" git push %s HEAD:<nom-de-la-branche-amont>\n"
-#: builtin/push.c:128
+#: builtin/push.c:131
#, c-format
msgid ""
"The current branch %s has no upstream branch.\n"
"\n"
" git push --set-upstream %s %s\n"
msgstr ""
+"La branche courante %s n'a pas de branche amont.\n"
+"Pour pousser la branche courante et définir la distante comme amont, "
+"utilisez\n"
+"\n"
+" git push --set-upstream %s %s\n"
-#: builtin/push.c:136
+#: builtin/push.c:139
#, c-format
msgid "The current branch %s has multiple upstream branches, refusing to push."
msgstr ""
+"La branche courante %s a de multiples branches amont, impossible de pousser."
-#: builtin/push.c:139
+#: builtin/push.c:142
#, c-format
msgid ""
"You are pushing to remote '%s', which is not the upstream of\n"
"your current branch '%s', without telling me what to push\n"
"to update which remote branch."
msgstr ""
+"Vous êtes en train de pousser vers la branche distante '%s', qui n'est\n"
+"pas une branche amont de votre branche courante '%s', sans me dire\n"
+"quoi pousser pour mettre à jour quelle branche amont."
-#: builtin/push.c:151
+#: builtin/push.c:165
msgid ""
"push.default is unset; its implicit value is changing in\n"
"Git 2.0 from 'matching' to 'simple'. To squelch this message\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 n'est pas défini ; sa valeur implicite change dans Git 2.0\n"
+"de 'matching' vers 'simple'. Pour supprimer ce message et maintenir\n"
+"le comportement actuel après les changements par défaut, utilisez :\n"
+"\n"
+" git config --global push.default matching\n"
+"\n"
+"Pour supprimer ce message et adopter le nouveau comportement maintenant, "
+"utilisez :\n"
+"\n"
+" git config --global push.default simple\n"
+"\n"
+"Voir 'git help config' et chercher 'push.default' pour plus d'information.\n"
+"(le mode 'simple' a été introduit dans Git 1.7.11. Utilisez le mode "
+"similaire\n"
+"'current' au lieu de 'simple' si vous utilisez de temps en temps d'anciennes "
+"versions de Git)"
-#: builtin/push.c:199
+#: builtin/push.c:225
msgid ""
"You didn't specify any refspecs to push, and push.default is \"nothing\"."
msgstr ""
+"Vous n'avez pas spécifié de spécifications de référence à pousser, et push."
+"default est \"nothing\"."
-#: builtin/push.c:206
+#: builtin/push.c:232
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"
-"before pushing again.\n"
+"its remote counterpart. Integrate the remote changes (e.g.\n"
+"'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
+"Les mises à jour ont été rejetées car la pointe de la branche courante est "
+"derrière\n"
+"son homologue distant. Intégrez les changements distants (par exemple 'git "
+"pull ...')\n"
+"avant de pousser à nouveau.\n"
+"Voir la 'Note à propos des avances rapides' dans 'git push --help' pour plus "
+"d'information."
-#: builtin/push.c:212
+#: builtin/push.c:238
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 variable\n"
"to 'simple', 'current' or 'upstream' to push only the current branch."
msgstr ""
+"Les mises à jour ont été rejetées car la pointe de la branche poussée est "
+"derrière\n"
+"son homologue distant. Si vous ne vouliez pas pousser cette branche, vous "
+"pourriez\n"
+"vouloir spécifier les branches à pousser ou définir la variable de "
+"configuration\n"
+"'push.default' à 'simple', 'current' ou 'upstream' pour pousser seulement la "
+"branche courante."
-#: builtin/push.c:218
+#: builtin/push.c:244
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"
-"(e.g. 'git pull') before pushing again.\n"
+"counterpart. Check out this branch and integrate the remote changes\n"
+"(e.g. 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
+"Les mises à jour ont été rejetées car la pointe de la branche courante est "
+"derrière\n"
+"son homologue distant. Extrayez cette branche et Intégrez les changements "
+"distants\n"
+"(par exemple 'git pull ...') avant de pousser à nouveau.\n"
+"Voir la 'Note à propos des avances rapides' dans 'git push --help' pour plus "
+"d'information."
-#: builtin/push.c:224
+#: builtin/push.c:250
msgid ""
"Updates were rejected because the remote contains work that you do\n"
"not have locally. This is usually caused by another repository pushing\n"
-"to the same ref. You may want to first merge the remote changes (e.g.,\n"
-"'git pull') before pushing again.\n"
+"to the same ref. You may want to first integrate the remote changes\n"
+"(e.g., 'git pull ...') before pushing again.\n"
"See the 'Note about fast-forwards' in 'git push --help' for details."
msgstr ""
-
-#: builtin/push.c:231
+"Les mises à jour ont été rejetées car la branche distante contient du "
+"travail que\n"
+"vous n'avez pas en local. Ceci est généralement causé par un autre dépôt "
+"poussé\n"
+"vers la même référence. Vous pourriez intégrer d'abord les changements "
+"distants\n"
+"(par exemple 'git pull ...') avant de pousser à nouveau.\n"
+"Voir la 'Note à propos des avances rapides' dans 'git push --help' pour plus "
+"d'information."
+
+#: builtin/push.c:257
msgid "Updates were rejected because the tag already exists in the remote."
msgstr ""
+"Les mises à jour ont été rejetées car l'étiquette existe déjà dans la "
+"branche distante."
-#: builtin/push.c:234
+#: builtin/push.c:260
msgid ""
"You cannot update a remote ref that points at a non-commit object,\n"
"or update a remote ref to make it point at a non-commit object,\n"
"without using the '--force' option.\n"
msgstr ""
+"Vous ne pouvez pas mettre à jour une référence distante qui pointe sur un "
+"objet qui\n"
+"n'est pas un commit, ou mettre à jour une référence distante pour la faire "
+"pointer\n"
+"vers un objet qui n'est pas un commit, sans utiliser l'option '--force'.\n"
-#: builtin/push.c:294
+#: builtin/push.c:320
#, c-format
msgid "Pushing to %s\n"
-msgstr ""
+msgstr "Poussage vers %s\n"
-#: builtin/push.c:298
+#: builtin/push.c:324
#, c-format
msgid "failed to push some refs to '%s'"
-msgstr ""
+msgstr "impossible de pousser des références vers '%s'"
-#: builtin/push.c:331
+#: builtin/push.c:357
#, c-format
msgid "bad repository '%s'"
-msgstr ""
+msgstr "mauvais dépôt '%s'"
-#: builtin/push.c:332
+#: builtin/push.c:358
msgid ""
"No configured push destination.\n"
"Either specify the URL from the command-line or configure a remote "
"\n"
" git push <name>\n"
msgstr ""
+"Pas de destination pour pousser.\n"
+"Spécifiez une URL depuis la ligne de commande ou configurez un dépôt distant "
+"en utilisant\n"
+"\n"
+" git remote add <nom> <url>\n"
+"\n"
+"et poussez alors en utilisant le dépôt distant\n"
+"\n"
+" git push <nom>\n"
-#: builtin/push.c:347
+#: builtin/push.c:373
msgid "--all and --tags are incompatible"
-msgstr ""
+msgstr "--all et --tags sont incompatibles"
-#: builtin/push.c:348
+#: builtin/push.c:374
msgid "--all can't be combined with refspecs"
-msgstr ""
+msgstr "--all ne peut pas être combiné avec des spécifications de référence"
-#: builtin/push.c:353
+#: builtin/push.c:379
msgid "--mirror and --tags are incompatible"
-msgstr ""
+msgstr "--mirror et --tags sont incompatibles"
-#: builtin/push.c:354
+#: builtin/push.c:380
msgid "--mirror can't be combined with refspecs"
-msgstr ""
+msgstr "--mirror ne peut pas être combiné avec des spécifications de référence"
-#: builtin/push.c:359
+#: builtin/push.c:385
msgid "--all and --mirror are incompatible"
-msgstr ""
+msgstr "--all et --mirror sont incompatibles"
-#: builtin/push.c:419
+#: builtin/push.c:445
msgid "repository"
-msgstr ""
+msgstr "dépôt"
-#: builtin/push.c:420
+#: builtin/push.c:446
msgid "push all refs"
-msgstr ""
+msgstr "pousser toutes les références"
-#: builtin/push.c:421
+#: builtin/push.c:447
msgid "mirror all refs"
-msgstr ""
+msgstr "refléter toutes les références"
-#: builtin/push.c:423
+#: builtin/push.c:449
msgid "delete refs"
-msgstr ""
+msgstr "supprimer les références"
-#: builtin/push.c:424
+#: builtin/push.c:450
msgid "push tags (can't be used with --all or --mirror)"
msgstr ""
+"pousser les étiquettes (ne peut pas être utilisé avec --all ou --mirror)"
-#: builtin/push.c:427
+#: builtin/push.c:453
msgid "force updates"
-msgstr ""
+msgstr "forcer les mises à jour"
-#: builtin/push.c:428
+#: builtin/push.c:454
msgid "check"
-msgstr ""
+msgstr "check"
-#: builtin/push.c:429
+#: builtin/push.c:455
msgid "control recursive pushing of submodules"
-msgstr ""
+msgstr "contrôler le poussage récursif des sous-modules"
-#: builtin/push.c:431
+#: builtin/push.c:457
msgid "use thin pack"
-msgstr ""
+msgstr "utiliser un empaquetage léger"
-#: builtin/push.c:432 builtin/push.c:433
+#: builtin/push.c:458 builtin/push.c:459
msgid "receive pack program"
-msgstr ""
+msgstr "recevoir le programme d'empaquetage"
-#: builtin/push.c:434
+#: builtin/push.c:460
msgid "set upstream for git pull/status"
-msgstr ""
+msgstr "définir la branche amont pour git pull/status"
-#: builtin/push.c:437
+#: builtin/push.c:463
msgid "prune locally removed refs"
-msgstr ""
+msgstr "éliminer les références locales supprimées"
-#: builtin/push.c:439
+#: builtin/push.c:465
msgid "bypass pre-push hook"
-msgstr ""
+msgstr "éviter d'utiliser le crochet pre-push"
-#: builtin/push.c:440
+#: builtin/push.c:466
msgid "push missing but relevant tags"
-msgstr ""
+msgstr "pousser les étiquettes manquantes mais pertinentes"
-#: builtin/push.c:450
+#: builtin/push.c:476
msgid "--delete is incompatible with --all, --mirror and --tags"
-msgstr ""
+msgstr "--delete est incompatible avec --all, --mirror et --tags"
-#: builtin/push.c:452
+#: builtin/push.c:478
msgid "--delete doesn't make sense without any refs"
-msgstr ""
+msgstr "--delete n'a pas de sens sans aucune référence"
#: builtin/read-tree.c:36
msgid ""
"[-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=<préfixe>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-"
+"sparse-checkout] [--index-output=<fichier>] (--empty | <arbre ou apparenté "
+"1> [<arbre ou apparenté 2> [<arbre ou apparenté 3>]])"
-#: builtin/read-tree.c:108
+#: builtin/read-tree.c:109
msgid "write resulting index to <file>"
-msgstr ""
+msgstr "écrire l'index résultant dans <fichier>"
-#: builtin/read-tree.c:111
+#: builtin/read-tree.c:112
msgid "only empty the index"
-msgstr ""
+msgstr "juste vider l'index"
-#: builtin/read-tree.c:113
+#: builtin/read-tree.c:114
msgid "Merging"
-msgstr ""
+msgstr "Fusion"
-#: builtin/read-tree.c:115
+#: builtin/read-tree.c:116
msgid "perform a merge in addition to a read"
-msgstr ""
+msgstr "effectuer une fusion en plus d'une lecture"
-#: builtin/read-tree.c:117
+#: builtin/read-tree.c:118
msgid "3-way merge if no file level merging required"
-msgstr ""
+msgstr "fusion à 3 points si aucune fusion de niveau fichier n'est requise"
-#: builtin/read-tree.c:119
+#: builtin/read-tree.c:120
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 ""
+msgstr "fusion à 3 points en présence d'ajouts et suppressions"
#: builtin/read-tree.c:122
-msgid "<subdirectory>/"
-msgstr ""
+msgid "same as -m, but discard unmerged entries"
+msgstr "comme -m, mais annule les éléments non fusionnés"
#: builtin/read-tree.c:123
+msgid "<subdirectory>/"
+msgstr "<sous-répertoire>/"
+
+#: builtin/read-tree.c:124
msgid "read the tree into the index under <subdirectory>/"
-msgstr ""
+msgstr "lire l'arbre dans l'index dans <sous-répertoire>/"
-#: builtin/read-tree.c:126
+#: builtin/read-tree.c:127
msgid "update working tree with merge result"
-msgstr ""
+msgstr "mettre à jour la copie de travail avec le résultat de la fusion"
-#: builtin/read-tree.c:128
+#: builtin/read-tree.c:129
msgid "gitignore"
-msgstr ""
+msgstr "gitignore"
-#: builtin/read-tree.c:129
+#: builtin/read-tree.c:130
msgid "allow explicitly ignored files to be overwritten"
-msgstr ""
+msgstr "autoriser explicitement les fichiers ignorés à être écrasés"
-#: builtin/read-tree.c:132
+#: builtin/read-tree.c:133
msgid "don't check the working tree after merging"
-msgstr ""
+msgstr "ne pas vérifier la copie de travail après la fusion"
-#: builtin/read-tree.c:133
+#: builtin/read-tree.c:134
msgid "don't update the index or the work tree"
-msgstr ""
+msgstr "ne pas mettre à jour l'index ou la copie de travail"
-#: builtin/read-tree.c:135
+#: builtin/read-tree.c:136
msgid "skip applying sparse checkout filter"
-msgstr ""
+msgstr "sauter l'application du filtre d'extraction creuse"
-#: builtin/read-tree.c:137
+#: builtin/read-tree.c:138
msgid "debug unpack-trees"
-msgstr ""
+msgstr "deboguer unpack-trees"
+
+#: builtin/reflog.c:500
+#, c-format
+msgid "%s' for '%s' is not a valid timestamp"
+msgstr "%s' pour '%s' n'est pas un horodatage valide"
+
+#: builtin/reflog.c:616 builtin/reflog.c:621
+#, c-format
+msgid "'%s' is not a valid timestamp"
+msgstr "'%s' n'est pas un horodatage valide"
#: builtin/remote.c:11
msgid "git remote [-v | --verbose]"
-msgstr ""
+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 <branche>] [-m <maîtresse>] [-f] [--tags|--no-tags] [--"
+"mirror=<fetch|push>] <nom> <URL>"
#: builtin/remote.c:13 builtin/remote.c:32
msgid "git remote rename <old> <new>"
-msgstr ""
+msgstr "git remote rename <ancienne> <nouvelle>"
#: builtin/remote.c:14 builtin/remote.c:37
msgid "git remote remove <name>"
-msgstr ""
+msgstr "git remote remove <nom>"
#: builtin/remote.c:15 builtin/remote.c:42
msgid "git remote set-head <name> (-a | -d | <branch>)"
-msgstr ""
+msgstr "git remote set-head <nom> (-a | -d | <branche>)"
#: builtin/remote.c:16
msgid "git remote [-v | --verbose] show [-n] <name>"
-msgstr ""
+msgstr "git remote [-v | --verbose] show [-n] <nom>"
#: builtin/remote.c:17
msgid "git remote prune [-n | --dry-run] <name>"
-msgstr ""
+msgstr "git remote prune [-n | --dry-run] <nom>"
#: builtin/remote.c:18
msgid ""
"git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"
msgstr ""
+"git remote [-v | --verbose] update [-p | --prune] [(<groupe> | "
+"<distante>)...]"
#: builtin/remote.c:19
msgid "git remote set-branches [--add] <name> <branch>..."
-msgstr ""
+msgstr "git remote set-branches [--add] <nom> <branche>..."
#: builtin/remote.c:20 builtin/remote.c:68
msgid "git remote set-url [--push] <name> <newurl> [<oldurl>]"
-msgstr ""
+msgstr "git remote set-url [--push] <nom> <nouvelle-URL> [<ancienne-URL>]"
#: builtin/remote.c:21 builtin/remote.c:69
msgid "git remote set-url --add <name> <newurl>"
-msgstr ""
+msgstr "git remote set-url --add <nom> <nouvelle-URL>"
#: builtin/remote.c:22 builtin/remote.c:70
msgid "git remote set-url --delete <name> <url>"
-msgstr ""
+msgstr "git remote set-url --delete <nom> <URL>"
#: builtin/remote.c:27
msgid "git remote add [<options>] <name> <url>"
-msgstr ""
+msgstr "git remote add [<options>] <nom> <URL>"
#: builtin/remote.c:47
msgid "git remote set-branches <name> <branch>..."
-msgstr ""
+msgstr "git remote set-branches <nom> <branche>..."
#: builtin/remote.c:48
msgid "git remote set-branches --add <name> <branch>..."
-msgstr ""
+msgstr "git remote set-branches --add <nom> <branche>..."
#: builtin/remote.c:53
msgid "git remote show [<options>] <name>"
-msgstr ""
+msgstr "git remote show [<options>] <nom>"
#: builtin/remote.c:58
msgid "git remote prune [<options>] <name>"
-msgstr ""
+msgstr "git remote prune [<options>] <nom>"
#: builtin/remote.c:63
msgid "git remote update [<options>] [<group> | <remote>]..."
-msgstr ""
+msgstr "git remote update [<options>] [<groupe> | <distante>]..."
#: builtin/remote.c:98
#, c-format
msgid "Updating %s"
-msgstr ""
+msgstr "Mise à jour de %s"
#: builtin/remote.c:130
msgid ""
"--mirror is dangerous and deprecated; please\n"
"\t use --mirror=fetch or --mirror=push instead"
msgstr ""
+"--mirror est dangereux et obsolète ; merci\n"
+"\t d'utiliser --mirror=fetch ou --mirror=push à la place"
#: builtin/remote.c:147
#, c-format
msgid "unknown mirror argument: %s"
-msgstr ""
+msgstr "argument miroir inconnu : %s"
#: builtin/remote.c:163
msgid "fetch the remote branches"
-msgstr ""
+msgstr "rapatrier les branches distantes"
#: builtin/remote.c:165
msgid "import all tags and associated objects when fetching"
msgstr ""
+"importer toutes les étiquettes et les objets associés lors du rapatriement"
#: builtin/remote.c:168
msgid "or do not fetch any tag at all (--no-tags)"
-msgstr ""
+msgstr "ou ne rapatrier aucune étiquette (--no-tags)"
#: builtin/remote.c:170
msgid "branch(es) to track"
-msgstr ""
+msgstr "branche(s) à suivre"
#: builtin/remote.c:171
msgid "master branch"
-msgstr ""
+msgstr "branche maîtresse"
#: builtin/remote.c:172
msgid "push|fetch"
-msgstr ""
+msgstr "push|fetch"
#: builtin/remote.c:173
msgid "set up remote as a mirror to push to or fetch from"
msgstr ""
+"paramétrer la distante comme miroir pour pousser ou pour rapatrier depuis"
#: builtin/remote.c:185
msgid "specifying a master branch makes no sense with --mirror"
-msgstr ""
+msgstr "spécifier une branche maîtresse n'a pas de sens avec --mirror"
#: builtin/remote.c:187
msgid "specifying branches to track makes sense only with fetch mirrors"
msgstr ""
+"spécifier les branches à suivre n'a de sens qu'avec des miroirs de "
+"rapatriement"
#: builtin/remote.c:195 builtin/remote.c:646
#, c-format
msgid "remote %s already exists."
-msgstr ""
+msgstr "la distante %s existe déjà."
#: builtin/remote.c:199 builtin/remote.c:650
#, c-format
msgid "'%s' is not a valid remote name"
-msgstr ""
+msgstr "'%s' n'est pas un nom valide de distante"
#: builtin/remote.c:243
#, c-format
msgid "Could not setup master '%s'"
-msgstr ""
+msgstr "Impossible de paramétrer la maîtresse '%s'"
#: builtin/remote.c:299
#, c-format
msgid "more than one %s"
-msgstr ""
+msgstr "plus d'un %s"
#: builtin/remote.c:339
#, c-format
msgid "Could not get fetch map for refspec %s"
-msgstr ""
+msgstr "Impossible d'obtenir une correspondance distante pour la spécification de référence %s"
#: builtin/remote.c:440 builtin/remote.c:448
msgid "(matching)"
-msgstr ""
+msgstr "(correspond)"
#: builtin/remote.c:452
msgid "(delete)"
-msgstr ""
+msgstr "(supprimer)"
#: builtin/remote.c:595 builtin/remote.c:601 builtin/remote.c:607
#, c-format
msgid "Could not append '%s' to '%s'"
-msgstr ""
+msgstr "Impossible d'ajouter '%s' à '%s'"
#: builtin/remote.c:639 builtin/remote.c:792 builtin/remote.c:890
#, c-format
msgid "No such remote: %s"
-msgstr ""
+msgstr "Distante inconnue : %s"
#: builtin/remote.c:656
#, c-format
msgid "Could not rename config section '%s' to '%s'"
-msgstr ""
+msgstr "Impossible de renommer la section de configuration '%s' en '%s'"
#: builtin/remote.c:662 builtin/remote.c:799
#, c-format
msgid "Could not remove config section '%s'"
-msgstr ""
+msgstr "Impossible de supprimer la section de configuration '%s'"
#: builtin/remote.c:677
#, c-format
"\t%s\n"
"\tPlease update the configuration manually if necessary."
msgstr ""
+"Pas de mise à jour du refspec de rapatriement qui n'est pas par défaut\n"
+"\t%s\n"
+"\tVeuillez mettre à jour la configuration manuellement si nécessaire."
#: builtin/remote.c:683
#, c-format
msgid "Could not append '%s'"
-msgstr ""
+msgstr "Impossible d'ajouter '%s'"
#: builtin/remote.c:694
#, c-format
msgid "Could not set '%s'"
-msgstr ""
+msgstr "Impossible de définir '%s'"
#: builtin/remote.c:716
#, c-format
msgid "deleting '%s' failed"
-msgstr ""
+msgstr "échec de suppression de '%s'"
#: builtin/remote.c:750
#, c-format
msgid "creating '%s' failed"
-msgstr ""
+msgstr "échec de création de '%s'"
#: builtin/remote.c:764
#, c-format
msgid "Could not remove branch %s"
-msgstr ""
+msgstr "Impossible de supprimer la branche %s"
#: builtin/remote.c:834
msgid ""
"Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
"to delete them, use:"
msgstr[0] ""
+"Note : Une branche en dehors de refs/remotes/ n'a pas été supprimée ;\n"
+"pour la supprimer, utilisez :"
msgstr[1] ""
+"Note : Plusieurs branches en dehors de refs/remotes/ n'ont pas été "
+"supprimées ;\n"
+"pour les supprimer, utilisez :"
#: builtin/remote.c:943
#, c-format
msgid " new (next fetch will store in remotes/%s)"
-msgstr ""
+msgstr " nouveau (le prochain rapatriement (fetch) stockera dans remotes/%s)"
#: builtin/remote.c:946
msgid " tracked"
-msgstr ""
+msgstr " suivi"
#: builtin/remote.c:948
msgid " stale (use 'git remote prune' to remove)"
-msgstr ""
+msgstr " dépassé (utilisez 'git remote prune' pour supprimer)"
#: builtin/remote.c:950
msgid " ???"
-msgstr ""
+msgstr " ???"
#: builtin/remote.c:991
#, c-format
msgid "invalid branch.%s.merge; cannot rebase onto > 1 branch"
-msgstr ""
+msgstr "branch.%s.merge invalide ; ne peut pas rebaser sur plus d'une branche"
#: builtin/remote.c:998
#, c-format
msgid "rebases onto remote %s"
-msgstr ""
+msgstr "rebase sur la distante %s"
#: builtin/remote.c:1001
#, c-format
msgid " merges with remote %s"
-msgstr ""
+msgstr " fusionne avec la distante %s"
#: builtin/remote.c:1002
msgid " and with remote"
-msgstr ""
+msgstr " et avec la distante"
#: builtin/remote.c:1004
#, c-format
msgid "merges with remote %s"
-msgstr ""
+msgstr "fusionne avec la distante %s"
#: builtin/remote.c:1005
msgid " and with remote"
-msgstr ""
+msgstr " et avec la distante"
#: builtin/remote.c:1051
msgid "create"
-msgstr ""
+msgstr "créer"
#: builtin/remote.c:1054
msgid "delete"
-msgstr ""
+msgstr "supprimer"
#: builtin/remote.c:1058
msgid "up to date"
-msgstr ""
+msgstr "à jour"
#: builtin/remote.c:1061
msgid "fast-forwardable"
-msgstr ""
+msgstr "peut être mis à jour en avance rapide"
#: builtin/remote.c:1064
msgid "local out of date"
-msgstr ""
+msgstr "le local n'est pas à jour"
#: builtin/remote.c:1071
#, c-format
msgid " %-*s forces to %-*s (%s)"
-msgstr ""
+msgstr " %-*s force vers %-*s (%s)"
#: builtin/remote.c:1074
#, c-format
msgid " %-*s pushes to %-*s (%s)"
-msgstr ""
+msgstr " %-*s pousse vers %-*s (%s)"
#: builtin/remote.c:1078
#, c-format
msgid " %-*s forces to %s"
-msgstr ""
+msgstr " %-*s force vers %s"
#: builtin/remote.c:1081
#, c-format
msgid " %-*s pushes to %s"
-msgstr ""
+msgstr " %-*s pousse vers %s"
#: builtin/remote.c:1091
msgid "do not query remotes"
-msgstr ""
+msgstr "ne pas interroger les distantes"
#: builtin/remote.c:1118
#, c-format
msgid "* remote %s"
-msgstr ""
+msgstr "* distante %s"
#: builtin/remote.c:1119
#, c-format
msgid " Fetch URL: %s"
-msgstr ""
+msgstr " URL de rapatriement : %s"
#: builtin/remote.c:1120 builtin/remote.c:1285
msgid "(no URL)"
-msgstr ""
+msgstr "(pas d'URL)"
#: builtin/remote.c:1129 builtin/remote.c:1131
#, c-format
msgid " Push URL: %s"
-msgstr ""
+msgstr " URL push : %s"
#: builtin/remote.c:1133 builtin/remote.c:1135 builtin/remote.c:1137
#, c-format
msgid " HEAD branch: %s"
-msgstr ""
+msgstr " Branche HEAD : %s"
#: builtin/remote.c:1139
#, c-format
msgid ""
" HEAD branch (remote HEAD is ambiguous, may be one of the following):\n"
msgstr ""
+" Branche HEAD (la HEAD distante est ambiguë, peut être l'une des "
+"suivantes) :\n"
#: builtin/remote.c:1151
#, c-format
msgid " Remote branch:%s"
msgid_plural " Remote branches:%s"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] " Branche distante :%s"
+msgstr[1] " Branches distantes :%s"
#: builtin/remote.c:1154 builtin/remote.c:1181
msgid " (status not queried)"
-msgstr ""
+msgstr " (statut non demandé)"
#: builtin/remote.c:1163
msgid " Local branch configured for 'git pull':"
msgid_plural " Local branches configured for 'git pull':"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] " Branche locale configurée pour 'git pull' :"
+msgstr[1] " Branches locales configurées pour 'git pull' :"
#: builtin/remote.c:1171
msgid " Local refs will be mirrored by 'git push'"
-msgstr ""
+msgstr " Les références locales seront reflétées par '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] ""
-msgstr[1] ""
+msgstr[0] " Référence locale configurée pour 'git push'%s :"
+msgstr[1] " Références locales configurées pour 'git push'%s :"
#: builtin/remote.c:1199
msgid "set refs/remotes/<name>/HEAD according to remote"
-msgstr ""
+msgstr "définir refs/remotes/<nom>/HEAD selon la distante"
#: builtin/remote.c:1201
msgid "delete refs/remotes/<name>/HEAD"
-msgstr ""
+msgstr "supprimer refs/remotes/<nom>/HEAD"
#: builtin/remote.c:1216
msgid "Cannot determine remote HEAD"
-msgstr ""
+msgstr "Impossible de déterminer la HEAD distante"
#: builtin/remote.c:1218
msgid "Multiple remote HEAD branches. Please choose one explicitly with:"
msgstr ""
+"Il y a de multiples branches HEAD distantes. Veuillez en choisir une "
+"explicitement avec :"
#: builtin/remote.c:1228
#, c-format
msgid "Could not delete %s"
-msgstr ""
+msgstr "Impossible de supprimer %s"
#: builtin/remote.c:1236
#, c-format
msgid "Not a valid ref: %s"
-msgstr ""
+msgstr "Référence non valide : %s"
#: builtin/remote.c:1238
#, c-format
msgid "Could not setup %s"
-msgstr ""
+msgstr "Impossible de paramétrer %s"
#: builtin/remote.c:1274
#, c-format
msgid " %s will become dangling!"
-msgstr ""
+msgstr " %s deviendra en suspens !"
#: builtin/remote.c:1275
#, c-format
msgid " %s has become dangling!"
-msgstr ""
+msgstr " %s est devenu en suspens !"
#: builtin/remote.c:1281
#, c-format
msgid "Pruning %s"
-msgstr ""
+msgstr "Élimination de %s"
#: builtin/remote.c:1282
#, c-format
msgid "URL: %s"
-msgstr ""
+msgstr "URL : %s"
#: builtin/remote.c:1295
#, c-format
msgid " * [would prune] %s"
-msgstr ""
+msgstr " * [serait éliminé] %s"
#: builtin/remote.c:1298
#, c-format
msgid " * [pruned] %s"
-msgstr ""
+msgstr " * [éliminé] %s"
#: builtin/remote.c:1321
msgid "prune remotes after fetching"
-msgstr ""
+msgstr "éliminer les distants après le rapatriement"
#: builtin/remote.c:1387 builtin/remote.c:1461
#, c-format
msgid "No such remote '%s'"
-msgstr ""
+msgstr "Pas de serveur remote '%s'"
#: builtin/remote.c:1407
msgid "add branch"
-msgstr ""
+msgstr "ajouter une branche"
#: builtin/remote.c:1414
msgid "no remote specified"
-msgstr ""
+msgstr "pas de serveur distant spécifié"
#: builtin/remote.c:1436
msgid "manipulate push URLs"
-msgstr ""
+msgstr "manipuler les URLs push"
#: builtin/remote.c:1438
msgid "add URL"
-msgstr ""
+msgstr "ajouter une URL"
#: builtin/remote.c:1440
msgid "delete URLs"
-msgstr ""
+msgstr "supprimer des URLs"
#: builtin/remote.c:1447
msgid "--add --delete doesn't make sense"
-msgstr ""
+msgstr "--add --delete n'a aucun sens"
#: builtin/remote.c:1487
#, c-format
msgid "Invalid old URL pattern: %s"
-msgstr ""
+msgstr "Motif d'URL ancien invalide : %s"
#: builtin/remote.c:1495
#, c-format
msgid "No such URL found: %s"
-msgstr ""
+msgstr "Pas d'URL trouvée : %s"
#: builtin/remote.c:1497
msgid "Will not delete all non-push URLs"
-msgstr ""
+msgstr "Pas de suppression de toutes les URLs non-push"
#: builtin/remote.c:1569
msgid "be verbose; must be placed before a subcommand"
-msgstr ""
+msgstr "être verbeux : doit être placé avant une sous-commande"
#: builtin/replace.c:17
msgid "git replace [-f] <object> <replacement>"
-msgstr ""
+msgstr "git replace [-f] <objet> <remplacement>"
#: builtin/replace.c:18
msgid "git replace -d <object>..."
-msgstr ""
+msgstr "git replace -d <objet>..."
#: builtin/replace.c:19
msgid "git replace -l [<pattern>]"
-msgstr ""
+msgstr "git replace -l [<motif>]"
#: builtin/replace.c:121
msgid "list replace refs"
-msgstr ""
+msgstr "afficher les références de remplacement"
#: builtin/replace.c:122
msgid "delete replace refs"
-msgstr ""
+msgstr "supprimer les références de remplacement"
#: builtin/replace.c:123
msgid "replace the ref if it exists"
-msgstr ""
+msgstr "remplacer la référence si elle existe"
#: builtin/rerere.c:11
msgid "git rerere [clear | forget path... | status | remaining | diff | gc]"
-msgstr ""
+msgstr "git rerere [clear | forget chemin... | status | remaining | diff | gc]"
#: builtin/rerere.c:56
msgid "register clean resolutions in index"
-msgstr ""
+msgstr "enregistrer des résolutions propres dans l'index"
#: 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] <tree-ish> [--] <paths>..."
-msgstr ""
+msgstr "git reset [-q] <arbre ou apparenté> [--] <chemins>..."
#: builtin/reset.c:27
msgid "git reset --patch [<tree-ish>] [--] [<paths>...]"
-msgstr ""
+msgstr "git reset --patch [<arbre ou apparenté>] [--] [<chemins>...]"
#: builtin/reset.c:33
msgid "mixed"
-msgstr ""
+msgstr "mixed"
#: builtin/reset.c:33
msgid "soft"
-msgstr ""
+msgstr "soft"
#: builtin/reset.c:33
msgid "hard"
-msgstr ""
+msgstr "hard"
#: builtin/reset.c:33
msgid "merge"
-msgstr ""
+msgstr "merge"
#: builtin/reset.c:33
msgid "keep"
-msgstr ""
+msgstr "keep"
#: builtin/reset.c:73
msgid "You do not have a valid HEAD."
-msgstr ""
+msgstr "Vous n'avez pas une HEAD valide."
#: builtin/reset.c:75
msgid "Failed to find tree of HEAD."
-msgstr ""
+msgstr "Impossible de trouver l'arbre pour HEAD."
#: builtin/reset.c:81
#, c-format
msgid "Failed to find tree of %s."
-msgstr ""
+msgstr "Impossible de trouver l'arbre pour %s."
-#: builtin/reset.c:98
+#: builtin/reset.c:99
#, c-format
msgid "HEAD is now at %s"
-msgstr ""
+msgstr "HEAD est maintenant à %s"
-#: builtin/reset.c:169
+#: builtin/reset.c:172
#, c-format
msgid "Cannot do a %s reset in the middle of a merge."
-msgstr ""
+msgstr "Impossible de faire un \"reset %s\" au milieu d'une fusion."
-#: builtin/reset.c:248
+#: builtin/reset.c:251
msgid "be quiet, only report errors"
-msgstr ""
+msgstr "être silencieux, afficher seulement les erreurs"
-#: builtin/reset.c:250
+#: builtin/reset.c:253
msgid "reset HEAD and index"
-msgstr ""
+msgstr "réinitialiser HEAD et l'index"
-#: builtin/reset.c:251
+#: builtin/reset.c:254
msgid "reset only HEAD"
-msgstr ""
+msgstr "réinitialiser seulement HEAD"
-#: builtin/reset.c:253 builtin/reset.c:255
+#: builtin/reset.c:256 builtin/reset.c:258
msgid "reset HEAD, index and working tree"
-msgstr ""
+msgstr "réinitialiser HEAD, l'index et la copie de travail"
-#: builtin/reset.c:257
+#: builtin/reset.c:260
msgid "reset HEAD but keep local changes"
-msgstr ""
+msgstr "réinitialiser HEAD mais garder les changements locaux"
-#: builtin/reset.c:275
+#: builtin/reset.c:278
#, c-format
msgid "Failed to resolve '%s' as a valid revision."
-msgstr ""
+msgstr "Échec de résolution de '%s' comme une révision valide."
-#: builtin/reset.c:278 builtin/reset.c:286
+#: builtin/reset.c:281 builtin/reset.c:289
#, c-format
msgid "Could not parse object '%s'."
-msgstr ""
+msgstr "Impossible d'analyser l'objet '%s'."
-#: builtin/reset.c:283
+#: builtin/reset.c:286
#, c-format
msgid "Failed to resolve '%s' as a valid tree."
-msgstr ""
+msgstr "Échec de résolution de '%s' comme un arbre valide."
-#: builtin/reset.c:292
+#: builtin/reset.c:295
msgid "--patch is incompatible with --{hard,mixed,soft}"
-msgstr ""
+msgstr "--patch est incompatible avec --{hard,mixed,soft}"
-#: builtin/reset.c:301
+#: builtin/reset.c:304
msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
msgstr ""
+"--mixed avec des chemins est obsolète ; utilisez 'git reset -- <paths>' à la "
+"place."
-#: builtin/reset.c:303
+#: builtin/reset.c:306
#, c-format
msgid "Cannot do %s reset with paths."
-msgstr ""
+msgstr "Impossible de faire un \"%s reset\" avec des chemins."
-#: builtin/reset.c:313
+#: builtin/reset.c:316
#, c-format
msgid "%s reset is not allowed in a bare repository"
-msgstr "RAZ de %s n'est pas permis dans un dépôt nu"
+msgstr "Le \"%s reset\" n'est pas permis dans un dépôt nu"
-#: builtin/reset.c:333
+#: builtin/reset.c:336
#, c-format
msgid "Could not reset index file to revision '%s'."
-msgstr ""
+msgstr "Impossible de réinitialiser le fichier d'index à la révision '%s'."
-#: builtin/reset.c:339
+#: builtin/reset.c:342
msgid "Unstaged changes after reset:"
-msgstr ""
+msgstr "Modifications non indexées après reset :"
-#: builtin/reset.c:344
+#: builtin/reset.c:347
msgid "Could not write new index file."
-msgstr ""
+msgstr "Impossible d'écrire le nouveau fichier d'index."
-#: builtin/rev-parse.c:339
+#: builtin/rev-parse.c:345
msgid "git rev-parse --parseopt [options] -- [<args>...]"
-msgstr ""
+msgstr "git rev-parse --parseopt [options] -- [<arguments>...]"
-#: builtin/rev-parse.c:344
+#: builtin/rev-parse.c:350
msgid "keep the `--` passed as an arg"
-msgstr ""
+msgstr "garder le `--` passé en argument"
-#: builtin/rev-parse.c:346
+#: builtin/rev-parse.c:352
msgid "stop parsing after the first non-option argument"
-msgstr ""
+msgstr "arrêt de l'analyse après le premier argument qui n'est pas une option"
-#: builtin/rev-parse.c:464
+#: builtin/rev-parse.c:470
msgid ""
"git rev-parse --parseopt [options] -- [<args>...]\n"
" or: git rev-parse --sq-quote [<arg>...]\n"
"\n"
"Run \"git rev-parse --parseopt -h\" for more information on the first usage."
msgstr ""
+"git rev-parse --parseopt [options] -- [<arguments>...]\n"
+" ou : git rev-parse --sq-quote [<argument>...]\n"
+" ou : git rev-parse [options] [<argument>...]\n"
+"\n"
+"Lancez \"git rev-parse --parseopt -h\" pour plus d'information sur "
+"l'utilisation principale."
#: builtin/revert.c:22
msgid "git revert [options] <commit-ish>..."
-msgstr ""
+msgstr "git revert [options] <commit ou apparenté>..."
#: builtin/revert.c:23
msgid "git revert <subcommand>"
-msgstr ""
+msgstr "git revert <sous-commande>"
#: builtin/revert.c:28
msgid "git cherry-pick [options] <commit-ish>..."
-msgstr ""
+msgstr "git cherry-pick [options] <commit ou apparenté>..."
#: builtin/revert.c:29
msgid "git cherry-pick <subcommand>"
-msgstr ""
+msgstr "git cherry-pick <sous-commande>"
-#: builtin/revert.c:70 builtin/revert.c:92
+#: builtin/revert.c:71 builtin/revert.c:94
#, c-format
msgid "%s: %s cannot be used with %s"
msgstr "%s : %s ne peut pas être utilisé avec %s"
-#: builtin/revert.c:103
+#: builtin/revert.c:105
msgid "end revert or cherry-pick sequence"
-msgstr ""
+msgstr "mettre fin au retour ou picorage"
-#: builtin/revert.c:104
+#: builtin/revert.c:106
msgid "resume revert or cherry-pick sequence"
-msgstr ""
+msgstr "reprendre le retour ou picorage"
-#: builtin/revert.c:105
+#: builtin/revert.c:107
msgid "cancel revert or cherry-pick sequence"
-msgstr ""
+msgstr "annuler le retour ou picorage"
-#: builtin/revert.c:106
+#: builtin/revert.c:108
msgid "don't automatically commit"
-msgstr ""
+msgstr "ne pas valider automatiquement"
-#: builtin/revert.c:107
+#: builtin/revert.c:109
msgid "edit the commit message"
-msgstr ""
+msgstr "éditer le message de validation"
-#: builtin/revert.c:110
+#: builtin/revert.c:112
msgid "parent number"
-msgstr ""
+msgstr "numéro de parent"
-#: builtin/revert.c:112
+#: builtin/revert.c:114
msgid "merge strategy"
-msgstr ""
+msgstr "stratégie de fusion"
-#: builtin/revert.c:113
+#: builtin/revert.c:115
msgid "option"
-msgstr ""
+msgstr "option"
-#: builtin/revert.c:114
+#: builtin/revert.c:116
msgid "option for merge strategy"
-msgstr ""
+msgstr "option pour la stratégie de fusion"
-#: builtin/revert.c:125
+#: builtin/revert.c:127
msgid "append commit name"
-msgstr ""
+msgstr "ajouter le nom de validation"
-#: builtin/revert.c:126
+#: builtin/revert.c:128
msgid "allow fast-forward"
-msgstr ""
+msgstr "autoriser l'avance rapide"
-#: builtin/revert.c:127
+#: builtin/revert.c:129
msgid "preserve initially empty commits"
-msgstr ""
+msgstr "préserver les validations vides initialement"
-#: builtin/revert.c:128
+#: builtin/revert.c:130
msgid "allow commits with empty messages"
-msgstr ""
+msgstr "autoriser les validations avec des messages vides"
-#: builtin/revert.c:129
+#: builtin/revert.c:131
msgid "keep redundant, empty commits"
-msgstr ""
+msgstr "garder les validations redondantes, vides"
-#: builtin/revert.c:133
+#: builtin/revert.c:135
msgid "program error"
-msgstr ""
+msgstr "erreur du programme"
-#: builtin/revert.c:223
+#: builtin/revert.c:225
msgid "revert failed"
-msgstr ""
+msgstr "revert a échoué"
-#: builtin/revert.c:238
+#: builtin/revert.c:240
msgid "cherry-pick failed"
-msgstr ""
+msgstr "le picorage a échoué"
-#: builtin/rm.c:15
+#: builtin/rm.c:16
msgid "git rm [options] [--] <file>..."
-msgstr ""
+msgstr "git rm [options] [--] <fichier>..."
-#: builtin/rm.c:64 builtin/rm.c:186
-#, c-format
+#: builtin/rm.c:64
+msgid ""
+"the following submodule (or one of its nested submodules)\n"
+"uses a .git directory:"
+msgid_plural ""
+"the following submodules (or one of its nested submodules)\n"
+"use a .git directory:"
+msgstr[0] ""
+"le sous-module suivant (ou un de ses sous-modules imbriqués)\n"
+"utilise un répertoire .git :"
+msgstr[1] ""
+"les sous-modules suivants (ou un de ses sous-modules imbriqués)\n"
+"utilisent un répertoire .git :"
+
+#: builtin/rm.c:70
msgid ""
-"submodule '%s' (or one of its nested submodules) uses a .git directory\n"
+"\n"
"(use 'rm -rf' if you really want to remove it including all of its history)"
msgstr ""
+"\n"
+"(utilisez 'rm -rf' si vous voulez vraiment le supprimer en incluant tout son "
+"historique)"
-#: builtin/rm.c:174
-#, c-format
+#: builtin/rm.c:230
msgid ""
-"'%s' has staged content different from both the file and the HEAD\n"
-"(use -f to force removal)"
-msgstr ""
+"the following file has staged content different from both the\n"
+"file and the HEAD:"
+msgid_plural ""
+"the following files have staged content different from both the\n"
+"file and the HEAD:"
+msgstr[0] ""
+"le fichier suivant a du contenu indexé différent\n"
+"du fichier et de HEAD :"
+msgstr[1] ""
+"les fichiers suivants ont du contenu indexé différent\n"
+"du fichier et de HEAD :"
-#: builtin/rm.c:180
-#, c-format
+#: builtin/rm.c:235
msgid ""
-"'%s' has changes staged in the index\n"
-"(use --cached to keep the file, or -f to force removal)"
+"\n"
+"(use -f to force removal)"
msgstr ""
+"\n"
+"(utilisez -f pour forcer la suppression)"
-#: builtin/rm.c:191
-#, c-format
+#: builtin/rm.c:239
+msgid "the following file has changes staged in the index:"
+msgid_plural "the following files have changes staged in the index:"
+msgstr[0] "le fichier suivant a des changements indexés :"
+msgstr[1] "les fichiers suivants ont des changements indexés :"
+
+#: builtin/rm.c:243 builtin/rm.c:254
msgid ""
-"'%s' has local modifications\n"
+"\n"
"(use --cached to keep the file, or -f to force removal)"
msgstr ""
+"\n"
+"(utilisez --cached pour garder le fichier, ou -f pour forcer la suppression)"
-#: builtin/rm.c:207
+#: builtin/rm.c:251
+msgid "the following file has local modifications:"
+msgid_plural "the following files have local modifications:"
+msgstr[0] "le fichier suivant a des modifications locales :"
+msgstr[1] "les fichiers suivants ont des modifications locales :"
+
+#: builtin/rm.c:269
msgid "do not list removed files"
-msgstr ""
+msgstr "ne pas afficher les fichiers supprimés"
-#: builtin/rm.c:208
+#: builtin/rm.c:270
msgid "only remove from the index"
-msgstr ""
+msgstr "supprimer seulement de l'index"
-#: builtin/rm.c:209
+#: builtin/rm.c:271
msgid "override the up-to-date check"
-msgstr ""
+msgstr "outrepasser la vérification des fichiers à jour"
-#: builtin/rm.c:210
+#: builtin/rm.c:272
msgid "allow recursive removal"
-msgstr ""
+msgstr "autoriser la suppression récursive"
-#: builtin/rm.c:212
+#: builtin/rm.c:274
msgid "exit with a zero status even if nothing matched"
-msgstr ""
+msgstr "sortir avec un statut zéro même si rien ne correspondait"
-#: builtin/rm.c:283
+#: builtin/rm.c:345
#, c-format
msgid "not removing '%s' recursively without -r"
-msgstr ""
+msgstr "pas de suppression récursive de '%s' sans -r"
-#: builtin/rm.c:322
+#: builtin/rm.c:384
#, c-format
msgid "git rm: unable to remove %s"
-msgstr ""
+msgstr "git rm : impossible de supprimer %s"
#: builtin/shortlog.c:13
msgid "git shortlog [<options>] [<revision range>] [[--] [<path>...]]"
-msgstr ""
+msgstr "git shortlog [<options>] [<intervalle révisions>] [[--] [<chemin>...]]"
#: builtin/shortlog.c:131
#, c-format
msgid "Missing author: %s"
-msgstr ""
+msgstr "Auteur manquant : %s"
-#: builtin/shortlog.c:227
+#: builtin/shortlog.c:228
msgid "sort output according to the number of commits per author"
-msgstr ""
+msgstr "trier la sortie sur le nombre de validations par auteur"
-#: builtin/shortlog.c:229
+#: builtin/shortlog.c:230
msgid "Suppress commit descriptions, only provides commit count"
msgstr ""
+"Supprimer les descriptions de validation, fournit seulement le nombre de "
+"validations"
-#: builtin/shortlog.c:231
+#: builtin/shortlog.c:232
msgid "Show the email address of each author"
-msgstr ""
+msgstr "Afficher l'adresse e-mail de chaque auteur"
-#: builtin/shortlog.c:232
+#: builtin/shortlog.c:233
msgid "w[,i1[,i2]]"
-msgstr ""
+msgstr "w[,i1[,i2]]"
-#: builtin/shortlog.c:233
+#: builtin/shortlog.c:234
msgid "Linewrap output"
-msgstr ""
+msgstr "Couper les lignes"
#: builtin/show-branch.c:9
msgid ""
"independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | "
"<glob>)...]"
msgstr ""
+"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--"
+"current] [--color[=<quand>] | --no-color] [--sparse] [--more=<n> | --list | "
+"--independent | --merge-base] [--no-name | --sha1-name] [--topics] "
+"[(<révision> | <glob>)...]"
#: builtin/show-branch.c:10
msgid "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"
-msgstr ""
+msgstr "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<référence>]"
#: builtin/show-branch.c:650
msgid "show remote-tracking and local branches"
-msgstr ""
+msgstr "afficher les branches de suivi distantes et les branches locales"
#: builtin/show-branch.c:652
msgid "show remote-tracking branches"
-msgstr ""
+msgstr "afficher les branches de suivi distantes"
#: builtin/show-branch.c:654
msgid "color '*!+-' corresponding to the branch"
-msgstr ""
+msgstr "couleur '*!+-' correspondant à la branche"
#: builtin/show-branch.c:656
msgid "show <n> more commits after the common ancestor"
-msgstr ""
+msgstr "afficher <n> validations de plus après l'ancêtre commun"
#: builtin/show-branch.c:658
msgid "synonym to more=-1"
-msgstr ""
+msgstr "synonyme de more=-1"
#: builtin/show-branch.c:659
msgid "suppress naming strings"
-msgstr ""
+msgstr "supprimer les chaînes de nommage"
#: builtin/show-branch.c:661
msgid "include the current branch"
-msgstr ""
+msgstr "inclure la branche courante"
#: builtin/show-branch.c:663
msgid "name commits with their object names"
-msgstr ""
+msgstr "nommer les validations avec leurs noms d'objet"
#: builtin/show-branch.c:665
msgid "show possible merge bases"
-msgstr ""
+msgstr "afficher les bases possibles de fusion"
#: builtin/show-branch.c:667
msgid "show refs unreachable from any other ref"
-msgstr ""
+msgstr "afficher les références inaccessibles depuis toute autre référence"
#: builtin/show-branch.c:669
msgid "show commits in topological order"
-msgstr ""
+msgstr "afficher les validations dans l'ordre topologique"
-#: builtin/show-branch.c:671
+#: builtin/show-branch.c:672
msgid "show only commits not on the first branch"
msgstr ""
+"afficher seulement les validations qui ne sont pas sur la première branche"
-#: builtin/show-branch.c:673
+#: builtin/show-branch.c:674
msgid "show merges reachable from only one tip"
-msgstr ""
+msgstr "afficher les fusions accessibles depuis une seule pointe"
-#: builtin/show-branch.c:675
-msgid "show commits where no parent comes before its children"
-msgstr ""
+#: builtin/show-branch.c:676
+msgid "topologically sort, maintaining date order where possible"
+msgstr "tri topologique, maintenant l'ordre par date si possible"
-#: builtin/show-branch.c:677
+#: builtin/show-branch.c:679
msgid "<n>[,<base>]"
-msgstr ""
+msgstr "<n>[,<base>]"
-#: builtin/show-branch.c:678
+#: builtin/show-branch.c:680
msgid "show <n> most recent ref-log entries starting at base"
msgstr ""
+"afficher les <n> plus récents éléments de ref-log en commençant à la 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] [--] [motif*] "
#: builtin/show-ref.c:11
msgid "git show-ref --exclude-existing[=pattern] < ref-list"
-msgstr ""
+msgstr "git show-ref --exclude-existing[=motif] < liste-références"
-#: builtin/show-ref.c:165
+#: builtin/show-ref.c:168
msgid "only show tags (can be combined with heads)"
-msgstr ""
+msgstr "afficher seulement les étiquettes (peut être combiné avec des têtes)"
-#: builtin/show-ref.c:166
+#: builtin/show-ref.c:169
msgid "only show heads (can be combined with tags)"
-msgstr ""
+msgstr "afficher seulement les têtes (peut être combiné avec des étiquettes)"
-#: builtin/show-ref.c:167
+#: builtin/show-ref.c:170
msgid "stricter reference checking, requires exact ref path"
msgstr ""
+"vérification de référence plus stricte, nécessite un chemin de référence "
+"exact"
-#: builtin/show-ref.c:170 builtin/show-ref.c:172
-msgid "show the HEAD reference"
-msgstr ""
+#: builtin/show-ref.c:173 builtin/show-ref.c:176
+msgid "show the HEAD reference, even if it would be filtered out"
+msgstr "afficher la référence HEAD, même si elle serait filtrée"
-#: builtin/show-ref.c:174
+#: builtin/show-ref.c:178
msgid "dereference tags into object IDs"
-msgstr ""
+msgstr "déréférencer les étiquettes en IDs d'objet"
-#: builtin/show-ref.c:176
+#: builtin/show-ref.c:180
msgid "only show SHA1 hash using <n> digits"
-msgstr ""
+msgstr "afficher seulement le hachage SHA1 en utilisant <n> chiffres"
-#: builtin/show-ref.c:180
+#: builtin/show-ref.c:184
msgid "do not print results to stdout (useful with --verify)"
msgstr ""
+"ne pas afficher les résultats sur la sortie standard (pratique avec --verify)"
-#: builtin/show-ref.c:182
+#: builtin/show-ref.c:186
msgid "show refs from stdin that aren't in local repository"
msgstr ""
+"afficher les références de l'entrée standard qui ne sont pas dans le dépôt "
+"local"
#: builtin/symbolic-ref.c:7
msgid "git symbolic-ref [options] name [ref]"
-msgstr ""
+msgstr "git symbolic-ref [options] nom [référence]"
#: builtin/symbolic-ref.c:8
msgid "git symbolic-ref -d [-q] name"
-msgstr ""
+msgstr "git symbolic-ref -d [-q] nom"
#: builtin/symbolic-ref.c:40
msgid "suppress error message for non-symbolic (detached) refs"
msgstr ""
+"supprimer le message d'erreur pour une référence non symbolique (détachée)"
#: builtin/symbolic-ref.c:41
msgid "delete symbolic ref"
-msgstr ""
+msgstr "supprimer la référence symbolique"
#: builtin/symbolic-ref.c:42
msgid "shorten ref output"
-msgstr ""
+msgstr "raccourcir l'affichage de la référence"
#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18
msgid "reason"
-msgstr ""
+msgstr "raison"
#: builtin/symbolic-ref.c:43 builtin/update-ref.c:18
msgid "reason of the update"
-msgstr ""
+msgstr "raison de la mise à jour"
#: 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 <id-clé>] [-f] [-m <message>|-F <file>] <nométiquette> "
+"[<head>]"
#: builtin/tag.c:23
msgid "git tag -d <tagname>..."
-msgstr ""
+msgstr "git tag -d <nométiquette>..."
#: 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 <objet>] \n"
+"\t\t[<motif>...]"
#: builtin/tag.c:26
msgid "git tag -v <tagname>..."
-msgstr ""
+msgstr "git tag -v <nométiquette>..."
#: builtin/tag.c:60
#, c-format
msgid "malformed object at '%s'"
-msgstr ""
+msgstr "objet malformé à '%s'"
#: builtin/tag.c:207
#, c-format
msgid "tag name too long: %.*s..."
-msgstr ""
+msgstr "nom d'étiquette trop long : %.*s..."
#: builtin/tag.c:212
#, c-format
msgid "tag '%s' not found."
-msgstr ""
+msgstr "étiquette '%s' non trouvée."
#: builtin/tag.c:227
#, c-format
msgid "Deleted tag '%s' (was %s)\n"
-msgstr ""
+msgstr "Étiquette '%s' supprimée (elle était %s)\n"
#: builtin/tag.c:239
#, c-format
msgid "could not verify the tag '%s'"
-msgstr ""
+msgstr "impossible de vérifier l'étiquette '%s'"
#: builtin/tag.c:249
#, c-format
"Write a tag message\n"
"Lines starting with '%c' will be ignored.\n"
msgstr ""
+"\n"
+"Écrire un message pour l'étiquette\n"
+"Les lignes commençant par '%c' seront ignorées.\n"
#: builtin/tag.c:253
#, c-format
"Lines starting with '%c' will be kept; you may remove them yourself if you "
"want to.\n"
msgstr ""
+"\n"
+"Écrire un message pour l'étiquette\n"
+"Les lignes commençant par '%c' seront gardées ; vous pouvez les retirer vous-"
+"même si vous le souhaitez.\n"
#: builtin/tag.c:292
msgid "unable to sign the tag"
-msgstr ""
+msgstr "impossible de signer l'étiquette"
#: builtin/tag.c:294
msgid "unable to write tag file"
-msgstr ""
+msgstr "impossible d'écrire le fichier d'étiquettes"
#: builtin/tag.c:319
msgid "bad object type."
-msgstr ""
+msgstr "mauvais type d'objet."
#: builtin/tag.c:332
msgid "tag header too big."
-msgstr ""
+msgstr "en-tête d'étiquette trop gros."
#: builtin/tag.c:368
msgid "no tag message?"
-msgstr ""
+msgstr "pas de message pour l'étiquette ?"
#: builtin/tag.c:374
#, c-format
msgid "The tag message has been left in %s\n"
-msgstr ""
+msgstr "Le message pour l'étiquette a été laissé dans %s\n"
#: builtin/tag.c:423
msgid "switch 'points-at' requires an object"
-msgstr ""
+msgstr "le commutateur 'points-at' a besoin d'un objet"
#: builtin/tag.c:425
#, c-format
msgid "malformed object name '%s'"
-msgstr ""
+msgstr "nom d'objet malformé '%s'"
#: builtin/tag.c:445
msgid "list tag names"
-msgstr ""
+msgstr "afficher les noms des étiquettes"
#: builtin/tag.c:447
msgid "print <n> lines of each tag message"
-msgstr ""
+msgstr "affiche <n> lignes de chaque message d'étiquette"
#: builtin/tag.c:449
msgid "delete tags"
-msgstr ""
+msgstr "supprimer des étiquettes"
#: builtin/tag.c:450
msgid "verify tags"
-msgstr ""
+msgstr "vérifier des étiquettes"
#: builtin/tag.c:452
msgid "Tag creation options"
-msgstr ""
+msgstr "Options de création de l'étiquette"
#: builtin/tag.c:454
msgid "annotated tag, needs a message"
-msgstr ""
+msgstr "étiquette annotée, nécessite un message"
#: builtin/tag.c:456
msgid "tag message"
-msgstr ""
+msgstr "message pour l'étiquette"
#: builtin/tag.c:458
msgid "annotated and GPG-signed tag"
-msgstr ""
+msgstr "étiquette annotée et signée avec GPG"
#: builtin/tag.c:462
msgid "use another key to sign the tag"
-msgstr ""
+msgstr "utiliser une autre clé pour signer l'étiquette"
#: builtin/tag.c:463
msgid "replace the tag if exists"
-msgstr ""
+msgstr "remplacer l'étiquette si elle existe"
#: builtin/tag.c:464
msgid "show tag list in columns"
-msgstr ""
+msgstr "afficher la liste des étiquettes sous forme de colonnes"
#: builtin/tag.c:466
msgid "Tag listing options"
-msgstr ""
+msgstr "Options d'affichage des étiquettes"
#: builtin/tag.c:469
msgid "print only tags that contain the commit"
-msgstr ""
+msgstr "afficher seulement les étiquettes qui contiennent la validation"
#: builtin/tag.c:475
msgid "print only tags of the object"
-msgstr ""
+msgstr "afficher seulement les étiquettes de l'objet"
#: builtin/tag.c:504
msgid "--column and -n are incompatible"
-msgstr ""
+msgstr "--column et -n sont incompatibles"
#: builtin/tag.c:521
msgid "-n option is only allowed with -l."
-msgstr ""
+msgstr "l'option -n est autorisée seulement avec -l."
#: builtin/tag.c:523
msgid "--contains option is only allowed with -l."
-msgstr ""
+msgstr "l'option --contains est autorisée seulement avec -l."
#: builtin/tag.c:525
msgid "--points-at option is only allowed with -l."
-msgstr ""
+msgstr "l'option --points-at est autorisée seulement avec -l."
#: builtin/tag.c:533
msgid "only one -F or -m option is allowed."
-msgstr ""
+msgstr "une seule option -F ou -m est autorisée."
#: builtin/tag.c:553
msgid "too many params"
-msgstr ""
+msgstr "trop de paramètres"
#: builtin/tag.c:559
#, c-format
msgid "'%s' is not a valid tag name."
-msgstr ""
+msgstr "'%s' n'est pas un nom d'étiquette valide."
#: builtin/tag.c:564
#, c-format
msgid "tag '%s' already exists"
-msgstr ""
+msgstr "l'étiquette '%s' existe déjà"
#: builtin/tag.c:582
#, c-format
#: builtin/tag.c:586
#, c-format
msgid "Updated tag '%s' (was %s)\n"
-msgstr ""
+msgstr "Étiquette '%s' mise à jour (elle était %s)\n"
#: builtin/update-index.c:401
msgid "git update-index [options] [--] [<file>...]"
-msgstr ""
+msgstr "git update-index [options] [--] [<fichier>...]"
#: builtin/update-index.c:718
msgid "continue refresh even when index needs update"
-msgstr ""
+msgstr "continuer de rafraîchir même si l'index a besoin d'une mise à jour"
#: builtin/update-index.c:721
msgid "refresh: ignore submodules"
-msgstr ""
+msgstr "rafraîchir : ignorer les sous-modules"
#: builtin/update-index.c:724
msgid "do not ignore new files"
-msgstr ""
+msgstr "ne pas ignorer les nouveaux fichiers"
#: builtin/update-index.c:726
msgid "let files replace directories and vice-versa"
-msgstr ""
+msgstr "laisser les fichiers remplacer des répertoires et vice-versa"
#: builtin/update-index.c:728
msgid "notice files missing from worktree"
-msgstr ""
+msgstr "aviser des fichiers manquants dans la copie de travail"
#: builtin/update-index.c:730
msgid "refresh even if index contains unmerged entries"
-msgstr ""
+msgstr "rafraîchir même si l'index contient des éléments non fusionnés"
#: builtin/update-index.c:733
msgid "refresh stat information"
-msgstr ""
+msgstr "rafraîchir l'information de stat"
#: builtin/update-index.c:737
msgid "like --refresh, but ignore assume-unchanged setting"
-msgstr ""
+msgstr "comme --refresh, mais en ignorant l'option assume-unchanged"
#: builtin/update-index.c:741
msgid "<mode> <object> <path>"
-msgstr ""
+msgstr "<mode> <objet> <chemin>"
#: builtin/update-index.c:742
msgid "add the specified entry to the index"
-msgstr ""
+msgstr "ajouter l'élément spécifié dans l'index"
#: builtin/update-index.c:746
msgid "(+/-)x"
-msgstr ""
+msgstr "(+/-)x"
#: builtin/update-index.c:747
msgid "override the executable bit of the listed files"
-msgstr ""
+msgstr "outrepasser le bit exécutable pour les fichiers listés"
#: builtin/update-index.c:751
msgid "mark files as \"not changing\""
-msgstr ""
+msgstr "marquer les fichiers comme \"non changeants\""
#: builtin/update-index.c:754
msgid "clear assumed-unchanged bit"
-msgstr ""
+msgstr "mettre à zéro le bit supposé-non-modifié"
#: builtin/update-index.c:757
msgid "mark files as \"index-only\""
-msgstr ""
+msgstr "marquer les fichiers comme \"index seulement\""
#: builtin/update-index.c:760
msgid "clear skip-worktree bit"
-msgstr ""
+msgstr "mettre à zéro le bit sauter-la-copie-de travail"
#: builtin/update-index.c:763
msgid "add to index only; do not add content to object database"
msgstr ""
+"ajouter seulement à l'index ; ne pas ajouter le contenu dans la base de "
+"données des objets"
#: builtin/update-index.c:765
msgid "remove named paths even if present in worktree"
msgstr ""
+"supprimer les chemins nommés même s'ils sont présents dans la copie de "
+"travail"
#: builtin/update-index.c:767
msgid "with --stdin: input lines are terminated by null bytes"
-msgstr ""
+msgstr "avec --stdin : les lignes en entrée sont terminées par des octets nuls"
#: builtin/update-index.c:769
msgid "read list of paths to be updated from standard input"
-msgstr ""
+msgstr "lire la liste des chemins à mettre à jour depuis l'entrée standard"
#: builtin/update-index.c:773
msgid "add entries from standard input to the index"
-msgstr ""
+msgstr "ajouter les éléments depuis l'entrée standard à l'index"
#: builtin/update-index.c:777
msgid "repopulate stages #2 and #3 for the listed paths"
-msgstr ""
+msgstr "repeupler les étapes n°2 et n°3 pour les chemins listés"
#: builtin/update-index.c:781
msgid "only update entries that differ from HEAD"
-msgstr ""
+msgstr "mettre à jour seulement les éléments qui diffèrent de HEAD"
#: builtin/update-index.c:785
msgid "ignore files missing from worktree"
-msgstr ""
+msgstr "ignorer les fichiers manquants dans la copie de travail"
#: builtin/update-index.c:788
msgid "report actions to standard output"
-msgstr ""
+msgstr "afficher les actions sur la sortie standard"
#: builtin/update-index.c:790
msgid "(for porcelains) forget saved unresolved conflicts"
-msgstr ""
+msgstr "(pour porcelaines) oublier les conflits sauvés et non résolus"
#: builtin/update-index.c:794
msgid "write index in this format"
-msgstr ""
+msgstr "écrire l'index dans ce format"
#: builtin/update-ref.c:7
msgid "git update-ref [options] -d <refname> [<oldval>]"
-msgstr ""
+msgstr "git update-ref [options] -d <nomréférence> [<anciennevaleur>]"
#: builtin/update-ref.c:8
msgid "git update-ref [options] <refname> <newval> [<oldval>]"
msgstr ""
+"git update-ref [options] <nomréférence> <nouvellevaleur> "
+"[<anciennevaleur>]"
#: builtin/update-ref.c:19
msgid "delete the reference"
-msgstr ""
+msgstr "supprimer la référence"
#: builtin/update-ref.c:21
msgid "update <refname> not the one it points to"
-msgstr ""
+msgstr "mettre à jour <nomréférence> et non la référence pointée par lui"
#: builtin/update-server-info.c:6
msgid "git update-server-info [--force]"
-msgstr ""
+msgstr "git update-server-info [--force]"
#: builtin/update-server-info.c:14
msgid "update the info files from scratch"
-msgstr ""
+msgstr "mettre à jour les fichiers d'information à partir de zéro"
#: builtin/verify-pack.c:56
msgid "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."
-msgstr ""
+msgstr "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."
#: builtin/verify-pack.c:66
msgid "verbose"
-msgstr ""
+msgstr "verbeux"
#: builtin/verify-pack.c:68
msgid "show statistics only"
-msgstr ""
+msgstr "afficher seulement les statistiques"
#: builtin/verify-tag.c:17
msgid "git verify-tag [-v|--verbose] <tag>..."
-msgstr ""
+msgstr "git verify-tag [-v|--verbose] <étiquette>..."
#: builtin/verify-tag.c:73
msgid "print tag contents"
-msgstr ""
+msgstr "afficher le contenu de l'étiquette"
#: builtin/write-tree.c:13
msgid "git write-tree [--missing-ok] [--prefix=<prefix>/]"
-msgstr ""
+msgstr "git write-tree [--missing-ok] [--prefix=<préfixe>/]"
#: builtin/write-tree.c:26
msgid "<prefix>/"
-msgstr ""
+msgstr "<préfixe>/"
#: builtin/write-tree.c:27
msgid "write tree object for a subdirectory <prefix>"
-msgstr ""
+msgstr "écrire l'objet arbre pour un sous-répertoire <préfixe>"
#: builtin/write-tree.c:30
msgid "only useful for debugging"
-msgstr ""
+msgstr "seulement utile pour le débogage"
-#: git.c:16
+#: git.c:17
msgid ""
"'git help -a' and 'git help -g' lists available subcommands and some\n"
"concept guides. See 'git help <command>' or 'git help <concept>'\n"
"to read about a specific subcommand or concept."
msgstr ""
+"'git help -a' et 'git help -g' listent les sous-commandes disponibles et\n"
+"quelques concepts. Voir 'git help <command>' ou 'git help <concept>'\n"
+"pour en lire plus à propos d'une commande spécifique ou d'un concept."
+
+#: parse-options.h:144
+msgid "expiry date"
+msgstr "date d'expiration"
-#: parse-options.h:156
+#: parse-options.h:159
msgid "no-op (backward compatibility)"
-msgstr ""
+msgstr "sans action (rétrocompatibilité)"
-#: parse-options.h:232
+#: parse-options.h:236
msgid "be more verbose"
-msgstr ""
+msgstr "être plus verbeux"
-#: parse-options.h:234
+#: parse-options.h:238
msgid "be more quiet"
-msgstr ""
+msgstr "être plus silencieux"
-#: parse-options.h:240
+#: parse-options.h:244
msgid "use <n> digits to display SHA-1s"
-msgstr ""
+msgstr "utiliser <n> chiffres pour afficher les SHA-1s"
#: common-cmds.h:8
msgid "Add file contents to the index"
-msgstr ""
+msgstr "Ajouter le contenu du fichier dans l'index"
#: common-cmds.h:9
msgid "Find by binary search the change that introduced a bug"
-msgstr ""
+msgstr "Rechercher de manière binaire le changement qui a introduit un bogue"
#: common-cmds.h:10
msgid "List, create, or delete branches"
-msgstr ""
+msgstr "Lister, créer ou supprimer des branches"
#: common-cmds.h:11
msgid "Checkout a branch or paths to the working tree"
-msgstr ""
+msgstr "Extraire une branche ou des chemins dans la copie de travail"
#: common-cmds.h:12
msgid "Clone a repository into a new directory"
-msgstr ""
+msgstr "Cloner un dépôt dans un nouveau répertoire"
#: common-cmds.h:13
msgid "Record changes to the repository"
-msgstr ""
+msgstr "Enregistrer les changements dans le dépôt"
#: common-cmds.h:14
msgid "Show changes between commits, commit and working tree, etc"
msgstr ""
+"Afficher les changements entre les validations, entre validation et copie de "
+"travail, etc"
#: common-cmds.h:15
msgid "Download objects and refs from another repository"
-msgstr ""
+msgstr "Télécharger les objets et références depuis un autre dépôt"
#: common-cmds.h:16
msgid "Print lines matching a pattern"
-msgstr ""
+msgstr "Afficher les lignes correspondant à un motif"
#: common-cmds.h:17
msgid "Create an empty Git repository or reinitialize an existing one"
-msgstr ""
+msgstr "Créer un dépôt Git vide ou réinitialiser un existant"
#: common-cmds.h:18
msgid "Show commit logs"
-msgstr ""
+msgstr "Afficher l'historique des validations"
#: common-cmds.h:19
msgid "Join two or more development histories together"
-msgstr ""
+msgstr "Joindre deux ou plusieurs historiques de développement ensemble"
#: common-cmds.h:20
msgid "Move or rename a file, a directory, or a symlink"
-msgstr ""
+msgstr "Déplacer ou renommer un fichier, un répertoire, ou un lien symbolique"
#: common-cmds.h:21
-msgid "Fetch from and merge with another repository or a local branch"
-msgstr ""
+msgid "Fetch from and integrate with another repository or a local branch"
+msgstr "Rapatrier et intégrer avec un autre dépôt ou une branche locale"
#: common-cmds.h:22
msgid "Update remote refs along with associated objects"
-msgstr ""
+msgstr "Mettre à jour les références distantes ainsi que les objets associés"
#: common-cmds.h:23
msgid "Forward-port local commits to the updated upstream head"
msgstr ""
+"Reporter en avant les validations locales dans la tête en amont mise à jour"
#: common-cmds.h:24
msgid "Reset current HEAD to the specified state"
-msgstr ""
+msgstr "Réinitialiser la HEAD courante à l'état spécifié"
#: common-cmds.h:25
msgid "Remove files from the working tree and from the index"
-msgstr ""
+msgstr "Supprimer les fichiers de la copie de travail et de l'index"
#: common-cmds.h:26
msgid "Show various types of objects"
-msgstr ""
+msgstr "Afficher différents types d'objets"
#: common-cmds.h:27
msgid "Show the working tree status"
-msgstr ""
+msgstr "Afficher le statut de la copie de travail"
#: common-cmds.h:28
msgid "Create, list, delete or verify a tag object signed with GPG"
msgstr ""
+"Créer, lister, supprimer ou vérifier un objet d'étiquette signé avec GPG"
#: git-am.sh:50
msgid "You need to set your committer info first"
-msgstr ""
+msgstr "Vous devez d'abord définir vos informations de validateur"
#: git-am.sh:95
msgid ""
"You seem to have moved HEAD since the last 'am' failure.\n"
"Not rewinding to ORIG_HEAD"
msgstr ""
+"Vous semblez avoir déplacé la HEAD depuis le dernier échec de 'am'.\n"
+"Pas de retour à ORIG_HEAD"
#: git-am.sh:105
#, sh-format
msgid ""
-"When you have resolved this problem, run \"$cmdline --resolved\".\n"
+"When you have resolved this problem, run \"$cmdline --continue\".\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 ""
+"Lorsque vous aurez résolu ce problème, lancez \"$cmdline --continue\".\n"
+"Si vous préférez sauter ce patch, lancez \"$cmdline --skip\" à la place.\n"
+"Pour restaurer la branche d'origine et stopper le patchage, lancez "
+"\"$cmdline --abort\"."
#: git-am.sh:121
msgid "Cannot fall back to three-way merge."
-msgstr ""
+msgstr "Impossible de retourner à une fusion à 3 points."
#: git-am.sh:137
msgid "Repository lacks necessary blobs to fall back on 3-way merge."
msgstr ""
+"Le dépôt n'a pas les blobs nécessaires pour un retour à une fusion à 3 "
+"points."
#: git-am.sh:139
msgid "Using index info to reconstruct a base tree..."
msgstr ""
+"Utilisation de l'information de l'index pour reconstruire un arbre de base..."
#: git-am.sh:154
msgid ""
"Did you hand edit your patch?\n"
"It does not apply to blobs recorded in its index."
msgstr ""
+"Avez-vous édité le patch à la main ?\n"
+"Il ne s'applique pas aux blobs enregistrés dans son index."
#: git-am.sh:163
msgid "Falling back to patching base and 3-way merge..."
-msgstr ""
+msgstr "Retour à un patch de la base et fusion à 3 points..."
#: git-am.sh:179
msgid "Failed to merge in the changes."
-msgstr ""
+msgstr "Échec d'intégration des modifications."
#: git-am.sh:274
msgid "Only one StGIT patch series can be applied at once"
-msgstr ""
+msgstr "Seulement une série de patchs StGIT peut être appliquée à la fois"
#: git-am.sh:361
#, sh-format
msgid "Patch format $patch_format is not supported."
-msgstr ""
+msgstr "Le format de patch $patch_format n'est pas supporté."
#: git-am.sh:363
msgid "Patch format detection failed."
-msgstr ""
+msgstr "Échec de détection du format du patch."
#: 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 ""
+"L'option -b/--binary ne fait plus rien depuis longtemps,\n"
+"et elle sera supprimée. Veuillez ne plus l'utiliser."
-#: git-am.sh:477
+#: git-am.sh:479
#, sh-format
msgid "previous rebase directory $dotest still exists but mbox given."
msgstr ""
+"le répertoire précédent de rebasage $dotest existe toujours mais mbox donnée."
-#: git-am.sh:482
+#: git-am.sh:484
msgid "Please make up your mind. --skip or --abort?"
+msgstr "Décidez-vous. --skip ou --abort ?"
+
+#: git-am.sh:520
+#, sh-format
+msgid ""
+"Stray $dotest directory found.\n"
+"Use \"git am --abort\" to remove it."
msgstr ""
+"Répertoire abandonné $dotest trouvé.\n"
+"Utilisez \"git am --abort\" pour le supprimer."
-#: git-am.sh:509
+#: git-am.sh:528
msgid "Resolve operation not in progress, we are not resuming."
msgstr ""
+"Pas de résolution de l'opération en cours, nous ne sommes pas dans une "
+"reprise."
-#: git-am.sh:575
+#: git-am.sh:594
#, sh-format
msgid "Dirty index: cannot apply patches (dirty: $files)"
-msgstr ""
+msgstr "Index sale : impossible d'appliquer des patchs (sales : $files)"
-#: git-am.sh:679
+#: git-am.sh:698
#, sh-format
msgid ""
"Patch is empty. Was it split wrong?\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 ""
+"Le patch est vide. Était-il mal découpé ?\n"
+"Si vous préférez sauter ce patch, lancez plutôt \"$cmdline --skip\".\n"
+"Pour restaurer la branche d'origine et stopper le patchage, lancez "
+"\"$cmdline --abort\"."
-#: git-am.sh:706
+#: git-am.sh:725
msgid "Patch does not have a valid e-mail address."
-msgstr ""
+msgstr "Le patch n'a pas d'adresse e-mail valide."
-#: git-am.sh:753
+#: git-am.sh:772
msgid "cannot be interactive without stdin connected to a terminal."
msgstr ""
+"impossible d'être interactif sans entrée standard connectée à un terminal."
-#: git-am.sh:757
+#: git-am.sh:776
msgid "Commit Body is:"
-msgstr ""
+msgstr "Le corps de la validation est :"
#. 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:764
+#: git-am.sh:783
msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
-msgstr ""
+msgstr "Appliquer ? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
-#: git-am.sh:800
+#: git-am.sh:819
#, sh-format
msgid "Applying: $FIRSTLINE"
-msgstr ""
+msgstr "Application : $FIRSTLINE"
-#: git-am.sh:821
+#: git-am.sh:840
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 ""
+"Aucun changement - avez-vous oublié d'utiliser 'git add' ?\n"
+"S'il n'y a plus rien à indexer, il se peut qu'autre chose ait déjà\n"
+"introduit les mêmes changements ; vous pourriez avoir envie de sauter ce "
+"patch."
-#: git-am.sh:829
+#: git-am.sh:848
msgid ""
"You still have unmerged paths in your index\n"
"did you forget to use 'git add'?"
msgstr ""
+"Vous avez toujours des chemins non fusionnés dans votre index\n"
+"auriez-vous oublié de faire 'git add' ?"
-#: git-am.sh:845
+#: git-am.sh:864
msgid "No changes -- Patch already applied."
-msgstr ""
+msgstr "Pas de changement -- Patch déjà appliqué."
-#: git-am.sh:855
+#: git-am.sh:874
#, sh-format
msgid "Patch failed at $msgnum $FIRSTLINE"
-msgstr ""
+msgstr "Le patch a échoué à $msgnum $FIRSTLINE"
-#: git-am.sh:858
+#: git-am.sh:877
#, sh-format
msgid ""
"The copy of the patch that failed is found in:\n"
" $dotest/patch"
msgstr ""
+"La copie du patch qui a échoué se trouve dans :\n"
+" $dotest/patch"
-#: git-am.sh:876
+#: git-am.sh:895
msgid "applying to an empty history"
-msgstr ""
+msgstr "application à un historique vide"
#: git-bisect.sh:48
msgid "You need to start by \"git bisect start\""
-msgstr ""
+msgstr "Vous devez démarrer avec \"git bisect start\""
#. TRANSLATORS: Make sure to include [Y] and [n] in your
#. translation. The program will only accept English input
#. at this point.
#: git-bisect.sh:54
msgid "Do you want me to do it for you [Y/n]? "
-msgstr ""
+msgstr "Souhaitez-vous que je le fasse pour vous [Y/n] ? "
#: git-bisect.sh:95
#, sh-format
msgid "unrecognised option: '$arg'"
-msgstr ""
+msgstr "option inconnue : '$arg'"
#: git-bisect.sh:99
#, sh-format
#: git-bisect.sh:117
msgid "Bad HEAD - I need a HEAD"
-msgstr ""
+msgstr "Mauvaise HEAD - j'ai besoin d'une HEAD"
#: git-bisect.sh:130
#, sh-format
msgid ""
"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
msgstr ""
+"L'extraction de '$start_head' a échoué. Essayez 'git bisect reset "
+"<branchevalide>'."
#: git-bisect.sh:140
msgid "won't bisect on seeked tree"
-msgstr ""
+msgstr "refus de bissecter sur un arbre 'seeked'"
#: git-bisect.sh:144
msgid "Bad HEAD - strange symbolic ref"
-msgstr ""
+msgstr "Mauvaise HEAD - référence symbolique douteuse"
#: git-bisect.sh:189
#, sh-format
msgid "Bad bisect_write argument: $state"
-msgstr ""
+msgstr "Mauvais argument pour bisect_write : $state"
#: git-bisect.sh:218
#, sh-format
msgid "Bad rev input: $arg"
-msgstr ""
+msgstr "Mauvaise révision en entrée : $arg"
#: git-bisect.sh:232
msgid "Please call 'bisect_state' with at least one argument."
-msgstr ""
+msgstr "Veuillez appeler 'bisect_state' avec au moins un argument."
#: git-bisect.sh:244
#, sh-format
msgid "Bad rev input: $rev"
-msgstr ""
+msgstr "Mauvaise révision en entrée : $rev"
#: git-bisect.sh:250
msgid "'git bisect bad' can take only one argument."
-msgstr ""
+msgstr "'git bisect bad' n'accepte qu'un seul argument."
#. 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 ""
+msgstr "Attention : bissection avec seulement une mauvaise validation."
#. 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 ""
+msgstr "Êtes-vous sûr [Y/n] ? "
#: git-bisect.sh:289
msgid ""
"You need to give me at least one good and one bad revisions.\n"
"(You can use \"git bisect bad\" and \"git bisect good\" for that.)"
msgstr ""
+"Vous devez me donner au moins une bonne et une mauvaise révision.\n"
+"(Vous pouvez utiliser \"git bisect bad\" et \"git bisect good\" pour cela.)"
#: git-bisect.sh:292
msgid ""
"You then need to give me at least one good and one bad revisions.\n"
"(You can use \"git bisect bad\" and \"git bisect good\" for that.)"
msgstr ""
+"Vous devez démarrer avec \"git bisect start\".\n"
+"Puis vous devez me donner au moins une bonne et une mauvaise révision.\n"
+"(Vous pouvez utiliser \"git bisect bad\" et \"git bisect good\" pour cela.)"
#: git-bisect.sh:363 git-bisect.sh:490
msgid "We are not bisecting."
-msgstr ""
+msgstr "Pas de bissection en cours."
#: git-bisect.sh:370
#, sh-format
msgid "'$invalid' is not a valid commit"
-msgstr "'$invalid' n'est pas un commit valide"
+msgstr "'$invalid' n'est pas une validation valide"
#: git-bisect.sh:379
#, sh-format
"Could not check out original HEAD '$branch'.\n"
"Try 'git bisect reset <commit>'."
msgstr ""
+"Échec d'extraction de la HEAD d'origine '$branch'.\n"
+"Essayez 'git bisect reset <commit>'."
#: git-bisect.sh:406
msgid "No logfile given"
-msgstr ""
+msgstr "Pas de fichier de log donné"
#: git-bisect.sh:407
#, sh-format
msgid "cannot read $file for replaying"
-msgstr ""
+msgstr "impossible de lire $file pour rejouer"
#: git-bisect.sh:424
msgid "?? what are you talking about?"
-msgstr ""
+msgstr "?? de quoi parlez-vous ?"
#: git-bisect.sh:436
#, sh-format
msgid "running $command"
-msgstr ""
+msgstr "lancement de $command"
#: git-bisect.sh:443
#, sh-format
"bisect run failed:\n"
"exit code $res from '$command' is < 0 or >= 128"
msgstr ""
+"la bissection a échoué :\n"
+"le code retour $res de '$command' est < 0 ou >= 128"
#: git-bisect.sh:469
msgid "bisect run cannot continue any more"
-msgstr ""
+msgstr "la bissection ne peut plus continuer"
#: git-bisect.sh:475
#, sh-format
"bisect run failed:\n"
"'bisect_state $state' exited with error code $res"
msgstr ""
+"la bissection a échoué :\n"
+"'bisect_state $state' a retourné le code erreur $res"
#: git-bisect.sh:482
msgid "bisect run success"
-msgstr ""
+msgstr "succès de la bissection"
#: git-pull.sh:21
msgid ""
"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n"
"as appropriate to mark resolution, or use 'git commit -a'."
msgstr ""
+"Le pull n'est pas possible car vous avez des fichiers non fusionnés.\n"
+"Veuillez les corriger dans votre copie de travail, et utilisez alors 'git "
+"add/rm <file>'\n"
+"si nécessaire pour marquer comme résolu, ou utilisez 'git commit -a'."
#: git-pull.sh:25
msgid "Pull is not possible because you have unmerged files."
-msgstr ""
+msgstr "Le pull n'est pas possible car vous avez des fichiers non fusionnés."
#: git-pull.sh:203
msgid "updating an unborn branch with changes added to the index"
msgstr ""
+"mise à jour d'une branche non encore créée avec les changements ajoutés dans "
+"l'index"
#. The fetch involved updating the current branch.
#. The working tree and the index file is still based on the
"Warning: fast-forwarding your working tree from\n"
"Warning: commit $orig_head."
msgstr ""
+"Attention : fetch a mis à jour la tête de la branche courante.\n"
+"Attention : mise à jour en avance rapide de votre copie de travail\n"
+"Attention : depuis la validation $orig_head."
#: git-pull.sh:260
msgid "Cannot merge multiple branches into empty head"
-msgstr ""
+msgstr "Impossible de fusionner de multiples branches sur une tête vide"
#: git-pull.sh:264
msgid "Cannot rebase onto multiple branches"
-msgstr ""
+msgstr "Impossible de rebaser sur de multiples branches"
-#: git-rebase.sh:53
+#: git-rebase.sh:54
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 ""
+"Lorsque vous aurez résolu ce problème, lancez \"git rebase --continue\".\n"
+"Si vous préférez sauter ce patch, lancez \"git rebase --skip\" à la place.\n"
+"Pour extraire la branche d'origine et stopper le rebasage, lancez \"git "
+"rebase --abort\"."
+
+#: git-rebase.sh:156
+msgid "Applied autostash."
+msgstr "Autoremisage appliqué."
+
+#: git-rebase.sh:159
+#, sh-format
+msgid "Cannot store $stash_sha1"
+msgstr "Impossible de stocker $stash_sha1"
#: git-rebase.sh:160
-msgid "The pre-rebase hook refused to rebase."
+msgid ""
+"Applying autostash resulted in conflicts.\n"
+"Your changes are safe in the stash.\n"
+"You can run \"git stash pop\" or \"git stash drop\" at any time.\n"
msgstr ""
+"L'application de l'autoremisage a provoqué des conflits\n"
+"Vos modifications sont à l'abri dans la remise.\n"
+"Vous pouvez lancer \"git stash pop\" ou \"git stash drop\" à tout moment.\n"
+
+#: git-rebase.sh:190
+msgid "The pre-rebase hook refused to rebase."
+msgstr "Le crochet pre-rebase a refusé de rebaser."
-#: git-rebase.sh:165
+#: git-rebase.sh:195
msgid "It looks like git-am is in progress. Cannot rebase."
-msgstr ""
+msgstr "Il semble que git-am soit en cours. Impossible de rebaser."
-#: git-rebase.sh:296
+#: git-rebase.sh:329
msgid "The --exec option must be used with the --interactive option"
-msgstr ""
+msgstr "L'option --exec doit être utilisée avec l'option --interactive"
-#: git-rebase.sh:301
+#: git-rebase.sh:334
msgid "No rebase in progress?"
-msgstr ""
+msgstr "Pas de rebasage en cours ?"
-#: git-rebase.sh:312
+#: git-rebase.sh:345
msgid "The --edit-todo action can only be used during interactive rebase."
msgstr ""
+"L'action --edit-todo peut seulement être utilisée lors d'un rebasage "
+"interactif."
-#: git-rebase.sh:319
+#: git-rebase.sh:352
msgid "Cannot read HEAD"
-msgstr ""
+msgstr "Impossible de lire HEAD"
-#: git-rebase.sh:322
+#: git-rebase.sh:355
msgid ""
"You must edit all merge conflicts and then\n"
"mark them as resolved using git add"
msgstr ""
+"Vous devez éditer tous les conflits de fusion et\n"
+"les marquer comme résolus avec git add"
-#: git-rebase.sh:340
+#: git-rebase.sh:373
#, sh-format
msgid "Could not move back to $head_name"
-msgstr ""
+msgstr "Impossible de revenir à $head_name"
-#: git-rebase.sh:359
+#: git-rebase.sh:392
#, sh-format
msgid ""
"It seems that there is already a $state_dir_base directory, and\n"
"and run me again. I am stopping in case you still have something\n"
"valuable there."
msgstr ""
+"Il semble qu'il y ait déjà un répertoire $state_dir_base, et je me demande\n"
+"si vous n'êtes pas au milieu d'un autre rebasage. Si c'est le cas,\n"
+"merci d'essayer\n"
+"\t$cmd_live_rebase\n"
+"Si ça n'est pas le cas, merci de\n"
+"\t$cmd_clear_stale_rebase\n"
+"puis relancez-moi à nouveau. Je m'arrête au cas où vous auriez quelque "
+"chose\n"
+"d'important ici."
-#: git-rebase.sh:404
+#: git-rebase.sh:437
#, sh-format
msgid "invalid upstream $upstream_name"
-msgstr ""
+msgstr "invalide $upstream_name en amont"
-#: git-rebase.sh:428
+#: git-rebase.sh:461
#, sh-format
msgid "$onto_name: there are more than one merge bases"
-msgstr ""
+msgstr "$onto_name : il y a plus d'une base de fusion"
-#: git-rebase.sh:431 git-rebase.sh:435
+#: git-rebase.sh:464 git-rebase.sh:468
#, sh-format
msgid "$onto_name: there is no merge base"
-msgstr ""
+msgstr "$onto_name : il n'y a pas de base de fusion"
-#: git-rebase.sh:440
+#: git-rebase.sh:473
#, sh-format
msgid "Does not point to a valid commit: $onto_name"
-msgstr ""
+msgstr "Ne pointe pas sur une validation valide : $onto_name"
-#: git-rebase.sh:463
+#: git-rebase.sh:496
#, sh-format
msgid "fatal: no such branch: $branch_name"
-msgstr ""
+msgstr "fatal : pas de branche : $branch_name"
+
+#: git-rebase.sh:519
+msgid "Cannot autostash"
+msgstr "Autoremisage impossible"
+
+#: git-rebase.sh:524
+#, sh-format
+msgid "Created autostash: $stash_abbrev"
+msgstr "Autoremisage créé : $stash_abbrev"
-#: git-rebase.sh:483
+#: git-rebase.sh:528
msgid "Please commit or stash them."
-msgstr ""
+msgstr "Veuillez les valider ou les remiser."
-#: git-rebase.sh:501
+#: git-rebase.sh:548
#, sh-format
msgid "Current branch $branch_name is up to date."
-msgstr ""
+msgstr "La branche courante $branch_name est à jour."
-#: git-rebase.sh:504
+#: git-rebase.sh:552
#, sh-format
msgid "Current branch $branch_name is up to date, rebase forced."
-msgstr ""
+msgstr "La branche courante $branch_name est à jour, rebasage forcé."
-#: git-rebase.sh:515
+#: git-rebase.sh:563
#, sh-format
msgid "Changes from $mb to $onto:"
-msgstr ""
+msgstr "Changements de $mb sur $onto :"
#. Detach HEAD and reset the tree
-#: git-rebase.sh:524
+#: git-rebase.sh:572
msgid "First, rewinding head to replay your work on top of it..."
-msgstr ""
+msgstr "Premièrement, retour de head pour rejouer votre travail par-dessus..."
-#: git-rebase.sh:532
+#: git-rebase.sh:582
#, sh-format
msgid "Fast-forwarded $branch_name to $onto_name."
-msgstr ""
+msgstr "$branch_name mise à jour en avance rapide sur $onto_name."
#: git-stash.sh:51
msgid "git stash clear with parameters is unimplemented"
-msgstr ""
+msgstr "git stash clear avec des paramètres n'est pas implémenté"
#: git-stash.sh:74
msgid "You do not have the initial commit yet"
-msgstr ""
+msgstr "Vous n'avez pas encore la validation initiale"
#: git-stash.sh:89
msgid "Cannot save the current index state"
-msgstr ""
+msgstr "Impossible de sauver l'état courant de l'index"
#: git-stash.sh:123 git-stash.sh:136
msgid "Cannot save the current worktree state"
-msgstr ""
+msgstr "Impossible de sauver l'état courant de la copie de travail"
#: git-stash.sh:140
msgid "No changes selected"
-msgstr ""
+msgstr "Aucun changement sélectionné"
#: git-stash.sh:143
msgid "Cannot remove temporary index (can't happen)"
-msgstr ""
+msgstr "Impossible de supprimer l'index temporaire (ne peut pas se produire)"
#: git-stash.sh:156
msgid "Cannot record working tree state"
-msgstr ""
+msgstr "Impossible d'enregistrer l'état de la copie de travail"
+
+#: git-stash.sh:190
+#, sh-format
+msgid "Cannot update $ref_stash with $w_commit"
+msgstr "Impossible de mettre à jour $ref_stash avec $w_commit"
#. TRANSLATORS: $option is an invalid option, like
#. `--blah-blah'. The 7 spaces at the beginning of the
#. $ git stash save --blah-blah 2>&1 | head -n 2
#. error: unknown option for 'stash save': --blah-blah
#. To provide a message, use git stash save -- '--blah-blah'
-#: git-stash.sh:202
+#: git-stash.sh:241
#, sh-format
msgid ""
"error: unknown option for 'stash save': $option\n"
" To provide a message, use git stash save -- '$option'"
msgstr ""
+"erreur: option inconnue pour 'stash save': $option\n"
+" Pour fournir un message, utilisez git stash save -- '$option'"
-#: git-stash.sh:223
+#: git-stash.sh:262
msgid "No local changes to save"
+msgstr "Pas de changements en local à sauver"
+
+#: git-stash.sh:268
+msgid ""
+"The following untracked files would NOT be saved but need to be removed by "
+"stash save:"
msgstr ""
+"Les fichiers suivants non suivis ne seront PAS sauvés mais doivent être "
+"supprimés par l'état du remisage :"
+
+#: git-stash.sh:270
+msgid ""
+"Aborting. Consider using either the --force or --include-untracked option."
+msgstr "Abandon. Utilisez l'option --force ou --include-untracked."
-#: git-stash.sh:227
+#: git-stash.sh:274
msgid "Cannot initialize stash"
-msgstr ""
+msgstr "Impossible d'initialiser le remisage"
-#: git-stash.sh:235
+#: git-stash.sh:278
msgid "Cannot save the current status"
-msgstr ""
+msgstr "Impossible de sauver le statut courant"
-#: git-stash.sh:253
+#: git-stash.sh:296
msgid "Cannot remove worktree changes"
-msgstr ""
+msgstr "Impossible de supprimer les changements de la copie de travail"
-#: git-stash.sh:352
+#: git-stash.sh:395
msgid "No stash found."
-msgstr ""
+msgstr "Pas de remisage trouvé."
-#: git-stash.sh:359
+#: git-stash.sh:402
#, sh-format
msgid "Too many revisions specified: $REV"
-msgstr ""
+msgstr "Trop de révisions spécifiées : $REV"
-#: git-stash.sh:365
+#: git-stash.sh:408
#, sh-format
msgid "$reference is not valid reference"
-msgstr ""
+msgstr "$reference n'est pas une référence valide"
-#: git-stash.sh:393
+#: git-stash.sh:436
#, sh-format
msgid "'$args' is not a stash-like commit"
-msgstr "'$args' n'est pas un commit de type remisage"
+msgstr "'$args' n'est pas une validation de type remisage"
-#: git-stash.sh:404
+#: git-stash.sh:447
#, sh-format
msgid "'$args' is not a stash reference"
msgstr "'$args' n'est pas une référence de remisage"
-#: git-stash.sh:412
+#: git-stash.sh:455
msgid "unable to refresh index"
-msgstr ""
+msgstr "impossible de rafraîchir l'index"
-#: git-stash.sh:416
+#: git-stash.sh:459
msgid "Cannot apply a stash in the middle of a merge"
-msgstr ""
+msgstr "Impossible d'appliquer un remisage au milieu d'une fusion"
-#: git-stash.sh:424
+#: git-stash.sh:467
msgid "Conflicts in index. Try without --index."
-msgstr ""
+msgstr "Conflits dans l'index. Essayez sans --index."
-#: git-stash.sh:426
+#: git-stash.sh:469
msgid "Could not save index tree"
-msgstr ""
+msgstr "Impossible de sauver l'arbre d'index"
-#: git-stash.sh:460
+#: git-stash.sh:503
msgid "Cannot unstage modified files"
-msgstr ""
+msgstr "Impossible de désindexer les fichiers modifiés"
-#: git-stash.sh:475
+#: git-stash.sh:518
msgid "Index was not unstashed."
-msgstr ""
+msgstr "L'index n'a pas été sorti de remise"
-#: git-stash.sh:492
+#: git-stash.sh:535
#, sh-format
msgid "Dropped ${REV} ($s)"
-msgstr ""
+msgstr "${REV} supprimé ($s)"
-#: git-stash.sh:493
+#: git-stash.sh:536
#, sh-format
msgid "${REV}: Could not drop stash entry"
-msgstr ""
+msgstr "${REV}: Impossible de supprimer l'élément de stash"
-#: git-stash.sh:500
+#: git-stash.sh:543
msgid "No branch name specified"
-msgstr ""
+msgstr "Aucune branche spécifiée"
-#: git-stash.sh:571
+#: git-stash.sh:615
msgid "(To restore them type \"git stash apply\")"
-msgstr ""
+msgstr "(Pour les restaurer tapez \"git stash apply\")"
-#: git-submodule.sh:91
+#: git-submodule.sh:95
#, sh-format
msgid "cannot strip one component off url '$remoteurl'"
-msgstr ""
+msgstr "impossible de supprimer un composant de l'URL '$remoteurl'"
-#: git-submodule.sh:196
+#: git-submodule.sh:237
#, sh-format
msgid "No submodule mapping found in .gitmodules for path '$sm_path'"
msgstr ""
+"Pas de mise en correspondance du sous-module trouvé dans .gitmodules pour le "
+"chemin '$sm_path'"
-#: git-submodule.sh:239
+#: git-submodule.sh:281
#, sh-format
msgid "Clone of '$url' into submodule path '$sm_path' failed"
-msgstr ""
+msgstr "Le clonage de '$url' dans le chemin de sous-module '$sm_path' a échoué"
-#: git-submodule.sh:251
+#: git-submodule.sh:293
#, sh-format
msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa"
msgstr ""
+"Le répertoire Git '$a' fait partie du chemin de sous-module '$b' ou vice-"
+"versa"
+
+#: git-submodule.sh:403
+msgid "Relative path can only be used from the toplevel of the working tree"
+msgstr ""
+"Un chemin relatif ne peut être utilisé que depuis la racine de la copie de "
+"travail"
-#: git-submodule.sh:349
+#: git-submodule.sh:413
#, sh-format
msgid "repo URL: '$repo' must be absolute or begin with ./|../"
-msgstr ""
+msgstr "L'URL de dépôt '$repo' doit être absolu ou commencer par ./|../"
-#: git-submodule.sh:366
+#: git-submodule.sh:430
#, sh-format
msgid "'$sm_path' already exists in the index"
-msgstr ""
+msgstr "'$sm_path' existe déjà dans l'index"
-#: git-submodule.sh:370
+#: git-submodule.sh:434
#, 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 ""
+"Le chemin suivant est ignoré par un de vos fichiers .gitignore :\n"
+"$sm_path\n"
+"Utilisez -f si vous voulez vraiment l'ajouter."
-#: git-submodule.sh:388
+#: git-submodule.sh:452
#, sh-format
msgid "Adding existing repo at '$sm_path' to the index"
-msgstr ""
+msgstr "Ajout du dépôt existant à '$sm_path' dans l'index"
-#: git-submodule.sh:390
+#: git-submodule.sh:454
#, sh-format
msgid "'$sm_path' already exists and is not a valid git repo"
msgstr "'$sm_path' existe déjà et n'est pas un dépôt git valide"
-#: git-submodule.sh:398
+#: git-submodule.sh:462
#, sh-format
msgid "A git directory for '$sm_name' is found locally with remote(s):"
msgstr ""
+"Un répertoire git pour '$sm_name' est trouvé en local avec le(s) serveur(s) "
+"distant(s) :"
-#: git-submodule.sh:400
+#: git-submodule.sh:464
#, sh-format
msgid ""
"If you want to reuse this local git directory instead of cloning again from"
msgstr ""
+"Si vous voulez réutiliser ce répertoire git local au lieu de cloner à "
+"nouveau depuis"
-#: git-submodule.sh:402
+#: git-submodule.sh:466
#, sh-format
msgid ""
"use the '--force' option. If the local git directory is not the correct repo"
msgstr ""
+"utilisez l'option '--force'. Si le répertoire local git n'est pas le dépôt "
+"correct"
-#: git-submodule.sh:403
+#: git-submodule.sh:467
#, sh-format
msgid ""
"or you are unsure what this means choose another name with the '--name' "
"option."
msgstr ""
+"ou vous ne savez pas ce que cela signifie de choisir un autre nom avec "
+"l'option '--name'."
-#: git-submodule.sh:405
+#: git-submodule.sh:469
#, sh-format
msgid "Reactivating local git directory for submodule '$sm_name'."
-msgstr ""
+msgstr "Réactivation du répertoire git local pour le sous-module '$sm_name'."
-#: git-submodule.sh:417
+#: git-submodule.sh:481
#, sh-format
msgid "Unable to checkout submodule '$sm_path'"
-msgstr ""
+msgstr "Impossible d'extraire le sous-module '$sm_path'"
-#: git-submodule.sh:422
+#: git-submodule.sh:486
#, sh-format
msgid "Failed to add submodule '$sm_path'"
-msgstr ""
+msgstr "Échec d'ajout du sous-module '$sm_path'"
-#: git-submodule.sh:431
+#: git-submodule.sh:495
#, sh-format
msgid "Failed to register submodule '$sm_path'"
-msgstr ""
+msgstr "Échec d'enregistrement du sous-module '$sm_path'"
-#: git-submodule.sh:474
+#: git-submodule.sh:539
#, sh-format
-msgid "Entering '$prefix$sm_path'"
-msgstr ""
+msgid "Entering '$prefix$displaypath'"
+msgstr "Entrée dans '$prefix$displaypath'"
-#: git-submodule.sh:488
+#: git-submodule.sh:554
#, sh-format
-msgid "Stopping at '$sm_path'; script returned non-zero status."
+msgid "Stopping at '$prefix$displaypath'; script returned non-zero status."
msgstr ""
+"Arrêt sur '$prefix$displaypath' ; le script a retourné un statut non nul."
-#: git-submodule.sh:532
+#: git-submodule.sh:600
#, sh-format
-msgid "No url found for submodule path '$sm_path' in .gitmodules"
+msgid "No url found for submodule path '$displaypath' in .gitmodules"
msgstr ""
+"URL non trouvé pour le chemin de sous-module '$displaypath' dans .gitmodules"
-#: git-submodule.sh:541
+#: git-submodule.sh:609
#, sh-format
-msgid "Failed to register url for submodule path '$sm_path'"
+msgid "Failed to register url for submodule path '$displaypath'"
msgstr ""
+"Échec d'enregistrement de l'URL pour le chemin de sous-module '$displaypath'"
-#: git-submodule.sh:543
+#: git-submodule.sh:611
#, sh-format
-msgid "Submodule '$name' ($url) registered for path '$sm_path'"
-msgstr ""
+msgid "Submodule '$name' ($url) registered for path '$displaypath'"
+msgstr "Sous-module '$name' ($url) enregistré pour le chemin '$displaypath'"
-#: git-submodule.sh:551
+#: git-submodule.sh:619
#, sh-format
-msgid "Failed to register update mode for submodule path '$sm_path'"
+msgid "Failed to register update mode for submodule path '$displaypath'"
msgstr ""
+"Échec d'enregistrement du mode de mise à jour pour le chemin de sous-module "
+"'$displaypath'"
-#: git-submodule.sh:588
+#: git-submodule.sh:656
#, sh-format
msgid "Use '.' if you really want to deinitialize all submodules"
msgstr ""
+"Utilisez '.' si vous voulez vraiment réinitialiser tous les sous-modules"
-#: git-submodule.sh:603
+#: git-submodule.sh:673
#, sh-format
-msgid "Submodule work tree '$sm_path' contains a .git directory"
+msgid "Submodule work tree '$displaypath' contains a .git directory"
msgstr ""
+"La copie de travail du sous-module '$displaypath' contient un répertoire .git"
-#: git-submodule.sh:604
+#: git-submodule.sh:674
#, sh-format
msgid ""
"(use 'rm -rf' if you really want to remove it including all of its history)"
msgstr ""
+"(utilisez 'rm -rf' si vous voulez vraiment le supprimer en incluant tout son "
+"historique)"
-#: git-submodule.sh:610
+#: git-submodule.sh:680
#, sh-format
msgid ""
-"Submodule work tree '$sm_path' contains local modifications; use '-f' to "
+"Submodule work tree '$displaypath' contains local modifications; use '-f' to "
"discard them"
msgstr ""
+"La copie de travail du sous-module '$displaypath' contient des modifications "
+"locales ; utilisez '-f' pour les annuler"
-#: git-submodule.sh:613
+#: git-submodule.sh:683
#, sh-format
-msgid "Cleared directory '$sm_path'"
-msgstr ""
+msgid "Cleared directory '$displaypath'"
+msgstr "Répertoire '$displaypath' nettoyé"
-#: git-submodule.sh:614
+#: git-submodule.sh:684
#, sh-format
-msgid "Could not remove submodule work tree '$sm_path'"
+msgid "Could not remove submodule work tree '$displaypath'"
msgstr ""
+"Impossible de supprimer la copie de travail du sous-module '$displaypath'"
-#: git-submodule.sh:617
+#: git-submodule.sh:687
#, sh-format
-msgid "Could not create empty submodule directory '$sm_path'"
-msgstr ""
+msgid "Could not create empty submodule directory '$displaypath'"
+msgstr "Impossible de créer le répertoire vide du sous-module '$displaypath'"
-#: git-submodule.sh:626
+#: git-submodule.sh:696
#, sh-format
-msgid "Submodule '$name' ($url) unregistered for path '$sm_path'"
+msgid "Submodule '$name' ($url) unregistered for path '$displaypath'"
msgstr ""
+"Le sous-module '$name' ($url) n'est pas enregistré pour le chemin "
+"'$displaypath'"
-#: git-submodule.sh:731
+#: git-submodule.sh:811
#, sh-format
msgid ""
-"Submodule path '$prefix$sm_path' not initialized\n"
+"Submodule path '$displaypath' not initialized\n"
"Maybe you want to use 'update --init'?"
msgstr ""
+"Chemin de sous-module '$displaypath' non initialisé\n"
+"Peut-être souhaitez-vous utiliser 'update --init' ?"
-#: git-submodule.sh:744
+#: git-submodule.sh:824
#, sh-format
-msgid "Unable to find current revision in submodule path '$prefix$sm_path'"
+msgid "Unable to find current revision in submodule path '$displaypath'"
msgstr ""
+"Impossible de trouver la révision courante dans le chemin de sous-module "
+"'$displaypath'"
-#: git-submodule.sh:753
+#: git-submodule.sh:833
#, sh-format
msgid "Unable to fetch in submodule path '$sm_path'"
-msgstr ""
+msgstr "Impossible de rapatrier dans le chemin de sous-module '$sm_path'"
-#: git-submodule.sh:777
+#: git-submodule.sh:857
#, sh-format
-msgid "Unable to fetch in submodule path '$prefix$sm_path'"
-msgstr ""
+msgid "Unable to fetch in submodule path '$displaypath'"
+msgstr "Impossible de rapatrier dans le chemin de sous-module '$displaypath'"
-#: git-submodule.sh:791
+#: git-submodule.sh:871
#, sh-format
-msgid "Unable to rebase '$sha1' in submodule path '$prefix$sm_path'"
+msgid "Unable to rebase '$sha1' in submodule path '$displaypath'"
msgstr ""
+"Impossible de rebaser '$sha1' dans le chemin de sous-module '$displaypath'"
-#: git-submodule.sh:792
+#: git-submodule.sh:872
#, sh-format
-msgid "Submodule path '$prefix$sm_path': rebased into '$sha1'"
-msgstr ""
+msgid "Submodule path '$displaypath': rebased into '$sha1'"
+msgstr "Chemin de sous-module '$displaypath' : rebasé dans '$sha1'"
-#: git-submodule.sh:797
+#: git-submodule.sh:877
#, sh-format
-msgid "Unable to merge '$sha1' in submodule path '$prefix$sm_path'"
+msgid "Unable to merge '$sha1' in submodule path '$displaypath'"
msgstr ""
+"Impossible de fusionner '$sha1' dans le chemin de sous-module '$displaypath'"
-#: git-submodule.sh:798
+#: git-submodule.sh:878
#, sh-format
-msgid "Submodule path '$prefix$sm_path': merged in '$sha1'"
-msgstr ""
+msgid "Submodule path '$displaypath': merged in '$sha1'"
+msgstr "Chemin de sous-module '$displaypath' : fusionné dans '$sha1'"
-#: git-submodule.sh:803
+#: git-submodule.sh:883
#, sh-format
-msgid "Unable to checkout '$sha1' in submodule path '$prefix$sm_path'"
+msgid ""
+"Execution of '$command $sha1' failed in submodule path '$prefix$sm_path'"
msgstr ""
+"L'exécution de '$command $sha1' a échoué dans le chemin de sous-module "
+"'$prefix$sm_path'"
-#: git-submodule.sh:804
+#: git-submodule.sh:884
#, sh-format
-msgid "Submodule path '$prefix$sm_path': checked out '$sha1'"
-msgstr ""
+msgid "Submodule path '$prefix$sm_path': '$command $sha1'"
+msgstr "Chemin de sous-module '$prefix$sm_path' : '$command $sha1'"
-#: git-submodule.sh:831
+#: git-submodule.sh:889
#, sh-format
-msgid "Failed to recurse into submodule path '$prefix$sm_path'"
+msgid "Unable to checkout '$sha1' in submodule path '$displaypath'"
msgstr ""
+"Impossible d'extraire '$sha1' dans le chemin de sous-module '$displaypath'"
+
+#: git-submodule.sh:890
+#, sh-format
+msgid "Submodule path '$displaypath': checked out '$sha1'"
+msgstr "Chemin de sous-module '$displaypath' : '$sha1' extrait"
+
+#: git-submodule.sh:917
+#, sh-format
+msgid "Failed to recurse into submodule path '$displaypath'"
+msgstr "Échec de parcours dans le chemin du sous-module '$displaypath'"
-#: git-submodule.sh:939
+#: git-submodule.sh:1025
msgid "The --cached option cannot be used with the --files option"
-msgstr ""
+msgstr "L'option --cached ne peut pas être utilisée avec l'option --files"
#. unexpected type
-#: git-submodule.sh:979
+#: git-submodule.sh:1066
#, sh-format
msgid "unexpected mode $mod_dst"
-msgstr ""
+msgstr "mode $mod_dst inattendu"
-#: git-submodule.sh:997
+#: git-submodule.sh:1086
#, sh-format
-msgid " Warn: $name doesn't contain commit $sha1_src"
-msgstr ""
+msgid " Warn: $display_name doesn't contain commit $sha1_src"
+msgstr " Attention : $display_name ne contient pas la validation $sha1_src"
-#: git-submodule.sh:1000
+#: git-submodule.sh:1089
#, sh-format
-msgid " Warn: $name doesn't contain commit $sha1_dst"
-msgstr ""
+msgid " Warn: $display_name doesn't contain commit $sha1_dst"
+msgstr " Attention : $display_name ne contient pas la validation $sha1_dst"
-#: git-submodule.sh:1003
+#: git-submodule.sh:1092
#, sh-format
-msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst"
+msgid " Warn: $display_name doesn't contain commits $sha1_src and $sha1_dst"
msgstr ""
+" Attention : $display_name ne contient pas les validations $sha1_src et "
+"$sha1_dst"
-#: git-submodule.sh:1028
+#: git-submodule.sh:1117
msgid "blob"
-msgstr ""
+msgstr "blob"
-#: git-submodule.sh:1066
+#: git-submodule.sh:1155
msgid "Submodules changed but not updated:"
-msgstr ""
+msgstr "Sous-modules modifiés mais non mis à jour :"
-#: git-submodule.sh:1068
+#: git-submodule.sh:1157
msgid "Submodule changes to be committed:"
-msgstr ""
+msgstr "Changements du sous-module à valider :"
-#: git-submodule.sh:1153
+#: git-submodule.sh:1242
#, sh-format
msgid "Failed to recurse into submodule path '$sm_path'"
-msgstr ""
+msgstr "Échec de parcours dans le chemin du sous-module '$sm_path'"
-#: git-submodule.sh:1216
+#: git-submodule.sh:1306
#, sh-format
-msgid "Synchronizing submodule url for '$prefix$sm_path'"
-msgstr ""
+msgid "Synchronizing submodule url for '$displaypath'"
+msgstr "Synchronisation de l'URL sous-module pour '$displaypath'"
msgstr ""
#: builtin/describe.c:16
-msgid "git describe [options] <committish>*"
+msgid "git describe [options] <commit-ish>*"
msgstr ""
#: builtin/describe.c:17
msgstr ""
#: builtin/describe.c:489
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
msgstr ""
#: builtin/diff.c:79
msgstr ""
#: builtin/describe.c:482
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
msgstr ""
#: builtin/diff.c:77
msgstr ""
#: builtin/describe.c:482
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
msgstr ""
#: builtin/diff.c:77
msgstr "Nenhum nome encontrado, não descreve nada."
#: builtin/describe.c:482
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
msgstr ""
#: builtin/diff.c:77
msgstr "skriv storlekar i människoläsbart format"
#: builtin/describe.c:16
-msgid "git describe [options] <committish>*"
+msgid "git describe [options] <commit-ish>*"
msgstr "git describe [flaggor] <incheckning-igt>*"
#: builtin/describe.c:17
msgstr "Inga namn hittades, kan inte beskriva något."
#: builtin/describe.c:489
-msgid "--dirty is incompatible with committishes"
-msgstr "--dirty är inkompatibelt med \"committish\"-värden"
+msgid "--dirty is incompatible with commit-ishes"
+msgstr "--dirty är inkompatibelt med \"commit-ish\"-värden"
#: builtin/diff.c:79
#, c-format
msgstr "hiển thị kích cỡ theo định dạng dành cho người đọc"
#: builtin/describe.c:16
-msgid "git describe [options] <committish>*"
-msgstr "git describe [các-tùy-chọn] <committish>*"
+msgid "git describe [options] <commit-ish>*"
+msgstr "git describe [các-tùy-chọn] <commit-ish>*"
#: builtin/describe.c:17
msgid "git describe [options] --dirty"
msgstr "Không tìm thấy các tên, không thể mô tả gì cả."
#: builtin/describe.c:489
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
msgstr "--dirty là xung khắc với các tùy chọn dành cho chuyển giao (commit)"
#: builtin/diff.c:79
msgstr "以用户可读的格式显示大小"
#: builtin/describe.c:16
-msgid "git describe [options] <committish>*"
+msgid "git describe [options] <commit-ish>*"
msgstr "git describe [选项] <提交号>*"
#: builtin/describe.c:17
msgstr "没有发现名称,无法描述任何东西。"
#: builtin/describe.c:489
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
msgstr "--dirty 不能与提交同时使用"
#: builtin/diff.c:79
* Copyright (C) 2008 Linus Torvalds
*/
#include "cache.h"
+#include "pathspec.h"
#ifdef NO_PTHREADS
-static void preload_index(struct index_state *index, const char **pathspec)
+static void preload_index(struct index_state *index,
+ const struct pathspec *pathspec)
{
; /* nothing */
}
struct thread_data {
pthread_t pthread;
struct index_state *index;
- const char **pathspec;
+ struct pathspec pathspec;
int offset, nr;
};
struct index_state *index = p->index;
struct cache_entry **cep = index->cache + p->offset;
struct cache_def cache;
- struct pathspec pathspec;
- init_pathspec(&pathspec, p->pathspec);
memset(&cache, 0, sizeof(cache));
nr = p->nr;
if (nr + p->offset > index->cache_nr)
continue;
if (ce_uptodate(ce))
continue;
- if (!ce_path_match(ce, &pathspec))
+ if (!ce_path_match(ce, &p->pathspec))
continue;
if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))
continue;
continue;
ce_mark_uptodate(ce);
} while (--nr > 0);
- free_pathspec(&pathspec);
return NULL;
}
-static void preload_index(struct index_state *index, const char **pathspec)
+static void preload_index(struct index_state *index,
+ const struct pathspec *pathspec)
{
int threads, i, work, offset;
struct thread_data data[MAX_PARALLEL];
threads = MAX_PARALLEL;
offset = 0;
work = DIV_ROUND_UP(index->cache_nr, threads);
+ memset(&data, 0, sizeof(data));
for (i = 0; i < threads; i++) {
struct thread_data *p = data+i;
p->index = index;
- p->pathspec = pathspec;
+ if (pathspec)
+ copy_pathspec(&p->pathspec, pathspec);
p->offset = offset;
p->nr = work;
offset += work;
}
#endif
-int read_index_preload(struct index_state *index, const char **pathspec)
+int read_index_preload(struct index_state *index,
+ const struct pathspec *pathspec)
{
int retval = read_index(index);
map_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
if (pp->fmt == CMIT_FMT_EMAIL) {
- if (pp->from_ident) {
+ if (pp->from_ident && ident_cmp(pp->from_ident, &ident)) {
struct strbuf buf = STRBUF_INIT;
strbuf_addstr(&buf, "From: ");
free(to_free);
}
-void sq_quote_print(FILE *stream, const char *src)
-{
- char c;
-
- fputc('\'', stream);
- while ((c = *src++)) {
- if (need_bs_quote(c)) {
- fputs("'\\", stream);
- fputc(c, stream);
- fputc('\'', stream);
- } else {
- fputc(c, stream);
- }
- }
- fputc('\'', stream);
-}
-
void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
{
int i;
/* quoting as a string literal for other languages */
-void perl_quote_print(FILE *stream, const char *src)
+void perl_quote_buf(struct strbuf *sb, const char *src)
{
const char sq = '\'';
const char bq = '\\';
char c;
- fputc(sq, stream);
+ strbuf_addch(sb, sq);
while ((c = *src++)) {
if (c == sq || c == bq)
- fputc(bq, stream);
- fputc(c, stream);
+ strbuf_addch(sb, bq);
+ strbuf_addch(sb, c);
}
- fputc(sq, stream);
+ strbuf_addch(sb, sq);
}
-void python_quote_print(FILE *stream, const char *src)
+void python_quote_buf(struct strbuf *sb, const char *src)
{
const char sq = '\'';
const char bq = '\\';
const char nl = '\n';
char c;
- fputc(sq, stream);
+ strbuf_addch(sb, sq);
while ((c = *src++)) {
if (c == nl) {
- fputc(bq, stream);
- fputc('n', stream);
+ strbuf_addch(sb, bq);
+ strbuf_addch(sb, 'n');
continue;
}
if (c == sq || c == bq)
- fputc(bq, stream);
- fputc(c, stream);
+ strbuf_addch(sb, bq);
+ strbuf_addch(sb, c);
}
- fputc(sq, stream);
+ strbuf_addch(sb, sq);
}
-void tcl_quote_print(FILE *stream, const char *src)
+void tcl_quote_buf(struct strbuf *sb, const char *src)
{
char c;
- fputc('"', stream);
+ strbuf_addch(sb, '"');
while ((c = *src++)) {
switch (c) {
case '[': case ']':
case '{': case '}':
case '$': case '\\': case '"':
- fputc('\\', stream);
+ strbuf_addch(sb, '\\');
default:
- fputc(c, stream);
+ strbuf_addch(sb, c);
break;
case '\f':
- fputs("\\f", stream);
+ strbuf_addstr(sb, "\\f");
break;
case '\r':
- fputs("\\r", stream);
+ strbuf_addstr(sb, "\\r");
break;
case '\n':
- fputs("\\n", stream);
+ strbuf_addstr(sb, "\\n");
break;
case '\t':
- fputs("\\t", stream);
+ strbuf_addstr(sb, "\\t");
break;
case '\v':
- fputs("\\v", stream);
+ strbuf_addstr(sb, "\\v");
break;
}
}
- fputc('"', stream);
+ strbuf_addch(sb, '"');
}
* excluding the final null regardless of the buffer size.
*/
-extern void sq_quote_print(FILE *stream, const char *src);
-
extern void sq_quote_buf(struct strbuf *, const char *src);
extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen);
struct strbuf *out);
/* quoting as a string literal for other languages */
-extern void perl_quote_print(FILE *stream, const char *src);
-extern void python_quote_print(FILE *stream, const char *src);
-extern void tcl_quote_print(FILE *stream, const char *src);
+extern void perl_quote_buf(struct strbuf *sb, const char *src);
+extern void python_quote_buf(struct strbuf *sb, const char *src);
+extern void tcl_quote_buf(struct strbuf *sb, const char *src);
#endif
else
process_blob(lookup_blob(entry.sha1), p, &me, entry.path, cp);
}
- free(tree->buffer);
- tree->buffer = NULL;
+ free_tree_buffer(tree);
}
static void process_tag(struct tag *tag, struct object_array *p,
if (*ptr == '/') {
struct cache_entry *foundce;
++ptr;
- foundce = index_name_exists(istate, ce->name, ptr - ce->name, ignore_case);
+ foundce = index_dir_exists(istate, ce->name, ptr - ce->name - 1);
if (foundce) {
memcpy((void *)startPtr, foundce->name + (startPtr - ce->name), ptr - startPtr);
startPtr = ptr;
}
}
- alias = index_name_exists(istate, ce->name, ce_namelen(ce), ignore_case);
+ alias = index_file_exists(istate, ce->name, ce_namelen(ce), ignore_case);
if (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, st, ce_option)) {
/* Nothing changed, really */
free(ce);
printf(fmt, name);
}
-int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec,
+int refresh_index(struct index_state *istate, unsigned int flags,
+ const struct pathspec *pathspec,
char *seen, const char *header_msg)
{
int i;
continue;
if (pathspec &&
- !match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
+ !match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, seen))
filtered = 1;
if (ce_stage(ce)) {
struct ondisk_cache_entry {
struct cache_time ctime;
struct cache_time mtime;
- unsigned int dev;
- unsigned int ino;
- unsigned int mode;
- unsigned int uid;
- unsigned int gid;
- unsigned int size;
+ uint32_t dev;
+ uint32_t ino;
+ uint32_t mode;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t size;
unsigned char sha1[20];
- unsigned short flags;
+ uint16_t flags;
char name[FLEX_ARRAY]; /* more */
};
struct ondisk_cache_entry_extended {
struct cache_time ctime;
struct cache_time mtime;
- unsigned int dev;
- unsigned int ino;
- unsigned int mode;
- unsigned int uid;
- unsigned int gid;
- unsigned int size;
+ uint32_t dev;
+ uint32_t ino;
+ uint32_t mode;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t size;
unsigned char sha1[20];
- unsigned short flags;
- unsigned short flags2;
+ uint16_t flags;
+ uint16_t flags2;
char name[FLEX_ARRAY]; /* more */
};
continue;
if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce))
ce_smudge_racily_clean_entry(ce);
- if (is_null_sha1(ce->sha1))
- return error("cache entry has null sha1: %s", ce->name);
+ if (is_null_sha1(ce->sha1)) {
+ static const char msg[] = "cache entry has null sha1: %s";
+ static int allow = -1;
+
+ if (allow < 0)
+ allow = git_env_bool("GIT_ALLOW_NULL_SHA1", 0);
+ if (allow)
+ warning(msg, ce->name);
+ else
+ return error(msg, ce->name);
+ }
if (ce_write_entry(&c, newfd, ce, previous_name) < 0)
return -1;
}
{
int component_len, component_count = 0;
+ if (!strcmp(refname, "@"))
+ /* Refname is a single character '@'. */
+ return -1;
+
while (1) {
/* We are at the start of a path component. */
component_len = check_refname_component(refname, flags);
static char *substitute_branch_name(const char **string, int *len)
{
struct strbuf buf = STRBUF_INIT;
- int ret = interpret_branch_name(*string, &buf);
+ int ret = interpret_branch_name(*string, *len, &buf);
if (ret == *len) {
size_t size;
}
struct ref_lock *lock_any_ref_for_update(const char *refname,
- const unsigned char *old_sha1, int flags)
+ const unsigned char *old_sha1,
+ int flags, int *type_p)
{
if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
return NULL;
- return lock_ref_sha1_basic(refname, old_sha1, flags, NULL);
+ return lock_ref_sha1_basic(refname, old_sha1, flags, type_p);
}
/*
return 0;
}
-static int repack_without_ref(const char *refname)
+static int repack_without_refs(const char **refnames, int n)
{
struct ref_dir *packed;
struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
struct string_list_item *ref_to_delete;
+ int i, removed = 0;
+
+ /* Look for a packed ref */
+ for (i = 0; i < n; i++)
+ if (get_packed_ref(refnames[i]))
+ break;
- if (!get_packed_ref(refname))
- return 0; /* refname does not exist in packed refs */
+ /* Avoid locking if we have nothing to do */
+ if (i == n)
+ return 0; /* no refname exists in packed refs */
if (lock_packed_refs(0)) {
unable_to_lock_error(git_path("packed-refs"), errno);
- return error("cannot delete '%s' from packed refs", refname);
+ return error("cannot delete '%s' from packed refs", refnames[i]);
}
packed = get_packed_refs(&ref_cache);
- /* Remove refname from the cache: */
- if (remove_entry(packed, refname) == -1) {
+ /* Remove refnames from the cache */
+ for (i = 0; i < n; i++)
+ if (remove_entry(packed, refnames[i]) != -1)
+ removed = 1;
+ if (!removed) {
/*
- * The packed entry disappeared while we were
+ * All packed entries disappeared while we were
* acquiring the lock.
*/
rollback_packed_refs();
return 0;
}
- /* Remove any other accumulated cruft: */
+ /* Remove any other accumulated cruft */
do_for_each_entry_in_dir(packed, 0, curate_packed_ref_fn, &refs_to_delete);
for_each_string_list_item(ref_to_delete, &refs_to_delete) {
if (remove_entry(packed, ref_to_delete->string) == -1)
die("internal error");
}
- /* Write what remains: */
+ /* Write what remains */
return commit_packed_refs();
}
-int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
+static int repack_without_ref(const char *refname)
{
- struct ref_lock *lock;
- int err, i = 0, ret = 0, flag = 0;
+ return repack_without_refs(&refname, 1);
+}
- lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
- if (!lock)
- return 1;
+static int delete_ref_loose(struct ref_lock *lock, int flag)
+{
if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
/* loose */
- i = strlen(lock->lk->filename) - 5; /* .lock */
+ int err, 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;
-
lock->lk->filename[i] = '.';
+ if (err && errno != ENOENT)
+ return 1;
}
+ return 0;
+}
+
+int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
+{
+ struct ref_lock *lock;
+ int ret = 0, flag = 0;
+
+ lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
+ if (!lock)
+ return 1;
+ ret |= delete_ref_loose(lock, flag);
+
/* removing the loose one could have resurrected an earlier
* packed one. Also, if it was not loose we need to repack
* without it.
return retval;
}
-int update_ref(const char *action, const char *refname,
- const unsigned char *sha1, const unsigned char *oldval,
- int flags, enum action_on_err onerr)
+static struct ref_lock *update_ref_lock(const char *refname,
+ const unsigned char *oldval,
+ int flags, int *type_p,
+ enum action_on_err onerr)
{
- static struct ref_lock *lock;
- lock = lock_any_ref_for_update(refname, oldval, flags);
+ struct ref_lock *lock;
+ lock = lock_any_ref_for_update(refname, oldval, flags, type_p);
if (!lock) {
const char *str = "Cannot lock the ref '%s'.";
switch (onerr) {
case DIE_ON_ERR: die(str, refname); break;
case QUIET_ON_ERR: break;
}
- return 1;
}
+ return lock;
+}
+
+static int update_ref_write(const char *action, const char *refname,
+ const unsigned char *sha1, struct ref_lock *lock,
+ enum action_on_err onerr)
+{
if (write_ref_sha1(lock, sha1, action) < 0) {
const char *str = "Cannot update the ref '%s'.";
switch (onerr) {
return 0;
}
-struct ref *find_ref_by_name(const struct ref *list, const char *name)
+int update_ref(const char *action, const char *refname,
+ const unsigned char *sha1, const unsigned char *oldval,
+ int flags, enum action_on_err onerr)
{
- for ( ; list; list = list->next)
- if (!strcmp(list->name, name))
- return (struct ref *)list;
- return NULL;
+ struct ref_lock *lock;
+ lock = update_ref_lock(refname, oldval, flags, NULL, onerr);
+ if (!lock)
+ return 1;
+ return update_ref_write(action, refname, sha1, lock, onerr);
+}
+
+static int ref_update_compare(const void *r1, const void *r2)
+{
+ const struct ref_update * const *u1 = r1;
+ const struct ref_update * const *u2 = r2;
+ return strcmp((*u1)->ref_name, (*u2)->ref_name);
+}
+
+static int ref_update_reject_duplicates(struct ref_update **updates, int n,
+ enum action_on_err onerr)
+{
+ int i;
+ for (i = 1; i < n; i++)
+ if (!strcmp(updates[i - 1]->ref_name, updates[i]->ref_name)) {
+ const char *str =
+ "Multiple updates for ref '%s' not allowed.";
+ switch (onerr) {
+ case MSG_ON_ERR:
+ error(str, updates[i]->ref_name); break;
+ case DIE_ON_ERR:
+ die(str, updates[i]->ref_name); break;
+ case QUIET_ON_ERR:
+ break;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int update_refs(const char *action, const struct ref_update **updates_orig,
+ int n, enum action_on_err onerr)
+{
+ int ret = 0, delnum = 0, i;
+ struct ref_update **updates;
+ int *types;
+ struct ref_lock **locks;
+ const char **delnames;
+
+ if (!updates_orig || !n)
+ return 0;
+
+ /* Allocate work space */
+ updates = xmalloc(sizeof(*updates) * n);
+ types = xmalloc(sizeof(*types) * n);
+ locks = xcalloc(n, sizeof(*locks));
+ delnames = xmalloc(sizeof(*delnames) * n);
+
+ /* Copy, sort, and reject duplicate refs */
+ memcpy(updates, updates_orig, sizeof(*updates) * n);
+ qsort(updates, n, sizeof(*updates), ref_update_compare);
+ ret = ref_update_reject_duplicates(updates, n, onerr);
+ if (ret)
+ goto cleanup;
+
+ /* Acquire all locks while verifying old values */
+ for (i = 0; i < n; i++) {
+ locks[i] = update_ref_lock(updates[i]->ref_name,
+ (updates[i]->have_old ?
+ updates[i]->old_sha1 : NULL),
+ updates[i]->flags,
+ &types[i], onerr);
+ if (!locks[i]) {
+ ret = 1;
+ goto cleanup;
+ }
+ }
+
+ /* Perform updates first so live commits remain referenced */
+ for (i = 0; i < n; i++)
+ if (!is_null_sha1(updates[i]->new_sha1)) {
+ ret = update_ref_write(action,
+ updates[i]->ref_name,
+ updates[i]->new_sha1,
+ locks[i], onerr);
+ locks[i] = NULL; /* freed by update_ref_write */
+ if (ret)
+ goto cleanup;
+ }
+
+ /* Perform deletes now that updates are safely completed */
+ for (i = 0; i < n; i++)
+ if (locks[i]) {
+ delnames[delnum++] = locks[i]->ref_name;
+ ret |= delete_ref_loose(locks[i], types[i]);
+ }
+ ret |= repack_without_refs(delnames, delnum);
+ for (i = 0; i < delnum; i++)
+ unlink_or_warn(git_path("logs/%s", delnames[i]));
+ clear_loose_ref_cache(&ref_cache);
+
+cleanup:
+ for (i = 0; i < n; i++)
+ if (locks[i])
+ unlock_ref(locks[i]);
+ free(updates);
+ free(types);
+ free(locks);
+ free(delnames);
+ return ret;
}
/*
size_t total_len = 0;
/* the rule list is NULL terminated, count them first */
- for (; ref_rev_parse_rules[nr_rules]; nr_rules++)
+ for (nr_rules = 0; ref_rev_parse_rules[nr_rules]; nr_rules++)
/* no +1 because strlen("%s") < strlen("%.*s") */
total_len += strlen(ref_rev_parse_rules[nr_rules]);
int force_write;
};
+/**
+ * Information needed for a single ref update. Set new_sha1 to the
+ * new value or to zero to delete the ref. To check the old value
+ * while locking the ref, set have_old to 1 and set old_sha1 to the
+ * value or to zero to ensure the ref does not exist before update.
+ */
+struct ref_update {
+ const char *ref_name;
+ unsigned char new_sha1[20];
+ unsigned char old_sha1[20];
+ int flags; /* REF_NODEREF? */
+ int have_old; /* 1 if old_sha1 is valid, 0 otherwise */
+};
+
/*
* Bit values set in the flags argument passed to each_ref_fn():
*/
#define REF_NODEREF 0x01
extern struct ref_lock *lock_any_ref_for_update(const char *refname,
const unsigned char *old_sha1,
- int flags);
+ int flags, int *type_p);
/** Close the file descriptor owned by a lock and return the status */
extern int close_ref(struct ref_lock *lock);
const unsigned char *sha1, const unsigned char *oldval,
int flags, enum action_on_err onerr);
+/**
+ * Lock all refs and then perform all modifications.
+ */
+int update_refs(const char *action, const struct ref_update **updates,
+ int n, enum action_on_err onerr);
+
extern int parse_hide_refs_config(const char *var, const char *value, const char *);
extern int ref_is_hidden(const char *);
#include "exec_cmd.h"
#include "run-command.h"
#include "pkt-line.h"
+#include "string-list.h"
#include "sideband.h"
#include "argv-array.h"
+#include "credential.h"
static struct remote *remote;
-static const char *url; /* always ends with a trailing slash */
+/* always ends with a trailing slash */
+static struct strbuf url = STRBUF_INIT;
struct options {
int verbosity;
unsigned long depth;
unsigned progress : 1,
+ check_self_contained_and_connected : 1,
followtags : 1,
dry_run : 1,
thin : 1;
};
static struct options options;
+static struct string_list cas_options = STRING_LIST_INIT_DUP;
static int set_option(const char *name, const char *value)
{
return -1;
return 0;
}
+ else if (!strcmp(name, "check-connectivity")) {
+ if (!strcmp(value, "true"))
+ options.check_self_contained_and_connected = 1;
+ else if (!strcmp(value, "false"))
+ options.check_self_contained_and_connected = 0;
+ else
+ return -1;
+ return 0;
+ }
+ else if (!strcmp(name, "cas")) {
+ struct strbuf val = STRBUF_INIT;
+ strbuf_addf(&val, "--" CAS_OPT_NAME "=%s", value);
+ string_list_append(&cas_options, val.buf);
+ strbuf_release(&val);
+ return 0;
+ }
else {
return 1 /* unsupported */;
}
mid = &data[i];
if (data[i] == '\n') {
if (mid - start != 40)
- die("%sinfo/refs not valid: is this a git repository?", url);
+ die("%sinfo/refs not valid: is this a git repository?",
+ url.buf);
data[i] = 0;
ref_name = mid + 1;
ref = xmalloc(sizeof(struct ref) +
}
ref = alloc_ref("HEAD");
- if (!http_fetch_ref(url, ref) &&
+ if (!http_fetch_ref(url.buf, ref) &&
!resolve_remote_symref(ref, refs)) {
ref->next = refs;
refs = ref;
struct strbuf exp = STRBUF_INIT;
struct strbuf type = STRBUF_INIT;
struct strbuf buffer = STRBUF_INIT;
+ struct strbuf refs_url = STRBUF_INIT;
+ struct strbuf effective_url = STRBUF_INIT;
struct discovery *last = last_discovery;
- char *refs_url;
int http_ret, maybe_smart = 0;
+ struct http_get_options options;
if (last && !strcmp(service, last->service))
return last;
free_discovery(last);
- strbuf_addf(&buffer, "%sinfo/refs", url);
- if ((!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) &&
+ strbuf_addf(&refs_url, "%sinfo/refs", url.buf);
+ if ((!prefixcmp(url.buf, "http://") || !prefixcmp(url.buf, "https://")) &&
git_env_bool("GIT_SMART_HTTP", 1)) {
maybe_smart = 1;
- if (!strchr(url, '?'))
- strbuf_addch(&buffer, '?');
+ if (!strchr(url.buf, '?'))
+ strbuf_addch(&refs_url, '?');
else
- strbuf_addch(&buffer, '&');
- strbuf_addf(&buffer, "service=%s", service);
+ strbuf_addch(&refs_url, '&');
+ strbuf_addf(&refs_url, "service=%s", service);
}
- refs_url = strbuf_detach(&buffer, NULL);
- http_ret = http_get_strbuf(refs_url, &type, &buffer,
- HTTP_NO_CACHE | HTTP_KEEP_ERROR);
+ memset(&options, 0, sizeof(options));
+ options.content_type = &type;
+ options.effective_url = &effective_url;
+ options.base_url = &url;
+ options.no_cache = 1;
+ options.keep_error = 1;
+
+ http_ret = http_get_strbuf(refs_url.buf, &buffer, &options);
switch (http_ret) {
case HTTP_OK:
break;
case HTTP_MISSING_TARGET:
show_http_message(&type, &buffer);
- die("repository '%s' not found", url);
+ die("repository '%s' not found", url.buf);
case HTTP_NOAUTH:
show_http_message(&type, &buffer);
- die("Authentication failed for '%s'", url);
+ die("Authentication failed for '%s'", url.buf);
default:
show_http_message(&type, &buffer);
- die("unable to access '%s': %s", url, curl_errorstr);
+ die("unable to access '%s': %s", url.buf, curl_errorstr);
}
last= xcalloc(1, sizeof(*last_discovery));
else
last->refs = parse_info_refs(last);
- free(refs_url);
+ strbuf_release(&refs_url);
strbuf_release(&exp);
strbuf_release(&type);
+ strbuf_release(&effective_url);
strbuf_release(&buffer);
last_discovery = last;
return last;
if (large_request) {
do {
err = probe_rpc(rpc);
+ if (err == HTTP_REAUTH)
+ credential_fill(&http_auth);
} while (err == HTTP_REAUTH);
if (err != HTTP_OK)
return -1;
curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
err = run_slot(slot);
- if (err == HTTP_REAUTH && !large_request)
+ if (err == HTTP_REAUTH && !large_request) {
+ credential_fill(&http_auth);
goto retry;
+ }
if (err != HTTP_OK)
err = -1;
rpc->out = client.out;
strbuf_init(&rpc->result, 0);
- strbuf_addf(&buf, "%s%s", url, svc);
+ strbuf_addf(&buf, "%s%s", url.buf, svc);
rpc->service_url = strbuf_detach(&buf, NULL);
strbuf_addf(&buf, "Content-Type: application/x-%s-request", svc);
for (i = 0; i < nr_heads; i++)
targets[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1));
- walker = get_http_walker(url);
+ walker = get_http_walker(url.buf);
walker->get_all = 1;
walker->get_tree = 1;
walker->get_history = 1;
struct strbuf preamble = STRBUF_INIT;
char *depth_arg = NULL;
int argc = 0, i, err;
- const char *argv[15];
+ const char *argv[16];
argv[argc++] = "fetch-pack";
argv[argc++] = "--stateless-rpc";
argv[argc++] = "-v";
argv[argc++] = "-v";
}
+ if (options.check_self_contained_and_connected)
+ argv[argc++] = "--check-self-contained-and-connected";
if (!options.progress)
argv[argc++] = "--no-progress";
if (options.depth) {
depth_arg = strbuf_detach(&buf, NULL);
argv[argc++] = depth_arg;
}
- argv[argc++] = url;
+ argv[argc++] = url.buf;
argv[argc++] = NULL;
for (i = 0; i < nr_heads; i++) {
argv[argc++] = "--dry-run";
if (options.verbosity > 1)
argv[argc++] = "--verbose";
- argv[argc++] = url;
+ argv[argc++] = url.buf;
for (i = 0; i < nr_spec; i++)
argv[argc++] = specs[i];
argv[argc++] = NULL;
struct rpc_state rpc;
int i, err;
struct argv_array args;
+ struct string_list_item *cas_option;
argv_array_init(&args);
argv_array_pushl(&args, "send-pack", "--stateless-rpc", "--helper-status",
else if (options.verbosity > 1)
argv_array_push(&args, "--verbose");
argv_array_push(&args, options.progress ? "--progress" : "--no-progress");
- argv_array_push(&args, url);
+ for_each_string_list_item(cas_option, &cas_options)
+ argv_array_push(&args, cas_option->string);
+ argv_array_push(&args, url.buf);
for (i = 0; i < nr_spec; i++)
argv_array_push(&args, specs[i]);
remote = remote_get(argv[1]);
if (argc > 2) {
- end_url_with_slash(&buf, argv[2]);
+ end_url_with_slash(&url, argv[2]);
} else {
- end_url_with_slash(&buf, remote->url[0]);
+ end_url_with_slash(&url, remote->url[0]);
}
- url = strbuf_detach(&buf, NULL);
-
- http_init(remote, url, 0);
+ http_init(remote, url.buf, 0);
do {
if (strbuf_getline(&buf, stdin, '\n') == EOF) {
printf("fetch\n");
printf("option\n");
printf("push\n");
+ printf("check-connectivity\n");
printf("\n");
fflush(stdout);
} else {
}
ret = xcalloc(1, sizeof(struct remote));
+ ret->prune = -1; /* unspecified */
ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
remotes[remotes_nr++] = ret;
if (len)
remote->skip_default_update = git_config_bool(key, value);
else if (!strcmp(subkey, ".skipfetchall"))
remote->skip_default_update = git_config_bool(key, value);
+ else if (!strcmp(subkey, ".prune"))
+ remote->prune = git_config_bool(key, value);
else if (!strcmp(subkey, ".url")) {
const char *v;
if (git_config_string(&v, key, value))
int flag;
if (default_remote_name) /* did this already */
return;
- default_remote_name = xstrdup("origin");
+ default_remote_name = "origin";
current_branch = NULL;
head_ref = resolve_ref_unsafe("HEAD", sha1, 0, &flag);
if (head_ref && (flag & REF_ISSYMREF) &&
free(sent_tips.tip);
}
+struct ref *find_ref_by_name(const struct ref *list, const char *name)
+{
+ for ( ; list; list = list->next)
+ if (!strcmp(list->name, name))
+ return (struct ref *)list;
+ return NULL;
+}
+
static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)
{
for ( ; ref; ref = ref->next)
}
void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
- int force_update)
+ int force_update)
{
struct ref *ref;
for (ref = remote_refs; ref; ref = ref->next) {
int force_ref_update = ref->force || force_update;
+ int reject_reason = 0;
if (ref->peer_ref)
hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
}
/*
+ * Bypass the usual "must fast-forward" check but
+ * replace it with a weaker "the old value must be
+ * this value we observed". If the remote ref has
+ * moved and is now different from what we expect,
+ * reject any push.
+ *
+ * It also is an error if the user told us to check
+ * with the remote-tracking branch to find the value
+ * to expect, but we did not have such a tracking
+ * branch.
+ */
+ if (ref->expect_old_sha1) {
+ if (ref->expect_old_no_trackback ||
+ hashcmp(ref->old_sha1, ref->old_sha1_expect))
+ reject_reason = REF_STATUS_REJECT_STALE;
+ }
+
+ /*
+ * The usual "must fast-forward" rules.
+ *
* Decide whether an individual refspec A:B can be
* pushed. The push will succeed if any of the
* following are true:
* passing the --force argument
*/
- if (!ref->deletion && !is_null_sha1(ref->old_sha1)) {
- int why = 0; /* why would this push require --force? */
-
+ else if (!ref->deletion && !is_null_sha1(ref->old_sha1)) {
if (!prefixcmp(ref->name, "refs/tags/"))
- why = REF_STATUS_REJECT_ALREADY_EXISTS;
+ reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
else if (!has_sha1_file(ref->old_sha1))
- why = REF_STATUS_REJECT_FETCH_FIRST;
+ reject_reason = REF_STATUS_REJECT_FETCH_FIRST;
else if (!lookup_commit_reference_gently(ref->old_sha1, 1) ||
!lookup_commit_reference_gently(ref->new_sha1, 1))
- why = REF_STATUS_REJECT_NEEDS_FORCE;
+ reject_reason = REF_STATUS_REJECT_NEEDS_FORCE;
else if (!ref_newer(ref->new_sha1, ref->old_sha1))
- why = REF_STATUS_REJECT_NONFASTFORWARD;
-
- if (!force_ref_update)
- ref->status = why;
- else if (why)
- ref->forced_update = 1;
+ reject_reason = REF_STATUS_REJECT_NONFASTFORWARD;
}
+
+ /*
+ * "--force" will defeat any rejection implemented
+ * by the rules above.
+ */
+ if (!force_ref_update)
+ ref->status = reject_reason;
+ else if (reject_reason)
+ ref->forced_update = 1;
}
}
}
/*
- * Return true if there is anything to report, otherwise false.
+ * Compare a branch with its upstream, and save their differences (number
+ * of commits) in *num_ours and *num_theirs.
+ *
+ * Return 0 if branch has no upstream (no base), -1 if upstream is missing
+ * (with "gone" base), otherwise 1 (with base).
*/
int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
{
const char *rev_argv[10], *base;
int rev_argc;
- /*
- * Nothing to report unless we are marked to build on top of
- * somebody else.
- */
+ /* Cannot stat unless we are marked to build on top of somebody else. */
if (!branch ||
!branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
return 0;
- /*
- * If what we used to build on no longer exists, there is
- * nothing to report.
- */
+ /* Cannot stat if what we used to build on no longer exists */
base = branch->merge[0]->dst;
if (read_ref(base, sha1))
- return 0;
+ return -1;
theirs = lookup_commit_reference(sha1);
if (!theirs)
- return 0;
+ return -1;
if (read_ref(branch->refname, sha1))
- return 0;
+ return -1;
ours = lookup_commit_reference(sha1);
if (!ours)
- return 0;
+ return -1;
/* are we the same? */
- if (theirs == ours)
- return 0;
+ if (theirs == ours) {
+ *num_theirs = *num_ours = 0;
+ return 1;
+ }
/* Run "rev-list --left-right ours...theirs" internally... */
rev_argc = 0;
*/
int format_tracking_info(struct branch *branch, struct strbuf *sb)
{
- int num_ours, num_theirs;
+ int ours, theirs;
const char *base;
+ int upstream_is_gone = 0;
- if (!stat_tracking_info(branch, &num_ours, &num_theirs))
+ switch (stat_tracking_info(branch, &ours, &theirs)) {
+ case 0:
+ /* no base */
return 0;
+ case -1:
+ /* with "gone" base */
+ upstream_is_gone = 1;
+ break;
+ default:
+ /* with base */
+ break;
+ }
base = branch->merge[0]->dst;
base = shorten_unambiguous_ref(base, 0);
- if (!num_theirs) {
+ if (upstream_is_gone) {
+ strbuf_addf(sb,
+ _("Your branch is based on '%s', but the upstream is gone.\n"),
+ base);
+ if (advice_status_hints)
+ strbuf_addf(sb,
+ _(" (use \"git branch --unset-upstream\" to fixup)\n"));
+ } else if (!ours && !theirs) {
+ strbuf_addf(sb,
+ _("Your branch is up-to-date with '%s'.\n"),
+ base);
+ } else if (!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);
+ ours),
+ base, ours);
if (advice_status_hints)
strbuf_addf(sb,
_(" (use \"git push\" to publish your local commits)\n"));
- } else if (!num_ours) {
+ } else if (!ours) {
strbuf_addf(sb,
Q_("Your branch is behind '%s' by %d commit, "
"and can be fast-forwarded.\n",
"Your branch is behind '%s' by %d commits, "
"and can be fast-forwarded.\n",
- num_theirs),
- base, num_theirs);
+ theirs),
+ base, theirs);
if (advice_status_hints)
strbuf_addf(sb,
_(" (use \"git pull\" to update your local branch)\n"));
"Your branch and '%s' have diverged,\n"
"and have %d and %d different commits each, "
"respectively.\n",
- num_theirs),
- base, num_ours, num_theirs);
+ theirs),
+ base, ours, theirs);
if (advice_status_hints)
strbuf_addf(sb,
_(" (use \"git pull\" to merge the remote branch into yours)\n"));
string_list_clear(&ref_names, 0);
return stale_refs;
}
+
+/*
+ * Compare-and-swap
+ */
+void clear_cas_option(struct push_cas_option *cas)
+{
+ int i;
+
+ for (i = 0; i < cas->nr; i++)
+ free(cas->entry[i].refname);
+ free(cas->entry);
+ memset(cas, 0, sizeof(*cas));
+}
+
+static struct push_cas *add_cas_entry(struct push_cas_option *cas,
+ const char *refname,
+ size_t refnamelen)
+{
+ struct push_cas *entry;
+ ALLOC_GROW(cas->entry, cas->nr + 1, cas->alloc);
+ entry = &cas->entry[cas->nr++];
+ memset(entry, 0, sizeof(*entry));
+ entry->refname = xmemdupz(refname, refnamelen);
+ return entry;
+}
+
+int parse_push_cas_option(struct push_cas_option *cas, const char *arg, int unset)
+{
+ const char *colon;
+ struct push_cas *entry;
+
+ if (unset) {
+ /* "--no-<option>" */
+ clear_cas_option(cas);
+ return 0;
+ }
+
+ if (!arg) {
+ /* just "--<option>" */
+ cas->use_tracking_for_rest = 1;
+ return 0;
+ }
+
+ /* "--<option>=refname" or "--<option>=refname:value" */
+ colon = strchrnul(arg, ':');
+ entry = add_cas_entry(cas, arg, colon - arg);
+ if (!*colon)
+ entry->use_tracking = 1;
+ else if (get_sha1(colon + 1, entry->expect))
+ return error("cannot parse expected object name '%s'", colon + 1);
+ return 0;
+}
+
+int parseopt_push_cas_option(const struct option *opt, const char *arg, int unset)
+{
+ return parse_push_cas_option(opt->value, arg, unset);
+}
+
+int is_empty_cas(const struct push_cas_option *cas)
+{
+ return !cas->use_tracking_for_rest && !cas->nr;
+}
+
+/*
+ * Look at remote.fetch refspec and see if we have a remote
+ * tracking branch for the refname there. Fill its current
+ * value in sha1[].
+ * If we cannot do so, return negative to signal an error.
+ */
+static int remote_tracking(struct remote *remote, const char *refname,
+ unsigned char sha1[20])
+{
+ char *dst;
+
+ dst = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname);
+ if (!dst)
+ return -1; /* no tracking ref for refname at remote */
+ if (read_ref(dst, sha1))
+ return -1; /* we know what the tracking ref is but we cannot read it */
+ return 0;
+}
+
+static void apply_cas(struct push_cas_option *cas,
+ struct remote *remote,
+ struct ref *ref)
+{
+ int i;
+
+ /* Find an explicit --<option>=<name>[:<value>] entry */
+ for (i = 0; i < cas->nr; i++) {
+ struct push_cas *entry = &cas->entry[i];
+ if (!refname_match(entry->refname, ref->name, ref_rev_parse_rules))
+ continue;
+ ref->expect_old_sha1 = 1;
+ if (!entry->use_tracking)
+ hashcpy(ref->old_sha1_expect, cas->entry[i].expect);
+ else if (remote_tracking(remote, ref->name, ref->old_sha1_expect))
+ ref->expect_old_no_trackback = 1;
+ return;
+ }
+
+ /* Are we using "--<option>" to cover all? */
+ if (!cas->use_tracking_for_rest)
+ return;
+
+ ref->expect_old_sha1 = 1;
+ if (remote_tracking(remote, ref->name, ref->old_sha1_expect))
+ ref->expect_old_no_trackback = 1;
+}
+
+void apply_push_cas(struct push_cas_option *cas,
+ struct remote *remote,
+ struct ref *remote_refs)
+{
+ struct ref *ref;
+ for (ref = remote_refs; ref; ref = ref->next)
+ apply_cas(cas, remote, ref);
+}
#ifndef REMOTE_H
#define REMOTE_H
+#include "parse-options.h"
+
enum {
REMOTE_CONFIG,
REMOTE_REMOTES,
int fetch_tags;
int skip_default_update;
int mirror;
+ int prune;
const char *receivepack;
const char *uploadpack;
extern const struct refspec *tag_refspec;
+struct ref {
+ struct ref *next;
+ unsigned char old_sha1[20];
+ unsigned char new_sha1[20];
+ unsigned char old_sha1_expect[20]; /* used by expect-old */
+ char *symref;
+ unsigned int
+ force:1,
+ forced_update:1,
+ expect_old_sha1:1,
+ expect_old_no_trackback:1,
+ deletion:1,
+ matched:1;
+
+ /*
+ * Order is important here, as we write to FETCH_HEAD
+ * in numeric order. And the default NOT_FOR_MERGE
+ * should be 0, so that xcalloc'd structures get it
+ * by default.
+ */
+ enum {
+ FETCH_HEAD_MERGE = -1,
+ FETCH_HEAD_NOT_FOR_MERGE = 0,
+ FETCH_HEAD_IGNORE = 1
+ } fetch_head_status;
+
+ enum {
+ REF_STATUS_NONE = 0,
+ REF_STATUS_OK,
+ REF_STATUS_REJECT_NONFASTFORWARD,
+ REF_STATUS_REJECT_ALREADY_EXISTS,
+ REF_STATUS_REJECT_NODELETE,
+ REF_STATUS_REJECT_FETCH_FIRST,
+ REF_STATUS_REJECT_NEEDS_FORCE,
+ REF_STATUS_REJECT_STALE,
+ REF_STATUS_UPTODATE,
+ REF_STATUS_REMOTE_REJECT,
+ REF_STATUS_EXPECTING_REPORT
+ } status;
+ char *remote_status;
+ struct ref *peer_ref; /* when renaming */
+ char name[FLEX_ARRAY]; /* more */
+};
+
+#define REF_NORMAL (1u << 0)
+#define REF_HEADS (1u << 1)
+#define REF_TAGS (1u << 2)
+
+extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
+
struct ref *alloc_ref(const char *name);
struct ref *copy_ref(const struct ref *ref);
struct ref *copy_ref_list(const struct ref *ref);
*/
void free_refs(struct ref *ref);
+struct extra_have_objects {
+ int nr, alloc;
+ unsigned char (*array)[20];
+};
+extern struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
+ struct ref **list, unsigned int flags,
+ struct extra_have_objects *);
+
int resolve_remote_symref(struct ref *ref, struct ref *list);
int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1);
/* Return refs which no longer exist on remote */
struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map);
+/*
+ * Compare-and-swap
+ */
+#define CAS_OPT_NAME "force-with-lease"
+
+struct push_cas_option {
+ unsigned use_tracking_for_rest:1;
+ struct push_cas {
+ unsigned char expect[20];
+ unsigned use_tracking:1;
+ char *refname;
+ } *entry;
+ int nr;
+ int alloc;
+};
+
+extern int parseopt_push_cas_option(const struct option *, const char *arg, int unset);
+extern int parse_push_cas_option(struct push_cas_option *, const char *arg, int unset);
+extern void clear_cas_option(struct push_cas_option *);
+
+extern int is_empty_cas(const struct push_cas_option *);
+void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
+
#endif
#include "resolve-undo.h"
#include "ll-merge.h"
#include "attr.h"
+#include "pathspec.h"
#define RESOLVED 0
#define PUNTED 1
return 0;
}
-int rerere_forget(const char **pathspec)
+int rerere_forget(struct pathspec *pathspec)
{
int i, fd;
struct string_list conflict = STRING_LIST_INIT_DUP;
find_conflict(&conflict);
for (i = 0; i < conflict.nr; i++) {
struct string_list_item *it = &conflict.items[i];
- if (!match_pathspec(pathspec, it->string, strlen(it->string),
- 0, NULL))
+ if (!match_pathspec_depth(pathspec, it->string, strlen(it->string),
+ 0, NULL))
continue;
rerere_forget_one_path(it->string, &merge_rr);
}
#include "string-list.h"
+struct pathspec;
+
#define RERERE_AUTOUPDATE 01
#define RERERE_NOAUTOUPDATE 02
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 rerere_forget(const char **);
+extern int rerere_forget(struct pathspec *);
extern int rerere_remaining(struct string_list *);
extern void rerere_clear(struct string_list *);
extern void rerere_gc(struct string_list *);
}
}
-void unmerge_index(struct index_state *istate, const char **pathspec)
+void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
{
int i;
for (i = 0; i < istate->cache_nr; i++) {
const struct cache_entry *ce = istate->cache[i];
- if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL))
+ if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
continue;
i = unmerge_index_entry_at(istate, i);
}
extern struct string_list *resolve_undo_read(const char *, unsigned long);
extern void resolve_undo_clear_index(struct index_state *);
extern int unmerge_index_entry_at(struct index_state *, int);
-extern void unmerge_index(struct index_state *, const char **);
+extern void unmerge_index(struct index_state *, const struct pathspec *);
extern void unmerge_marked_index(struct index_state *);
#endif
#include "string-list.h"
#include "line-log.h"
#include "mailmap.h"
+#include "commit-slab.h"
volatile show_early_output_fn_t show_early_output;
* We don't care about the tree any more
* after it has been marked uninteresting.
*/
- free(tree->buffer);
- tree->buffer = NULL;
+ free_tree_buffer(tree);
}
void mark_parents_uninteresting(struct commit *commit)
revs->no_walk = 0;
if (revs->reflog_info && obj->type == OBJ_COMMIT) {
struct strbuf buf = STRBUF_INIT;
- int len = interpret_branch_name(name, &buf);
+ int len = interpret_branch_name(name, 0, &buf);
int st;
if (0 < len && name[len] && buf.len)
i++;
}
free_pathspec(&revs->prune_data);
- init_pathspec(&revs->prune_data, prune);
+ parse_pathspec(&revs->prune_data, PATHSPEC_ALL_MAGIC,
+ PATHSPEC_PREFER_FULL, "", prune);
revs->limited = 1;
}
}
if (!get_sha1_committish(this, from_sha1) &&
!get_sha1_committish(next, sha1)) {
- struct commit *a, *b;
- struct commit_list *exclude;
-
- a = lookup_commit_reference(from_sha1);
- b = lookup_commit_reference(sha1);
- if (!a || !b) {
- if (revs->ignore_missing)
- return 0;
- die(symmetric ?
- "Invalid symmetric difference expression %s...%s" :
- "Invalid revision range %s..%s",
- arg, next);
- }
+ struct object *a_obj, *b_obj;
if (!cant_be_filename) {
*dotdot = '.';
verify_non_filename(revs->prefix, arg);
}
- if (symmetric) {
+ a_obj = parse_object(from_sha1);
+ b_obj = parse_object(sha1);
+ if (!a_obj || !b_obj) {
+ missing:
+ if (revs->ignore_missing)
+ return 0;
+ die(symmetric
+ ? "Invalid symmetric difference expression %s"
+ : "Invalid revision range %s", arg);
+ }
+
+ if (!symmetric) {
+ /* just A..B */
+ a_flags = flags_exclude;
+ } else {
+ /* A...B -- find merge bases between the two */
+ struct commit *a, *b;
+ struct commit_list *exclude;
+
+ a = (a_obj->type == OBJ_COMMIT
+ ? (struct commit *)a_obj
+ : lookup_commit_reference(a_obj->sha1));
+ b = (b_obj->type == OBJ_COMMIT
+ ? (struct commit *)b_obj
+ : lookup_commit_reference(b_obj->sha1));
+ if (!a || !b)
+ goto missing;
exclude = get_merge_bases(a, b, 1);
add_rev_cmdline_list(revs, exclude,
REV_CMD_MERGE_BASE,
add_pending_commit_list(revs, exclude,
flags_exclude);
free_commit_list(exclude);
+
a_flags = flags | SYMMETRIC_LEFT;
- } else
- a_flags = flags_exclude;
- a->object.flags |= a_flags;
- b->object.flags |= flags;
- add_rev_cmdline(revs, &a->object, this,
+ }
+
+ a_obj->flags |= a_flags;
+ b_obj->flags |= flags;
+ add_rev_cmdline(revs, a_obj, this,
REV_CMD_LEFT, a_flags);
- add_rev_cmdline(revs, &b->object, next,
+ add_rev_cmdline(revs, b_obj, next,
REV_CMD_RIGHT, flags);
- add_pending_object(revs, &a->object, this);
- add_pending_object(revs, &b->object, next);
+ add_pending_object(revs, a_obj, this);
+ add_pending_object(revs, b_obj, next);
return 0;
}
*dotdot = '.';
*/
ALLOC_GROW(prune_data.path, prune_data.nr+1, prune_data.alloc);
prune_data.path[prune_data.nr++] = NULL;
- init_pathspec(&revs->prune_data,
- get_pathspec(revs->prefix, prune_data.path));
+ parse_pathspec(&revs->prune_data, 0, 0,
+ revs->prefix, prune_data.path);
}
if (revs->def == NULL)
revs->limited = 1;
if (revs->prune_data.nr) {
- diff_tree_setup_paths(revs->prune_data.raw, &revs->pruning);
+ copy_pathspec(&revs->pruning.pathspec, &revs->prune_data);
/* Can't prune commits with rename following: the paths change.. */
if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
revs->prune = 1;
if (!revs->full_diff)
- diff_tree_setup_paths(revs->prune_data.raw, &revs->diffopt);
+ copy_pathspec(&revs->diffopt.pathspec,
+ &revs->prune_data);
}
if (revs->combine_merges)
revs->ignore_merges = 0;
return retval;
}
-static inline int want_ancestry(struct rev_info *revs)
+static inline int want_ancestry(const struct rev_info *revs)
{
return (revs->rewrite_parents || revs->children.name);
}
if (action == commit_show &&
!revs->show_all &&
revs->prune && revs->dense && want_ancestry(revs)) {
+ /*
+ * --full-diff on simplified parents is no good: it
+ * will show spurious changes from the commits that
+ * were elided. So we save the parents on the side
+ * when --full-diff is in effect.
+ */
+ if (revs->full_diff)
+ save_parents(revs, commit);
if (rewrite_parents(revs, commit, rewrite_one) < 0)
return commit_error;
}
free(entry);
if (revs->reflog_info) {
+ save_parents(revs, commit);
fake_reflog_parent(revs->reflog_info, commit);
commit->object.flags &= ~(ADDED | SEEN | SHOWN);
}
c = get_revision_internal(revs);
if (c && revs->graph)
graph_update(revs->graph, c);
+ if (!c)
+ free_saved_parents(revs);
return c;
}
fputs(mark, stdout);
putchar(' ');
}
+
+define_commit_slab(saved_parents, struct commit_list *);
+
+#define EMPTY_PARENT_LIST ((struct commit_list *)-1)
+
+void save_parents(struct rev_info *revs, struct commit *commit)
+{
+ struct commit_list **pp;
+
+ if (!revs->saved_parents_slab) {
+ revs->saved_parents_slab = xmalloc(sizeof(struct saved_parents));
+ init_saved_parents(revs->saved_parents_slab);
+ }
+
+ pp = saved_parents_at(revs->saved_parents_slab, commit);
+
+ /*
+ * When walking with reflogs, we may visit the same commit
+ * several times: once for each appearance in the reflog.
+ *
+ * In this case, save_parents() will be called multiple times.
+ * We want to keep only the first set of parents. We need to
+ * store a sentinel value for an empty (i.e., NULL) parent
+ * list to distinguish it from a not-yet-saved list, however.
+ */
+ if (*pp)
+ return;
+ if (commit->parents)
+ *pp = copy_commit_list(commit->parents);
+ else
+ *pp = EMPTY_PARENT_LIST;
+}
+
+struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit)
+{
+ struct commit_list *parents;
+
+ if (!revs->saved_parents_slab)
+ return commit->parents;
+
+ parents = *saved_parents_at(revs->saved_parents_slab, commit);
+ if (parents == EMPTY_PARENT_LIST)
+ return NULL;
+ return parents;
+}
+
+void free_saved_parents(struct rev_info *revs)
+{
+ if (revs->saved_parents_slab)
+ clear_saved_parents(revs->saved_parents_slab);
+}
struct rev_info;
struct log_info;
struct string_list;
+struct saved_parents;
struct rev_cmdline_info {
unsigned int nr;
/* line level range that we are chasing */
struct decoration line_log_data;
+
+ /* copies of the parent lists, for --full-diff display */
+ struct saved_parents *saved_parents_slab;
};
#define REV_TREE_SAME 0
extern int rewrite_parents(struct rev_info *revs, struct commit *commit,
rewrite_parent_fn_t rewrite_parent);
+
+/*
+ * Save a copy of the parent list, and return the saved copy. This is
+ * used by the log machinery to retrieve the original parents when
+ * commit->parents has been modified by history simpification.
+ *
+ * You may only call save_parents() once per commit (this is checked
+ * for non-root commits).
+ *
+ * get_saved_parents() will transparently return commit->parents if
+ * history simplification is off.
+ */
+extern void save_parents(struct rev_info *revs, struct commit *commit);
+extern struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);
+extern void free_saved_parents(struct rev_info *revs);
+
#endif
#include "sideband.h"
#include "run-command.h"
#include "remote.h"
+#include "connect.h"
#include "send-pack.h"
#include "quote.h"
#include "transport.h"
case REF_STATUS_REJECT_ALREADY_EXISTS:
case REF_STATUS_REJECT_FETCH_FIRST:
case REF_STATUS_REJECT_NEEDS_FORCE:
+ case REF_STATUS_REJECT_STALE:
case REF_STATUS_UPTODATE:
continue;
default:
shutdown(fd[0], SHUT_WR);
if (use_sideband)
finish_async(&demux);
+ fd[1] = -1;
return -1;
}
+ if (!args->stateless_rpc)
+ /* Closed by pack_objects() via start_command() */
+ fd[1] = -1;
}
if (args->stateless_rpc && cmds_sent)
packet_flush(out);
read_cache();
if (checkout_fast_forward(from, to, 1))
exit(1); /* the callee should have complained already */
- ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from, 0);
+ ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from,
+ 0, NULL);
strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
ret = write_ref_sha1(ref_lock, to, sb.buf);
strbuf_release(&sb);
static int inside_git_dir = -1;
static int inside_work_tree = -1;
-static char *prefix_path_gently(const char *prefix, int len, const char *path)
+/*
+ * Normalize "path", prepending the "prefix" for relative paths. If
+ * remaining_prefix is not NULL, return the actual prefix still
+ * remains in the path. For example, prefix = sub1/sub2/ and path is
+ *
+ * foo -> sub1/sub2/foo (full prefix)
+ * ../foo -> sub1/foo (remaining prefix is sub1/)
+ * ../../bar -> bar (no remaining prefix)
+ * ../../sub1/sub2/foo -> sub1/sub2/foo (but no remaining prefix)
+ * `pwd`/../bar -> sub1/bar (no remaining prefix)
+ */
+char *prefix_path_gently(const char *prefix, int len,
+ int *remaining_prefix, const char *path)
{
const char *orig = path;
char *sanitized;
const char *temp = real_path(path);
sanitized = xmalloc(len + strlen(temp) + 1);
strcpy(sanitized, temp);
+ if (remaining_prefix)
+ *remaining_prefix = 0;
} else {
sanitized = xmalloc(len + strlen(path) + 1);
if (len)
memcpy(sanitized, prefix, len);
strcpy(sanitized + len, path);
+ if (remaining_prefix)
+ *remaining_prefix = len;
}
- if (normalize_path_copy(sanitized, sanitized))
+ if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix))
goto error_out;
if (is_absolute_path(orig)) {
size_t root_len, len, total;
char *prefix_path(const char *prefix, int len, const char *path)
{
- char *r = prefix_path_gently(prefix, len, path);
+ char *r = prefix_path_gently(prefix, len, NULL, path);
if (!r)
die("'%s' is outside repository", path);
return r;
int path_inside_repo(const char *prefix, const char *path)
{
int len = prefix ? strlen(prefix) : 0;
- char *r = prefix_path_gently(prefix, len, path);
+ char *r = prefix_path_gently(prefix, len, NULL, path);
if (r) {
free(r);
return 1;
"'git <command> [<revision>...] -- [<file>...]'", arg);
}
-/*
- * Magic pathspec
- *
- * NEEDSWORK: These need to be moved to dir.h or even to a new
- * pathspec.h when we restructure get_pathspec() users to use the
- * "struct pathspec" interface.
- *
- * Possible future magic semantics include stuff like:
- *
- * { PATHSPEC_NOGLOB, '!', "noglob" },
- * { PATHSPEC_ICASE, '\0', "icase" },
- * { PATHSPEC_RECURSIVE, '*', "recursive" },
- * { PATHSPEC_REGEXP, '\0', "regexp" },
- *
- */
-#define PATHSPEC_FROMTOP (1<<0)
-
-static struct pathspec_magic {
- unsigned bit;
- char mnemonic; /* this cannot be ':'! */
- const char *name;
-} pathspec_magic[] = {
- { PATHSPEC_FROMTOP, '/', "top" },
-};
-
-/*
- * Take an element of a pathspec and check for magic signatures.
- * Append the result to the prefix.
- *
- * For now, we only parse the syntax and throw out anything other than
- * "top" magic.
- *
- * NEEDSWORK: This needs to be rewritten when we start migrating
- * get_pathspec() users to use the "struct pathspec" interface. For
- * example, a pathspec element may be marked as case-insensitive, but
- * the prefix part must always match literally, and a single stupid
- * string cannot express such a case.
- */
-static const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt)
-{
- unsigned magic = 0;
- const char *copyfrom = elt;
- int i;
-
- if (elt[0] != ':') {
- ; /* nothing to do */
- } else if (elt[1] == '(') {
- /* longhand */
- const char *nextat;
- for (copyfrom = elt + 2;
- *copyfrom && *copyfrom != ')';
- copyfrom = nextat) {
- size_t len = strcspn(copyfrom, ",)");
- if (copyfrom[len] == ',')
- nextat = copyfrom + len + 1;
- else
- /* handle ')' and '\0' */
- nextat = copyfrom + len;
- if (!len)
- continue;
- for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
- if (strlen(pathspec_magic[i].name) == len &&
- !strncmp(pathspec_magic[i].name, copyfrom, len)) {
- magic |= pathspec_magic[i].bit;
- break;
- }
- if (ARRAY_SIZE(pathspec_magic) <= i)
- die("Invalid pathspec magic '%.*s' in '%s'",
- (int) len, copyfrom, elt);
- }
- if (*copyfrom != ')')
- die("Missing ')' at the end of pathspec magic in '%s'", elt);
- copyfrom++;
- } else {
- /* shorthand */
- for (copyfrom = elt + 1;
- *copyfrom && *copyfrom != ':';
- copyfrom++) {
- char ch = *copyfrom;
-
- if (!is_pathspec_magic(ch))
- break;
- for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
- if (pathspec_magic[i].mnemonic == ch) {
- magic |= pathspec_magic[i].bit;
- break;
- }
- if (ARRAY_SIZE(pathspec_magic) <= i)
- die("Unimplemented pathspec magic '%c' in '%s'",
- ch, elt);
- }
- if (*copyfrom == ':')
- copyfrom++;
- }
-
- if (magic & PATHSPEC_FROMTOP)
- return xstrdup(copyfrom);
- else
- return prefix_path(prefix, prefixlen, copyfrom);
-}
-
-/*
- * N.B. get_pathspec() is deprecated in favor of the "struct pathspec"
- * based interface - see pathspec_magic above.
- *
- * Arguments:
- * - prefix - a path relative to the root of the working tree
- * - pathspec - a list of paths underneath the prefix path
- *
- * Iterates over pathspec, prepending each path with prefix,
- * and return the resulting list.
- *
- * If pathspec is empty, return a singleton list containing prefix.
- *
- * If pathspec and prefix are both empty, return an empty list.
- *
- * This is typically used by built-in commands such as add.c, in order
- * to normalize argv arguments provided to the built-in into a list of
- * paths to process, all relative to the root of the working tree.
- */
-const char **get_pathspec(const char *prefix, const char **pathspec)
-{
- const char *entry = *pathspec;
- const char **src, **dst;
- int prefixlen;
-
- if (!prefix && !entry)
- return NULL;
-
- if (!entry) {
- static const char *spec[2];
- spec[0] = prefix;
- spec[1] = NULL;
- return spec;
- }
-
- /* Otherwise we have to re-write the entries.. */
- src = pathspec;
- dst = pathspec;
- prefixlen = prefix ? strlen(prefix) : 0;
- while (*src) {
- *(dst++) = prefix_pathspec(prefix, prefixlen, *src);
- src++;
- }
- *dst = NULL;
- if (!*pathspec)
- return NULL;
- return pathspec;
-}
/*
* Test if it looks like we're at a git directory.
void setup_work_tree(void)
{
- struct strbuf sb = STRBUF_INIT;
const char *work_tree, *git_dir;
static int initialized = 0;
if (getenv(GIT_WORK_TREE_ENVIRONMENT))
setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
- set_git_dir(relative_path(git_dir, work_tree, &sb));
+ set_git_dir(remove_leading_path(git_dir, work_tree));
initialized = 1;
-
- strbuf_release(&sb);
}
static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
* byte 0 thru (ofs-1) are the same between
* lo and hi; ofs is the first byte that is
* different.
+ *
+ * If ofs==20, then no bytes are different,
+ * meaning we have entries with duplicate
+ * keys. We know that we are in a solid run
+ * of this entry (because the entries are
+ * sorted, and our lo and hi are the same,
+ * there can be nothing but this single key
+ * in between). So we can stop the search.
+ * Either one of these entries is it (and
+ * we do not care which), or we do not have
+ * it.
+ *
+ * Furthermore, we know that one of our
+ * endpoints must be the edge of the run of
+ * duplicates. For example, given this
+ * sequence:
+ *
+ * idx 0 1 2 3 4 5
+ * key A C C C C D
+ *
+ * If we are searching for "B", we might
+ * hit the duplicate run at lo=1, hi=3
+ * (e.g., by first mi=3, then mi=0). But we
+ * can never have lo > 1, because B < C.
+ * That is, if our key is less than the
+ * run, we know that "lo" is the edge, but
+ * we can say nothing of "hi". Similarly,
+ * if our key is greater than the run, we
+ * know that "hi" is the edge, but we can
+ * say nothing of "lo".
+ *
+ * Therefore if we do not find it, we also
+ * know where it would go if it did exist:
+ * just on the far side of the edge that we
+ * know about.
*/
+ if (ofs == 20) {
+ mi = lo;
+ mi_key = base + elem_size * mi + key_offset;
+ cmp = memcmp(mi_key, key, 20);
+ if (!cmp)
+ return mi;
+ if (cmp < 0)
+ return -1 - hi;
+ else
+ return -1 - lo;
+ }
+
hiv = hi_key[ofs_0];
if (ofs_0 < 19)
hiv = (hiv << 8) | hi_key[ofs_0+1];
}
}
-static int unuse_one_window(struct packed_git *current, int keep_fd)
+static int unuse_one_window(struct packed_git *current)
{
struct packed_git *p, *lru_p = NULL;
struct pack_window *lru_w = NULL, *lru_l = NULL;
pack_mapped -= lru_w->len;
if (lru_l)
lru_l->next = lru_w->next;
- else {
+ else
lru_p->windows = lru_w->next;
- if (!lru_p->windows && lru_p->pack_fd != -1
- && lru_p->pack_fd != keep_fd) {
- close(lru_p->pack_fd);
- pack_open_fds--;
- lru_p->pack_fd = -1;
- }
- }
free(lru_w);
pack_open_windows--;
return 1;
return 0;
}
-void release_pack_memory(size_t need, int fd)
+void release_pack_memory(size_t need)
{
size_t cur = pack_mapped;
- while (need >= (cur - pack_mapped) && unuse_one_window(NULL, fd))
+ while (need >= (cur - pack_mapped) && unuse_one_window(NULL))
; /* nothing */
}
if (ret == MAP_FAILED) {
if (!length)
return NULL;
- release_pack_memory(length, fd);
+ release_pack_memory(length);
ret = mmap(start, length, prot, flags, fd, offset);
if (ret == MAP_FAILED)
die_errno("Out of memory? mmap failed");
}
}
+/*
+ * The LRU pack is the one with the oldest MRU window, preferring packs
+ * with no used windows, or the oldest mtime if it has no windows allocated.
+ */
+static void find_lru_pack(struct packed_git *p, struct packed_git **lru_p, struct pack_window **mru_w, int *accept_windows_inuse)
+{
+ struct pack_window *w, *this_mru_w;
+ int has_windows_inuse = 0;
+
+ /*
+ * Reject this pack if it has windows and the previously selected
+ * one does not. If this pack does not have windows, reject
+ * it if the pack file is newer than the previously selected one.
+ */
+ if (*lru_p && !*mru_w && (p->windows || p->mtime > (*lru_p)->mtime))
+ return;
+
+ for (w = this_mru_w = p->windows; w; w = w->next) {
+ /*
+ * Reject this pack if any of its windows are in use,
+ * but the previously selected pack did not have any
+ * inuse windows. Otherwise, record that this pack
+ * has windows in use.
+ */
+ if (w->inuse_cnt) {
+ if (*accept_windows_inuse)
+ has_windows_inuse = 1;
+ else
+ return;
+ }
+
+ if (w->last_used > this_mru_w->last_used)
+ this_mru_w = w;
+
+ /*
+ * Reject this pack if it has windows that have been
+ * used more recently than the previously selected pack.
+ * If the previously selected pack had windows inuse and
+ * we have not encountered a window in this pack that is
+ * inuse, skip this check since we prefer a pack with no
+ * inuse windows to one that has inuse windows.
+ */
+ if (*mru_w && *accept_windows_inuse == has_windows_inuse &&
+ this_mru_w->last_used > (*mru_w)->last_used)
+ return;
+ }
+
+ /*
+ * Select this pack.
+ */
+ *mru_w = this_mru_w;
+ *lru_p = p;
+ *accept_windows_inuse = has_windows_inuse;
+}
+
+static int close_one_pack(void)
+{
+ struct packed_git *p, *lru_p = NULL;
+ struct pack_window *mru_w = NULL;
+ int accept_windows_inuse = 1;
+
+ for (p = packed_git; p; p = p->next) {
+ if (p->pack_fd == -1)
+ continue;
+ find_lru_pack(p, &lru_p, &mru_w, &accept_windows_inuse);
+ }
+
+ if (lru_p) {
+ close(lru_p->pack_fd);
+ pack_open_fds--;
+ lru_p->pack_fd = -1;
+ return 1;
+ }
+
+ return 0;
+}
+
void unuse_pack(struct pack_window **w_cursor)
{
struct pack_window *w = *w_cursor;
pack_max_fds = 1;
}
- while (pack_max_fds <= pack_open_fds && unuse_one_window(NULL, -1))
+ while (pack_max_fds <= pack_open_fds && close_one_pack())
; /* nothing */
p->pack_fd = git_open_noatime(p->pack_name);
win->len = (size_t)len;
pack_mapped += win->len;
while (packed_git_limit < pack_mapped
- && unuse_one_window(p, p->pack_fd))
+ && unuse_one_window(p))
; /* nothing */
win->base = xmmap(NULL, win->len,
PROT_READ, MAP_PRIVATE,
static void try_to_free_pack_memory(size_t size)
{
- release_pack_memory(size, -1);
+ release_pack_memory(size);
}
struct packed_git *add_packed_git(const char *path, int path_len, int local)
int i;
struct delta_base_cache_entry *ent;
+ ent = get_delta_base_cache_entry(p, curpos);
+ if (eq_delta_base_cache_entry(ent, p, curpos)) {
+ type = ent->type;
+ data = ent->data;
+ size = ent->size;
+ clear_delta_base_cache_entry(ent);
+ base_from_cache = 1;
+ break;
+ }
+
if (do_check_packed_object_crc && p->index_version > 1) {
struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
unsigned long len = revidx[1].offset - obj_offset;
}
}
- ent = get_delta_base_cache_entry(p, curpos);
- if (eq_delta_base_cache_entry(ent, p, curpos)) {
- type = ent->type;
- data = ent->data;
- size = ent->size;
- clear_delta_base_cache_entry(ent);
- base_from_cache = 1;
- break;
- }
-
type = unpack_object_header(p, &w_curs, &curpos, &size);
if (type != OBJ_OFS_DELTA && type != OBJ_REF_DELTA)
break;
return 0;
}
-/* returns enum object_type or negative */
int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi)
{
struct cached_object *co;
return 0;
}
+/* returns enum object_type or negative */
int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
{
enum object_type type;
if (find_pack_entry(sha1, &e))
return 1;
- return has_loose_object(sha1);
+ if (has_loose_object(sha1))
+ return 1;
+ reprepare_packed_git();
+ return find_pack_entry(sha1, &e);
}
static void check_tree(const void *buf, size_t size)
return -1;
sp++; /* beginning of type name, or closing brace for empty */
- if (!strncmp(commit_type, sp, 6) && sp[6] == '}')
+ if (!prefixcmp(sp, "commit}"))
expected_type = OBJ_COMMIT;
- else if (!strncmp(tree_type, sp, 4) && sp[4] == '}')
+ else if (!prefixcmp(sp, "tag}"))
+ expected_type = OBJ_TAG;
+ else if (!prefixcmp(sp, "tree}"))
expected_type = OBJ_TREE;
- else if (!strncmp(blob_type, sp, 4) && sp[4] == '}')
+ else if (!prefixcmp(sp, "blob}"))
expected_type = OBJ_BLOB;
else if (!prefixcmp(sp, "object}"))
expected_type = OBJ_ANY;
return st;
}
+/* parse @something syntax, when 'something' is not {.*} */
+static int interpret_empty_at(const char *name, int namelen, int len, struct strbuf *buf)
+{
+ const char *next;
+
+ if (len || name[1] == '{')
+ return -1;
+
+ /* make sure it's a single @, or @@{.*}, not @foo */
+ next = strchr(name + len + 1, '@');
+ if (next && next[1] != '{')
+ return -1;
+ if (!next)
+ next = name + namelen;
+ if (next != name + 1)
+ return -1;
+
+ strbuf_reset(buf);
+ strbuf_add(buf, "HEAD", 4);
+ return 1;
+}
+
static int reinterpret(const char *name, int namelen, int len, struct strbuf *buf)
{
/* we have extra data, which might need further processing */
int ret;
strbuf_add(buf, name + len, namelen - len);
- ret = interpret_branch_name(buf->buf, &tmp);
+ ret = interpret_branch_name(buf->buf, buf->len, &tmp);
/* that data was not interpreted, remove our cruft */
if (ret < 0) {
strbuf_setlen(buf, used);
* If the input was ok but there are not N branch switches in the
* reflog, it returns 0.
*/
-int interpret_branch_name(const char *name, struct strbuf *buf)
+int interpret_branch_name(const char *name, int namelen, struct strbuf *buf)
{
char *cp;
struct branch *upstream;
- int namelen = strlen(name);
int len = interpret_nth_prior_checkout(name, buf);
int tmp_len;
+ if (!namelen)
+ namelen = strlen(name);
+
if (!len) {
return len; /* syntax Ok, not enough switches */
} else if (len > 0) {
cp = strchr(name, '@');
if (!cp)
return -1;
+
+ len = interpret_empty_at(name, namelen, cp - name, buf);
+ if (len > 0)
+ return reinterpret(name, namelen, len, buf);
+
tmp_len = upstream_mark(cp, namelen - (cp - name));
if (!tmp_len)
return -1;
+
len = cp + tmp_len - name;
cp = xstrndup(name, cp - name);
upstream = branch_get(*cp ? cp : NULL);
int strbuf_branchname(struct strbuf *sb, const char *name)
{
int len = strlen(name);
- int used = interpret_branch_name(name, sb);
+ int used = interpret_branch_name(name, len, sb);
if (used == len)
return 0;
}
/*
- * Many callers know that the user meant to name a committish by
+ * Many callers know that the user meant to name a commit-ish 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.
+ * abbreviated object names between commit-ish 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
+ * commit-ish. It is merely to give a hint to the disambiguation
* machinery.
*/
int get_sha1_committish(const char *name, unsigned char *sha1)
#include "cache.h"
#include "commit.h"
#include "tag.h"
+#include "pkt-line.h"
static int is_shallow = -1;
static struct stat shallow_stat;
)
die("shallow file was changed during fetch");
}
+
+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);
+ if (graft->nr_parent != -1)
+ return 0;
+ 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;
+}
+
+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;
+}
+
+char *setup_temporary_shallow(void)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int fd;
+
+ if (write_shallow_commits(&sb, 0)) {
+ struct strbuf path = STRBUF_INIT;
+ strbuf_addstr(&path, git_path("shallow_XXXXXX"));
+ fd = xmkstemp(path.buf);
+ if (write_in_full(fd, sb.buf, sb.len) != sb.len)
+ die_errno("failed to write to %s",
+ path.buf);
+ close(fd);
+ strbuf_release(&sb);
+ return strbuf_detach(&path, NULL);
+ }
+ /*
+ * is_repository_shallow() sees empty string as "no shallow
+ * file".
+ */
+ return xstrdup("");
+}
+
+void setup_alternate_shallow(struct lock_file *shallow_lock,
+ const char **alternate_shallow_file)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int fd;
+
+ check_shallow_file_for_update();
+ fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"),
+ LOCK_DIE_ON_ERROR);
+ if (write_shallow_commits(&sb, 0)) {
+ if (write_in_full(fd, sb.buf, sb.len) != sb.len)
+ die_errno("failed to write to %s",
+ shallow_lock->filename);
+ *alternate_shallow_file = shallow_lock->filename;
+ } else
+ /*
+ * is_repository_shallow() sees empty string as "no
+ * shallow file".
+ */
+ *alternate_shallow_file = "";
+ strbuf_release(&sb);
+}
#include "string-list.h"
#include "sha1-array.h"
#include "argv-array.h"
+#include "blob.h"
static struct string_list config_name_for_path;
static struct string_list config_fetch_recurse_submodules_for_name;
*/
static int gitmodules_is_unmerged;
+/*
+ * This flag is set if the .gitmodules file had unstaged modifications on
+ * startup. This must be checked before allowing modifications to the
+ * .gitmodules file with the intention to stage them later, because when
+ * continuing we would stage the modifications the user didn't stage herself
+ * too. That might change in a future version when we learn to stage the
+ * changes we do ourselves without staging any previous modifications.
+ */
+static int gitmodules_is_modified;
+
+
+int is_staging_gitmodules_ok(void)
+{
+ return !gitmodules_is_modified;
+}
+
+/*
+ * Try to update the "path" entry in the "submodule.<name>" section of the
+ * .gitmodules file. Return 0 only if a .gitmodules file was found, a section
+ * with the correct path=<oldpath> setting was found and we could update it.
+ */
+int update_path_in_gitmodules(const char *oldpath, const char *newpath)
+{
+ struct strbuf entry = STRBUF_INIT;
+ struct string_list_item *path_option;
+
+ if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
+ return -1;
+
+ if (gitmodules_is_unmerged)
+ die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
+
+ path_option = unsorted_string_list_lookup(&config_name_for_path, oldpath);
+ if (!path_option) {
+ warning(_("Could not find section in .gitmodules where path=%s"), oldpath);
+ return -1;
+ }
+ strbuf_addstr(&entry, "submodule.");
+ strbuf_addstr(&entry, path_option->util);
+ strbuf_addstr(&entry, ".path");
+ if (git_config_set_in_file(".gitmodules", entry.buf, newpath) < 0) {
+ /* Maybe the user already did that, don't error out here */
+ warning(_("Could not update .gitmodules entry %s"), entry.buf);
+ strbuf_release(&entry);
+ return -1;
+ }
+ strbuf_release(&entry);
+ return 0;
+}
+
+/*
+ * Try to remove the "submodule.<name>" section from .gitmodules where the given
+ * path is configured. Return 0 only if a .gitmodules file was found, a section
+ * with the correct path=<path> setting was found and we could remove it.
+ */
+int remove_path_from_gitmodules(const char *path)
+{
+ struct strbuf sect = STRBUF_INIT;
+ struct string_list_item *path_option;
+
+ if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
+ return -1;
+
+ if (gitmodules_is_unmerged)
+ die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
+
+ path_option = unsorted_string_list_lookup(&config_name_for_path, path);
+ if (!path_option) {
+ warning(_("Could not find section in .gitmodules where path=%s"), path);
+ return -1;
+ }
+ strbuf_addstr(§, "submodule.");
+ strbuf_addstr(§, path_option->util);
+ if (git_config_rename_section_in_file(".gitmodules", sect.buf, NULL) < 0) {
+ /* Maybe the user already did that, don't error out here */
+ warning(_("Could not remove .gitmodules entry for %s"), path);
+ strbuf_release(§);
+ return -1;
+ }
+ strbuf_release(§);
+ return 0;
+}
+
+void stage_updated_gitmodules(void)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct stat st;
+ int pos;
+ struct cache_entry *ce;
+ int namelen = strlen(".gitmodules");
+
+ pos = cache_name_pos(".gitmodules", namelen);
+ if (pos < 0) {
+ warning(_("could not find .gitmodules in index"));
+ return;
+ }
+ ce = active_cache[pos];
+ ce->ce_flags = namelen;
+ if (strbuf_read_file(&buf, ".gitmodules", 0) < 0)
+ die(_("reading updated .gitmodules failed"));
+ if (lstat(".gitmodules", &st) < 0)
+ die_errno(_("unable to stat updated .gitmodules"));
+ fill_stat_cache_info(ce, &st);
+ ce->ce_mode = ce_mode_from_stat(ce, st.st_mode);
+ if (remove_cache_entry_at(pos) < 0)
+ die(_("unable to remove .gitmodules from index"));
+ if (write_sha1_file(buf.buf, buf.len, blob_type, ce->sha1))
+ die(_("adding updated .gitmodules failed"));
+ if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
+ die(_("staging updated .gitmodules failed"));
+}
+
static int add_submodule_odb(const char *path)
{
struct strbuf objects_directory = STRBUF_INIT;
!memcmp(ce->name, ".gitmodules", 11))
gitmodules_is_unmerged = 1;
}
+ } else if (pos < active_nr) {
+ struct stat st;
+ if (lstat(".gitmodules", &st) == 0 &&
+ ce_match_stat(active_cache[pos], &st, 0) & DATA_CHANGED)
+ gitmodules_is_modified = 1;
}
if (!gitmodules_is_unmerged)
return 0;
if (!strcmp(key, "path")) {
+ if (!value)
+ return config_error_nonbool(var);
+
config = unsorted_string_list_lookup(&config_name_for_path, value);
if (config)
free(config->util);
} else if (!strcmp(key, "ignore")) {
char *name_cstr;
+ if (!value)
+ return config_error_nonbool(var);
+
if (strcmp(value, "untracked") && strcmp(value, "dirty") &&
strcmp(value, "all") && strcmp(value, "none")) {
warning("Invalid parameter \"%s\" for config option \"submodule.%s.ignore\"", value, var);
free(merges.objects);
return 0;
}
+
+/* Update gitfile and core.worktree setting to connect work tree and git dir */
+void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir)
+{
+ struct strbuf file_name = STRBUF_INIT;
+ struct strbuf rel_path = STRBUF_INIT;
+ const char *real_work_tree = xstrdup(real_path(work_tree));
+ FILE *fp;
+
+ /* Update gitfile */
+ strbuf_addf(&file_name, "%s/.git", work_tree);
+ fp = fopen(file_name.buf, "w");
+ if (!fp)
+ die(_("Could not create git link %s"), file_name.buf);
+ fprintf(fp, "gitdir: %s\n", relative_path(git_dir, real_work_tree,
+ &rel_path));
+ fclose(fp);
+
+ /* Update core.worktree setting */
+ strbuf_reset(&file_name);
+ strbuf_addf(&file_name, "%s/config", git_dir);
+ if (git_config_set_in_file(file_name.buf, "core.worktree",
+ relative_path(real_work_tree, git_dir,
+ &rel_path)))
+ die(_("Could not set core.worktree in %s"),
+ file_name.buf);
+
+ strbuf_release(&file_name);
+ strbuf_release(&rel_path);
+ free((void *)real_work_tree);
+}
RECURSE_SUBMODULES_ON = 2
};
+int is_staging_gitmodules_ok(void);
+int update_path_in_gitmodules(const char *oldpath, const char *newpath);
+int remove_path_from_gitmodules(const char *path);
+void stage_updated_gitmodules(void);
void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
const char *path);
int submodule_config(const char *var, const char *value, void *cb);
int find_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name,
struct string_list *needs_pushing);
int push_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name);
+void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir);
#endif
t[0-9][0-9][0-9][0-9]/* -whitespace
+t0110/url-* binary
check_count -L6,3 B 1 B1 1 B2 1 D 1
'
+test_expect_success 'blame -L -X' '
+ test_must_fail $PROG -L-1 file
+'
+
+test_expect_success 'blame -L 0' '
+ test_must_fail $PROG -L0 file
+'
+
+test_expect_success 'blame -L ,0' '
+ test_must_fail $PROG -L,0 file
+'
+
+test_expect_success 'blame -L ,+0' '
+ test_must_fail $PROG -L,+0 file
+'
+
+test_expect_success 'blame -L X,+0' '
+ test_must_fail $PROG -L1,+0 file
+'
+
test_expect_success 'blame -L X,+1' '
check_count -L3,+1 B2 1
'
check_count -L3,+4 B 1 B1 1 B2 1 D 1
'
+test_expect_success 'blame -L ,-0' '
+ test_must_fail $PROG -L,-0 file
+'
+
+test_expect_success 'blame -L X,-0' '
+ test_must_fail $PROG -L1,-0 file
+'
+
test_expect_success 'blame -L X,-1' '
check_count -L3,-1 B2 1
'
check_count -L/99/,-3 B 1 B2 1 D 1
'
+# 'file' ends with an incomplete line, so 'wc' reports one fewer lines than
+# git-blame sees, hence the last line is actually $(wc...)+1.
+test_expect_success 'blame -L X (X == nlines)' '
+ n=$(expr $(wc -l <file) + 1) &&
+ check_count -L$n C 1
+'
+
+test_expect_success 'blame -L X (X == nlines + 1)' '
+ n=$(expr $(wc -l <file) + 2) &&
+ test_must_fail $PROG -L$n file
+'
+
test_expect_success 'blame -L X (X > nlines)' '
test_must_fail $PROG -L12345 file
'
+test_expect_success 'blame -L ,Y (Y == nlines)' '
+ n=$(expr $(wc -l <file) + 1) &&
+ check_count -L,$n A 1 B 1 B1 1 B2 1 "A U Thor" 1 C 1 D 1 E 1
+'
+
+test_expect_success 'blame -L ,Y (Y == nlines + 1)' '
+ n=$(expr $(wc -l <file) + 2) &&
+ test_must_fail $PROG -L,$n file
+'
+
test_expect_success 'blame -L ,Y (Y > nlines)' '
test_must_fail $PROG -L,12345 file
'
+test_expect_success 'blame -L multiple (disjoint)' '
+ check_count -L2,3 -L6,7 A 1 B1 1 B2 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L multiple (disjoint: unordered)' '
+ check_count -L6,7 -L2,3 A 1 B1 1 B2 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L multiple (adjacent)' '
+ check_count -L2,3 -L4,5 A 1 B 1 B2 1 D 1
+'
+
+test_expect_success 'blame -L multiple (adjacent: unordered)' '
+ check_count -L4,5 -L2,3 A 1 B 1 B2 1 D 1
+'
+
+test_expect_success 'blame -L multiple (overlapping)' '
+ check_count -L2,4 -L3,5 A 1 B 1 B2 1 D 1
+'
+
+test_expect_success 'blame -L multiple (overlapping: unordered)' '
+ check_count -L3,5 -L2,4 A 1 B 1 B2 1 D 1
+'
+
+test_expect_success 'blame -L multiple (superset/subset)' '
+ check_count -L2,8 -L3,5 A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L multiple (superset/subset: unordered)' '
+ check_count -L3,5 -L2,8 A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L /RE/ (relative)' '
+ check_count -L3,3 -L/fox/ B1 1 B2 1 C 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L /RE/ (relative: no preceding range)' '
+ check_count -L/dog/ A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1
+'
+
+test_expect_success 'blame -L /RE/ (relative: adjacent)' '
+ check_count -L1,1 -L/dog/,+1 A 1 E 1
+'
+
+test_expect_success 'blame -L /RE/ (relative: not found)' '
+ test_must_fail $PROG -L4,4 -L/dog/ file
+'
+
+test_expect_success 'blame -L /RE/ (relative: end-of-file)' '
+ test_must_fail $PROG -L, -L/$/ file
+'
+
+test_expect_success 'blame -L ^/RE/ (absolute)' '
+ check_count -L3,3 -L^/dog/,+2 A 1 B2 1
+'
+
+test_expect_success 'blame -L ^/RE/ (absolute: no preceding range)' '
+ check_count -L^/dog/,+2 A 1 B2 1
+'
+
+test_expect_success 'blame -L ^/RE/ (absolute: not found)' '
+ test_must_fail $PROG -L4,4 -L^/tambourine/ file
+'
+
+test_expect_success 'blame -L ^/RE/ (absolute: end-of-file)' '
+ n=$(expr $(wc -l <file) + 1) &&
+ check_count -L$n -L^/$/,+2 A 1 C 1 E 1
+'
+
test_expect_success 'setup -L :regex' '
tr Q "\\t" >hello.c <<-\EOF &&
int main(int argc, const char *argv[])
test_must_fail $PROG -L:nomatch hello.c
'
-test_expect_success 'blame -L bogus' '
- test_must_fail $PROG -L file &&
- test_must_fail $PROG -L1,+ file &&
- test_must_fail $PROG -L1,- file &&
- test_must_fail $PROG -LX file &&
- test_must_fail $PROG -L1,X file &&
- test_must_fail $PROG -L1,+N file &&
+test_expect_success 'blame -L :RE (relative)' '
+ check_count -f hello.c -L3,3 -L:ma.. F 1 H 4
+'
+
+test_expect_success 'blame -L :RE (relative: no preceding range)' '
+ check_count -f hello.c -L:ma.. F 4 G 1
+'
+
+test_expect_success 'blame -L :RE (relative: not found)' '
+ test_must_fail $PROG -L3,3 -L:tambourine hello.c
+'
+
+test_expect_success 'blame -L :RE (relative: end-of-file)' '
+ test_must_fail $PROG -L, -L:main hello.c
+'
+
+test_expect_success 'blame -L ^:RE (absolute)' '
+ check_count -f hello.c -L3,3 -L^:ma.. F 4 G 1
+'
+
+test_expect_success 'blame -L ^:RE (absolute: no preceding range)' '
+ check_count -f hello.c -L^:ma.. F 4 G 1
+'
+
+test_expect_success 'blame -L ^:RE (absolute: not found)' '
+ test_must_fail $PROG -L4,4 -L^:tambourine hello.c
+'
+
+test_expect_success 'blame -L ^:RE (absolute: end-of-file)' '
+ n=$(printf "%d" $(wc -l <hello.c)) &&
+ check_count -f hello.c -L$n -L^:ma.. F 4 G 1 H 1
+'
+
+test_expect_success 'setup incremental' '
+ (
+ GIT_AUTHOR_NAME=I &&
+ export GIT_AUTHOR_NAME &&
+ GIT_AUTHOR_EMAIL=I@test.git &&
+ export GIT_AUTHOR_EMAIL &&
+ >incremental &&
+ git add incremental &&
+ git commit -m "step 0" &&
+ printf "partial" >>incremental &&
+ git commit -a -m "step 0.5" &&
+ echo >>incremental &&
+ git commit -a -m "step 1"
+ )
+'
+
+test_expect_success 'blame empty' '
+ check_count -h HEAD^^ -f incremental
+'
+
+test_expect_success 'blame -L 0 empty' '
+ test_must_fail $PROG -L0 incremental HEAD^^
+'
+
+test_expect_success 'blame -L 1 empty' '
+ test_must_fail $PROG -L1 incremental HEAD^^
+'
+
+test_expect_success 'blame -L 2 empty' '
+ test_must_fail $PROG -L2 incremental HEAD^^
+'
+
+test_expect_success 'blame half' '
+ check_count -h HEAD^ -f incremental I 1
+'
+
+test_expect_success 'blame -L 0 half' '
+ test_must_fail $PROG -L0 incremental HEAD^
+'
+
+test_expect_success 'blame -L 1 half' '
+ check_count -h HEAD^ -f incremental -L1 I 1
+'
+
+test_expect_success 'blame -L 2 half' '
+ test_must_fail $PROG -L2 incremental HEAD^
+'
+
+test_expect_success 'blame -L 3 half' '
+ test_must_fail $PROG -L3 incremental HEAD^
+'
+
+test_expect_success 'blame full' '
+ check_count -f incremental I 1
+'
+
+test_expect_success 'blame -L 0 full' '
+ test_must_fail $PROG -L0 incremental
+'
+
+test_expect_success 'blame -L 1 full' '
+ check_count -f incremental -L1 I 1
+'
+
+test_expect_success 'blame -L 2 full' '
+ test_must_fail $PROG -L2 incremental
+'
+
+test_expect_success 'blame -L 3 full' '
+ test_must_fail $PROG -L3 incremental
+'
+
+test_expect_success 'blame -L' '
+ test_must_fail $PROG -L file
+'
+
+test_expect_success 'blame -L X,+' '
+ test_must_fail $PROG -L1,+ file
+'
+
+test_expect_success 'blame -L X,-' '
+ test_must_fail $PROG -L1,- file
+'
+
+test_expect_success 'blame -L X (non-numeric X)' '
+ test_must_fail $PROG -LX file
+'
+
+test_expect_success 'blame -L X,Y (non-numeric Y)' '
+ test_must_fail $PROG -L1,Y file
+'
+
+test_expect_success 'blame -L X,+N (non-numeric N)' '
+ test_must_fail $PROG -L1,+N file
+'
+
+test_expect_success 'blame -L X,-N (non-numeric N)' '
test_must_fail $PROG -L1,-N file
'
+
+test_expect_success 'blame -L ,^/RE/' '
+ test_must_fail $PROG -L1,^/99/ file
+'
P4PORT=localhost:$P4DPORT
P4CLIENT=client
P4EDITOR=:
-export P4PORT P4CLIENT P4EDITOR
+unset P4CHARSET
+export P4PORT P4CLIENT P4EDITOR P4CHARSET
db="$TRASH_DIRECTORY/db"
cli="$TRASH_DIRECTORY/cli"
-f "$TEST_PATH/apache.conf" $HTTPD_PARA -k stop
}
-test_http_push_nonff() {
+test_http_push_nonff () {
REMOTE_REPO=$1
LOCAL_REPO=$2
BRANCH=$3
+ EXPECT_CAS_RESULT=${4-failure}
test_expect_success 'non-fast-forward push fails' '
cd "$REMOTE_REPO" &&
test_expect_success 'non-fast-forward push shows help message' '
test_i18ngrep "Updates were rejected because" output
'
+
+ test_expect_${EXPECT_CAS_RESULT} 'force with lease aka cas' '
+ HEAD=$( cd "$REMOTE_REPO" && git rev-parse --verify HEAD ) &&
+ test_when_finished '\''
+ (cd "$REMOTE_REPO" && git update-ref HEAD "$HEAD")
+ '\'' &&
+ (
+ cd "$LOCAL_REPO" &&
+ git push -v --force-with-lease=$BRANCH:$HEAD origin
+ ) &&
+ git rev-parse --verify "$BRANCH" >expect &&
+ (
+ cd "$REMOTE_REPO" && git rev-parse --verify HEAD
+ ) >actual &&
+ test_cmp expect actual
+ '
}
setup_askpass_helper() {
}
expect_askpass() {
- dest=$HTTPD_DEST
+ dest=$HTTPD_DEST${3+/$3}
+
{
case "$1" in
none)
<IfModule !mod_version.c>
LoadModule version_module modules/mod_version.so
</IfModule>
+<IfModule !mod_headers.c>
+ LoadModule headers_module modules/mod_headers.so
+</IfModule>
<IfVersion < 2.4>
LockFile accept.lock
SetEnv GIT_HTTP_EXPORT_ALL
SetEnv GIT_NAMESPACE ns
</LocationMatch>
+<LocationMatch /smart_cookies/>
+ SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
+ SetEnv GIT_HTTP_EXPORT_ALL
+ Header set Set-Cookie name=value
+</LocationMatch>
ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
ScriptAlias /broken_smart/ broken-smart-http.sh/
<Directory ${GIT_EXEC_PATH}>
RewriteEngine on
RewriteRule ^/smart-redir-perm/(.*)$ /smart/$1 [R=301]
RewriteRule ^/smart-redir-temp/(.*)$ /smart/$1 [R=302]
+RewriteRule ^/smart-redir-auth/(.*)$ /auth/smart/$1 [R=301]
+RewriteRule ^/smart-redir-limited/(.*)/info/refs$ /smart/$1/info/refs [R=301]
<IfDefine SSL>
LoadModule ssl_module modules/mod_ssl.so
--- /dev/null
+#!/bin/sh
+#
+# Support routines for hand-crafting weird or malicious packs.
+#
+# You can make a complete pack like:
+#
+# pack_header 2 >foo.pack &&
+# pack_obj e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 >>foo.pack &&
+# pack_obj e68fe8129b546b101aee9510c5328e7f21ca1d18 >>foo.pack &&
+# pack_trailer foo.pack
+
+# Print the big-endian 4-byte octal representation of $1
+uint32_octal () {
+ n=$1
+ printf '\%o' $(($n / 16777216)); n=$((n % 16777216))
+ printf '\%o' $(($n / 65536)); n=$((n % 65536))
+ printf '\%o' $(($n / 256)); n=$((n % 256))
+ printf '\%o' $(($n ));
+}
+
+# Print the big-endian 4-byte binary representation of $1
+uint32_binary () {
+ printf "$(uint32_octal "$1")"
+}
+
+# Print a pack header, version 2, for a pack with $1 objects
+pack_header () {
+ printf 'PACK' &&
+ printf '\0\0\0\2' &&
+ uint32_binary "$1"
+}
+
+# Print the pack data for object $1, as a delta against object $2 (or as a full
+# object if $2 is missing or empty). The output is suitable for including
+# directly in the packfile, and represents the entirety of the object entry.
+# Doing this on the fly (especially picking your deltas) is quite tricky, so we
+# have hardcoded some well-known objects. See the case statements below for the
+# complete list.
+pack_obj () {
+ case "$1" in
+ # empty blob
+ e69de29bb2d1d6434b8b29ae775ad8c2e48c5391)
+ case "$2" in
+ '')
+ printf '\060\170\234\003\0\0\0\0\1'
+ return
+ ;;
+ esac
+ ;;
+
+ # blob containing "\7\76"
+ e68fe8129b546b101aee9510c5328e7f21ca1d18)
+ case "$2" in
+ '')
+ printf '\062\170\234\143\267\3\0\0\116\0\106'
+ return
+ ;;
+ 01d7713666f4de822776c7622c10f1b07de280dc)
+ printf '\165\1\327\161\66\146\364\336\202\47\166' &&
+ printf '\307\142\54\20\361\260\175\342\200\334\170' &&
+ printf '\234\143\142\142\142\267\003\0\0\151\0\114'
+ return
+ ;;
+ esac
+ ;;
+
+ # blob containing "\7\0"
+ 01d7713666f4de822776c7622c10f1b07de280dc)
+ case "$2" in
+ '')
+ printf '\062\170\234\143\147\0\0\0\20\0\10'
+ return
+ ;;
+ e68fe8129b546b101aee9510c5328e7f21ca1d18)
+ printf '\165\346\217\350\22\233\124\153\20\32\356' &&
+ printf '\225\20\305\62\216\177\41\312\35\30\170\234' &&
+ printf '\143\142\142\142\147\0\0\0\53\0\16'
+ return
+ ;;
+ esac
+ ;;
+ esac
+
+ echo >&2 "BUG: don't know how to print $1${2:+ (from $2)}"
+ return 1
+}
+
+# Compute and append pack trailer to "$1"
+pack_trailer () {
+ test-sha1 -b <"$1" >trailer.tmp &&
+ cat trailer.tmp >>"$1" &&
+ rm -f trailer.tmp
+}
+
+# Remove any existing packs to make sure that
+# whatever we index next will be the pack that we
+# actually use.
+clear_packs () {
+ rm -f .git/objects/pack/*
+}
test -d realgitdir/refs
'
+test_expect_success 're-init on .git file' '
+ ( cd newdir && git init )
+'
+
test_expect_success 're-init to update git link' '
(
cd newdir &&
init_vars &&
rm -f "$HOME/stdout" "$HOME/stderr" "$HOME/cmd" &&
- echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
+ echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $no_index_opt $args \
>"$HOME/cmd" &&
echo "$expect_code" >"$HOME/expected-exit-code" &&
test_expect_code "$expect_code" \
- git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
+ git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $no_index_opt $args \
>"$HOME/stdout" 2>"$HOME/stderr" &&
test_cmp "$HOME/expected-stdout" "$HOME/stdout" &&
stderr_empty_on_success "$expect_code"
# check-ignore --verbose output is the same as normal output except
# for the extra first column.
#
+# A parameter is used to determine if the tests are run with the
+# normal case (using the index), or with the --no-index option.
+#
# Arguments:
# - (optional) prereqs for this test, e.g. 'SYMLINKS'
# - test name
# from the other verbosity modes is automatically inferred
# from this value)
# - code to run (should invoke test_check_ignore)
-test_expect_success_multi () {
+# - index option: --index or --no-index
+test_expect_success_multiple () {
prereq=
- if test $# -eq 4
+ if test $# -eq 5
then
prereq=$1
shift
fi
+ if test "$4" = "--index"
+ then
+ no_index_opt=
+ else
+ no_index_opt=$4
+ fi
testname="$1" expect_all="$2" code="$3"
expect_verbose=$( echo "$expect_all" | grep -v '^:: ' )
expect=$( echo "$expect_verbose" | sed -e 's/.* //' )
- test_expect_success $prereq "$testname" '
+ test_expect_success $prereq "$testname${no_index_opt:+ with $no_index_opt}" '
expect "$expect" &&
eval "$code"
'
then
for quiet_opt in '-q' '--quiet'
do
- test_expect_success $prereq "$testname${quiet_opt:+ with $quiet_opt}" "
+ opts="${no_index_opt:+$no_index_opt }$quiet_opt"
+ test_expect_success $prereq "$testname${opts:+ with $opts}" "
expect '' &&
$code
"
for verbose_opt in '-v' '--verbose'
do
- for non_matching_opt in '' ' -n' ' --non-matching'
+ for non_matching_opt in '' '-n' '--non-matching'
do
if test -n "$non_matching_opt"
then
expect '$my_expect' &&
$code
"
- opts="$verbose_opt$non_matching_opt"
+ opts="${no_index_opt:+$no_index_opt }$verbose_opt${non_matching_opt:+ $non_matching_opt}"
test_expect_success $prereq "$testname${opts:+ with $opts}" "$test_code"
done
done
verbose_opt=
non_matching_opt=
+ no_index_opt=
+}
+
+test_expect_success_multi () {
+ test_expect_success_multiple "$@" "--index"
+}
+
+test_expect_success_no_index_multi () {
+ test_expect_success_multiple "$@" "--no-index"
}
test_expect_success 'setup' '
# First make sure that the presence of a file in the working tree
# does not impact results, but that the presence of a file in the
-# index does.
+# index does unless the --no-index option is used.
for subdir in '' 'a/'
do
":: ${subdir}non-existent" \
"test_check_ignore '${subdir}non-existent' 1"
+ test_expect_success_no_index_multi "non-existent file $where not ignored" \
+ ":: ${subdir}non-existent" \
+ "test_check_ignore '${subdir}non-existent' 1"
+
test_expect_success_multi "non-existent file $where ignored" \
".gitignore:1:one ${subdir}one" \
"test_check_ignore '${subdir}one'"
+ test_expect_success_no_index_multi "non-existent file $where ignored" \
+ ".gitignore:1:one ${subdir}one" \
+ "test_check_ignore '${subdir}one'"
+
test_expect_success_multi "existing untracked file $where not ignored" \
":: ${subdir}not-ignored" \
"test_check_ignore '${subdir}not-ignored' 1"
+ test_expect_success_no_index_multi "existing untracked file $where not ignored" \
+ ":: ${subdir}not-ignored" \
+ "test_check_ignore '${subdir}not-ignored' 1"
+
test_expect_success_multi "existing tracked file $where not ignored" \
":: ${subdir}ignored-but-in-index" \
"test_check_ignore '${subdir}ignored-but-in-index' 1"
+ test_expect_success_no_index_multi "existing tracked file $where shown as ignored" \
+ ".gitignore:2:ignored-* ${subdir}ignored-but-in-index" \
+ "test_check_ignore '${subdir}ignored-but-in-index'"
+
test_expect_success_multi "existing untracked file $where ignored" \
".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
"test_check_ignore '${subdir}ignored-and-untracked'"
+ test_expect_success_no_index_multi "existing untracked file $where ignored" \
+ ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
+ "test_check_ignore '${subdir}ignored-and-untracked'"
+
test_expect_success_multi "mix of file types $where" \
":: ${subdir}non-existent
.gitignore:1:one ${subdir}one
:: ${subdir}not-ignored
:: ${subdir}ignored-but-in-index
+.gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
+ "test_check_ignore '
+ ${subdir}non-existent
+ ${subdir}one
+ ${subdir}not-ignored
+ ${subdir}ignored-but-in-index
+ ${subdir}ignored-and-untracked'
+ "
+
+ test_expect_success_no_index_multi "mix of file types $where" \
+":: ${subdir}non-existent
+.gitignore:1:one ${subdir}one
+:: ${subdir}not-ignored
+.gitignore:2:ignored-* ${subdir}ignored-but-in-index
.gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
"test_check_ignore '
${subdir}non-existent
test_expect_success_multi SYMLINKS 'beyond a symlink' '' '
test_check_ignore "a/symlink/foo" 128 &&
- test_stderr "fatal: '\''a/symlink/foo'\'' is beyond a symbolic link"
+ test_stderr "fatal: pathspec '\''a/symlink/foo'\'' is beyond a symbolic link"
'
test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '
cd a &&
test_check_ignore "symlink/foo" 128
) &&
- test_stderr "fatal: '\''symlink/foo'\'' is beyond a symbolic link"
+ test_stderr "fatal: pathspec '\''symlink/foo'\'' is beyond a symbolic link"
'
############################################################################
test_expect_success_multi 'submodule' '' '
test_check_ignore "a/submodule/one" 128 &&
- test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
+ test_stderr "fatal: Pathspec '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
'
test_expect_success_multi 'submodule from subdirectory' '' '
cd a &&
test_check_ignore "submodule/one" 128
) &&
- test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
+ test_stderr "fatal: Pathspec '\''submodule/one'\'' is in submodule '\''a/submodule'\''"
'
############################################################################
test_must_fail git add test.fc
'
+test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
+
+test_expect_success EXPENSIVE 'filter large file' '
+ git config filter.largefile.smudge cat &&
+ git config filter.largefile.clean cat &&
+ for i in $(test_seq 1 2048); do printf "%1048576d" 1; done >2GB &&
+ echo "2GB filter=largefile" >.gitattributes &&
+ git add 2GB 2>err &&
+ ! test -s err &&
+ rm -f 2GB &&
+ git checkout -- 2GB 2>err &&
+ ! test -s err
+'
+
test_done
test_expect_success "setup unicode normalization tests" '
test_create_repo unicode &&
cd unicode &&
+ git config core.precomposeunicode false &&
touch "$aumlcdiar" &&
git add "$aumlcdiar" &&
git commit -m initial &&
--- /dev/null
+#!/bin/sh
+
+test_description='"-C <path>" option and its effects on other path-related options'
+
+. ./test-lib.sh
+
+test_expect_success '"git -C <path>" runs git from the directory <path>' '
+ test_create_repo dir1 &&
+ echo 1 >dir1/a.txt &&
+ msg="initial in dir1" &&
+ (cd dir1 && git add a.txt && git commit -m "$msg") &&
+ echo "$msg" >expected &&
+ git -C dir1 log --format=%s >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Multiple -C options: "-C dir1 -C dir2" is equivalent to "-C dir1/dir2"' '
+ test_create_repo dir1/dir2 &&
+ echo 1 >dir1/dir2/b.txt &&
+ git -C dir1/dir2 add b.txt &&
+ msg="initial in dir1/dir2" &&
+ echo "$msg" >expected &&
+ git -C dir1/dir2 commit -m "$msg" &&
+ git -C dir1 -C dir2 log --format=%s >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Effect on --git-dir option: "-C c --git-dir=a.git" is equivalent to "--git-dir c/a.git"' '
+ mkdir c &&
+ mkdir c/a &&
+ mkdir c/a.git &&
+ (cd c/a.git && git init --bare) &&
+ echo 1 >c/a/a.txt &&
+ git --git-dir c/a.git --work-tree=c/a add a.txt &&
+ git --git-dir c/a.git --work-tree=c/a commit -m "initial" &&
+ git --git-dir=c/a.git log -1 --format=%s >expected &&
+ git -C c --git-dir=a.git log -1 --format=%s >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Order should not matter: "--git-dir=a.git -C c" is equivalent to "-C c --git-dir=a.git"' '
+ git -C c --git-dir=a.git log -1 --format=%s >expected &&
+ git --git-dir=a.git -C c log -1 --format=%s >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Effect on --work-tree option: "-C c/a.git --work-tree=../a" is equivalent to "--work-tree=c/a --git-dir=c/a.git"' '
+ rm c/a/a.txt &&
+ git --git-dir=c/a.git --work-tree=c/a status >expected &&
+ git -C c/a.git --work-tree=../a status >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Order should not matter: "--work-tree=../a -C c/a.git" is equivalent to "-C c/a.git --work-tree=../a"' '
+ git -C c/a.git --work-tree=../a status >expected &&
+ git --work-tree=../a -C c/a.git status >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Effect on --git-dir and --work-tree options - "-C c --git-dir=a.git --work-tree=a" is equivalent to "--git-dir=c/a.git --work-tree=c/a"' '
+ git --git-dir=c/a.git --work-tree=c/a status >expected &&
+ git -C c --git-dir=a.git --work-tree=a status >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Order should not matter: "-C c --git-dir=a.git --work-tree=a" is equivalent to "--git-dir=a.git -C c --work-tree=a"' '
+ git -C c --git-dir=a.git --work-tree=a status >expected &&
+ git --git-dir=a.git -C c --work-tree=a status >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Order should not matter: "-C c --git-dir=a.git --work-tree=a" is equivalent to "--git-dir=a.git --work-tree=a -C c"' '
+ git -C c --git-dir=a.git --work-tree=a status >expected &&
+ git --git-dir=a.git --work-tree=a -C c status >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'Relative followed by fullpath: "-C ./here -C /there" is equivalent to "-C /there"' '
+ echo "initial in dir1/dir2" >expected &&
+ git -C dir1 -C "$(pwd)/dir1/dir2" log --format=%s >actual &&
+ test_cmp expected actual
+'
+
+test_done
. ./test-lib.sh
norm_path() {
- expected=$(test-path-utils mingw_path "$2")
+ expected=$(test-path-utils print_path "$2")
test_expect_success $3 "normalize path: $1 => $2" \
"test \"\$(test-path-utils normalize_path_copy '$1')\" = '$expected'"
}
relative_path() {
- expected=$(test-path-utils mingw_path "$3")
+ expected=$(test-path-utils print_path "$3")
test_expect_success $4 "relative path: $1 $2 => $3" \
"test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
}
test "$sym" = "$(test-path-utils real_path "$dir2/syml")"
'
-relative_path /a/b/c/ /a/b/ c/
-relative_path /a/b/c/ /a/b c/
-relative_path /a//b//c/ //a/b// c/ POSIX
-relative_path /a/b /a/b ./
-relative_path /a/b/ /a/b ./
-relative_path /a /a/b ../
-relative_path / /a/b/ ../../
-relative_path /a/c /a/b/ ../c
-relative_path /a/c /a/b ../c
-relative_path /x/y /a/b/ ../../x/y
-relative_path /a/b "<empty>" /a/b
-relative_path /a/b "<null>" /a/b
-relative_path a/b/c/ a/b/ c/
-relative_path a/b/c/ a/b c/
-relative_path a/b//c a//b c
-relative_path a/b/ a/b/ ./
-relative_path a/b/ a/b ./
-relative_path a a/b ../
-relative_path x/y a/b ../../x/y
-relative_path a/c a/b ../c
-relative_path a/b "<empty>" a/b
-relative_path a/b "<null>" a/b
-relative_path "<empty>" /a/b ./
-relative_path "<empty>" "<empty>" ./
-relative_path "<empty>" "<null>" ./
-relative_path "<null>" "<empty>" ./
-relative_path "<null>" "<null>" ./
-relative_path "<null>" /a/b ./
+relative_path /foo/a/b/c/ /foo/a/b/ c/
+relative_path /foo/a/b/c/ /foo/a/b c/
+relative_path /foo/a//b//c/ ///foo/a/b// c/ POSIX
+relative_path /foo/a/b /foo/a/b ./
+relative_path /foo/a/b/ /foo/a/b ./
+relative_path /foo/a /foo/a/b ../
+relative_path / /foo/a/b/ ../../../
+relative_path /foo/a/c /foo/a/b/ ../c
+relative_path /foo/a/c /foo/a/b ../c
+relative_path /foo/x/y /foo/a/b/ ../../x/y
+relative_path /foo/a/b "<empty>" /foo/a/b
+relative_path /foo/a/b "<null>" /foo/a/b
+relative_path foo/a/b/c/ foo/a/b/ c/
+relative_path foo/a/b/c/ foo/a/b c/
+relative_path foo/a/b//c foo/a//b c
+relative_path foo/a/b/ foo/a/b/ ./
+relative_path foo/a/b/ foo/a/b ./
+relative_path foo/a foo/a/b ../
+relative_path foo/x/y foo/a/b ../../x/y
+relative_path foo/a/c foo/a/b ../c
+relative_path foo/a/b /foo/x/y foo/a/b
+relative_path /foo/a/b foo/x/y /foo/a/b
+relative_path d:/a/b D:/a/c ../b MINGW
+relative_path C:/a/b D:/a/c C:/a/b MINGW
+relative_path foo/a/b "<empty>" foo/a/b
+relative_path foo/a/b "<null>" foo/a/b
+relative_path "<empty>" /foo/a/b ./
+relative_path "<empty>" "<empty>" ./
+relative_path "<empty>" "<null>" ./
+relative_path "<null>" "<empty>" ./
+relative_path "<null>" "<null>" ./
+relative_path "<null>" /foo/a/b ./
test_done
grep "cannotwrite/test" err
'
+test_expect_success 'git_mkstemps_mode does not fail if fd 0 is not open' '
+ git commit --allow-empty -m message <&-
+'
+
test_expect_success 'check for a bug in the regex routines' '
# if this test fails, re-build git with NO_REGEX=1
test-regex
--- /dev/null
+#!/bin/sh
+
+test_description='urlmatch URL normalization'
+. ./test-lib.sh
+
+# The base name of the test url files
+tu="$TEST_DIRECTORY/t0110/url"
+
+# Note that only file: URLs should be allowed without a host
+
+test_expect_success 'url scheme' '
+ ! test-urlmatch-normalization "" &&
+ ! test-urlmatch-normalization "_" &&
+ ! test-urlmatch-normalization "scheme" &&
+ ! test-urlmatch-normalization "scheme:" &&
+ ! test-urlmatch-normalization "scheme:/" &&
+ ! test-urlmatch-normalization "scheme://" &&
+ ! test-urlmatch-normalization "file" &&
+ ! test-urlmatch-normalization "file:" &&
+ ! test-urlmatch-normalization "file:/" &&
+ test-urlmatch-normalization "file://" &&
+ ! test-urlmatch-normalization "://acme.co" &&
+ ! test-urlmatch-normalization "x_test://acme.co" &&
+ ! test-urlmatch-normalization "-test://acme.co" &&
+ ! test-urlmatch-normalization "0test://acme.co" &&
+ ! test-urlmatch-normalization "+test://acme.co" &&
+ ! test-urlmatch-normalization ".test://acme.co" &&
+ ! test-urlmatch-normalization "schem%6e://" &&
+ test-urlmatch-normalization "x-Test+v1.0://acme.co" &&
+ test "$(test-urlmatch-normalization -p "AbCdeF://x.Y")" = "abcdef://x.y/"
+'
+
+test_expect_success 'url authority' '
+ ! test-urlmatch-normalization "scheme://user:pass@" &&
+ ! test-urlmatch-normalization "scheme://?" &&
+ ! test-urlmatch-normalization "scheme://#" &&
+ ! test-urlmatch-normalization "scheme:///" &&
+ ! test-urlmatch-normalization "scheme://:" &&
+ ! test-urlmatch-normalization "scheme://:555" &&
+ test-urlmatch-normalization "file://user:pass@" &&
+ test-urlmatch-normalization "file://?" &&
+ test-urlmatch-normalization "file://#" &&
+ test-urlmatch-normalization "file:///" &&
+ test-urlmatch-normalization "file://:" &&
+ ! test-urlmatch-normalization "file://:555" &&
+ test-urlmatch-normalization "scheme://user:pass@host" &&
+ test-urlmatch-normalization "scheme://@host" &&
+ test-urlmatch-normalization "scheme://%00@host" &&
+ ! test-urlmatch-normalization "scheme://%%@host" &&
+ ! test-urlmatch-normalization "scheme://host_" &&
+ test-urlmatch-normalization "scheme://user:pass@host/" &&
+ test-urlmatch-normalization "scheme://@host/" &&
+ test-urlmatch-normalization "scheme://host/" &&
+ test-urlmatch-normalization "scheme://host?x" &&
+ test-urlmatch-normalization "scheme://host#x" &&
+ test-urlmatch-normalization "scheme://host/@" &&
+ test-urlmatch-normalization "scheme://host?@x" &&
+ test-urlmatch-normalization "scheme://host#@x" &&
+ test-urlmatch-normalization "scheme://[::1]" &&
+ test-urlmatch-normalization "scheme://[::1]/" &&
+ ! test-urlmatch-normalization "scheme://hos%41/" &&
+ test-urlmatch-normalization "scheme://[invalid....:/" &&
+ test-urlmatch-normalization "scheme://invalid....:]/" &&
+ ! test-urlmatch-normalization "scheme://invalid....:[/" &&
+ ! test-urlmatch-normalization "scheme://invalid....:["
+'
+
+test_expect_success 'url port checks' '
+ test-urlmatch-normalization "xyz://q@some.host:" &&
+ test-urlmatch-normalization "xyz://q@some.host:456/" &&
+ ! test-urlmatch-normalization "xyz://q@some.host:0" &&
+ ! test-urlmatch-normalization "xyz://q@some.host:0000000" &&
+ test-urlmatch-normalization "xyz://q@some.host:0000001?" &&
+ test-urlmatch-normalization "xyz://q@some.host:065535#" &&
+ test-urlmatch-normalization "xyz://q@some.host:65535" &&
+ ! test-urlmatch-normalization "xyz://q@some.host:65536" &&
+ ! test-urlmatch-normalization "xyz://q@some.host:99999" &&
+ ! test-urlmatch-normalization "xyz://q@some.host:100000" &&
+ ! test-urlmatch-normalization "xyz://q@some.host:100001" &&
+ test-urlmatch-normalization "http://q@some.host:80" &&
+ test-urlmatch-normalization "https://q@some.host:443" &&
+ test-urlmatch-normalization "http://q@some.host:80/" &&
+ test-urlmatch-normalization "https://q@some.host:443?" &&
+ ! test-urlmatch-normalization "http://q@:8008" &&
+ ! test-urlmatch-normalization "http://:8080" &&
+ ! test-urlmatch-normalization "http://:" &&
+ test-urlmatch-normalization "xyz://q@some.host:456/" &&
+ test-urlmatch-normalization "xyz://[::1]:456/" &&
+ test-urlmatch-normalization "xyz://[::1]:/" &&
+ ! test-urlmatch-normalization "xyz://[::1]:000/" &&
+ ! test-urlmatch-normalization "xyz://[::1]:0%300/" &&
+ ! test-urlmatch-normalization "xyz://[::1]:0x80/" &&
+ ! test-urlmatch-normalization "xyz://[::1]:4294967297/" &&
+ ! test-urlmatch-normalization "xyz://[::1]:030f/"
+'
+
+test_expect_success 'url port normalization' '
+ test "$(test-urlmatch-normalization -p "http://x:800")" = "http://x:800/" &&
+ test "$(test-urlmatch-normalization -p "http://x:0800")" = "http://x:800/" &&
+ test "$(test-urlmatch-normalization -p "http://x:00000800")" = "http://x:800/" &&
+ test "$(test-urlmatch-normalization -p "http://x:065535")" = "http://x:65535/" &&
+ test "$(test-urlmatch-normalization -p "http://x:1")" = "http://x:1/" &&
+ test "$(test-urlmatch-normalization -p "http://x:80")" = "http://x/" &&
+ test "$(test-urlmatch-normalization -p "http://x:080")" = "http://x/" &&
+ test "$(test-urlmatch-normalization -p "http://x:000000080")" = "http://x/" &&
+ test "$(test-urlmatch-normalization -p "https://x:443")" = "https://x/" &&
+ test "$(test-urlmatch-normalization -p "https://x:0443")" = "https://x/" &&
+ test "$(test-urlmatch-normalization -p "https://x:000000443")" = "https://x/"
+'
+
+test_expect_success 'url general escapes' '
+ ! test-urlmatch-normalization "http://x.y?%fg" &&
+ test "$(test-urlmatch-normalization -p "X://W/%7e%41^%3a")" = "x://w/~A%5E%3A" &&
+ test "$(test-urlmatch-normalization -p "X://W/:/?#[]@")" = "x://w/:/?#[]@" &&
+ test "$(test-urlmatch-normalization -p "X://W/$&()*+,;=")" = "x://w/$&()*+,;=" &&
+ test "$(test-urlmatch-normalization -p "X://W/'\''")" = "x://w/'\''" &&
+ test "$(test-urlmatch-normalization -p "X://W?'\!'")" = "x://w/?'\!'"
+'
+
+test_expect_success 'url high-bit escapes' '
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-1")")" = "x://q/%01%02%03%04%05%06%07%08%0E%0F%10%11%12" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-2")")" = "x://q/%13%14%15%16%17%18%19%1B%1C%1D%1E%1F%7F" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-3")")" = "x://q/%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-4")")" = "x://q/%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-5")")" = "x://q/%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-6")")" = "x://q/%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-7")")" = "x://q/%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-8")")" = "x://q/%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-9")")" = "x://q/%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-10")")" = "x://q/%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF" &&
+ test "$(test-urlmatch-normalization -p "$(cat "$tu-11")")" = "x://q/%C2%80%DF%BF%E0%A0%80%EF%BF%BD%F0%90%80%80%F0%AF%BF%BD"
+'
+
+test_expect_success 'url username/password escapes' '
+ test "$(test-urlmatch-normalization -p "x://%41%62(^):%70+d@foo")" = "x://Ab(%5E):p+d@foo/"
+'
+
+test_expect_success 'url normalized lengths' '
+ test "$(test-urlmatch-normalization -l "Http://%4d%65:%4d^%70@The.Host")" = 25 &&
+ test "$(test-urlmatch-normalization -l "http://%41:%42@x.y/%61/")" = 17 &&
+ test "$(test-urlmatch-normalization -l "http://@x.y/^")" = 15
+'
+
+test_expect_success 'url . and .. segments' '
+ test "$(test-urlmatch-normalization -p "x://y/.")" = "x://y/" &&
+ test "$(test-urlmatch-normalization -p "x://y/./")" = "x://y/" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/.")" = "x://y/a" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/./")" = "x://y/a/" &&
+ test "$(test-urlmatch-normalization -p "x://y/.?")" = "x://y/?" &&
+ test "$(test-urlmatch-normalization -p "x://y/./?")" = "x://y/?" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/.?")" = "x://y/a?" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/./?")" = "x://y/a/?" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/./b/.././../c")" = "x://y/c" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/./b/../.././c/")" = "x://y/c/" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/./b/.././../c/././.././.")" = "x://y/" &&
+ ! test-urlmatch-normalization "x://y/a/./b/.././../c/././.././.." &&
+ test "$(test-urlmatch-normalization -p "x://y/a/./?/././..")" = "x://y/a/?/././.." &&
+ test "$(test-urlmatch-normalization -p "x://y/%2e/")" = "x://y/" &&
+ test "$(test-urlmatch-normalization -p "x://y/%2E/")" = "x://y/" &&
+ test "$(test-urlmatch-normalization -p "x://y/a/%2e./")" = "x://y/" &&
+ test "$(test-urlmatch-normalization -p "x://y/b/.%2E/")" = "x://y/" &&
+ test "$(test-urlmatch-normalization -p "x://y/c/%2e%2E/")" = "x://y/"
+'
+
+# http://@foo specifies an empty user name but does not specify a password
+# http://foo specifies neither a user name nor a password
+# So they should not be equivalent
+test_expect_success 'url equivalents' '
+ test-urlmatch-normalization "httP://x" "Http://X/" &&
+ test-urlmatch-normalization "Http://%4d%65:%4d^%70@The.Host" "hTTP://Me:%4D^p@the.HOST:80/" &&
+ ! test-urlmatch-normalization "https://@x.y/^" "httpS://x.y:443/^" &&
+ test-urlmatch-normalization "https://@x.y/^" "httpS://@x.y:0443/^" &&
+ test-urlmatch-normalization "https://@x.y/^/../abc" "httpS://@x.y:0443/abc" &&
+ test-urlmatch-normalization "https://@x.y/^/.." "httpS://@x.y:0443/"
+'
+
+test_done
--- /dev/null
+The url data files in this directory contain URLs with characters
+in the range 0x01-0x1f and 0x7f-0xff to test the proper normalization
+of unprintable characters.
+
+A select few characters in the 0x01-0x1f range are skipped to help
+avoid problems running the test itself.
+
+The urls are in test files in this directory rather than being
+embedded in the test script for portability.
echo $sha1 | git cat-file --batch-check="%(objecttype) %(objectname)" >actual &&
test_cmp expect actual
'
+
+ test_expect_success '--batch-check with %(rest)' '
+ echo "$type this is some extra content" >expect &&
+ echo "$sha1 this is some extra content" |
+ git cat-file --batch-check="%(objecttype) %(rest)" >actual &&
+ test_cmp expect actual
+ '
}
hello_content="Hello World"
run_tests 'blob' $hello_sha1 $hello_size "$hello_content" "$hello_content"
+test_expect_success '--batch-check without %(rest) considers whole line' '
+ echo "$hello_sha1 blob $hello_size" >expect &&
+ git update-index --add --cacheinfo 100644 $hello_sha1 "white space" &&
+ test_when_finished "git update-index --remove \"white space\"" &&
+ echo ":white space" | git cat-file --batch-check >actual &&
+ test_cmp expect actual
+'
+
tree_sha1=$(git write-tree)
tree_size=33
tree_pretty_content="100644 blob $hello_sha1 hello"
test_cmp expect actual
'
+test_expect_success '--int is at least 64 bits' '
+ git config giga.watts 121g &&
+ echo 129922760704 >expect &&
+ git config --int --get giga.watts >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'invalid unit' '
git config aninvalid.unit "1auto" &&
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
+ cat >expect <<-\EOF
+ fatal: bad numeric config value '\''1auto'\'' for '\''aninvalid.unit'\'' in .git/config: invalid unit
EOF
test_must_fail git config --int --get aninvalid.unit 2>actual &&
- test_cmp actual expect
+ test_i18ncmp expect actual
'
cat > expect << EOF
grep " line 3 " error
'
+test_expect_success 'urlmatch' '
+ cat >.git/config <<-\EOF &&
+ [http]
+ sslVerify
+ [http "https://weak.example.com"]
+ sslVerify = false
+ cookieFile = /tmp/cookie.txt
+ EOF
+
+ echo true >expect &&
+ git config --bool --get-urlmatch http.SSLverify https://good.example.com >actual &&
+ test_cmp expect actual &&
+
+ echo false >expect &&
+ git config --bool --get-urlmatch http.sslverify https://weak.example.com >actual &&
+ test_cmp expect actual &&
+
+ {
+ echo http.cookiefile /tmp/cookie.txt &&
+ echo http.sslverify false
+ } >expect &&
+ git config --get-urlmatch HTTP https://weak.example.com >actual &&
+ test_cmp expect actual
+'
+
# good section hygiene
test_expect_failure 'unsetting the last key in a section removes header' '
cat >.git/config <<-\EOF &&
'git cat-file blob master@{2005-05-26 23:42}:F (expect OTHER)' \
'test OTHER = $(git cat-file blob "master@{2005-05-26 23:42}:F")'
+a=refs/heads/a
+b=refs/heads/b
+c=refs/heads/c
+E='""'
+F='%s\0'
+pws='path with space'
+
+test_expect_success 'stdin test setup' '
+ echo "$pws" >"$pws" &&
+ git add -- "$pws" &&
+ git commit -m "$pws"
+'
+
+test_expect_success '-z fails without --stdin' '
+ test_must_fail git update-ref -z $m $m $m 2>err &&
+ grep "usage: git update-ref" err
+'
+
+test_expect_success 'stdin works with no input' '
+ >stdin &&
+ git update-ref --stdin <stdin &&
+ git rev-parse --verify -q $m
+'
+
+test_expect_success 'stdin fails on empty line' '
+ echo "" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: empty command in input" err
+'
+
+test_expect_success 'stdin fails on only whitespace' '
+ echo " " >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: whitespace before command: " err
+'
+
+test_expect_success 'stdin fails on leading whitespace' '
+ echo " create $a $m" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: whitespace before command: create $a $m" err
+'
+
+test_expect_success 'stdin fails on unknown command' '
+ echo "unknown $a" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: unknown command: unknown $a" err
+'
+
+test_expect_success 'stdin fails on badly quoted input' '
+ echo "create $a \"master" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: badly quoted argument: \\\"master" err
+'
+
+test_expect_success 'stdin fails on arguments not separated by space' '
+ echo "create \"$a\"master" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: expected SP but got: master" err
+'
+
+test_expect_success 'stdin fails create with no ref' '
+ echo "create " >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: create line missing <ref>" err
+'
+
+test_expect_success 'stdin fails create with bad ref name' '
+ echo "create ~a $m" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: invalid ref format: ~a" err
+'
+
+test_expect_success 'stdin fails create with no new value' '
+ echo "create $a" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: create $a missing <newvalue>" err
+'
+
+test_expect_success 'stdin fails create with too many arguments' '
+ echo "create $a $m $m" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: create $a has extra input: $m" err
+'
+
+test_expect_success 'stdin fails update with no ref' '
+ echo "update " >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: update line missing <ref>" err
+'
+
+test_expect_success 'stdin fails update with bad ref name' '
+ echo "update ~a $m" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: invalid ref format: ~a" err
+'
+
+test_expect_success 'stdin fails update with no new value' '
+ echo "update $a" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: update $a missing <newvalue>" err
+'
+
+test_expect_success 'stdin fails update with too many arguments' '
+ echo "update $a $m $m $m" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: update $a has extra input: $m" err
+'
+
+test_expect_success 'stdin fails delete with no ref' '
+ echo "delete " >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: delete line missing <ref>" err
+'
+
+test_expect_success 'stdin fails delete with bad ref name' '
+ echo "delete ~a $m" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: invalid ref format: ~a" err
+'
+
+test_expect_success 'stdin fails delete with too many arguments' '
+ echo "delete $a $m $m" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: delete $a has extra input: $m" err
+'
+
+test_expect_success 'stdin fails verify with too many arguments' '
+ echo "verify $a $m $m" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: verify $a has extra input: $m" err
+'
+
+test_expect_success 'stdin fails option with unknown name' '
+ echo "option unknown" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: option unknown: unknown" err
+'
+
+test_expect_success 'stdin fails with duplicate refs' '
+ cat >stdin <<-EOF &&
+ create $a $m
+ create $b $m
+ create $a $m
+ EOF
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: Multiple updates for ref '"'"'$a'"'"' not allowed." err
+'
+
+test_expect_success 'stdin create ref works' '
+ echo "create $a $m" >stdin &&
+ git update-ref --stdin <stdin &&
+ git rev-parse $m >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin update ref creates with zero old value' '
+ echo "update $b $m $Z" >stdin &&
+ git update-ref --stdin <stdin &&
+ git rev-parse $m >expect &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual &&
+ git update-ref -d $b
+'
+
+test_expect_success 'stdin update ref creates with empty old value' '
+ echo "update $b $m $E" >stdin &&
+ git update-ref --stdin <stdin &&
+ git rev-parse $m >expect &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin create ref works with path with space to blob' '
+ echo "create refs/blobs/pws \"$m:$pws\"" >stdin &&
+ git update-ref --stdin <stdin &&
+ git rev-parse "$m:$pws" >expect &&
+ git rev-parse refs/blobs/pws >actual &&
+ test_cmp expect actual &&
+ git update-ref -d refs/blobs/pws
+'
+
+test_expect_success 'stdin update ref fails with wrong old value' '
+ echo "update $c $m $m~1" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin update ref fails with bad old value' '
+ echo "update $c $m does-not-exist" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: invalid old value for ref $c: does-not-exist" err &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin create ref fails with bad new value' '
+ echo "create $c does-not-exist" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: invalid new value for ref $c: does-not-exist" err &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin create ref fails with zero new value' '
+ echo "create $c " >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: create $c given zero new value" err &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin update ref works with right old value' '
+ echo "update $b $m~1 $m" >stdin &&
+ git update-ref --stdin <stdin &&
+ git rev-parse $m~1 >expect &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin delete ref fails with wrong old value' '
+ echo "delete $a $m~1" >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: Cannot lock the ref '"'"'$a'"'"'" err &&
+ git rev-parse $m >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin delete ref fails with zero old value' '
+ echo "delete $a " >stdin &&
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: delete $a given zero old value" err &&
+ git rev-parse $m >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin update symref works option no-deref' '
+ git symbolic-ref TESTSYMREF $b &&
+ cat >stdin <<-EOF &&
+ option no-deref
+ update TESTSYMREF $a $b
+ EOF
+ git update-ref --stdin <stdin &&
+ git rev-parse TESTSYMREF >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual &&
+ git rev-parse $m~1 >expect &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin delete symref works option no-deref' '
+ git symbolic-ref TESTSYMREF $b &&
+ cat >stdin <<-EOF &&
+ option no-deref
+ delete TESTSYMREF $b
+ EOF
+ git update-ref --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q TESTSYMREF &&
+ git rev-parse $m~1 >expect &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin delete ref works with right old value' '
+ echo "delete $b $m~1" >stdin &&
+ git update-ref --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q $b
+'
+
+test_expect_success 'stdin update/create/verify combination works' '
+ cat >stdin <<-EOF &&
+ update $a $m
+ create $b $m
+ verify $c
+ EOF
+ git update-ref --stdin <stdin &&
+ git rev-parse $m >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin update refs works with identity updates' '
+ cat >stdin <<-EOF &&
+ update $a $m $m
+ update $b $m $m
+ update $c $Z $E
+ EOF
+ git update-ref --stdin <stdin &&
+ git rev-parse $m >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin update refs fails with wrong old value' '
+ git update-ref $c $m &&
+ cat >stdin <<-EOF &&
+ update $a $m $m
+ update $b $m $m
+ update $c ''
+ EOF
+ test_must_fail git update-ref --stdin <stdin 2>err &&
+ grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err &&
+ git rev-parse $m >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual &&
+ git rev-parse $c >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin delete refs works with packed and loose refs' '
+ git pack-refs --all &&
+ git update-ref $c $m~1 &&
+ cat >stdin <<-EOF &&
+ delete $a $m
+ update $b $Z $m
+ update $c $E $m~1
+ EOF
+ git update-ref --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q $a &&
+ test_must_fail git rev-parse --verify -q $b &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z works on empty input' '
+ >stdin &&
+ git update-ref -z --stdin <stdin &&
+ git rev-parse --verify -q $m
+'
+
+test_expect_success 'stdin -z fails on empty line' '
+ echo "" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: whitespace before command: " err
+'
+
+test_expect_success 'stdin -z fails on empty command' '
+ printf $F "" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: empty command in input" err
+'
+
+test_expect_success 'stdin -z fails on only whitespace' '
+ printf $F " " >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: whitespace before command: " err
+'
+
+test_expect_success 'stdin -z fails on leading whitespace' '
+ printf $F " create $a" "$m" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: whitespace before command: create $a" err
+'
+
+test_expect_success 'stdin -z fails on unknown command' '
+ printf $F "unknown $a" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: unknown command: unknown $a" err
+'
+
+test_expect_success 'stdin -z fails create with no ref' '
+ printf $F "create " >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: create line missing <ref>" err
+'
+
+test_expect_success 'stdin -z fails create with bad ref name' '
+ printf $F "create ~a " "$m" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: invalid ref format: ~a " err
+'
+
+test_expect_success 'stdin -z fails create with no new value' '
+ printf $F "create $a" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: create $a missing <newvalue>" err
+'
+
+test_expect_success 'stdin -z fails create with too many arguments' '
+ printf $F "create $a" "$m" "$m" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: unknown command: $m" err
+'
+
+test_expect_success 'stdin -z fails update with no ref' '
+ printf $F "update " >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: update line missing <ref>" err
+'
+
+test_expect_success 'stdin -z fails update with bad ref name' '
+ printf $F "update ~a" "$m" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: invalid ref format: ~a" err
+'
+
+test_expect_success 'stdin -z fails update with no new value' '
+ printf $F "update $a" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: update $a missing <newvalue>" err
+'
+
+test_expect_success 'stdin -z fails update with no old value' '
+ printf $F "update $a" "$m" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: update $a missing \\[<oldvalue>\\] NUL" err
+'
+
+test_expect_success 'stdin -z fails update with too many arguments' '
+ printf $F "update $a" "$m" "$m" "$m" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: unknown command: $m" err
+'
+
+test_expect_success 'stdin -z fails delete with no ref' '
+ printf $F "delete " >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: delete line missing <ref>" err
+'
+
+test_expect_success 'stdin -z fails delete with bad ref name' '
+ printf $F "delete ~a" "$m" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: invalid ref format: ~a" err
+'
+
+test_expect_success 'stdin -z fails delete with no old value' '
+ printf $F "delete $a" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: delete $a missing \\[<oldvalue>\\] NUL" err
+'
+
+test_expect_success 'stdin -z fails delete with too many arguments' '
+ printf $F "delete $a" "$m" "$m" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: unknown command: $m" err
+'
+
+test_expect_success 'stdin -z fails verify with too many arguments' '
+ printf $F "verify $a" "$m" "$m" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: unknown command: $m" err
+'
+
+test_expect_success 'stdin -z fails verify with no old value' '
+ printf $F "verify $a" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: verify $a missing \\[<oldvalue>\\] NUL" err
+'
+
+test_expect_success 'stdin -z fails option with unknown name' '
+ printf $F "option unknown" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: option unknown: unknown" err
+'
+
+test_expect_success 'stdin -z fails with duplicate refs' '
+ printf $F "create $a" "$m" "create $b" "$m" "create $a" "$m" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: Multiple updates for ref '"'"'$a'"'"' not allowed." err
+'
+
+test_expect_success 'stdin -z create ref works' '
+ printf $F "create $a" "$m" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ git rev-parse $m >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z update ref creates with zero old value' '
+ printf $F "update $b" "$m" "$Z" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ git rev-parse $m >expect &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual &&
+ git update-ref -d $b
+'
+
+test_expect_success 'stdin -z update ref creates with empty old value' '
+ printf $F "update $b" "$m" "" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ git rev-parse $m >expect &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z create ref works with path with space to blob' '
+ printf $F "create refs/blobs/pws" "$m:$pws" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ git rev-parse "$m:$pws" >expect &&
+ git rev-parse refs/blobs/pws >actual &&
+ test_cmp expect actual &&
+ git update-ref -d refs/blobs/pws
+'
+
+test_expect_success 'stdin -z update ref fails with wrong old value' '
+ printf $F "update $c" "$m" "$m~1" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z update ref fails with bad old value' '
+ printf $F "update $c" "$m" "does-not-exist" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: invalid old value for ref $c: does-not-exist" err &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z create ref fails with bad new value' '
+ printf $F "create $c" "does-not-exist" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: invalid new value for ref $c: does-not-exist" err &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z create ref fails with zero new value' '
+ printf $F "create $c" "" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: create $c given zero new value" err &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z update ref works with right old value' '
+ printf $F "update $b" "$m~1" "$m" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ git rev-parse $m~1 >expect &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z delete ref fails with wrong old value' '
+ printf $F "delete $a" "$m~1" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: Cannot lock the ref '"'"'$a'"'"'" err &&
+ git rev-parse $m >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z delete ref fails with zero old value' '
+ printf $F "delete $a" "$Z" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: delete $a given zero old value" err &&
+ git rev-parse $m >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z update symref works option no-deref' '
+ git symbolic-ref TESTSYMREF $b &&
+ printf $F "option no-deref" "update TESTSYMREF" "$a" "$b" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ git rev-parse TESTSYMREF >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual &&
+ git rev-parse $m~1 >expect &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z delete symref works option no-deref' '
+ git symbolic-ref TESTSYMREF $b &&
+ printf $F "option no-deref" "delete TESTSYMREF" "$b" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q TESTSYMREF &&
+ git rev-parse $m~1 >expect &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z delete ref works with right old value' '
+ printf $F "delete $b" "$m~1" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q $b
+'
+
+test_expect_success 'stdin -z update/create/verify combination works' '
+ printf $F "update $a" "$m" "" "create $b" "$m" "verify $c" "" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ git rev-parse $m >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z update refs works with identity updates' '
+ printf $F "update $a" "$m" "$m" "update $b" "$m" "$m" "update $c" "$Z" "" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ git rev-parse $m >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z update refs fails with wrong old value' '
+ git update-ref $c $m &&
+ printf $F "update $a" "$m" "$m" "update $b" "$m" "$m" "update $c" "" "$Z" >stdin &&
+ test_must_fail git update-ref -z --stdin <stdin 2>err &&
+ grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err &&
+ git rev-parse $m >expect &&
+ git rev-parse $a >actual &&
+ test_cmp expect actual &&
+ git rev-parse $b >actual &&
+ test_cmp expect actual &&
+ git rev-parse $c >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'stdin -z delete refs works with packed and loose refs' '
+ git pack-refs --all &&
+ git update-ref $c $m~1 &&
+ printf $F "delete $a" "$m" "update $b" "$Z" "$m" "update $c" "" "$m~1" >stdin &&
+ git update-ref -z --stdin <stdin &&
+ test_must_fail git rev-parse --verify -q $a &&
+ test_must_fail git rev-parse --verify -q $b &&
+ test_must_fail git rev-parse --verify -q $c
+'
+
test_done
test_cmp expect actual
'
+# This guards against the alternative of showing the diffs vs. the
+# reflog ancestor. The reflog used is designed to list the commits
+# more than once, so as to exercise the corresponding logic.
+test_expect_success 'git log -g -p shows diffs vs. parents' '
+ test_commit two &&
+ git branch flipflop &&
+ git update-ref refs/heads/flipflop -m flip1 HEAD^ &&
+ git update-ref refs/heads/flipflop -m flop1 HEAD &&
+ git update-ref refs/heads/flipflop -m flip2 HEAD^ &&
+ git log -g -p flipflop >reflog &&
+ grep -v ^Reflog reflog >actual &&
+ git log -1 -p HEAD^ >log.one &&
+ git log -1 -p HEAD >log.two &&
+ (
+ cat log.one; echo
+ cat log.two; echo
+ cat log.one; echo
+ cat log.two
+ ) >expect &&
+ test_cmp expect actual
+'
+
test_done
git checkout -b upstream-branch &&
test_commit upstream-one &&
test_commit upstream-two &&
+ git checkout -b @/at-test &&
+ git checkout -b @@/at-test &&
+ git checkout -b @at-test &&
git checkout -b old-branch &&
test_commit old-one &&
test_commit old-two &&
check "@{u}@{1}" commit upstream-one
check "@{-1}@{u}" ref refs/heads/master
check "@{-1}@{u}@{1}" commit master-one
+check "@" commit new-two
+check "@@{u}" ref refs/heads/upstream-branch
+check "@@/at-test" ref refs/heads/@@/at-test
+check "@/at-test" ref refs/heads/@/at-test
+check "@at-test" ref refs/heads/@at-test
nonsense "@{u}@{-1}"
nonsense "@{0}@{0}"
nonsense "@{1}@{u}"
test_must_fail git rev-parse blob-tag^{tree}
'
+test_expect_success 'ref^{tag}' '
+ test_must_fail git rev-parse HEAD^{tag} &&
+ git rev-parse commit-tag >expected &&
+ git rev-parse commit-tag^{tag} >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'ref^{/.}' '
git rev-parse master >expected &&
git rev-parse master^{/.} >actual &&
'
-# This is not expected to work as ls-files was not designed
-# to deal with such. Enable it when ls-files is updated.
-: test_expect_success 'checkout with complex relative path' '
-
- rm file1 &&
- git checkout HEAD -- ../dir1/../dir1/file1 && test -f ./file1
-
+test_expect_success 'checkout with complex relative path' '
+ (
+ cd dir1 &&
+ rm file1 &&
+ git checkout HEAD -- ../dir1/../dir1/file1 &&
+ test "hello" = "$(cat file1)"
+ )
'
test_expect_success 'relative path outside tree should fail' \
git diff --exit-code --quiet
'
+test_expect_success 'accurate error message with more than one ref' '
+ test_must_fail git checkout HEAD master -- 2>actual &&
+ grep 2 actual &&
+ test_i18ngrep "one reference expected, 2 given" actual
+'
+
test_done
cd repo_c &&
test_commit c_master &&
git checkout -b bar &&
- test_commit c_bar
+ test_commit c_bar &&
git checkout -b spam &&
test_commit c_spam
) &&
cd repo_d &&
test_commit d_master &&
git checkout -b baz &&
- test_commit f_baz
+ test_commit d_baz &&
git checkout -b eggs &&
- test_commit c_eggs
+ test_commit d_eggs
) &&
git remote add repo_c repo_c &&
git config remote.repo_c.fetch \
test_branch_upstream eggs repo_d eggs
'
+test_expect_success 'checkout of branch with a file having the same name fails' '
+ git checkout -B master &&
+ test_might_fail git branch -D spam &&
+
+ >spam &&
+ test_must_fail git checkout spam &&
+ test_must_fail git rev-parse --verify refs/heads/spam &&
+ test_branch master
+'
+
+test_expect_success 'checkout <branch> -- succeeds, even if a file with the same name exists' '
+ git checkout -B master &&
+ test_might_fail git branch -D spam &&
+
+ >spam &&
+ git checkout spam -- &&
+ test_branch spam &&
+ test_cmp_rev refs/remotes/extra_dir/repo_c/extra_dir/spam HEAD &&
+ test_branch_upstream spam repo_c spam
+'
+
test_done
git config core.excludesFile excludes-file
-git status | grep "^# " > output
+git -c status.displayCommentPrefix=true status | grep "^# " > output
cat > expect << EOF
# .gitignore
path1 - a symlink
path2/file2 - a file in a directory
path3/file3 - a file in a directory
+ pathx/ju - a file in a directory
submod1/ - a submodule
submod2/ - another submodule
path4 - a file
path5 - a symlink
path6/file6 - a file in a directory
+ pathx/ju/nk - a file in a directory to be killed
submod1/ - a submodule (modified from the cache)
submod2/ - a submodule (matches the cache)
test_expect_success 'git update-index --add to add various paths.' '
date >path0 &&
test_ln_s_add xyzzy path1 &&
- mkdir path2 path3 &&
+ mkdir path2 path3 pathx &&
date >path2/file2 &&
date >path3/file3 &&
+ >pathx/ju &&
: >path7 &&
date >path8 &&
: >path9 &&
date >path10 &&
- git update-index --add -- path0 path?/file? path7 path8 path9 path10 &&
+ git update-index --add -- path0 path?/file? pathx/ju path7 path8 path9 path10 &&
for i in 1 2
do
git init submod$i &&
date >path3 &&
date >path5
fi &&
- mkdir path0 path1 path6 &&
+ mkdir -p path0 path1 path6 pathx/ju &&
date >path0/file0 &&
date >path1/file1 &&
date >path6/file6 &&
: >path8 &&
: >path9 &&
touch path10 &&
- git ls-files -k >.output
-'
-
-test_expect_success 'validate git ls-files -k output.' '
- cat >.expected <<-\EOF &&
+ >pathx/ju/nk &&
+ cat >.expected <<-\EOF
path0/file0
path1/file1
path2
path3
+ pathx/ju/nk
EOF
+'
+
+test_expect_success 'git ls-files -k output (w/o icase)' '
+ git ls-files -k >.output
+ test_cmp .expected .output
+'
+
+test_expect_success 'git ls-files -k output (w/ icase)' '
+ git -c core.ignorecase=true ls-files -k >.output
test_cmp .expected .output
'
path3/file3
path7
path8
+ pathx/ju
submod1
EOF
test_cmp .expected .output
echo World >>A &&
git update-index --add A &&
git commit -m "Second commit." &&
- HEAD=$(git rev-parse --verify HEAD)'
+ HEAD=$(git rev-parse --verify HEAD)
+'
test_expect_success 'git branch --help should not have created a bogus branch' '
test_might_fail git branch --help </dev/null >/dev/null 2>/dev/null &&
test_expect_success 'tracking setup fails on non-matching refspec' '
git config remote.local.url . &&
- git config remote.local.fetch refs/heads/s:refs/remotes/local/s &&
+ git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
(git show-ref -q refs/remotes/local/master || git fetch local) &&
+ git config remote.local.fetch refs/heads/s:refs/remotes/local/s &&
test_must_fail git branch --track my5 local/master &&
test_must_fail git config branch.my5.remote &&
test_must_fail git config branch.my5.merge
test_expect_success 'no tracking without .fetch entries' '
git config branch.autosetupmerge true &&
git branch my6 s &&
- git config branch.automsetupmerge false &&
+ git config branch.autosetupmerge false &&
test -z "$(git config branch.my6.remote)" &&
test -z "$(git config branch.my6.merge)"
'
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 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 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 'test --unset-upstream on HEAD' '
- git branch my14
+ git branch my14 &&
test_config branch.master.remote foo &&
test_config branch.master.merge foo &&
git branch --set-upstream-to my14 &&
'
test_expect_success 'test --unset-upstream on a particular branch' '
- git branch my15
+ 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 branch --merged 0000000000000000000000000000000000000000
'
+test_expect_success 'tracking with unexpected .fetch refspec' '
+ rm -rf a b c d &&
+ git init a &&
+ (
+ cd a &&
+ test_commit a
+ ) &&
+ git init b &&
+ (
+ cd b &&
+ test_commit b
+ ) &&
+ git init c &&
+ (
+ cd c &&
+ test_commit c &&
+ git remote add a ../a &&
+ git remote add b ../b &&
+ git fetch --all
+ ) &&
+ git init d &&
+ (
+ cd d &&
+ git remote add c ../c &&
+ git config remote.c.fetch "+refs/remotes/*:refs/remotes/*" &&
+ git fetch c &&
+ git branch --track local/a/master remotes/a/master &&
+ test "$(git config branch.local/a/master.remote)" = "c" &&
+ test "$(git config branch.local/a/master.merge)" = "refs/remotes/a/master" &&
+ git rev-parse --verify a >expect &&
+ git rev-parse --verify local/a/master >actual &&
+ test_cmp expect actual
+ )
+'
+
test_done
. "$TEST_DIRECTORY"/lib-rebase.sh
-set_fake_editor
-
# WARNING: Modifications to the initial repository can change the SHA ID used
# in the expect2 file for the 'stop on conflicting pick' test.
test_expect_success 'rebase -i with the exec command' '
git checkout master &&
(
+ set_fake_editor &&
FAKE_LINES="1 exec_>touch-one
2 exec_>touch-two exec_false exec_>touch-three
3 4 exec_>\"touch-file__name_with_spaces\";_>touch-after-semicolon 5" &&
test_expect_success 'rebase -i with the exec command runs from tree root' '
git checkout master &&
mkdir subdir && (cd subdir &&
+ set_fake_editor &&
FAKE_LINES="1 exec_>touch-subdir" \
git rebase -i HEAD^
) &&
test_expect_success 'rebase -i with the exec command checks tree cleanness' '
git checkout master &&
(
+ set_fake_editor &&
FAKE_LINES="exec_echo_foo_>file1 1" &&
export FAKE_LINES &&
test_must_fail git rebase -i HEAD^
git checkout master &&
test_when_finished "git rebase --abort" &&
(
+ set_fake_editor &&
FAKE_LINES="exec_this-command-does-not-exist 1" &&
export FAKE_LINES &&
test_must_fail git rebase -i HEAD^ >actual 2>&1
test_expect_success 'no changes are a nop' '
git checkout branch2 &&
+ set_fake_editor &&
git rebase -i F &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
test $(git rev-parse I) = $(git rev-parse HEAD)
git checkout -b dead-end &&
git rm file6 &&
git commit -m "stop here" &&
+ set_fake_editor &&
git rebase -i F branch2 &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
test $(git rev-parse I) = $(git rev-parse branch2) &&
test_expect_success 'test --onto <branch>' '
git checkout -b test-onto branch2 &&
+ set_fake_editor &&
git rebase -i --onto branch1 F &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/test-onto" &&
test $(git rev-parse HEAD^) = $(git rev-parse branch1) &&
test_expect_success 'rebase on top of a non-conflicting commit' '
git checkout branch1 &&
git tag original-branch1 &&
+ set_fake_editor &&
git rebase -i branch2 &&
test file6 = $(git diff --name-only original-branch1) &&
test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
'
test_expect_success 'exchange two commits' '
+ set_fake_editor &&
FAKE_LINES="2 1" git rebase -i HEAD~2 &&
test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
test G = $(git cat-file commit HEAD | sed -ne \$p)
test_expect_success 'stop on conflicting pick' '
git tag new-branch1 &&
+ set_fake_editor &&
test_must_fail git rebase -i master &&
test "$(git rev-parse HEAD~3)" = "$(git rev-parse master)" &&
test_cmp expect .git/rebase-merge/patch &&
test_expect_success 'abort with error when new base cannot be checked out' '
git rm --cached file1 &&
git commit -m "remove file in base" &&
+ set_fake_editor &&
test_must_fail git rebase -i master > output 2>&1 &&
grep "The following untracked working tree files would be overwritten by checkout:" \
output &&
test_tick &&
GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
git tag twerp &&
+ set_fake_editor &&
git rebase -i --onto master HEAD^ &&
git show HEAD | grep "^Author: Twerp Snog"
'
test_tick &&
GIT_AUTHOR_NAME="Nitfol" git commit -m "nitfol" file7 &&
echo "******************************" &&
+ set_fake_editor &&
FAKE_LINES="1 squash 2" EXPECT_HEADER_COUNT=2 \
git rebase -i --onto master HEAD~2 &&
test B = $(cat file7) &&
test_expect_success '-p handles "no changes" gracefully' '
HEAD=$(git rev-parse HEAD) &&
+ set_fake_editor &&
git rebase -i -p HEAD^ &&
git update-index --refresh &&
git diff-files --quiet &&
test_expect_failure 'exchange two commits with -p' '
git checkout H &&
+ set_fake_editor &&
FAKE_LINES="2 1" git rebase -i -p HEAD~2 &&
test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
test G = $(git cat-file commit HEAD | sed -ne \$p)
git commit -m M file1 &&
git checkout -b to-be-rebased &&
test_tick &&
+ set_fake_editor &&
git rebase -i -p --onto branch1 master &&
git update-index --refresh &&
git diff-files --quiet &&
'
test_expect_success 'edit ancestor with -p' '
+ set_fake_editor &&
FAKE_LINES="1 2 edit 3 4" git rebase -i -p HEAD~3 &&
echo 2 > unrelated-file &&
test_tick &&
test_expect_success '--continue tries to commit' '
test_tick &&
+ set_fake_editor &&
test_must_fail git rebase -i --onto new-branch1 HEAD^ &&
echo resolved > file1 &&
git add file1 &&
test_expect_success 'verbose flag is heeded, even after --continue' '
git reset --hard master@{1} &&
test_tick &&
+ set_fake_editor &&
test_must_fail git rebase -v -i --onto new-branch1 HEAD^ &&
echo resolved > file1 &&
git add file1 &&
test_expect_success 'multi-squash only fires up editor once' '
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 squash 2 squash 3 squash 4" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
test_expect_success 'multi-fixup does not fire up editor' '
git checkout -b multi-fixup E &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="NEVER" FAKE_LINES="1 fixup 2 fixup 3 fixup 4" \
git rebase -i $base &&
test $base = $(git rev-parse HEAD^) &&
test_expect_success 'commit message used after conflict' '
git checkout -b conflict-fixup conflict-branch &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
(
FAKE_LINES="1 fixup 3 fixup 4" &&
export FAKE_LINES &&
test_expect_success 'commit message retained after conflict' '
git checkout -b conflict-squash conflict-branch &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
(
FAKE_LINES="1 fixup 3 squash 4" &&
export FAKE_LINES &&
test_expect_success 'squash and fixup generate correct log messages' '
git checkout -b squash-fixup E &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 squash 3 fixup 4" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
test_expect_success 'squash ignores comments' '
git checkout -b skip-comments E &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="# 1 # squash 2 # squash 3 # squash 4 #" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
test_expect_success 'squash ignores blank lines' '
git checkout -b skip-blank-lines E &&
base=$(git rev-parse HEAD~4) &&
+ set_fake_editor &&
FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="> 1 > squash 2 > squash 3 > squash 4 >" \
EXPECT_HEADER_COUNT=4 \
git rebase -i $base &&
test_expect_success 'squash works as expected' '
git checkout -b squash-works no-conflict-branch &&
one=$(git rev-parse HEAD~3) &&
+ set_fake_editor &&
FAKE_LINES="1 squash 3 2" EXPECT_HEADER_COUNT=2 \
git rebase -i HEAD~3 &&
test $one = $(git rev-parse HEAD~2)
test_expect_success 'interrupted squash works as expected' '
git checkout -b interrupted-squash conflict-branch &&
one=$(git rev-parse HEAD~3) &&
+ set_fake_editor &&
(
FAKE_LINES="1 squash 3 2" &&
export FAKE_LINES &&
test_expect_success 'interrupted squash works as expected (case 2)' '
git checkout -b interrupted-squash2 conflict-branch &&
one=$(git rev-parse HEAD~3) &&
+ set_fake_editor &&
(
FAKE_LINES="3 squash 1 2" &&
export FAKE_LINES &&
git commit -m "unrelated change" &&
parent=$(git rev-parse HEAD^) &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="edit 1" git rebase -i HEAD^ &&
echo edited > file7 &&
git add file7 &&
test_expect_success 'aborted --continue does not squash commits after "edit"' '
old=$(git rev-parse HEAD) &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="edit 1" git rebase -i HEAD^ &&
echo "edited again" > file7 &&
git add file7 &&
test_expect_success 'auto-amend only edited commits after "edit"' '
test_tick &&
+ set_fake_editor &&
FAKE_LINES="edit 1" git rebase -i HEAD^ &&
echo "edited again" > file7 &&
git add file7 &&
test_expect_success 'clean error after failed "exec"' '
test_tick &&
test_when_finished "git rebase --abort || :" &&
+ set_fake_editor &&
(
FAKE_LINES="1 exec_false" &&
export FAKE_LINES &&
grandparent=$(git rev-parse HEAD~2) &&
git checkout $(git rev-parse HEAD) &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="2 1" git rebase -i HEAD~2 &&
test $grandparent = $(git rev-parse HEAD~2)
'
test_must_fail git commit -m doesnt-verify file1 &&
git commit -m doesnt-verify --no-verify file1 &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES=2 git rebase -i HEAD~2
'
git commit -m "Add body"
) &&
+ set_fake_editor &&
FAKE_LINES="1 squash 2" git rebase -i to-be-rebased &&
test "$(git show -s --pretty=format:%an)" = "Squashed Away"
GIT_EDITOR=: git commit --amend \
--author="Somebody else <somebody@else.com>" &&
test $(git rev-parse branch3) != $(git rev-parse branch4) &&
+ set_fake_editor &&
git rebase -i branch3 &&
test $(git rev-parse branch3) = $(git rev-parse branch4)
git commit -a -m "submodule second"
) &&
test_tick &&
+ set_fake_editor &&
git commit -a -m "Three changes submodule"
'
test_expect_success 'submodule rebase -i' '
+ set_fake_editor &&
FAKE_LINES="1 squash 2 3" git rebase -i A
'
'
test_expect_success 'rebase -i continue with only submodule staged' '
+ set_fake_editor &&
test_must_fail git rebase -i submodule-base &&
git add sub &&
git rebase --continue &&
test_expect_success 'rebase -i continue with unstaged submodule' '
git checkout submodule-topic &&
git reset --hard &&
+ set_fake_editor &&
test_must_fail git rebase -i submodule-base &&
git reset &&
git rebase --continue &&
test-chmtime =123456789 file3 &&
git update-index --refresh &&
HEAD=$(git rev-parse HEAD) &&
+ set_fake_editor &&
git rebase -i HEAD~4 &&
test $HEAD = $(git rev-parse HEAD) &&
MTIME=$(test-chmtime -v +0 file3 | sed 's/[^0-9].*$//') &&
test_expect_success 'reword' '
git checkout -b reword-branch master &&
+ set_fake_editor &&
FAKE_LINES="1 2 3 reword 4" FAKE_COMMIT_MESSAGE="E changed" git rebase -i A &&
git show HEAD | grep "E changed" &&
test $(git rev-parse master) != $(git rev-parse HEAD) &&
test_commit n2 &&
test_commit n3 &&
git notes add -m"a note" n3 &&
+ set_fake_editor &&
git rebase -i --onto n1 n2 &&
test "a note" = "$(git notes show HEAD)"
'
test_expect_success 'rebase -i can copy notes over a fixup' '
git reset --hard n3 &&
git notes add -m"an earlier note" n2 &&
+ set_fake_editor &&
GIT_NOTES_REWRITE_MODE=concatenate FAKE_LINES="1 fixup 2" git rebase -i n1 &&
git notes show > output &&
test_cmp expect output
git symbolic-ref HEAD &&
grandparent=$(git rev-parse HEAD~2) &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="2 1" git rebase -i HEAD~2 HEAD^0 &&
test $grandparent = $(git rev-parse HEAD~2) &&
test_must_fail git symbolic-ref HEAD
test_expect_success 'always cherry-pick with --no-ff' '
git checkout no-ff-branch &&
git tag original-no-ff-branch &&
+ set_fake_editor &&
git rebase -i --no-ff A &&
touch empty &&
for p in 0 1 2
test_expect_success 'rebase-i history with funny messages' '
git rev-list A..funny >expect &&
test_tick &&
+ set_fake_editor &&
FAKE_LINES="1 2 3 4" git rebase -i A &&
git rev-list A.. >actual &&
test_cmp expect actual
test_expect_success 'running "git rebase -i --exec git show HEAD"' '
+ set_fake_editor &&
git rebase -i --exec "git show HEAD" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
test_expect_success 'running "git rebase --exec git show HEAD -i"' '
git reset --hard execute &&
+ set_fake_editor &&
git rebase --exec "git show HEAD" -i HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
test_expect_success 'running "git rebase -ix git show HEAD"' '
git reset --hard execute &&
+ set_fake_editor &&
git rebase -ix "git show HEAD" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
test_expect_success 'rebase -ix with several <CMD>' '
git reset --hard execute &&
+ set_fake_editor &&
git rebase -ix "git show HEAD; pwd" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" &&
test_expect_success 'rebase -ix with several instances of --exec' '
git reset --hard execute &&
+ set_fake_editor &&
git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual &&
(
FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2
echo bis >bis.txt &&
git add bis.txt &&
git commit -m "fixup! two_exec" &&
+ set_fake_editor &&
(
git checkout -b autosquash_actual &&
git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual
test_expect_success 'rebase --exec without -i shows error message' '
git reset --hard execute &&
+ set_fake_editor &&
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 &&
+ set_fake_editor &&
test_must_fail git rebase -i --exec 2>tmp &&
sed -e "1d" tmp >actual &&
test_must_fail git rebase -h >expected &&
test_expect_success 'rebase -i --root re-order and drop commits' '
git checkout E &&
+ set_fake_editor &&
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) &&
echo B >file7 &&
git add file7 &&
GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
+ set_fake_editor &&
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 &&
(
+ set_fake_editor &&
FAKE_LINES="2" &&
export FAKE_LINES &&
test_must_fail git rebase -i --root
test_expect_success 'rebase -i --root fixup root commit' '
git checkout B &&
+ set_fake_editor &&
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_expect_success 'rebase --edit-todo does not works on non-interactive rebase' '
git reset --hard &&
git checkout conflict-branch &&
+ set_fake_editor &&
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 &&
+ set_fake_editor &&
FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 &&
FAKE_LINES="2 1" git rebase --edit-todo &&
git rebase --continue
test_expect_success 'rebase -i produces readable reflog' '
git reset --hard &&
git branch -f branch-reflog-test H &&
+ set_fake_editor &&
git rebase -i --onto I F branch-reflog-test &&
cat >expect <<-\EOF &&
rebase -i (start): checkout I
test $(cat file1) = Z
'
+test_expect_success 'rebase -i error on commits with \ in message' '
+ current_head=$(git rev-parse HEAD)
+ test_when_finished "git rebase --abort; git reset --hard $current_head; rm -f error" &&
+ test_commit TO-REMOVE will-conflict old-content &&
+ test_commit "\temp" will-conflict new-content dummy &&
+ (
+ EDITOR=true &&
+ export EDITOR &&
+ test_must_fail git rebase -i HEAD^ --onto HEAD^^ 2>error
+ ) &&
+ test_expect_code 1 grep " emp" error
+'
+
+test_expect_success 'short SHA-1 setup' '
+ test_when_finished "git checkout master" &&
+ git checkout --orphan collide &&
+ git rm -rf . &&
+ (
+ unset test_tick &&
+ test_commit collide1 collide &&
+ test_commit --notick collide2 collide &&
+ test_commit --notick collide3 collide
+ )
+'
+
+test_expect_success 'short SHA-1 collide' '
+ test_when_finished "reset_rebase && git checkout master" &&
+ git checkout collide &&
+ (
+ unset test_tick &&
+ test_tick &&
+ set_fake_editor &&
+ FAKE_COMMIT_MESSAGE="collide2 ac4f2ee" \
+ FAKE_LINES="reword 1 2" git rebase -i HEAD~2
+ )
+'
+
test_done
# \--A3 <-- topic2
# \
# B2 <-- origin/topic
+#
+# Clone 4 (same as Clone 3)
test_expect_success 'setup for merge-preserving rebase' \
'echo First > A &&
git merge --no-ff topic2
) &&
+ git clone ./. clone4 &&
+ (
+ cd clone4 &&
+ git checkout -b topic2 origin/topic &&
+ echo Sixth > A &&
+ git commit -a -m "Modify A3" &&
+ git checkout -b topic origin/topic &&
+ git merge --no-ff topic2
+ ) &&
+
git checkout topic &&
echo Fourth >> B &&
git commit -a -m "Modify B2"
)
'
+test_expect_success 'rebase -p ignores merge.log config' '
+ (
+ cd clone4 &&
+ git fetch &&
+ git -c merge.log=1 rebase -p origin/topic &&
+ echo >expected &&
+ git log --format="%b" -1 >current &&
+ test_cmp expected current
+ )
+'
+
test_done
'
-test_expect_success 'chery-pick on unborn branch' '
+test_expect_success 'cherry-pick on unborn branch' '
git checkout --orphan unborn &&
git rm --cached -r . &&
rm -rf * &&
! test_cmp_rev initial HEAD
'
+test_expect_success 'cherry-pick "-" to pick from previous branch' '
+ git checkout unborn &&
+ test_commit to-pick actual content &&
+ git checkout master &&
+ git cherry-pick - &&
+ echo content >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick "-" is meaningless without checkout' '
+ test_create_repo afresh &&
+ (
+ cd afresh &&
+ test_commit one &&
+ test_commit two &&
+ test_commit three &&
+ test_must_fail git cherry-pick -
+ )
+'
+
+test_expect_success 'cherry-pick "-" works with arguments' '
+ git checkout -b side-branch &&
+ test_commit change actual change &&
+ git checkout master &&
+ git cherry-pick -s - &&
+ echo "Signed-off-by: C O Mitter <committer@example.com>" >expect &&
+ git cat-file commit HEAD | grep ^Signed-off-by: >signoff &&
+ test_cmp expect signoff &&
+ echo change >expect &&
+ test_cmp expect actual
+'
+
test_done
test "$(git rev-parse --verify HEAD)" = "1df192cd8bc58a2b275d842cede4d221ad9000d1"
'
-test_expect_success 'chery-pick --ff on unborn branch' '
+test_expect_success 'cherry-pick --ff on unborn branch' '
git checkout --orphan unborn &&
git rm --cached -r . &&
rm -rf * &&
echo content > sub/file &&
echo foo > othersub/whatever &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
git rm -rf othersub &&
git mv sub/file othersub &&
test_expect_success 'choking "git rm" should not let it die with cruft' '
git reset -q --hard &&
+ test_when_finished "rm -f .git/index.lock && git reset -q --hard" &&
i=0 &&
while test $i -lt 12000
do
- echo "100644 $_z40 0 some-file-$i"
+ echo "100644 1234567890123456789012345678901234567890 0 some-file-$i"
i=$(( $i + 1 ))
done | git update-index --index-info &&
- git rm -n "some-file-*" | :;
- test -f .git/index.lock
- status=$?
- rm -f .git/index.lock
- git reset -q --hard
- test "$status" != 0
+ git rm -n "some-file-*" | : &&
+ test_path_is_missing .git/index.lock
'
test_expect_success 'rm removes subdirectories recursively' '
'
cat >expect <<EOF
+M .gitmodules
D submod
EOF
M submod
EOF
+cat >expect.cached <<EOF
+D submod
+EOF
+
+cat >expect.both_deleted<<EOF
+D .gitmodules
+D 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 rm submod &&
test ! -e submod &&
git status -s -uno --ignore-submodules=none > actual &&
- test_cmp expect actual
+ test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.sub.url &&
+ test_must_fail git config -f .gitmodules submodule.sub.path
'
-test_expect_success 'rm removes removed submodule from index' '
+test_expect_success 'rm removes removed submodule from index and .gitmodules' '
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_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.sub.url &&
+ test_must_fail git config -f .gitmodules submodule.sub.path
'
test_expect_success 'rm 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_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.sub.url &&
+ test_must_fail git config -f .gitmodules submodule.sub.path
'
test_expect_success 'rm removes a submodule with a trailing /' '
git rm -f submod &&
test ! -d submod &&
git status -s -uno --ignore-submodules=none > actual &&
+ test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.sub.url &&
+ test_must_fail git config -f .gitmodules submodule.sub.path
+'
+
+test_expect_success 'rm --cached leaves work tree of populated submodules and .gitmodules alone' '
+ git reset --hard &&
+ git submodule update &&
+ git rm --cached submod &&
+ test -d submod &&
+ test -f submod/.git &&
+ git status -s -uno >actual &&
+ test_cmp expect.cached actual &&
+ git config -f .gitmodules submodule.sub.url &&
+ git config -f .gitmodules submodule.sub.path
+'
+
+test_expect_success 'rm --dry-run does not touch the submodule or .gitmodules' '
+ git reset --hard &&
+ git submodule update &&
+ git rm -n submod &&
+ test -f submod/.git &&
+ git diff-index --exit-code HEAD
+'
+
+test_expect_success 'rm does not complain when no .gitmodules file is found' '
+ git reset --hard &&
+ git submodule update &&
+ git rm .gitmodules &&
+ git rm submod >actual 2>actual.err &&
+ ! test -s actual.err &&
+ ! test -d submod &&
+ ! test -f submod/.git &&
+ git status -s -uno >actual &&
+ test_cmp expect.both_deleted actual
+'
+
+test_expect_success 'rm will error out on a modified .gitmodules file unless staged' '
+ git reset --hard &&
+ git submodule update &&
+ git config -f .gitmodules foo.bar true &&
+ test_must_fail git rm submod >actual 2>actual.err &&
+ test -s actual.err &&
+ test -d submod &&
+ test -f submod/.git &&
+ git diff-files --quiet -- submod &&
+ git add .gitmodules &&
+ git rm submod >actual 2>actual.err &&
+ ! test -s actual.err &&
+ ! test -d submod &&
+ ! test -f submod/.git &&
+ git status -s -uno >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'rm issues a warning when section is not found in .gitmodules' '
+ git reset --hard &&
+ git submodule update &&
+ git config -f .gitmodules --remove-section submodule.sub &&
+ git add .gitmodules &&
+ echo "warning: Could not find section in .gitmodules where path=submod" >expect.err &&
+ git rm submod >actual 2>actual.err &&
+ test_i18ncmp expect.err actual.err &&
+ ! test -d submod &&
+ ! test -f submod/.git &&
+ git status -s -uno >actual &&
test_cmp expect actual
'
git rm -f submod &&
test ! -d submod &&
git status -s -uno --ignore-submodules=none > actual &&
- test_cmp expect actual
+ test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.sub.url &&
+ test_must_fail git config -f .gitmodules submodule.sub.path
'
test_expect_success 'rm of a conflicted populated submodule with modifications fails unless forced' '
git rm -f submod &&
test ! -d submod &&
git status -s -uno --ignore-submodules=none > actual &&
- test_cmp expect actual
+ test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.sub.url &&
+ test_must_fail git config -f .gitmodules submodule.sub.path
'
test_expect_success 'rm of a conflicted populated submodule with untracked files fails unless forced' '
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh
-test_expect_success PERL 'setup (initial)' '
+if ! test_have_prereq PERL
+then
+ skip_all='skipping add -i tests, perl not available'
+ test_done
+fi
+
+test_expect_success 'setup (initial)' '
echo content >file &&
git add file &&
echo more >>file &&
echo lines >>file
'
-test_expect_success PERL 'status works (initial)' '
+test_expect_success 'status works (initial)' '
git add -i </dev/null >output &&
grep "+1/-0 *+2/-0 file" output
'
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
cat >expected <<EOF
new file mode 100644
index 0000000..d95f3ad
EOF
'
-test_expect_success PERL 'diff works (initial)' '
+test_expect_success 'diff works (initial)' '
(echo d; echo 1) | git add -i >output &&
sed -ne "/new file/,/content/p" <output >diff &&
test_cmp expected diff
'
-test_expect_success PERL 'revert works (initial)' '
+test_expect_success 'revert works (initial)' '
git add file &&
(echo r; echo 1) | git add -i &&
git ls-files >output &&
! grep . output
'
-test_expect_success PERL 'setup (commit)' '
+test_expect_success 'setup (commit)' '
echo baseline >file &&
git add file &&
git commit -m commit &&
echo more >>file &&
echo lines >>file
'
-test_expect_success PERL 'status works (commit)' '
+test_expect_success 'status works (commit)' '
git add -i </dev/null >output &&
grep "+1/-0 *+2/-0 file" output
'
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
cat >expected <<EOF
index 180b47c..b6f2c08 100644
--- a/file
EOF
'
-test_expect_success PERL 'diff works (commit)' '
+test_expect_success 'diff works (commit)' '
(echo d; echo 1) | git add -i >output &&
sed -ne "/^index/,/content/p" <output >diff &&
test_cmp expected diff
'
-test_expect_success PERL 'revert works (commit)' '
+test_expect_success 'revert works (commit)' '
git add file &&
(echo r; echo 1) | git add -i &&
git add -i </dev/null >output &&
'
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
cat >expected <<EOF
EOF
'
-test_expect_success PERL 'setup fake editor' '
+test_expect_success 'setup fake editor' '
>fake_editor.sh &&
chmod a+x fake_editor.sh &&
test_set_editor "$(pwd)/fake_editor.sh"
'
-test_expect_success PERL 'dummy edit works' '
+test_expect_success 'dummy edit works' '
(echo e; echo a) | git add -p &&
git diff > diff &&
test_cmp expected diff
'
-test_expect_success PERL 'setup patch' '
+test_expect_success 'setup patch' '
cat >patch <<EOF
@@ -1,1 +1,4 @@
this
EOF
'
-test_expect_success PERL 'setup fake editor' '
+test_expect_success 'setup fake editor' '
echo "#!$SHELL_PATH" >fake_editor.sh &&
cat >>fake_editor.sh <<\EOF &&
mv -f "$1" oldpatch &&
test_set_editor "$(pwd)/fake_editor.sh"
'
-test_expect_success PERL 'bad edit rejected' '
+test_expect_success 'bad edit rejected' '
git reset &&
(echo e; echo n; echo d) | git add -p >output &&
grep "hunk does not apply" output
'
-test_expect_success PERL 'setup patch' '
+test_expect_success 'setup patch' '
cat >patch <<EOF
this patch
is garbage
EOF
'
-test_expect_success PERL 'garbage edit rejected' '
+test_expect_success 'garbage edit rejected' '
git reset &&
(echo e; echo n; echo d) | git add -p >output &&
grep "hunk does not apply" output
'
-test_expect_success PERL 'setup patch' '
+test_expect_success 'setup patch' '
cat >patch <<EOF
@@ -1,0 +1,0 @@
baseline
EOF
'
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
cat >expected <<EOF
diff --git a/file b/file
index b5dd6c9..f910ae9 100644
EOF
'
-test_expect_success PERL 'real edit works' '
+test_expect_success 'real edit works' '
(echo e; echo n; echo d) | git add -p &&
git diff >output &&
test_cmp expected output
'
-test_expect_success PERL 'skip files similarly as commit -a' '
+test_expect_success 'skip files similarly as commit -a' '
git reset &&
echo file >.gitignore &&
echo changed >file &&
'
rm -f .gitignore
-test_expect_success PERL,FILEMODE 'patch does not affect mode' '
+test_expect_success FILEMODE 'patch does not affect mode' '
git reset --hard &&
echo content >>file &&
chmod +x file &&
git diff file | grep "new mode"
'
-test_expect_success PERL,FILEMODE 'stage mode but not hunk' '
+test_expect_success FILEMODE 'stage mode but not hunk' '
git reset --hard &&
echo content >>file &&
chmod +x file &&
'
-test_expect_success PERL,FILEMODE 'stage mode and hunk' '
+test_expect_success FILEMODE 'stage mode and hunk' '
git reset --hard &&
echo content >>file &&
chmod +x file &&
# end of tests disabled when filemode is not usable
-test_expect_success PERL 'setup again' '
+test_expect_success 'setup again' '
git reset --hard &&
test_chmod +x file &&
echo content >>file
'
# Write the patch file with a new line at the top and bottom
-test_expect_success PERL 'setup patch' '
+test_expect_success 'setup patch' '
cat >patch <<EOF
index 180b47c..b6f2c08 100644
--- a/file
'
# Expected output, similar to the patch but w/ diff at the top
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
cat >expected <<EOF
diff --git a/file b/file
index b6f2c08..61b9053 100755
'
# Test splitting the first patch, then adding both
-test_expect_success PERL 'add first line works' '
+test_expect_success 'add first line works' '
git commit -am "clear local changes" &&
git apply patch &&
(echo s; echo y; echo y) | git add -p file &&
test_cmp expected diff
'
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
cat >expected <<EOF
diff --git a/non-empty b/non-empty
deleted file mode 100644
EOF
'
-test_expect_success PERL 'deleting a non-empty file' '
+test_expect_success 'deleting a non-empty file' '
git reset --hard &&
echo content >non-empty &&
git add non-empty &&
test_cmp expected diff
'
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
cat >expected <<EOF
diff --git a/empty b/empty
deleted file mode 100644
EOF
'
-test_expect_success PERL 'deleting an empty file' '
+test_expect_success 'deleting an empty file' '
git reset --hard &&
> empty &&
git add empty &&
test_cmp expected diff
'
-test_expect_success PERL 'split hunk setup' '
+test_expect_success 'split hunk setup' '
git reset --hard &&
for i in 10 20 30 40 50 60
do
done >test
'
-test_expect_success PERL 'split hunk "add -p (edit)"' '
+test_expect_success 'split hunk "add -p (edit)"' '
# Split, say Edit and do nothing. Then:
#
# 1. Broken version results in a patch that does not apply and
test_expect_success "detect if nfd needed" '
precomposeunicode=`git config core.precomposeunicode` &&
- test "$precomposeunicode" = false &&
+ test "$precomposeunicode" = true &&
git config core.precomposeunicode true
'
test_expect_success "setup" '
test_cmp expect patch.head
'
+test_expect_success '--from omits redundant in-body header' '
+ git format-patch -1 --stdout --from="A U Thor <author@example.com>" >patch &&
+ cat >expect <<-\EOF &&
+ From: A U Thor <author@example.com>
+
+ EOF
+ sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
+ test_cmp expect patch.head
+'
+
test_expect_success 'in-body headers trigger content encoding' '
GIT_AUTHOR_NAME="éxötìc" test_commit exotic &&
test_when_finished "git reset --hard HEAD^" &&
test_cmp expect.text actual
'
+test_expect_success 'show commit produces text' '
+ git show HEAD >diff &&
+ find_diff <diff >actual &&
+ test_cmp expect.text actual
+'
+
test_expect_success 'diff-tree produces binary' '
git diff-tree -p HEAD^ HEAD >diff &&
find_diff <diff >actual &&
git reset --soft HEAD@{1}
'
+test_expect_success 'show blob produces binary' '
+ git show HEAD:file >actual &&
+ printf "\\0\\n\\01\\n" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'show --textconv blob produces text' '
+ git show --textconv HEAD:file >actual &&
+ printf "0\\n1\\n" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'show --no-textconv blob produces binary' '
+ git show --no-textconv HEAD:file >actual &&
+ printf "\\0\\n\\01\\n" >expect &&
+ test_cmp expect actual
+'
+
test_expect_success 'grep-diff (-G) operates on textconv data (add)' '
echo one >expect &&
git log --root --format=%s -G0 >actual &&
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_i18ngrep "bad numeric config value" output
'
test_expect_success 'negative integer config parsing' '
git shortlog HEAD~2.. > out &&
test_cmp expect out'
+test_expect_success 'shortlog ignores commits with missing authors' '
+ git commit --allow-empty -m normal &&
+ git commit --allow-empty -m soon-to-be-broken &&
+ git cat-file commit HEAD >commit.tmp &&
+ sed "/^author/d" commit.tmp >broken.tmp &&
+ commit=$(git hash-object -w -t commit --stdin <broken.tmp) &&
+ git update-ref HEAD $commit &&
+ cat >expect <<-\EOF &&
+ A U Thor (1):
+ normal
+
+ EOF
+ git shortlog HEAD~2.. >actual &&
+ test_cmp expect actual
+'
+
test_done
Blob Guy <author@example.com>
Blob Guy <bugs@company.xx>
EOF
- git add just-bugs both &&
+ printf "Tricky Guy <author@example.com>" >no-newline &&
+ git add just-bugs both no-newline &&
git commit -m "my mailmaps" &&
echo "Repo Guy <author@example.com>" >.mailmap &&
echo "Internal Guy <author@example.com>" >internal.map
)
'
+test_expect_success 'mailmap.blob can handle blobs without trailing newline' '
+ cat >expect <<-\EOF &&
+ Tricky Guy (1):
+ initial
+
+ nick1 (1):
+ second
+
+ EOF
+ git -c mailmap.blob=map:no-newline shortlog HEAD >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'cleanup after mailmap.blob tests' '
rm -f .mailmap
'
test_cmp expect actual.fuzz
'
+cat >expect <<\EOF
+Some Dude <some@dude.xx>
+EOF
+
+test_expect_success 'commit --author honors mailmap' '
+ test_must_fail git commit --author "nick" --allow-empty -meight &&
+ git commit --author "Some Dude" --allow-empty -meight &&
+ git show --pretty=format:"%an <%ae>%n" >actual &&
+ test_cmp expect actual
+'
+
test_done
test_cmp expected actual
'
+test_expect_success 'command line pathspec parsing for "git log"' '
+ git reset --hard &&
+ >a &&
+ git add a &&
+ git commit -m "add an empty a" --allow-empty &&
+ echo 1 >a &&
+ git commit -a -m "update a to 1" &&
+ git checkout HEAD^ &&
+ echo 2 >a &&
+ git commit -a -m "update a to 2" &&
+ test_must_fail git merge master &&
+ git add a &&
+ git log --merge -- a
+'
+
test_done
canned_test "-M -L ':f:b.c' parallel-change" parallel-change-f-to-main
canned_test "-L 4,12:a.c -L :main:a.c simple" multiple
-canned_test "-L 4,18:a.c -L :main:a.c simple" multiple-overlapping
+canned_test "-L 4,18:a.c -L ^:main:a.c simple" multiple-overlapping
canned_test "-L :main:a.c -L 4,18:a.c simple" multiple-overlapping
canned_test "-L 4:a.c -L 8,12:a.c simple" multiple-superset
canned_test "-L 8,12:a.c -L 4:a.c simple" multiple-superset
test_bad_opts "-L :b.c" "argument.*not of the form"
test_bad_opts "-L :foo:b.c" "no match"
-# There is a separate bug when an empty -L range is the first -L encountered,
-# thus to demonstrate this particular bug, the empty -L range must follow a
-# non-empty -L range.
-test_expect_success '-L {empty-range} (any -L)' '
+test_expect_success '-L X (X == nlines)' '
+ n=$(wc -l <b.c) &&
+ git log -L $n:b.c
+'
+
+test_expect_success '-L X (X == nlines + 1)' '
n=$(expr $(wc -l <b.c) + 1) &&
- git log -L1,1:b.c -L$n:b.c
+ test_must_fail git log -L $n:b.c
+'
+
+test_expect_success '-L X (X == nlines + 2)' '
+ n=$(expr $(wc -l <b.c) + 2) &&
+ test_must_fail git log -L $n:b.c
'
-test_expect_success '-L {empty-range} (first -L)' '
+test_expect_success '-L ,Y (Y == nlines)' '
+ n=$(printf "%d" $(wc -l <b.c)) &&
+ git log -L ,$n:b.c
+'
+
+test_expect_success '-L ,Y (Y == nlines + 1)' '
n=$(expr $(wc -l <b.c) + 1) &&
- git log -L$n:b.c
+ test_must_fail git log -L ,$n:b.c
+'
+
+test_expect_success '-L ,Y (Y == nlines + 2)' '
+ n=$(expr $(wc -l <b.c) + 2) &&
+ test_must_fail git log -L ,$n:b.c
'
test_done
git update-ref refs/heads/broken_email $(cat broken_email.hash)
'
+test_expect_success 'fsck notices broken commit' '
+ git fsck 2>actual &&
+ test_i18ngrep invalid.author actual
+'
+
test_expect_success 'git log with broken author email' '
{
echo commit $(cat broken_email.hash)
echo "Author: A U Thor <author@example.com>"
- echo "Date: Thu Jan 1 00:00:00 1970 +0000"
+ echo "Date: Thu Apr 7 15:13:13 2005 -0700"
echo
echo " foo"
} >expect.out &&
'
test_expect_success 'git log --format with broken author email' '
- echo "A U Thor+author@example.com+" >expect.out &&
+ echo "A U Thor+author@example.com+Thu Apr 7 15:13:13 2005 -0700" >expect.out &&
: >expect.err &&
git log --format="%an+%ae+%ad" broken_email >actual.out 2>actual.err &&
test_description='git am with corrupt input'
. ./test-lib.sh
-# Note the missing "+++" line:
-cat > bad-patch.diff <<'EOF'
-From: A U Thor <au.thor@example.com>
-diff --git a/f b/f
-index 7898192..6178079 100644
---- a/f
-@@ -1 +1 @@
--a
-+b
-EOF
-
test_expect_success setup '
- test $? = 0 &&
- echo a > f &&
+ # Note the missing "+++" line:
+ cat >bad-patch.diff <<-\EOF &&
+ From: A U Thor <au.thor@example.com>
+ diff --git a/f b/f
+ index 7898192..6178079 100644
+ --- a/f
+ @@ -1 +1 @@
+ -a
+ +b
+ EOF
+
+ echo a >f &&
git add f &&
test_tick &&
git commit -m initial
# fatal: unable to write file '(null)' mode 100644: Bad address
# Also, it had the unwanted side-effect of deleting f.
test_expect_success 'try to apply corrupted patch' '
- git am bad-patch.diff 2> actual
- test $? = 1
+ test_must_fail git am bad-patch.diff 2>actual
'
-cat > expected <<EOF
-fatal: git diff header lacks filename information (line 4)
-EOF
-
test_expect_success 'compare diagnostic; ensure file is still here' '
- test $? = 0 &&
- test -f f &&
+ echo "fatal: git diff header lacks filename information (line 4)" >expected &&
+ test_path_is_file f &&
test_cmp expected actual
'
--- /dev/null
+#!/bin/sh
+
+test_description='handling of duplicate objects in incoming packfiles'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-pack.sh
+
+# The sha1s we have in our pack. It's important that these have the same
+# starting byte, so that they end up in the same fanout section of the index.
+# That lets us make sure we are exercising the binary search with both sets.
+LO_SHA1=e68fe8129b546b101aee9510c5328e7f21ca1d18
+HI_SHA1=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
+
+# And here's a "missing sha1" which will produce failed lookups. It must also
+# be in the same fanout section, and should be between the two (so that during
+# our binary search, we are sure to end up looking at one or the other of the
+# duplicate runs).
+MISSING_SHA1='e69d000000000000000000000000000000000000'
+
+# git will never intentionally create packfiles with
+# duplicate objects, so we have to construct them by hand.
+#
+# $1 is the name of the packfile to create
+#
+# $2 is the number of times to duplicate each object
+create_pack () {
+ pack_header "$((2 * $2))" >"$1" &&
+ for i in $(test_seq 1 "$2"); do
+ pack_obj $LO_SHA1 &&
+ pack_obj $HI_SHA1
+ done >>"$1" &&
+ pack_trailer "$1"
+}
+
+# double-check that create_pack actually works
+test_expect_success 'pack with no duplicates' '
+ create_pack no-dups.pack 1 &&
+ git index-pack --stdin <no-dups.pack
+'
+
+test_expect_success 'index-pack will allow duplicate objects by default' '
+ clear_packs &&
+ create_pack dups.pack 100 &&
+ git index-pack --stdin <dups.pack
+'
+
+test_expect_success 'create batch-check test vectors' '
+ cat >input <<-EOF &&
+ $LO_SHA1
+ $HI_SHA1
+ $MISSING_SHA1
+ EOF
+ cat >expect <<-EOF
+ $LO_SHA1 blob 2
+ $HI_SHA1 blob 0
+ $MISSING_SHA1 missing
+ EOF
+'
+
+test_expect_success 'lookup in duplicated pack (binary search)' '
+ git cat-file --batch-check <input >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'lookup in duplicated pack (GIT_USE_LOOKUP)' '
+ (
+ GIT_USE_LOOKUP=1 &&
+ export GIT_USE_LOOKUP &&
+ git cat-file --batch-check <input >actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_expect_success 'index-pack can reject packs with duplicates' '
+ clear_packs &&
+ create_pack dups.pack 2 &&
+ test_must_fail git index-pack --strict --stdin <dups.pack &&
+ test_expect_code 1 git cat-file -e $LO_SHA1
+'
+
+test_done
--- /dev/null
+#!/bin/sh
+
+test_description='test index-pack handling of delta cycles in packfiles'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-pack.sh
+
+# Two similar-ish objects that we have computed deltas between.
+A=01d7713666f4de822776c7622c10f1b07de280dc
+B=e68fe8129b546b101aee9510c5328e7f21ca1d18
+
+# double-check our hand-constucted packs
+test_expect_success 'index-pack works with a single delta (A->B)' '
+ clear_packs &&
+ {
+ pack_header 2 &&
+ pack_obj $A $B &&
+ pack_obj $B
+ } >ab.pack &&
+ pack_trailer ab.pack &&
+ git index-pack --stdin <ab.pack &&
+ git cat-file -t $A &&
+ git cat-file -t $B
+'
+
+test_expect_success 'index-pack works with a single delta (B->A)' '
+ clear_packs &&
+ {
+ pack_header 2 &&
+ pack_obj $A &&
+ pack_obj $B $A
+ } >ba.pack &&
+ pack_trailer ba.pack &&
+ git index-pack --stdin <ba.pack &&
+ git cat-file -t $A &&
+ git cat-file -t $B
+'
+
+test_expect_success 'index-pack detects missing base objects' '
+ clear_packs &&
+ {
+ pack_header 1 &&
+ pack_obj $A $B
+ } >missing.pack &&
+ pack_trailer missing.pack &&
+ test_must_fail git index-pack --fix-thin --stdin <missing.pack
+'
+
+test_expect_success 'index-pack detects REF_DELTA cycles' '
+ clear_packs &&
+ {
+ pack_header 2 &&
+ pack_obj $A $B &&
+ pack_obj $B $A
+ } >cycle.pack &&
+ pack_trailer cycle.pack &&
+ test_must_fail git index-pack --fix-thin --stdin <cycle.pack
+'
+
+test_expect_failure 'failover to an object in another pack' '
+ clear_packs &&
+ git index-pack --stdin <ab.pack &&
+ git index-pack --stdin --fix-thin <cycle.pack
+'
+
+test_expect_failure 'failover to a duplicate object in the same pack' '
+ clear_packs &&
+ {
+ pack_header 3 &&
+ pack_obj $A $B &&
+ pack_obj $B $A &&
+ pack_obj $A
+ } >recoverable.pack &&
+ pack_trailer recoverable.pack &&
+ git index-pack --fix-thin --stdin <recoverable.pack
+'
+
+test_done
git fsck --no-dangling
)
'
+test_expect_success 'fetch creating new shallow root' '
+ (
+ git clone "file://$(pwd)/." shallow10 &&
+ git commit --allow-empty -m empty &&
+ cd shallow10 &&
+ git fetch --depth=1 --progress 2>actual &&
+ # This should fetch only the empty commit, no tree or
+ # blob objects
+ grep "remote: Total 1" actual
+ )
+'
test_expect_success 'setup tests for the --stdin parameter' '
for head in C D E F
) >out-adt 2>error-adt
'
+test_expect_success 'shallow fetch with tags does not break the repository' '
+ mkdir repo1 &&
+ (
+ cd repo1 &&
+ git init &&
+ test_commit 1 &&
+ test_commit 2 &&
+ test_commit 3 &&
+ mkdir repo2 &&
+ cd repo2 &&
+ git init &&
+ git fetch --depth=2 ../.git master:branch &&
+ git fsck
+ )
+'
+
test_done
* remote two
Fetch URL: ../two
Push URL: ../three
- HEAD branch (remote HEAD is ambiguous, may be one of the following):
- another
- master
+ HEAD branch: master
Local refs configured for 'git push':
ahead forces to master (fast-forwardable)
master pushes to another (up to date)
)
'
-cat >test/expect <<\EOF
-error: Multiple remote HEAD branches. Please choose one explicitly with:
- git remote set-head two another
- git remote set-head two master
-EOF
-
-test_expect_success 'set-head --auto fails w/multiple HEADs' '
+test_expect_success 'set-head --auto has no problem w/multiple HEADs' '
(
cd test &&
- test_must_fail git remote set-head --auto two >output 2>&1 &&
+ git fetch two "refs/heads/*:refs/remotes/two/*" &&
+ git remote set-head --auto two >output 2>&1 &&
+ echo "two/HEAD set to master" >expect &&
test_i18ncmp expect output
)
'
)
'
+# configured prune tests
+
+set_config_tristate () {
+ # var=$1 val=$2
+ case "$2" in
+ unset) test_unconfig "$1" ;;
+ *) git config "$1" "$2" ;;
+ esac
+}
+
+test_configured_prune () {
+ fetch_prune=$1 remote_origin_prune=$2 cmdline=$3 expected=$4
+
+ test_expect_success "prune fetch.prune=$1 remote.origin.prune=$2${3:+ $3}; $4" '
+ # make sure a newbranch is there in . and also in one
+ git branch -f newbranch &&
+ (
+ cd one &&
+ test_unconfig fetch.prune &&
+ test_unconfig remote.origin.prune &&
+ git fetch &&
+ git rev-parse --verify refs/remotes/origin/newbranch
+ )
+
+ # now remove it
+ git branch -d newbranch &&
+
+ # then test
+ (
+ cd one &&
+ set_config_tristate fetch.prune $fetch_prune &&
+ set_config_tristate remote.origin.prune $remote_origin_prune &&
+
+ git fetch $cmdline &&
+ case "$expected" in
+ pruned)
+ test_must_fail git rev-parse --verify refs/remotes/origin/newbranch
+ ;;
+ kept)
+ git rev-parse --verify refs/remotes/origin/newbranch
+ ;;
+ esac
+ )
+ '
+}
+
+test_configured_prune unset unset "" kept
+test_configured_prune unset unset "--no-prune" kept
+test_configured_prune unset unset "--prune" pruned
+
+test_configured_prune false unset "" kept
+test_configured_prune false unset "--no-prune" kept
+test_configured_prune false unset "--prune" pruned
+
+test_configured_prune true unset "" pruned
+test_configured_prune true unset "--prune" pruned
+test_configured_prune true unset "--no-prune" kept
+
+test_configured_prune unset false "" kept
+test_configured_prune unset false "--no-prune" kept
+test_configured_prune unset false "--prune" pruned
+
+test_configured_prune false false "" kept
+test_configured_prune false false "--no-prune" kept
+test_configured_prune false false "--prune" pruned
+
+test_configured_prune true false "" kept
+test_configured_prune true false "--prune" pruned
+test_configured_prune true false "--no-prune" kept
+
+test_configured_prune unset true "" pruned
+test_configured_prune unset true "--no-prune" kept
+test_configured_prune unset true "--prune" pruned
+
+test_configured_prune false true "" pruned
+test_configured_prune false true "--no-prune" kept
+test_configured_prune false true "--prune" pruned
+
+test_configured_prune true true "" pruned
+test_configured_prune true true "--prune" pruned
+test_configured_prune true true "--no-prune" kept
+
test_expect_success 'all boundary commits are excluded' '
test_commit base &&
test_commit oneside &&
test_cmp expect actual
'
+test_expect_success 'push --no-thin must produce non-thin pack' '
+ cat >>path1 <<\EOF &&
+keep base version of path1 big enough, compared to the new changes
+later, in order to pass size heuristics in
+builtin/pack-objects.c:try_delta()
+EOF
+ git commit -am initial &&
+ git init no-thin &&
+ git --git-dir=no-thin/.git config receive.unpacklimit 0 &&
+ git push no-thin/.git refs/heads/master:refs/heads/foo &&
+ echo modified >> path1 &&
+ git commit -am modified &&
+ git repack -adf &&
+ rcvpck="git receive-pack --reject-thin-pack-for-testing" &&
+ git push --no-thin --receive-pack="$rcvpck" no-thin/.git refs/heads/master:refs/heads/foo
+'
+
test_done
test new = $(git show HEAD:file2)
'
+# add a feature branch, keep-merge, that is merged into master, so the
+# test can try preserving the merge commit (or not) with various
+# --rebase flags/pull.rebase settings.
+test_expect_success 'preserve merge setup' '
+ git reset --hard before-rebase &&
+ git checkout -b keep-merge second^ &&
+ test_commit file3 &&
+ git checkout to-rebase &&
+ git merge keep-merge &&
+ git tag before-preserve-rebase
+'
+
+test_expect_success 'pull.rebase=false create a new merge commit' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase false &&
+ git pull . copy &&
+ test $(git rev-parse HEAD^1) = $(git rev-parse before-preserve-rebase) &&
+ test $(git rev-parse HEAD^2) = $(git rev-parse copy) &&
+ test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success 'pull.rebase=true flattens keep-merge' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase true &&
+ git pull . copy &&
+ test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+ test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success 'pull.rebase=1 is treated as true and flattens keep-merge' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase 1 &&
+ git pull . copy &&
+ test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+ test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success 'pull.rebase=preserve rebases and merges keep-merge' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase preserve &&
+ git pull . copy &&
+ test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+ test $(git rev-parse HEAD^2) = $(git rev-parse keep-merge)
+'
+
+test_expect_success 'pull.rebase=invalid fails' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase invalid &&
+ ! git pull . copy
+'
+
+test_expect_success '--rebase=false create a new merge commit' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase true &&
+ git pull --rebase=false . copy &&
+ test $(git rev-parse HEAD^1) = $(git rev-parse before-preserve-rebase) &&
+ test $(git rev-parse HEAD^2) = $(git rev-parse copy) &&
+ test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success '--rebase=true rebases and flattens keep-merge' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase preserve &&
+ git pull --rebase=true . copy &&
+ test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+ test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success '--rebase=preserve rebases and merges keep-merge' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase true &&
+ git pull --rebase=preserve . copy &&
+ test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+ test $(git rev-parse HEAD^2) = $(git rev-parse keep-merge)
+'
+
+test_expect_success '--rebase=invalid fails' '
+ git reset --hard before-preserve-rebase &&
+ ! git pull --rebase=invalid . copy
+'
+
+test_expect_success '--rebase overrides pull.rebase=preserve and flattens keep-merge' '
+ git reset --hard before-preserve-rebase &&
+ test_config pull.rebase preserve &&
+ git pull --rebase . copy &&
+ test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+ test file3 = $(git show HEAD:file3.t)
+'
+
test_expect_success '--rebase with rebased upstream' '
git remote add -f me . &&
printf "0032want %s\n0034shallow %s00000009done\n0000" \
$(git rev-parse HEAD) $(git rev-parse HEAD^) >input &&
test_must_fail git upload-pack . <input >/dev/null 2>output.err &&
- # pack-objects survived
- grep "Total.*, reused" output.err &&
- # but there was an error, which must have been in rev-list
grep "bad tree object" output.err
'
--- /dev/null
+#!/bin/sh
+
+test_description='compare & swap push force/delete safety'
+
+. ./test-lib.sh
+
+setup_srcdst_basic () {
+ rm -fr src dst &&
+ git clone --no-local . src &&
+ git clone --no-local src dst &&
+ (
+ cd src && git checkout HEAD^0
+ )
+}
+
+test_expect_success setup '
+ : create template repository
+ test_commit A &&
+ test_commit B &&
+ test_commit C
+'
+
+test_expect_success 'push to update (protected)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ test_commit D &&
+ test_must_fail git push --force-with-lease=master:master origin master
+ ) &&
+ git ls-remote . refs/heads/master >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (protected, forced)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ test_commit D &&
+ git push --force --force-with-lease=master:master origin master
+ ) &&
+ git ls-remote dst refs/heads/master >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (protected, tracking)' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git checkout master &&
+ test_commit D &&
+ git checkout HEAD^0
+ ) &&
+ git ls-remote src refs/heads/master >expect &&
+ (
+ cd dst &&
+ test_commit E &&
+ git ls-remote . refs/remotes/origin/master >expect &&
+ test_must_fail git push --force-with-lease=master origin master &&
+ git ls-remote . refs/remotes/origin/master >actual &&
+ test_cmp expect actual
+ ) &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (protected, tracking, forced)' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git checkout master &&
+ test_commit D &&
+ git checkout HEAD^0
+ ) &&
+ (
+ cd dst &&
+ test_commit E &&
+ git ls-remote . refs/remotes/origin/master >expect &&
+ git push --force --force-with-lease=master origin master
+ ) &&
+ git ls-remote dst refs/heads/master >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (allowed)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ test_commit D &&
+ git push --force-with-lease=master:master^ origin master
+ ) &&
+ git ls-remote dst refs/heads/master >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (allowed, tracking)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ test_commit D &&
+ git push --force-with-lease=master origin master
+ ) &&
+ git ls-remote dst refs/heads/master >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (allowed even though no-ff)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ git reset --hard HEAD^ &&
+ test_commit D &&
+ git push --force-with-lease=master origin master
+ ) &&
+ git ls-remote dst refs/heads/master >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to delete (protected)' '
+ setup_srcdst_basic &&
+ git ls-remote src refs/heads/master >expect &&
+ (
+ cd dst &&
+ test_must_fail git push --force-with-lease=master:master^ origin :master
+ ) &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to delete (protected, forced)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ git push --force --force-with-lease=master:master^ origin :master
+ ) &&
+ >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to delete (allowed)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ git push --force-with-lease=master origin :master
+ ) &&
+ >expect &&
+ git ls-remote src refs/heads/master >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cover everything with default force-with-lease (protected)' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git branch naster master^
+ )
+ git ls-remote src refs/heads/\* >expect &&
+ (
+ cd dst &&
+ test_must_fail git push --force-with-lease origin master master:naster
+ ) &&
+ git ls-remote src refs/heads/\* >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cover everything with default force-with-lease (allowed)' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git branch naster master^
+ )
+ (
+ cd dst &&
+ git fetch &&
+ git push --force-with-lease origin master master:naster
+ ) &&
+ git ls-remote dst refs/heads/master |
+ sed -e "s/master/naster/" >expect &&
+ git ls-remote src refs/heads/naster >actual &&
+ test_cmp expect actual
+'
+
+test_done
'
test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \
- "$ROOT_PATH"/test_repo_clone master
+ "$ROOT_PATH"/test_repo_clone master success
test_expect_success 'push fails for non-fast-forward refs unmatched by remote helper' '
# create a dissimilarly-named remote ref so that git is unable to match the
git clone $HTTPD_URL/smart-redir-temp/repo.git --quiet repo-t
'
+test_expect_success 'redirects re-root further requests' '
+ git clone $HTTPD_URL/smart-redir-limited/repo.git repo-redir-limited
+'
+
test_expect_success 'clone from password-protected repository' '
echo two >expect &&
set_askpass user@host &&
expect_askpass none
'
+test_expect_success 'redirects send auth to new location' '
+ set_askpass user@host &&
+ git -c credential.useHttpPath=true \
+ clone $HTTPD_URL/smart-redir-auth/repo.git repo-redir-auth &&
+ expect_askpass both user@host auth/smart/repo.git
+'
+
test_expect_success 'disable dumb http on server' '
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
config http.getanyfile false
test_cmp expect actual
'
+cat >cookies.txt <<EOF
+127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue
+EOF
+cat >expect_cookies.txt <<EOF
+
+127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue
+127.0.0.1 FALSE /smart_cookies/repo.git/info/ FALSE 0 name value
+EOF
+test_expect_success 'cookies stored in http.cookiefile when http.savecookies set' '
+ git config http.cookiefile cookies.txt &&
+ git config http.savecookies true &&
+ git ls-remote $HTTPD_URL/smart_cookies/repo.git master &&
+ tail -3 cookies.txt > cookies_tail.txt
+ test_cmp expect_cookies.txt cookies_tail.txt
+'
+
test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
test_cmp file clone/file
'
-test_expect_failure 'remote detects correct HEAD' '
+test_expect_success 'remote detects correct HEAD' '
git push public master:other &&
(cd clone &&
git remote set-head -d origin &&
fi
test_must_fail git "$cmd" "$GIT_DAEMON_URL/$repo" "$@" 2>output &&
- echo "fatal: remote error: $msg: /$repo" >expect &&
- test_cmp expect output
+ test_i18ngrep "fatal: remote error: $msg: /$repo" output &&
ret=$?
chmod +x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git"
(exit $ret)
test_expect_success C_LOCALE_OUTPUT 'output from clone' '
rm -fr dst &&
- git clone -n "file://$(pwd)/src" dst >output &&
+ git clone -n "file://$(pwd)/src" dst >output 2>&1 &&
test $(grep Clon output | wc -l) = 1
'
test_cmp fetch.expected fetch.actual
'
+test_expect_success 'setup ssh wrapper' '
+ write_script "$TRASH_DIRECTORY/ssh-wrapper" <<-\EOF &&
+ echo >>"$TRASH_DIRECTORY/ssh-output" "ssh: $*" &&
+ # throw away all but the last argument, which should be the
+ # command
+ while test $# -gt 1; do shift; done
+ eval "$1"
+ EOF
+
+ GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper" &&
+ export GIT_SSH &&
+ export TRASH_DIRECTORY
+'
+
+clear_ssh () {
+ >"$TRASH_DIRECTORY/ssh-output"
+}
+
+expect_ssh () {
+ {
+ case "$1" in
+ none)
+ ;;
+ *)
+ echo "ssh: $1 git-upload-pack '$2'"
+ esac
+ } >"$TRASH_DIRECTORY/ssh-expect" &&
+ (cd "$TRASH_DIRECTORY" && test_cmp ssh-expect ssh-output)
+}
+
+test_expect_success 'cloning myhost:src uses ssh' '
+ clear_ssh &&
+ git clone myhost:src ssh-clone &&
+ expect_ssh myhost src
+'
+
test_expect_success NOT_MINGW,NOT_CYGWIN 'clone local path foo:bar' '
+ clear_ssh &&
cp -R src "foo:bar" &&
- git clone "./foo:bar" foobar
+ git clone "./foo:bar" foobar &&
+ expect_ssh none
+'
+
+test_expect_success 'bracketed hostnames are still ssh' '
+ clear_ssh &&
+ git clone "[myhost:123]:src" ssh-bracket-clone &&
+ expect_ssh myhost:123 src
+'
+
+test_expect_success 'clone from a repository with two identical branches' '
+
+ (
+ cd src &&
+ git checkout -b another master
+ ) &&
+ git clone src target-11 &&
+ test "z$( cd target-11 && git symbolic-ref HEAD )" = zrefs/heads/another
+
'
test_done
! repo_is_hardlinked force-nonlocal
'
+test_expect_success 'cloning locally respects "-u" for fetching refs' '
+ test_must_fail git clone --bare -u false a should_not_work.git
+'
+
test_done
'
-test_expect_success 'redirected clone' '
+test_expect_success 'redirected clone does not show progress' '
git clone "file://$(pwd)/parent" clone-redirected >out 2>err &&
- test_must_be_empty err
+ ! grep % err &&
+ test_i18ngrep ! "Checking connectivity" err
'
-test_expect_success 'redirected clone -v' '
+
+test_expect_success 'redirected clone -v does show progress' '
git clone --progress "file://$(pwd)/parent" clone-redirected-progress \
>out 2>err &&
- test -s err
+ grep % err
'
echo one >file && git add file && git commit -m one &&
git checkout -b two &&
echo two >file && git add file && git commit -m two &&
- git checkout master)
+ git checkout master) &&
+ mkdir empty &&
+ (cd empty && git init)
'
test_expect_success 'vanilla clone chooses HEAD' '
test_must_fail git clone -b bogus parent clone-bogus
'
+test_expect_success 'clone -b not allowed with empty repos' '
+ test_must_fail git clone -b branch empty clone-branch-empty
+'
+
test_done
+++ /dev/null
-#!/bin/sh
-#
-# Copyright (c) 2010 Sverre Rabbelier
-#
-
-test_description='Test python remote-helper framework'
-
-. ./test-lib.sh
-
-if ! test_have_prereq PYTHON ; then
- skip_all='skipping python remote-helper tests, python not available'
- test_done
-fi
-
-"$PYTHON_PATH" -c '
-import sys
-if sys.hexversion < 0x02040000:
- sys.exit(1)
-' || {
- skip_all='skipping python remote-helper tests, python version < 2.4'
- test_done
-}
-
-compare_refs() {
- git --git-dir="$1/.git" rev-parse --verify $2 >expect &&
- git --git-dir="$3/.git" rev-parse --verify $4 >actual &&
- test_cmp expect actual
-}
-
-test_expect_success 'setup repository' '
- git init --bare server/.git &&
- git clone server public &&
- (cd public &&
- echo content >file &&
- git add file &&
- git commit -m one &&
- git push origin master)
-'
-
-test_expect_success 'cloning from local repo' '
- git clone "testpy::${PWD}/server" localclone &&
- test_cmp public/file localclone/file
-'
-
-test_expect_success 'cloning from remote repo' '
- git clone "testpy::file://${PWD}/server" clone &&
- test_cmp public/file clone/file
-'
-
-test_expect_success 'create new commit on remote' '
- (cd public &&
- echo content >>file &&
- git commit -a -m two &&
- git push)
-'
-
-test_expect_success 'pulling from local repo' '
- (cd localclone && git pull) &&
- test_cmp public/file localclone/file
-'
-
-test_expect_success 'pulling from remote remote' '
- (cd clone && git pull) &&
- test_cmp public/file clone/file
-'
-
-test_expect_success 'pushing to local repo' '
- (cd localclone &&
- echo content >>file &&
- git commit -a -m three &&
- git push) &&
- compare_refs localclone HEAD server HEAD
-'
-
-# Generally, skip this test. It demonstrates a now-fixed race in
-# git-remote-testpy, 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 -R server server2 &&
- git clone "testpy::${PWD}/server2" localclone2 &&
- (cd localclone2 &&
- echo content >>file &&
- git commit -a -m three &&
- GIT_REMOTE_TESTGIT_SLEEPY=2 git push) &&
- compare_refs localclone2 HEAD server2 HEAD
-'
-
-test_expect_success 'synch with changes from localclone' '
- (cd clone &&
- git pull)
-'
-
-test_expect_success 'pushing remote local repo' '
- (cd clone &&
- echo content >>file &&
- git commit -a -m four &&
- git push) &&
- compare_refs clone HEAD server HEAD
-'
-
-test_expect_success 'fetch new branch' '
- (cd public &&
- git checkout -b new &&
- echo content >>file &&
- git commit -a -m five &&
- git push origin new
- ) &&
- (cd localclone &&
- git fetch origin new
- ) &&
- compare_refs public HEAD localclone FETCH_HEAD
-'
-
-test_expect_success 'fetch multiple branches' '
- (cd localclone &&
- git fetch
- ) &&
- compare_refs server master localclone refs/remotes/origin/master &&
- compare_refs server new localclone refs/remotes/origin/new
-'
-
-test_expect_success 'push when remote has extra refs' '
- (cd clone &&
- echo content >>file &&
- git commit -a -m six &&
- git push
- ) &&
- compare_refs clone master server master
-'
-
-test_expect_success 'push new branch by name' '
- (cd clone &&
- git checkout -b new-name &&
- echo content >>file &&
- git commit -a -m seven &&
- git push origin new-name
- ) &&
- compare_refs clone HEAD server refs/heads/new-name
-'
-
-test_expect_failure 'push new branch with old:new refspec' '
- (cd clone &&
- git push origin new-name:new-refspec
- ) &&
- compare_refs clone HEAD server refs/heads/new-refspec
-'
-
-test_expect_success 'proper failure checks for fetching' '
- (GIT_REMOTE_TESTGIT_FAILURE=1 &&
- export GIT_REMOTE_TESTGIT_FAILURE &&
- cd localclone &&
- test_must_fail git fetch 2>&1 | \
- grep "Error while running fast-import"
- )
-'
-
-# We sleep to give fast-export a chance to catch the SIGPIPE
-test_expect_failure 'proper failure checks for pushing' '
- (GIT_REMOTE_TESTGIT_FAILURE=1 &&
- export GIT_REMOTE_TESTGIT_FAILURE &&
- GIT_REMOTE_TESTGIT_SLEEPY=1 &&
- export GIT_REMOTE_TESTGIT_SLEEPY &&
- cd localclone &&
- test_must_fail git push --all 2>&1 | \
- grep "Error while running fast-export"
- )
-'
-
-test_done
)
'
+test_expect_success 'push update refs disabled by no-private-update' '
+ (cd local &&
+ echo more-update >>file &&
+ git commit -a -m more-update &&
+ git rev-parse --verify testgit/origin/heads/update >expect &&
+ GIT_REMOTE_TESTGIT_NO_PRIVATE_UPDATE=t git push origin update &&
+ git rev-parse --verify testgit/origin/heads/update >actual &&
+ test_cmp expect actual
+ )
+'
+
test_expect_success 'push update refs failure' '
(cd local &&
git checkout update &&
--- /dev/null
+#!/bin/sh
+
+test_description='ext::cmd remote "connect" helper'
+. ./test-lib.sh
+
+test_expect_success setup '
+ test_tick &&
+ git commit --allow-empty -m initial &&
+ test_tick &&
+ git commit --allow-empty -m second &&
+ test_tick &&
+ git commit --allow-empty -m third &&
+ test_tick &&
+ git tag -a -m "tip three" three &&
+
+ test_tick &&
+ git commit --allow-empty -m fourth
+'
+
+test_expect_success clone '
+ cmd=$(echo "echo >&2 ext::sh invoked && %S .." | sed -e "s/ /% /g") &&
+ git clone "ext::sh -c %S% ." dst &&
+ git for-each-ref refs/heads/ refs/tags/ >expect &&
+ (
+ cd dst &&
+ git config remote.origin.url "ext::sh -c $cmd" &&
+ git for-each-ref refs/heads/ refs/tags/
+ ) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'update following tag' '
+ test_tick &&
+ git commit --allow-empty -m fifth &&
+ test_tick &&
+ git tag -a -m "tip five" five &&
+ git for-each-ref refs/heads/ refs/tags/ >expect &&
+ (
+ cd dst &&
+ git pull &&
+ git for-each-ref refs/heads/ refs/tags/ >../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_expect_success 'update backfilled tag' '
+ test_tick &&
+ git commit --allow-empty -m sixth &&
+ test_tick &&
+ git tag -a -m "tip two" two three^1 &&
+ git for-each-ref refs/heads/ refs/tags/ >expect &&
+ (
+ cd dst &&
+ git pull &&
+ git for-each-ref refs/heads/ refs/tags/ >../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_expect_success 'update backfilled tag without primary transfer' '
+ test_tick &&
+ git tag -a -m "tip one " one two^1 &&
+ git for-each-ref refs/heads/ refs/tags/ >expect &&
+ (
+ cd dst &&
+ git pull &&
+ git for-each-ref refs/heads/ refs/tags/ >../actual
+ ) &&
+ test_cmp expect actual
+'
+
+test_done
! grep one output
'
+test_expect_success 'rev-list A..B and rev-list ^A B are the same' '
+ git commit --allow-empty -m another &&
+ git tag -a -m "annotated" v1.0 &&
+ git rev-list --objects ^v1.0^ v1.0 >expect &&
+ git rev-list --objects v1.0^..v1.0 >actual &&
+ test_cmp expect actual
+'
+
test_done
}
'
+test_expect_success '--full-diff is not affected by --parents' '
+ git log -p --pretty="%H" --full-diff -- file >expected &&
+ git log -p --pretty="%H" --full-diff --parents -- file >actual &&
+ test_cmp expected actual
+'
+
test_done
printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file &&
echo foo >dir/file-in-the-way &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
echo 11 >>sub/file &&
echo more >>dir/file-in-the-way &&
mkdir one &&
echo stuff >one/file &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
git mv one/file destdir &&
git commit -m "Renamed to destdir" &&
echo stuff >one/file &&
echo other >two/file &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
git rm -rf one &&
git mv two/file one &&
echo stuff >original &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
mkdir two &&
>two/file &&
mkdir one two &&
touch one/file two/file &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
git rm -rf one &&
git mv original one &&
printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
git mv original rename &&
echo 11 >>rename &&
mkdir df &&
printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file &&
git add -A &&
- git commit -m "Common commmit" &&
+ git commit -m "Common commit" &&
git mv df/file temp &&
rm -rf df &&
git reset --hard HEAD^ &&
git checkout -b b4 origin &&
advance e &&
- advance f
+ advance f &&
+ git checkout -b brokenbase origin &&
+ git checkout -b b5 --track brokenbase &&
+ advance g &&
+ git branch -d brokenbase &&
+ git checkout -b b6 origin
) &&
git checkout -b follower --track master &&
- advance g
+ advance h
'
script='s/^..\(b.\)[ 0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
b2 origin/master: ahead 1, behind 1
b3 origin/master: behind 1
b4 origin/master: ahead 2
+b5 brokenbase: gone
+b6 origin/master
EOF
test_expect_success 'branch -vv' '
test_i18ncmp expect actual
'
-test_expect_success 'checkout' '
+test_expect_success 'checkout (diverged from upstream)' '
(
cd test && git checkout b1
) >actual &&
test_i18ngrep "is ahead of" actual
'
-test_expect_success 'status' '
+test_expect_success 'checkout (upstream is gone)' '
+ (
+ cd test &&
+ git checkout b5
+ ) >actual &&
+ test_i18ngrep "is based on .*, but the upstream is gone." actual
+'
+
+test_expect_success 'checkout (up-to-date with upstream)' '
+ (
+ cd test && git checkout b6
+ ) >actual &&
+ test_i18ngrep "Your branch is up-to-date with .origin/master" actual
+'
+
+test_expect_success 'status (diverged from upstream)' '
(
cd test &&
git checkout b1 >/dev/null &&
test_i18ngrep "have 1 and 1 different" actual
'
+test_expect_success 'status (upstream is gone)' '
+ (
+ cd test &&
+ git checkout b5 >/dev/null &&
+ # reports nothing to commit
+ test_must_fail git commit --dry-run
+ ) >actual &&
+ test_i18ngrep "is based on .*, but the upstream is gone." actual
+'
+
+test_expect_success 'status (up-to-date with upstream)' '
+ (
+ cd test &&
+ git checkout b6 >/dev/null &&
+ # reports nothing to commit
+ test_must_fail git commit --dry-run
+ ) >actual &&
+ test_i18ngrep "Your branch is up-to-date with .origin/master" actual
+'
+
+cat >expect <<\EOF
+## b1...origin/master [ahead 1, behind 1]
+EOF
+
+test_expect_success 'status -s -b (diverged from upstream)' '
+ (
+ cd test &&
+ git checkout b1 >/dev/null &&
+ git status -s -b | head -1
+ ) >actual &&
+ test_i18ncmp expect actual
+'
+
+cat >expect <<\EOF
+## b5...brokenbase [gone]
+EOF
+
+test_expect_success 'status -s -b (upstream is gone)' '
+ (
+ cd test &&
+ git checkout b5 >/dev/null &&
+ git status -s -b | head -1
+ ) >actual &&
+ test_i18ncmp expect actual
+'
+
+cat >expect <<\EOF
+## b6...origin/master
+EOF
+
+test_expect_success 'status -s -b (up-to-date with upstream)' '
+ (
+ cd test &&
+ git checkout b6 >/dev/null &&
+ git status -s -b | head -1
+ ) >actual &&
+ test_i18ncmp expect actual
+'
+
test_expect_success 'fail to track lightweight tags' '
git checkout master &&
git tag light &&
test "$HASH2" = "$(git replace -l)" &&
test "$HASH2" = "$(git replace)" &&
aa=${HASH2%??????????????????????????????????????} &&
- test "$HASH2" = "$(git replace -l "$aa*")" &&
+ test "$HASH2" = "$(git replace --list "$aa*")" &&
test_must_fail git replace -d $R &&
- test_must_fail git replace -d &&
+ test_must_fail git replace --delete &&
test_must_fail git replace -l -d $HASH2 &&
git replace -d $HASH2 &&
git show $HASH2 | grep "A U Thor" &&
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_must_fail git replace --force &&
test "$HASH2" = "$(git replace)"
'
test_cmp file.replaced file
'
+test_expect_success 'replaced and replacement objects must be of the same type' '
+ test_must_fail git replace mytag $HASH1 &&
+ test_must_fail git replace HEAD^{tree} HEAD~1 &&
+ BLOB=$(git rev-parse :file) &&
+ test_must_fail git replace HEAD^ $BLOB
+'
+
+test_expect_success '-f option bypasses the type check' '
+ git replace -f mytag $HASH1 &&
+ git replace --force HEAD^{tree} HEAD~1 &&
+ git replace -f HEAD^ $BLOB
+'
+
+test_expect_success 'replace ref cleanup' '
+ test -n "$(git replace)" &&
+ git replace -d $(git replace) &&
+ test -z "$(git replace)"
+'
+
test_done
test_description='Test git rev-parse with different parent options'
. ./test-lib.sh
-. "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
-
-date >path0
-git update-index --add path0
-save_tag tree git write-tree
-hide_error save_tag start unique_commit "start" tree
-save_tag second unique_commit "second" tree -p start
-hide_error save_tag start2 unique_commit "start2" tree
-save_tag two_parents unique_commit "next" tree -p second -p start2
-save_tag final unique_commit "final" tree -p two_parents
-
-test_expect_success 'start is valid' 'git rev-parse start | grep "^[0-9a-f]\{40\}$"'
-test_expect_success 'start^0' "test $(cat .git/refs/tags/start) = $(git rev-parse start^0)"
-test_expect_success 'start^1 not valid' "if git rev-parse --verify start^1; then false; else :; fi"
-test_expect_success 'second^1 = second^' "test $(git rev-parse second^1) = $(git rev-parse second^)"
-test_expect_success 'final^1^1^1' "test $(git rev-parse start) = $(git rev-parse final^1^1^1)"
-test_expect_success 'final^1^1^1 = final^^^' "test $(git rev-parse final^1^1^1) = $(git rev-parse final^^^)"
-test_expect_success 'final^1^2' "test $(git rev-parse start2) = $(git rev-parse final^1^2)"
-test_expect_success 'final^1^2 != final^1^1' "test $(git rev-parse final^1^2) != $(git rev-parse final^1^1)"
-test_expect_success 'final^1^3 not valid' "if git rev-parse --verify final^1^3; then false; else :; fi"
-test_expect_success '--verify start2^1' 'test_must_fail git rev-parse --verify start2^1'
-test_expect_success '--verify start2^0' 'git rev-parse --verify start2^0'
-test_expect_success 'final^1^@ = final^1^1 final^1^2' "test \"$(git rev-parse final^1^@)\" = \"$(git rev-parse final^1^1 final^1^2)\""
-test_expect_success 'final^1^! = final^1 ^final^1^1 ^final^1^2' "test \"$(git rev-parse final^1^\!)\" = \"$(git rev-parse final^1 ^final^1^1 ^final^1^2)\""
-
-test_expect_success 'repack for next test' 'git repack -a -d'
+
+test_cmp_rev_output () {
+ git rev-parse --verify "$1" >expect &&
+ eval "$2" >actual &&
+ test_cmp expect actual
+}
+
+test_expect_success 'setup' '
+ test_commit start &&
+ test_commit second &&
+ git checkout --orphan tmp &&
+ test_commit start2 &&
+ git checkout master &&
+ git merge -m next start2 &&
+ test_commit final
+'
+
+test_expect_success 'start is valid' '
+ git rev-parse start | grep "^[0-9a-f]\{40\}$"
+'
+
+test_expect_success 'start^0' '
+ test_cmp_rev_output tags/start "git rev-parse start^0"
+'
+
+test_expect_success 'start^1 not valid' '
+ test_must_fail git rev-parse --verify start^1
+'
+
+test_expect_success 'second^1 = second^' '
+ test_cmp_rev_output second^ "git rev-parse second^1"
+'
+
+test_expect_success 'final^1^1^1' '
+ test_cmp_rev_output start "git rev-parse final^1^1^1"
+'
+
+test_expect_success 'final^1^1^1 = final^^^' '
+ test_cmp_rev_output final^^^ "git rev-parse final^1^1^1"
+'
+
+test_expect_success 'final^1^2' '
+ test_cmp_rev_output start2 "git rev-parse final^1^2"
+'
+
+test_expect_success 'final^1^2 != final^1^1' '
+ test $(git rev-parse final^1^2) != $(git rev-parse final^1^1)
+'
+
+test_expect_success 'final^1^3 not valid' '
+ test_must_fail git rev-parse --verify final^1^3
+'
+
+test_expect_success '--verify start2^1' '
+ test_must_fail git rev-parse --verify start2^1
+'
+
+test_expect_success '--verify start2^0' '
+ git rev-parse --verify start2^0
+'
+
+test_expect_success 'final^1^@ = final^1^1 final^1^2' '
+ git rev-parse final^1^1 final^1^2 >expect &&
+ git rev-parse final^1^@ >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'final^1^! = final^1 ^final^1^1 ^final^1^2' '
+ git rev-parse final^1 ^final^1^1 ^final^1^2 >expect &&
+ git rev-parse final^1^! >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'repack for next test' '
+ git repack -a -d
+'
+
test_expect_success 'short SHA-1 works' '
- start=`git rev-parse --verify start` &&
- echo $start &&
- abbrv=`echo $start | sed s/.\$//` &&
- echo $abbrv &&
- abbrv=`git rev-parse --verify $abbrv` &&
- echo $abbrv &&
- test $start = $abbrv'
+ start=$(git rev-parse --verify start) &&
+ test_cmp_rev_output start "git rev-parse ${start%?}"
+'
test_done
test_cmp expect actual
'
+test_expect_success 'star pathspec globs' '
+ cat >expect <<-\EOF &&
+ bracket
+ star
+ vanilla
+ EOF
+ git log --format=%s -- ":(glob)f*" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'bracket pathspec globs and matches literal brackets' '
cat >expect <<-\EOF &&
bracket
test_cmp expect actual
'
+test_expect_success 'bracket pathspec globs and matches literal brackets' '
+ cat >expect <<-\EOF &&
+ bracket
+ vanilla
+ EOF
+ git log --format=%s -- ":(glob)f[o][o]" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'no-glob option matches literally (vanilla)' '
echo vanilla >expect &&
git --literal-pathspecs log --format=%s -- foo >actual &&
test_cmp expect actual
'
+test_expect_success 'no-glob option matches literally (vanilla)' '
+ echo vanilla >expect &&
+ git log --format=%s -- ":(literal)foo" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'no-glob option matches literally (star)' '
echo star >expect &&
git --literal-pathspecs log --format=%s -- "f*" >actual &&
test_cmp expect actual
'
+test_expect_success 'no-glob option matches literally (star)' '
+ echo star >expect &&
+ git log --format=%s -- ":(literal)f*" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'no-glob option matches literally (bracket)' '
echo bracket >expect &&
git --literal-pathspecs log --format=%s -- "f[o][o]" >actual &&
test_cmp expect actual
'
+test_expect_success 'no-glob option matches literally (bracket)' '
+ echo bracket >expect &&
+ git log --format=%s -- ":(literal)f[o][o]" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'no-glob option disables :(literal)' '
+ : >expect &&
+ git --literal-pathspecs log --format=%s -- ":(literal)foo" >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'no-glob environment variable works' '
echo star >expect &&
GIT_LITERAL_PATHSPECS=1 git log --format=%s -- "f*" >actual &&
test_cmp expect actual
'
+test_expect_success 'setup xxx/bar' '
+ mkdir xxx &&
+ test_commit xxx xxx/bar
+'
+
+test_expect_success '**/ works with :(glob)' '
+ cat >expect <<-\EOF &&
+ xxx
+ unrelated
+ EOF
+ git log --format=%s -- ":(glob)**/bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '**/ does not work with --noglob-pathspecs' '
+ : >expect &&
+ git --noglob-pathspecs log --format=%s -- "**/bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '**/ works with :(glob) and --noglob-pathspecs' '
+ cat >expect <<-\EOF &&
+ xxx
+ unrelated
+ EOF
+ git --noglob-pathspecs log --format=%s -- ":(glob)**/bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '**/ works with --glob-pathspecs' '
+ cat >expect <<-\EOF &&
+ xxx
+ unrelated
+ EOF
+ git --glob-pathspecs log --format=%s -- "**/bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '**/ does not work with :(literal) and --glob-pathspecs' '
+ : >expect &&
+ git --glob-pathspecs log --format=%s -- ":(literal)**/bar" >actual &&
+ test_cmp expect actual
+'
+
test_done
--- /dev/null
+#!/bin/sh
+
+test_description='test case insensitive pathspec limiting'
+. ./test-lib.sh
+
+if test_have_prereq CASE_INSENSITIVE_FS
+then
+ skip_all='skipping case sensitive tests - case insensitive file system'
+ test_done
+fi
+
+test_expect_success 'create commits with glob characters' '
+ test_commit bar bar &&
+ test_commit bAr bAr &&
+ test_commit BAR BAR &&
+ mkdir foo &&
+ test_commit foo/bar foo/bar &&
+ test_commit foo/bAr foo/bAr &&
+ test_commit foo/BAR foo/BAR &&
+ mkdir fOo &&
+ test_commit fOo/bar fOo/bar &&
+ test_commit fOo/bAr fOo/bAr &&
+ test_commit fOo/BAR fOo/BAR &&
+ mkdir FOO &&
+ test_commit FOO/bar FOO/bar &&
+ test_commit FOO/bAr FOO/bAr &&
+ test_commit FOO/BAR FOO/BAR
+'
+
+test_expect_success 'tree_entry_interesting matches bar' '
+ echo bar >expect &&
+ git log --format=%s -- "bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'tree_entry_interesting matches :(icase)bar' '
+ cat <<-EOF >expect &&
+ BAR
+ bAr
+ bar
+ EOF
+ git log --format=%s -- ":(icase)bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'tree_entry_interesting matches :(icase)bar with prefix' '
+ cat <<-EOF >expect &&
+ fOo/BAR
+ fOo/bAr
+ fOo/bar
+ EOF
+ ( cd fOo && git log --format=%s -- ":(icase)bar" ) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'tree_entry_interesting matches :(icase)bar with empty prefix' '
+ cat <<-EOF >expect &&
+ FOO/BAR
+ FOO/bAr
+ FOO/bar
+ fOo/BAR
+ fOo/bAr
+ fOo/bar
+ foo/BAR
+ foo/bAr
+ foo/bar
+ EOF
+ ( cd fOo && git log --format=%s -- ":(icase)../foo/bar" ) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'match_pathspec_depth matches :(icase)bar' '
+ cat <<-EOF >expect &&
+ BAR
+ bAr
+ bar
+ EOF
+ git ls-files ":(icase)bar" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'match_pathspec_depth matches :(icase)bar with prefix' '
+ cat <<-EOF >expect &&
+ fOo/BAR
+ fOo/bAr
+ fOo/bar
+ EOF
+ ( cd fOo && git ls-files --full-name ":(icase)bar" ) >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'match_pathspec_depth matches :(icase)bar with empty prefix' '
+ cat <<-EOF >expect &&
+ bar
+ fOo/BAR
+ fOo/bAr
+ fOo/bar
+ EOF
+ ( cd fOo && git ls-files --full-name ":(icase)bar" ../bar ) >actual &&
+ test_cmp expect actual
+'
+
+test_done
git gc
'
+test_expect_success 'gc does not leave behind pid file' '
+ git gc &&
+ test_path_is_missing .git/gc.pid
+'
+
test_expect_success 'gc --gobbledegook' '
test_expect_code 129 git gc --nonsense 2>err &&
test_i18ngrep "[Uu]sage: git gc" err
rm -f moved symlink
+test_expect_success 'setup submodule' '
+ git commit -m initial &&
+ git reset --hard &&
+ git submodule add ./. sub &&
+ echo content >file &&
+ git add file &&
+ git commit -m "added sub and file"
+'
+
+test_expect_success 'git mv cannot move a submodule in a file' '
+ test_must_fail git mv sub file
+'
+
+test_expect_success 'git mv moves a submodule with a .git directory and no .gitmodules' '
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ git rm .gitmodules &&
+ (
+ cd sub &&
+ rm -f .git &&
+ cp -a ../.git/modules/sub .git &&
+ GIT_WORK_TREE=. git config --unset core.worktree
+ ) &&
+ mkdir mod &&
+ git mv sub mod/sub &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'git mv moves a submodule with a .git directory and .gitmodules' '
+ rm -rf mod &&
+ git reset --hard &&
+ git submodule update &&
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ (
+ cd sub &&
+ rm -f .git &&
+ cp -a ../.git/modules/sub .git &&
+ GIT_WORK_TREE=. git config --unset core.worktree
+ ) &&
+ mkdir mod &&
+ git mv sub mod/sub &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ echo mod/sub >expected &&
+ git config -f .gitmodules submodule.sub.path >actual &&
+ test_cmp expected actual &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'git mv moves a submodule with gitfile' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ (
+ cd mod &&
+ git mv ../sub/ .
+ ) &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ echo mod/sub >expected &&
+ git config -f .gitmodules submodule.sub.path >actual &&
+ test_cmp expected actual &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'mv does not complain when no .gitmodules file is found' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ git rm .gitmodules &&
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ git mv sub mod/sub 2>actual.err &&
+ ! test -s actual.err &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ git config -f .gitmodules foo.bar true &&
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ test_must_fail git mv sub mod/sub 2>actual.err &&
+ test -s actual.err &&
+ test -e sub &&
+ git diff-files --quiet -- sub &&
+ git add .gitmodules &&
+ git mv sub mod/sub 2>actual.err &&
+ ! test -s actual.err &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'mv issues a warning when section is not found in .gitmodules' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ git config -f .gitmodules --remove-section submodule.sub &&
+ git add .gitmodules &&
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
+ git mv sub mod/sub 2>actual.err &&
+ test_i18ncmp expect.err actual.err &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ git mv -n sub mod/sub 2>actual.err &&
+ test -f sub/.git &&
+ git diff-index --exit-code HEAD &&
+ git update-index --refresh &&
+ git diff-files --quiet -- sub .gitmodules
+'
+
test_done
test_cmp expect actual
'
+cat >nul_to_q_textconv <<'EOF'
+#!/bin/sh
+"$PERL_PATH" -pe 'y/\000/Q/' < "$1"
+EOF
+chmod +x nul_to_q_textconv
+
+test_expect_success 'setup textconv filters' '
+ echo a diff=foo >.gitattributes &&
+ git config diff.foo.textconv "\"$(pwd)\""/nul_to_q_textconv
+'
+
+test_expect_success 'grep does not honor textconv' '
+ test_must_fail git grep Qfile
+'
+
+test_expect_success 'grep --textconv honors textconv' '
+ echo "a:binaryQfile" >expect &&
+ git grep --textconv Qfile >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'grep --no-textconv does not honor textconv' '
+ test_must_fail git grep --no-textconv Qfile
+'
+
+test_expect_success 'grep --textconv blob honors textconv' '
+ echo "HEAD:a:binaryQfile" >expect &&
+ git grep --textconv Qfile HEAD:a >actual &&
+ test_cmp expect actual
+'
+
test_done
--- /dev/null
+#!/bin/sh
+
+test_description='filter-branch removal of trees with null sha1'
+. ./test-lib.sh
+
+test_expect_success 'setup: base commits' '
+ test_commit one &&
+ test_commit two &&
+ test_commit three
+'
+
+test_expect_success 'setup: a commit with a bogus null sha1 in the tree' '
+ {
+ git ls-tree HEAD &&
+ printf "160000 commit $_z40\\tbroken\\n"
+ } >broken-tree
+ echo "add broken entry" >msg &&
+
+ tree=$(git mktree <broken-tree) &&
+ test_tick &&
+ commit=$(git commit-tree $tree -p HEAD <msg) &&
+ git update-ref HEAD "$commit"
+'
+
+# we have to make one more commit on top removing the broken
+# entry, since otherwise our index does not match HEAD (and filter-branch will
+# complain). We could make the index match HEAD, but doing so would involve
+# writing a null sha1 into the index.
+test_expect_success 'setup: bring HEAD and index in sync' '
+ test_tick &&
+ git commit -a -m "back to normal"
+'
+
+test_expect_success 'filter commands are still checked' '
+ test_must_fail git filter-branch \
+ --force --prune-empty \
+ --index-filter "git rm --cached --ignore-unmatch three.t"
+'
+
+test_expect_success 'removing the broken entry works' '
+ echo three >expect &&
+ git filter-branch \
+ --force --prune-empty \
+ --index-filter "git rm --cached --ignore-unmatch broken" &&
+ git log -1 --format=%s >actual &&
+ test_cmp expect actual
+'
+
+test_done
test_cmp expect actual
'
-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)
-#
-# deleted by us: foo
-#
+test_expect_success 'M/D conflict does not segfault' '
+ 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)
+
+ deleted by us: foo
+
no changes added to commit (use "git add" and/or "git commit -a")
EOF
-
-test_expect_success 'M/D conflict does not segfault' '
mkdir mdconflict &&
(
cd mdconflict &&
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
+ 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 '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
+ 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_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
+ 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 &&
test_expect_success 'reset' '
git add a b &&
git reset &&
- test "$(git ls-files)" = ""
+
+ >expect &&
+ git ls-files >actual &&
+ test_cmp expect actual
'
test_expect_success 'reset HEAD' '
rm .git/index &&
git add a b &&
git reset a &&
- test "$(git ls-files)" = "b"
+
+ echo b >expect &&
+ git ls-files >actual &&
+ test_cmp expect actual
'
-test_expect_success 'reset -p' '
+test_expect_success PERL 'reset -p' '
rm .git/index &&
git add a &&
- echo y | git reset -p &&
- test "$(git ls-files)" = ""
+ echo y >yes &&
+ git reset -p <yes &&
+
+ >expect &&
+ git ls-files >actual &&
+ test_cmp expect actual
'
test_expect_success 'reset --soft is a no-op' '
rm .git/index &&
git add a &&
- git reset --soft
- test "$(git ls-files)" = "a"
+ git reset --soft &&
+
+ echo a >expect &&
+ git ls-files >actual &&
+ test_cmp expect actual
'
test_expect_success 'reset --hard' '
rm .git/index &&
git add a &&
+ test_when_finished "echo a >a" &&
git reset --hard &&
- test "$(git ls-files)" = "" &&
+
+ >expect &&
+ git ls-files >actual &&
+ test_cmp expect actual &&
test_path_is_missing a
'
git branch initial
'
+test_expect_success 'configuration parsing' '
+ test_when_finished "rm -f .gitmodules" &&
+ cat >.gitmodules <<-\EOF &&
+ [submodule "s"]
+ path
+ ignore
+ EOF
+ test_must_fail git status
+'
+
test_expect_success 'setup - repository in init subdirectory' '
mkdir init &&
(
'
-test_expect_success 'gracefully add submodule with a trailing slash' '
+test_expect_success 'gracefully add/reset submodule with a trailing slash' '
git reset --hard &&
git commit -m "commit subproject" init &&
git add init/ &&
test_must_fail git diff --exit-code --cached init &&
test $commit = $(git ls-files --stage |
- sed -n "s/^160000 \([^ ]*\).*/\1/p")
+ sed -n "s/^160000 \([^ ]*\).*/\1/p") &&
+ git reset init/ &&
+ git diff --exit-code --cached init
'
test_cmp expect .git
) &&
echo "repo" >expect &&
- git config -f .gitmodules submodule.repo.path >actual &&
- test_cmp expect actual &&
+ test_must_fail git config -f .gitmodules submodule.repo.path &&
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 &&
+ test_must_fail git config -f .gitmodules submodule.repo.url &&
echo "$submodurl/bare.git" >expect &&
git config -f .gitmodules submodule.repo_new.url >actual &&
test_cmp expect actual &&
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 &&
+ test_must_fail git config -f .gitmodules submodule.repo_new.path &&
+ test_must_fail git config -f .gitmodules submodule.repo_new.url &&
echo "$submodurl/bare.git" >expect &&
git config submodule.repo_new.url >actual &&
test_cmp expect actual &&
git add sub &&
git commit -m "init sub"
) &&
- test_config core.precomposeunicode true &&
git submodule add ./"$svname" &&
git submodule >&2 &&
test -n "$(git submodule | grep "$svname")"
test_cmp expected actual
"
+test_expect_success 'no ignore=all setting has any effect' "
+ git config -f .gitmodules submodule.sm1.path sm1 &&
+ git config -f .gitmodules submodule.sm1.ignore all &&
+ git config submodule.sm1.ignore all &&
+ git config diff.ignoreSubmodules all &&
+ git submodule summary >actual &&
+ cat >expected <<-EOF &&
+* sm1 $head1...$head2 (1):
+ > Add foo3
+
+EOF
+ test_cmp expected actual &&
+ git config --unset diff.ignoreSubmodules &&
+ git config --remove-section submodule.sm1 &&
+ git config -f .gitmodules --remove-section submodule.sm1
+"
+
+
commit_file sm1 &&
head3=$(
cd sm1 &&
test_expect_success '--for-status' "
git submodule summary --for-status HEAD^ >actual &&
test_i18ncmp actual - <<EOF
-# Submodule changes to be committed:
-#
-# * sm1 $head6...0000000:
-#
-# * sm2 0000000...$head7 (2):
-# > Add foo9
-#
+* sm1 $head6...0000000:
+
+* sm2 0000000...$head7 (2):
+ > Add foo9
+
EOF
"
git submodule add ../merging merging &&
test_tick &&
git commit -m "rebasing"
- )
+ ) &&
(cd super &&
git submodule add ../none none &&
test_tick &&
'
test_expect_success 'using invalid commit with -C' '
- test_must_fail git commit -C bogus
+ test_must_fail git commit --allow-empty -C bogus
'
test_expect_success 'nothing to commit' '
test_i18ngrep "use \"git rm --cached <file>\.\.\.\" to unstage" output
'
+strip_comments () {
+ tab=' '
+ sed "s/^\# //; s/^\#$//; s/^#$tab/$tab/" <"$1" >"$1".tmp &&
+ rm "$1" && mv "$1".tmp "$1"
+}
+
test_expect_success 'status --column' '
- COLUMNS=50 git status --column="column dense" >output &&
cat >expect <<\EOF &&
# On branch master
# Changes to be committed:
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
-# dir1/untracked dir2/untracked untracked
-# dir2/modified output
+# dir1/untracked dir2/untracked output
+# dir2/modified expect untracked
+#
EOF
+ COLUMNS=50 git -c status.displayCommentPrefix=true status --column="column dense" >output &&
+ test_i18ncmp expect output
+'
+
+test_expect_success 'status --column status.displayCommentPrefix=false' '
+ strip_comments expect &&
+ COLUMNS=49 git -c status.displayCommentPrefix=false status --column="column dense" >output &&
test_i18ncmp expect output
'
# expect
# output
# untracked
+#
EOF
-test_expect_success 'status (2)' '
- git status >output &&
+test_expect_success 'status with status.displayCommentPrefix=true' '
+ git -c status.displayCommentPrefix=true status >output &&
+ test_i18ncmp expect output
+'
+
+test_expect_success 'status with status.displayCommentPrefix=false' '
+ strip_comments expect &&
+ git -c status.displayCommentPrefix=false status >output &&
test_i18ncmp expect output
'
+test_expect_success 'setup fake editor' '
+ cat >.git/editor <<-\EOF &&
+ #! /bin/sh
+ cp "$1" output
+EOF
+ chmod 755 .git/editor
+'
+
+commit_template_commented () {
+ (
+ EDITOR=.git/editor &&
+ export EDITOR &&
+ # Fails due to empty message
+ test_must_fail git commit
+ ) &&
+ ! grep '^[^#]' output
+}
+
+test_expect_success 'commit ignores status.displayCommentPrefix=false in COMMIT_EDITMSG' '
+ commit_template_commented
+'
+
cat >expect <<\EOF
-# On branch master
-# Changes to be committed:
-# new file: dir2/added
-#
-# Changes not staged for commit:
-# modified: dir1/modified
-#
-# Untracked files:
-# dir1/untracked
-# dir2/modified
-# dir2/untracked
-# expect
-# output
-# untracked
+On branch master
+Changes to be committed:
+ new file: dir2/added
+
+Changes not staged for commit:
+ modified: dir1/modified
+
+Untracked files:
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ expect
+ output
+ untracked
+
EOF
test_expect_success 'status (advice.statusHints false)' '
git status -s --ignored >output &&
test_cmp expect output &&
- cat >expect <<-\EOF &&
- # On branch master
- # Changes to be committed:
- # (use "git reset HEAD <file>..." to unstage)
- #
- # new file: dir2/added
- #
- # 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: dir1/modified
- #
- # Untracked files:
- # (use "git add <file>..." to include in what will be committed)
- #
- # dir2/modified
- # Ignored files:
- # (use "git add -f <file>..." to include in what will be committed)
- #
- # .gitignore
- # dir1/untracked
- # dir2/untracked
- # expect
- # output
- # untracked
- EOF
+ cat >expect <<\EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ new file: dir2/added
+
+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: dir1/modified
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ dir2/modified
+
+Ignored files:
+ (use "git add -f <file>..." to include in what will be committed)
+
+ .gitignore
+ dir1/untracked
+ dir2/untracked
+ expect
+ output
+ untracked
+
+EOF
git status --ignored >output &&
test_i18ncmp expect output
'
git status -s --ignored >output &&
test_cmp expect output &&
- cat >expect <<-\EOF &&
- # On branch master
- # Changes to be committed:
- # (use "git reset HEAD <file>..." to unstage)
- #
- # new file: dir2/added
- #
- # 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: dir1/modified
- #
- # Ignored files:
- # (use "git add -f <file>..." to include in what will be committed)
- #
- # .gitignore
- # dir1/untracked
- # dir2/modified
- # dir2/untracked
- # expect
- # output
- # untracked
- EOF
+ cat >expect <<\EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ new file: dir2/added
+
+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: dir1/modified
+
+Ignored files:
+ (use "git add -f <file>..." to include in what will be committed)
+
+ .gitignore
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ expect
+ output
+ untracked
+
+EOF
git status --ignored >output &&
test_i18ncmp expect output
'
: >dir3/untracked2
'
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-# (use "git reset HEAD <file>..." to unstage)
-#
-# new file: dir2/added
-#
-# 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: dir1/modified
-#
-# Untracked files not listed (use -u option to show untracked files)
-EOF
test_expect_success 'status -uno' '
+ cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ new file: dir2/added
+
+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: dir1/modified
+
+Untracked files not listed (use -u option to show untracked files)
+EOF
git status -uno >output &&
test_i18ncmp expect output
'
test_i18ncmp expect output
'
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-# new file: dir2/added
-#
-# Changes not staged for commit:
-# modified: dir1/modified
-#
-# Untracked files not listed
-EOF
test_expect_success 'status -uno (advice.statusHints false)' '
+ cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+ new file: dir2/added
+
+Changes not staged for commit:
+ modified: dir1/modified
+
+Untracked files not listed
+EOF
test_config advice.statusHints false &&
git status -uno >output &&
test_i18ncmp expect output
test_cmp expect output
'
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-# (use "git reset HEAD <file>..." to unstage)
-#
-# new file: dir2/added
-#
-# 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: dir1/modified
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# dir1/untracked
-# dir2/modified
-# dir2/untracked
-# dir3/
-# expect
-# output
-# untracked
-EOF
test_expect_success 'status -unormal' '
+ cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ new file: dir2/added
+
+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: dir1/modified
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ dir3/
+ expect
+ output
+ untracked
+
+EOF
git status -unormal >output &&
test_i18ncmp expect output
'
test_cmp expect output
'
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-# (use "git reset HEAD <file>..." to unstage)
-#
-# new file: dir2/added
-#
-# 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: dir1/modified
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# dir1/untracked
-# dir2/modified
-# dir2/untracked
-# dir3/untracked1
-# dir3/untracked2
-# expect
-# output
-# untracked
-EOF
test_expect_success 'status -uall' '
+ cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ new file: dir2/added
+
+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: dir1/modified
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ dir3/untracked1
+ dir3/untracked2
+ expect
+ output
+ untracked
+
+EOF
git status -uall >output &&
test_i18ncmp expect output
'
test_cmp expect output
'
-cat >expect <<\EOF
-# On branch master
-# Changes to be committed:
-# (use "git reset HEAD <file>..." to unstage)
-#
-# new file: ../dir2/added
-#
-# 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: modified
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# untracked
-# ../dir2/modified
-# ../dir2/untracked
-# ../expect
-# ../output
-# ../untracked
-EOF
-
test_expect_success 'status with relative paths' '
+ cat >expect <<\EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ new file: ../dir2/added
+
+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: modified
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ untracked
+ ../dir2/modified
+ ../dir2/untracked
+ ../expect
+ ../output
+ ../untracked
+
+EOF
(cd dir1 && git status) >output &&
test_i18ncmp expect output
'
'
-cat >expect <<\EOF
-# On branch <GREEN>master<RESET>
-# Changes to be committed:
-# (use "git reset HEAD <file>..." to unstage)
-#
-# <GREEN>new file: dir2/added<RESET>
-#
-# 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)
-#
-# <RED>modified: dir1/modified<RESET>
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# <BLUE>dir1/untracked<RESET>
-# <BLUE>dir2/modified<RESET>
-# <BLUE>dir2/untracked<RESET>
-# <BLUE>expect<RESET>
-# <BLUE>output<RESET>
-# <BLUE>untracked<RESET>
-EOF
-
test_expect_success 'status with color.ui' '
+ cat >expect <<\EOF &&
+On branch <GREEN>master<RESET>
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ <GREEN>new file: dir2/added<RESET>
+
+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)
+
+ <RED>modified: dir1/modified<RESET>
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ <BLUE>dir1/untracked<RESET>
+ <BLUE>dir2/modified<RESET>
+ <BLUE>dir2/untracked<RESET>
+ <BLUE>expect<RESET>
+ <BLUE>output<RESET>
+ <BLUE>untracked<RESET>
+
+EOF
test_config color.ui always &&
git status | test_decode_color >output &&
test_i18ncmp expect output
'
-cat >expect <<\EOF
-# On branch master
-# Changes to be committed:
-# (use "git reset HEAD <file>..." to unstage)
-#
-# new file: dir2/added
-#
-# 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: dir1/modified
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# dir1/untracked
-# dir2/modified
-# dir2/untracked
-# expect
-# output
-# untracked
-EOF
test_expect_success 'status without relative paths' '
+ cat >expect <<\EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ new file: dir2/added
+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: dir1/modified
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ expect
+ output
+ untracked
+
+EOF
test_config status.relativePaths false &&
(cd dir1 && git status) >output &&
test_i18ncmp expect output
'
-cat <<EOF >expect
-# On branch master
-# Changes to be committed:
-# (use "git reset HEAD <file>..." to unstage)
-#
-# modified: dir1/modified
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# dir1/untracked
-# dir2/
-# expect
-# output
-# untracked
-EOF
test_expect_success 'dry-run of partial commit excluding new file in index' '
+ cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ modified: dir1/modified
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ dir1/untracked
+ dir2/
+ expect
+ output
+ untracked
+
+EOF
git commit --dry-run dir1/modified >output &&
test_i18ncmp expect output
'
git add sm
'
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-# (use "git reset HEAD <file>..." to unstage)
-#
-# new file: dir2/added
-# new file: sm
-#
-# 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: dir1/modified
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# dir1/untracked
-# dir2/modified
-# dir2/untracked
-# expect
-# output
-# untracked
-EOF
test_expect_success 'status submodule summary is disabled by default' '
+ cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ new file: dir2/added
+ new file: sm
+
+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: dir1/modified
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ expect
+ output
+ untracked
+
+EOF
git status >output &&
test_i18ncmp expect output
'
head=$(cd sm && git rev-parse --short=7 --verify HEAD)
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-# (use "git reset HEAD <file>..." to unstage)
-#
-# new file: dir2/added
-# new file: sm
-#
-# 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: dir1/modified
-#
-# Submodule changes to be committed:
-#
-# * sm 0000000...$head (1):
-# > Add foo
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# dir1/untracked
-# dir2/modified
-# dir2/untracked
-# expect
-# output
-# untracked
-EOF
test_expect_success 'status submodule summary' '
+ cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ new file: dir2/added
+ new file: sm
+
+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: dir1/modified
+
+Submodule changes to be committed:
+
+* sm 0000000...$head (1):
+ > Add foo
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ expect
+ output
+ untracked
+
+EOF
git config status.submodulesummary 10 &&
git status >output &&
test_i18ncmp expect output
'
+test_expect_success 'status submodule summary with status.displayCommentPrefix=false' '
+ strip_comments expect &&
+ git -c status.displayCommentPrefix=false status >output &&
+ test_i18ncmp expect output
+'
+
+test_expect_success 'commit with submodule summary ignores status.displayCommentPrefix' '
+ commit_template_commented
+'
+
cat >expect <<EOF
M dir1/modified
A dir2/added
test_cmp expect output
'
-cat >expect <<EOF
-# On branch master
-# 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: dir1/modified
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# dir1/untracked
-# dir2/modified
-# dir2/untracked
-# expect
-# output
-# untracked
+test_expect_success 'status submodule summary (clean submodule): commit' '
+ cat >expect <<EOF &&
+On branch master
+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: dir1/modified
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ expect
+ output
+ untracked
+
no changes added to commit (use "git add" and/or "git commit -a")
EOF
-test_expect_success 'status submodule summary (clean submodule): commit' '
git commit -m "commit submodule" &&
git config status.submodulesummary 10 &&
test_must_fail git commit --dry-run >output &&
test_cmp expect output
'
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-# (use "git reset HEAD^1 <file>..." to unstage)
-#
-# new file: dir2/added
-# new file: sm
-#
-# 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: dir1/modified
-#
-# Submodule changes to be committed:
-#
-# * sm 0000000...$head (1):
-# > Add foo
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# dir1/untracked
-# dir2/modified
-# dir2/untracked
-# expect
-# output
-# untracked
-EOF
test_expect_success 'commit --dry-run submodule summary (--amend)' '
+ cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD^1 <file>..." to unstage)
+
+ new file: dir2/added
+ new file: sm
+
+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: dir1/modified
+
+Submodule changes to be committed:
+
+* sm 0000000...$head (1):
+ > Add foo
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ expect
+ output
+ untracked
+
+EOF
git config status.submodulesummary 10 &&
git commit --dry-run --amend >output &&
test_i18ncmp expect output
new_head=$(cd sm && git rev-parse --short=7 --verify HEAD)
touch .gitmodules
-cat > expect << EOF
-# On branch master
-# Changes to be committed:
-# (use "git reset HEAD <file>..." to unstage)
-#
-# modified: sm
-#
-# 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: dir1/modified
-#
-# Submodule changes to be committed:
-#
-# * sm $head...$new_head (1):
-# > Add bar
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# .gitmodules
-# dir1/untracked
-# dir2/modified
-# dir2/untracked
-# expect
-# output
-# untracked
-EOF
-
test_expect_success '--ignore-submodules=untracked suppresses submodules with untracked content' '
+ cat > expect << EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ modified: sm
+
+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: dir1/modified
+
+Submodule changes to be committed:
+
+* sm $head...$new_head (1):
+ > Add bar
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ .gitmodules
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ expect
+ output
+ untracked
+
+EOF
echo modified sm/untracked &&
git status --ignore-submodules=untracked >output &&
test_i18ncmp expect output
git config -f .gitmodules --remove-section submodule.subname
'
-cat > expect << EOF
-# On branch master
-# Changes to be committed:
-# (use "git reset HEAD <file>..." to unstage)
-#
-# modified: sm
-#
-# 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)
-# (commit or discard the untracked or modified content in submodules)
-#
-# modified: dir1/modified
-# modified: sm (modified content)
-#
-# Submodule changes to be committed:
-#
-# * sm $head...$new_head (1):
-# > Add bar
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# .gitmodules
-# dir1/untracked
-# dir2/modified
-# dir2/untracked
-# expect
-# output
-# untracked
-EOF
-
test_expect_success "--ignore-submodules=untracked doesn't suppress submodules with modified content" '
+ cat > expect << EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ modified: sm
+
+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)
+ (commit or discard the untracked or modified content in submodules)
+
+ modified: dir1/modified
+ modified: sm (modified content)
+
+Submodule changes to be committed:
+
+* sm $head...$new_head (1):
+ > Add bar
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ .gitmodules
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ expect
+ output
+ untracked
+
+EOF
git status --ignore-submodules=untracked > output &&
test_i18ncmp expect output
'
head2=$(cd sm && git commit -q -m "2nd commit" foo && git rev-parse --short=7 --verify HEAD)
-cat > expect << EOF
-# On branch master
-# Changes to be committed:
-# (use "git reset HEAD <file>..." to unstage)
-#
-# modified: sm
-#
-# 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: dir1/modified
-# modified: sm (new commits)
-#
-# Submodule changes to be committed:
-#
-# * sm $head...$new_head (1):
-# > Add bar
-#
-# Submodules changed but not updated:
-#
-# * sm $new_head...$head2 (1):
-# > 2nd commit
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# .gitmodules
-# dir1/untracked
-# dir2/modified
-# dir2/untracked
-# expect
-# output
-# untracked
-EOF
-
test_expect_success "--ignore-submodules=untracked doesn't suppress submodule summary" '
+ cat > expect << EOF &&
+On branch master
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ modified: sm
+
+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: dir1/modified
+ modified: sm (new commits)
+
+Submodule changes to be committed:
+
+* sm $head...$new_head (1):
+ > Add bar
+
+Submodules changed but not updated:
+
+* sm $new_head...$head2 (1):
+ > 2nd commit
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ .gitmodules
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ expect
+ output
+ untracked
+
+EOF
git status --ignore-submodules=untracked > output &&
test_i18ncmp expect output
'
; expect
; output
; untracked
+;
EOF
test_expect_success "status (core.commentchar with submodule summary)" '
test_config core.commentchar ";" &&
- git status >output &&
+ git -c status.displayCommentPrefix=true status >output &&
test_i18ncmp expect output
'
test_expect_success "status (core.commentchar with two chars with submodule summary)" '
test_config core.commentchar ";;" &&
- git status >output &&
+ git -c status.displayCommentPrefix=true status >output &&
test_i18ncmp expect output
'
-cat > expect << EOF
-# On branch master
-# 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: dir1/modified
-#
-# Untracked files:
-# (use "git add <file>..." to include in what will be committed)
-#
-# .gitmodules
-# dir1/untracked
-# dir2/modified
-# dir2/untracked
-# expect
-# output
-# untracked
+test_expect_success "--ignore-submodules=all suppresses submodule summary" '
+ cat > expect << EOF &&
+On branch master
+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: dir1/modified
+
+Untracked files:
+ (use "git add <file>..." to include in what will be committed)
+
+ .gitmodules
+ dir1/untracked
+ dir2/modified
+ dir2/untracked
+ expect
+ output
+ untracked
+
no changes added to commit (use "git add" and/or "git commit -a")
EOF
-
-test_expect_success "--ignore-submodules=all suppresses submodule summary" '
git status --ignore-submodules=all > output &&
test_i18ncmp expect output
'
-test_expect_failure '.gitmodules ignore=all suppresses submodule summary' '
+test_expect_success '.gitmodules ignore=all suppresses submodule summary' '
git config --add -f .gitmodules submodule.subname.ignore all &&
git config --add -f .gitmodules submodule.subname.path sm &&
git status > output &&
git config -f .gitmodules --remove-section submodule.subname
'
-test_expect_failure '.git/config ignore=all suppresses submodule summary' '
+test_expect_success '.git/config ignore=all suppresses submodule summary' '
git config --add -f .gitmodules submodule.subname.ignore none &&
git config --add -f .gitmodules submodule.subname.path sm &&
git config --add submodule.subname.ignore all &&
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
+ 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_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
+ 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_when_finished "git rebase --abort" &&
ONTO=$(git rev-parse --short HEAD^^) &&
test_must_fail git rebase HEAD^ --onto HEAD^^ &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''.
+ (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_must_fail git rebase HEAD^ --onto HEAD^^ &&
echo three >main.txt &&
git add main.txt &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''.
+ (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_when_finished "git rebase --abort" &&
ONTO=$(git rev-parse --short rebase_i_conflicts) &&
test_must_fail git rebase -i rebase_i_conflicts &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''.
+ (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
'
ONTO=$(git rev-parse --short rebase_i_conflicts) &&
test_must_fail git rebase -i rebase_i_conflicts &&
git add main.txt &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''.
+ (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_when_finished "git rebase --abort" &&
ONTO=$(git rev-parse --short HEAD~2) &&
git rebase -i HEAD~2 &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently editing a commit while rebasing branch '\''rebase_i_edit'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''rebase_i_edit'\'' on '\''$ONTO'\''.
+ (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
'
ONTO=$(git rev-parse --short HEAD~3) &&
git rebase -i HEAD~3 &&
git reset HEAD^ &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently splitting a commit while rebasing branch '\''split_commit'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently splitting a commit while rebasing branch '\''split_commit'\'' on '\''$ONTO'\''.
+ (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
'
ONTO=$(git rev-parse --short HEAD~3) &&
git rebase -i HEAD~3 &&
git commit --amend -m "foo" &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently editing a commit while rebasing branch '\''amend_last'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''amend_last'\'' on '\''$ONTO'\''.
+ (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
'
ONTO=$(git rev-parse --short HEAD~3) &&
git rebase -i HEAD~3 &&
git rebase --continue &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+ (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
'
git rebase -i HEAD~3 &&
git rebase --continue &&
git reset HEAD^ &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+ (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
'
git rebase -i HEAD~3 &&
git rebase --continue &&
git commit --amend -m "foo" &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+ (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
'
git rebase -i HEAD~3 &&
git commit --amend -m "a" &&
git rebase --continue &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+ (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
'
git commit --amend -m "b" &&
git rebase --continue &&
git reset HEAD^ &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+ (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
'
git commit --amend -m "c" &&
git rebase --continue &&
git commit --amend -m "d" &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+ (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
'
git add main.txt &&
git commit -m "e" &&
git rebase --continue &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+ (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
'
git commit --amend -m "f" &&
git rebase --continue &&
git reset HEAD^ &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+ (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
'
git commit --amend -m "g" &&
git rebase --continue &&
git commit --amend -m "h" &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
- # (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
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+ (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_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 --continue")
- # (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
+ cat >expected <<\EOF &&
+On branch am_already_exists
+You are in the middle of an am session.
+ (fix conflicts and then run "git am --continue")
+ (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_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 --continue")
- # (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
+ cat >expected <<\EOF &&
+On branch am_not_exists
+You are in the middle of an am session.
+ (fix conflicts and then run "git am --continue")
+ (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
'
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
+ 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
'
git bisect bad &&
git bisect good one_bisect &&
TGT=$(git rev-parse --short two_bisect) &&
- cat >expected <<-EOF &&
- # HEAD detached at $TGT
- # You are currently bisecting, started from branch '\''bisect'\''.
- # (use "git bisect reset" to get back to the original branch)
- #
- nothing to commit (use -u to show untracked files)
- EOF
+ cat >expected <<EOF &&
+HEAD detached at $TGT
+You are currently bisecting, started from branch '\''bisect'\''.
+ (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_when_finished "git rebase --abort" &&
ONTO=$(git rev-parse --short HEAD^^) &&
test_must_fail git rebase HEAD^ --onto HEAD^^ &&
- cat >expected <<-EOF &&
- # rebase in progress; onto $ONTO
- # You are currently rebasing branch '\''statushints_disabled'\'' on '\''$ONTO'\''.
- #
- # Unmerged paths:
- # both modified: main.txt
- #
- no changes added to commit
- EOF
+ cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently rebasing branch '\''statushints_disabled'\'' on '\''$ONTO'\''.
+
+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 '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 cherry-pick --continue")
- # (use "git cherry-pick --abort" to cancel the cherry-pick operation)
- #
- # 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
+ TO_CHERRY_PICK=$(git rev-parse --short CHERRY_PICK_HEAD) &&
+ cat >expected <<EOF &&
+On branch cherry_branch
+You are currently cherry-picking commit $TO_CHERRY_PICK.
+ (fix conflicts and run "git cherry-pick --continue")
+ (use "git cherry-pick --abort" to cancel the cherry-pick operation)
+
+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
'
git reset --hard cherry_branch &&
test_when_finished "git cherry-pick --abort" &&
test_must_fail git cherry-pick cherry_branch_second &&
+ TO_CHERRY_PICK=$(git rev-parse --short CHERRY_PICK_HEAD) &&
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 cherry-pick --continue")
- # (use "git cherry-pick --abort" to cancel the cherry-pick operation)
- #
- # Changes to be committed:
- #
- # modified: main.txt
- #
- # Untracked files not listed (use -u option to show untracked files)
- EOF
+ cat >expected <<EOF &&
+On branch cherry_branch
+You are currently cherry-picking commit $TO_CHERRY_PICK.
+ (all conflicts fixed: run "git cherry-pick --continue")
+ (use "git cherry-pick --abort" to cancel the cherry-pick operation)
+
+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 'status showing detached at and from a tag' '
test_commit atag tagging &&
git checkout atag &&
- cat >expected <<-\EOF
- # HEAD detached at atag
- nothing to commit (use -u to show untracked files)
- EOF
+ cat >expected <<\EOF &&
+HEAD detached at atag
+nothing to commit (use -u to show untracked files)
+EOF
git status --untracked-files=no >actual &&
test_i18ncmp expected actual &&
git reset --hard HEAD^ &&
- cat >expected <<-\EOF
- # HEAD detached from atag
- nothing to commit (use -u to show untracked files)
- EOF
+ cat >expected <<\EOF &&
+HEAD detached from atag
+nothing to commit (use -u to show untracked files)
+EOF
git status --untracked-files=no >actual &&
test_i18ncmp expected actual
'
test_commit new to-revert.txt &&
TO_REVERT=$(git rev-parse --short HEAD^) &&
test_must_fail git revert $TO_REVERT &&
- cat >expected <<-EOF
- # On branch master
- # You are currently reverting commit $TO_REVERT.
- # (fix conflicts and run "git revert --continue")
- # (use "git revert --abort" to cancel the revert operation)
- #
- # Unmerged paths:
- # (use "git reset HEAD <file>..." to unstage)
- # (use "git add <file>..." to mark resolution)
- #
- # both modified: to-revert.txt
- #
- no changes added to commit (use "git add" and/or "git commit -a")
- EOF
+ cat >expected <<EOF &&
+On branch master
+You are currently reverting commit $TO_REVERT.
+ (fix conflicts and run "git revert --continue")
+ (use "git revert --abort" to cancel the revert operation)
+
+Unmerged paths:
+ (use "git reset HEAD <file>..." to unstage)
+ (use "git add <file>..." to mark resolution)
+
+ both modified: to-revert.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 while reverting commit (conflicts resolved)' '
echo reverted >to-revert.txt &&
git add to-revert.txt &&
- cat >expected <<-EOF
- # On branch master
- # You are currently reverting commit $TO_REVERT.
- # (all conflicts fixed: run "git revert --continue")
- # (use "git revert --abort" to cancel the revert operation)
- #
- # Changes to be committed:
- # (use "git reset HEAD <file>..." to unstage)
- #
- # modified: to-revert.txt
- #
- # Untracked files not listed (use -u option to show untracked files)
- EOF
+ cat >expected <<EOF &&
+On branch master
+You are currently reverting commit $TO_REVERT.
+ (all conflicts fixed: run "git revert --continue")
+ (use "git revert --abort" to cancel the revert operation)
+
+Changes to be committed:
+ (use "git reset HEAD <file>..." to unstage)
+
+ modified: to-revert.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 after reverting commit' '
git revert --continue &&
- cat >expected <<-\EOF
- # On branch master
- nothing to commit (use -u to show untracked files)
- EOF
+ cat >expected <<\EOF &&
+On branch master
+nothing to commit (use -u to show untracked files)
+EOF
git status --untracked-files=no >actual &&
test_i18ncmp expected actual
'
git checkout -b test6 branch1 &&
git submodule update -N &&
mv submod submod-movedaside &&
- git rm submod &&
+ git rm --cached submod &&
git commit -m "Submodule deleted from branch" &&
git checkout -b test6.a test6 &&
test_must_fail git merge master &&
git checkout -b test7 branch1 &&
git submodule update -N &&
mv submod submod-movedaside &&
- git rm submod &&
+ git rm --cached submod &&
echo not a submodule >submod &&
git add submod &&
git commit -m "Submodule path becomes file" &&
test_expect_success 'directory vs modified submodule' '
git checkout -b test11 branch1 &&
mv submod submod-movedaside &&
- git rm submod &&
+ git rm --cached submod &&
mkdir submod &&
echo not a submodule >submod/file16 &&
git add submod/file16 &&
'
cat >expected <<EOF
-fatal: git cat-file --textconv: unable to run textconv on :one.bin
+bin: test version 2
EOF
test_expect_success 'no filter specified' '
- git cat-file --textconv :one.bin 2>result
+ git cat-file --textconv :one.bin >result &&
test_cmp expected result
'
git config diff.test.cachetextconv false
'
-cat >expected <<EOF
-bin: test version 2
-EOF
-
test_expect_success 'cat-file without --textconv' '
git cat-file blob :one.bin >result &&
test_cmp expected result
'
test_expect_success 'cat-file without --textconv (symlink)' '
+ printf "%s" "one.bin" >expected &&
git cat-file blob :symlink.bin >result &&
- printf "%s" "one.bin" >expected
test_cmp expected result
'
test_expect_success 'cat-file --textconv on index (symlink)' '
- ! git cat-file --textconv :symlink.bin 2>result &&
- cat >expected <<\EOF &&
-fatal: git cat-file --textconv: unable to run textconv on :symlink.bin
-EOF
+ git cat-file --textconv :symlink.bin >result &&
test_cmp expected result
'
test_expect_success 'cat-file --textconv on HEAD (symlink)' '
- ! git cat-file --textconv HEAD:symlink.bin 2>result &&
- cat >expected <<EOF &&
-fatal: git cat-file --textconv: unable to run textconv on HEAD:symlink.bin
-EOF
+ git cat-file --textconv HEAD:symlink.bin >result &&
test_cmp expected result
'
rm -rf target
'
+test_expect_success 'init without -s/-T/-b/-t does not warn' '
+ test ! -d trunk &&
+ git svn init "$svnrepo"/project/trunk trunk 2>warning &&
+ test_must_fail grep -q prefix warning &&
+ rm -rf trunk &&
+ rm -f warning
+ '
+
+test_expect_success 'clone without -s/-T/-b/-t does not warn' '
+ test ! -d trunk &&
+ git svn clone "$svnrepo"/project/trunk 2>warning &&
+ test_must_fail grep -q prefix warning &&
+ rm -rf trunk &&
+ rm -f warning
+ '
+
+test_svn_configured_prefix () {
+ prefix=$1 &&
+ cat >expect <<EOF &&
+project/trunk:refs/remotes/${prefix}trunk
+project/branches/*:refs/remotes/${prefix}*
+project/tags/*:refs/remotes/${prefix}tags/*
+EOF
+ test ! -f actual &&
+ git --git-dir=project/.git config svn-remote.svn.fetch >>actual &&
+ git --git-dir=project/.git config svn-remote.svn.branches >>actual &&
+ git --git-dir=project/.git config svn-remote.svn.tags >>actual &&
+ test_cmp expect actual &&
+ rm -f expect actual
+}
+
+test_expect_success 'init with -s/-T/-b/-t without --prefix warns' '
+ test ! -d project &&
+ git svn init -s "$svnrepo"/project project 2>warning &&
+ grep -q prefix warning &&
+ test_svn_configured_prefix "" &&
+ rm -rf project &&
+ rm -f warning
+ '
+
+test_expect_success 'clone with -s/-T/-b/-t without --prefix warns' '
+ test ! -d project &&
+ git svn clone -s "$svnrepo"/project 2>warning &&
+ grep -q prefix warning &&
+ test_svn_configured_prefix "" &&
+ rm -rf project &&
+ rm -f warning
+ '
+
+test_expect_success 'init with -s/-T/-b/-t and --prefix does not warn' '
+ test ! -d project &&
+ git svn init -s "$svnrepo"/project project --prefix="" 2>warning &&
+ test_must_fail grep -q prefix warning &&
+ test_svn_configured_prefix "" &&
+ rm -rf project &&
+ rm -f warning
+ '
+
+test_expect_success 'clone with -s/-T/-b/-t and --prefix does not warn' '
+ test ! -d project &&
+ git svn clone -s "$svnrepo"/project --prefix="" 2>warning &&
+ test_must_fail grep -q prefix warning &&
+ test_svn_configured_prefix "" &&
+ rm -rf project &&
+ rm -f warning
+ '
+
test_done
git diff-tree -M -r M3^ M3 >actual &&
compare_diff_raw expect actual'
+cat >input <<INPUT_END
+commit refs/heads/M4
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+rename root
+COMMIT
+
+from refs/heads/M2^0
+R "" sub
+
+INPUT_END
+
+cat >expect <<EOF
+:100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100 file2/oldf sub/file2/oldf
+:100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 R100 file4 sub/file4
+:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 i/am/new/to/you sub/i/am/new/to/you
+:100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 R100 newdir/exec.sh sub/newdir/exec.sh
+:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100 newdir/interesting sub/newdir/interesting
+EOF
+test_expect_success \
+ 'M: rename root to subdirectory' \
+ 'git fast-import <input &&
+ git diff-tree -M -r M4^ M4 >actual &&
+ cat actual &&
+ compare_diff_raw expect actual'
+
###
### series N
###
git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
compare_diff_raw expect actual'
+test_expect_success \
+ 'N: copy root by path' \
+ 'cat >expect <<-\EOF &&
+ :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf oldroot/file2/newf
+ :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf oldroot/file2/oldf
+ :100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 C100 file4 oldroot/file4
+ :100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 C100 newdir/exec.sh oldroot/newdir/exec.sh
+ :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting oldroot/newdir/interesting
+ EOF
+ cat >input <<-INPUT_END &&
+ commit refs/heads/N-copy-root-path
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ copy root directory by (empty) path
+ COMMIT
+
+ from refs/heads/branch^0
+ C "" oldroot
+ INPUT_END
+ git fast-import <input &&
+ git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual &&
+ compare_diff_raw expect actual'
+
test_expect_success \
'N: delete directory by copying' \
'cat >expect <<-\EOF &&
'
#
-# notemodify, mark in committish
+# notemodify, mark in commit-ish
#
-test_expect_success 'S: notemodify with garbarge after mark committish must fail' '
+test_expect_success 'S: notemodify with garbarge after mark commit-ish must fail' '
test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
commit refs/heads/Snotes
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
data <<COMMIT
- commit S note committish
+ commit S note commit-ish
COMMIT
N :202 :302x
EOF
test_i18ngrep "space after tree-ish" err
'
+###
+### series T (ls)
+###
+# Setup is carried over from series S.
+
+test_expect_success 'T: ls root tree' '
+ sed -e "s/Z\$//" >expect <<-EOF &&
+ 040000 tree $(git rev-parse S^{tree}) Z
+ EOF
+ sha1=$(git rev-parse --verify S) &&
+ git fast-import --import-marks=marks <<-EOF >actual &&
+ ls $sha1 ""
+ EOF
+ test_cmp expect actual
+'
+
test_done
# syntax highlighting
-highlight --version >/dev/null 2>&1
+highlight_version=$(highlight --version </dev/null 2>/dev/null)
if [ $? -eq 127 ]; then
- say "Skipping syntax highlighting test, because 'highlight' was not found"
+ say "Skipping syntax highlighting tests: 'highlight' not found"
+elif test -z "$highlight_version"; then
+ say "Skipping syntax highlighting tests: incorrect 'highlight' found"
else
test_set_prereq HIGHLIGHT
cat >>gitweb_config.perl <<-\EOF
local -a COMPREPLY _words
local _cword
_words=( $1 )
- test "${1: -1}" = ' ' && _words+=('')
+ test "${1: -1}" = ' ' && _words[${#_words[@]}+1]=''
(( _cword = ${#_words[@]} - 1 ))
__git_wrap__git_main && print_comp
}
test_cmp expected "$actual"
'
+repo_with_newline='repo
+with
+newline'
+
+if mkdir "$repo_with_newline" 2>/dev/null
+then
+ test_set_prereq FUNNYNAMES
+else
+ say 'Your filesystem does not allow newlines in filenames.'
+fi
+
+test_expect_success FUNNYNAMES 'prompt - with newline in path' '
+ printf " (master)" >expected &&
+ git init "$repo_with_newline" &&
+ test_when_finished "rm -rf \"$repo_with_newline\"" &&
+ mkdir "$repo_with_newline"/subdir &&
+ (
+ cd "$repo_with_newline/subdir" &&
+ __git_ps1 >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
test_expect_success 'prompt - detached head' '
printf " ((%s...))" $(git log -1 --format="%h" --abbrev=13 b1^) >expected &&
test_config core.abbrev 13 &&
--valgrind-only=*)
valgrind_only=$(expr "z$1" : 'z[^=]*=\(.*\)')
shift ;;
- --valgrind-parallel=*)
- valgrind_parallel=$(expr "z$1" : 'z[^=]*=\(.*\)')
- shift ;;
- --valgrind-only-stride=*)
- valgrind_only_stride=$(expr "z$1" : 'z[^=]*=\(.*\)')
- shift ;;
- --valgrind-only-offset=*)
- valgrind_only_offset=$(expr "z$1" : 'z[^=]*=\(.*\)')
- shift ;;
--tee)
shift ;; # was handled already
--root=*)
root=$(expr "z$1" : 'z[^=]*=\(.*\)')
shift ;;
- --statusprefix=*)
- statusprefix=$(expr "z$1" : 'z[^=]*=\(.*\)')
- shift ;;
*)
echo "error: unknown test option '$1'" >&2; exit 1 ;;
esac
done
-if test -n "$valgrind_only" || test -n "$valgrind_only_stride"
+if test -n "$valgrind_only"
then
test -z "$valgrind" && valgrind=memcheck
test -z "$verbose" && verbose_only="$valgrind_only"
. "$TEST_DIRECTORY/test-lib-functions.sh"
# You are not expected to call test_ok_ and test_failure_ directly, use
-# the text_expect_* functions instead.
+# the test_expect_* functions instead.
test_ok_ () {
test_success=$(($test_success + 1))
- say_color "" "${statusprefix}ok $test_count - $@"
+ say_color "" "ok $test_count - $@"
}
test_failure_ () {
test_failure=$(($test_failure + 1))
- say_color error "${statusprefix}not ok $test_count - $1"
+ say_color error "not ok $test_count - $1"
shift
echo "$@" | sed -e 's/^/# /'
test "$immediate" = "" || { GIT_EXIT_OK=t; exit 1; }
test_known_broken_ok_ () {
test_fixed=$(($test_fixed+1))
- say_color error "${statusprefix}ok $test_count - $@ # TODO known breakage vanished"
+ say_color error "ok $test_count - $@ # TODO known breakage vanished"
}
test_known_broken_failure_ () {
test_broken=$(($test_broken+1))
- say_color warn "${statusprefix}not ok $test_count - $@ # TODO known breakage"
+ say_color warn "not ok $test_count - $@ # TODO known breakage"
}
test_debug () {
last_verbose=t
maybe_setup_verbose () {
test -z "$verbose_only" && return
- if match_pattern_list $test_count $verbose_only ||
- { test -n "$valgrind_only_stride" &&
- expr $test_count "%" $valgrind_only_stride - $valgrind_only_offset = 0 >/dev/null; }
+ if match_pattern_list $test_count $verbose_only
then
exec 4>&2 3>&1
# Emit a delimiting blank line when going from
maybe_setup_valgrind () {
test -z "$GIT_VALGRIND" && return
- if test -z "$valgrind_only" && test -z "$valgrind_only_stride"
+ if test -z "$valgrind_only"
then
GIT_VALGRIND_ENABLED=t
return
fi
GIT_VALGRIND_ENABLED=
if match_pattern_list $test_count $valgrind_only
- then
- GIT_VALGRIND_ENABLED=t
- elif test -n "$valgrind_only_stride" &&
- expr $test_count "%" $valgrind_only_stride - $valgrind_only_offset = 0 >/dev/null
then
GIT_VALGRIND_ENABLED=t
fi
of_prereq=" of $test_prereq"
fi
- say_color skip >&3 "${statusprefix}skipping test: $@"
- say_color skip "${statusprefix}ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
+ say_color skip >&3 "skipping test: $@"
+ say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
: true
;;
*)
if test "$test_fixed" != 0
then
- say_color error "${statusprefix}# $test_fixed known breakage(s) vanished; please update test(s)"
+ say_color error "# $test_fixed known breakage(s) vanished; please update test(s)"
fi
if test "$test_broken" != 0
then
- say_color warn "${statusprefix}# still have $test_broken known breakage(s)"
+ say_color warn "# still have $test_broken known breakage(s)"
fi
if test "$test_broken" != 0 || test "$test_fixed" != 0
then
then
if test $test_remaining -gt 0
then
- say_color pass "${statusprefix}# passed all $msg"
+ say_color pass "# passed all $msg"
fi
- say "${statusprefix}1..$test_count$skip_all"
+ say "1..$test_count$skip_all"
fi
test -d "$remove_trash" &&
*)
if test $test_external_has_tap -eq 0
then
- say_color error "${statusprefix}# failed $test_failure among $msg"
- say "${statusprefix}1..$test_count"
+ say_color error "# failed $test_failure among $msg"
+ say "1..$test_count"
fi
exit 1 ;;
esac
}
-
-# Set up a directory that we can put in PATH which redirects all git
-# calls to 'valgrind git ...'.
if test -n "$valgrind"
then
make_symlink () {
make_symlink "$symlink_target" "$GIT_VALGRIND/bin/$base" || exit
}
- # In the case of --valgrind-parallel, we only need to do the
- # wrapping once, in the main script. The worker children all
- # have $valgrind_only_stride set, so we can skip based on that.
- if test -z "$valgrind_only_stride"
- then
- # override all git executables in TEST_DIRECTORY/..
- GIT_VALGRIND=$TEST_DIRECTORY/valgrind
- mkdir -p "$GIT_VALGRIND"/bin
- for file in $GIT_BUILD_DIR/git* $GIT_BUILD_DIR/test-*
- do
- make_valgrind_symlink $file
- done
- # special-case the mergetools loadables
- make_symlink "$GIT_BUILD_DIR"/mergetools "$GIT_VALGRIND/bin/mergetools"
- OLDIFS=$IFS
- IFS=:
- for path in $PATH
+ # override all git executables in TEST_DIRECTORY/..
+ GIT_VALGRIND=$TEST_DIRECTORY/valgrind
+ mkdir -p "$GIT_VALGRIND"/bin
+ for file in $GIT_BUILD_DIR/git* $GIT_BUILD_DIR/test-*
+ do
+ make_valgrind_symlink $file
+ done
+ # special-case the mergetools loadables
+ make_symlink "$GIT_BUILD_DIR"/mergetools "$GIT_VALGRIND/bin/mergetools"
+ OLDIFS=$IFS
+ IFS=:
+ for path in $PATH
+ do
+ ls "$path"/git-* 2> /dev/null |
+ while read file
do
- ls "$path"/git-* 2> /dev/null |
- while read file
- do
- make_valgrind_symlink "$file"
- done
+ make_valgrind_symlink "$file"
done
- IFS=$OLDIFS
- fi
+ done
+ IFS=$OLDIFS
PATH=$GIT_VALGRIND/bin:$PATH
GIT_EXEC_PATH=$GIT_VALGRIND/bin
export GIT_VALGRIND
GIT_VALGRIND_MODE="$valgrind"
export GIT_VALGRIND_MODE
GIT_VALGRIND_ENABLED=t
- if test -n "$valgrind_only" || test -n "$valgrind_only_stride"
- then
- GIT_VALGRIND_ENABLED=
- fi
+ test -n "$valgrind_only" && GIT_VALGRIND_ENABLED=
export GIT_VALGRIND_ENABLED
elif test -n "$GIT_TEST_INSTALLED"
then
error "You haven't built things yet, have you?"
}
-if test -z "$GIT_TEST_INSTALLED" && test -z "$NO_PYTHON"
-then
- GITPYTHONLIB="$GIT_BUILD_DIR/git_remote_helpers/build/lib"
- export GITPYTHONLIB
- test -d "$GIT_BUILD_DIR"/git_remote_helpers/build || {
- error "You haven't built git_remote_helpers yet, have you?"
- }
-fi
-
if ! test -x "$GIT_BUILD_DIR"/test-chmtime
then
echo >&2 'You need to build test-chmtime:'
else
mkdir -p "$TRASH_DIRECTORY"
fi
-
-# Gross hack to spawn N sub-instances of the tests in parallel, and
-# summarize the results. Note that if this is enabled, the script
-# terminates at the end of this 'if' block.
-if test -n "$valgrind_parallel"
-then
- for i in $(test_seq 1 $valgrind_parallel)
- do
- root="$TRASH_DIRECTORY/vgparallel-$i"
- mkdir "$root"
- TEST_OUTPUT_DIRECTORY="$root" \
- ${SHELL_PATH} "$0" \
- --root="$root" --statusprefix="[$i] " \
- --valgrind="$valgrind" \
- --valgrind-only-stride="$valgrind_parallel" \
- --valgrind-only-offset="$i" &
- pids="$pids $!"
- done
- trap "kill $pids" INT TERM HUP
- wait $pids
- trap - INT TERM HUP
- for i in $(test_seq 1 $valgrind_parallel)
- do
- root="$TRASH_DIRECTORY/vgparallel-$i"
- eval "$(cat "$root/test-results/$(basename "$0" .sh)"-*.counts |
- sed 's/^\([a-z][a-z]*\) \([0-9][0-9]*\)/inner_\1=\2/')"
- test_count=$(expr $test_count + $inner_total)
- test_success=$(expr $test_success + $inner_success)
- test_fixed=$(expr $test_fixed + $inner_fixed)
- test_broken=$(expr $test_broken + $inner_broken)
- test_failure=$(expr $test_failure + $inner_failed)
- done
- test_done
-fi
-
# Use -P to resolve symlinks in our working directory so that the cwd
# in subprocesses like git equals our $PWD (for pathname comparisons).
cd -P "$TRASH_DIRECTORY" || exit 1
fi
# If you want to allow non-ASCII filenames set this variable to true.
-allownonascii=$(git config hooks.allownonascii)
+allownonascii=$(git config --bool hooks.allownonascii)
# Redirect output to stderr.
exec 1>&2
if [ "$local_sha" = $z40 ]
then
# Handle delete
+ :
else
if [ "$remote_sha" = $z40 ]
then
die("cannot parse %s as an object name", av[2]);
one = parse_tree_indirect(hash1);
if (!one)
- die("not a treeish %s", av[1]);
+ die("not a tree-ish %s", av[1]);
two = parse_tree_indirect(hash2);
if (!two)
- die("not a treeish %s", av[2]);
+ die("not a tree-ish %s", av[2]);
shift_tree(one->object.sha1, two->object.sha1, shifted, -1);
printf("shifted: %s\n", sha1_to_hex(shifted));
return 0;
}
- if (argc == 3 && !strcmp(argv[1], "mingw_path")) {
+ if (argc == 3 && !strcmp(argv[1], "print_path")) {
puts(argv[2]);
return 0;
}
git_SHA_CTX ctx;
unsigned char sha1[20];
unsigned bufsz = 8192;
+ int binary = 0;
char *buffer;
- if (ac == 2)
- bufsz = strtoul(av[1], NULL, 10) * 1024 * 1024;
+ if (ac == 2) {
+ if (!strcmp(av[1], "-b"))
+ binary = 1;
+ else
+ bufsz = strtoul(av[1], NULL, 10) * 1024 * 1024;
+ }
if (!bufsz)
bufsz = 8192;
git_SHA1_Update(&ctx, buffer, this_sz);
}
git_SHA1_Final(sha1, &ctx);
- puts(sha1_to_hex(sha1));
+
+ if (binary)
+ fwrite(sha1, 1, 20, stdout);
+ else
+ puts(sha1_to_hex(sha1));
exit(0);
}
--- /dev/null
+#include "git-compat-util.h"
+#include "urlmatch.h"
+
+int main(int argc, char **argv)
+{
+ const char usage[] = "test-urlmatch-normalization [-p | -l] <url1> | <url1> <url2>";
+ char *url1, *url2;
+ int opt_p = 0, opt_l = 0;
+
+ /*
+ * For one url, succeed if url_normalize succeeds on it, fail otherwise.
+ * For two urls, succeed only if url_normalize succeeds on both and
+ * the results compare equal with strcmp. If -p is given (one url only)
+ * and url_normalize succeeds, print the result followed by "\n". If
+ * -l is given (one url only) and url_normalize succeeds, print the
+ * returned length in decimal followed by "\n".
+ */
+
+ if (argc > 1 && !strcmp(argv[1], "-p")) {
+ opt_p = 1;
+ argc--;
+ argv++;
+ } else if (argc > 1 && !strcmp(argv[1], "-l")) {
+ opt_l = 1;
+ argc--;
+ argv++;
+ }
+
+ if (argc < 2 || argc > 3)
+ die("%s", usage);
+
+ if (argc == 2) {
+ struct url_info info;
+ url1 = url_normalize(argv[1], &info);
+ if (!url1)
+ return 1;
+ if (opt_p)
+ printf("%s\n", url1);
+ if (opt_l)
+ printf("%u\n", (unsigned)info.url_len);
+ return 0;
+ }
+
+ if (opt_p || opt_l)
+ die("%s", usage);
+
+ url1 = url_normalize(argv[1], NULL);
+ url2 = url_normalize(argv[2], NULL);
+ return (url1 && url2 && !strcmp(url1, url2)) ? 0 : 1;
+}
push : 1,
connect : 1,
signed_tags : 1,
- no_disconnect_req : 1;
+ check_connectivity : 1,
+ no_disconnect_req : 1,
+ no_private_update : 1;
char *export_marks;
char *import_marks;
/* These go from remote name (as in "list") to private name */
data->bidi_import = 1;
else if (!strcmp(capname, "export"))
data->export = 1;
+ else if (!strcmp(capname, "check-connectivity"))
+ data->check_connectivity = 1;
else if (!data->refspecs && !prefixcmp(capname, "refspec ")) {
ALLOC_GROW(refspecs,
refspec_nr + 1,
strbuf_addstr(&arg, "--import-marks=");
strbuf_addstr(&arg, capname + strlen("import-marks "));
data->import_marks = strbuf_detach(&arg, NULL);
+ } else if (!prefixcmp(capname, "no-private-update")) {
+ data->no_private_update = 1;
} else if (mandatory) {
die("Unknown mandatory capability %s. This remote "
"helper probably needs newer version of Git.",
struct strbuf buf = STRBUF_INIT;
standard_options(transport);
+ if (data->check_connectivity &&
+ data->transport_options.check_self_contained_and_connected)
+ set_helper_option(transport, "check-connectivity", "true");
for (i = 0; i < nr_heads; i++) {
const struct ref *posn = to_fetch[i];
else
transport->pack_lockfile = xstrdup(name);
}
+ else if (data->check_connectivity &&
+ data->transport_options.check_self_contained_and_connected &&
+ !strcmp(buf.buf, "connectivity-ok"))
+ data->transport_options.self_contained_and_connected = 1;
else if (!buf.len)
break;
else
free(msg);
msg = NULL;
}
+ else if (!strcmp(msg, "stale info")) {
+ status = REF_STATUS_REJECT_STALE;
+ free(msg);
+ msg = NULL;
+ }
}
if (*ref)
if (push_update_ref_status(&buf, &ref, remote_refs))
continue;
- if (!data->refspecs)
+ if (!data->refspecs || data->no_private_update)
continue;
/* propagate back the update to the remote namespace */
}
static int push_refs_with_push(struct transport *transport,
- struct ref *remote_refs, int flags)
+ struct ref *remote_refs, int flags)
{
int force_all = flags & TRANSPORT_PUSH_FORCE;
int mirror = flags & TRANSPORT_PUSH_MIRROR;
struct helper_data *data = transport->data;
struct strbuf buf = STRBUF_INIT;
struct ref *ref;
+ struct string_list cas_options = STRING_LIST_INIT_DUP;
+ struct string_list_item *cas_option;
get_helper(transport);
if (!data->push)
/* Check for statuses set by set_ref_status_for_push() */
switch (ref->status) {
case REF_STATUS_REJECT_NONFASTFORWARD:
+ case REF_STATUS_REJECT_STALE:
case REF_STATUS_REJECT_ALREADY_EXISTS:
case REF_STATUS_UPTODATE:
continue;
strbuf_addch(&buf, ':');
strbuf_addstr(&buf, ref->name);
strbuf_addch(&buf, '\n');
+
+ /*
+ * The "--force-with-lease" options without explicit
+ * values to expect have already been expanded into
+ * the ref->old_sha1_expect[] field; we can ignore
+ * transport->smart_options->cas altogether and instead
+ * can enumerate them from the refs.
+ */
+ if (ref->expect_old_sha1) {
+ struct strbuf cas = STRBUF_INIT;
+ strbuf_addf(&cas, "%s:%s",
+ ref->name, sha1_to_hex(ref->old_sha1_expect));
+ string_list_append(&cas_options, strbuf_detach(&cas, NULL));
+ }
}
- if (buf.len == 0)
+ if (buf.len == 0) {
+ string_list_clear(&cas_options, 0);
return 0;
+ }
standard_options(transport);
+ for_each_string_list_item(cas_option, &cas_options)
+ set_helper_option(transport, "cas", cas_option->string);
if (flags & TRANSPORT_PUSH_DRY_RUN) {
if (set_helper_option(transport, "dry-run", "true") != 0)
#include "run-command.h"
#include "pkt-line.h"
#include "fetch-pack.h"
+#include "remote.h"
+#include "connect.h"
#include "send-pack.h"
#include "walker.h"
#include "bundle.h"
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
"needs force", porcelain);
break;
+ case REF_STATUS_REJECT_STALE:
+ print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ "stale info", porcelain);
+ break;
case REF_STATUS_REMOTE_REJECT:
print_ref_status('!', "[remote rejected]", ref,
ref->deletion ? NULL : ref->peer_ref,
transport->push_refs = git_transport_push;
transport->disconnect = disconnect_git;
transport->smart_options = &(data->options);
+
+ transport->cannot_reuse = 1;
}
static int is_local(const char *url)
for (r = remote_refs; r; r = r->next) {
if (!r->peer_ref) continue;
if (r->status == REF_STATUS_REJECT_NONFASTFORWARD) continue;
+ if (r->status == REF_STATUS_REJECT_STALE) continue;
if (r->status == REF_STATUS_UPTODATE) continue;
strbuf_reset(&buf);
return -1;
}
+ if (transport->smart_options &&
+ transport->smart_options->cas &&
+ !is_empty_cas(transport->smart_options->cas))
+ apply_push_cas(transport->smart_options->cas,
+ transport->remote, remote_refs);
+
set_ref_status_for_push(remote_refs,
flags & TRANSPORT_PUSH_MIRROR,
flags & TRANSPORT_PUSH_FORCE);
#define TRANSPORT_H
#include "cache.h"
+#include "run-command.h"
#include "remote.h"
struct git_transport_options {
int depth;
const char *uploadpack;
const char *receivepack;
+ struct push_cas_option *cas;
};
struct transport {
*/
unsigned got_remote_refs : 1;
+ /*
+ * Transports that call take-over destroys the data specific to
+ * the transport type while doing so, and cannot be reused.
+ */
+ unsigned cannot_reuse : 1;
+
/**
* Returns 0 if successful, positive if the option is not
* recognized or is inapplicable, and negative if the option
/* Transfer the data as a thin pack if not null */
#define TRANS_OPT_THIN "thin"
+/* Check the current value of the remote ref */
+#define TRANS_OPT_CAS "cas"
+
/* Keep the pack that was transferred if not null */
#define TRANS_OPT_KEEP "keep"
/* Enable recursion indefinitely */
opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
- opt->pathspec.max_depth = -1;
strbuf_init(&base, PATH_MAX);
strbuf_add(&base, base_str, baselen);
struct diff_options diff_opts;
struct diff_queue_struct *q = &diff_queued_diff;
struct diff_filepair *choice;
- const char *paths[1];
int i;
+ /*
+ * follow-rename code is very specific, we need exactly one
+ * path. Magic that matches more than one path is not
+ * supported.
+ */
+ GUARD_PATHSPEC(&opt->pathspec, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
+#if 0
+ /*
+ * We should reject wildcards as well. Unfortunately we
+ * haven't got a reliable way to detect that 'foo\*bar' in
+ * fact has no wildcards. nowildcard_len is merely a hint for
+ * optimization. Let it slip for now until wildmatch is taught
+ * about dry-run mode and returns wildcard info.
+ */
+ if (opt->pathspec.has_wildcard)
+ die("BUG:%s:%d: wildcards are not supported",
+ __FILE__, __LINE__);
+#endif
+
/* Remove the file creation entry from the diff queue, and remember it */
choice = q->queue[0];
q->nr = 0;
DIFF_OPT_SET(&diff_opts, RECURSIVE);
DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
- diff_opts.single_follow = opt->pathspec.raw[0];
+ diff_opts.single_follow = opt->pathspec.items[0].match;
diff_opts.break_opt = opt->break_opt;
diff_opts.rename_score = opt->rename_score;
- paths[0] = NULL;
- diff_tree_setup_paths(paths, &diff_opts);
diff_setup_done(&diff_opts);
diff_tree(t1, t2, base, &diff_opts);
diffcore_std(&diff_opts);
- diff_tree_release_paths(&diff_opts);
+ free_pathspec(&diff_opts.pathspec);
/* Go through the new set of filepairing, and see if we find a more interesting one */
opt->found_follow = 0;
* the future!
*/
if ((p->status == 'R' || p->status == 'C') &&
- !strcmp(p->two->path, opt->pathspec.raw[0])) {
+ !strcmp(p->two->path, opt->pathspec.items[0].match)) {
+ const char *path[2];
+
/* Switch the file-pairs around */
q->queue[i] = choice;
choice = p;
/* Update the path we use from now on.. */
- diff_tree_release_paths(opt);
- opt->pathspec.raw[0] = xstrdup(p->one->path);
- diff_tree_setup_paths(opt->pathspec.raw, opt);
+ path[0] = p->one->path;
+ path[1] = NULL;
+ free_pathspec(&opt->pathspec);
+ parse_pathspec(&opt->pathspec, PATHSPEC_ALL_MAGIC, 0, "", path);
/*
* The caller expects us to return a set of vanilla
free(tree);
return retval;
}
-
-void diff_tree_release_paths(struct diff_options *opt)
-{
- free_pathspec(&opt->pathspec);
-}
-
-void diff_tree_setup_paths(const char **p, struct diff_options *opt)
-{
- init_pathspec(&opt->pathspec, p);
-}
#include "unpack-trees.h"
#include "dir.h"
#include "tree.h"
+#include "pathspec.h"
static const char *get_mode(const char *str, unsigned int *modep)
{
return retval;
}
-static int match_entry(const struct name_entry *entry, int pathlen,
+static int match_entry(const struct pathspec_item *item,
+ const struct name_entry *entry, int pathlen,
const char *match, int matchlen,
enum interesting *never_interesting)
{
int m = -1; /* signals that we haven't called strncmp() */
- if (*never_interesting != entry_not_interesting) {
+ if (item->magic & PATHSPEC_ICASE)
+ /*
+ * "Never interesting" trick requires exact
+ * matching. We could do something clever with inexact
+ * matching, but it's trickier (and not to forget that
+ * strcasecmp is locale-dependent, at least in
+ * glibc). Just disable it for now. It can't be worse
+ * than the wildcard's codepath of '[Tt][Hi][Is][Ss]'
+ * pattern.
+ */
+ *never_interesting = entry_not_interesting;
+ else if (*never_interesting != entry_not_interesting) {
/*
* We have not seen any match that sorts later
* than the current path.
* we cheated and did not do strncmp(), so we do
* that here.
*/
- m = strncmp(match, entry->path, pathlen);
+ m = ps_strncmp(item, match, entry->path, pathlen);
/*
* If common part matched earlier then it is a hit,
* leading directory and is shorter than match.
*/
if (!m)
+ /*
+ * match_entry does not check if the prefix part is
+ * matched case-sensitively. If the entry is a
+ * directory and part of prefix, it'll be rematched
+ * eventually by basecmp with special treatment for
+ * the prefix.
+ */
return 1;
return 0;
}
-static int match_dir_prefix(const char *base,
+/* :(icase)-aware string compare */
+static int basecmp(const struct pathspec_item *item,
+ const char *base, const char *match, int len)
+{
+ if (item->magic & PATHSPEC_ICASE) {
+ int ret, n = len > item->prefix ? item->prefix : len;
+ ret = strncmp(base, match, n);
+ if (ret)
+ return ret;
+ base += n;
+ match += n;
+ len -= n;
+ }
+ return ps_strncmp(item, base, match, len);
+}
+
+static int match_dir_prefix(const struct pathspec_item *item,
+ const char *base,
const char *match, int matchlen)
{
- if (strncmp(base, match, matchlen))
+ if (basecmp(item, base, match, matchlen))
return 0;
/*
*/
if (baselen >= matchlen) {
*matched = matchlen;
- return !strncmp(base, match, matchlen);
+ return !basecmp(item, base, match, matchlen);
}
dirlen = matchlen;
* base ends with '/' so we are sure it really matches
* directory
*/
- if (strncmp(base, match, baselen))
+ if (basecmp(item, base, match, baselen))
return 0;
*matched = baselen;
} else
enum interesting never_interesting = ps->has_wildcard ?
entry_not_interesting : all_entries_not_interesting;
+ GUARD_PATHSPEC(ps,
+ PATHSPEC_FROMTOP |
+ PATHSPEC_MAXDEPTH |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ICASE);
+
if (!ps->nr) {
- if (!ps->recursive || ps->max_depth == -1)
+ if (!ps->recursive ||
+ !(ps->magic & PATHSPEC_MAXDEPTH) ||
+ ps->max_depth == -1)
return all_entries_interesting;
return within_depth(base->buf + base_offset, baselen,
!!S_ISDIR(entry->mode),
if (baselen >= matchlen) {
/* If it doesn't match, move along... */
- if (!match_dir_prefix(base_str, match, matchlen))
+ if (!match_dir_prefix(item, base_str, match, matchlen))
goto match_wildcards;
- if (!ps->recursive || ps->max_depth == -1)
+ if (!ps->recursive ||
+ !(ps->magic & PATHSPEC_MAXDEPTH) ||
+ ps->max_depth == -1)
return all_entries_interesting;
return within_depth(base_str + matchlen + 1,
}
/* Either there must be no base, or the base must match. */
- if (baselen == 0 || !strncmp(base_str, match, baselen)) {
- if (match_entry(entry, pathlen,
+ if (baselen == 0 || !basecmp(item, base_str, match, baselen)) {
+ if (match_entry(item, entry, pathlen,
match + baselen, matchlen - baselen,
&never_interesting))
return entry_interesting;
if (item->nowildcard_len < item->len) {
- if (!git_fnmatch(match + baselen, entry->path,
- item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,
+ if (!git_fnmatch(item, match + baselen, entry->path,
item->nowildcard_len - baselen))
return entry_interesting;
strbuf_add(base, entry->path, pathlen);
- if (!git_fnmatch(match, base->buf + base_offset,
- item->flags & PATHSPEC_ONESTAR ? GFNM_ONESTAR : 0,
+ if (!git_fnmatch(item, match, base->buf + base_offset,
item->nowildcard_len)) {
strbuf_setlen(base, base_offset + baselen);
return entry_interesting;
}
static int read_tree_1(struct tree *tree, struct strbuf *base,
- int stage, struct pathspec *pathspec,
+ int stage, const struct pathspec *pathspec,
read_tree_fn_t fn, void *context)
{
struct tree_desc desc;
int read_tree_recursive(struct tree *tree,
const char *base, int baselen,
- int stage, struct pathspec *pathspec,
+ int stage, const struct pathspec *pathspec,
read_tree_fn_t fn, void *context)
{
struct strbuf sb = STRBUF_INIT;
return parse_tree_buffer(item, buffer, size);
}
+void free_tree_buffer(struct tree *tree)
+{
+ free(tree->buffer);
+ tree->buffer = NULL;
+ tree->size = 0;
+ tree->object.parsed = 0;
+}
+
struct tree *parse_tree_indirect(const unsigned char *sha1)
{
struct object *obj = parse_object(sha1);
int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);
int parse_tree(struct tree *tree);
+void free_tree_buffer(struct tree *tree);
/* Parses and returns the tree in the given ent, chasing tags and commits. */
struct tree *parse_tree_indirect(const unsigned char *sha1);
extern int read_tree_recursive(struct tree *tree,
const char *base, int baselen,
- int stage, struct pathspec *pathspec,
+ int stage, const struct pathspec *pathspec,
read_tree_fn_t fn, void *context);
extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspec);
o->src_index = NULL;
ret = check_updates(o) ? (-2) : 0;
- if (o->dst_index)
+ if (o->dst_index) {
+ discard_index(o->dst_index);
*o->dst_index = o->result;
+ }
done:
clear_exclude_list(&el);
{
const struct cache_entry *src;
- src = index_name_exists(o->src_index, name, len, 1);
+ src = index_file_exists(o->src_index, name, len, 1);
return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
}
* delete this path, which is in a subdirectory that
* is being replaced with a blob.
*/
- result = index_name_exists(&o->result, name, len, 0);
+ result = index_file_exists(&o->result, name, len, 0);
if (result) {
if (result->ce_flags & CE_REMOVE)
return 0;
#include "revision.h"
#include "list-objects.h"
#include "run-command.h"
+#include "connect.h"
#include "sigchain.h"
#include "version.h"
#include "string-list.h"
static struct object_array want_obj;
static struct object_array extra_edge_obj;
static unsigned int timeout;
+static int keepalive = 5;
/* 0 for no sideband,
* otherwise maximum packet size (up to 65520 bytes).
*/
return sz;
}
-static FILE *pack_pipe = NULL;
-static void show_commit(struct commit *commit, void *data)
-{
- if (commit->object.flags & BOUNDARY)
- fputc('-', pack_pipe);
- if (fputs(sha1_to_hex(commit->object.sha1), pack_pipe) < 0)
- die("broken output pipe");
- fputc('\n', pack_pipe);
- fflush(pack_pipe);
- free(commit->buffer);
- commit->buffer = NULL;
-}
-
-static void show_object(struct object *obj,
- const struct name_path *path, const char *component,
- void *cb_data)
-{
- show_object_with_name(pack_pipe, obj, path, component);
-}
-
-static void show_edge(struct commit *commit)
-{
- fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1));
-}
-
-static int do_rev_list(int in, int out, void *user_data)
-{
- int i;
- struct rev_info revs;
-
- pack_pipe = xfdopen(out, "w");
- init_revisions(&revs, NULL);
- revs.tag_objects = 1;
- revs.tree_objects = 1;
- revs.blob_objects = 1;
- if (use_thin_pack)
- revs.edge_hint = 1;
-
- for (i = 0; i < want_obj.nr; i++) {
- struct object *o = want_obj.objects[i].item;
- /* why??? */
- o->flags &= ~UNINTERESTING;
- add_pending_object(&revs, o, NULL);
- }
- for (i = 0; i < have_obj.nr; i++) {
- struct object *o = have_obj.objects[i].item;
- o->flags |= UNINTERESTING;
- add_pending_object(&revs, o, NULL);
- }
- setup_revisions(0, NULL, &revs, NULL);
- if (prepare_revision_walk(&revs))
- die("revision walk setup failed");
- mark_edges_uninteresting(revs.commits, &revs, show_edge);
- if (use_thin_pack)
- for (i = 0; i < extra_edge_obj.nr; i++)
- fprintf(pack_pipe, "-%s\n", sha1_to_hex(
- extra_edge_obj.objects[i].item->sha1));
- traverse_commit_list(&revs, show_commit, show_object, NULL);
- fflush(pack_pipe);
- fclose(pack_pipe);
- return 0;
-}
-
static void create_pack_file(void)
{
- struct async rev_list;
struct child_process pack_objects;
char data[8193], progress[128];
char abort_msg[] = "aborting due to possible repository "
"corruption on the remote side.";
int buffered = -1;
ssize_t sz;
- const char *argv[10];
- int arg = 0;
+ const char *argv[12];
+ int i, arg = 0;
+ FILE *pipe_fd;
+ char *shallow_file = NULL;
- argv[arg++] = "pack-objects";
- if (!shallow_nr) {
- argv[arg++] = "--revs";
- if (use_thin_pack)
- argv[arg++] = "--thin";
+ if (shallow_nr) {
+ shallow_file = setup_temporary_shallow();
+ argv[arg++] = "--shallow-file";
+ argv[arg++] = shallow_file;
}
+ argv[arg++] = "pack-objects";
+ argv[arg++] = "--revs";
+ if (use_thin_pack)
+ argv[arg++] = "--thin";
argv[arg++] = "--stdout";
if (!no_progress)
if (start_command(&pack_objects))
die("git upload-pack: unable to fork git-pack-objects");
- if (shallow_nr) {
- memset(&rev_list, 0, sizeof(rev_list));
- rev_list.proc = do_rev_list;
- rev_list.out = pack_objects.in;
- if (start_async(&rev_list))
- die("git upload-pack: unable to fork git-rev-list");
- }
- else {
- FILE *pipe_fd = xfdopen(pack_objects.in, "w");
- int i;
-
- for (i = 0; i < want_obj.nr; i++)
- fprintf(pipe_fd, "%s\n",
- sha1_to_hex(want_obj.objects[i].item->sha1));
- fprintf(pipe_fd, "--not\n");
- for (i = 0; i < have_obj.nr; i++)
- fprintf(pipe_fd, "%s\n",
- sha1_to_hex(have_obj.objects[i].item->sha1));
- fprintf(pipe_fd, "\n");
- fflush(pipe_fd);
- fclose(pipe_fd);
- }
-
+ pipe_fd = xfdopen(pack_objects.in, "w");
+
+ for (i = 0; i < want_obj.nr; i++)
+ fprintf(pipe_fd, "%s\n",
+ sha1_to_hex(want_obj.objects[i].item->sha1));
+ fprintf(pipe_fd, "--not\n");
+ for (i = 0; i < have_obj.nr; i++)
+ fprintf(pipe_fd, "%s\n",
+ sha1_to_hex(have_obj.objects[i].item->sha1));
+ for (i = 0; i < extra_edge_obj.nr; i++)
+ fprintf(pipe_fd, "%s\n",
+ sha1_to_hex(extra_edge_obj.objects[i].item->sha1));
+ fprintf(pipe_fd, "\n");
+ fflush(pipe_fd);
+ fclose(pipe_fd);
/* We read from pack_objects.err to capture stderr output for
* progress bar, and pack_objects.out to capture the pack data.
while (1) {
struct pollfd pfd[2];
int pe, pu, pollsize;
+ int ret;
reset_timeout();
if (!pollsize)
break;
- if (poll(pfd, pollsize, -1) < 0) {
+ ret = poll(pfd, pollsize, 1000 * keepalive);
+ if (ret < 0) {
if (errno != EINTR) {
error("poll failed, resuming: %s",
strerror(errno));
if (sz < 0)
goto fail;
}
+
+ /*
+ * We hit the keepalive timeout without saying anything; send
+ * an empty message on the data sideband just to let the other
+ * side know we're still working on it, but don't have any data
+ * yet.
+ *
+ * If we don't have a sideband channel, there's no room in the
+ * protocol to say anything, so those clients are just out of
+ * luck.
+ */
+ if (!ret && use_sideband) {
+ static const char buf[] = "0005\1";
+ write_or_die(1, buf, 5);
+ }
}
if (finish_command(&pack_objects)) {
error("git upload-pack: git-pack-objects died with error.");
goto fail;
}
- if (shallow_nr && finish_async(&rev_list))
- goto fail; /* error was already reported */
+ if (shallow_file) {
+ if (*shallow_file)
+ unlink(shallow_file);
+ free(shallow_file);
+ }
/* flush the data */
if (0 <= buffered) {
return 0;
}
+static void format_symref_info(struct strbuf *buf, struct string_list *symref)
+{
+ struct string_list_item *item;
+
+ if (!symref->nr)
+ return;
+ for_each_string_list_item(item, symref)
+ strbuf_addf(buf, " symref=%s:%s", item->string, (char *)item->util);
+}
+
static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
{
static const char *capabilities = "multi_ack thin-pack side-band"
const char *refname_nons = strip_namespace(refname);
unsigned char peeled[20];
- if (mark_our_ref(refname, sha1, flag, cb_data))
+ if (mark_our_ref(refname, sha1, flag, NULL))
return 0;
- if (capabilities)
- packet_write(1, "%s %s%c%s%s%s agent=%s\n",
+ if (capabilities) {
+ struct strbuf symref_info = STRBUF_INIT;
+
+ format_symref_info(&symref_info, cb_data);
+ packet_write(1, "%s %s%c%s%s%s%s agent=%s\n",
sha1_to_hex(sha1), refname_nons,
0, capabilities,
allow_tip_sha1_in_want ? " allow-tip-sha1-in-want" : "",
stateless_rpc ? " no-done" : "",
+ symref_info.buf,
git_user_agent_sanitized());
- else
+ strbuf_release(&symref_info);
+ } else {
packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname_nons);
+ }
capabilities = NULL;
if (!peel_ref(refname, peeled))
packet_write(1, "%s %s^{}\n", sha1_to_hex(peeled), refname_nons);
return 0;
}
+static int find_symref(const char *refname, const unsigned char *sha1, int flag,
+ void *cb_data)
+{
+ const char *symref_target;
+ struct string_list_item *item;
+ unsigned char unused[20];
+
+ if ((flag & REF_ISSYMREF) == 0)
+ return 0;
+ symref_target = resolve_ref_unsafe(refname, unused, 0, &flag);
+ if (!symref_target || (flag & REF_ISSYMREF) == 0)
+ die("'%s' is a symref but it is not?", refname);
+ item = string_list_append(cb_data, refname);
+ item->util = xstrdup(symref_target);
+ return 0;
+}
+
static void upload_pack(void)
{
+ struct string_list symref = STRING_LIST_INIT_DUP;
+
+ head_ref_namespaced(find_symref, &symref);
+ for_each_namespaced_ref(find_symref, &symref);
+
if (advertise_refs || !stateless_rpc) {
reset_timeout();
- head_ref_namespaced(send_ref, NULL);
- for_each_namespaced_ref(send_ref, NULL);
+ head_ref_namespaced(send_ref, &symref);
+ for_each_namespaced_ref(send_ref, &symref);
packet_flush(1);
} else {
head_ref_namespaced(mark_our_ref, NULL);
for_each_namespaced_ref(mark_our_ref, NULL);
}
+ string_list_clear(&symref, 1);
if (advertise_refs)
return;
{
if (!strcmp("uploadpack.allowtipsha1inwant", var))
allow_tip_sha1_in_want = git_config_bool(var, value);
+ else if (!strcmp("uploadpack.keepalive", var)) {
+ keepalive = git_config_int(var, value);
+ if (!keepalive)
+ keepalive = -1;
+ }
return parse_hide_refs_config(var, value, "uploadpack");
}
--- /dev/null
+#include "cache.h"
+#include "urlmatch.h"
+
+#define URL_ALPHA "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+#define URL_DIGIT "0123456789"
+#define URL_ALPHADIGIT URL_ALPHA URL_DIGIT
+#define URL_SCHEME_CHARS URL_ALPHADIGIT "+.-"
+#define URL_HOST_CHARS URL_ALPHADIGIT ".-[:]" /* IPv6 literals need [:] */
+#define URL_UNSAFE_CHARS " <>\"%{}|\\^`" /* plus 0x00-0x1F,0x7F-0xFF */
+#define URL_GEN_RESERVED ":/?#[]@"
+#define URL_SUB_RESERVED "!$&'()*+,;="
+#define URL_RESERVED URL_GEN_RESERVED URL_SUB_RESERVED /* only allowed delims */
+
+static int append_normalized_escapes(struct strbuf *buf,
+ const char *from,
+ size_t from_len,
+ const char *esc_extra,
+ const char *esc_ok)
+{
+ /*
+ * Append to strbuf 'buf' characters from string 'from' with length
+ * 'from_len' while unescaping characters that do not need to be escaped
+ * and escaping characters that do. The set of characters to escape
+ * (the complement of which is unescaped) starts out as the RFC 3986
+ * unsafe characters (0x00-0x1F,0x7F-0xFF," <>\"#%{}|\\^`"). If
+ * 'esc_extra' is not NULL, those additional characters will also always
+ * be escaped. If 'esc_ok' is not NULL, those characters will be left
+ * escaped if found that way, but will not be unescaped otherwise (used
+ * for delimiters). If a %-escape sequence is encountered that is not
+ * followed by 2 hexadecimal digits, the sequence is invalid and
+ * false (0) will be returned. Otherwise true (1) will be returned for
+ * success.
+ *
+ * Note that all %-escape sequences will be normalized to UPPERCASE
+ * as indicated in RFC 3986. Unless included in esc_extra or esc_ok
+ * alphanumerics and "-._~" will always be unescaped as per RFC 3986.
+ */
+
+ while (from_len) {
+ int ch = *from++;
+ int was_esc = 0;
+
+ from_len--;
+ if (ch == '%') {
+ if (from_len < 2 ||
+ !isxdigit((unsigned char)from[0]) ||
+ !isxdigit((unsigned char)from[1]))
+ return 0;
+ ch = hexval_table[(unsigned char)*from++] << 4;
+ ch |= hexval_table[(unsigned char)*from++];
+ from_len -= 2;
+ was_esc = 1;
+ }
+ if ((unsigned char)ch <= 0x1F || (unsigned char)ch >= 0x7F ||
+ strchr(URL_UNSAFE_CHARS, ch) ||
+ (esc_extra && strchr(esc_extra, ch)) ||
+ (was_esc && strchr(esc_ok, ch)))
+ strbuf_addf(buf, "%%%02X", (unsigned char)ch);
+ else
+ strbuf_addch(buf, ch);
+ }
+
+ return 1;
+}
+
+char *url_normalize(const char *url, struct url_info *out_info)
+{
+ /*
+ * Normalize NUL-terminated url using the following rules:
+ *
+ * 1. Case-insensitive parts of url will be converted to lower case
+ * 2. %-encoded characters that do not need to be will be unencoded
+ * 3. Characters that are not %-encoded and must be will be encoded
+ * 4. All %-encodings will be converted to upper case hexadecimal
+ * 5. Leading 0s are removed from port numbers
+ * 6. If the default port for the scheme is given it will be removed
+ * 7. A path part (including empty) not starting with '/' has one added
+ * 8. Any dot segments (. or ..) in the path are resolved and removed
+ * 9. IPv6 host literals are allowed (but not normalized or validated)
+ *
+ * The rules are based on information in RFC 3986.
+ *
+ * Please note this function requires a full URL including a scheme
+ * and host part (except for file: URLs which may have an empty host).
+ *
+ * The return value is a newly allocated string that must be freed
+ * or NULL if the url is not valid.
+ *
+ * If out_info is non-NULL, the url and err fields therein will always
+ * be set. If a non-NULL value is returned, it will be stored in
+ * out_info->url as well, out_info->err will be set to NULL and the
+ * other fields of *out_info will also be filled in. If a NULL value
+ * is returned, NULL will be stored in out_info->url and out_info->err
+ * will be set to a brief, translated, error message, but no other
+ * fields will be filled in.
+ *
+ * This is NOT a URL validation function. Full URL validation is NOT
+ * performed. Some invalid host names are passed through this function
+ * undetected. However, most all other problems that make a URL invalid
+ * will be detected (including a missing host for non file: URLs).
+ */
+
+ size_t url_len = strlen(url);
+ struct strbuf norm;
+ size_t spanned;
+ size_t scheme_len, user_off=0, user_len=0, passwd_off=0, passwd_len=0;
+ size_t host_off=0, host_len=0, port_len=0, path_off, path_len, result_len;
+ const char *slash_ptr, *at_ptr, *colon_ptr, *path_start;
+ char *result;
+
+ /*
+ * Copy lowercased scheme and :// suffix, %-escapes are not allowed
+ * First character of scheme must be URL_ALPHA
+ */
+ spanned = strspn(url, URL_SCHEME_CHARS);
+ if (!spanned || !isalpha(url[0]) || spanned + 3 > url_len ||
+ url[spanned] != ':' || url[spanned+1] != '/' || url[spanned+2] != '/') {
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid URL scheme name or missing '://' suffix");
+ }
+ return NULL; /* Bad scheme and/or missing "://" part */
+ }
+ strbuf_init(&norm, url_len);
+ scheme_len = spanned;
+ spanned += 3;
+ url_len -= spanned;
+ while (spanned--)
+ strbuf_addch(&norm, tolower(*url++));
+
+
+ /*
+ * Copy any username:password if present normalizing %-escapes
+ */
+ at_ptr = strchr(url, '@');
+ slash_ptr = url + strcspn(url, "/?#");
+ if (at_ptr && at_ptr < slash_ptr) {
+ user_off = norm.len;
+ if (at_ptr > url) {
+ if (!append_normalized_escapes(&norm, url, at_ptr - url,
+ "", URL_RESERVED)) {
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid %XX escape sequence");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ colon_ptr = strchr(norm.buf + scheme_len + 3, ':');
+ if (colon_ptr) {
+ passwd_off = (colon_ptr + 1) - norm.buf;
+ passwd_len = norm.len - passwd_off;
+ user_len = (passwd_off - 1) - (scheme_len + 3);
+ } else {
+ user_len = norm.len - (scheme_len + 3);
+ }
+ }
+ strbuf_addch(&norm, '@');
+ url_len -= (++at_ptr - url);
+ url = at_ptr;
+ }
+
+
+ /*
+ * Copy the host part excluding any port part, no %-escapes allowed
+ */
+ if (!url_len || strchr(":/?#", *url)) {
+ /* Missing host invalid for all URL schemes except file */
+ if (strncmp(norm.buf, "file:", 5)) {
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("missing host and scheme is not 'file:'");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ } else {
+ host_off = norm.len;
+ }
+ colon_ptr = slash_ptr - 1;
+ while (colon_ptr > url && *colon_ptr != ':' && *colon_ptr != ']')
+ colon_ptr--;
+ if (*colon_ptr != ':') {
+ colon_ptr = slash_ptr;
+ } else if (!host_off && colon_ptr < slash_ptr && colon_ptr + 1 != slash_ptr) {
+ /* file: URLs may not have a port number */
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("a 'file:' URL may not have a port number");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ spanned = strspn(url, URL_HOST_CHARS);
+ if (spanned < colon_ptr - url) {
+ /* Host name has invalid characters */
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid characters in host name");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ while (url < colon_ptr) {
+ strbuf_addch(&norm, tolower(*url++));
+ url_len--;
+ }
+
+
+ /*
+ * Check the port part and copy if not the default (after removing any
+ * leading 0s); no %-escapes allowed
+ */
+ if (colon_ptr < slash_ptr) {
+ /* skip the ':' and leading 0s but not the last one if all 0s */
+ url++;
+ url += strspn(url, "0");
+ if (url == slash_ptr && url[-1] == '0')
+ url--;
+ if (url == slash_ptr) {
+ /* Skip ":" port with no number, it's same as default */
+ } else if (slash_ptr - url == 2 &&
+ !strncmp(norm.buf, "http:", 5) &&
+ !strncmp(url, "80", 2)) {
+ /* Skip http :80 as it's the default */
+ } else if (slash_ptr - url == 3 &&
+ !strncmp(norm.buf, "https:", 6) &&
+ !strncmp(url, "443", 3)) {
+ /* Skip https :443 as it's the default */
+ } else {
+ /*
+ * Port number must be all digits with leading 0s removed
+ * and since all the protocols we deal with have a 16-bit
+ * port number it must also be in the range 1..65535
+ * 0 is not allowed because that means "next available"
+ * on just about every system and therefore cannot be used
+ */
+ unsigned long pnum = 0;
+ spanned = strspn(url, URL_DIGIT);
+ if (spanned < slash_ptr - url) {
+ /* port number has invalid characters */
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid port number");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ if (slash_ptr - url <= 5)
+ pnum = strtoul(url, NULL, 10);
+ if (pnum == 0 || pnum > 65535) {
+ /* port number not in range 1..65535 */
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid port number");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ strbuf_addch(&norm, ':');
+ strbuf_add(&norm, url, slash_ptr - url);
+ port_len = slash_ptr - url;
+ }
+ url_len -= slash_ptr - colon_ptr;
+ url = slash_ptr;
+ }
+ if (host_off)
+ host_len = norm.len - host_off;
+
+
+ /*
+ * Now copy the path resolving any . and .. segments being careful not
+ * to corrupt the URL by unescaping any delimiters, but do add an
+ * initial '/' if it's missing and do normalize any %-escape sequences.
+ */
+ path_off = norm.len;
+ path_start = norm.buf + path_off;
+ strbuf_addch(&norm, '/');
+ if (*url == '/') {
+ url++;
+ url_len--;
+ }
+ for (;;) {
+ const char *seg_start;
+ size_t seg_start_off = norm.len;
+ const char *next_slash = url + strcspn(url, "/?#");
+ int skip_add_slash = 0;
+
+ /*
+ * RFC 3689 indicates that any . or .. segments should be
+ * unescaped before being checked for.
+ */
+ if (!append_normalized_escapes(&norm, url, next_slash - url, "",
+ URL_RESERVED)) {
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid %XX escape sequence");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+
+ seg_start = norm.buf + seg_start_off;
+ if (!strcmp(seg_start, ".")) {
+ /* ignore a . segment; be careful not to remove initial '/' */
+ if (seg_start == path_start + 1) {
+ strbuf_setlen(&norm, norm.len - 1);
+ skip_add_slash = 1;
+ } else {
+ strbuf_setlen(&norm, norm.len - 2);
+ }
+ } else if (!strcmp(seg_start, "..")) {
+ /*
+ * ignore a .. segment and remove the previous segment;
+ * be careful not to remove initial '/' from path
+ */
+ const char *prev_slash = norm.buf + norm.len - 3;
+ if (prev_slash == path_start) {
+ /* invalid .. because no previous segment to remove */
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid '..' path segment");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ while (*--prev_slash != '/') {}
+ if (prev_slash == path_start) {
+ strbuf_setlen(&norm, prev_slash - norm.buf + 1);
+ skip_add_slash = 1;
+ } else {
+ strbuf_setlen(&norm, prev_slash - norm.buf);
+ }
+ }
+ url_len -= next_slash - url;
+ url = next_slash;
+ /* if the next char is not '/' done with the path */
+ if (*url != '/')
+ break;
+ url++;
+ url_len--;
+ if (!skip_add_slash)
+ strbuf_addch(&norm, '/');
+ }
+ path_len = norm.len - path_off;
+
+
+ /*
+ * Now simply copy the rest, if any, only normalizing %-escapes and
+ * being careful not to corrupt the URL by unescaping any delimiters.
+ */
+ if (*url) {
+ if (!append_normalized_escapes(&norm, url, url_len, "", URL_RESERVED)) {
+ if (out_info) {
+ out_info->url = NULL;
+ out_info->err = _("invalid %XX escape sequence");
+ }
+ strbuf_release(&norm);
+ return NULL;
+ }
+ }
+
+
+ result = strbuf_detach(&norm, &result_len);
+ if (out_info) {
+ out_info->url = result;
+ out_info->err = NULL;
+ out_info->url_len = result_len;
+ out_info->scheme_len = scheme_len;
+ out_info->user_off = user_off;
+ out_info->user_len = user_len;
+ out_info->passwd_off = passwd_off;
+ out_info->passwd_len = passwd_len;
+ out_info->host_off = host_off;
+ out_info->host_len = host_len;
+ out_info->port_len = port_len;
+ out_info->path_off = path_off;
+ out_info->path_len = path_len;
+ }
+ return result;
+}
+
+static size_t url_match_prefix(const char *url,
+ const char *url_prefix,
+ size_t url_prefix_len)
+{
+ /*
+ * url_prefix matches url if url_prefix is an exact match for url or it
+ * is a prefix of url and the match ends on a path component boundary.
+ * Both url and url_prefix are considered to have an implicit '/' on the
+ * end for matching purposes if they do not already.
+ *
+ * url must be NUL terminated. url_prefix_len is the length of
+ * url_prefix which need not be NUL terminated.
+ *
+ * The return value is the length of the match in characters (including
+ * the final '/' even if it's implicit) or 0 for no match.
+ *
+ * Passing NULL as url and/or url_prefix will always cause 0 to be
+ * returned without causing any faults.
+ */
+ if (!url || !url_prefix)
+ return 0;
+ if (!url_prefix_len || (url_prefix_len == 1 && *url_prefix == '/'))
+ return (!*url || *url == '/') ? 1 : 0;
+ if (url_prefix[url_prefix_len - 1] == '/')
+ url_prefix_len--;
+ if (strncmp(url, url_prefix, url_prefix_len))
+ return 0;
+ if ((strlen(url) == url_prefix_len) || (url[url_prefix_len] == '/'))
+ return url_prefix_len + 1;
+ return 0;
+}
+
+int match_urls(const struct url_info *url,
+ const struct url_info *url_prefix,
+ int *exactusermatch)
+{
+ /*
+ * url_prefix matches url if the scheme, host and port of url_prefix
+ * are the same as those of url and the path portion of url_prefix
+ * is the same as the path portion of url or it is a prefix that
+ * matches at a '/' boundary. If url_prefix contains a user name,
+ * that must also exactly match the user name in url.
+ *
+ * If the user, host, port and path match in this fashion, the returned
+ * value is the length of the path match including any implicit
+ * final '/'. For example, "http://me@example.com/path" is matched by
+ * "http://example.com" with a path length of 1.
+ *
+ * If there is a match and exactusermatch is not NULL, then
+ * *exactusermatch will be set to true if both url and url_prefix
+ * contained a user name or false if url_prefix did not have a
+ * user name. If there is no match *exactusermatch is left untouched.
+ */
+ int usermatched = 0;
+ int pathmatchlen;
+
+ if (!url || !url_prefix || !url->url || !url_prefix->url)
+ return 0;
+
+ /* check the scheme */
+ if (url_prefix->scheme_len != url->scheme_len ||
+ strncmp(url->url, url_prefix->url, url->scheme_len))
+ return 0; /* schemes do not match */
+
+ /* check the user name if url_prefix has one */
+ if (url_prefix->user_off) {
+ if (!url->user_off || url->user_len != url_prefix->user_len ||
+ strncmp(url->url + url->user_off,
+ url_prefix->url + url_prefix->user_off,
+ url->user_len))
+ return 0; /* url_prefix has a user but it's not a match */
+ usermatched = 1;
+ }
+
+ /* check the host and port */
+ if (url_prefix->host_len != url->host_len ||
+ strncmp(url->url + url->host_off,
+ url_prefix->url + url_prefix->host_off, url->host_len))
+ return 0; /* host names and/or ports do not match */
+
+ /* check the path */
+ pathmatchlen = url_match_prefix(
+ url->url + url->path_off,
+ url_prefix->url + url_prefix->path_off,
+ url_prefix->url_len - url_prefix->path_off);
+
+ if (pathmatchlen && exactusermatch)
+ *exactusermatch = usermatched;
+ return pathmatchlen;
+}
+
+int urlmatch_config_entry(const char *var, const char *value, void *cb)
+{
+ struct string_list_item *item;
+ struct urlmatch_config *collect = cb;
+ struct urlmatch_item *matched;
+ struct url_info *url = &collect->url;
+ const char *key, *dot;
+ struct strbuf synthkey = STRBUF_INIT;
+ size_t matched_len = 0;
+ int user_matched = 0;
+ int retval;
+
+ key = skip_prefix(var, collect->section);
+ if (!key || *(key++) != '.') {
+ if (collect->cascade_fn)
+ return collect->cascade_fn(var, value, cb);
+ return 0; /* not interested */
+ }
+ dot = strrchr(key, '.');
+ if (dot) {
+ char *config_url, *norm_url;
+ struct url_info norm_info;
+
+ config_url = xmemdupz(key, dot - key);
+ norm_url = url_normalize(config_url, &norm_info);
+ free(config_url);
+ if (!norm_url)
+ return 0;
+ matched_len = match_urls(url, &norm_info, &user_matched);
+ free(norm_url);
+ if (!matched_len)
+ return 0;
+ key = dot + 1;
+ }
+
+ if (collect->key && strcmp(key, collect->key))
+ return 0;
+
+ item = string_list_insert(&collect->vars, key);
+ if (!item->util) {
+ matched = xcalloc(1, sizeof(*matched));
+ item->util = matched;
+ } else {
+ matched = item->util;
+ /*
+ * Is our match shorter? Is our match the same
+ * length, and without user while the current
+ * candidate is with user? Then we cannot use it.
+ */
+ if (matched_len < matched->matched_len ||
+ ((matched_len == matched->matched_len) &&
+ (!user_matched && matched->user_matched)))
+ return 0;
+ /* Otherwise, replace it with this one. */
+ }
+
+ matched->matched_len = matched_len;
+ matched->user_matched = user_matched;
+ strbuf_addstr(&synthkey, collect->section);
+ strbuf_addch(&synthkey, '.');
+ strbuf_addstr(&synthkey, key);
+ retval = collect->collect_fn(synthkey.buf, value, collect->cb);
+
+ strbuf_release(&synthkey);
+ return retval;
+}
--- /dev/null
+#ifndef URL_MATCH_H
+#include "string-list.h"
+
+struct url_info {
+ /* normalized url on success, must be freed, otherwise NULL */
+ char *url;
+ /* if !url, a brief reason for the failure, otherwise NULL */
+ const char *err;
+
+ /* the rest of the fields are only set if url != NULL */
+
+ size_t url_len; /* total length of url (which is now normalized) */
+ size_t scheme_len; /* length of scheme name (excluding final :) */
+ size_t user_off; /* offset into url to start of user name (0 => none) */
+ size_t user_len; /* length of user name; if user_off != 0 but
+ user_len == 0, an empty user name was given */
+ size_t passwd_off; /* offset into url to start of passwd (0 => none) */
+ size_t passwd_len; /* length of passwd; if passwd_off != 0 but
+ passwd_len == 0, an empty passwd was given */
+ size_t host_off; /* offset into url to start of host name (0 => none) */
+ size_t host_len; /* length of host name; this INCLUDES any ':portnum';
+ * file urls may have host_len == 0 */
+ size_t port_len; /* if a portnum is present (port_len != 0), it has
+ * this length (excluding the leading ':') at the
+ * end of the host name (always 0 for file urls) */
+ size_t path_off; /* offset into url to the start of the url path;
+ * this will always point to a '/' character
+ * after the url has been normalized */
+ size_t path_len; /* length of path portion excluding any trailing
+ * '?...' and '#...' portion; will always be >= 1 */
+};
+
+extern char *url_normalize(const char *, struct url_info *);
+extern int match_urls(const struct url_info *url, const struct url_info *url_prefix, int *exactusermatch);
+
+struct urlmatch_item {
+ size_t matched_len;
+ char user_matched;
+};
+
+struct urlmatch_config {
+ struct string_list vars;
+ struct url_info url;
+ const char *section;
+ const char *key;
+
+ void *cb;
+ int (*collect_fn)(const char *var, const char *value, void *cb);
+ int (*cascade_fn)(const char *var, const char *value, void *cb);
+};
+
+extern int urlmatch_config_entry(const char *var, const char *value, void *cb);
+
+#endif /* URL_MATCH_H */
if (!obj || process(walker, obj))
return -1;
}
- free(tree->buffer);
- tree->buffer = NULL;
- tree->size = 0;
- tree->object.parsed = 0;
+ free_tree_buffer(tree);
return 0;
}
return ret;
}
+/*
+ * Limit size of IO chunks, because huge chunks only cause pain. OS X
+ * 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in
+ * the absense of bugs, large chunks can result in bad latencies when
+ * you decide to kill the process.
+ */
+#define MAX_IO_SIZE (8*1024*1024)
+
/*
* xread() is the same a read(), but it automatically restarts read()
* operations with a recoverable error (EAGAIN and EINTR). xread()
ssize_t xread(int fd, void *buf, size_t len)
{
ssize_t nr;
+ if (len > MAX_IO_SIZE)
+ len = MAX_IO_SIZE;
while (1) {
nr = read(fd, buf, len);
if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
ssize_t xwrite(int fd, const void *buf, size_t len)
{
ssize_t nr;
+ if (len > MAX_IO_SIZE)
+ len = MAX_IO_SIZE;
while (1) {
nr = write(fd, buf, len);
if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
return git_mkstemps_mode(pattern, 0, mode);
}
+#ifdef NO_MKSTEMPS
int gitmkstemps(char *pattern, int suffix_len)
{
return git_mkstemps_mode(pattern, suffix_len, 0600);
}
+#endif
int xmkstemp_mode(char *template, int mode)
{
#include "cache.h"
+#include "pathspec.h"
#include "wt-status.h"
#include "object.h"
#include "dir.h"
#include "diffcore.h"
#include "quote.h"
#include "run-command.h"
+#include "argv-array.h"
#include "remote.h"
#include "refs.h"
#include "submodule.h"
strbuf_vaddf(&sb, fmt, ap);
if (!sb.len) {
- strbuf_addch(&sb, comment_line_char);
- if (!trail)
- strbuf_addch(&sb, ' ');
+ if (s->display_comment_prefix) {
+ strbuf_addch(&sb, comment_line_char);
+ if (!trail)
+ strbuf_addch(&sb, ' ');
+ }
color_print_strbuf(s->fp, color, &sb);
if (trail)
fprintf(s->fp, "%s", trail);
eol = strchr(line, '\n');
strbuf_reset(&linebuf);
- if (at_bol) {
+ if (at_bol && s->display_comment_prefix) {
strbuf_addch(&linebuf, comment_line_char);
if (*line != '\n' && *line != '\t')
strbuf_addch(&linebuf, ' ');
s->untracked.strdup_strings = 1;
s->ignored.strdup_strings = 1;
s->show_branch = -1; /* unspecified */
+ s->display_comment_prefix = 0;
}
static void wt_status_print_unmerged_header(struct wt_status *s)
}
}
- if (!advice_status_hints)
+ if (!s->hints)
return;
if (s->whence != FROM_COMMIT)
;
const char *c = color(WT_STATUS_HEADER, s);
status_printf_ln(s, c, _("Changes to be committed:"));
- if (!advice_status_hints)
+ if (!s->hints)
return;
if (s->whence != FROM_COMMIT)
; /* NEEDSWORK: use "git reset --unresolve"??? */
const char *c = color(WT_STATUS_HEADER, s);
status_printf_ln(s, c, _("Changes not staged for commit:"));
- if (!advice_status_hints)
+ if (!s->hints)
return;
if (!has_deleted)
status_printf_ln(s, c, _(" (use \"git add <file>...\" to update what will be committed)"));
{
const char *c = color(WT_STATUS_HEADER, s);
status_printf_ln(s, c, "%s:", what);
- if (!advice_status_hints)
+ if (!s->hints)
return;
status_printf_ln(s, c, _(" (use \"git %s <file>...\" to include in what will be committed)"), how);
status_printf_ln(s, c, "");
}
rev.diffopt.format_callback = wt_status_collect_changed_cb;
rev.diffopt.format_callback_data = s;
- init_pathspec(&rev.prune_data, s->pathspec);
+ copy_pathspec(&rev.prune_data, &s->pathspec);
run_diff_files(&rev, 0);
}
rev.diffopt.detect_rename = 1;
rev.diffopt.rename_limit = 200;
rev.diffopt.break_opt = 0;
- init_pathspec(&rev.prune_data, s->pathspec);
+ copy_pathspec(&rev.prune_data, &s->pathspec);
run_diff_index(&rev, 1);
}
static void wt_status_collect_changes_initial(struct wt_status *s)
{
- struct pathspec pathspec;
int i;
- init_pathspec(&pathspec, s->pathspec);
for (i = 0; i < active_nr; i++) {
struct string_list_item *it;
struct wt_status_change_data *d;
const struct cache_entry *ce = active_cache[i];
- if (!ce_path_match(ce, &pathspec))
+ if (!ce_path_match(ce, &s->pathspec))
continue;
it = string_list_insert(&s->change, ce->name);
d = it->util;
else
d->index_status = DIFF_STATUS_ADDED;
}
- free_pathspec(&pathspec);
}
static void wt_status_collect_untracked(struct wt_status *s)
dir.flags |= DIR_SHOW_IGNORED_TOO;
setup_standard_excludes(&dir);
- fill_directory(&dir, s->pathspec);
+ fill_directory(&dir, &s->pathspec);
for (i = 0; i < dir.nr; i++) {
struct dir_entry *ent = dir.entries[i];
if (cache_name_is_other(ent->name, ent->len) &&
- match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL))
+ match_pathspec_depth(&s->pathspec, ent->name, ent->len, 0, NULL))
string_list_insert(&s->untracked, ent->name);
free(ent);
}
for (i = 0; i < dir.ignored_nr; i++) {
struct dir_entry *ent = dir.ignored[i];
if (cache_name_is_other(ent->name, ent->len) &&
- match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL))
+ match_pathspec_depth(&s->pathspec, ent->name, ent->len, 0, NULL))
string_list_insert(&s->ignored, ent->name);
free(ent);
}
char summary_limit[64];
char index[PATH_MAX];
const char *env[] = { NULL, NULL };
- const char *argv[8];
-
- env[0] = index;
- argv[0] = "submodule";
- argv[1] = "summary";
- argv[2] = uncommitted ? "--files" : "--cached";
- argv[3] = "--for-status";
- argv[4] = "--summary-limit";
- argv[5] = summary_limit;
- argv[6] = uncommitted ? NULL : (s->amend ? "HEAD^" : "HEAD");
- argv[7] = NULL;
+ struct argv_array argv = ARGV_ARRAY_INIT;
+ struct strbuf cmd_stdout = STRBUF_INIT;
+ struct strbuf summary = STRBUF_INIT;
+ char *summary_content;
+ size_t len;
sprintf(summary_limit, "%d", s->submodule_summary);
snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", s->index_file);
+ env[0] = index;
+ argv_array_push(&argv, "submodule");
+ argv_array_push(&argv, "summary");
+ argv_array_push(&argv, uncommitted ? "--files" : "--cached");
+ argv_array_push(&argv, "--for-status");
+ argv_array_push(&argv, "--summary-limit");
+ argv_array_push(&argv, summary_limit);
+ if (!uncommitted)
+ argv_array_push(&argv, s->amend ? "HEAD^" : "HEAD");
+
memset(&sm_summary, 0, sizeof(sm_summary));
- sm_summary.argv = argv;
+ sm_summary.argv = argv.argv;
sm_summary.env = env;
sm_summary.git_cmd = 1;
sm_summary.no_stdin = 1;
fflush(s->fp);
- sm_summary.out = dup(fileno(s->fp)); /* run_command closes it */
+ sm_summary.out = -1;
+
run_command(&sm_summary);
+ argv_array_clear(&argv);
+
+ len = strbuf_read(&cmd_stdout, sm_summary.out, 1024);
+
+ /* prepend header, only if there's an actual output */
+ if (len) {
+ if (uncommitted)
+ strbuf_addstr(&summary, _("Submodules changed but not updated:"));
+ else
+ strbuf_addstr(&summary, _("Submodule changes to be committed:"));
+ strbuf_addstr(&summary, "\n\n");
+ }
+ strbuf_addbuf(&summary, &cmd_stdout);
+ strbuf_release(&cmd_stdout);
+
+ if (s->display_comment_prefix) {
+ summary_content = strbuf_detach(&summary, &len);
+ strbuf_add_commented_lines(&summary, summary_content, len);
+ free(summary_content);
+ }
+
+ fputs(summary.buf, s->fp);
+ strbuf_release(&summary);
}
static void wt_status_print_other(struct wt_status *s,
strbuf_release(&buf);
if (!column_active(s->colopts))
- return;
+ goto conclude;
- strbuf_addf(&buf, "%s#\t%s",
+ strbuf_addf(&buf, "%s%s\t%s",
color(WT_STATUS_HEADER, s),
+ s->display_comment_prefix ? "#" : "",
color(WT_STATUS_UNTRACKED, s));
memset(&copts, 0, sizeof(copts));
copts.padding = 1;
print_columns(&output, s->colopts, &copts);
string_list_clear(&output, 0);
strbuf_release(&buf);
+conclude:
+ status_printf_ln(s, GIT_COLOR_NORMAL, "");
}
static void wt_status_print_verbose(struct wt_status *s)
struct strbuf sb = STRBUF_INIT;
const char *cp, *ep;
struct branch *branch;
+ char comment_line_string[3];
+ int i;
assert(s->branch && !s->is_initial);
if (prefixcmp(s->branch, "refs/heads/"))
if (!format_tracking_info(branch, &sb))
return;
+ i = 0;
+ if (s->display_comment_prefix) {
+ comment_line_string[i++] = comment_line_char;
+ comment_line_string[i++] = ' ';
+ }
+ comment_line_string[i] = '\0';
+
for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1)
color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s),
- "%c %.*s", comment_line_char,
+ "%s%.*s", comment_line_string,
(int)(ep - cp), cp);
- color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c",
- comment_line_char);
+ if (s->display_comment_prefix)
+ color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c",
+ comment_line_char);
+ else
+ fprintf_ln(s->fp, "");
}
static int has_unmerged(struct wt_status *s)
{
if (has_unmerged(s)) {
status_printf_ln(s, color, _("You have unmerged paths."));
- if (advice_status_hints)
+ if (s->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)
+ if (s->hints)
status_printf_ln(s, color,
_(" (use \"git commit\" to conclude merge)"));
}
if (state->am_empty_patch)
status_printf_ln(s, color,
_("The current patch is empty."));
- if (advice_status_hints) {
+ if (s->hints) {
if (!state->am_empty_patch)
status_printf_ln(s, color,
_(" (fix conflicts and then run \"git am --continue\")"));
else
status_printf_ln(s, color,
_("You are currently rebasing."));
- if (advice_status_hints) {
+ if (s->hints) {
status_printf_ln(s, color,
_(" (fix conflicts and then run \"git rebase --continue\")"));
status_printf_ln(s, color,
else
status_printf_ln(s, color,
_("You are currently rebasing."));
- if (advice_status_hints)
+ if (s->hints)
status_printf_ln(s, color,
_(" (all conflicts fixed: run \"git rebase --continue\")"));
} else if (split_commit_in_progress(s)) {
else
status_printf_ln(s, color,
_("You are currently splitting a commit during a rebase."));
- if (advice_status_hints)
+ if (s->hints)
status_printf_ln(s, color,
_(" (Once your working directory is clean, run \"git rebase --continue\")"));
} else {
else
status_printf_ln(s, color,
_("You are currently editing a commit during a rebase."));
- if (advice_status_hints && !s->amend) {
+ if (s->hints && !s->amend) {
status_printf_ln(s, color,
_(" (use \"git commit --amend\" to amend the current commit)"));
status_printf_ln(s, color,
struct wt_status_state *state,
const char *color)
{
- status_printf_ln(s, color, _("You are currently cherry-picking."));
- if (advice_status_hints) {
+ status_printf_ln(s, color, _("You are currently cherry-picking commit %s."),
+ find_unique_abbrev(state->cherry_pick_head_sha1, DEFAULT_ABBREV));
+ if (s->hints) {
if (has_unmerged(s))
status_printf_ln(s, color,
_(" (fix conflicts and run \"git cherry-pick --continue\")"));
{
status_printf_ln(s, color, _("You are currently reverting commit %s."),
find_unique_abbrev(state->revert_head_sha1, DEFAULT_ABBREV));
- if (advice_status_hints) {
+ if (s->hints) {
if (has_unmerged(s))
status_printf_ln(s, color,
_(" (fix conflicts and run \"git revert --continue\")"));
else
status_printf_ln(s, color,
_("You are currently bisecting."));
- if (advice_status_hints)
+ if (s->hints)
status_printf_ln(s, color,
_(" (use \"git bisect reset\" to get back to the original branch)"));
wt_status_print_trailer(s);
state->rebase_in_progress = 1;
state->branch = read_and_strip_branch("rebase-merge/head-name");
state->onto = read_and_strip_branch("rebase-merge/onto");
- } else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) {
+ } else if (!stat(git_path("CHERRY_PICK_HEAD"), &st) &&
+ !get_sha1("CHERRY_PICK_HEAD", sha1)) {
state->cherry_pick_in_progress = 1;
+ hashcpy(state->cherry_pick_head_sha1, sha1);
}
if (!stat(git_path("BISECT_LOG"), &st)) {
state->bisect_in_progress = 1;
}
} else if (s->commitable)
status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"),
- advice_status_hints
+ s->hints
? _(" (use -u option to show untracked files)") : "");
if (s->verbose)
else if (s->nowarn)
; /* nothing */
else if (s->workdir_dirty) {
- if (advice_status_hints)
+ if (s->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)
+ if (s->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)
+ if (s->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)
+ if (s->hints)
printf(_("nothing to commit (use -u to show untracked files)\n"));
else
printf(_("nothing to commit\n"));
const char *base;
const char *branch_name;
int num_ours, num_theirs;
+ int upstream_is_gone = 0;
color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## ");
branch = branch_get(s->branch + 11);
if (s->is_initial)
color_fprintf(s->fp, header_color, _("Initial commit on "));
- if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
- color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+
+ color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+
+ switch (stat_tracking_info(branch, &num_ours, &num_theirs)) {
+ case 0:
+ /* no base */
fputc(s->null_termination ? '\0' : '\n', s->fp);
return;
+ case -1:
+ /* with "gone" base */
+ upstream_is_gone = 1;
+ break;
+ default:
+ /* with base */
+ break;
}
base = branch->merge[0]->dst;
base = shorten_unambiguous_ref(base, 0);
- color_fprintf(s->fp, branch_color_local, "%s", branch_name);
color_fprintf(s->fp, header_color, "...");
color_fprintf(s->fp, branch_color_remote, "%s", base);
+ if (!upstream_is_gone && !num_ours && !num_theirs) {
+ fputc(s->null_termination ? '\0' : '\n', s->fp);
+ return;
+ }
+
color_fprintf(s->fp, header_color, " [");
- if (!num_ours) {
+ if (upstream_is_gone) {
+ color_fprintf(s->fp, header_color, _("gone"));
+ } else if (!num_ours) {
color_fprintf(s->fp, header_color, _("behind "));
color_fprintf(s->fp, branch_color_remote, "%d", num_theirs);
} else if (!num_theirs) {
int is_initial;
char *branch;
const char *reference;
- const char **pathspec;
+ struct pathspec pathspec;
int verbose;
int amend;
enum commit_whence whence;
int nowarn;
int use_color;
+ int display_comment_prefix;
int relative_paths;
int submodule_summary;
int show_ignored_files;
unsigned colopts;
int null_termination;
int show_branch;
+ int hints;
/* These are computed during processing of the individual sections */
int commitable;
char *detached_from;
unsigned char detached_sha1[20];
unsigned char revert_head_sha1[20];
+ unsigned char cherry_pick_head_sha1[20];
};
void wt_status_prepare(struct wt_status *s);
{
if (len > 0 &&
(isalpha((unsigned char)*rec) || /* identifier? */
- *rec == '_' || /* also identifier? */
+ *rec == '_' || /* also identifier? */
*rec == '$')) { /* identifiers from VMS and other esoterico */
if (len > sz)
len = sz;