Compare commits
76 Commits
Author | SHA1 | Date | |
---|---|---|---|
0b3dcfe721 | |||
d16a5dafdc | |||
11f54989da | |||
476386858c | |||
a3cfb7f83f | |||
dddfb3f126 | |||
b6c7c41b17 | |||
8fe5d87622 | |||
730b020030 | |||
8da61a2ab4 | |||
aac1d7b889 | |||
e9bd323510 | |||
c40d92e4c7 | |||
0d12e59f63 | |||
7d182f52f1 | |||
d23e7570a7 | |||
7325283987 | |||
71928f7f11 | |||
8fcaca3ff2 | |||
8ca7880356 | |||
34b383e7cd | |||
00fb3d214c | |||
4a2284b999 | |||
7ff8b790bb | |||
6eb3adff9e | |||
990169b9b1 | |||
bd08ecc487 | |||
030bc0aa8b | |||
193c7aaf5f | |||
57c118c268 | |||
2dd96ea21f | |||
162b4643b6 | |||
919451330b | |||
493e433277 | |||
6ae611fa8d | |||
1f54d693fd | |||
89cd4aa862 | |||
4ac23f375f | |||
c214f2c80c | |||
8499da0476 | |||
47b333f759 | |||
b7380fa7a9 | |||
cb16bcc369 | |||
11a1a49a16 | |||
7b576f9910 | |||
7f43e75adc | |||
90ff12a860 | |||
4a9f439415 | |||
cbf731ed4e | |||
2e48fcdbc4 | |||
ec2537beda | |||
bfb8306de5 | |||
04416018a7 | |||
1f80c2afb0 | |||
18879bc526 | |||
5ce9086ddf | |||
74ae14199d | |||
7d750f0ea5 | |||
94c8ccaaba | |||
48a7c1c49d | |||
3909f14f62 | |||
e6cc51046f | |||
db03b55781 | |||
bba5322a71 | |||
13e65fe631 | |||
e1327ed5fb | |||
5256b00631 | |||
1d9740cb32 | |||
f80c7ae8fe | |||
b862b61c03 | |||
00787ed55a | |||
7aba6185d5 | |||
21da426214 | |||
470b452628 | |||
13be3e31f1 | |||
80235ba79e |
1
.mailmap
1
.mailmap
@ -36,6 +36,7 @@ Li Hong <leehong@pku.edu.cn>
|
||||
Lukas Sandström <lukass@etek.chalmers.se>
|
||||
Martin Langhoff <martin@catalyst.net.nz>
|
||||
Michael Coleman <tutufan@gmail.com>
|
||||
Michael J Gruber <git@drmicha.warpmail.net> <michaeljgruber+gmane@fastmail.fm>
|
||||
Michael W. Olson <mwolson@gnu.org>
|
||||
Michele Ballabio <barra_cuda@katamail.com>
|
||||
Nanako Shiraishi <nanako3@bluebottle.com>
|
||||
|
34
Documentation/RelNotes-1.7.0.3.txt
Normal file
34
Documentation/RelNotes-1.7.0.3.txt
Normal file
@ -0,0 +1,34 @@
|
||||
Git v1.7.0.3 Release Notes
|
||||
==========================
|
||||
|
||||
Fixes since v1.7.0.2
|
||||
--------------------
|
||||
|
||||
* Object files are created in a more ACL friendly way in repositories
|
||||
where group permission is ACL controlled.
|
||||
|
||||
* "git add -i" didn't handle a deleted path very well.
|
||||
|
||||
* "git blame" padded line numbers with one extra SP when the total number
|
||||
of lines was one less than multiple of ten due to an off-by-one error.
|
||||
|
||||
* "git fetch --all/--multi" used to discard information for remotes that
|
||||
are fetched earlier.
|
||||
|
||||
* "git log --author=me --grep=it" tried to find commits that have "it"
|
||||
or are written by "me", instead of the ones that have "it" _and_ are
|
||||
written by "me".
|
||||
|
||||
* "git log -g branch" misbehaved when there was no entries in the reflog
|
||||
for the named branch.
|
||||
|
||||
* "git mailinfo" (hence "git am") incorrectly removed initial indent from
|
||||
paragraphs.
|
||||
|
||||
* "git prune" and "git reflog" (hence "git gc" as well) didn't honor
|
||||
an instruction never to expire by setting gc.reflogexpire to never.
|
||||
|
||||
* "git push" misbehaved when branch.<name>.merge was configured without
|
||||
matching branch.<name>.remote.
|
||||
|
||||
And other minor fixes and documentation updates.
|
@ -138,6 +138,11 @@ advice.*::
|
||||
Advice on how to set your identity configuration when
|
||||
your information is guessed from the system username and
|
||||
domain name. Default: true.
|
||||
|
||||
detachedHead::
|
||||
Advice shown when you used linkgit::git-checkout[1] to
|
||||
move to the detach HEAD state, to instruct how to create
|
||||
a local branch after the fact. Default: true.
|
||||
--
|
||||
|
||||
core.fileMode::
|
||||
@ -1437,7 +1442,7 @@ receive.denyCurrentBranch::
|
||||
out of sync with the index and working tree. If set to "warn",
|
||||
print a warning of such a push to stderr, but allow the push to
|
||||
proceed. If set to false or "ignore", allow such pushes with no
|
||||
message. Defaults to "warn".
|
||||
message. Defaults to "refuse".
|
||||
|
||||
receive.denyNonFastForwards::
|
||||
If set to true, git-receive-pack will deny a ref update which is
|
||||
|
@ -187,7 +187,7 @@ include::urls.txt[]
|
||||
Examples
|
||||
--------
|
||||
|
||||
Clone from upstream::
|
||||
* Clone from upstream:
|
||||
+
|
||||
------------
|
||||
$ git clone git://git.kernel.org/pub/scm/.../linux-2.6 my2.6
|
||||
@ -196,7 +196,7 @@ $ make
|
||||
------------
|
||||
|
||||
|
||||
Make a local clone that borrows from the current directory, without checking things out::
|
||||
* Make a local clone that borrows from the current directory, without checking things out:
|
||||
+
|
||||
------------
|
||||
$ git clone -l -s -n . ../copy
|
||||
@ -205,7 +205,7 @@ $ git show-branch
|
||||
------------
|
||||
|
||||
|
||||
Clone from upstream while borrowing from an existing local directory::
|
||||
* Clone from upstream while borrowing from an existing local directory:
|
||||
+
|
||||
------------
|
||||
$ git clone --reference my2.6 \
|
||||
@ -215,14 +215,14 @@ $ cd my2.7
|
||||
------------
|
||||
|
||||
|
||||
Create a bare repository to publish your changes to the public::
|
||||
* Create a bare repository to publish your changes to the public:
|
||||
+
|
||||
------------
|
||||
$ git clone --bare -l /home/proj/.git /pub/scm/proj.git
|
||||
------------
|
||||
|
||||
|
||||
Create a repository on the kernel.org machine that borrows from Linus::
|
||||
* Create a repository on the kernel.org machine that borrows from Linus:
|
||||
+
|
||||
------------
|
||||
$ git clone --bare -l -s /pub/scm/.../torvalds/linux-2.6.git \
|
||||
|
@ -9,8 +9,7 @@ git-grep - Print lines matching a pattern
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git grep' [--cached]
|
||||
[-a | --text] [-I] [-i | --ignore-case] [-w | --word-regexp]
|
||||
'git grep' [-a | --text] [-I] [-i | --ignore-case] [-w | --word-regexp]
|
||||
[-v | --invert-match] [-h|-H] [--full-name]
|
||||
[-E | --extended-regexp] [-G | --basic-regexp]
|
||||
[-F | --fixed-strings] [-n]
|
||||
@ -21,7 +20,8 @@ SYNOPSIS
|
||||
[--color | --no-color]
|
||||
[-A <post-context>] [-B <pre-context>] [-C <context>]
|
||||
[-f <file>] [-e] <pattern>
|
||||
[--and|--or|--not|(|)|-e <pattern>...] [<tree>...]
|
||||
[--and|--or|--not|(|)|-e <pattern>...]
|
||||
[--cached | --no-index | <tree>...]
|
||||
[--] [<pathspec>...]
|
||||
|
||||
DESCRIPTION
|
||||
@ -33,8 +33,11 @@ registered in the index file, or blobs in given tree objects.
|
||||
OPTIONS
|
||||
-------
|
||||
--cached::
|
||||
Instead of searching in the working tree files, check
|
||||
the blobs registered in the index file.
|
||||
Instead of searching tracked files in the working tree, search
|
||||
blobs registered in the index file.
|
||||
|
||||
--no-index::
|
||||
Search files in the current directory, not just those tracked by git.
|
||||
|
||||
-a::
|
||||
--text::
|
||||
@ -98,8 +101,8 @@ OPTIONS
|
||||
--files-without-match::
|
||||
Instead of showing every matched line, show only the
|
||||
names of files that contain (or do not contain) matches.
|
||||
For better compatibility with 'git diff', --name-only is a
|
||||
synonym for --files-with-matches.
|
||||
For better compatibility with 'git diff', `--name-only` is a
|
||||
synonym for `--files-with-matches`.
|
||||
|
||||
-z::
|
||||
--null::
|
||||
@ -125,7 +128,7 @@ OPTIONS
|
||||
matches.
|
||||
|
||||
-<num>::
|
||||
A shortcut for specifying -C<num>.
|
||||
A shortcut for specifying `-C<num>`.
|
||||
|
||||
-p::
|
||||
--show-function::
|
||||
@ -140,7 +143,7 @@ OPTIONS
|
||||
|
||||
-e::
|
||||
The next parameter is the pattern. This option has to be
|
||||
used for patterns starting with - and should be used in
|
||||
used for patterns starting with `-` and should be used in
|
||||
scripts passing user input to grep. Multiple patterns are
|
||||
combined by 'or'.
|
||||
|
||||
@ -163,8 +166,9 @@ OPTIONS
|
||||
Do not output matched lines; instead, exit with status 0 when
|
||||
there is a match and with non-zero status when there isn't.
|
||||
|
||||
`<tree>...`::
|
||||
Search blobs in the trees for specified patterns.
|
||||
<tree>...::
|
||||
Instead of searching tracked files in the working tree, search
|
||||
blobs in the given trees.
|
||||
|
||||
\--::
|
||||
Signals the end of options; the rest of the parameters
|
||||
@ -174,8 +178,8 @@ OPTIONS
|
||||
If given, limit the search to paths matching at least one pattern.
|
||||
Both leading paths match and glob(7) patterns are supported.
|
||||
|
||||
Example
|
||||
-------
|
||||
Examples
|
||||
--------
|
||||
|
||||
git grep 'time_t' -- '*.[ch]'::
|
||||
Looks for `time_t` in all tracked .c and .h files in the working
|
||||
|
@ -115,18 +115,17 @@ base-name::
|
||||
|
||||
--honor-pack-keep::
|
||||
This flag causes an object already in a local pack that
|
||||
has a .keep file to be ignored, even if it appears in the
|
||||
standard input.
|
||||
has a .keep file to be ignored, even if it it would have
|
||||
otherwise been packed.
|
||||
|
||||
--incremental::
|
||||
This flag causes an object already in a pack ignored
|
||||
even if it appears in the standard input.
|
||||
This flag causes an object already in a pack to be ignored
|
||||
even if it would have otherwise been packed.
|
||||
|
||||
--local::
|
||||
This flag is similar to `--incremental`; instead of
|
||||
ignoring all packed objects, it only ignores objects
|
||||
that are packed and/or not in the local object store
|
||||
(i.e. borrowed from an alternate).
|
||||
This flag causes an object that is borrowed from an alternate
|
||||
object store to be ignored even if it would have otherwise been
|
||||
packed.
|
||||
|
||||
--non-empty::
|
||||
Only create a packed archive if it would contain at
|
||||
|
@ -130,7 +130,7 @@ Single Tree Merge
|
||||
~~~~~~~~~~~~~~~~~
|
||||
If only 1 tree is specified, 'git read-tree' operates as if the user did not
|
||||
specify `-m`, except that if the original index has an entry for a
|
||||
given pathname, and the contents of the path matches with the tree
|
||||
given pathname, and the contents of the path match with the tree
|
||||
being read, the stat info from the index is used. (In other words, the
|
||||
index's stat()s take precedence over the merged tree's).
|
||||
|
||||
@ -154,40 +154,42 @@ When two trees are specified, the user is telling 'git read-tree'
|
||||
the following:
|
||||
|
||||
1. The current index and work tree is derived from $H, but
|
||||
the user may have local changes in them since $H;
|
||||
the user may have local changes in them since $H.
|
||||
|
||||
2. The user wants to fast-forward to $M.
|
||||
|
||||
In this case, the `git read-tree -m $H $M` command makes sure
|
||||
that no local change is lost as the result of this "merge".
|
||||
Here are the "carry forward" rules:
|
||||
Here are the "carry forward" rules, where "I" denotes the index,
|
||||
"clean" means that index and work tree coincide, and "exists"/"nothing"
|
||||
refer to the presence of a path in the specified commit:
|
||||
|
||||
I (index) H M Result
|
||||
I H M Result
|
||||
-------------------------------------------------------
|
||||
0 nothing nothing nothing (does not happen)
|
||||
1 nothing nothing exists use M
|
||||
2 nothing exists nothing remove path from index
|
||||
3 nothing exists exists, use M if "initial checkout"
|
||||
0 nothing nothing nothing (does not happen)
|
||||
1 nothing nothing exists use M
|
||||
2 nothing exists nothing remove path from index
|
||||
3 nothing exists exists, use M if "initial checkout",
|
||||
H == M keep index otherwise
|
||||
exists fail
|
||||
exists, fail
|
||||
H != M
|
||||
|
||||
clean I==H I==M
|
||||
------------------
|
||||
4 yes N/A N/A nothing nothing keep index
|
||||
5 no N/A N/A nothing nothing keep index
|
||||
4 yes N/A N/A nothing nothing keep index
|
||||
5 no N/A N/A nothing nothing keep index
|
||||
|
||||
6 yes N/A yes nothing exists keep index
|
||||
7 no N/A yes nothing exists keep index
|
||||
8 yes N/A no nothing exists fail
|
||||
9 no N/A no nothing exists fail
|
||||
6 yes N/A yes nothing exists keep index
|
||||
7 no N/A yes nothing exists keep index
|
||||
8 yes N/A no nothing exists fail
|
||||
9 no N/A no nothing exists fail
|
||||
|
||||
10 yes yes N/A exists nothing remove path from index
|
||||
11 no yes N/A exists nothing fail
|
||||
12 yes no N/A exists nothing fail
|
||||
13 no no N/A exists nothing fail
|
||||
|
||||
clean (H=M)
|
||||
clean (H==M)
|
||||
------
|
||||
14 yes exists exists keep index
|
||||
15 no exists exists keep index
|
||||
@ -202,26 +204,26 @@ Here are the "carry forward" rules:
|
||||
21 no yes no exists exists fail
|
||||
|
||||
In all "keep index" cases, the index entry stays as in the
|
||||
original index file. If the entry were not up to date,
|
||||
original index file. If the entry is not up to date,
|
||||
'git read-tree' keeps the copy in the work tree intact when
|
||||
operating under the -u flag.
|
||||
|
||||
When this form of 'git read-tree' returns successfully, you can
|
||||
see what "local changes" you made are carried forward by running
|
||||
see which of the "local changes" that you made were carried forward by running
|
||||
`git diff-index --cached $M`. Note that this does not
|
||||
necessarily match `git diff-index --cached $H` would have
|
||||
necessarily match what `git diff-index --cached $H` would have
|
||||
produced before such a two tree merge. This is because of cases
|
||||
18 and 19 --- if you already had the changes in $M (e.g. maybe
|
||||
you picked it up via e-mail in a patch form), `git diff-index
|
||||
--cached $H` would have told you about the change before this
|
||||
merge, but it would not show in `git diff-index --cached $M`
|
||||
output after two-tree merge.
|
||||
output after the two-tree merge.
|
||||
|
||||
Case #3 is slightly tricky and needs explanation. The result from this
|
||||
Case 3 is slightly tricky and needs explanation. The result from this
|
||||
rule logically should be to remove the path if the user staged the removal
|
||||
of the path and then switching to a new branch. That however will prevent
|
||||
the initial checkout from happening, so the rule is modified to use M (new
|
||||
tree) only when the contents of the index is empty. Otherwise the removal
|
||||
tree) only when the content of the index is empty. Otherwise the removal
|
||||
of the path is kept as long as $H and $M are the same.
|
||||
|
||||
3-Way Merge
|
||||
|
@ -18,9 +18,7 @@ depending on the subcommand:
|
||||
[verse]
|
||||
'git reflog expire' [--dry-run] [--stale-fix] [--verbose]
|
||||
[--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...
|
||||
+
|
||||
'git reflog delete' ref@\{specifier\}...
|
||||
+
|
||||
'git reflog' ['show'] [log-options] [<ref>]
|
||||
|
||||
Reflog is a mechanism to record when the tip of branches are
|
||||
|
@ -148,6 +148,12 @@ shown. If the pattern does not contain a globbing character (`?`,
|
||||
--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.
|
||||
|
||||
--short::
|
||||
--short=number::
|
||||
Instead of outputting the full SHA1 values of object names try to
|
||||
|
@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master'
|
||||
branch of the `git.git` repository.
|
||||
Documentation for older releases are available here:
|
||||
|
||||
* link:v1.7.0.2/git.html[documentation for release 1.7.0.2]
|
||||
* link:v1.7.0.3/git.html[documentation for release 1.7.0.3]
|
||||
|
||||
* release notes for
|
||||
link:RelNotes-1.7.0.3.txt[1.7.0.3],
|
||||
link:RelNotes-1.7.0.2.txt[1.7.0.2],
|
||||
link:RelNotes-1.7.0.1.txt[1.7.0.1],
|
||||
link:RelNotes-1.7.0.txt[1.7.0].
|
||||
|
@ -3,7 +3,7 @@ gitdiffcore(7)
|
||||
|
||||
NAME
|
||||
----
|
||||
gitdiffcore - Tweaking diff output (June 2005)
|
||||
gitdiffcore - Tweaking diff output
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
|
@ -4,7 +4,6 @@ GIT URLS[[URLS]]
|
||||
One of the following notations can be used
|
||||
to name the remote repository:
|
||||
|
||||
===============================================================
|
||||
- rsync://host.xz/path/to/repo.git/
|
||||
- http://host.xz{startsb}:port{endsb}/path/to/repo.git/
|
||||
- https://host.xz{startsb}:port{endsb}/path/to/repo.git/
|
||||
@ -14,7 +13,6 @@ to name the remote repository:
|
||||
- ssh://{startsb}user@{endsb}host.xz/path/to/repo.git/
|
||||
- ssh://{startsb}user@{endsb}host.xz/~user/path/to/repo.git/
|
||||
- ssh://{startsb}user@{endsb}host.xz/~/path/to/repo.git
|
||||
===============================================================
|
||||
|
||||
SSH is the default transport protocol over the network. You can
|
||||
optionally specify which user to log-in as, and an alternate,
|
||||
@ -23,18 +21,14 @@ username expansion, as does the native git protocol, but
|
||||
only the former supports port specification. The following
|
||||
three are identical to the last three above, respectively:
|
||||
|
||||
===============================================================
|
||||
- {startsb}user@{endsb}host.xz:/path/to/repo.git/
|
||||
- {startsb}user@{endsb}host.xz:~user/path/to/repo.git/
|
||||
- {startsb}user@{endsb}host.xz:path/to/repo.git
|
||||
===============================================================
|
||||
|
||||
To sync with a local directory, you can use:
|
||||
|
||||
===============================================================
|
||||
- /path/to/repo.git/
|
||||
- file:///path/to/repo.git/
|
||||
===============================================================
|
||||
|
||||
ifndef::git-clone[]
|
||||
They are mostly equivalent, except when cloning. See
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.7.0.2
|
||||
DEF_VER=v1.7.0.3
|
||||
|
||||
LF='
|
||||
'
|
||||
|
7
Makefile
7
Makefile
@ -317,6 +317,12 @@ SCRIPT_PYTHON =
|
||||
SCRIPT_SH =
|
||||
TEST_PROGRAMS =
|
||||
|
||||
# Having this variable in your environment would break pipelines because
|
||||
# you cause "cd" to echo its destination to stdout. It can also take
|
||||
# scripts to unexpected places. If you like CDPATH, define it for your
|
||||
# interactive shell sessions without exporting it.
|
||||
unexport CDPATH
|
||||
|
||||
SCRIPT_SH += git-am.sh
|
||||
SCRIPT_SH += git-bisect.sh
|
||||
SCRIPT_SH += git-difftool--helper.sh
|
||||
@ -1200,7 +1206,6 @@ ifdef NO_MKDTEMP
|
||||
endif
|
||||
ifdef NO_MKSTEMPS
|
||||
COMPAT_CFLAGS += -DNO_MKSTEMPS
|
||||
COMPAT_OBJS += compat/mkstemps.o
|
||||
endif
|
||||
ifdef NO_UNSETENV
|
||||
COMPAT_CFLAGS += -DNO_UNSETENV
|
||||
|
2
RelNotes
2
RelNotes
@ -1 +1 @@
|
||||
Documentation/RelNotes-1.7.0.2.txt
|
||||
Documentation/RelNotes-1.7.0.3.txt
|
2
advice.c
2
advice.c
@ -5,6 +5,7 @@ int advice_status_hints = 1;
|
||||
int advice_commit_before_merge = 1;
|
||||
int advice_resolve_conflict = 1;
|
||||
int advice_implicit_identity = 1;
|
||||
int advice_detached_head = 1;
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
@ -15,6 +16,7 @@ static struct {
|
||||
{ "commitbeforemerge", &advice_commit_before_merge },
|
||||
{ "resolveconflict", &advice_resolve_conflict },
|
||||
{ "implicitidentity", &advice_implicit_identity },
|
||||
{ "detachedhead", &advice_detached_head },
|
||||
};
|
||||
|
||||
int git_default_advice_config(const char *var, const char *value)
|
||||
|
1
advice.h
1
advice.h
@ -8,6 +8,7 @@ extern int advice_status_hints;
|
||||
extern int advice_commit_before_merge;
|
||||
extern int advice_resolve_conflict;
|
||||
extern int advice_implicit_identity;
|
||||
extern int advice_detached_head;
|
||||
|
||||
int git_default_advice_config(const char *var, const char *value);
|
||||
|
||||
|
@ -1772,7 +1772,7 @@ static int lineno_width(int lines)
|
||||
{
|
||||
int i, width;
|
||||
|
||||
for (width = 1, i = 10; i <= lines + 1; width++)
|
||||
for (width = 1, i = 10; i <= lines; width++)
|
||||
i *= 10;
|
||||
return width;
|
||||
}
|
||||
|
@ -488,6 +488,20 @@ static void report_tracking(struct branch_info *new)
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
static void detach_advice(const char *old_path, const char *new_name)
|
||||
{
|
||||
const char fmt[] =
|
||||
"Note: checking out '%s'.\n\n"
|
||||
"You are in 'detached HEAD' state. You can look around, make experimental\n"
|
||||
"changes and commit them, and you can discard any commits you make in this\n"
|
||||
"state without impacting any branches by performing another checkout.\n\n"
|
||||
"If you want to create a new branch to retain commits you create, you may\n"
|
||||
"do so (now or later) by using -b with the checkout command again. Example:\n\n"
|
||||
" git checkout -b new_branch_name\n\n";
|
||||
|
||||
fprintf(stderr, fmt, new_name);
|
||||
}
|
||||
|
||||
static void update_refs_for_switch(struct checkout_opts *opts,
|
||||
struct branch_info *old,
|
||||
struct branch_info *new)
|
||||
@ -522,8 +536,8 @@ static void update_refs_for_switch(struct checkout_opts *opts,
|
||||
update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
|
||||
REF_NODEREF, DIE_ON_ERR);
|
||||
if (!opts->quiet) {
|
||||
if (old->path)
|
||||
fprintf(stderr, "Note: moving to '%s' which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n git checkout -b <new_branch_name>\n", new->name);
|
||||
if (old->path && advice_detached_head)
|
||||
detach_advice(old->path, new->name);
|
||||
describe_detached_head("HEAD is now at", new->commit);
|
||||
}
|
||||
}
|
||||
|
@ -104,10 +104,8 @@ static void add_merge_config(struct ref **head,
|
||||
* there is no entry in the resulting FETCH_HEAD marked
|
||||
* for merging.
|
||||
*/
|
||||
memset(&refspec, 0, sizeof(refspec));
|
||||
refspec.src = branch->merge[i]->src;
|
||||
refspec.dst = NULL;
|
||||
refspec.pattern = 0;
|
||||
refspec.force = 0;
|
||||
get_fetch_map(remote_refs, &refspec, tail, 1);
|
||||
for (rm = *old_tail; rm; rm = rm->next)
|
||||
rm->merge = 1;
|
||||
@ -389,9 +387,10 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
|
||||
fputc(url[i], fp);
|
||||
fputc('\n', fp);
|
||||
|
||||
if (ref)
|
||||
if (ref) {
|
||||
rc |= update_local_ref(ref, what, note);
|
||||
else
|
||||
free(ref);
|
||||
} else
|
||||
sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
|
||||
SUMMARY_WIDTH, *kind ? kind : "branch",
|
||||
REFCOL_WIDTH, *what ? what : "HEAD");
|
||||
@ -588,7 +587,7 @@ static void find_non_local_tags(struct transport *transport,
|
||||
* to fetch then we can mark the ref entry in the list
|
||||
* as one to ignore by setting util to NULL.
|
||||
*/
|
||||
if (!strcmp(ref->name + strlen(ref->name) - 3, "^{}")) {
|
||||
if (!suffixcmp(ref->name, "^{}")) {
|
||||
if (item && !has_sha1_file(ref->old_sha1) &&
|
||||
!will_fetch(head, ref->old_sha1) &&
|
||||
!has_sha1_file(item->util) &&
|
||||
@ -651,6 +650,17 @@ static void check_not_current_branch(struct ref *ref_map)
|
||||
"of non-bare repository", current_branch->refname);
|
||||
}
|
||||
|
||||
static int truncate_fetch_head(void)
|
||||
{
|
||||
char *filename = git_path("FETCH_HEAD");
|
||||
FILE *fp = fopen(filename, "w");
|
||||
|
||||
if (!fp)
|
||||
return error("cannot open %s: %s\n", filename, strerror(errno));
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_fetch(struct transport *transport,
|
||||
struct refspec *refs, int ref_count)
|
||||
{
|
||||
@ -672,11 +682,9 @@ static int do_fetch(struct transport *transport,
|
||||
|
||||
/* if not appending, truncate FETCH_HEAD */
|
||||
if (!append && !dry_run) {
|
||||
char *filename = git_path("FETCH_HEAD");
|
||||
FILE *fp = fopen(filename, "w");
|
||||
if (!fp)
|
||||
return error("cannot open %s: %s\n", filename, strerror(errno));
|
||||
fclose(fp);
|
||||
int errcode = truncate_fetch_head();
|
||||
if (errcode)
|
||||
return errcode;
|
||||
}
|
||||
|
||||
ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags);
|
||||
@ -784,13 +792,19 @@ static int add_remote_or_group(const char *name, struct string_list *list)
|
||||
static int fetch_multiple(struct string_list *list)
|
||||
{
|
||||
int i, result = 0;
|
||||
const char *argv[] = { "fetch", NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
int argc = 1;
|
||||
const char *argv[11] = { "fetch", "--append" };
|
||||
int argc = 2;
|
||||
|
||||
if (dry_run)
|
||||
argv[argc++] = "--dry-run";
|
||||
if (prune)
|
||||
argv[argc++] = "--prune";
|
||||
if (update_head_ok)
|
||||
argv[argc++] = "--update-head-ok";
|
||||
if (force)
|
||||
argv[argc++] = "--force";
|
||||
if (keep)
|
||||
argv[argc++] = "--keep";
|
||||
if (verbosity >= 2)
|
||||
argv[argc++] = "-v";
|
||||
if (verbosity >= 1)
|
||||
@ -798,9 +812,16 @@ static int fetch_multiple(struct string_list *list)
|
||||
else if (verbosity < 0)
|
||||
argv[argc++] = "-q";
|
||||
|
||||
if (!append && !dry_run) {
|
||||
int errcode = truncate_fetch_head();
|
||||
if (errcode)
|
||||
return errcode;
|
||||
}
|
||||
|
||||
for (i = 0; i < list->nr; i++) {
|
||||
const char *name = list->items[i].string;
|
||||
argv[argc] = name;
|
||||
argv[argc + 1] = NULL;
|
||||
if (verbosity >= 0)
|
||||
printf("Fetching %s\n", name);
|
||||
if (run_command_v_opt(argv, RUN_GIT_CMD)) {
|
||||
|
@ -844,6 +844,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
||||
opt.relative = 1;
|
||||
opt.pathname = 1;
|
||||
opt.pattern_tail = &opt.pattern_list;
|
||||
opt.header_tail = &opt.header_list;
|
||||
opt.regflags = REG_NEWLINE;
|
||||
opt.max_depth = -1;
|
||||
|
||||
|
@ -779,8 +779,7 @@ static int handle_commit_msg(struct strbuf *line)
|
||||
return 0;
|
||||
|
||||
if (still_looking) {
|
||||
strbuf_ltrim(line);
|
||||
if (!line->len)
|
||||
if (!line->len || (line->len == 1 && line->buf[0] == '\n'))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -464,9 +464,6 @@ static int write_one(struct sha1file *f,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* forward declaration for write_pack_file */
|
||||
static int adjust_perm(const char *path, mode_t mode);
|
||||
|
||||
static void write_pack_file(void)
|
||||
{
|
||||
uint32_t i = 0, j;
|
||||
@ -523,21 +520,17 @@ static void write_pack_file(void)
|
||||
}
|
||||
|
||||
if (!pack_to_stdout) {
|
||||
mode_t mode = umask(0);
|
||||
struct stat st;
|
||||
const char *idx_tmp_name;
|
||||
char tmpname[PATH_MAX];
|
||||
|
||||
umask(mode);
|
||||
mode = 0444 & ~mode;
|
||||
|
||||
idx_tmp_name = write_idx_file(NULL, written_list,
|
||||
nr_written, sha1);
|
||||
|
||||
snprintf(tmpname, sizeof(tmpname), "%s-%s.pack",
|
||||
base_name, sha1_to_hex(sha1));
|
||||
free_pack_by_name(tmpname);
|
||||
if (adjust_perm(pack_tmp_name, mode))
|
||||
if (adjust_shared_perm(pack_tmp_name))
|
||||
die_errno("unable to make temporary pack file readable");
|
||||
if (rename(pack_tmp_name, tmpname))
|
||||
die_errno("unable to rename temporary pack file");
|
||||
@ -565,7 +558,7 @@ static void write_pack_file(void)
|
||||
|
||||
snprintf(tmpname, sizeof(tmpname), "%s-%s.idx",
|
||||
base_name, sha1_to_hex(sha1));
|
||||
if (adjust_perm(idx_tmp_name, mode))
|
||||
if (adjust_shared_perm(idx_tmp_name))
|
||||
die_errno("unable to make temporary index file readable");
|
||||
if (rename(idx_tmp_name, tmpname))
|
||||
die_errno("unable to rename temporary index file");
|
||||
@ -2125,13 +2118,6 @@ static void get_object_list(int ac, const char **av)
|
||||
loosen_unused_packed_objects(&revs);
|
||||
}
|
||||
|
||||
static int adjust_perm(const char *path, mode_t mode)
|
||||
{
|
||||
if (chmod(path, mode))
|
||||
return -1;
|
||||
return adjust_shared_perm(path);
|
||||
}
|
||||
|
||||
int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int use_internal_rev_list = 0;
|
||||
|
@ -18,13 +18,11 @@ static unsigned long expire;
|
||||
static int prune_tmp_object(const char *path, const char *filename)
|
||||
{
|
||||
const char *fullpath = mkpath("%s/%s", path, filename);
|
||||
if (expire) {
|
||||
struct stat st;
|
||||
if (lstat(fullpath, &st))
|
||||
return error("Could not stat '%s'", fullpath);
|
||||
if (st.st_mtime > expire)
|
||||
return 0;
|
||||
}
|
||||
struct stat st;
|
||||
if (lstat(fullpath, &st))
|
||||
return error("Could not stat '%s'", fullpath);
|
||||
if (st.st_mtime > expire)
|
||||
return 0;
|
||||
printf("Removing stale temporary file %s\n", fullpath);
|
||||
if (!show_only)
|
||||
unlink_or_warn(fullpath);
|
||||
@ -34,13 +32,11 @@ static int prune_tmp_object(const char *path, const char *filename)
|
||||
static int prune_object(char *path, const char *filename, const unsigned char *sha1)
|
||||
{
|
||||
const char *fullpath = mkpath("%s/%s", path, filename);
|
||||
if (expire) {
|
||||
struct stat st;
|
||||
if (lstat(fullpath, &st))
|
||||
return error("Could not stat '%s'", fullpath);
|
||||
if (st.st_mtime > expire)
|
||||
return 0;
|
||||
}
|
||||
struct stat st;
|
||||
if (lstat(fullpath, &st))
|
||||
return error("Could not stat '%s'", fullpath);
|
||||
if (st.st_mtime > expire)
|
||||
return 0;
|
||||
if (show_only || verbose) {
|
||||
enum object_type type = sha1_object_info(sha1, NULL);
|
||||
printf("%s %s\n", sha1_to_hex(sha1),
|
||||
@ -139,6 +135,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
|
||||
};
|
||||
char *s;
|
||||
|
||||
expire = ULONG_MAX;
|
||||
save_commit_buffer = 0;
|
||||
read_replace_refs = 0;
|
||||
init_revisions(&revs, prefix);
|
||||
|
@ -68,7 +68,7 @@ static void setup_push_tracking(void)
|
||||
struct branch *branch = branch_get(NULL);
|
||||
if (!branch)
|
||||
die("You are not currently on a branch.");
|
||||
if (!branch->merge_nr)
|
||||
if (!branch->merge_nr || !branch->merge)
|
||||
die("The current branch %s is not tracking anything.",
|
||||
branch->name);
|
||||
if (branch->merge_nr != 1)
|
||||
|
@ -530,16 +530,14 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
|
||||
int i, status, do_all;
|
||||
int explicit_expiry = 0;
|
||||
|
||||
default_reflog_expire_unreachable = now - 30 * 24 * 3600;
|
||||
default_reflog_expire = now - 90 * 24 * 3600;
|
||||
git_config(reflog_expire_config, NULL);
|
||||
|
||||
save_commit_buffer = 0;
|
||||
do_all = status = 0;
|
||||
memset(&cb, 0, sizeof(cb));
|
||||
|
||||
if (!default_reflog_expire_unreachable)
|
||||
default_reflog_expire_unreachable = now - 30 * 24 * 3600;
|
||||
if (!default_reflog_expire)
|
||||
default_reflog_expire = now - 90 * 24 * 3600;
|
||||
cb.expire_total = default_reflog_expire;
|
||||
cb.expire_unreachable = default_reflog_expire_unreachable;
|
||||
|
||||
|
@ -371,8 +371,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
||||
revs.diff)
|
||||
usage(rev_list_usage);
|
||||
|
||||
save_commit_buffer = revs.verbose_header ||
|
||||
revs.grep_filter.pattern_list;
|
||||
save_commit_buffer = (revs.verbose_header ||
|
||||
revs.grep_filter.pattern_list ||
|
||||
revs.grep_filter.header_list);
|
||||
if (bisect_list)
|
||||
revs.limited = 1;
|
||||
|
||||
|
@ -455,6 +455,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
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 > 1 && !strcmp("-h", argv[1]))
|
||||
usage(builtin_rev_parse_usage);
|
||||
|
||||
|
13
cache.h
13
cache.h
@ -388,6 +388,15 @@ static inline enum object_type object_type(unsigned int mode)
|
||||
#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
|
||||
#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
|
||||
|
||||
/*
|
||||
* Repository-local GIT_* environment variables
|
||||
* The array is NULL-terminated to simplify its usage in contexts such
|
||||
* environment creation or simple walk of the list.
|
||||
* The number of non-NULL entries is available as a macro.
|
||||
*/
|
||||
#define LOCAL_REPO_ENV_SIZE 8
|
||||
extern const char *const local_repo_env[LOCAL_REPO_ENV_SIZE + 1];
|
||||
|
||||
extern int is_bare_repository_cfg;
|
||||
extern int is_bare_repository(void);
|
||||
extern int is_inside_git_dir(void);
|
||||
@ -641,6 +650,10 @@ int git_mkstemp(char *path, size_t n, const char *template);
|
||||
|
||||
int git_mkstemps(char *path, size_t n, const char *template, int suffix_len);
|
||||
|
||||
/* set default permissions by passing mode arguments to open(2) */
|
||||
int git_mkstemps_mode(char *pattern, int suffix_len, int mode);
|
||||
int git_mkstemp_mode(char *pattern, int mode);
|
||||
|
||||
/*
|
||||
* NOTE NOTE NOTE!!
|
||||
*
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
char *gitmkdtemp(char *template)
|
||||
{
|
||||
if (!mktemp(template) || mkdir(template, 0700))
|
||||
if (!*mktemp(template) || mkdir(template, 0700))
|
||||
return NULL;
|
||||
return template;
|
||||
}
|
||||
|
@ -1,70 +0,0 @@
|
||||
#include "../git-compat-util.h"
|
||||
|
||||
/* Adapted from libiberty's mkstemp.c. */
|
||||
|
||||
#undef TMP_MAX
|
||||
#define TMP_MAX 16384
|
||||
|
||||
int gitmkstemps(char *pattern, int suffix_len)
|
||||
{
|
||||
static const char letters[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789";
|
||||
static const int num_letters = 62;
|
||||
uint64_t value;
|
||||
struct timeval tv;
|
||||
char *template;
|
||||
size_t len;
|
||||
int fd, count;
|
||||
|
||||
len = strlen(pattern);
|
||||
|
||||
if (len < 6 + suffix_len) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp(&pattern[len - 6 - suffix_len], "XXXXXX", 6)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace pattern's XXXXXX characters with randomness.
|
||||
* Try TMP_MAX different filenames.
|
||||
*/
|
||||
gettimeofday(&tv, NULL);
|
||||
value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();
|
||||
template = &pattern[len - 6 - suffix_len];
|
||||
for (count = 0; count < TMP_MAX; ++count) {
|
||||
uint64_t v = value;
|
||||
/* Fill in the random bits. */
|
||||
template[0] = letters[v % num_letters]; v /= num_letters;
|
||||
template[1] = letters[v % num_letters]; v /= num_letters;
|
||||
template[2] = letters[v % num_letters]; v /= num_letters;
|
||||
template[3] = letters[v % num_letters]; v /= num_letters;
|
||||
template[4] = letters[v % num_letters]; v /= num_letters;
|
||||
template[5] = letters[v % num_letters]; v /= num_letters;
|
||||
|
||||
fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, 0600);
|
||||
if (fd > 0)
|
||||
return fd;
|
||||
/*
|
||||
* Fatal error (EPERM, ENOSPC etc).
|
||||
* It doesn't make sense to loop.
|
||||
*/
|
||||
if (errno != EEXIST)
|
||||
break;
|
||||
/*
|
||||
* This is a random value. It is only necessary that
|
||||
* the next TMP_MAX values generated by adding 7777 to
|
||||
* VALUE are different with (module 2^32).
|
||||
*/
|
||||
value += 7777;
|
||||
}
|
||||
/* We return the null string if we can't find a unique file name. */
|
||||
pattern[0] = '\0';
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
14
connect.c
14
connect.c
@ -607,18 +607,8 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
|
||||
*arg++ = host;
|
||||
}
|
||||
else {
|
||||
/* remove these from the environment */
|
||||
const char *env[] = {
|
||||
ALTERNATE_DB_ENVIRONMENT,
|
||||
DB_ENVIRONMENT,
|
||||
GIT_DIR_ENVIRONMENT,
|
||||
GIT_WORK_TREE_ENVIRONMENT,
|
||||
GRAFT_ENVIRONMENT,
|
||||
INDEX_ENVIRONMENT,
|
||||
NO_REPLACE_OBJECTS_ENVIRONMENT,
|
||||
NULL
|
||||
};
|
||||
conn->env = env;
|
||||
/* remove repo-local variables from the environment */
|
||||
conn->env = local_repo_env;
|
||||
conn->use_shell = 1;
|
||||
}
|
||||
*arg++ = cmd.buf;
|
||||
|
@ -250,7 +250,9 @@ __git_refs ()
|
||||
refs="${cur%/*}"
|
||||
;;
|
||||
*)
|
||||
if [ -e "$dir/HEAD" ]; then echo HEAD; fi
|
||||
for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
|
||||
if [ -e "$dir/$i" ]; then echo $i; fi
|
||||
done
|
||||
format="refname:short"
|
||||
refs="refs/tags refs/heads refs/remotes"
|
||||
;;
|
||||
|
2
daemon.c
2
daemon.c
@ -420,7 +420,7 @@ static void parse_host_and_port(char *hostport, char **host,
|
||||
*host = hostport;
|
||||
*port = strrchr(hostport, ':');
|
||||
if (*port) {
|
||||
*port = '\0';
|
||||
**port = '\0';
|
||||
++*port;
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,23 @@ static char *work_tree;
|
||||
static const char *git_dir;
|
||||
static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
|
||||
|
||||
/*
|
||||
* Repository-local GIT_* environment variables
|
||||
* Remember to update local_repo_env_size in cache.h when
|
||||
* the size of the list changes
|
||||
*/
|
||||
const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = {
|
||||
ALTERNATE_DB_ENVIRONMENT,
|
||||
CONFIG_ENVIRONMENT,
|
||||
DB_ENVIRONMENT,
|
||||
GIT_DIR_ENVIRONMENT,
|
||||
GIT_WORK_TREE_ENVIRONMENT,
|
||||
GRAFT_ENVIRONMENT,
|
||||
INDEX_ENVIRONMENT,
|
||||
NO_REPLACE_OBJECTS_ENVIRONMENT,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void setup_git_env(void)
|
||||
{
|
||||
git_dir = getenv(GIT_DIR_ENVIRONMENT);
|
||||
|
@ -957,6 +957,28 @@ sub coalesce_overlapping_hunks {
|
||||
return @out;
|
||||
}
|
||||
|
||||
sub reassemble_patch {
|
||||
my $head = shift;
|
||||
my @patch;
|
||||
|
||||
# Include everything in the header except the beginning of the diff.
|
||||
push @patch, (grep { !/^[-+]{3}/ } @$head);
|
||||
|
||||
# Then include any headers from the hunk lines, which must
|
||||
# come before any actual hunk.
|
||||
while (@_ && $_[0] !~ /^@/) {
|
||||
push @patch, shift;
|
||||
}
|
||||
|
||||
# Then begin the diff.
|
||||
push @patch, grep { /^[-+]{3}/ } @$head;
|
||||
|
||||
# And then the actual hunks.
|
||||
push @patch, @_;
|
||||
|
||||
return @patch;
|
||||
}
|
||||
|
||||
sub color_diff {
|
||||
return map {
|
||||
colored((/^@/ ? $fraginfo_color :
|
||||
@ -1453,7 +1475,7 @@ sub patch_update_file {
|
||||
|
||||
if (@result) {
|
||||
my $fh;
|
||||
my @patch = (@{$head->{TEXT}}, @result);
|
||||
my @patch = reassemble_patch($head->{TEXT}, @result);
|
||||
my $apply_routine = $patch_mode_flavour{APPLY};
|
||||
&$apply_routine(@patch);
|
||||
refresh();
|
||||
|
@ -41,7 +41,7 @@ strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
|
||||
log_arg= verbosity=
|
||||
merge_args=
|
||||
curr_branch=$(git symbolic-ref -q HEAD)
|
||||
curr_branch_short=$(echo "$curr_branch" | sed "s|refs/heads/||")
|
||||
curr_branch_short="${curr_branch#refs/heads/}"
|
||||
rebase=$(git config --bool branch.$curr_branch_short.rebase)
|
||||
while :
|
||||
do
|
||||
|
@ -172,6 +172,13 @@ get_author_ident_from_commit () {
|
||||
LANG=C LC_ALL=C sed -ne "$pick_author_script"
|
||||
}
|
||||
|
||||
# Clear repo-local GIT_* environment variables. Useful when switching to
|
||||
# another repository (e.g. when entering a submodule). See also the env
|
||||
# list in git_connect()
|
||||
clear_local_git_env() {
|
||||
unset $(git rev-parse --local-env-vars)
|
||||
}
|
||||
|
||||
# Make sure we are in a valid repository of a vintage we understand,
|
||||
# if we require to be in a git repository.
|
||||
if test -z "$NONGIT_OK"
|
||||
|
@ -222,7 +222,7 @@ cmd_add()
|
||||
|
||||
module_clone "$path" "$realrepo" "$reference" || exit
|
||||
(
|
||||
unset GIT_DIR
|
||||
clear_local_git_env
|
||||
cd "$path" &&
|
||||
# ash fails to wordsplit ${branch:+-b "$branch"...}
|
||||
case "$branch" in
|
||||
@ -278,7 +278,7 @@ cmd_foreach()
|
||||
name=$(module_name "$path")
|
||||
(
|
||||
prefix="$prefix$path/"
|
||||
unset GIT_DIR
|
||||
clear_local_git_env
|
||||
cd "$path" &&
|
||||
eval "$@" &&
|
||||
if test -n "$recursive"
|
||||
@ -434,7 +434,7 @@ cmd_update()
|
||||
module_clone "$path" "$url" "$reference"|| exit
|
||||
subsha1=
|
||||
else
|
||||
subsha1=$(unset GIT_DIR; cd "$path" &&
|
||||
subsha1=$(clear_local_git_env; cd "$path" &&
|
||||
git rev-parse --verify HEAD) ||
|
||||
die "Unable to find current revision in submodule path '$path'"
|
||||
fi
|
||||
@ -454,7 +454,7 @@ cmd_update()
|
||||
|
||||
if test -z "$nofetch"
|
||||
then
|
||||
(unset GIT_DIR; cd "$path" &&
|
||||
(clear_local_git_env; cd "$path" &&
|
||||
git-fetch) ||
|
||||
die "Unable to fetch in submodule path '$path'"
|
||||
fi
|
||||
@ -477,14 +477,14 @@ cmd_update()
|
||||
;;
|
||||
esac
|
||||
|
||||
(unset GIT_DIR; cd "$path" && $command "$sha1") ||
|
||||
(clear_local_git_env; cd "$path" && $command "$sha1") ||
|
||||
die "Unable to $action '$sha1' in submodule path '$path'"
|
||||
say "Submodule path '$path': $msg '$sha1'"
|
||||
fi
|
||||
|
||||
if test -n "$recursive"
|
||||
then
|
||||
(unset GIT_DIR; cd "$path" && cmd_update $orig_args) ||
|
||||
(clear_local_git_env; cd "$path" && cmd_update $orig_args) ||
|
||||
die "Failed to recurse into submodule path '$path'"
|
||||
fi
|
||||
done
|
||||
@ -492,7 +492,7 @@ cmd_update()
|
||||
|
||||
set_name_rev () {
|
||||
revname=$( (
|
||||
unset GIT_DIR
|
||||
clear_local_git_env
|
||||
cd "$1" && {
|
||||
git describe "$2" 2>/dev/null ||
|
||||
git describe --tags "$2" 2>/dev/null ||
|
||||
@ -757,7 +757,7 @@ cmd_status()
|
||||
else
|
||||
if test -z "$cached"
|
||||
then
|
||||
sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD)
|
||||
sha1=$(clear_local_git_env; cd "$path" && git rev-parse --verify HEAD)
|
||||
set_name_rev "$path" "$sha1"
|
||||
fi
|
||||
say "+$sha1 $displaypath$revname"
|
||||
@ -767,7 +767,7 @@ cmd_status()
|
||||
then
|
||||
(
|
||||
prefix="$displaypath/"
|
||||
unset GIT_DIR
|
||||
clear_local_git_env
|
||||
cd "$path" &&
|
||||
cmd_status $orig_args
|
||||
) ||
|
||||
@ -818,7 +818,7 @@ cmd_sync()
|
||||
if test -e "$path"/.git
|
||||
then
|
||||
(
|
||||
unset GIT_DIR
|
||||
clear_local_git_env
|
||||
cd "$path"
|
||||
remote=$(get_default_remote)
|
||||
say "Synchronizing submodule url for '$name'"
|
||||
|
44
grep.c
44
grep.c
@ -11,8 +11,8 @@ void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field fie
|
||||
p->no = 0;
|
||||
p->token = GREP_PATTERN_HEAD;
|
||||
p->field = field;
|
||||
*opt->pattern_tail = p;
|
||||
opt->pattern_tail = &p->next;
|
||||
*opt->header_tail = p;
|
||||
opt->header_tail = &p->next;
|
||||
p->next = NULL;
|
||||
}
|
||||
|
||||
@ -184,9 +184,26 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
|
||||
void compile_grep_patterns(struct grep_opt *opt)
|
||||
{
|
||||
struct grep_pat *p;
|
||||
struct grep_expr *header_expr = NULL;
|
||||
|
||||
if (opt->all_match)
|
||||
opt->extended = 1;
|
||||
if (opt->header_list) {
|
||||
p = opt->header_list;
|
||||
header_expr = compile_pattern_expr(&p);
|
||||
if (p)
|
||||
die("incomplete pattern expression: %s", p->pattern);
|
||||
for (p = opt->header_list; p; p = p->next) {
|
||||
switch (p->token) {
|
||||
case GREP_PATTERN: /* atom */
|
||||
case GREP_PATTERN_HEAD:
|
||||
case GREP_PATTERN_BODY:
|
||||
compile_regexp(p, opt);
|
||||
break;
|
||||
default:
|
||||
opt->extended = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (p = opt->pattern_list; p; p = p->next) {
|
||||
switch (p->token) {
|
||||
@ -201,7 +218,9 @@ void compile_grep_patterns(struct grep_opt *opt)
|
||||
}
|
||||
}
|
||||
|
||||
if (!opt->extended)
|
||||
if (opt->all_match || header_expr)
|
||||
opt->extended = 1;
|
||||
else if (!opt->extended)
|
||||
return;
|
||||
|
||||
/* Then bundle them up in an expression.
|
||||
@ -212,6 +231,21 @@ void compile_grep_patterns(struct grep_opt *opt)
|
||||
opt->pattern_expression = compile_pattern_expr(&p);
|
||||
if (p)
|
||||
die("incomplete pattern expression: %s", p->pattern);
|
||||
|
||||
if (!header_expr)
|
||||
return;
|
||||
|
||||
if (opt->pattern_expression) {
|
||||
struct grep_expr *z;
|
||||
z = xcalloc(1, sizeof(*z));
|
||||
z->node = GREP_NODE_OR;
|
||||
z->u.binary.left = opt->pattern_expression;
|
||||
z->u.binary.right = header_expr;
|
||||
opt->pattern_expression = z;
|
||||
} else {
|
||||
opt->pattern_expression = header_expr;
|
||||
}
|
||||
opt->all_match = 1;
|
||||
}
|
||||
|
||||
static void free_pattern_expr(struct grep_expr *x)
|
||||
|
2
grep.h
2
grep.h
@ -59,6 +59,8 @@ struct grep_expr {
|
||||
struct grep_opt {
|
||||
struct grep_pat *pattern_list;
|
||||
struct grep_pat **pattern_tail;
|
||||
struct grep_pat *header_list;
|
||||
struct grep_pat **header_tail;
|
||||
struct grep_expr *pattern_expression;
|
||||
const char *prefix;
|
||||
int prefix_length;
|
||||
|
79
path.c
79
path.c
@ -157,6 +157,85 @@ int git_mkstemps(char *path, size_t len, const char *template, int suffix_len)
|
||||
return mkstemps(path, suffix_len);
|
||||
}
|
||||
|
||||
/* Adapted from libiberty's mkstemp.c. */
|
||||
|
||||
#undef TMP_MAX
|
||||
#define TMP_MAX 16384
|
||||
|
||||
int git_mkstemps_mode(char *pattern, int suffix_len, int mode)
|
||||
{
|
||||
static const char letters[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789";
|
||||
static const int num_letters = 62;
|
||||
uint64_t value;
|
||||
struct timeval tv;
|
||||
char *template;
|
||||
size_t len;
|
||||
int fd, count;
|
||||
|
||||
len = strlen(pattern);
|
||||
|
||||
if (len < 6 + suffix_len) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp(&pattern[len - 6 - suffix_len], "XXXXXX", 6)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace pattern's XXXXXX characters with randomness.
|
||||
* Try TMP_MAX different filenames.
|
||||
*/
|
||||
gettimeofday(&tv, NULL);
|
||||
value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();
|
||||
template = &pattern[len - 6 - suffix_len];
|
||||
for (count = 0; count < TMP_MAX; ++count) {
|
||||
uint64_t v = value;
|
||||
/* Fill in the random bits. */
|
||||
template[0] = letters[v % num_letters]; v /= num_letters;
|
||||
template[1] = letters[v % num_letters]; v /= num_letters;
|
||||
template[2] = letters[v % num_letters]; v /= num_letters;
|
||||
template[3] = letters[v % num_letters]; v /= num_letters;
|
||||
template[4] = letters[v % num_letters]; v /= num_letters;
|
||||
template[5] = letters[v % num_letters]; v /= num_letters;
|
||||
|
||||
fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode);
|
||||
if (fd > 0)
|
||||
return fd;
|
||||
/*
|
||||
* Fatal error (EPERM, ENOSPC etc).
|
||||
* It doesn't make sense to loop.
|
||||
*/
|
||||
if (errno != EEXIST)
|
||||
break;
|
||||
/*
|
||||
* This is a random value. It is only necessary that
|
||||
* the next TMP_MAX values generated by adding 7777 to
|
||||
* VALUE are different with (module 2^32).
|
||||
*/
|
||||
value += 7777;
|
||||
}
|
||||
/* We return the null string if we can't find a unique file name. */
|
||||
pattern[0] = '\0';
|
||||
return -1;
|
||||
}
|
||||
|
||||
int git_mkstemp_mode(char *pattern, int mode)
|
||||
{
|
||||
/* mkstemp is just mkstemps with no suffix */
|
||||
return git_mkstemps_mode(pattern, 0, mode);
|
||||
}
|
||||
|
||||
int gitmkstemps(char *pattern, int suffix_len)
|
||||
{
|
||||
return git_mkstemps_mode(pattern, suffix_len, 0600);
|
||||
}
|
||||
|
||||
int validate_headref(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
|
22
refs.c
22
refs.c
@ -1574,7 +1574,7 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs,
|
||||
{
|
||||
const char *logfile;
|
||||
FILE *logfp;
|
||||
char buf[1024];
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
int ret = 0;
|
||||
|
||||
logfile = git_path("logs/%s", ref);
|
||||
@ -1587,24 +1587,24 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs,
|
||||
if (fstat(fileno(logfp), &statbuf) ||
|
||||
statbuf.st_size < ofs ||
|
||||
fseek(logfp, -ofs, SEEK_END) ||
|
||||
fgets(buf, sizeof(buf), logfp)) {
|
||||
strbuf_getwholeline(&sb, logfp, '\n')) {
|
||||
fclose(logfp);
|
||||
strbuf_release(&sb);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf), logfp)) {
|
||||
while (!strbuf_getwholeline(&sb, logfp, '\n')) {
|
||||
unsigned char osha1[20], nsha1[20];
|
||||
char *email_end, *message;
|
||||
unsigned long timestamp;
|
||||
int len, tz;
|
||||
int tz;
|
||||
|
||||
/* old SP new SP name <email> SP time TAB msg LF */
|
||||
len = strlen(buf);
|
||||
if (len < 83 || buf[len-1] != '\n' ||
|
||||
get_sha1_hex(buf, osha1) || buf[40] != ' ' ||
|
||||
get_sha1_hex(buf + 41, nsha1) || buf[81] != ' ' ||
|
||||
!(email_end = strchr(buf + 82, '>')) ||
|
||||
if (sb.len < 83 || sb.buf[sb.len - 1] != '\n' ||
|
||||
get_sha1_hex(sb.buf, osha1) || sb.buf[40] != ' ' ||
|
||||
get_sha1_hex(sb.buf + 41, nsha1) || sb.buf[81] != ' ' ||
|
||||
!(email_end = strchr(sb.buf + 82, '>')) ||
|
||||
email_end[1] != ' ' ||
|
||||
!(timestamp = strtoul(email_end + 2, &message, 10)) ||
|
||||
!message || message[0] != ' ' ||
|
||||
@ -1618,11 +1618,13 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs,
|
||||
message += 6;
|
||||
else
|
||||
message += 7;
|
||||
ret = fn(osha1, nsha1, buf+82, timestamp, tz, message, cb_data);
|
||||
ret = fn(osha1, nsha1, sb.buf + 82, timestamp, tz, message,
|
||||
cb_data);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
fclose(logfp);
|
||||
strbuf_release(&sb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -826,6 +826,7 @@ void init_revisions(struct rev_info *revs, const char *prefix)
|
||||
|
||||
revs->grep_filter.status_only = 1;
|
||||
revs->grep_filter.pattern_tail = &(revs->grep_filter.pattern_list);
|
||||
revs->grep_filter.header_tail = &(revs->grep_filter.header_list);
|
||||
revs->grep_filter.regflags = REG_NEWLINE;
|
||||
|
||||
diff_setup(&revs->diffopt);
|
||||
@ -1333,7 +1334,7 @@ static void append_prune_data(const char ***prune_data, const char **av)
|
||||
*/
|
||||
int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def)
|
||||
{
|
||||
int i, flags, left, seen_dashdash, read_from_stdin;
|
||||
int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0;
|
||||
const char **prune_data = NULL;
|
||||
|
||||
/* First, search for "--" */
|
||||
@ -1459,6 +1460,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
append_prune_data(&prune_data, argv + i);
|
||||
break;
|
||||
}
|
||||
else
|
||||
got_rev_arg = 1;
|
||||
}
|
||||
|
||||
if (prune_data)
|
||||
@ -1468,7 +1471,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
revs->def = def;
|
||||
if (revs->show_merge)
|
||||
prepare_show_merge(revs);
|
||||
if (revs->def && !revs->pending.nr) {
|
||||
if (revs->def && !revs->pending.nr && !got_rev_arg) {
|
||||
unsigned char sha1[20];
|
||||
struct object *object;
|
||||
unsigned mode;
|
||||
@ -1804,7 +1807,7 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)
|
||||
|
||||
static int commit_match(struct commit *commit, struct rev_info *opt)
|
||||
{
|
||||
if (!opt->grep_filter.pattern_list)
|
||||
if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list)
|
||||
return 1;
|
||||
return grep_buffer(&opt->grep_filter,
|
||||
NULL, /* we say nothing, not even filename */
|
||||
|
@ -67,19 +67,21 @@ static int child_notifier = -1;
|
||||
|
||||
static void notify_parent(void)
|
||||
{
|
||||
write(child_notifier, "", 1);
|
||||
ssize_t unused;
|
||||
unused = write(child_notifier, "", 1);
|
||||
}
|
||||
|
||||
static NORETURN void die_child(const char *err, va_list params)
|
||||
{
|
||||
char msg[4096];
|
||||
ssize_t unused;
|
||||
int len = vsnprintf(msg, sizeof(msg), err, params);
|
||||
if (len > sizeof(msg))
|
||||
len = sizeof(msg);
|
||||
|
||||
write(child_err, "fatal: ", 7);
|
||||
write(child_err, msg, len);
|
||||
write(child_err, "\n", 1);
|
||||
unused = write(child_err, "fatal: ", 7);
|
||||
unused = write(child_err, msg, len);
|
||||
unused = write(child_err, "\n", 1);
|
||||
exit(128);
|
||||
}
|
||||
|
||||
|
@ -2206,7 +2206,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
|
||||
}
|
||||
|
||||
out:
|
||||
if (set_shared_perm(filename, (S_IFREG|0444)))
|
||||
if (adjust_shared_perm(filename))
|
||||
return error("unable to set permission to '%s'", filename);
|
||||
return 0;
|
||||
}
|
||||
@ -2262,7 +2262,7 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename)
|
||||
}
|
||||
memcpy(buffer, filename, dirlen);
|
||||
strcpy(buffer + dirlen, "tmp_obj_XXXXXX");
|
||||
fd = mkstemp(buffer);
|
||||
fd = git_mkstemp_mode(buffer, 0444);
|
||||
if (fd < 0 && dirlen && errno == ENOENT) {
|
||||
/* Make sure the directory exists */
|
||||
memcpy(buffer, filename, dirlen);
|
||||
@ -2272,7 +2272,7 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename)
|
||||
|
||||
/* Try again */
|
||||
strcpy(buffer + dirlen - 1, "/tmp_obj_XXXXXX");
|
||||
fd = mkstemp(buffer);
|
||||
fd = git_mkstemp_mode(buffer, 0444);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
22
submodule.c
22
submodule.c
@ -123,16 +123,19 @@ void show_submodule_summary(FILE *f, const char *path,
|
||||
|
||||
int is_submodule_modified(const char *path)
|
||||
{
|
||||
int len;
|
||||
int len, i;
|
||||
struct child_process cp;
|
||||
const char *argv[] = {
|
||||
"status",
|
||||
"--porcelain",
|
||||
NULL,
|
||||
};
|
||||
char *env[4];
|
||||
const char *env[LOCAL_REPO_ENV_SIZE + 3];
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
|
||||
for (i = 0; i < LOCAL_REPO_ENV_SIZE; i++)
|
||||
env[i] = local_repo_env[i];
|
||||
|
||||
strbuf_addf(&buf, "%s/.git/", path);
|
||||
if (!is_directory(buf.buf)) {
|
||||
strbuf_release(&buf);
|
||||
@ -143,16 +146,14 @@ int is_submodule_modified(const char *path)
|
||||
strbuf_reset(&buf);
|
||||
|
||||
strbuf_addf(&buf, "GIT_WORK_TREE=%s", path);
|
||||
env[0] = strbuf_detach(&buf, NULL);
|
||||
env[i++] = strbuf_detach(&buf, NULL);
|
||||
strbuf_addf(&buf, "GIT_DIR=%s/.git", path);
|
||||
env[1] = strbuf_detach(&buf, NULL);
|
||||
strbuf_addf(&buf, "GIT_INDEX_FILE");
|
||||
env[2] = strbuf_detach(&buf, NULL);
|
||||
env[3] = NULL;
|
||||
env[i++] = strbuf_detach(&buf, NULL);
|
||||
env[i] = NULL;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.argv = argv;
|
||||
cp.env = (const char *const *)env;
|
||||
cp.env = env;
|
||||
cp.git_cmd = 1;
|
||||
cp.no_stdin = 1;
|
||||
cp.out = -1;
|
||||
@ -165,9 +166,8 @@ int is_submodule_modified(const char *path)
|
||||
if (finish_command(&cp))
|
||||
die("git status --porcelain failed");
|
||||
|
||||
free(env[0]);
|
||||
free(env[1]);
|
||||
free(env[2]);
|
||||
for (i = LOCAL_REPO_ENV_SIZE; env[i]; i++)
|
||||
free((char *)env[i]);
|
||||
strbuf_release(&buf);
|
||||
return len != 0;
|
||||
}
|
||||
|
@ -27,6 +27,8 @@ pre-clean:
|
||||
|
||||
clean:
|
||||
$(RM) -r 'trash directory'.* test-results
|
||||
$(RM) t????/cvsroot/CVSROOT/?*
|
||||
$(RM) -r valgrind/bin
|
||||
|
||||
aggregate-results-and-cleanup: $(T)
|
||||
$(MAKE) aggregate-results
|
||||
|
67
t/t1304-default-acl.sh
Executable file
67
t/t1304-default-acl.sh
Executable file
@ -0,0 +1,67 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2010 Matthieu Moy
|
||||
#
|
||||
|
||||
test_description='Test repository with default ACL'
|
||||
|
||||
# Create the test repo with restrictive umask
|
||||
# => this must come before . ./test-lib.sh
|
||||
umask 077
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
# We need an arbitrary other user give permission to using ACLs. root
|
||||
# is a good candidate: exists on all unices, and it has permission
|
||||
# anyway, so we don't create a security hole running the testsuite.
|
||||
|
||||
if ! setfacl -m u:root:rwx .; then
|
||||
say "Skipping ACL tests: unable to use setfacl"
|
||||
test_done
|
||||
fi
|
||||
|
||||
modebits () {
|
||||
ls -l "$1" | sed -e 's|^\(..........\).*|\1|'
|
||||
}
|
||||
|
||||
check_perms_and_acl () {
|
||||
actual=$(modebits "$1") &&
|
||||
case "$actual" in
|
||||
-r--r-----*)
|
||||
: happy
|
||||
;;
|
||||
*)
|
||||
echo "Got permission '$actual', expected '-r--r-----'"
|
||||
false
|
||||
;;
|
||||
esac &&
|
||||
getfacl "$1" > actual &&
|
||||
grep -q "user:root:rwx" actual &&
|
||||
grep -q "user:${LOGNAME}:rwx" actual &&
|
||||
grep -q "mask::r--" actual &&
|
||||
grep -q "group::---" actual || false
|
||||
}
|
||||
|
||||
dirs_to_set="./ .git/ .git/objects/ .git/objects/pack/"
|
||||
|
||||
test_expect_success 'Setup test repo' '
|
||||
setfacl -m u:root:rwx $dirs_to_set &&
|
||||
setfacl -d -m u:"$LOGNAME":rwx $dirs_to_set &&
|
||||
setfacl -d -m u:root:rwx $dirs_to_set &&
|
||||
|
||||
touch file.txt &&
|
||||
git add file.txt &&
|
||||
git commit -m "init"
|
||||
'
|
||||
|
||||
test_expect_success 'Objects creation does not break ACLs with restrictive umask' '
|
||||
# SHA1 for empty blob
|
||||
check_perms_and_acl .git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
|
||||
'
|
||||
|
||||
test_expect_success 'git gc does not break ACLs with restrictive umask' '
|
||||
git gc &&
|
||||
check_perms_and_acl .git/objects/pack/*.pack
|
||||
'
|
||||
|
||||
test_done
|
@ -214,4 +214,45 @@ test_expect_success 'delete' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'rewind2' '
|
||||
|
||||
test_tick && git reset --hard HEAD~2 &&
|
||||
loglen=$(wc -l <.git/logs/refs/heads/master) &&
|
||||
test $loglen = 4
|
||||
|
||||
'
|
||||
|
||||
test_expect_success '--expire=never' '
|
||||
|
||||
git reflog expire --verbose \
|
||||
--expire=never \
|
||||
--expire-unreachable=never \
|
||||
--all &&
|
||||
loglen=$(wc -l <.git/logs/refs/heads/master) &&
|
||||
test $loglen = 4
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'gc.reflogexpire=never' '
|
||||
|
||||
git config gc.reflogexpire never &&
|
||||
git config gc.reflogexpireunreachable never &&
|
||||
git reflog expire --verbose --all &&
|
||||
loglen=$(wc -l <.git/logs/refs/heads/master) &&
|
||||
test $loglen = 4
|
||||
'
|
||||
|
||||
test_expect_success 'gc.reflogexpire=false' '
|
||||
|
||||
git config gc.reflogexpire false &&
|
||||
git config gc.reflogexpireunreachable false &&
|
||||
git reflog expire --verbose --all &&
|
||||
loglen=$(wc -l <.git/logs/refs/heads/master) &&
|
||||
test $loglen = 4 &&
|
||||
|
||||
git config --unset gc.reflogexpire &&
|
||||
git config --unset gc.reflogexpireunreachable
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
@ -64,4 +64,13 @@ test_expect_success 'using --date= shows reflog date (oneline)' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
: >expect
|
||||
test_expect_success 'empty reflog file' '
|
||||
git branch empty &&
|
||||
: >.git/logs/refs/heads/empty &&
|
||||
|
||||
git log -g empty >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
@ -66,6 +66,14 @@ test_expect_success 'git checkout -p HEAD^' '
|
||||
verify_state dir/foo parent parent
|
||||
'
|
||||
|
||||
test_expect_success 'git checkout -p handles deletion' '
|
||||
set_state dir/foo work index &&
|
||||
rm dir/foo &&
|
||||
(echo n; echo y) | git checkout -p &&
|
||||
verify_saved_state bar &&
|
||||
verify_state dir/foo index index
|
||||
'
|
||||
|
||||
# The idea in the rest is that bar sorts first, so we always say 'y'
|
||||
# first and if the path limiter fails it'll apply to bar instead of
|
||||
# dir/foo. There's always an extra 'n' to reject edits to dir/foo in
|
||||
|
@ -1,2 +1,2 @@
|
||||
- a list
|
||||
- a list
|
||||
- of stuff
|
||||
|
@ -148,6 +148,38 @@ test_expect_success 'gc --prune=<date>' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'gc --prune=never' '
|
||||
|
||||
add_blob &&
|
||||
git gc --prune=never &&
|
||||
test -f $BLOB_FILE &&
|
||||
git gc --prune=now &&
|
||||
test ! -f $BLOB_FILE
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'gc respects gc.pruneExpire=never' '
|
||||
|
||||
git config gc.pruneExpire never &&
|
||||
add_blob &&
|
||||
git gc &&
|
||||
test -f $BLOB_FILE &&
|
||||
git config gc.pruneExpire now &&
|
||||
git gc &&
|
||||
test ! -f $BLOB_FILE
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'prune --expire=never' '
|
||||
|
||||
add_blob &&
|
||||
git prune --expire=never &&
|
||||
test -f $BLOB_FILE &&
|
||||
git prune &&
|
||||
test ! -f $BLOB_FILE
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'gc: prune old objects after local clone' '
|
||||
add_blob &&
|
||||
test-chmtime =-$((2*$week+1)) $BLOB_FILE &&
|
||||
|
@ -4,8 +4,6 @@ test_description='pull options'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
D=`pwd`
|
||||
|
||||
test_expect_success 'setup' '
|
||||
mkdir parent &&
|
||||
(cd parent && git init &&
|
||||
@ -13,48 +11,83 @@ test_expect_success 'setup' '
|
||||
git commit -m one)
|
||||
'
|
||||
|
||||
cd "$D"
|
||||
|
||||
test_expect_success 'git pull -q' '
|
||||
mkdir clonedq &&
|
||||
cd clonedq &&
|
||||
git pull -q "$D/parent" >out 2>err &&
|
||||
test ! -s out
|
||||
(cd clonedq && git init &&
|
||||
git pull -q "../parent" >out 2>err &&
|
||||
test ! -s err &&
|
||||
test ! -s out)
|
||||
'
|
||||
|
||||
cd "$D"
|
||||
|
||||
test_expect_success 'git pull' '
|
||||
mkdir cloned &&
|
||||
cd cloned &&
|
||||
git pull "$D/parent" >out 2>err &&
|
||||
test -s out
|
||||
(cd cloned && git init &&
|
||||
git pull "../parent" >out 2>err &&
|
||||
test -s err &&
|
||||
test ! -s out)
|
||||
'
|
||||
cd "$D"
|
||||
|
||||
test_expect_success 'git pull -v' '
|
||||
mkdir clonedv &&
|
||||
cd clonedv &&
|
||||
git pull -v "$D/parent" >out 2>err &&
|
||||
test -s out
|
||||
(cd clonedv && git init &&
|
||||
git pull -v "../parent" >out 2>err &&
|
||||
test -s err &&
|
||||
test ! -s out)
|
||||
'
|
||||
|
||||
cd "$D"
|
||||
|
||||
test_expect_success 'git pull -v -q' '
|
||||
mkdir clonedvq &&
|
||||
cd clonedvq &&
|
||||
git pull -v -q "$D/parent" >out 2>err &&
|
||||
test ! -s out
|
||||
(cd clonedvq && git init &&
|
||||
git pull -v -q "../parent" >out 2>err &&
|
||||
test ! -s out &&
|
||||
test ! -s err)
|
||||
'
|
||||
|
||||
cd "$D"
|
||||
|
||||
test_expect_success 'git pull -q -v' '
|
||||
mkdir clonedqv &&
|
||||
cd clonedqv &&
|
||||
git pull -q -v "$D/parent" >out 2>err &&
|
||||
test -s out
|
||||
(cd clonedqv && git init &&
|
||||
git pull -q -v "../parent" >out 2>err &&
|
||||
test ! -s out &&
|
||||
test -s err)
|
||||
'
|
||||
|
||||
test_expect_success 'git pull --force' '
|
||||
mkdir clonedoldstyle &&
|
||||
(cd clonedoldstyle && git init &&
|
||||
cat >>.git/config <<-\EOF &&
|
||||
[remote "one"]
|
||||
url = ../parent
|
||||
fetch = refs/heads/master:refs/heads/mirror
|
||||
[remote "two"]
|
||||
url = ../parent
|
||||
fetch = refs/heads/master:refs/heads/origin
|
||||
[branch "master"]
|
||||
remote = two
|
||||
merge = refs/heads/master
|
||||
EOF
|
||||
git pull two &&
|
||||
test_commit A &&
|
||||
git branch -f origin &&
|
||||
git pull --all --force
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'git pull --all' '
|
||||
mkdir clonedmulti &&
|
||||
(cd clonedmulti && git init &&
|
||||
cat >>.git/config <<-\EOF &&
|
||||
[remote "one"]
|
||||
url = ../parent
|
||||
fetch = refs/heads/*:refs/remotes/one/*
|
||||
[remote "two"]
|
||||
url = ../parent
|
||||
fetch = refs/heads/*:refs/remotes/two/*
|
||||
[branch "master"]
|
||||
remote = one
|
||||
merge = refs/heads/master
|
||||
EOF
|
||||
git pull --all
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
@ -353,7 +353,7 @@ test_expect_success 'log grep (4)' '
|
||||
'
|
||||
|
||||
test_expect_success 'log grep (5)' '
|
||||
git log --author=Thor -F --grep=Thu --pretty=tformat:%s >actual &&
|
||||
git log --author=Thor -F --pretty=tformat:%s >actual &&
|
||||
( echo third ; echo initial ) >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
@ -364,6 +364,14 @@ test_expect_success 'log grep (6)' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'log --grep --author implicitly uses all-match' '
|
||||
# grep matches initial and second but not third
|
||||
# author matches only initial and third
|
||||
git log --author="A U Thor" --grep=s --grep=l --format=%s >actual &&
|
||||
echo initial >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'grep with CE_VALID file' '
|
||||
git update-index --assume-unchanged t/t &&
|
||||
rm t/t &&
|
||||
|
@ -166,19 +166,31 @@ test_expect_success 'checkout -m with merge conflict' '
|
||||
! test -s current
|
||||
'
|
||||
|
||||
test_expect_success 'checkout to detach HEAD' '
|
||||
test_expect_success 'checkout to detach HEAD (with advice declined)' '
|
||||
|
||||
git config advice.detachedHead false &&
|
||||
git checkout -f renamer && git clean -f &&
|
||||
git checkout renamer^ 2>messages &&
|
||||
(cat >messages.expect <<EOF
|
||||
Note: moving to '\''renamer^'\'' 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>
|
||||
HEAD is now at 7329388... Initial A one, A two
|
||||
EOF
|
||||
) &&
|
||||
test_cmp messages.expect messages &&
|
||||
grep "HEAD is now at 7329388" messages &&
|
||||
test 1 -eq $(wc -l <messages) &&
|
||||
H=$(git rev-parse --verify HEAD) &&
|
||||
M=$(git show-ref -s --verify refs/heads/master) &&
|
||||
test "z$H" = "z$M" &&
|
||||
if git symbolic-ref HEAD >/dev/null 2>&1
|
||||
then
|
||||
echo "OOPS, HEAD is still symbolic???"
|
||||
false
|
||||
else
|
||||
: happy
|
||||
fi
|
||||
'
|
||||
|
||||
test_expect_success 'checkout to detach HEAD' '
|
||||
git config advice.detachedHead true &&
|
||||
git checkout -f renamer && git clean -f &&
|
||||
git checkout renamer^ 2>messages &&
|
||||
grep "HEAD is now at 7329388" messages &&
|
||||
test 1 -lt $(wc -l <messages) &&
|
||||
H=$(git rev-parse --verify HEAD) &&
|
||||
M=$(git show-ref -s --verify refs/heads/master) &&
|
||||
test "z$H" = "z$M" &&
|
||||
|
@ -11,7 +11,15 @@ test_expect_success setup '
|
||||
echo B B B B B >two &&
|
||||
echo C C C C C >tres &&
|
||||
echo ABC >mouse &&
|
||||
git add one two tres mouse &&
|
||||
for i in 1 2 3 4 5 6 7 8 9
|
||||
do
|
||||
echo $i
|
||||
done >nine_lines &&
|
||||
for i in 1 2 3 4 5 6 7 8 9 a
|
||||
do
|
||||
echo $i
|
||||
done >ten_lines &&
|
||||
git add one two tres mouse nine_lines ten_lines &&
|
||||
test_tick &&
|
||||
GIT_AUTHOR_NAME=Initial git commit -m Initial &&
|
||||
|
||||
@ -167,4 +175,14 @@ test_expect_success 'blame -L with invalid end' '
|
||||
grep "has only 2 lines" errors
|
||||
'
|
||||
|
||||
test_expect_success 'indent of line numbers, nine lines' '
|
||||
git blame nine_lines >actual &&
|
||||
test $(grep -c " " actual) = 0
|
||||
'
|
||||
|
||||
test_expect_success 'indent of line numbers, ten lines' '
|
||||
git blame ten_lines >actual &&
|
||||
test $(grep -c " " actual) = 9
|
||||
'
|
||||
|
||||
test_done
|
||||
|
@ -226,7 +226,7 @@ test_expect_success 'gitcvs.ext.enabled = true' \
|
||||
'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
|
||||
GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false &&
|
||||
GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 master >cvs.log 2>&1 &&
|
||||
diff -q cvswork cvswork2'
|
||||
test_cmp cvswork cvswork2'
|
||||
|
||||
rm -fr cvswork2
|
||||
test_expect_success 'gitcvs.ext.enabled = false' \
|
||||
@ -247,7 +247,7 @@ test_expect_success 'gitcvs.dbname' \
|
||||
'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
|
||||
GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs.%a.%m.sqlite &&
|
||||
GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 master >cvs.log 2>&1 &&
|
||||
diff -q cvswork cvswork2 &&
|
||||
test_cmp cvswork cvswork2 &&
|
||||
test -f "$SERVERDIR/gitcvs.ext.master.sqlite" &&
|
||||
cmp "$SERVERDIR/gitcvs.master.sqlite" "$SERVERDIR/gitcvs.ext.master.sqlite"'
|
||||
|
||||
@ -257,7 +257,7 @@ test_expect_success 'gitcvs.ext.dbname' \
|
||||
GIT_DIR="$SERVERDIR" git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
|
||||
GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite &&
|
||||
GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 master >cvs.log 2>&1 &&
|
||||
diff -q cvswork cvswork2 &&
|
||||
test_cmp cvswork cvswork2 &&
|
||||
test -f "$SERVERDIR/gitcvs1.ext.master.sqlite" &&
|
||||
test ! -f "$SERVERDIR/gitcvs2.ext.master.sqlite" &&
|
||||
cmp "$SERVERDIR/gitcvs.master.sqlite" "$SERVERDIR/gitcvs1.ext.master.sqlite"'
|
||||
@ -282,7 +282,7 @@ test_expect_success 'cvs update (create new file)' \
|
||||
cd cvswork &&
|
||||
GIT_CONFIG="$git_config" cvs -Q update &&
|
||||
test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.1/" &&
|
||||
diff -q testfile1 ../testfile1'
|
||||
test_cmp testfile1 ../testfile1'
|
||||
|
||||
cd "$WORKDIR"
|
||||
test_expect_success 'cvs update (update existing file)' \
|
||||
@ -293,7 +293,7 @@ test_expect_success 'cvs update (update existing file)' \
|
||||
cd cvswork &&
|
||||
GIT_CONFIG="$git_config" cvs -Q update &&
|
||||
test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.2/" &&
|
||||
diff -q testfile1 ../testfile1'
|
||||
test_cmp testfile1 ../testfile1'
|
||||
|
||||
cd "$WORKDIR"
|
||||
#TODO: cvsserver doesn't support update w/o -d
|
||||
@ -322,7 +322,7 @@ test_expect_success 'cvs update (subdirectories)' \
|
||||
(for dir in A A/B A/B/C A/D E; do
|
||||
filename="file_in_$(echo $dir|sed -e "s#/# #g")" &&
|
||||
if test "$(echo $(grep -v ^D $dir/CVS/Entries|cut -d/ -f2,3,5))" = "$filename/1.1/" &&
|
||||
diff -q "$dir/$filename" "../$dir/$filename"; then
|
||||
test_cmp "$dir/$filename" "../$dir/$filename"; then
|
||||
:
|
||||
else
|
||||
echo >failure
|
||||
@ -349,7 +349,7 @@ test_expect_success 'cvs update (re-add deleted file)' \
|
||||
cd cvswork &&
|
||||
GIT_CONFIG="$git_config" cvs -Q update &&
|
||||
test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.4/" &&
|
||||
diff -q testfile1 ../testfile1'
|
||||
test_cmp testfile1 ../testfile1'
|
||||
|
||||
cd "$WORKDIR"
|
||||
test_expect_success 'cvs update (merge)' \
|
||||
@ -366,7 +366,7 @@ test_expect_success 'cvs update (merge)' \
|
||||
cd cvswork &&
|
||||
GIT_CONFIG="$git_config" cvs -Q update &&
|
||||
test "$(echo $(grep merge CVS/Entries|cut -d/ -f2,3,5))" = "merge/1.1/" &&
|
||||
diff -q merge ../merge &&
|
||||
test_cmp merge ../merge &&
|
||||
( echo Line 0; cat merge ) >merge.tmp &&
|
||||
mv merge.tmp merge &&
|
||||
cd "$WORKDIR" &&
|
||||
@ -377,7 +377,7 @@ test_expect_success 'cvs update (merge)' \
|
||||
cd cvswork &&
|
||||
sleep 1 && touch merge &&
|
||||
GIT_CONFIG="$git_config" cvs -Q update &&
|
||||
diff -q merge ../expected'
|
||||
test_cmp merge ../expected'
|
||||
|
||||
cd "$WORKDIR"
|
||||
|
||||
@ -402,13 +402,13 @@ test_expect_success 'cvs update (conflict merge)' \
|
||||
git push gitcvs.git >/dev/null &&
|
||||
cd cvswork &&
|
||||
GIT_CONFIG="$git_config" cvs -Q update &&
|
||||
diff -q merge ../expected.C'
|
||||
test_cmp merge ../expected.C'
|
||||
|
||||
cd "$WORKDIR"
|
||||
test_expect_success 'cvs update (-C)' \
|
||||
'cd cvswork &&
|
||||
GIT_CONFIG="$git_config" cvs -Q update -C &&
|
||||
diff -q merge ../merge'
|
||||
test_cmp merge ../merge'
|
||||
|
||||
cd "$WORKDIR"
|
||||
test_expect_success 'cvs update (merge no-op)' \
|
||||
@ -420,7 +420,7 @@ test_expect_success 'cvs update (merge no-op)' \
|
||||
cd cvswork &&
|
||||
sleep 1 && touch merge &&
|
||||
GIT_CONFIG="$git_config" cvs -Q update &&
|
||||
diff -q merge ../merge'
|
||||
test_cmp merge ../merge'
|
||||
|
||||
cd "$WORKDIR"
|
||||
test_expect_success 'cvs update (-p)' '
|
||||
|
20
wrapper.c
20
wrapper.c
@ -204,6 +204,16 @@ int xmkstemp(char *template)
|
||||
return fd;
|
||||
}
|
||||
|
||||
int xmkstemp_mode(char *template, int mode)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = git_mkstemp_mode(template, mode);
|
||||
if (fd < 0)
|
||||
die_errno("Unable to create temporary file");
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* zlib wrappers to make sure we don't silently miss errors
|
||||
* at init time.
|
||||
@ -267,10 +277,14 @@ int git_inflate(z_streamp strm, int flush)
|
||||
int odb_mkstemp(char *template, size_t limit, const char *pattern)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* we let the umask do its job, don't try to be more
|
||||
* restrictive except to remove write permission.
|
||||
*/
|
||||
int mode = 0444;
|
||||
snprintf(template, limit, "%s/%s",
|
||||
get_object_directory(), pattern);
|
||||
fd = mkstemp(template);
|
||||
fd = git_mkstemp_mode(template, mode);
|
||||
if (0 <= fd)
|
||||
return fd;
|
||||
|
||||
@ -279,7 +293,7 @@ int odb_mkstemp(char *template, size_t limit, const char *pattern)
|
||||
snprintf(template, limit, "%s/%s",
|
||||
get_object_directory(), pattern);
|
||||
safe_create_leading_directories(template);
|
||||
return xmkstemp(template);
|
||||
return xmkstemp_mode(template, mode);
|
||||
}
|
||||
|
||||
int odb_pack_keep(char *name, size_t namesz, unsigned char *sha1)
|
||||
|
Reference in New Issue
Block a user