--- /dev/null
+Git v1.8.2.2 Release Notes
+==========================
+
+Fixes since v1.8.2.1
+--------------------
+
+ * "git diff --diff-algorithm=algo" was understood by the command line
+ parser, but "git diff --diff-algorithm algo" was not.
+
+ * "git log -S/-G" started paying attention to textconv filter, but
+ there was no way to disable this. Make it honor --no-textconv
+ option.
+
+ * "git merge $(git rev-parse v1.8.2)" behaved quite differently from
+ "git merge v1.8.2", as if v1.8.2 were written as v1.8.2^0 and did
+ not pay much attention to the annotated tag payload. Make the code
+ notice the type of the tag object, in addition to the dwim_ref()
+ based classification the current code uses (i.e. the name appears
+ in refs/tags/) to decide when to special case merging of tags.
+
+ * "git cherry-pick" and "git revert" can take more than one commit
+ on the command line these days, but it was not mentioned on the usage
+ text.
+
+ * Perl scripts like "git-svn" closed (not redirecting to /dev/null)
+ the standard error stream, which is not a very smart thing to do.
+ Later open may return file descriptor #2 for unrelated purpose, and
+ error reporting code may write into them.
+
+ * "git apply --whitespace=fix" was not prepared to see a line getting
+ longer after fixing whitespaces (e.g. tab-in-indent aka Python).
+
+ * "git diff/log --cc" did not work well with options that ignore
+ whitespace changes.
+
+ * Documentation on setting up a http server that requires
+ authentication only on the push but not fetch has been clarified.
+
+ * A few bugfixes to "git rerere" working on corner case merge
+ conflicts have been applied.
+
+ * "git bundle" did not like a bundle created using a commit without
+ any message as its one of the prerequistes.
core.logAllRefUpdates::
Enable the reflog. Updates to a ref <ref> is logged to the file
"$GIT_DIR/logs/<ref>", by appending the new and old
- SHA1, the date/time and the reason of the update, but
+ SHA-1, the date/time and the reason of the update, but
only when the file exists. If this configuration
variable is set to true, missing "$GIT_DIR/logs/<ref>"
file is automatically created for branch heads (i.e. under
(which implies type "blob").
In the second form, a list of objects (separated by linefeeds) is provided on
-stdin, and the SHA1, type, and size of each object is printed on stdout.
+stdin, and the SHA-1, type, and size of each object is printed on stdout.
OPTIONS
-------
to apply the filter to the content recorded in the index at <path>.
--batch::
- Print the SHA1, type, size, and contents of each object provided on
+ Print the SHA-1, type, size, and contents of each object provided on
stdin. May not be combined with any other options or arguments.
--batch-check::
- Print the SHA1, type, and size of each object provided on stdin. May not
+ Print the SHA-1, type, and size of each object provided on stdin. May not
be combined with any other options or arguments.
OUTPUT
Giving these options is an error when used with `--inetd`; use
the facility of inet daemon to achieve the same before spawning
'git daemon' if needed.
++
+Like many programs that switch user id, the daemon does not reset
+environment variables such as `$HOME` when it runs git programs,
+e.g. `upload-pack` and `receive-pack`. When using this option, you
+may also want to set and export `HOME` to point at the home
+directory of `<user>` before starting the daemon, and make sure any
+Git configuration files in that directory are readable by `<user>`.
--enable=<service>::
--disable=<service>::
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 SHA1.
+abbreviation of the input committish's SHA-1.
If multiple tags were found during the walk then the tag which
has the fewest commits different from the input committish will be
An object to treat as the head of an unreachability trace.
+
If no objects are given, 'git fsck' defaults to using the
-index file, all SHA1 references in `refs` namespace, and all reflogs
+index file, all SHA-1 references in `refs` namespace, and all reflogs
(unless --no-reflogs is given) as heads.
--unreachable::
DISCUSSION
----------
-git-fsck tests SHA1 and general object sanity, and it does full tracking
+git-fsck tests SHA-1 and general object sanity, and it does full tracking
of the resulting reachability and everything else. It prints out any
corruption it finds (missing or bad objects), and if you use the
'--unreachable' flag it will also print out objects that exist but that
----------------------------------------------------------------
+
To enable anonymous read access but authenticated write access,
-require authorization with a LocationMatch directive:
+require authorization for both the initial ref advertisement (which we
+detect as a push via the service parameter in the query string), and the
+receive-pack invocation itself:
++
+----------------------------------------------------------------
+RewriteCond %{QUERY_STRING} service=git-receive-pack [OR]
+RewriteCond %{REQUEST_URI} /git-receive-pack$
+RewriteRule ^/git/ - [E=AUTHREQUIRED:yes]
+
+<LocationMatch "^/git/">
+ Order Deny,Allow
+ Deny from env=AUTHREQUIRED
+
+ AuthType Basic
+ AuthName "Git Access"
+ Require group committers
+ Satisfy Any
+ ...
+</LocationMatch>
+----------------------------------------------------------------
++
+If you do not have `mod_rewrite` available to match against the query
+string, it is sufficient to just protect `git-receive-pack` itself,
+like:
+
----------------------------------------------------------------
<LocationMatch "^/git/.*/git-receive-pack$">
</LocationMatch>
----------------------------------------------------------------
+
+In this mode, the server will not request authentication until the
+client actually starts the object negotiation phase of the push, rather
+than during the initial contact. For this reason, you must also enable
+the `http.receivepack` config option in any repositories that should
+accept a push. The default behavior, if `http.receivepack` is not set,
+is to reject any pushes by unauthenticated users; the initial request
+will therefore report `403 Forbidden` to the client, without even giving
+an opportunity for authentication.
++
To require authentication for both reads and writes, use a Location
directive around the repository, or one of its parent directories:
+
ScriptAlias /git/ /var/www/cgi-bin/gitweb.cgi/
----------------------------------------------------------------
+Lighttpd::
+ Ensure that `mod_cgi`, `mod_alias, `mod_auth`, `mod_setenv` are
+ loaded, then set `GIT_PROJECT_ROOT` appropriately and redirect
+ all requests to the CGI:
++
+----------------------------------------------------------------
+alias.url += ( "/git" => "/usr/lib/git-core/git-http-backend" )
+$HTTP["url"] =~ "^/git" {
+ cgi.assign = ("" => "")
+ setenv.add-environment = (
+ "GIT_PROJECT_ROOT" => "/var/www/git",
+ "GIT_HTTP_EXPORT_ALL" => ""
+ )
+}
+----------------------------------------------------------------
++
+To enable anonymous read access but authenticated write access:
++
+----------------------------------------------------------------
+$HTTP["querystring"] =~ "service=git-receive-pack" {
+ include "git-auth.conf"
+}
+$HTTP["url"] =~ "^/git/.*/git-receive-pack$" {
+ include "git-auth.conf"
+}
+----------------------------------------------------------------
++
+where `git-auth.conf` looks something like:
++
+----------------------------------------------------------------
+auth.require = (
+ "/" => (
+ "method" => "basic",
+ "realm" => "Git Access",
+ "require" => "valid-user"
+ )
+)
+# ...and set up auth.backend here
+----------------------------------------------------------------
++
+To require authentication for both reads and writes:
++
+----------------------------------------------------------------
+$HTTP["url"] =~ "^/git/private" {
+ include "git-auth.conf"
+}
+----------------------------------------------------------------
+
ENVIRONMENT
-----------
----
Once the index has been created, the list of object names is sorted
-and the SHA1 hash of that list is printed to stdout. If --stdin was
+and the SHA-1 hash of that list is printed to stdout. If --stdin was
also used then this is prefixed by either "pack\t", or "keep\t" if a
new .keep file was successfully created. This is useful to remove a
.keep file used as a lock to prevent the race with 'git repack'
'git ls-files --unmerged' and 'git ls-files --stage' can be used to examine
detailed information on unmerged paths.
-For an unmerged path, instead of recording a single mode/SHA1 pair,
+For an unmerged path, instead of recording a single mode/SHA-1 pair,
the index records up to three such pairs; one from tree O in stage
1, A in stage 2, and B in stage 3. This information can be used by
the user (or the porcelain) to see what should eventually be recorded at the
DESCRIPTION
-----------
This looks up the <file>(s) in the index and, if there are any merge
-entries, passes the SHA1 hash for those files as arguments 1, 2, 3 (empty
+entries, passes the SHA-1 hash for those files as arguments 1, 2, 3 (empty
argument if no file), and <file> as argument 4. File modes for the three
files are passed as arguments 5, 6 and 7.
Write into a pair of files (.pack and .idx), using
<base-name> to determine the name of the created file.
When this option is used, the two files are written in
- <base-name>-<SHA1>.{pack,idx} files. <SHA1> is a hash
+ <base-name>-<SHA-1>.{pack,idx} files. <SHA-1> is a hash
of the sorted object names to make the resulting filename
based on the pack content, and written to the standard
output of the command.
DESCRIPTION
-----------
-A "patch ID" is nothing but a SHA1 of the diff associated with a patch, with
+A "patch ID" is nothing but a SHA-1 of the diff associated with a patch, with
whitespace and line numbers ignored. As such, it's "reasonably stable", but at
the same time also reasonably unique, i.e., two patches that have the same "patch
ID" are almost guaranteed to be the same thing.
-----------
Adds a 'replace' reference in `refs/replace/` namespace.
-The name of the 'replace' reference is the SHA1 of the object that is
-replaced. The content of the 'replace' reference is the SHA1 of the
+The name of the 'replace' reference is the SHA-1 of the object that is
+replaced. The content of the 'replace' reference is the SHA-1 of the
replacement object.
Unless `-f` is given, the 'replace' reference must not yet exist.
one.
--symbolic::
- Usually the object names are output in SHA1 form (with
+ Usually the object names are output in SHA-1 form (with
possible '{caret}' prefix); this option makes them output in a
form as close to the original input as possible.
--short::
--short=number::
- Instead of outputting the full SHA1 values of object names try to
+ 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.
OPTIONS
-------
<rev>::
- Arbitrary extended SHA1 expression (see linkgit:gitrevisions[7])
+ Arbitrary extended SHA-1 expression (see linkgit:gitrevisions[7])
that typically names a branch head or a tag.
<glob>::
branch, the I-th indentation character shows a `+` sign;
otherwise it shows a space. Merge commits are denoted by
a `-` sign. Each commit shows a short name that
-can be used as an extended SHA1 to name that commit.
+can be used as an extended SHA-1 to name that commit.
The following example shows three branches, "master", "fixes"
and "mhf":
The information it outputs is subset of what you can get from
'git verify-pack -v'; this command only shows the packfile
-offset and SHA1 of each object.
+offset and SHA-1 of each object.
GIT
---
-s::
--hash[=<n>]::
- Only show the SHA1 hash, not the reference name. When combined with
- --dereference the dereferenced tag will still be shown after the SHA1.
+ Only show the SHA-1 hash, not the reference name. When combined with
+ --dereference the dereferenced tag will still be shown after the SHA-1.
--verify::
If `-m <msg>` or `-F <file>` is given and `-a`, `-s`, and `-u <key-id>`
are absent, `-a` is implied.
-Otherwise just a tag reference for the SHA1 object name of the commit object is
+Otherwise just a tag reference for the SHA-1 object name of the commit object is
created (i.e. a lightweight tag).
A GnuPG signed tag object will be created when `-s` or `-u
------------
The first line of the input feeds 0 as the mode to remove the
-path; the SHA1 does not matter as long as it is well formatted.
+path; the SHA-1 does not matter as long as it is well formatted.
Then the second and third line feeds stage 1 and stage 2 entries
for that path. After the above, we would end up with this:
-------------
When specifying the -v option the format used is:
- SHA1 type size size-in-pack-file offset-in-packfile
+ SHA-1 type size size-in-pack-file offset-in-packfile
for objects that are not deltified in the pack, and
- SHA1 type size size-in-packfile offset-in-packfile depth base-SHA1
+ SHA-1 type size size-in-packfile offset-in-packfile depth base-SHA-1
for objects that are deltified.
Print the contents of the tag object before validating it.
<tag>...::
- SHA1 identifiers of Git tag objects.
+ SHA-1 identifiers of Git tag objects.
GIT
---
<old|new>-file:: are files GIT_EXTERNAL_DIFF can use to read the
contents of <old|new>,
- <old|new>-hex:: are the 40-hexdigit SHA1 hashes,
+ <old|new>-hex:: are the 40-hexdigit SHA-1 hashes,
<old|new>-mode:: are the octal representation of the file modes.
+
The file parameters can point at the user's working file
represents an immediately preceding step. Commits with more than one
parent represent merges of independent lines of development.
-All objects are named by the SHA1 hash of their contents, normally
+All objects are named by the SHA-1 hash of their contents, normally
written as a string of 40 hex digits. Such names are globally unique.
The entire history leading up to a commit can be vouched for by signing
just that commit. A fourth object type, the tag, is provided for this
efficiency may later be compressed together into "pack files".
Named pointers called refs mark interesting points in history. A ref
-may contain the SHA1 name of an object or the name of another ref. Refs
-with names beginning `ref/head/` contain the SHA1 name of the most
-recent commit (or "head") of a branch under development. SHA1 names of
+may contain the SHA-1 name of an object or the name of another ref. Refs
+with names beginning `ref/head/` contain the SHA-1 name of the most
+recent commit (or "head") of a branch under development. SHA-1 names of
tags of interest are stored under `ref/tags/`. A special ref named
`HEAD` contains the name of the currently checked-out branch.
valid, though.
[NOTE]
-An 'object' is identified by its 160-bit SHA1 hash, aka 'object name',
+An 'object' is identified by its 160-bit SHA-1 hash, aka 'object name',
and a reference to an object is always the 40-byte hex
-representation of that SHA1 name. The files in the `refs`
+representation of that SHA-1 name. The files in the `refs`
subdirectory are expected to contain these hex references
(usually with a final `\n` at the end), and you should thus
expect to see a number of 41-byte files containing these
these object pointers.
You can at any time create a new branch by just picking an arbitrary
-point in the project history, and just writing the SHA1 name of that
+point in the project history, and just writing the SHA-1 name of that
object into a file under `.git/refs/heads/`. You can use any filename you
want (and indeed, subdirectories), but the convention is that the
"normal" branch is called `master`. That's just a convention, though,
etc.). After reading three trees into three stages, the paths
that are the same in all three stages are 'collapsed' into stage
0. Also paths that are the same in two of three stages are
-collapsed into stage 0, taking the SHA1 from either stage 2 or
+collapsed into stage 0, taking the SHA-1 from either stage 2 or
stage 3, whichever is different from stage 1 (i.e. only one side
changed from the common ancestor).
For the purpose of breaking a filepair, diffcore-break examines
the extent of changes between the contents of the files before
and after modification (i.e. the contents that have "bcd1234..."
-and "0123456..." as their SHA1 content ID, in the above
+and "0123456..." as their SHA-1 content ID, in the above
example). The amount of deletion of original contents and
insertion of new material are added together, and if it exceeds
the "break score", the filepair is broken into two. The break
configuration option `commit.template` is set); `merge` (if the
commit is a merge or a `.git/MERGE_MSG` file exists); `squash`
(if a `.git/SQUASH_MSG` file exists); or `commit`, followed by
-a commit SHA1 (if a `-c`, `-C` or `--amend` option was given).
+a commit SHA-1 (if a `-c`, `-C` or `--amend` option was given).
If the exit status is non-zero, 'git commit' will abort.
refs/heads/master 67890 refs/heads/foreign 12345
-although the full, 40-character SHA1s would be supplied. If the foreign ref
-does not yet exist the `<remote SHA1>` will be 40 `0`. If a ref is to be
+although the full, 40-character SHA-1s would be supplied. If the foreign ref
+does not yet exist the `<remote SHA-1>` will be 40 `0`. If a ref is to be
deleted, the `<local ref>` will be supplied as `(delete)` and the `<local
-SHA1>` will be 40 `0`. If the local commit was specified by something other
-than a name which could be expanded (such as `HEAD~`, or a SHA1) it will be
+SHA-1>` will be 40 `0`. If the local commit was specified by something other
+than a name which could be expanded (such as `HEAD~`, or a SHA-1) it will be
supplied as it was originally given.
If this hook exits with a non-zero status, 'git push' will abort without
from a remote repository.
refs/replace/`<obj-sha1>`::
- records the SHA1 of the object that replaces `<obj-sha1>`.
+ records the SHA-1 of the object that replaces `<obj-sha1>`.
This is similar to info/grafts and is internally used and
maintained by linkgit:git-replace[1]. Such refs can be exchanged
between repositories while grafts are not.
We saw in part one of the tutorial that commits have names like this.
It turns out that every object in the Git history is stored under
-a 40-digit hex name. That name is the SHA1 hash of the object's
+a 40-digit hex name. That name is the SHA-1 hash of the object's
contents; among other things, this ensures that Git will never store
-the same data twice (since identical data is given an identical SHA1
+the same data twice (since identical data is given an identical SHA-1
name), and that the contents of a Git object will never change (since
that would change the object's name as well). The 7 char hex strings
here are simply the abbreviation of such 40 character long strings.
can be used, so long as they are unambiguous.
It is expected that the content of the commit object you created while
-following the example above generates a different SHA1 hash than
+following the example above generates a different SHA-1 hash than
the one shown above because the commit object records the time when
it was created and the name of the person performing the commit.
a file. In addition, a tree can also refer to other tree objects,
thus creating a directory hierarchy. You can examine the contents of
any tree using ls-tree (remember that a long enough initial portion
-of the SHA1 will also work):
+of the SHA-1 will also work):
------------------------------------------------
$ git ls-tree 92b8b694
100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad file.txt
------------------------------------------------
-Thus we see that this tree has one file in it. The SHA1 hash is a
+Thus we see that this tree has one file in it. The SHA-1 hash is a
reference to that file's data:
------------------------------------------------
its response to the initial tree was a tree with a snapshot of the
directory state that was recorded by the first commit.
-All of these objects are stored under their SHA1 names inside the Git
+All of these objects are stored under their SHA-1 names inside the Git
directory:
------------------------------------------------
As you can see, this tells us which branch we're currently on, and it
tells us this by naming a file under the .git directory, which itself
-contains a SHA1 name referring to a commit object, which we can
+contains a SHA-1 name referring to a commit object, which we can
examine with cat-file:
------------------------------------------------
Note, by the way, that lots of commands take a tree as an argument.
But as we can see above, a tree can be referred to in many different
-ways--by the SHA1 name for that tree, by the name of a commit that
+ways--by the SHA-1 name for that tree, by the name of a commit that
refers to the tree, by the name of a branch whose head refers to that
tree, etc.--and most such commands can accept any of these names.
[[def_detached_HEAD]]detached HEAD::
Normally the <<def_HEAD,HEAD>> stores the name of a
- <<def_branch,branch>>. However, Git also allows you to <<def_checkout,check out>>
- an arbitrary <<def_commit,commit>> that isn't necessarily the tip of any
- particular branch. In this case HEAD is said to be "detached".
-
-[[def_dircache]]dircache::
- You are *waaaaay* behind. See <<def_index,index>>.
+ <<def_branch,branch>>, and commands that operate on the
+ history HEAD represents operate on the history leading to the
+ tip of the branch the HEAD points at. However, Git also
+ allows you to <<def_checkout,check out>> an arbitrary
+ <<def_commit,commit>> that isn't necessarily the tip of any
+ particular branch. The HEAD in such a state is called
+ "detached".
++
+Note that commands that operate on the history of the current branch
+(e.g. `git commit` to build a new history on top of it) still work
+while the HEAD is detached. They update the HEAD to point at the tip
+of the updated history without affecting any branch. Commands that
+update or inquire information _about_ the current branch (e.g. `git
+branch --set-upstream-to` that sets what remote tracking branch the
+current branch integrates with) obviously do not work, as there is no
+(real) current branch to ask about in this state.
[[def_directory]]directory::
The list you get with "ls" :-)
it contains modifications which have not been <<def_commit,committed>> to the current
<<def_branch,branch>>.
-[[def_ent]]ent::
- Favorite synonym to "<<def_tree-ish,tree-ish>>" by some total geeks. See
- http://en.wikipedia.org/wiki/Ent_(Middle-earth) for an in-depth
- explanation. Avoid this term, not to confuse people.
-
[[def_evil_merge]]evil merge::
An evil merge is a <<def_merge,merge>> that introduces changes that
do not appear in any <<def_parent,parent>>.
created. Configured via the `.git/info/grafts` file.
[[def_hash]]hash::
- In Git's context, synonym to <<def_object_name,object name>>.
+ In Git's context, synonym for <<def_object_name,object name>>.
[[def_head]]head::
A <<def_ref,named reference>> to the <<def_commit,commit>> at the tip of a
[[def_object]]object::
The unit of storage in Git. It is uniquely identified by the
- <<def_SHA1,SHA1>> of its contents. Consequently, an
+ <<def_SHA1,SHA-1>> of its contents. Consequently, an
object can not be changed.
[[def_object_database]]object database::
Synonym for <<def_object_name,object name>>.
[[def_object_name]]object name::
- The unique identifier of an <<def_object,object>>. The <<def_hash,hash>>
- of the object's contents using the Secure Hash Algorithm
- 1 and usually represented by the 40 character hexadecimal encoding of
- the <<def_hash,hash>> of the object.
+ The unique identifier of an <<def_object,object>>. The
+ object name is usually represented by a 40 character
+ hexadecimal string. Also colloquially called <<def_SHA1,SHA-1>>.
[[def_object_type]]object type::
One of the identifiers "<<def_commit_object,commit>>",
<<def_object,object>>.
[[def_octopus]]octopus::
- To <<def_merge,merge>> more than two <<def_branch,branches>>. Also denotes an
- intelligent predator.
+ To <<def_merge,merge>> more than two <<def_branch,branches>>.
[[def_origin]]origin::
The default upstream <<def_repository,repository>>. Most projects have
pack.
[[def_pathspec]]pathspec::
- Pattern used to specify paths.
+ Pattern used to limit paths in Git commands.
+
Pathspecs are used on the command line of "git ls-files", "git
ls-tree", "git add", "git grep", "git diff", "git checkout",
worktree. See the documentation of each command for whether
paths are relative to the current directory or toplevel. The
pathspec syntax is as follows:
++
+--
* any path matches itself
* the pathspec up to the last slash represents a
of the pathname. Paths relative to the directory
prefix will be matched against that pattern using fnmatch(3);
in particular, '*' and '?' _can_ match directory separators.
+
+--
+
For example, Documentation/*.jpg will match all .jpg files
in the Documentation subtree,
including Documentation/chapter_1/figure_1.jpg.
-
+
A pathspec that begins with a colon `:` has special meaning. In the
short form, the leading colon `:` is followed by zero or more "magic
against the path.
+
The "magic signature" consists of an ASCII symbol that is not
-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.
---
-+
-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.
+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.
+
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,SHA1>> or a name that
+ 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.
[[def_refspec]]refspec::
A "refspec" is used by <<def_fetch,fetch>> and
<<def_push,push>> to describe the mapping between remote
- <<def_ref,ref>> and local ref. They are combined with a colon in
- the format <src>:<dst>, preceded by an optional plus sign, +.
- For example: `git fetch $URL
- refs/heads/master:refs/heads/origin` means "grab the master
- <<def_branch,branch>> <<def_head,head>> from the $URL and store
- it as my origin branch head". And `git push
- $URL refs/heads/master:refs/heads/to-upstream` means "publish my
- master branch head as to-upstream branch at $URL". See also
- linkgit:git-push[1].
+ <<def_ref,ref>> and local ref.
[[def_remote_tracking_branch]]remote-tracking branch::
A regular Git <<def_branch,branch>> that is used to follow changes from
[[def_SCM]]SCM::
Source code management (tool).
-[[def_SHA1]]SHA1::
- Synonym for <<def_object_name,object name>>.
+[[def_SHA1]]SHA-1::
+ "Secure Hash Algorithm 1"; a cryptographic hash function.
+ In the context of Git used as a synonym for <<def_object_name,object name>>.
[[def_shallow_repository]]shallow repository::
A shallow <<def_repository,repository>> has an incomplete
its history can be later deepened with linkgit:git-fetch[1].
[[def_symref]]symref::
- Symbolic reference: instead of containing the <<def_SHA1,SHA1>>
+ Symbolic reference: instead of containing the <<def_SHA1,SHA-1>>
id itself, it is of the format 'ref: refs/some/thing' and when
referenced, it recursively dereferences to this reference.
'<<def_HEAD,HEAD>>' is a prime example of a symref. Symbolic
> Any one know how can I track this object and understand which file is it
-----------------------------------------------------------
-So exactly *because* the SHA1 hash is cryptographically secure, the hash
+So exactly *because* the SHA-1 hash is cryptographically secure, the hash
itself doesn't actually tell you anything, in order to fix a corrupt
object you basically have to find the "original source" for it.
-----------------------------------------------------------
This is the right thing to do, although it's usually best to save it under
-it's full SHA1 name (you just dropped the "4b" from the result ;).
+it's full SHA-1 name (you just dropped the "4b" from the result ;).
Let's see what that tells us:
git hash-object -w my-magic-file
-again, and if it outputs the missing SHA1 (4b945..) you're now all done!
+again, and if it outputs the missing SHA-1 (4b945..) you're now all done!
But that's the really lucky case, so let's assume that it was some older
version that was broken. How do you tell which version it was?
this when the branches to be merged have diverged wildly.
See also linkgit:git-diff[1] `--patience`.
+diff-algorithm=[patience|minimal|histogram|myers];;
+ Tells 'merge-recursive' to use a different diff algorithm, which
+ can help avoid mismerges that occur due to unimportant matching
+ lines (such as braces from distinct functions). See also
+ linkgit:git-diff[1] `--diff-algorithm`.
+
ignore-space-change;;
ignore-all-space;;
ignore-space-at-eol;;
* 'raw'
+
The 'raw' format shows the entire commit exactly as
-stored in the commit object. Notably, the SHA1s are
+stored in the commit object. Notably, the SHA-1s are
displayed in full, regardless of whether --abbrev or
--no-abbrev are used, and 'parents' information show the
true parent commits, without taking grafts nor history
--------------------
A revision parameter '<rev>' typically, but not necessarily, names a
-commit object. It uses what is called an 'extended SHA1'
+commit object. It uses what is called an 'extended SHA-1'
syntax. Here are various ways to spell object names. The
ones listed near the end of this list name trees and
blobs contained in a commit.
'<sha1>', e.g. 'dae86e1950b1277e545cee180551750029cfe735', 'dae86e'::
- The full SHA1 object name (40-byte hexadecimal string), or
+ The full SHA-1 object name (40-byte hexadecimal string), or
a leading substring that is unique within the repository.
E.g. dae86e1950b1277e545cee180551750029cfe735 and dae86e both
name the same commit object if there is no other object in
sha1-array API
==============
-The sha1-array API provides storage and manipulation of sets of SHA1
+The sha1-array API provides storage and manipulation of sets of SHA-1
identifiers. The emphasis is on storage and processing efficiency,
making them suitable for large lists. Note that the ordering of items is
not preserved over some operations.
`struct sha1_array`::
- A single array of SHA1 hashes. This should be initialized by
+ A single array of SHA-1 hashes. This should be initialized by
assignment from `SHA1_ARRAY_INIT`. The `sha1` member contains
the actual data. The `nr` member contains the number of items in
the set. The `alloc` and `sorted` members are used internally,
Observation: length of each object is encoded in a variable
length format and is not constrained to 32-bit or anything.
- - The trailer records 20-byte SHA1 checksum of all of the above.
+ - The trailer records 20-byte SHA-1 checksum of all of the above.
== Original (version 1) pack-*.idx files have the following format:
- The file is concluded with a trailer:
- A copy of the 20-byte SHA1 checksum at the end of
+ A copy of the 20-byte SHA-1 checksum at the end of
corresponding packfile.
- 20-byte SHA1-checksum of all of the above.
+ 20-byte SHA-1-checksum of all of the above.
Pack Idx file:
If it is not DELTA, then deflated bytes (the size above
is the size before compression).
If it is REF_DELTA, then
- 20-byte base object name SHA1 (the size above is the
+ 20-byte base object name SHA-1 (the size above is the
size of the delta data that follows).
delta data, deflated.
If it is OFS_DELTA, then
- A 256-entry fan-out table just like v1.
- - A table of sorted 20-byte SHA1 object names. These are
+ - A table of sorted 20-byte SHA-1 object names. These are
packed together without offset values to reduce the cache
footprint of the binary search for a specific object name.
- The same trailer as a v1 pack file:
- A copy of the 20-byte SHA1 checksum at the end of
+ A copy of the 20-byte SHA-1 checksum at the end of
corresponding packfile.
- 20-byte SHA1-checksum of all of the above.
+ 20-byte SHA-1-checksum of all of the above.
<linus> The "magic" is actually in theory totally arbitrary.
ANY order will give you a working pack, but no, it's not
- ordered by SHA1.
+ ordered by SHA-1.
Before talking about the ordering for the sliding delta
window, let's talk about the recency order. That's more
these commits have no parents.
*********************************************************
-The basic idea is to write the SHA1s of shallow commits into
+The basic idea is to write the SHA-1s of shallow commits into
$GIT_DIR/shallow, and handle its contents like the contents
of $GIT_DIR/info/grafts (with the difference that shallow
cannot contain parent information).
at all (even throughout development of the shallow clone, it
was never manually edited!).
-Each line contains exactly one SHA1. When read, a commit_graft
+Each line contains exactly one SHA-1. When read, a commit_graft
will be constructed, which has nr_parent < 0 to make it easier
to discern from user provided grafts.
-Documentation/RelNotes/1.8.2.1.txt
\ No newline at end of file
+Documentation/RelNotes/1.8.2.2.txt
\ No newline at end of file
/*
* Adjust the common context lines in postimage. This can be
- * done in-place when we are just doing whitespace fixing,
- * which does not make the string grow, but needs a new buffer
- * when ignoring whitespace causes the update, since in this case
- * we could have e.g. tabs converted to multiple spaces.
+ * done in-place when we are shrinking it with whitespace
+ * fixing, but needs a new buffer when ignoring whitespace or
+ * expanding leading tabs to spaces.
+ *
* We trust the caller to tell us if the update can be done
* in place (postlen==0) or not.
*/
int i;
char *fixed_buf, *buf, *orig, *target;
struct strbuf fixed;
- size_t fixed_len;
+ size_t fixed_len, postlen;
int preimage_limit;
if (preimage->nr + try_lno <= img->nr) {
strbuf_init(&fixed, preimage->len + 1);
orig = preimage->buf;
target = img->buf + try;
+ postlen = 0;
for (i = 0; i < preimage_limit; i++) {
size_t oldlen = preimage->line[i].len;
size_t tgtlen = img->line[try_lno + i].len;
match = (tgtfix.len == fixed.len - fixstart &&
!memcmp(tgtfix.buf, fixed.buf + fixstart,
fixed.len - fixstart));
+ postlen += tgtfix.len;
strbuf_release(&tgtfix);
if (!match)
* hunk match. Update the context lines in the postimage.
*/
fixed_buf = strbuf_detach(&fixed, &fixed_len);
+ if (postlen < postimage->len)
+ postlen = 0;
update_pre_post_images(preimage, postimage,
- fixed_buf, fixed_len, 0);
+ fixed_buf, fixed_len, postlen);
return 1;
unmatch_exit:
maillen = ident.mail_end - ident.mail_begin;
mailbuf = ident.mail_begin;
- *time = strtoul(ident.date_begin, NULL, 10);
+ if (ident.date_begin && ident.date_end)
+ *time = strtoul(ident.date_begin, NULL, 10);
+ else
+ *time = 0;
- len = ident.tz_end - ident.tz_begin;
- strbuf_add(tz, ident.tz_begin, len);
+ if (ident.tz_begin && ident.tz_end)
+ strbuf_add(tz, ident.tz_begin, ident.tz_end - ident.tz_begin);
+ else
+ strbuf_addstr(tz, "(unknown)");
/*
* Now, convert both name and e-mail using mailmap
#define BATCH 1
#define BATCH_CHECK 2
-static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size)
-{
- /* the parser in tag.c is useless here. */
- const char *endp = buf + size;
- const char *cp = buf;
-
- while (cp < endp) {
- char c = *cp++;
- if (c != '\n')
- continue;
- if (7 <= endp - cp && !memcmp("tagger ", cp, 7)) {
- const char *tagger = cp;
-
- /* Found the tagger line. Copy out the contents
- * of the buffer so far.
- */
- write_or_die(1, buf, cp - buf);
-
- /*
- * Do something intelligent, like pretty-printing
- * the date.
- */
- while (cp < endp) {
- if (*cp++ == '\n') {
- /* tagger to cp is a line
- * that has ident and time.
- */
- const char *sp = tagger;
- char *ep;
- unsigned long date;
- long tz;
- while (sp < cp && *sp != '>')
- sp++;
- if (sp == cp) {
- /* give up */
- write_or_die(1, tagger,
- cp - tagger);
- break;
- }
- while (sp < cp &&
- !('0' <= *sp && *sp <= '9'))
- sp++;
- write_or_die(1, tagger, sp - tagger);
- date = strtoul(sp, &ep, 10);
- tz = strtol(ep, NULL, 10);
- sp = show_date(date, tz, 0);
- write_or_die(1, sp, strlen(sp));
- xwrite(1, "\n", 1);
- break;
- }
- }
- break;
- }
- if (cp < endp && *cp == '\n')
- /* end of header */
- break;
- }
- /* At this point, we have copied out the header up to the end of
- * the tagger line and cp points at one past \n. It could be the
- * next header line after the tagger line, or it could be another
- * \n that marks the end of the headers. We need to copy out the
- * remainder as is.
- */
- if (cp < endp)
- write_or_die(1, cp, endp - cp);
-}
-
static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
{
unsigned char sha1[20];
buf = read_sha1_file(sha1, &type, &size);
if (!buf)
die("Cannot read object %s", obj_name);
- if (type == OBJ_TAG) {
- pprint_tag(sha1, buf, size);
- return 0;
- }
/* otherwise just spit out the data */
break;
const char *me;
if (kind == 'a') {
- label = "\n# By ";
+ label = "By";
me = git_author_info(IDENT_NO_DATE);
} else {
- label = "\n# Via ";
+ label = "Via";
me = git_committer_info(IDENT_NO_DATE);
}
(me = skip_prefix(me, them->items->string)) != NULL &&
skip_prefix(me, " <")))
return;
- strbuf_addstr(out, label);
+ strbuf_addf(out, "\n%c %s ", comment_line_char, label);
add_people_count(out, them);
}
} else {
if (tag_number == 2) {
struct strbuf tagline = STRBUF_INIT;
- strbuf_addf(&tagline, "\n# %s\n",
- origins.items[first_tag].string);
+ strbuf_addch(&tagline, '\n');
+ strbuf_add_commented_lines(&tagline,
+ origins.items[first_tag].string,
+ strlen(origins.items[first_tag].string));
strbuf_insert(&tagbuf, 0, tagline.buf,
tagline.len);
strbuf_release(&tagline);
}
- strbuf_addf(&tagbuf, "\n# %s\n",
- origins.items[i].string);
+ strbuf_addch(&tagbuf, '\n');
+ strbuf_add_commented_lines(&tagbuf,
+ origins.items[i].string,
+ strlen(origins.items[i].string));
fmt_tag_signature(&tagbuf, &sig, buf, len);
}
strbuf_release(&sig);
strbuf_release(&line);
goto cleanup;
}
+
+ if (remote_head->util) {
+ struct merge_remote_desc *desc;
+ desc = merge_remote_util(remote_head);
+ if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
+ strbuf_addf(msg, "%s\t\t%s '%s'\n",
+ sha1_to_hex(desc->obj->sha1),
+ typename(desc->obj->type),
+ remote);
+ goto cleanup;
+ }
+ }
+
strbuf_addf(msg, "%s\t\tcommit '%s'\n",
sha1_to_hex(remote_head->object.sha1), remote);
cleanup:
: 0);
hdr_err = parse_pack_header(&hdr);
- if (hdr_err)
+ if (hdr_err) {
+ if (err_fd > 0)
+ close(err_fd);
return hdr_err;
+ }
snprintf(hdr_arg, sizeof(hdr_arg),
"--pack_header=%"PRIu32",%"PRIu32,
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
*/
static const char * const revert_usage[] = {
- N_("git revert [options] <commit-ish>"),
+ N_("git revert [options] <commit-ish>..."),
N_("git revert <subcommand>"),
NULL
};
static const char * const cherry_pick_usage[] = {
- N_("git cherry-pick [options] <commit-ish>"),
+ N_("git cherry-pick [options] <commit-ish>..."),
N_("git cherry-pick <subcommand>"),
NULL
};
nth = 0;
while (parents) {
struct commit *p = parents->item;
- char newname[1000], *en;
+ struct strbuf newname = STRBUF_INIT;
parents = parents->next;
nth++;
if (p->util)
continue;
- en = newname;
switch (n->generation) {
case 0:
- en += sprintf(en, "%s", n->head_name);
+ strbuf_addstr(&newname, n->head_name);
break;
case 1:
- en += sprintf(en, "%s^", n->head_name);
+ strbuf_addf(&newname, "%s^", n->head_name);
break;
default:
- en += sprintf(en, "%s~%d",
- n->head_name, n->generation);
+ strbuf_addf(&newname, "%s~%d",
+ n->head_name, n->generation);
break;
}
if (nth == 1)
- en += sprintf(en, "^");
+ strbuf_addch(&newname, '^');
else
- en += sprintf(en, "^%d", nth);
- name_commit(p, xstrdup(newname), 0);
+ strbuf_addf(&newname, "^%d", nth);
+ name_commit(p, strbuf_detach(&newname, NULL), 0);
i++;
name_first_parent_chain(p);
}
* followed by SP and subject line.
*/
if (get_sha1_hex(buf.buf, sha1) ||
- (40 <= buf.len && !isspace(buf.buf[40])) ||
+ (buf.len > 40 && !isspace(buf.buf[40])) ||
(!is_prereq && buf.len <= 40)) {
if (report_path)
error(_("unrecognized header: %s%s (%d)"),
#include "diffcore.h"
#include "quote.h"
#include "xdiff-interface.h"
+#include "xdiff/xmacros.h"
#include "log-tree.h"
#include "refs.h"
#include "userdiff.h"
return blob;
}
-static void append_lost(struct sline *sline, int n, const char *line, int len)
+static int match_string_spaces(const char *line1, int len1,
+ const char *line2, int len2,
+ long flags)
+{
+ if (flags & XDF_WHITESPACE_FLAGS) {
+ for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
+ for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
+ }
+
+ if (!(flags & (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE)))
+ return (len1 == len2 && !memcmp(line1, line2, len1));
+
+ while (len1 > 0 && len2 > 0) {
+ len1--;
+ len2--;
+ if (XDL_ISSPACE(line1[len1]) || XDL_ISSPACE(line2[len2])) {
+ if ((flags & XDF_IGNORE_WHITESPACE_CHANGE) &&
+ (!XDL_ISSPACE(line1[len1]) || !XDL_ISSPACE(line2[len2])))
+ return 0;
+
+ for (; len1 > 0 && XDL_ISSPACE(line1[len1]); len1--);
+ for (; len2 > 0 && XDL_ISSPACE(line2[len2]); len2--);
+ }
+ if (line1[len1] != line2[len2])
+ return 0;
+ }
+
+ if (flags & XDF_IGNORE_WHITESPACE) {
+ /* Consume remaining spaces */
+ for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
+ for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
+ }
+
+ /* We matched full line1 and line2 */
+ if (!len1 && !len2)
+ return 1;
+
+ return 0;
+}
+
+static void append_lost(struct sline *sline, int n, const char *line, int len, long flags)
{
struct lline *lline;
unsigned long this_mask = (1UL<<n);
if (sline->lost_head) {
lline = sline->next_lost;
while (lline) {
- if (lline->len == len &&
- !memcmp(lline->line, line, len)) {
+ if (match_string_spaces(lline->line, lline->len,
+ line, len, flags)) {
lline->parent_map |= this_mask;
sline->next_lost = lline->next;
return;
int n;
struct sline *sline;
struct sline *lost_bucket;
+ long flags;
};
static void consume_line(void *state_, char *line, unsigned long len)
return; /* not in any hunk yet */
switch (line[0]) {
case '-':
- append_lost(state->lost_bucket, state->n, line+1, len-1);
+ append_lost(state->lost_bucket, state->n, line+1, len-1, state->flags);
break;
case '+':
state->sline[state->lno-1].flag |= state->nmask;
struct sline *sline, unsigned int cnt, int n,
int num_parent, int result_deleted,
struct userdiff_driver *textconv,
- const char *path)
+ const char *path, long flags)
{
unsigned int p_lno, lno;
unsigned long nmask = (1UL << n);
parent_file.ptr = grab_blob(parent, mode, &sz, textconv, path);
parent_file.size = sz;
memset(&xpp, 0, sizeof(xpp));
- xpp.flags = 0;
+ xpp.flags = flags;
memset(&xecfg, 0, sizeof(xecfg));
memset(&state, 0, sizeof(state));
+ state.flags = flags;
state.nmask = nmask;
state.sline = sline;
state.lno = 1;
elem->parent[i].mode,
&result_file, sline,
cnt, i, num_parent, result_deleted,
- textconv, elem->path);
+ textconv, elem->path, opt->xdl_opts);
}
show_hunks = make_hunks(sline, cnt, num_parent, dense);
;;
esac
- case "$prev" in
- -c|-C)
- __gitcomp_nl "$(__git_refs)" "" "${cur}"
- return
- ;;
- esac
-
case "$cur" in
--cleanup=*)
__gitcomp "default strip verbatim whitespace
r="|MERGING"
elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
r="|CHERRY-PICKING"
+ elif [ -f "$g/REVERT_HEAD" ]; then
+ r="|REVERTING"
elif [ -f "$g/BISECT_LOG" ]; then
r="|BISECTING"
fi
[ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
[ -n "$(git ls-files --others --exclude-standard)" ]
then
- u="%"
+ u="%${ZSH_VERSION+%}"
fi
if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
else:
modified, removed = get_filechanges(repo, c, parents[0])
+ desc += '\n'
+
if mode == 'hg':
extra_msg = ''
else:
extra_msg += "extra : %s : %s\n" % (key, urllib.quote(value))
- desc += '\n'
if extra_msg:
desc += '\n--HG--\n' + extra_msg
) >> "$HOME"/.hgrc &&
git config --global remote-hg.hg-git-compat true
- export HGEDITOR=/usr/bin/true
-
- export GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230"
- export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
+ HGEDITOR=/usr/bin/true
+ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230"
+ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
+ export HGEDITOR GIT_AUTHOR_DATE GIT_COMMITTER_DATE
}
setup
git add alpha &&
git commit -m "add älphà " &&
- export GIT_AUTHOR_NAME="tést èncödîng" &&
+ GIT_AUTHOR_NAME="tést èncödîng" &&
+ export GIT_AUTHOR_NAME &&
echo beta > beta &&
git add beta &&
git commit -m "add beta" &&
git config --global receive.denycurrentbranch warn
git config --global remote-hg.hg-git-compat true
- export HGEDITOR=/usr/bin/true
+ HGEDITOR=/usr/bin/true
- export GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230"
- export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
+ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230"
+ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
+ export HGEDITOR GIT_AUTHOR_DATE GIT_COMMITTER_DATE
}
setup
git add alpha &&
git commit -m "add älphà " &&
- export GIT_AUTHOR_NAME="tést èncödîng" &&
+ GIT_AUTHOR_NAME="tést èncödîng" &&
+ export GIT_AUTHOR_NAME &&
echo beta > beta &&
git add beta &&
git commit -m "add beta" &&
options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
else if (!strcmp(arg, "--histogram"))
options->xdl_opts = DIFF_WITH_ALG(options, HISTOGRAM_DIFF);
- else if (!prefixcmp(arg, "--diff-algorithm=")) {
- long value = parse_algorithm_value(arg+17);
+ else if ((argcount = parse_long_opt("diff-algorithm", av, &optarg))) {
+ long value = parse_algorithm_value(optarg);
if (value < 0)
return error("option diff-algorithm accepts \"myers\", "
"\"minimal\", \"patience\" and \"histogram\"");
DIFF_XDL_CLR(options, NEED_MINIMAL);
options->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;
options->xdl_opts |= value;
+ return argcount;
}
/* flags options */
#include "xdiff-interface.h"
#include "kwset.h"
-typedef int (*pickaxe_fn)(struct diff_filepair *p, struct diff_options *o, regex_t *regexp, kwset_t kws);
+typedef int (*pickaxe_fn)(mmfile_t *one, mmfile_t *two,
+ struct diff_options *o,
+ regex_t *regexp, kwset_t kws);
+
+static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
+ regex_t *regexp, kwset_t kws, pickaxe_fn fn);
static void pickaxe(struct diff_queue_struct *q, struct diff_options *o,
regex_t *regexp, kwset_t kws, pickaxe_fn fn)
/* Showing the whole changeset if needle exists */
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
- if (fn(p, o, regexp, kws))
+ if (pickaxe_match(p, o, regexp, kws, fn))
return; /* do not munge the queue */
}
/* Showing only the filepairs that has the needle */
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
- if (fn(p, o, regexp, kws))
+ if (pickaxe_match(p, o, regexp, kws, fn))
diff_q(&outq, p);
else
diff_free_filepair(p);
line[len] = hold;
}
-static void fill_one(struct diff_filespec *one,
- mmfile_t *mf, struct userdiff_driver **textconv)
-{
- if (DIFF_FILE_VALID(one)) {
- *textconv = get_textconv(one);
- mf->size = fill_textconv(*textconv, one, &mf->ptr);
- } else {
- memset(mf, 0, sizeof(*mf));
- }
-}
-
-static int diff_grep(struct diff_filepair *p, struct diff_options *o,
+static int diff_grep(mmfile_t *one, mmfile_t *two,
+ struct diff_options *o,
regex_t *regexp, kwset_t kws)
{
regmatch_t regmatch;
- struct userdiff_driver *textconv_one = NULL;
- struct userdiff_driver *textconv_two = NULL;
- mmfile_t mf1, mf2;
- int hit;
+ struct diffgrep_cb ecbdata;
+ xpparam_t xpp;
+ xdemitconf_t xecfg;
- if (diff_unmodified_pair(p))
- return 0;
+ if (!one)
+ return !regexec(regexp, two->ptr, 1, ®match, 0);
+ if (!two)
+ return !regexec(regexp, one->ptr, 1, ®match, 0);
- fill_one(p->one, &mf1, &textconv_one);
- fill_one(p->two, &mf2, &textconv_two);
-
- if (!mf1.ptr) {
- if (!mf2.ptr)
- return 0; /* ignore unmerged */
- /* created "two" -- does it have what we are looking for? */
- hit = !regexec(regexp, mf2.ptr, 1, ®match, 0);
- } else if (!mf2.ptr) {
- /* removed "one" -- did it have what we are looking for? */
- hit = !regexec(regexp, mf1.ptr, 1, ®match, 0);
- } else {
- /*
- * We have both sides; need to run textual diff and see if
- * the pattern appears on added/deleted lines.
- */
- struct diffgrep_cb ecbdata;
- xpparam_t xpp;
- xdemitconf_t xecfg;
-
- memset(&xpp, 0, sizeof(xpp));
- memset(&xecfg, 0, sizeof(xecfg));
- ecbdata.regexp = regexp;
- ecbdata.hit = 0;
- xecfg.ctxlen = o->context;
- xecfg.interhunkctxlen = o->interhunkcontext;
- xdi_diff_outf(&mf1, &mf2, diffgrep_consume, &ecbdata,
- &xpp, &xecfg);
- hit = ecbdata.hit;
- }
- if (textconv_one)
- free(mf1.ptr);
- if (textconv_two)
- free(mf2.ptr);
- return hit;
+ /*
+ * We have both sides; need to run textual diff and see if
+ * the pattern appears on added/deleted lines.
+ */
+ memset(&xpp, 0, sizeof(xpp));
+ memset(&xecfg, 0, sizeof(xecfg));
+ ecbdata.regexp = regexp;
+ ecbdata.hit = 0;
+ xecfg.ctxlen = o->context;
+ xecfg.interhunkctxlen = o->interhunkcontext;
+ xdi_diff_outf(one, two, diffgrep_consume, &ecbdata,
+ &xpp, &xecfg);
+ return ecbdata.hit;
}
static void diffcore_pickaxe_grep(struct diff_options *o)
return cnt;
}
-static int has_changes(struct diff_filepair *p, struct diff_options *o,
+static int has_changes(mmfile_t *one, mmfile_t *two,
+ struct diff_options *o,
regex_t *regexp, kwset_t kws)
{
- struct userdiff_driver *textconv_one = get_textconv(p->one);
- struct userdiff_driver *textconv_two = get_textconv(p->two);
+ if (!one)
+ return contains(two, o, regexp, kws) != 0;
+ if (!two)
+ return contains(one, o, regexp, kws) != 0;
+ return contains(one, o, regexp, kws) != contains(two, o, regexp, kws);
+}
+
+static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
+ regex_t *regexp, kwset_t kws, pickaxe_fn fn)
+{
+ struct userdiff_driver *textconv_one = NULL;
+ struct userdiff_driver *textconv_two = NULL;
mmfile_t mf1, mf2;
int ret;
if (!o->pickaxe[0])
return 0;
+ /* ignore unmerged */
+ if (!DIFF_FILE_VALID(p->one) && !DIFF_FILE_VALID(p->two))
+ return 0;
+
+ if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {
+ textconv_one = get_textconv(p->one);
+ textconv_two = get_textconv(p->two);
+ }
+
/*
* If we have an unmodified pair, we know that the count will be the
* same and don't even have to load the blobs. Unless textconv is in
if (textconv_one == textconv_two && diff_unmodified_pair(p))
return 0;
- fill_one(p->one, &mf1, &textconv_one);
- fill_one(p->two, &mf2, &textconv_two);
+ mf1.size = fill_textconv(textconv_one, p->one, &mf1.ptr);
+ mf2.size = fill_textconv(textconv_two, p->two, &mf2.ptr);
- if (!mf1.ptr) {
- if (!mf2.ptr)
- ret = 0; /* ignore unmerged */
- /* created */
- ret = contains(&mf2, o, regexp, kws) != 0;
- }
- else if (!mf2.ptr) /* removed */
- ret = contains(&mf1, o, regexp, kws) != 0;
- else
- ret = contains(&mf1, o, regexp, kws) !=
- contains(&mf2, o, regexp, kws);
+ ret = fn(DIFF_FILE_VALID(p->one) ? &mf1 : NULL,
+ DIFF_FILE_VALID(p->two) ? &mf2 : NULL,
+ o, regexp, kws);
if (textconv_one)
free(mf1.ptr);
test -d "$tempdir" &&
die "$tempdir already exists, please remove it"
esac
+orig_dir=$(pwd)
mkdir -p "$tempdir/t" &&
tempdir="$(cd "$tempdir"; pwd)" &&
cd "$tempdir/t" &&
die ""
# Remove tempdir on exit
-trap 'cd ../..; rm -rf "$tempdir"' 0
+trap 'cd "$orig_dir"; rm -rf "$tempdir"' 0
ORIG_GIT_DIR="$GIT_DIR"
ORIG_GIT_WORK_TREE="$GIT_WORK_TREE"
done
fi
-cd ../..
+cd "$orig_dir"
rm -rf "$tempdir"
trap - 0
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"
+ eval="git-rebase $diffstat $strategy_args $merge_args $verbosity"
eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
;;
*)
for (p = opt->header_list; p; p = p->next) {
if (p->token != GREP_PATTERN_HEAD)
die("bug: a non-header pattern in grep header list.");
- if (p->field < 0 || GREP_HEADER_FIELD_MAX <= p->field)
+ if (p->field < GREP_HEADER_FIELD_MIN ||
+ GREP_HEADER_FIELD_MAX <= p->field)
die("bug: unknown header field %d", p->field);
compile_regexp(p, opt);
}
};
enum grep_header_field {
- GREP_HEADER_AUTHOR = 0,
+ GREP_HEADER_FIELD_MIN = 0,
+ GREP_HEADER_AUTHOR = GREP_HEADER_FIELD_MIN,
GREP_HEADER_COMMITTER,
GREP_HEADER_REFLOG,
int cmd_version(int argc, const char **argv, const char *prefix)
{
+ /*
+ * The format of this string should be kept stable for compatibility
+ * with external projects that rely on the output of "git version".
+ */
printf("git version %s\n", git_version_string);
return 0;
}
if (not defined $pid) {
throw Error::Simple("open failed: $!");
} elsif ($pid == 0) {
- if (defined $opts{STDERR}) {
- close STDERR;
- }
if ($opts{STDERR}) {
open (STDERR, '>&', $opts{STDERR})
or die "dup failed: $!";
+ } elsif (defined $opts{STDERR}) {
+ open (STDERR, '>', '/dev/null')
+ or die "opening /dev/null failed: $!";
}
_cmd_exec($self, $cmd, @args);
}
strbuf_addstr(sb, "?=");
}
+static const char *show_ident_date(const struct ident_split *ident,
+ enum date_mode mode)
+{
+ unsigned long date = 0;
+ int tz = 0;
+
+ if (ident->date_begin && ident->date_end)
+ date = strtoul(ident->date_begin, NULL, 10);
+ if (ident->tz_begin && ident->tz_end)
+ tz = strtol(ident->tz_begin, NULL, 10);
+ return show_date(date, tz, mode);
+}
+
void pp_user_info(const struct pretty_print_context *pp,
const char *what, struct strbuf *sb,
const char *line, const char *encoding)
struct strbuf mail;
struct ident_split ident;
int linelen;
- char *line_end, *date;
+ char *line_end;
const char *mailbuf, *namebuf;
size_t namelen, maillen;
int max_length = 78; /* per rfc2822 */
- unsigned long time;
- int tz;
if (pp->fmt == CMIT_FMT_ONELINE)
return;
strbuf_add(&name, namebuf, namelen);
namelen = name.len + mail.len + 3; /* ' ' + '<' + '>' */
- time = strtoul(ident.date_begin, &date, 10);
- tz = strtol(date, NULL, 10);
if (pp->fmt == CMIT_FMT_EMAIL) {
strbuf_addstr(sb, "From: ");
switch (pp->fmt) {
case CMIT_FMT_MEDIUM:
- strbuf_addf(sb, "Date: %s\n", show_date(time, tz, pp->date_mode));
+ strbuf_addf(sb, "Date: %s\n",
+ show_ident_date(&ident, pp->date_mode));
break;
case CMIT_FMT_EMAIL:
- strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
+ strbuf_addf(sb, "Date: %s\n",
+ show_ident_date(&ident, DATE_RFC2822));
break;
case CMIT_FMT_FULLER:
- strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, pp->date_mode));
+ strbuf_addf(sb, "%sDate: %s\n", what,
+ show_ident_date(&ident, pp->date_mode));
break;
default:
/* notin' */
{
/* currently all placeholders have same length */
const int placeholder_len = 2;
- int tz;
- unsigned long date = 0;
struct ident_split s;
const char *name, *mail;
size_t maillen, namelen;
if (!s.date_begin)
goto skip;
- date = strtoul(s.date_begin, NULL, 10);
-
if (part == 't') { /* date, UNIX timestamp */
strbuf_add(sb, s.date_begin, s.date_end - s.date_begin);
return placeholder_len;
}
- /* parse tz */
- tz = strtoul(s.tz_begin + 1, NULL, 10);
- if (*s.tz_begin == '-')
- tz = -tz;
-
switch (part) {
case 'd': /* date */
- strbuf_addstr(sb, show_date(date, tz, dmode));
+ strbuf_addstr(sb, show_ident_date(&s, dmode));
return placeholder_len;
case 'D': /* date, RFC2822 style */
- strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
+ strbuf_addstr(sb, show_ident_date(&s, DATE_RFC2822));
return placeholder_len;
case 'r': /* date, relative */
- strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE));
+ strbuf_addstr(sb, show_ident_date(&s, DATE_RELATIVE));
return placeholder_len;
case 'i': /* date, ISO 8601 */
- strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601));
+ strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601));
return placeholder_len;
}
strbuf_release(sb);
if (!io->input.len)
return -1;
- ep = strchrnul(io->input.buf, '\n');
- if (*ep == '\n')
+ ep = memchr(io->input.buf, '\n', io->input.len);
+ if (!ep)
+ ep = io->input.buf + io->input.len;
+ else if (*ep == '\n')
ep++;
len = ep - io->input.buf;
strbuf_add(sb, io->input.buf, len);
static int handle_cache(const char *path, unsigned char *sha1, const char *output)
{
- mmfile_t mmfile[3];
+ mmfile_t mmfile[3] = {{NULL}};
mmbuffer_t result = {NULL, 0};
struct cache_entry *ce;
int pos, len, i, hunk_no;
for (i = 0; i < 3; i++) {
enum object_type type;
unsigned long size;
+ int j;
- mmfile[i].size = 0;
- mmfile[i].ptr = NULL;
if (active_nr <= pos)
break;
ce = active_cache[pos++];
- if (ce_namelen(ce) != len || memcmp(ce->name, path, len)
- || ce_stage(ce) != i + 1)
- break;
- mmfile[i].ptr = read_sha1_file(ce->sha1, &type, &size);
- mmfile[i].size = size;
+ if (ce_namelen(ce) != len || memcmp(ce->name, path, len))
+ continue;
+ j = ce_stage(ce) - 1;
+ mmfile[j].ptr = read_sha1_file(ce->sha1, &type, &size);
+ mmfile[j].size = size;
}
for (i = 0; i < 3; i++) {
if (!mmfile[i].ptr && !mmfile[i].size)
<IfModule !mod_authz_user.c>
LoadModule authz_user_module modules/mod_authz_user.so
</IfModule>
+<IfModule !mod_authz_host.c>
+ LoadModule authz_host_module modules/mod_authz_host.so
+</IfModule>
</IfVersion>
PassEnv GIT_VALGRIND
Require valid-user
</LocationMatch>
+RewriteCond %{QUERY_STRING} service=git-receive-pack [OR]
+RewriteCond %{REQUEST_URI} /git-receive-pack$
+RewriteRule ^/half-auth-complete/ - [E=AUTHREQUIRED:yes]
+
+<Location /half-auth-complete/>
+ Order Deny,Allow
+ Deny from env=AUTHREQUIRED
+
+ AuthType Basic
+ AuthName "Git Access"
+ AuthUserFile passwd
+ Require valid-user
+ Satisfy Any
+</Location>
+
<IfDefine DAV>
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so
tag_description="This is a tag"
tag_content="$tag_header_without_timestamp 0000000000 +0000
-$tag_description"
-tag_pretty_content="$tag_header_without_timestamp Thu Jan 1 00:00:00 1970 +0000
-
$tag_description"
tag_sha1=$(echo_without_newline "$tag_content" | git mktag)
tag_size=$(strlen "$tag_content")
-run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_pretty_content" 1
+run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content" 1
test_expect_success \
"Reach a blob from a tag pointing to it" \
test_expect_success setup '
mkdir fi &&
+ printf "a\0a" >binary &&
+ git add binary &&
test_commit initial fi/le first &&
git branch side &&
git branch another &&
+ printf "a\0b" >binary &&
+ git add binary &&
test_commit second fi/le second &&
git checkout side &&
test_commit third fi/le third &&
+ git branch add-add &&
git checkout another &&
test_commit fourth fi/le fourth &&
+ git checkout add-add &&
+ test_commit fifth add-differently &&
git checkout master
'
test_cmp expect actual
'
+test_expect_success 'rerere forget (binary)' '
+ git checkout -f side &&
+ printf "a\0c" >binary &&
+ git commit -a -m binary &&
+ test_must_fail git merge second &&
+ git rerere forget binary
+'
+
+test_expect_success 'rerere forget (add-add conflict)' '
+ git checkout -f master &&
+ echo master >add-differently &&
+ git add add-differently &&
+ git commit -m "add differently" &&
+ test_must_fail git merge fifth &&
+ git rerere forget add-differently 2>actual &&
+ test_i18ngrep "no remembered" actual
+'
+
test_done
test_description='combined diff'
. ./test-lib.sh
+. "$TEST_DIRECTORY"/diff-lib.sh
setup_helper () {
one=$1 branch=$2 side=$3 &&
grep "^::::::::::::::::::::::::::::::::::::::::[^:]" out
'
+test_expect_success 'setup combined ignore spaces' '
+ git checkout master &&
+ >test &&
+ git add test &&
+ git commit -m initial &&
+
+ tr -d Q <<-\EOF >test &&
+ always coalesce
+ eol space coalesce Q
+ space change coalesce
+ all spa ces coalesce
+ eol spaces Q
+ space change
+ all spa ces
+ EOF
+ git commit -m "test space change" -a &&
+
+ git checkout -b side HEAD^ &&
+ tr -d Q <<-\EOF >test &&
+ always coalesce
+ eol space coalesce
+ space change coalesce
+ all spaces coalesce
+ eol spaces
+ space change
+ all spaces
+ EOF
+ git commit -m "test other space changes" -a &&
+
+ test_must_fail git merge master &&
+ tr -d Q <<-\EOF >test &&
+ eol spaces Q
+ space change
+ all spa ces
+ EOF
+ git commit -m merged -a
+'
+
+test_expect_success 'check combined output (no ignore space)' '
+ git show >actual.tmp &&
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
+ tr -d Q <<-\EOF >expected &&
+ --always coalesce
+ - eol space coalesce
+ - space change coalesce
+ - all spaces coalesce
+ - eol spaces
+ - space change
+ - all spaces
+ -eol space coalesce Q
+ -space change coalesce
+ -all spa ces coalesce
+ + eol spaces Q
+ + space change
+ + all spa ces
+ EOF
+ compare_diff_patch expected actual
+'
+
+test_expect_success 'check combined output (ignore space at eol)' '
+ git show --ignore-space-at-eol >actual.tmp &&
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
+ tr -d Q <<-\EOF >expected &&
+ --always coalesce
+ --eol space coalesce
+ - space change coalesce
+ - all spaces coalesce
+ -space change coalesce
+ -all spa ces coalesce
+ eol spaces Q
+ - space change
+ - all spaces
+ + space change
+ + all spa ces
+ EOF
+ compare_diff_patch expected actual
+'
+
+test_expect_success 'check combined output (ignore space change)' '
+ git show -b >actual.tmp &&
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
+ tr -d Q <<-\EOF >expected &&
+ --always coalesce
+ --eol space coalesce
+ --space change coalesce
+ - all spaces coalesce
+ -all spa ces coalesce
+ eol spaces Q
+ space change
+ - all spaces
+ + all spa ces
+ EOF
+ compare_diff_patch expected actual
+'
+
+test_expect_success 'check combined output (ignore all spaces)' '
+ git show -w >actual.tmp &&
+ sed -e "1,/^@@@/d" < actual.tmp >actual &&
+ tr -d Q <<-\EOF >expected &&
+ --always coalesce
+ --eol space coalesce
+ --space change coalesce
+ --all spaces coalesce
+ eol spaces Q
+ space change
+ all spa ces
+ EOF
+ compare_diff_patch expected actual
+'
+
test_done
test_cmp one expect
'
+test_expect_success 'whitespace=fix to expand' '
+ qz_to_tab_space >preimage <<-\EOF &&
+ QQa
+ QQb
+ QQc
+ ZZZZZZZZZZZZZZZZd
+ QQe
+ QQf
+ QQg
+ EOF
+ qz_to_tab_space >patch <<-\EOF &&
+ diff --git a/preimage b/preimage
+ --- a/preimage
+ +++ b/preimage
+ @@ -1,7 +1,6 @@
+ QQa
+ QQb
+ QQc
+ -QQd
+ QQe
+ QQf
+ QQg
+ EOF
+ git -c core.whitespace=tab-in-indent apply --whitespace=fix patch
+'
+
test_done
vero eos et accusam et justo duo dolores et ea rebum.
EOF
- q_to_tab <<-\EOF >>msg &&
+ qz_to_tab_space <<-\EOF >>msg &&
QDuis autem vel eum iriure dolor in hendrerit in vulputate velit
Qesse molestie consequat, vel illum dolore eu feugiat nulla facilisis
Qat vero eros et accumsan et iusto odio dignissim qui blandit
test_cmp expect actual
'
+test_expect_success 'log -G --textconv (missing textconv tool)' '
+ echo "* diff=test" >.gitattributes &&
+ test_must_fail git -c diff.test.textconv=missing log -Gfoo &&
+ rm .gitattributes
+'
+
+test_expect_success 'log -G --no-textconv (missing textconv tool)' '
+ echo "* diff=test" >.gitattributes &&
+ git -c diff.test.textconv=missing log -Gfoo --no-textconv >actual &&
+ >expect &&
+ test_cmp expect actual &&
+ rm .gitattributes
+'
+
test_expect_success 'log -S (nomatch)' '
git log -Spicked --format=%H >actual &&
>expect &&
test_cmp expect actual
'
+test_expect_success 'log -S --textconv (missing textconv tool)' '
+ echo "* diff=test" >.gitattributes &&
+ test_must_fail git -c diff.test.textconv=missing log -Sfoo &&
+ rm .gitattributes
+'
+
+test_expect_success 'log -S --no-textconv (missing textconv tool)' '
+ echo "* diff=test" >.gitattributes &&
+ git -c diff.test.textconv=missing log -Sfoo --no-textconv >actual &&
+ >expect &&
+ test_cmp expect actual &&
+ rm .gitattributes
+'
+
test_done
--- /dev/null
+#!/bin/sh
+
+test_description='git log with invalid commit headers'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit foo &&
+
+ git cat-file commit HEAD |
+ sed "/^author /s/>/>-<>/" >broken_email.commit &&
+ git hash-object -w -t commit broken_email.commit >broken_email.hash &&
+ git update-ref refs/heads/broken_email $(cat broken_email.hash)
+'
+
+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
+ echo " foo"
+ } >expect.out &&
+ : >expect.err &&
+
+ git log broken_email >actual.out 2>actual.err &&
+
+ test_cmp expect.out actual.out &&
+ test_cmp expect.err actual.err
+'
+
+test_expect_success 'git log --format with broken author email' '
+ echo "A U Thor+author@example.com+" >expect.out &&
+ : >expect.err &&
+
+ git log --format="%an+%ae+%ad" broken_email >actual.out 2>actual.err &&
+
+ test_cmp expect.out actual.out &&
+ test_cmp expect.err actual.err
+'
+
+test_done
}
test_expect_success 'tar archive of empty tree is empty' '
- git archive --format=tar HEAD >empty.tar &&
+ git archive --format=tar HEAD: >empty.tar &&
make_dir extract &&
"$TAR" xf empty.tar -C extract &&
check_dir extract
test ! -s out)
'
+test_expect_success 'git pull -q --rebase' '
+ mkdir clonedqrb &&
+ (cd clonedqrb && git init &&
+ git pull -q --rebase "../parent" >out 2>err &&
+ test ! -s err &&
+ test ! -s out &&
+ git pull -q --rebase "../parent" >out 2>err &&
+ test ! -s err &&
+ test ! -s out)
+'
+
test_expect_success 'git pull' '
mkdir cloned &&
(cd cloned && git init &&
test ! -s out)
'
+test_expect_success 'git pull --rebase' '
+ mkdir clonedrb &&
+ (cd clonedrb && git init &&
+ git pull --rebase "../parent" >out 2>err &&
+ test -s err &&
+ test ! -s out)
+'
+
test_expect_success 'git pull -v' '
mkdir clonedv &&
(cd clonedv && git init &&
test ! -s out)
'
+test_expect_success 'git pull -v --rebase' '
+ mkdir clonedvrb &&
+ (cd clonedvrb && git init &&
+ git pull -v --rebase "../parent" >out 2>err &&
+ test -s err &&
+ test ! -s out)
+'
+
test_expect_success 'git pull -v -q' '
mkdir clonedvq &&
(cd clonedvq && git init &&
test_cmp expect actual
'
+test_expect_success 'create repo without http.receivepack set' '
+ cd "$ROOT_PATH" &&
+ git init half-auth &&
+ (
+ cd half-auth &&
+ test_commit one
+ ) &&
+ git clone --bare half-auth "$HTTPD_DOCUMENT_ROOT_PATH/half-auth.git"
+'
+
+test_expect_success 'clone via half-auth-complete does not need password' '
+ cd "$ROOT_PATH" &&
+ set_askpass wrong &&
+ git clone "$HTTPD_URL"/half-auth-complete/smart/half-auth.git \
+ half-auth-clone &&
+ expect_askpass none
+'
+
+test_expect_success 'push into half-auth-complete requires password' '
+ cd "$ROOT_PATH/half-auth-clone" &&
+ echo two >expect &&
+ test_commit two &&
+ set_askpass user@host &&
+ git push "$HTTPD_URL/half-auth-complete/smart/half-auth.git" &&
+ git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/half-auth.git" \
+ log -1 --format=%s >actual &&
+ expect_askpass both user@host &&
+ test_cmp expect actual
+'
+
stop_httpd
test_done
grep "^-[0-9a-f]\\{40\\} " boundary
'
+test_expect_success 'prerequisites with an empty commit message' '
+ : >file1 &&
+ git add file1 &&
+ test_tick &&
+ git commit --allow-empty-message -m "" &&
+ test_commit file2 &&
+ git bundle create bundle HEAD^.. &&
+ git bundle verify bundle
+'
+
test_done
Common #1
EOF
- git config merge.log true &&
- test_might_fail git config --unset-all merge.summary &&
+ test_config merge.log true &&
+ test_unconfig merge.summary &&
git checkout master &&
test_tick &&
git fmt-merge-msg <.git/FETCH_HEAD >actual1 &&
- test_might_fail git config --unset-all merge.log &&
- git config merge.summary true &&
+ test_unconfig merge.log &&
+ test_config merge.summary true &&
git checkout master &&
test_tick &&
test_cmp expected actual2
'
-test_expect_success 'setup: clear [merge] configuration' '
- test_might_fail git config --unset-all merge.log &&
- test_might_fail git config --unset-all merge.summary
-'
-
test_expect_success 'setup FETCH_HEAD' '
git checkout master &&
test_tick &&
test_cmp expected actual
'
+test_expect_success '--log=5 with custom comment character' '
+ cat >expected <<-EOF &&
+ Merge branch ${apos}left${apos}
+
+ x By Another Author (3) and A U Thor (2)
+ x Via Another Committer
+ * left:
+ Left #5
+ Left #4
+ Left #3
+ Common #2
+ Common #1
+ EOF
+
+ git -c core.commentchar="x" fmt-merge-msg --log=5 <.git/FETCH_HEAD >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'merge.log=0 disables shortlog' '
echo "Merge branch ${apos}left${apos}" >expected
git -c merge.log=0 fmt-merge-msg <.git/FETCH_HEAD >actual &&
Common #1
EOF
- test_might_fail git config --unset merge.log &&
- test_might_fail git config --unset merge.summary &&
+ test_unconfig merge.log &&
+ test_unconfig merge.summary &&
git checkout master &&
git fetch "$(pwd)" left &&
git fmt-merge-msg -m "Sync with left" <.git/FETCH_HEAD >actual &&
git fmt-merge-msg --log -m "Sync with left" \
<.git/FETCH_HEAD >actual.log &&
- git config merge.log true &&
+ test_config merge.log true &&
git fmt-merge-msg -m "Sync with left" \
<.git/FETCH_HEAD >actual.log-config &&
git fmt-merge-msg --no-log -m "Sync with left" \
'
test_expect_success 'shortlog for two branches' '
- git config merge.log true &&
- test_might_fail git config --unset-all merge.summary &&
+ test_config merge.log true &&
+ test_unconfig merge.summary &&
git checkout master &&
test_tick &&
git fetch . left right &&
git fmt-merge-msg <.git/FETCH_HEAD >actual1 &&
- test_might_fail git config --unset-all merge.log &&
- git config merge.summary true &&
+ test_unconfig merge.log &&
+ test_config merge.summary true &&
git checkout master &&
test_tick &&
git fetch . left right &&
git fmt-merge-msg <.git/FETCH_HEAD >actual2 &&
- git config merge.log yes &&
- test_might_fail git config --unset-all merge.summary &&
+ test_config merge.log yes &&
+ test_unconfig merge.summary &&
git checkout master &&
test_tick &&
git fetch . left right &&
git fmt-merge-msg <.git/FETCH_HEAD >actual3 &&
- test_might_fail git config --unset-all merge.log &&
- git config merge.summary yes &&
+ test_unconfig merge.log &&
+ test_config merge.summary yes &&
git checkout master &&
test_tick &&
git fetch . left right &&
'
test_expect_success 'merge-msg -F' '
- test_might_fail git config --unset-all merge.log &&
- git config merge.summary yes &&
+ test_unconfig merge.log &&
+ test_config merge.summary yes &&
git checkout master &&
test_tick &&
git fetch . left right &&
'
test_expect_success 'merge-msg -F in subdirectory' '
- test_might_fail git config --unset-all merge.log &&
- git config merge.summary yes &&
+ test_unconfig merge.log &&
+ test_config merge.summary yes &&
git checkout master &&
test_tick &&
git fetch . left right &&
'
test_expect_success 'merge-msg with nothing to merge' '
- test_might_fail git config --unset-all merge.log &&
- git config merge.summary yes &&
+ test_unconfig merge.log &&
+ test_config merge.summary yes &&
>empty &&
Common #1
EOF
- test_might_fail git config --unset-all merge.log &&
- git config merge.summary yes &&
+ test_unconfig merge.log &&
+ test_config merge.summary yes &&
git checkout master &&
test_tick &&
Common #1
EOF
- test_might_fail git config --unset-all merge.log &&
- git config merge.summary yes &&
+ test_unconfig merge.log &&
+ test_config merge.summary yes &&
git checkout master &&
test_tick &&
Common #1
EOF
- test_might_fail git config --unset-all merge.log &&
- git config merge.summary yes &&
+ test_unconfig merge.log &&
+ test_config merge.summary yes &&
git checkout master &&
test_tick &&
echo " ..."
} >expected &&
+ test_config merge.summary yes &&
+
git checkout master &&
test_tick &&
git fetch . long &&
test_cmp expected actual
'
+test_expect_success 'merge-msg with "merging" an annotated tag' '
+ test_config merge.log true &&
+
+ git checkout master^0 &&
+ git commit --allow-empty -m "One step ahead" &&
+ git tag -a -m "An annotated one" annote HEAD &&
+
+ git checkout master &&
+ git fetch . annote &&
+
+ git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+ {
+ cat <<-\EOF
+ Merge tag '\''annote'\''
+
+ An annotated one
+
+ * tag '\''annote'\'':
+ One step ahead
+ EOF
+ } >expected &&
+ test_cmp expected actual &&
+
+ test_when_finished "git reset --hard" &&
+ annote=$(git rev-parse annote) &&
+ git merge --no-commit $annote &&
+ {
+ cat <<-EOF
+ Merge tag '\''$annote'\''
+
+ An annotated one
+
+ * tag '\''$annote'\'':
+ One step ahead
+ EOF
+ } >expected &&
+ test_cmp expected .git/MERGE_MSG
+'
+
test_done
grep drepo "$TRASHDIR/backup-refs"
'
+test_expect_success 'tree-filter works with -d' '
+ git init drepo-tree &&
+ (
+ cd drepo-tree &&
+ test_commit one &&
+ git filter-branch -d "$TRASHDIR/dfoo" \
+ --tree-filter "echo changed >one.t" &&
+ echo changed >expect &&
+ git cat-file blob HEAD:one.t >actual &&
+ test_cmp expect actual &&
+ test_cmp one.t actual
+ )
+'
+
test_expect_success 'Fail if commit filter fails' '
test_must_fail git filter-branch -f --commit-filter "exit 1" HEAD
'
mkdir home &&
(
cd home &&
- export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" &&
+ GIT_WORK_TREE="$(pwd)" &&
+ GIT_DIR="$(pwd)/.dotfiles" &&
+ export GIT_WORK_TREE GIT_DIR &&
git clone --bare ../remote .dotfiles &&
git submodule add ../bundle1 .vim/bundle/sogood &&
test_commit "sogood" &&
(
cd home2 &&
git clone --bare ../remote .dotfiles &&
- export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" &&
+ GIT_WORK_TREE="$(pwd)" &&
+ GIT_DIR="$(pwd)/.dotfiles" &&
+ export GIT_WORK_TREE GIT_DIR &&
git checkout master &&
git submodule update --init &&
(
mkdir home3 &&
(
cd home3 &&
- export GIT_DIR="$(pwd)/.dotfiles" &&
+ GIT_DIR="$(pwd)/.dotfiles" &&
+ export GIT_DIR &&
git clone --bare ../remote "$GIT_DIR" &&
git config core.bare false &&
git config core.worktree .. &&
) &&
(
cd home &&
- export GIT_DIR="$(pwd)/.dotfiles" &&
+ GIT_DIR="$(pwd)/.dotfiles" &&
+ export GIT_DIR &&
git config core.bare false &&
git config core.worktree .. &&
git pull &&
'
test_expect_success REMOTE_SVN 'incremental imports must lead to the same head' '
- export SVNRMAX=3 &&
+ SVNRMAX=3 &&
+ export SVNRMAX &&
init_git &&
git fetch svnsim &&
test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master &&
test_debug 'cat gitweb.headers'
test_expect_success DATE_PARSER 'modification: feed if-modified-since (modified)' '
- export HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" &&
+ HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" &&
+ export HTTP_IF_MODIFIED_SINCE &&
test_when_finished "unset HTTP_IF_MODIFIED_SINCE" &&
gitweb_run "p=.git;a=atom;h=master" &&
grep "Status: 200 OK" gitweb.headers
test_debug 'cat gitweb.headers'
test_expect_success DATE_PARSER 'modification: feed if-modified-since (unmodified)' '
- export HTTP_IF_MODIFIED_SINCE="Thu, 7 Apr 2005 22:14:13 +0000" &&
+ HTTP_IF_MODIFIED_SINCE="Thu, 7 Apr 2005 22:14:13 +0000" &&
+ export HTTP_IF_MODIFIED_SINCE &&
test_when_finished "unset HTTP_IF_MODIFIED_SINCE" &&
gitweb_run "p=.git;a=atom;h=master" &&
grep "Status: 304 Not Modified" gitweb.headers
test_debug 'cat gitweb.headers'
test_expect_success DATE_PARSER 'modification: snapshot if-modified-since (modified)' '
- export HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" &&
+ HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" &&
+ export HTTP_IF_MODIFIED_SINCE &&
test_when_finished "unset HTTP_IF_MODIFIED_SINCE" &&
gitweb_run "p=.git;a=snapshot;h=master;sf=tgz" &&
grep "Status: 200 OK" gitweb.headers
test_debug 'cat gitweb.headers'
test_expect_success DATE_PARSER 'modification: snapshot if-modified-since (unmodified)' '
- export HTTP_IF_MODIFIED_SINCE="Thu, 7 Apr 2005 22:14:13 +0000" &&
+ HTTP_IF_MODIFIED_SINCE="Thu, 7 Apr 2005 22:14:13 +0000" &&
+ export HTTP_IF_MODIFIED_SINCE &&
test_when_finished "unset HTTP_IF_MODIFIED_SINCE" &&
gitweb_run "p=.git;a=snapshot;h=master;sf=tgz" &&
grep "Status: 304 Not Modified" gitweb.headers
test_expect_success DATE_PARSER 'modification: tree snapshot' '
ID=`git rev-parse --verify HEAD^{tree}` &&
- export HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" &&
+ HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" &&
+ export HTTP_IF_MODIFIED_SINCE &&
test_when_finished "unset HTTP_IF_MODIFIED_SINCE" &&
gitweb_run "p=.git;a=snapshot;h=$ID;sf=tgz" &&
grep "Status: 200 OK" gitweb.headers &&
# Failure cases for config:
# Save and restore STDERR; we will probably extract this into a
# "dies_ok" method and possibly move the STDERR handling to Git.pm.
-open our $tmpstderr, ">&STDERR" or die "cannot save STDERR"; close STDERR;
+open our $tmpstderr, ">&STDERR" or die "cannot save STDERR";
+open STDERR, ">", "/dev/null" or die "cannot redirect STDERR to /dev/null";
is($r->config("test.dupstring"), "value2", "config: multivar");
eval { $r->config_bool("test.boolother") };
ok($@, "config_bool: non-boolean values fail");
tr Q '\011'
}
+qz_to_tab_space () {
+ tr QZ '\011\040'
+}
+
append_cr () {
sed -e 's/$/Q/' | tr Q '\015'
}
fi
# Test repository
-test="trash directory.$(basename "$0" .sh)"
-test -n "$root" && test="$root/$test"
-case "$test" in
-/*) TRASH_DIRECTORY="$test" ;;
- *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$test" ;;
+TRASH_DIRECTORY="trash directory.$(basename "$0" .sh)"
+test -n "$root" && TRASH_DIRECTORY="$root/$TRASH_DIRECTORY"
+case "$TRASH_DIRECTORY" in
+/*) ;; # absolute path is good
+ *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$TRASH_DIRECTORY" ;;
esac
test ! -z "$debug" || remove_trash=$TRASH_DIRECTORY
-rm -fr "$test" || {
+rm -fr "$TRASH_DIRECTORY" || {
GIT_EXIT_OK=t
echo >&5 "FATAL: Cannot prepare test area"
exit 1
if test -z "$TEST_NO_CREATE_REPO"
then
- test_create_repo "$test"
+ test_create_repo "$TRASH_DIRECTORY"
else
- mkdir -p "$test"
+ mkdir -p "$TRASH_DIRECTORY"
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 "$test" || exit 1
+cd -P "$TRASH_DIRECTORY" || exit 1
this_test=${0##*/}
this_test=${this_test%%-*}