mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge commit 'mingw/master' into devel
Conflicts: builtin-tag.c
This commit is contained in:
@@ -489,6 +489,13 @@ color.status.<slot>::
|
||||
commit.template::
|
||||
Specify a file to use as the template for new commit messages.
|
||||
|
||||
color.ui::
|
||||
When set to `always`, always use colors in all git commands which
|
||||
are capable of colored output. When false (or `never`), never. When
|
||||
set to `true` or `auto`, use colors only when the output is to the
|
||||
terminal. When more specific variables of color.* are set, they always
|
||||
take precedence over this setting. Defaults to false.
|
||||
|
||||
diff.autorefreshindex::
|
||||
When using `git diff` to compare with work tree
|
||||
files, do not consider stat-only change as changed.
|
||||
|
||||
@@ -74,8 +74,8 @@ OPTIONS
|
||||
Update only files that git already knows about. This is similar
|
||||
to what "git commit -a" does in preparation for making a commit,
|
||||
except that the update is limited to paths specified on the
|
||||
command line. If no paths are specified, all tracked files are
|
||||
updated.
|
||||
command line. If no paths are specified, all tracked files in the
|
||||
current directory and its subdirectories are updated.
|
||||
|
||||
\--refresh::
|
||||
Don't add the file(s), but only refresh their stat()
|
||||
|
||||
@@ -75,9 +75,11 @@ OPTIONS
|
||||
-n::
|
||||
Prefix the line number to matching lines.
|
||||
|
||||
-l | --files-with-matches | -L | --files-without-match::
|
||||
-l | --files-with-matches | --name-only | -L | --files-without-match::
|
||||
Instead of showing every matched line, show only the
|
||||
names of files that contain (or do not contain) matches.
|
||||
For better compatability with git-diff, --name-only is a
|
||||
synonym for --files-with-matches.
|
||||
|
||||
-c | --count::
|
||||
Instead of showing every matched line, show the number of
|
||||
|
||||
@@ -8,7 +8,7 @@ git-merge-index - Run a merge for files needing merging
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-merge-index' [-o] [-q] <merge-program> (-a | \-- | <file>\*)
|
||||
'git-merge-index' [-o] [-q] <merge-program> (-a | [--] <file>\*)
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
@@ -15,6 +15,7 @@ DESCRIPTION
|
||||
-----------
|
||||
Runs `git-fetch` with the given parameters, and calls `git-merge`
|
||||
to merge the retrieved head(s) into the current branch.
|
||||
With `--rebase`, calls `git-rebase` instead of `git-merge`.
|
||||
|
||||
Note that you can use `.` (current directory) as the
|
||||
<repository> to pull from the local repository -- this is useful
|
||||
@@ -26,19 +27,14 @@ OPTIONS
|
||||
include::merge-options.txt[]
|
||||
|
||||
:git-pull: 1
|
||||
include::fetch-options.txt[]
|
||||
|
||||
include::pull-fetch-param.txt[]
|
||||
|
||||
include::urls-remotes.txt[]
|
||||
|
||||
include::merge-strategies.txt[]
|
||||
|
||||
\--rebase::
|
||||
Instead of a merge, perform a rebase after fetching. If
|
||||
there is a remote ref for the upstream branch, and this branch
|
||||
was rebased since last fetched, the rebase uses that information
|
||||
to avoid rebasing non-local changes.
|
||||
to avoid rebasing non-local changes. To make this the default
|
||||
for branch `<name>`, set configuration `branch.<name>.rebase`
|
||||
to `true`.
|
||||
+
|
||||
*NOTE:* This is a potentially _dangerous_ mode of operation.
|
||||
It rewrites history, which does not bode well when you
|
||||
@@ -48,6 +44,14 @@ unless you have read linkgit:git-rebase[1] carefully.
|
||||
\--no-rebase::
|
||||
Override earlier \--rebase.
|
||||
|
||||
include::fetch-options.txt[]
|
||||
|
||||
include::pull-fetch-param.txt[]
|
||||
|
||||
include::urls-remotes.txt[]
|
||||
|
||||
include::merge-strategies.txt[]
|
||||
|
||||
DEFAULT BEHAVIOUR
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -47,9 +47,9 @@ even if it does not result in a fast forward update.
|
||||
+
|
||||
Note: If no explicit refspec is found, (that is neither
|
||||
on the command line nor in any Push line of the
|
||||
corresponding remotes file---see below), then all the
|
||||
heads that exist both on the local side and on the remote
|
||||
side are updated.
|
||||
corresponding remotes file---see below), then "matching" heads are
|
||||
pushed: for every head that exists on the local side, the remote side is
|
||||
updated if a head of the same name already exists on the remote side.
|
||||
+
|
||||
`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
|
||||
+
|
||||
@@ -108,6 +108,55 @@ the remote repository.
|
||||
|
||||
include::urls-remotes.txt[]
|
||||
|
||||
OUTPUT
|
||||
------
|
||||
|
||||
The output of "git push" depends on the transport method used; this
|
||||
section describes the output when pushing over the git protocol (either
|
||||
locally or via ssh).
|
||||
|
||||
The status of the push is output in tabular form, with each line
|
||||
representing the status of a single ref. Each line is of the form:
|
||||
|
||||
-------------------------------
|
||||
<flag> <summary> <from> -> <to> (<reason>)
|
||||
-------------------------------
|
||||
|
||||
flag::
|
||||
A single character indicating the status of the ref. This is
|
||||
blank for a successfully pushed ref, `!` for a ref that was
|
||||
rejected or failed to push, and '=' for a ref that was up to
|
||||
date and did not need pushing (note that the status of up to
|
||||
date refs is shown only when `git push` is running verbosely).
|
||||
|
||||
summary::
|
||||
For a successfully pushed ref, the summary shows the old and new
|
||||
values of the ref in a form suitable for using as an argument to
|
||||
`git log` (this is `<old>..<new>` in most cases, and
|
||||
`<old>...<new>` for forced non-fast forward updates). For a
|
||||
failed update, more details are given for the failure.
|
||||
The string `rejected` indicates that git did not try to send the
|
||||
ref at all (typically because it is not a fast forward). The
|
||||
string `remote rejected` indicates that the remote end refused
|
||||
the update; this rejection is typically caused by a hook on the
|
||||
remote side. The string `remote failure` indicates that the
|
||||
remote end did not report the successful update of the ref
|
||||
(perhaps because of a temporary error on the remote side, a
|
||||
break in the network connection, or other transient error).
|
||||
|
||||
from::
|
||||
The name of the local ref being pushed, minus its
|
||||
`refs/<type>/` prefix. In the case of deletion, the
|
||||
name of the local ref is omitted.
|
||||
|
||||
to::
|
||||
The name of the remote ref being updated, minus its
|
||||
`refs/<type>/` prefix.
|
||||
|
||||
reason::
|
||||
A human-readable explanation. In the case of successfully pushed
|
||||
refs, no explanation is needed. For a failed ref, the reason for
|
||||
failure is described.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
@@ -43,7 +43,7 @@ save [<message>]::
|
||||
subcommand is given. The <message> part is optional and gives
|
||||
the description along with the stashed state.
|
||||
|
||||
list::
|
||||
list [<options>]::
|
||||
|
||||
List the stashes that you currently have. Each 'stash' is listed
|
||||
with its name (e.g. `stash@\{0}` is the latest stash, `stash@\{1}` is
|
||||
@@ -55,6 +55,9 @@ list::
|
||||
stash@{0}: WIP on submit: 6ebd0e2... Update git-stash documentation
|
||||
stash@{1}: On master: 9cc0589... Add git-stash
|
||||
----------------------------------------------------------------
|
||||
+
|
||||
The command takes options applicable to the linkgit:git-log[1]
|
||||
command to control what is shown and how.
|
||||
|
||||
show [<stash>]::
|
||||
|
||||
|
||||
123
Documentation/technical/api-remote.txt
Normal file
123
Documentation/technical/api-remote.txt
Normal file
@@ -0,0 +1,123 @@
|
||||
Remotes configuration API
|
||||
=========================
|
||||
|
||||
The API in remote.h gives access to the configuration related to
|
||||
remotes. It handles all three configuration mechanisms historically
|
||||
and currently used by git, and presents the information in a uniform
|
||||
fashion. Note that the code also handles plain URLs without any
|
||||
configuration, giving them just the default information.
|
||||
|
||||
struct remote
|
||||
-------------
|
||||
|
||||
`name`::
|
||||
|
||||
The user's nickname for the remote
|
||||
|
||||
`url`::
|
||||
|
||||
An array of all of the url_nr URLs configured for the remote
|
||||
|
||||
`push`::
|
||||
|
||||
An array of refspecs configured for pushing, with
|
||||
push_refspec being the literal strings, and push_refspec_nr
|
||||
being the quantity.
|
||||
|
||||
`fetch`::
|
||||
|
||||
An array of refspecs configured for fetching, with
|
||||
fetch_refspec being the literal strings, and fetch_refspec_nr
|
||||
being the quantity.
|
||||
|
||||
`fetch_tags`::
|
||||
|
||||
The setting for whether to fetch tags (as a separate rule from
|
||||
the configured refspecs); -1 means never to fetch tags, 0
|
||||
means to auto-follow tags based on the default heuristic, 1
|
||||
means to always auto-follow tags, and 2 means to fetch all
|
||||
tags.
|
||||
|
||||
`receivepack`, `uploadpack`::
|
||||
|
||||
The configured helper programs to run on the remote side, for
|
||||
git-native protocols.
|
||||
|
||||
`http_proxy`::
|
||||
|
||||
The proxy to use for curl (http, https, ftp, etc.) URLs.
|
||||
|
||||
struct remotes can be found by name with remote_get(), and iterated
|
||||
through with for_each_remote(). remote_get(NULL) will return the
|
||||
default remote, given the current branch and configuration.
|
||||
|
||||
struct refspec
|
||||
--------------
|
||||
|
||||
A struct refspec holds the parsed interpretation of a refspec. If it
|
||||
will force updates (starts with a '+'), force is true. If it is a
|
||||
pattern (sides end with '*') pattern is true. src and dest are the two
|
||||
sides (if a pattern, only the part outside of the wildcards); if there
|
||||
is only one side, it is src, and dst is NULL; if sides exist but are
|
||||
empty (i.e., the refspec either starts or ends with ':'), the
|
||||
corresponding side is "".
|
||||
|
||||
This parsing can be done to an array of strings to give an array of
|
||||
struct refpsecs with parse_ref_spec().
|
||||
|
||||
remote_find_tracking(), given a remote and a struct refspec with
|
||||
either src or dst filled out, will fill out the other such that the
|
||||
result is in the "fetch" specification for the remote (note that this
|
||||
evaluates patterns and returns a single result).
|
||||
|
||||
struct branch
|
||||
-------------
|
||||
|
||||
Note that this may end up moving to branch.h
|
||||
|
||||
struct branch holds the configuration for a branch. It can be looked
|
||||
up with branch_get(name) for "refs/heads/{name}", or with
|
||||
branch_get(NULL) for HEAD.
|
||||
|
||||
It contains:
|
||||
|
||||
`name`::
|
||||
|
||||
The short name of the branch.
|
||||
|
||||
`refname`::
|
||||
|
||||
The full path for the branch ref.
|
||||
|
||||
`remote_name`::
|
||||
|
||||
The name of the remote listed in the configuration.
|
||||
|
||||
`remote`::
|
||||
|
||||
The struct remote for that remote.
|
||||
|
||||
`merge_name`::
|
||||
|
||||
An array of the "merge" lines in the configuration.
|
||||
|
||||
`merge`::
|
||||
|
||||
An array of the struct refspecs used for the merge lines. That
|
||||
is, merge[i]->dst is a local tracking ref which should be
|
||||
merged into this branch by default.
|
||||
|
||||
`merge_nr`::
|
||||
|
||||
The number of merge configurations
|
||||
|
||||
branch_has_merge_config() returns true if the given branch has merge
|
||||
configuration given.
|
||||
|
||||
Other stuff
|
||||
-----------
|
||||
|
||||
There is other stuff in remote.h that is related, in general, to the
|
||||
process of interacting with remotes.
|
||||
|
||||
(Daniel Barkalow)
|
||||
@@ -1,10 +1,171 @@
|
||||
run-command API
|
||||
===============
|
||||
|
||||
Talk about <run-command.h>, and things like:
|
||||
The run-command API offers a versatile tool to run sub-processes with
|
||||
redirected input and output as well as with a modified environment
|
||||
and an alternate current directory.
|
||||
|
||||
* Environment the command runs with (e.g. GIT_DIR);
|
||||
* File descriptors and pipes;
|
||||
* Exit status;
|
||||
A similar API offers the capability to run a function asynchronously,
|
||||
which is primarily used to capture the output that the function
|
||||
produces in the caller in order to process it.
|
||||
|
||||
(Hannes, Dscho, Shawn)
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
`start_command`::
|
||||
|
||||
Start a sub-process. Takes a pointer to a `struct child_process`
|
||||
that specifies the details and returns pipe FDs (if requested).
|
||||
See below for details.
|
||||
|
||||
`finish_command`::
|
||||
|
||||
Wait for the completion of a sub-process that was started with
|
||||
start_command().
|
||||
|
||||
`run_command`::
|
||||
|
||||
A convenience function that encapsulates a sequence of
|
||||
start_command() followed by finish_command(). Takes a pointer
|
||||
to a `struct child_process` that specifies the details.
|
||||
|
||||
`run_command_v_opt`, `run_command_v_opt_dir`, `run_command_v_opt_cd_env`::
|
||||
|
||||
Convenience functions that encapsulate a sequence of
|
||||
start_command() followed by finish_command(). The argument argv
|
||||
specifies the program and its arguments. The argument opt is zero
|
||||
or more of the flags `RUN_COMMAND_NO_STDIN`, `RUN_GIT_CMD`, or
|
||||
`RUN_COMMAND_STDOUT_TO_STDERR` that correspond to the members
|
||||
.no_stdin, .git_cmd, .stdout_to_stderr of `struct child_process`.
|
||||
The argument dir corresponds the member .dir. The argument env
|
||||
corresponds to the member .env.
|
||||
|
||||
`start_async`::
|
||||
|
||||
Run a function asynchronously. Takes a pointer to a `struct
|
||||
async` that specifies the details and returns a pipe FD
|
||||
from which the caller reads. See below for details.
|
||||
|
||||
`finish_async`::
|
||||
|
||||
Wait for the completeion of an asynchronous function that was
|
||||
started with start_async().
|
||||
|
||||
|
||||
Data structures
|
||||
---------------
|
||||
|
||||
* `struct child_process`
|
||||
|
||||
This describes the arguments, redirections, and environment of a
|
||||
command to run in a sub-process.
|
||||
|
||||
The caller:
|
||||
|
||||
1. allocates and clears (memset(&chld, '0', sizeof(chld));) a
|
||||
struct child_process variable;
|
||||
2. initializes the members;
|
||||
3. calls start_command();
|
||||
4. processes the data;
|
||||
5. closes file descriptors (if necessary; see below);
|
||||
6. calls finish_command().
|
||||
|
||||
The .argv member is set up as an array of string pointers (NULL
|
||||
terminated), of which .argv[0] is the program name to run (usually
|
||||
without a path). If the command to run is a git command, set argv[0] to
|
||||
the command name without the 'git-' prefix and set .git_cmd = 1.
|
||||
|
||||
The members .in, .out, .err are used to redirect stdin, stdout,
|
||||
stderr as follows:
|
||||
|
||||
. Specify 0 to request no special redirection. No new file descriptor
|
||||
is allocated. The child process simply inherits the channel from the
|
||||
parent.
|
||||
|
||||
. Specify -1 to have a pipe allocated; start_command() replaces -1
|
||||
by the pipe FD in the following way:
|
||||
|
||||
.in: Returns the writable pipe end into which the caller writes;
|
||||
the readable end of the pipe becomes the child's stdin.
|
||||
|
||||
.out, .err: Returns the readable pipe end from which the caller
|
||||
reads; the writable end of the pipe end becomes child's
|
||||
stdout/stderr.
|
||||
|
||||
The caller of start_command() must close the so returned FDs
|
||||
after it has completed reading from/writing to it!
|
||||
|
||||
. Specify a file descriptor > 0 to be used by the child:
|
||||
|
||||
.in: The FD must be readable; it becomes child's stdin.
|
||||
.out: The FD must be writable; it becomes child's stdout.
|
||||
.err > 0 is not supported.
|
||||
|
||||
The specified FD is closed by start_command(), even if it fails to
|
||||
run the sub-process!
|
||||
|
||||
. Special forms of redirection are available by setting these members
|
||||
to 1:
|
||||
|
||||
.no_stdin, .no_stdout, .no_stderr: The respective channel is
|
||||
redirected to /dev/null.
|
||||
|
||||
.stdout_to_stderr: stdout of the child is redirected to the
|
||||
parent's stderr (i.e. *not* to what .err or
|
||||
.no_stderr specify).
|
||||
|
||||
To modify the environment of the sub-process, specify an array of
|
||||
string pointers (NULL terminated) in .env:
|
||||
|
||||
. If the string is of the form "VAR=value", i.e. it contains '='
|
||||
the variable is added to the child process's environment.
|
||||
|
||||
. If the string does not contain '=', it names an environement
|
||||
variable that will be removed from the child process's envionment.
|
||||
|
||||
To specify a new initial working directory for the sub-process,
|
||||
specify it in the .dir member.
|
||||
|
||||
|
||||
* `struct async`
|
||||
|
||||
This describes a function to run asynchronously, whose purpose is
|
||||
to produce output that the caller reads.
|
||||
|
||||
The caller:
|
||||
|
||||
1. allocates and clears (memset(&asy, '0', sizeof(asy));) a
|
||||
struct async variable;
|
||||
2. initializes .proc and .data;
|
||||
3. calls start_async();
|
||||
4. processes the data by reading from the fd in .out;
|
||||
5. closes .out;
|
||||
6. calls finish_async().
|
||||
|
||||
The function pointer in .proc has the following signature:
|
||||
|
||||
int proc(int fd, void *data);
|
||||
|
||||
. fd specifies a writable file descriptor to which the function must
|
||||
write the data that it produces. The function *must* close this
|
||||
descriptor before it returns.
|
||||
|
||||
. data is the value that the caller has specified in the .data member
|
||||
of struct async.
|
||||
|
||||
. The return value of the function is 0 on success and non-zero
|
||||
on failure. If the function indicates failure, finish_async() will
|
||||
report failure as well.
|
||||
|
||||
|
||||
There are serious restrictions on what the asynchronous function can do
|
||||
because this facility is implemented by a pipe to a forked process on
|
||||
UNIX, but by a thread in the same address space on Windows:
|
||||
|
||||
. It cannot change the program's state (global variables, environment,
|
||||
etc.) in a way that the caller notices; in other words, .out is the
|
||||
only communication channel to the caller.
|
||||
|
||||
. It must not change the program's state that the caller of the
|
||||
facility also uses.
|
||||
|
||||
7
Makefile
7
Makefile
@@ -3,6 +3,9 @@ all::
|
||||
|
||||
# Define V=1 to have a more verbose compile.
|
||||
#
|
||||
# Define FREAD_READS_DIRECTORIES if your are on a system which succeeds
|
||||
# when attempting to read from an fopen'ed directory.
|
||||
#
|
||||
# Define NO_OPENSSL environment variable if you do not have OpenSSL.
|
||||
# This also implies MOZILLA_SHA1.
|
||||
#
|
||||
@@ -660,6 +663,10 @@ endif
|
||||
ifdef NO_C99_FORMAT
|
||||
BASIC_CFLAGS += -DNO_C99_FORMAT
|
||||
endif
|
||||
ifdef FREAD_READS_DIRECTORIES
|
||||
COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
|
||||
COMPAT_OBJS += compat/fopen.o
|
||||
endif
|
||||
ifdef NO_SYMLINK_HEAD
|
||||
BASIC_CFLAGS += -DNO_SYMLINK_HEAD
|
||||
endif
|
||||
|
||||
@@ -228,6 +228,18 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (*argv) {
|
||||
/* Was there an invalid path? */
|
||||
if (pathspec) {
|
||||
int num;
|
||||
for (num = 0; pathspec[num]; num++)
|
||||
; /* just counting */
|
||||
if (argc != num)
|
||||
exit(1); /* error message already given */
|
||||
} else
|
||||
exit(1); /* error message already given */
|
||||
}
|
||||
|
||||
fill_directory(&dir, pathspec, ignored_too);
|
||||
|
||||
if (show_only) {
|
||||
|
||||
@@ -1894,9 +1894,7 @@ static unsigned parse_score(const char *arg)
|
||||
|
||||
static const char *add_prefix(const char *prefix, const char *path)
|
||||
{
|
||||
if (!prefix || !prefix[0])
|
||||
return path;
|
||||
return prefix_path(prefix, strlen(prefix), path);
|
||||
return prefix_path(prefix, prefix ? strlen(prefix) : 0, path);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2369,7 +2367,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
* bottom commits we would reach while traversing as
|
||||
* uninteresting.
|
||||
*/
|
||||
prepare_revision_walk(&revs);
|
||||
if (prepare_revision_walk(&revs))
|
||||
die("revision walk setup failed");
|
||||
|
||||
if (is_null_sha1(sb.final->object.sha1)) {
|
||||
char *buf;
|
||||
|
||||
@@ -31,7 +31,7 @@ static unsigned char head_sha1[20];
|
||||
|
||||
static int branch_track = 1;
|
||||
|
||||
static int branch_use_color;
|
||||
static int branch_use_color = -1;
|
||||
static char branch_colors[][COLOR_MAXLEN] = {
|
||||
"\033[m", /* reset */
|
||||
"", /* PLAIN (normal) */
|
||||
@@ -79,12 +79,12 @@ static int git_branch_config(const char *var, const char *value)
|
||||
branch_track = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(var, value);
|
||||
return git_color_default_config(var, value);
|
||||
}
|
||||
|
||||
static const char *branch_get_color(enum color_branch ix)
|
||||
{
|
||||
if (branch_use_color)
|
||||
if (branch_use_color > 0)
|
||||
return branch_colors[ix];
|
||||
return "";
|
||||
}
|
||||
@@ -588,6 +588,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
};
|
||||
|
||||
git_config(git_branch_config);
|
||||
|
||||
if (branch_use_color == -1)
|
||||
branch_use_color = git_use_color_default;
|
||||
|
||||
track = branch_track;
|
||||
argc = parse_options(argc, argv, options, builtin_branch_usage, 0);
|
||||
if (!!delete + !!rename + !!force_create > 1)
|
||||
|
||||
@@ -29,7 +29,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
|
||||
int ignored_only = 0, baselen = 0, config_set = 0;
|
||||
int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
|
||||
struct strbuf directory;
|
||||
struct dir_struct dir;
|
||||
const char *path, *base;
|
||||
@@ -137,12 +137,15 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
||||
if (show_only && (remove_directories || matches)) {
|
||||
printf("Would remove %s\n",
|
||||
directory.buf + prefix_offset);
|
||||
} else if (quiet && (remove_directories || matches)) {
|
||||
remove_dir_recursively(&directory, 0);
|
||||
} else if (remove_directories || matches) {
|
||||
printf("Removing %s\n",
|
||||
directory.buf + prefix_offset);
|
||||
remove_dir_recursively(&directory, 0);
|
||||
if (!quiet)
|
||||
printf("Removing %s\n",
|
||||
directory.buf + prefix_offset);
|
||||
if (remove_dir_recursively(&directory, 0) != 0) {
|
||||
warning("failed to remove '%s'",
|
||||
directory.buf + prefix_offset);
|
||||
errors++;
|
||||
}
|
||||
} else if (show_only) {
|
||||
printf("Would not remove %s\n",
|
||||
directory.buf + prefix_offset);
|
||||
@@ -162,11 +165,14 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
|
||||
printf("Removing %s\n",
|
||||
ent->name + prefix_offset);
|
||||
}
|
||||
unlink(ent->name);
|
||||
if (unlink(ent->name) != 0) {
|
||||
warning("failed to remove '%s'", ent->name);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(seen);
|
||||
|
||||
strbuf_release(&directory);
|
||||
return 0;
|
||||
return (errors != 0);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "cache.h"
|
||||
#include "cache-tree.h"
|
||||
#include "color.h"
|
||||
#include "dir.h"
|
||||
#include "builtin.h"
|
||||
#include "diff.h"
|
||||
@@ -771,6 +772,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
|
||||
|
||||
git_config(git_status_config);
|
||||
|
||||
if (wt_status_use_color == -1)
|
||||
wt_status_use_color = git_use_color_default;
|
||||
|
||||
argc = parse_and_validate_options(argc, argv, builtin_status_usage);
|
||||
|
||||
index_file = prepare_index(argc, argv, prefix);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* Copyright (c) 2006 Junio C Hamano
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include "color.h"
|
||||
#include "commit.h"
|
||||
#include "blob.h"
|
||||
#include "tag.h"
|
||||
@@ -229,6 +230,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
|
||||
prefix = setup_git_directory_gently(&nongit);
|
||||
git_config(git_diff_ui_config);
|
||||
|
||||
if (diff_use_color_default == -1)
|
||||
diff_use_color_default = git_use_color_default;
|
||||
|
||||
init_revisions(&rev, prefix);
|
||||
rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
|
||||
|
||||
|
||||
@@ -383,7 +383,8 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
|
||||
|
||||
get_tags_and_duplicates(&revs.pending, &extra_refs);
|
||||
|
||||
prepare_revision_walk(&revs);
|
||||
if (prepare_revision_walk(&revs))
|
||||
die("revision walk setup failed");
|
||||
revs.diffopt.format_callback = show_filemodify;
|
||||
DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
|
||||
while ((commit = get_revision(&revs))) {
|
||||
|
||||
@@ -187,7 +187,8 @@ static void shortlog(const char *name, unsigned char *sha1,
|
||||
add_pending_object(rev, branch, name);
|
||||
add_pending_object(rev, &head->object, "^HEAD");
|
||||
head->object.flags |= UNINTERESTING;
|
||||
prepare_revision_walk(rev);
|
||||
if (prepare_revision_walk(rev))
|
||||
die("revision walk setup failed");
|
||||
while ((commit = get_revision(rev)) != NULL) {
|
||||
char *oneline, *bol, *eol;
|
||||
|
||||
|
||||
@@ -578,6 +578,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("-l", arg) ||
|
||||
!strcmp("--name-only", arg) ||
|
||||
!strcmp("--files-with-matches", arg)) {
|
||||
opt.name_only = 1;
|
||||
continue;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* 2006 Junio Hamano
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include "color.h"
|
||||
#include "commit.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
@@ -197,7 +198,8 @@ static int cmd_log_walk(struct rev_info *rev)
|
||||
if (rev->early_output)
|
||||
setup_early_output(rev);
|
||||
|
||||
prepare_revision_walk(rev);
|
||||
if (prepare_revision_walk(rev))
|
||||
die("revision walk setup failed");
|
||||
|
||||
if (rev->early_output)
|
||||
finish_early_output(rev);
|
||||
@@ -235,6 +237,10 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
|
||||
struct rev_info rev;
|
||||
|
||||
git_config(git_log_config);
|
||||
|
||||
if (diff_use_color_default == -1)
|
||||
diff_use_color_default = git_use_color_default;
|
||||
|
||||
init_revisions(&rev, prefix);
|
||||
rev.diff = 1;
|
||||
rev.simplify_history = 0;
|
||||
@@ -307,6 +313,10 @@ int cmd_show(int argc, const char **argv, const char *prefix)
|
||||
int i, count, ret = 0;
|
||||
|
||||
git_config(git_log_config);
|
||||
|
||||
if (diff_use_color_default == -1)
|
||||
diff_use_color_default = git_use_color_default;
|
||||
|
||||
init_revisions(&rev, prefix);
|
||||
rev.diff = 1;
|
||||
rev.combine_merges = 1;
|
||||
@@ -367,6 +377,10 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
|
||||
struct rev_info rev;
|
||||
|
||||
git_config(git_log_config);
|
||||
|
||||
if (diff_use_color_default == -1)
|
||||
diff_use_color_default = git_use_color_default;
|
||||
|
||||
init_revisions(&rev, prefix);
|
||||
init_reflog_walk(&rev.reflog_info);
|
||||
rev.abbrev_commit = 1;
|
||||
@@ -395,6 +409,10 @@ int cmd_log(int argc, const char **argv, const char *prefix)
|
||||
struct rev_info rev;
|
||||
|
||||
git_config(git_log_config);
|
||||
|
||||
if (diff_use_color_default == -1)
|
||||
diff_use_color_default = git_use_color_default;
|
||||
|
||||
init_revisions(&rev, prefix);
|
||||
rev.always_show_header = 1;
|
||||
cmd_log_init(argc, argv, prefix, &rev);
|
||||
@@ -556,7 +574,8 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const cha
|
||||
o2->flags ^= UNINTERESTING;
|
||||
add_pending_object(&check_rev, o1, "o1");
|
||||
add_pending_object(&check_rev, o2, "o2");
|
||||
prepare_revision_walk(&check_rev);
|
||||
if (prepare_revision_walk(&check_rev))
|
||||
die("revision walk setup failed");
|
||||
|
||||
while ((commit = get_revision(&check_rev)) != NULL) {
|
||||
/* ignore merges */
|
||||
@@ -781,7 +800,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
||||
if (!use_stdout)
|
||||
realstdout = xfdopen(xdup(1), "w");
|
||||
|
||||
prepare_revision_walk(&rev);
|
||||
if (prepare_revision_walk(&rev))
|
||||
die("revision walk setup failed");
|
||||
while ((commit = get_revision(&rev)) != NULL) {
|
||||
/* ignore merges */
|
||||
if (commit->parents && commit->parents->next)
|
||||
@@ -923,7 +943,8 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
|
||||
die("Unknown commit %s", limit);
|
||||
|
||||
/* reverse the list of commits */
|
||||
prepare_revision_walk(&revs);
|
||||
if (prepare_revision_walk(&revs))
|
||||
die("revision walk setup failed");
|
||||
while ((commit = get_revision(&revs)) != NULL) {
|
||||
/* ignore merges */
|
||||
if (commit->parents && commit->parents->next)
|
||||
|
||||
@@ -574,8 +574,17 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
||||
pathspec = get_pathspec(prefix, argv + i);
|
||||
|
||||
/* Verify that the pathspec matches the prefix */
|
||||
if (pathspec)
|
||||
if (pathspec) {
|
||||
if (argc != i) {
|
||||
int cnt;
|
||||
for (cnt = 0; pathspec[cnt]; cnt++)
|
||||
;
|
||||
if (cnt != (argc - i))
|
||||
exit(1); /* error message already given */
|
||||
}
|
||||
prefix = verify_pathspec(prefix);
|
||||
} else if (argc != i)
|
||||
exit(1); /* error message already given */
|
||||
|
||||
/* Treat unmatching pathspec elements as errors */
|
||||
if (pathspec && error_unmatch) {
|
||||
|
||||
10
builtin-mv.c
10
builtin-mv.c
@@ -19,6 +19,7 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
|
||||
int count, int base_name)
|
||||
{
|
||||
int i;
|
||||
int len = prefix ? strlen(prefix) : 0;
|
||||
const char **result = xmalloc((count + 1) * sizeof(const char *));
|
||||
memcpy(result, pathspec, count * sizeof(const char *));
|
||||
result[count] = NULL;
|
||||
@@ -32,8 +33,11 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
|
||||
if (last_slash)
|
||||
result[i] = last_slash + 1;
|
||||
}
|
||||
result[i] = prefix_path(prefix, len, result[i]);
|
||||
if (!result[i])
|
||||
exit(1); /* error already given */
|
||||
}
|
||||
return get_pathspec(prefix, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void show_list(const char *label, struct path_list *list)
|
||||
@@ -164,7 +168,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
dst = add_slash(dst);
|
||||
dst_len = strlen(dst) - 1;
|
||||
dst_len = strlen(dst);
|
||||
|
||||
for (j = 0; j < last - first; j++) {
|
||||
const char *path =
|
||||
@@ -172,7 +176,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
source[argc + j] = path;
|
||||
destination[argc + j] =
|
||||
prefix_path(dst, dst_len,
|
||||
path + length);
|
||||
path + length + 1);
|
||||
modes[argc + j] = INDEX;
|
||||
}
|
||||
argc += last - first;
|
||||
|
||||
@@ -2033,7 +2033,8 @@ static void get_object_list(int ac, const char **av)
|
||||
die("bad revision '%s'", line);
|
||||
}
|
||||
|
||||
prepare_revision_walk(&revs);
|
||||
if (prepare_revision_walk(&revs))
|
||||
die("revision walk setup failed");
|
||||
mark_edges_uninteresting(revs.commits, &revs, show_edge);
|
||||
traverse_commit_list(&revs, show_commit, show_object);
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ static int do_push(const char *repo, int flags)
|
||||
if (!err)
|
||||
continue;
|
||||
|
||||
error("failed to push to '%s'", remote->url[i]);
|
||||
error("failed to push some refs to '%s'", remote->url[i]);
|
||||
errs++;
|
||||
}
|
||||
return !!errs;
|
||||
|
||||
@@ -45,7 +45,7 @@ static int read_cache_unmerged(void)
|
||||
continue;
|
||||
cache_tree_invalidate_path(active_cache_tree, ce->name);
|
||||
last = ce;
|
||||
ce->ce_flags |= CE_REMOVE;
|
||||
continue;
|
||||
}
|
||||
*dst++ = ce;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,8 @@ static void show_commit(struct commit *commit)
|
||||
fputs(header_prefix, stdout);
|
||||
if (commit->object.flags & BOUNDARY)
|
||||
putchar('-');
|
||||
else if (commit->object.flags & UNINTERESTING)
|
||||
putchar('^');
|
||||
else if (revs.left_right) {
|
||||
if (commit->object.flags & SYMMETRIC_LEFT)
|
||||
putchar('<');
|
||||
@@ -84,7 +86,7 @@ static void show_commit(struct commit *commit)
|
||||
else
|
||||
putchar('\n');
|
||||
|
||||
if (revs.verbose_header) {
|
||||
if (revs.verbose_header && commit->buffer) {
|
||||
struct strbuf buf;
|
||||
strbuf_init(&buf, 0);
|
||||
pretty_print_commit(revs.commit_format, commit,
|
||||
@@ -609,7 +611,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
|
||||
if (bisect_list)
|
||||
revs.limited = 1;
|
||||
|
||||
prepare_revision_walk(&revs);
|
||||
if (prepare_revision_walk(&revs))
|
||||
die("revision walk setup failed");
|
||||
if (revs.tree_objects)
|
||||
mark_edges_uninteresting(revs.commits, &revs, show_edge);
|
||||
|
||||
|
||||
@@ -136,7 +136,8 @@ static void get_from_rev(struct rev_info *rev, struct path_list *list)
|
||||
{
|
||||
struct commit *commit;
|
||||
|
||||
prepare_revision_walk(rev);
|
||||
if (prepare_revision_walk(rev))
|
||||
die("revision walk setup failed");
|
||||
while ((commit = get_revision(rev)) != NULL) {
|
||||
const char *author = NULL, *buffer;
|
||||
|
||||
|
||||
@@ -86,6 +86,9 @@ match:
|
||||
sha1_to_hex(sha1));
|
||||
if (obj->type == OBJ_TAG) {
|
||||
obj = deref_tag(obj, refname, 0);
|
||||
if (!obj)
|
||||
die("git-show-ref: bad tag at ref %s (%s)", refname,
|
||||
sha1_to_hex(sha1));
|
||||
hex = find_unique_abbrev(obj->sha1, abbrev);
|
||||
printf("%s %s^{}\n", hex, refname);
|
||||
}
|
||||
|
||||
@@ -236,9 +236,6 @@ static int do_sign(struct strbuf *buffer)
|
||||
if (finish_command(&gpg) || !len || len < 0)
|
||||
return error("gpg failed to sign the tag");
|
||||
|
||||
if (len < 0)
|
||||
return error("could not read the entire signature from gpg.");
|
||||
|
||||
#ifdef __MINGW32__
|
||||
/* strip CR from the line endings */
|
||||
{
|
||||
|
||||
3
bundle.c
3
bundle.c
@@ -128,7 +128,8 @@ int verify_bundle(struct bundle_header *header, int verbose)
|
||||
add_object_array(e->item, e->name, &refs);
|
||||
}
|
||||
|
||||
prepare_revision_walk(&revs);
|
||||
if (prepare_revision_walk(&revs))
|
||||
die("revision walk setup failed");
|
||||
|
||||
i = req_nr;
|
||||
while (i && (commit = get_revision(&revs)))
|
||||
|
||||
12
color.c
12
color.c
@@ -3,6 +3,8 @@
|
||||
|
||||
#define COLOR_RESET "\033[m"
|
||||
|
||||
int git_use_color_default = 0;
|
||||
|
||||
static int parse_color(const char *name, int len)
|
||||
{
|
||||
static const char * const color_names[] = {
|
||||
@@ -143,6 +145,16 @@ int git_config_colorbool(const char *var, const char *value, int stdout_is_tty)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_color_default_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "color.ui")) {
|
||||
git_use_color_default = git_config_colorbool(var, value, -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
|
||||
va_list args, const char *trail)
|
||||
{
|
||||
|
||||
11
color.h
11
color.h
@@ -4,6 +4,17 @@
|
||||
/* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */
|
||||
#define COLOR_MAXLEN 24
|
||||
|
||||
/*
|
||||
* This variable stores the value of color.ui
|
||||
*/
|
||||
extern int git_use_color_default;
|
||||
|
||||
|
||||
/*
|
||||
* Use this instead of git_default_config if you need the value of color.ui.
|
||||
*/
|
||||
int git_color_default_config(const char *var, const char *value);
|
||||
|
||||
int git_config_colorbool(const char *var, const char *value, int stdout_is_tty);
|
||||
void color_parse(const char *var, const char *value, char *dst);
|
||||
int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
|
||||
|
||||
14
commit.c
14
commit.c
@@ -311,6 +311,8 @@ int parse_commit(struct commit *item)
|
||||
unsigned long size;
|
||||
int ret;
|
||||
|
||||
if (!item)
|
||||
return -1;
|
||||
if (item->object.parsed)
|
||||
return 0;
|
||||
buffer = read_sha1_file(item->object.sha1, &type, &size);
|
||||
@@ -385,8 +387,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
|
||||
|
||||
while (parents) {
|
||||
struct commit *commit = parents->item;
|
||||
parse_commit(commit);
|
||||
if (!(commit->object.flags & mark)) {
|
||||
if (!parse_commit(commit) && !(commit->object.flags & mark)) {
|
||||
commit->object.flags |= mark;
|
||||
insert_by_date(commit, list);
|
||||
}
|
||||
@@ -552,8 +553,10 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two)
|
||||
*/
|
||||
return commit_list_insert(one, &result);
|
||||
|
||||
parse_commit(one);
|
||||
parse_commit(two);
|
||||
if (parse_commit(one))
|
||||
return NULL;
|
||||
if (parse_commit(two))
|
||||
return NULL;
|
||||
|
||||
one->object.flags |= PARENT1;
|
||||
two->object.flags |= PARENT2;
|
||||
@@ -586,7 +589,8 @@ static struct commit_list *merge_bases(struct commit *one, struct commit *two)
|
||||
parents = parents->next;
|
||||
if ((p->object.flags & flags) == flags)
|
||||
continue;
|
||||
parse_commit(p);
|
||||
if (parse_commit(p))
|
||||
return NULL;
|
||||
p->object.flags |= flags;
|
||||
insert_by_date(p, &list);
|
||||
}
|
||||
|
||||
26
compat/fopen.c
Normal file
26
compat/fopen.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "../git-compat-util.h"
|
||||
#undef fopen
|
||||
FILE *git_fopen(const char *path, const char *mode)
|
||||
{
|
||||
FILE *fp;
|
||||
struct stat st;
|
||||
|
||||
if (mode[0] == 'w' || mode[0] == 'a')
|
||||
return fopen(path, mode);
|
||||
|
||||
if (!(fp = fopen(path, mode)))
|
||||
return NULL;
|
||||
|
||||
if (fstat(fileno(fp), &st)) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
fclose(fp);
|
||||
errno = EISDIR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
@@ -315,12 +315,14 @@ repeat:
|
||||
|
||||
struct tm *gmtime_r(const time_t *timep, struct tm *result)
|
||||
{
|
||||
/* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */
|
||||
memcpy(result, gmtime(timep), sizeof(struct tm));
|
||||
return result;
|
||||
}
|
||||
|
||||
struct tm *localtime_r(const time_t *timep, struct tm *result)
|
||||
{
|
||||
/* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */
|
||||
memcpy(result, localtime(timep), sizeof(struct tm));
|
||||
return result;
|
||||
}
|
||||
@@ -778,7 +780,7 @@ char **env_setenv(char **env, const char *name)
|
||||
}
|
||||
|
||||
/* this is the first function to call into WS_32; initialize it */
|
||||
#undef gethostbyname
|
||||
#undef gethostbyname
|
||||
struct hostent *mingw_gethostbyname(const char *host)
|
||||
{
|
||||
WSADATA wsa;
|
||||
@@ -911,7 +913,7 @@ static sig_handler_t timer_fn = SIG_DFL;
|
||||
* wait state every now and then, namely exactly after timer's interval
|
||||
* length. At these opportunities it calls the signal handler.
|
||||
*/
|
||||
|
||||
|
||||
static __stdcall unsigned ticktack(void *dummy)
|
||||
{
|
||||
while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
|
||||
|
||||
11
config.c
11
config.c
@@ -280,11 +280,18 @@ int git_parse_ulong(const char *value, unsigned long *ret)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void die_bad_config(const char *name)
|
||||
{
|
||||
if (config_file_name)
|
||||
die("bad config value for '%s' in %s", name, config_file_name);
|
||||
die("bad config value for '%s'", name);
|
||||
}
|
||||
|
||||
int git_config_int(const char *name, const char *value)
|
||||
{
|
||||
long ret;
|
||||
if (!git_parse_long(value, &ret))
|
||||
die("bad config value for '%s' in %s", name, config_file_name);
|
||||
die_bad_config(name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -292,7 +299,7 @@ unsigned long git_config_ulong(const char *name, const char *value)
|
||||
{
|
||||
unsigned long ret;
|
||||
if (!git_parse_ulong(value, &ret))
|
||||
die("bad config value for '%s' in %s", name, config_file_name);
|
||||
die_bad_config(name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -185,9 +185,8 @@ if there is already one that displays the same directory."
|
||||
|
||||
(defun git-call-process-env (buffer env &rest args)
|
||||
"Wrapper for call-process that sets environment strings."
|
||||
(if env
|
||||
(apply #'call-process "env" nil buffer nil
|
||||
(append (git-get-env-strings env) (list "git") args))
|
||||
(let ((process-environment (append (git-get-env-strings env)
|
||||
process-environment)))
|
||||
(apply #'call-process "git" nil buffer nil args)))
|
||||
|
||||
(defun git-call-process-display-error (&rest args)
|
||||
@@ -204,7 +203,7 @@ if there is already one that displays the same directory."
|
||||
|
||||
(defun git-call-process-env-string (env &rest args)
|
||||
"Wrapper for call-process that sets environment strings,
|
||||
and returns the process output as a string."
|
||||
and returns the process output as a string, or nil if the git failed."
|
||||
(with-temp-buffer
|
||||
(and (eq 0 (apply #' git-call-process-env t env args))
|
||||
(buffer-string))))
|
||||
|
||||
8
diff.c
8
diff.c
@@ -20,7 +20,7 @@
|
||||
|
||||
static int diff_detect_rename_default;
|
||||
static int diff_rename_limit_default = 100;
|
||||
static int diff_use_color_default;
|
||||
int diff_use_color_default = -1;
|
||||
static const char *external_diff_cmd_cfg;
|
||||
int diff_auto_refresh_index = 1;
|
||||
|
||||
@@ -191,7 +191,7 @@ int git_diff_basic_config(const char *var, const char *value)
|
||||
}
|
||||
}
|
||||
|
||||
return git_default_config(var, value);
|
||||
return git_color_default_config(var, value);
|
||||
}
|
||||
|
||||
static char *quote_two(const char *one, const char *two)
|
||||
@@ -1199,7 +1199,7 @@ static struct builtin_funcname_pattern {
|
||||
"new\\|return\\|switch\\|throw\\|while\\)\n"
|
||||
"^[ ]*\\(\\([ ]*"
|
||||
"[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}"
|
||||
"[ ]*([^;]*$\\)" },
|
||||
"[ ]*([^;]*\\)$" },
|
||||
{ "tex", "^\\(\\\\\\(sub\\)*section{.*\\)$" },
|
||||
};
|
||||
|
||||
@@ -2055,7 +2055,7 @@ void diff_setup(struct diff_options *options)
|
||||
|
||||
options->change = diff_change;
|
||||
options->add_remove = diff_addremove;
|
||||
if (diff_use_color_default)
|
||||
if (diff_use_color_default > 0)
|
||||
DIFF_OPT_SET(options, COLOR_DIFF);
|
||||
else
|
||||
DIFF_OPT_CLR(options, COLOR_DIFF);
|
||||
|
||||
1
diff.h
1
diff.h
@@ -174,6 +174,7 @@ extern void diff_unmerge(struct diff_options *,
|
||||
|
||||
extern int git_diff_basic_config(const char *var, const char *value);
|
||||
extern int git_diff_ui_config(const char *var, const char *value);
|
||||
extern int diff_use_color_default;
|
||||
extern void diff_setup(struct diff_options *);
|
||||
extern int diff_opt_parse(struct diff_options *, const char **, int);
|
||||
extern int diff_setup_done(struct diff_options *);
|
||||
|
||||
@@ -82,6 +82,19 @@ sub list_untracked {
|
||||
my $status_fmt = '%12s %12s %s';
|
||||
my $status_head = sprintf($status_fmt, 'staged', 'unstaged', 'path');
|
||||
|
||||
{
|
||||
my $initial;
|
||||
sub is_initial_commit {
|
||||
$initial = system('git rev-parse HEAD -- >/dev/null 2>&1') != 0
|
||||
unless defined $initial;
|
||||
return $initial;
|
||||
}
|
||||
}
|
||||
|
||||
sub get_empty_tree {
|
||||
return '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
|
||||
}
|
||||
|
||||
# Returns list of hashes, contents of each of which are:
|
||||
# VALUE: pathname
|
||||
# BINARY: is a binary path
|
||||
@@ -103,8 +116,10 @@ sub list_modified {
|
||||
return if (!@tracked);
|
||||
}
|
||||
|
||||
my $reference = is_initial_commit() ? get_empty_tree() : 'HEAD';
|
||||
for (run_cmd_pipe(qw(git diff-index --cached
|
||||
--numstat --summary HEAD --), @tracked)) {
|
||||
--numstat --summary), $reference,
|
||||
'--', @tracked)) {
|
||||
if (($add, $del, $file) =
|
||||
/^([-\d]+) ([-\d]+) (.*)/) {
|
||||
my ($change, $bin);
|
||||
@@ -476,21 +491,27 @@ sub revert_cmd {
|
||||
HEADER => $status_head, },
|
||||
list_modified());
|
||||
if (@update) {
|
||||
my @lines = run_cmd_pipe(qw(git ls-tree HEAD --),
|
||||
map { $_->{VALUE} } @update);
|
||||
my $fh;
|
||||
open $fh, '| git update-index --index-info'
|
||||
or die;
|
||||
for (@lines) {
|
||||
print $fh $_;
|
||||
if (is_initial_commit()) {
|
||||
system(qw(git rm --cached),
|
||||
map { $_->{VALUE} } @update);
|
||||
}
|
||||
close($fh);
|
||||
for (@update) {
|
||||
if ($_->{INDEX_ADDDEL} &&
|
||||
$_->{INDEX_ADDDEL} eq 'create') {
|
||||
system(qw(git update-index --force-remove --),
|
||||
$_->{VALUE});
|
||||
print "note: $_->{VALUE} is untracked now.\n";
|
||||
else {
|
||||
my @lines = run_cmd_pipe(qw(git ls-tree HEAD --),
|
||||
map { $_->{VALUE} } @update);
|
||||
my $fh;
|
||||
open $fh, '| git update-index --index-info'
|
||||
or die;
|
||||
for (@lines) {
|
||||
print $fh $_;
|
||||
}
|
||||
close($fh);
|
||||
for (@update) {
|
||||
if ($_->{INDEX_ADDDEL} &&
|
||||
$_->{INDEX_ADDDEL} eq 'create') {
|
||||
system(qw(git update-index --force-remove --),
|
||||
$_->{VALUE});
|
||||
print "note: $_->{VALUE} is untracked now.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
refresh();
|
||||
@@ -956,7 +977,9 @@ sub diff_cmd {
|
||||
HEADER => $status_head, },
|
||||
@mods);
|
||||
return if (!@them);
|
||||
system(qw(git diff -p --cached HEAD --), map { $_->{VALUE} } @them);
|
||||
my $reference = is_initial_commit() ? get_empty_tree() : 'HEAD';
|
||||
system(qw(git diff -p --cached), $reference, '--',
|
||||
map { $_->{VALUE} } @them);
|
||||
}
|
||||
|
||||
sub quit_cmd {
|
||||
|
||||
@@ -331,9 +331,9 @@ bisect_visualize() {
|
||||
|
||||
if test $# = 0
|
||||
then
|
||||
case "${DISPLAY+set}" in
|
||||
case "${DISPLAY+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" in
|
||||
'') set git log ;;
|
||||
set) set gitk ;;
|
||||
set*) set gitk ;;
|
||||
esac
|
||||
else
|
||||
case "$1" in
|
||||
|
||||
18
git-clone.sh
18
git-clone.sh
@@ -461,11 +461,12 @@ else
|
||||
cd "$D" || exit
|
||||
fi
|
||||
|
||||
if test -z "$bare" && test -f "$GIT_DIR/REMOTE_HEAD"
|
||||
if test -z "$bare"
|
||||
then
|
||||
# a non-bare repository is always in separate-remote layout
|
||||
remote_top="refs/remotes/$origin"
|
||||
head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"`
|
||||
head_sha1=
|
||||
test ! -r "$GIT_DIR/REMOTE_HEAD" || head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"`
|
||||
case "$head_sha1" in
|
||||
'ref: refs/'*)
|
||||
# Uh-oh, the remote told us (http transport done against
|
||||
@@ -522,9 +523,16 @@ then
|
||||
git config branch."$head_points_at".merge "refs/heads/$head_points_at"
|
||||
;;
|
||||
'')
|
||||
# Source had detached HEAD pointing nowhere
|
||||
git update-ref --no-deref HEAD "$head_sha1" &&
|
||||
rm -f "refs/remotes/$origin/HEAD"
|
||||
if test -z "$head_sha1"
|
||||
then
|
||||
# Source had nonexistent ref in HEAD
|
||||
echo >&2 "Warning: Remote HEAD refers to nonexistent ref, unable to checkout."
|
||||
no_checkout=t
|
||||
else
|
||||
# Source had detached HEAD pointing nowhere
|
||||
git update-ref --no-deref HEAD "$head_sha1" &&
|
||||
rm -f "refs/remotes/$origin/HEAD"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
@@ -214,6 +214,11 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
|
||||
const void *needle, size_t needlelen);
|
||||
#endif
|
||||
|
||||
#ifdef FREAD_READS_DIRECTORIES
|
||||
#define fopen(a,b) git_fopen(a,b)
|
||||
extern FILE *git_fopen(const char*, const char*);
|
||||
#endif
|
||||
|
||||
#ifdef __GLIBC_PREREQ
|
||||
#if __GLIBC_PREREQ(2, 1)
|
||||
#define HAVE_STRCHRNUL
|
||||
|
||||
@@ -197,15 +197,39 @@ if (@canstatusfiles) {
|
||||
my @updated = xargs_safe_pipe_capture([@cvs, 'update'], @canstatusfiles);
|
||||
print @updated;
|
||||
}
|
||||
my @cvsoutput;
|
||||
@cvsoutput = xargs_safe_pipe_capture([@cvs, 'status'], @canstatusfiles);
|
||||
my $matchcount = 0;
|
||||
foreach my $l (@cvsoutput) {
|
||||
chomp $l;
|
||||
if ( $l =~ /^File:/ and $l =~ /Status: (.*)$/ ) {
|
||||
$cvsstat{$canstatusfiles[$matchcount]} = $1;
|
||||
$matchcount++;
|
||||
# "cvs status" reorders the parameters, notably when there are multiple
|
||||
# arguments with the same basename. So be precise here.
|
||||
|
||||
my %added = map { $_ => 1 } @afiles;
|
||||
my %todo = map { $_ => 1 } @canstatusfiles;
|
||||
|
||||
while (%todo) {
|
||||
my @canstatusfiles2 = ();
|
||||
my %fullname = ();
|
||||
foreach my $name (keys %todo) {
|
||||
my $basename = basename($name);
|
||||
|
||||
$basename = "no file " . $basename if (exists($added{$basename}));
|
||||
chomp($basename);
|
||||
|
||||
if (!exists($fullname{$basename})) {
|
||||
$fullname{$basename} = $name;
|
||||
push (@canstatusfiles2, $name);
|
||||
delete($todo{$name});
|
||||
}
|
||||
}
|
||||
my @cvsoutput;
|
||||
@cvsoutput = xargs_safe_pipe_capture([@cvs, 'status'], @canstatusfiles2);
|
||||
foreach my $l (@cvsoutput) {
|
||||
chomp $l;
|
||||
if ($l =~ /^File:\s+(.*\S)\s+Status: (.*)$/) {
|
||||
if (!exists($fullname{$1})) {
|
||||
print STDERR "Huh? Status reported for unexpected file '$1'\n";
|
||||
} else {
|
||||
$cvsstat{$fullname{$1}} = $2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +170,9 @@ my $envelope_sender;
|
||||
|
||||
my $repo = Git->repository();
|
||||
my $term = eval {
|
||||
new Term::ReadLine 'git-send-email';
|
||||
$ENV{"GIT_SEND_EMAIL_NOTTY"}
|
||||
? new Term::ReadLine 'git-send-email', \*STDIN, \*STDOUT
|
||||
: new Term::ReadLine 'git-send-email';
|
||||
};
|
||||
if ($@) {
|
||||
$term = new FakeTerm "$@: going non-interactive";
|
||||
@@ -475,9 +477,10 @@ if ($thread && !defined $initial_reply_to && $prompting) {
|
||||
|
||||
$initial_reply_to = $_;
|
||||
}
|
||||
if (defined $initial_reply_to && $_ ne "") {
|
||||
$initial_reply_to =~ s/^\s*<?/</;
|
||||
$initial_reply_to =~ s/>?\s*$/>/;
|
||||
if (defined $initial_reply_to) {
|
||||
$initial_reply_to =~ s/^\s*<?//;
|
||||
$initial_reply_to =~ s/>?\s*$//;
|
||||
$initial_reply_to = "<$initial_reply_to>" if $initial_reply_to ne '';
|
||||
}
|
||||
|
||||
if (!defined $smtp_server) {
|
||||
|
||||
@@ -127,20 +127,14 @@ get_author_ident_from_commit () {
|
||||
# if we require to be in a git repository.
|
||||
if test -z "$NONGIT_OK"
|
||||
then
|
||||
GIT_DIR=$(git rev-parse --git-dir) || exit
|
||||
if [ -z "$SUBDIRECTORY_OK" ]
|
||||
then
|
||||
: ${GIT_DIR=.git}
|
||||
test -z "$(git rev-parse --show-cdup)" || {
|
||||
exit=$?
|
||||
echo >&2 "You need to run this command from the toplevel of the working tree."
|
||||
exit $exit
|
||||
}
|
||||
else
|
||||
GIT_DIR=$(git rev-parse --git-dir) || {
|
||||
exit=$?
|
||||
echo >&2 "Failed to find a valid git directory."
|
||||
exit $exit
|
||||
}
|
||||
fi
|
||||
test -n "$GIT_DIR" && GIT_DIR=$(cd "$GIT_DIR" && pwd) || {
|
||||
echo >&2 "Unable to determine absolute path of git directory"
|
||||
|
||||
69
git.spec.in
69
git.spec.in
@@ -3,7 +3,7 @@
|
||||
Name: git
|
||||
Version: @@VERSION@@
|
||||
Release: 1%{?dist}
|
||||
Summary: Git core and tools
|
||||
Summary: Core git tools
|
||||
License: GPL
|
||||
Group: Development/Tools
|
||||
URL: http://kernel.org/pub/software/scm/git/
|
||||
@@ -11,80 +11,86 @@ Source: http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz
|
||||
BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel, gettext %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
|
||||
Requires: git-core = %{version}-%{release}
|
||||
Requires: git-svn = %{version}-%{release}
|
||||
Requires: git-cvs = %{version}-%{release}
|
||||
Requires: git-arch = %{version}-%{release}
|
||||
Requires: git-email = %{version}-%{release}
|
||||
Requires: gitk = %{version}-%{release}
|
||||
Requires: git-gui = %{version}-%{release}
|
||||
Requires: perl-Git = %{version}-%{release}
|
||||
Requires: zlib >= 1.2, rsync, curl, less, openssh-clients, expat
|
||||
Provides: git-core = %{version}-%{release}
|
||||
Obsoletes: git-core <= 1.5.4.2
|
||||
Obsoletes: git-p4
|
||||
|
||||
%description
|
||||
Git is a fast, scalable, distributed revision control system with an
|
||||
unusually rich command set that provides both high-level operations
|
||||
and full access to internals.
|
||||
|
||||
This is a dummy package which brings in all subpackages.
|
||||
The git rpm installs the core tools with minimal dependencies. To
|
||||
install all git packages, including tools for integrating with other
|
||||
SCMs, install the git-all meta-package.
|
||||
|
||||
%package core
|
||||
Summary: Core git tools
|
||||
%package all
|
||||
Summary: Meta-package to pull in all git tools
|
||||
Group: Development/Tools
|
||||
Requires: zlib >= 1.2, rsync, curl, less, openssh-clients, expat
|
||||
Obsoletes: git-p4
|
||||
%description core
|
||||
Requires: git = %{version}-%{release}
|
||||
Requires: git-svn = %{version}-%{release}
|
||||
Requires: git-cvs = %{version}-%{release}
|
||||
Requires: git-arch = %{version}-%{release}
|
||||
Requires: git-email = %{version}-%{release}
|
||||
Requires: gitk = %{version}-%{release}
|
||||
Requires: git-gui = %{version}-%{release}
|
||||
Obsoletes: git <= 1.5.4.2
|
||||
|
||||
%description all
|
||||
Git is a fast, scalable, distributed revision control system with an
|
||||
unusually rich command set that provides both high-level operations
|
||||
and full access to internals.
|
||||
|
||||
These are the core tools with minimal dependencies.
|
||||
This is a dummy package which brings in all subpackages.
|
||||
|
||||
%package svn
|
||||
Summary: Git tools for importing Subversion repositories
|
||||
Group: Development/Tools
|
||||
Requires: git-core = %{version}-%{release}, subversion
|
||||
Requires: git = %{version}-%{release}, subversion
|
||||
%description svn
|
||||
Git tools for importing Subversion repositories.
|
||||
|
||||
%package cvs
|
||||
Summary: Git tools for importing CVS repositories
|
||||
Group: Development/Tools
|
||||
Requires: git-core = %{version}-%{release}, cvs, cvsps
|
||||
Requires: git = %{version}-%{release}, cvs, cvsps
|
||||
%description cvs
|
||||
Git tools for importing CVS repositories.
|
||||
|
||||
%package arch
|
||||
Summary: Git tools for importing Arch repositories
|
||||
Group: Development/Tools
|
||||
Requires: git-core = %{version}-%{release}, tla
|
||||
Requires: git = %{version}-%{release}, tla
|
||||
%description arch
|
||||
Git tools for importing Arch repositories.
|
||||
|
||||
%package email
|
||||
Summary: Git tools for sending email
|
||||
Group: Development/Tools
|
||||
Requires: git-core = %{version}-%{release}
|
||||
Requires: git = %{version}-%{release}
|
||||
%description email
|
||||
Git tools for sending email.
|
||||
|
||||
%package gui
|
||||
Summary: Git GUI tool
|
||||
Group: Development/Tools
|
||||
Requires: git-core = %{version}-%{release}, tk >= 8.4
|
||||
Requires: git = %{version}-%{release}, tk >= 8.4
|
||||
%description gui
|
||||
Git GUI tool
|
||||
|
||||
%package -n gitk
|
||||
Summary: Git revision tree visualiser ('gitk')
|
||||
Group: Development/Tools
|
||||
Requires: git-core = %{version}-%{release}, tk >= 8.4
|
||||
Requires: git = %{version}-%{release}, tk >= 8.4
|
||||
%description -n gitk
|
||||
Git revision tree visualiser ('gitk')
|
||||
|
||||
%package -n perl-Git
|
||||
Summary: Perl interface to Git
|
||||
Group: Development/Libraries
|
||||
Requires: git-core = %{version}-%{release}
|
||||
Requires: git = %{version}-%{release}
|
||||
Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version))
|
||||
BuildRequires: perl(Error)
|
||||
|
||||
@@ -121,8 +127,12 @@ rm -rf $RPM_BUILD_ROOT%{_mandir}
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
# These are no files in the root package
|
||||
%files -f bin-man-doc-files
|
||||
%defattr(-,root,root)
|
||||
%{_datadir}/git-core/
|
||||
%doc README COPYING Documentation/*.txt
|
||||
%{!?_without_docs: %doc Documentation/*.html Documentation/howto}
|
||||
%{!?_without_docs: %doc Documentation/technical}
|
||||
|
||||
%files svn
|
||||
%defattr(-,root,root)
|
||||
@@ -173,14 +183,13 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%files -n perl-Git -f perl-files
|
||||
%defattr(-,root,root)
|
||||
|
||||
%files core -f bin-man-doc-files
|
||||
%defattr(-,root,root)
|
||||
%{_datadir}/git-core/
|
||||
%doc README COPYING Documentation/*.txt
|
||||
%{!?_without_docs: %doc Documentation/*.html Documentation/howto}
|
||||
%{!?_without_docs: %doc Documentation/technical}
|
||||
%files all
|
||||
# No files for you!
|
||||
|
||||
%changelog
|
||||
* Fri Feb 15 2008 Kristian Høgsberg <krh@redhat.com>
|
||||
- Rename git-core to just git and rename meta package from git to git-all.
|
||||
|
||||
* Sun Feb 03 2008 James Bowes <jbowes@dangerouslyinc.com>
|
||||
- Add a BuildRequires for gettext
|
||||
|
||||
|
||||
@@ -233,6 +233,10 @@ You can use the following files in repository:
|
||||
Displayed in the project summary page. You can use multiple-valued
|
||||
gitweb.url repository configuration variable for that, but the file
|
||||
takes precendence.
|
||||
* gitweb.owner
|
||||
You can use the gitweb.owner repository configuration variable to set
|
||||
repository's owner. It is displayed in the project list and summary
|
||||
page. If it's not set, filesystem directory's owner is used.
|
||||
* various gitweb.* config variables (in config)
|
||||
Read description of %feature hash for detailed list, and some
|
||||
descriptions.
|
||||
|
||||
@@ -611,6 +611,8 @@ sub href(%) {
|
||||
);
|
||||
my %mapping = @mapping;
|
||||
|
||||
$params{'project'} = $project unless exists $params{'project'};
|
||||
|
||||
if ($params{-replay}) {
|
||||
while (my ($name, $symbol) = each %mapping) {
|
||||
if (!exists $params{$name}) {
|
||||
@@ -620,8 +622,6 @@ sub href(%) {
|
||||
}
|
||||
}
|
||||
|
||||
$params{'project'} = $project unless exists $params{'project'};
|
||||
|
||||
my ($use_pathinfo) = gitweb_check_feature('pathinfo');
|
||||
if ($use_pathinfo) {
|
||||
# use PATH_INFO for project name
|
||||
@@ -753,29 +753,40 @@ sub esc_path {
|
||||
# Make control characters "printable", using character escape codes (CEC)
|
||||
sub quot_cec {
|
||||
my $cntrl = shift;
|
||||
my %opts = @_;
|
||||
my %es = ( # character escape codes, aka escape sequences
|
||||
"\t" => '\t', # tab (HT)
|
||||
"\n" => '\n', # line feed (LF)
|
||||
"\r" => '\r', # carrige return (CR)
|
||||
"\f" => '\f', # form feed (FF)
|
||||
"\b" => '\b', # backspace (BS)
|
||||
"\a" => '\a', # alarm (bell) (BEL)
|
||||
"\e" => '\e', # escape (ESC)
|
||||
"\013" => '\v', # vertical tab (VT)
|
||||
"\000" => '\0', # nul character (NUL)
|
||||
);
|
||||
"\t" => '\t', # tab (HT)
|
||||
"\n" => '\n', # line feed (LF)
|
||||
"\r" => '\r', # carrige return (CR)
|
||||
"\f" => '\f', # form feed (FF)
|
||||
"\b" => '\b', # backspace (BS)
|
||||
"\a" => '\a', # alarm (bell) (BEL)
|
||||
"\e" => '\e', # escape (ESC)
|
||||
"\013" => '\v', # vertical tab (VT)
|
||||
"\000" => '\0', # nul character (NUL)
|
||||
);
|
||||
my $chr = ( (exists $es{$cntrl})
|
||||
? $es{$cntrl}
|
||||
: sprintf('\%03o', ord($cntrl)) );
|
||||
return "<span class=\"cntrl\">$chr</span>";
|
||||
if ($opts{-nohtml}) {
|
||||
return $chr;
|
||||
} else {
|
||||
return "<span class=\"cntrl\">$chr</span>";
|
||||
}
|
||||
}
|
||||
|
||||
# Alternatively use unicode control pictures codepoints,
|
||||
# Unicode "printable representation" (PR)
|
||||
sub quot_upr {
|
||||
my $cntrl = shift;
|
||||
my %opts = @_;
|
||||
|
||||
my $chr = sprintf('&#%04d;', 0x2400+ord($cntrl));
|
||||
return "<span class=\"cntrl\">$chr</span>";
|
||||
if ($opts{-nohtml}) {
|
||||
return $chr;
|
||||
} else {
|
||||
return "<span class=\"cntrl\">$chr</span>";
|
||||
}
|
||||
}
|
||||
|
||||
# git may return quoted and escaped filenames
|
||||
@@ -800,7 +811,7 @@ sub unquote {
|
||||
return chr(oct($seq));
|
||||
} elsif (exists $es{$seq}) {
|
||||
# C escape sequence, aka character escape code
|
||||
return $es{$seq}
|
||||
return $es{$seq};
|
||||
}
|
||||
# quoted ordinary character
|
||||
return $seq;
|
||||
@@ -866,8 +877,8 @@ sub chop_and_escape_str {
|
||||
if ($chopped eq $str) {
|
||||
return esc_html($chopped);
|
||||
} else {
|
||||
return qq{<span title="} . esc_html($str) . qq{">} .
|
||||
esc_html($chopped) . qq{</span>};
|
||||
$str =~ s/([[:cntrl:]])/?/g;
|
||||
return $cgi->span({-title=>$str}, esc_html($chopped));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1759,6 +1770,7 @@ sub git_get_project_owner {
|
||||
my $owner;
|
||||
|
||||
return undef unless $project;
|
||||
$git_dir = "$projectroot/$project";
|
||||
|
||||
if (!defined $gitweb_project_owner) {
|
||||
git_get_project_list_from_file();
|
||||
@@ -1767,8 +1779,11 @@ sub git_get_project_owner {
|
||||
if (exists $gitweb_project_owner->{$project}) {
|
||||
$owner = $gitweb_project_owner->{$project};
|
||||
}
|
||||
if (!defined $owner){
|
||||
$owner = git_get_project_config('owner');
|
||||
}
|
||||
if (!defined $owner) {
|
||||
$owner = get_file_owner("$projectroot/$project");
|
||||
$owner = get_file_owner("$git_dir");
|
||||
}
|
||||
|
||||
return $owner;
|
||||
@@ -3769,18 +3784,24 @@ sub git_search_grep_body {
|
||||
print "<td title=\"$co{'age_string_age'}\"><i>$co{'age_string_date'}</i></td>\n" .
|
||||
"<td><i>" . $author . "</i></td>\n" .
|
||||
"<td>" .
|
||||
$cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), -class => "list subject"},
|
||||
chop_and_escape_str($co{'title'}, 50) . "<br/>");
|
||||
$cgi->a({-href => href(action=>"commit", hash=>$co{'id'}),
|
||||
-class => "list subject"},
|
||||
chop_and_escape_str($co{'title'}, 50) . "<br/>");
|
||||
my $comment = $co{'comment'};
|
||||
foreach my $line (@$comment) {
|
||||
if ($line =~ m/^(.*)($search_regexp)(.*)$/i) {
|
||||
my $lead = esc_html($1) || "";
|
||||
$lead = chop_str($lead, 30, 10);
|
||||
my $match = esc_html($2) || "";
|
||||
my $trail = esc_html($3) || "";
|
||||
$trail = chop_str($trail, 30, 10);
|
||||
my $text = "$lead<span class=\"match\">$match</span>$trail";
|
||||
print chop_str($text, 80, 5) . "<br/>\n";
|
||||
my ($lead, $match, $trail) = ($1, $2, $3);
|
||||
$match = chop_str($match, 70, 5); # in case match is very long
|
||||
my $contextlen = (80 - len($match))/2; # is left for the remainder
|
||||
$contextlen = 30 if ($contextlen > 30); # but not too much
|
||||
$lead = chop_str($lead, $contextlen, 10);
|
||||
$trail = chop_str($trail, $contextlen, 10);
|
||||
|
||||
$lead = esc_html($lead);
|
||||
$match = esc_html($match);
|
||||
$trail = esc_html($trail);
|
||||
|
||||
print "$lead<span class=\"match\">$match</span>$trail<br />";
|
||||
}
|
||||
}
|
||||
print "</td>\n" .
|
||||
|
||||
2
hash.c
2
hash.c
@@ -70,7 +70,7 @@ void *lookup_hash(unsigned int hash, struct hash_table *table)
|
||||
{
|
||||
if (!table->array)
|
||||
return NULL;
|
||||
return &lookup_hash_entry(hash, table)->ptr;
|
||||
return lookup_hash_entry(hash, table)->ptr;
|
||||
}
|
||||
|
||||
void **insert_hash(unsigned int hash, void *ptr, struct hash_table *table)
|
||||
|
||||
8
help.c
8
help.c
@@ -44,12 +44,8 @@ static void parse_help_format(const char *format)
|
||||
|
||||
static int git_help_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "help.format")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
help_default_format = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "help.format"))
|
||||
return git_config_string(&help_default_format, var, value);
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
|
||||
30
http-push.c
30
http-push.c
@@ -1634,12 +1634,19 @@ static struct object_list **process_tree(struct tree *tree,
|
||||
|
||||
init_tree_desc(&desc, tree->buffer, tree->size);
|
||||
|
||||
while (tree_entry(&desc, &entry)) {
|
||||
if (S_ISDIR(entry.mode))
|
||||
while (tree_entry(&desc, &entry))
|
||||
switch (object_type(entry.mode)) {
|
||||
case OBJ_TREE:
|
||||
p = process_tree(lookup_tree(entry.sha1), p, &me, name);
|
||||
else
|
||||
break;
|
||||
case OBJ_BLOB:
|
||||
p = process_blob(lookup_blob(entry.sha1), p, &me, name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Subproject commit - not in this repository */
|
||||
break;
|
||||
}
|
||||
|
||||
free(tree->buffer);
|
||||
tree->buffer = NULL;
|
||||
return p;
|
||||
@@ -2383,7 +2390,8 @@ int main(int argc, char **argv)
|
||||
|
||||
/* Generate a list of objects that need to be pushed */
|
||||
pushing = 0;
|
||||
prepare_revision_walk(&revs);
|
||||
if (prepare_revision_walk(&revs))
|
||||
die("revision walk setup failed");
|
||||
mark_edges_uninteresting(revs.commits);
|
||||
objects_to_send = get_delta(&revs, ref_lock);
|
||||
finish_all_active_slots();
|
||||
@@ -2398,15 +2406,17 @@ int main(int argc, char **argv)
|
||||
fill_active_slots();
|
||||
add_fill_function(NULL, fill_active_slot);
|
||||
#endif
|
||||
finish_all_active_slots();
|
||||
do {
|
||||
finish_all_active_slots();
|
||||
#ifdef USE_CURL_MULTI
|
||||
fill_active_slots();
|
||||
#endif
|
||||
} while (request_queue_head && !aborted);
|
||||
|
||||
/* Update the remote branch if all went well */
|
||||
if (aborted || !update_remote(ref->new_sha1, ref_lock)) {
|
||||
if (aborted || !update_remote(ref->new_sha1, ref_lock))
|
||||
rc = 1;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
unlock:
|
||||
if (!rc)
|
||||
fprintf(stderr, " done\n");
|
||||
unlock_remote(ref_lock);
|
||||
|
||||
@@ -18,6 +18,8 @@ static void process_blob(struct rev_info *revs,
|
||||
|
||||
if (!revs->blob_objects)
|
||||
return;
|
||||
if (!obj)
|
||||
die("bad blob object");
|
||||
if (obj->flags & (UNINTERESTING | SEEN))
|
||||
return;
|
||||
obj->flags |= SEEN;
|
||||
@@ -69,6 +71,8 @@ static void process_tree(struct rev_info *revs,
|
||||
|
||||
if (!revs->tree_objects)
|
||||
return;
|
||||
if (!obj)
|
||||
die("bad tree object");
|
||||
if (obj->flags & (UNINTERESTING | SEEN))
|
||||
return;
|
||||
if (parse_tree(tree) < 0)
|
||||
|
||||
15
log-tree.c
15
log-tree.c
@@ -149,10 +149,12 @@ void show_log(struct rev_info *opt, const char *sep)
|
||||
|
||||
opt->loginfo = NULL;
|
||||
if (!opt->verbose_header) {
|
||||
if (opt->left_right) {
|
||||
if (commit->object.flags & BOUNDARY)
|
||||
putchar('-');
|
||||
else if (commit->object.flags & SYMMETRIC_LEFT)
|
||||
if (commit->object.flags & BOUNDARY)
|
||||
putchar('-');
|
||||
else if (commit->object.flags & UNINTERESTING)
|
||||
putchar('^');
|
||||
else if (opt->left_right) {
|
||||
if (commit->object.flags & SYMMETRIC_LEFT)
|
||||
putchar('<');
|
||||
else
|
||||
putchar('>');
|
||||
@@ -250,6 +252,8 @@ void show_log(struct rev_info *opt, const char *sep)
|
||||
fputs("commit ", stdout);
|
||||
if (commit->object.flags & BOUNDARY)
|
||||
putchar('-');
|
||||
else if (commit->object.flags & UNINTERESTING)
|
||||
putchar('^');
|
||||
else if (opt->left_right) {
|
||||
if (commit->object.flags & SYMMETRIC_LEFT)
|
||||
putchar('<');
|
||||
@@ -278,6 +282,9 @@ void show_log(struct rev_info *opt, const char *sep)
|
||||
}
|
||||
}
|
||||
|
||||
if (!commit->buffer)
|
||||
return;
|
||||
|
||||
/*
|
||||
* And then the pretty-printed message itself
|
||||
*/
|
||||
|
||||
@@ -91,7 +91,7 @@ int main(int argc, char **argv)
|
||||
signal(SIGCHLD, SIG_DFL);
|
||||
|
||||
if (argc < 3)
|
||||
usage("git-merge-index [-o] [-q] <merge-program> (-a | <filename>*)");
|
||||
usage("git-merge-index [-o] [-q] <merge-program> (-a | [--] <filename>*)");
|
||||
|
||||
setup_git_directory();
|
||||
read_cache();
|
||||
|
||||
@@ -1673,6 +1673,8 @@ static struct commit *get_ref(const char *ref)
|
||||
if (get_sha1(ref, sha1))
|
||||
die("Could not resolve ref '%s'", ref);
|
||||
object = deref_tag(parse_object(sha1), ref, strlen(ref));
|
||||
if (!object)
|
||||
return NULL;
|
||||
if (object->type == OBJ_TREE)
|
||||
return make_virtual_commit((struct tree*)object,
|
||||
better_branch_name(ref));
|
||||
|
||||
7
pager.c
7
pager.c
@@ -34,7 +34,10 @@ static struct child_process pager_process = {
|
||||
static void wait_for_pager(void)
|
||||
{
|
||||
fflush(stdout);
|
||||
close(1); /* signals EOF to pager */
|
||||
fflush(stderr);
|
||||
/* signal EOF to pager */
|
||||
close(1);
|
||||
close(2);
|
||||
finish_command(&pager_process);
|
||||
}
|
||||
#endif
|
||||
@@ -76,6 +79,7 @@ void setup_pager(void)
|
||||
/* return in the child */
|
||||
if (!pid) {
|
||||
dup2(fd[1], 1);
|
||||
dup2(fd[1], 2);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
return;
|
||||
@@ -98,6 +102,7 @@ void setup_pager(void)
|
||||
|
||||
/* original process continues, but writes to the pipe */
|
||||
dup2(pager_process.in, 1);
|
||||
dup2(pager_process.in, 2);
|
||||
close(pager_process.in);
|
||||
|
||||
/* this makes sure that the parent terminates after the pager */
|
||||
|
||||
178
pretty.c
178
pretty.c
@@ -282,59 +282,59 @@ static char *logmsg_reencode(const struct commit *commit,
|
||||
return out;
|
||||
}
|
||||
|
||||
static void format_person_part(struct strbuf *sb, char part,
|
||||
static size_t format_person_part(struct strbuf *sb, char part,
|
||||
const char *msg, int len)
|
||||
{
|
||||
/* currently all placeholders have same length */
|
||||
const int placeholder_len = 2;
|
||||
int start, end, tz = 0;
|
||||
unsigned long date;
|
||||
unsigned long date = 0;
|
||||
char *ep;
|
||||
|
||||
/* parse name */
|
||||
/* advance 'end' to point to email start delimiter */
|
||||
for (end = 0; end < len && msg[end] != '<'; end++)
|
||||
; /* do nothing */
|
||||
/*
|
||||
* If it does not even have a '<' and '>', that is
|
||||
* quite a bogus commit author and we discard it;
|
||||
* this is in line with add_user_info() that is used
|
||||
* in the normal codepath. When end points at the '<'
|
||||
* that we found, it should have matching '>' later,
|
||||
* which means start (beginning of email address) must
|
||||
* be strictly below len.
|
||||
*/
|
||||
start = end + 1;
|
||||
if (start >= len - 1)
|
||||
return;
|
||||
while (end > 0 && isspace(msg[end - 1]))
|
||||
end--;
|
||||
if (part == 'n') { /* name */
|
||||
strbuf_add(sb, msg, end);
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse email */
|
||||
for (end = start; end < len && msg[end] != '>'; end++)
|
||||
/*
|
||||
* When end points at the '<' that we found, it should have
|
||||
* matching '>' later, which means 'end' must be strictly
|
||||
* below len - 1.
|
||||
*/
|
||||
if (end >= len - 2)
|
||||
goto skip;
|
||||
|
||||
if (part == 'n') { /* name */
|
||||
while (end > 0 && isspace(msg[end - 1]))
|
||||
end--;
|
||||
strbuf_add(sb, msg, end);
|
||||
return placeholder_len;
|
||||
}
|
||||
start = ++end; /* save email start position */
|
||||
|
||||
/* advance 'end' to point to email end delimiter */
|
||||
for ( ; end < len && msg[end] != '>'; end++)
|
||||
; /* do nothing */
|
||||
|
||||
if (end >= len)
|
||||
return;
|
||||
goto skip;
|
||||
|
||||
if (part == 'e') { /* email */
|
||||
strbuf_add(sb, msg + start, end - start);
|
||||
return;
|
||||
return placeholder_len;
|
||||
}
|
||||
|
||||
/* parse date */
|
||||
/* advance 'start' to point to date start delimiter */
|
||||
for (start = end + 1; start < len && isspace(msg[start]); start++)
|
||||
; /* do nothing */
|
||||
if (start >= len)
|
||||
return;
|
||||
goto skip;
|
||||
date = strtoul(msg + start, &ep, 10);
|
||||
if (msg + start == ep)
|
||||
return;
|
||||
goto skip;
|
||||
|
||||
if (part == 't') { /* date, UNIX timestamp */
|
||||
strbuf_add(sb, msg + start, ep - (msg + start));
|
||||
return;
|
||||
return placeholder_len;
|
||||
}
|
||||
|
||||
/* parse tz */
|
||||
@@ -349,17 +349,28 @@ static void format_person_part(struct strbuf *sb, char part,
|
||||
switch (part) {
|
||||
case 'd': /* date */
|
||||
strbuf_addstr(sb, show_date(date, tz, DATE_NORMAL));
|
||||
return;
|
||||
return placeholder_len;
|
||||
case 'D': /* date, RFC2822 style */
|
||||
strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
|
||||
return;
|
||||
return placeholder_len;
|
||||
case 'r': /* date, relative */
|
||||
strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE));
|
||||
return;
|
||||
return placeholder_len;
|
||||
case 'i': /* date, ISO 8601 */
|
||||
strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601));
|
||||
return;
|
||||
return placeholder_len;
|
||||
}
|
||||
|
||||
skip:
|
||||
/*
|
||||
* bogus commit, 'sb' cannot be updated, but we still need to
|
||||
* compute a valid return value.
|
||||
*/
|
||||
if (part == 'n' || part == 'e' || part == 't' || part == 'd'
|
||||
|| part == 'D' || part == 'r' || part == 'i')
|
||||
return placeholder_len;
|
||||
|
||||
return 0; /* unknown placeholder */
|
||||
}
|
||||
|
||||
struct chunk {
|
||||
@@ -440,7 +451,7 @@ static void parse_commit_header(struct format_commit_context *context)
|
||||
context->commit_header_parsed = 1;
|
||||
}
|
||||
|
||||
static void format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
void *context)
|
||||
{
|
||||
struct format_commit_context *c = context;
|
||||
@@ -451,23 +462,23 @@ static void format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
/* these are independent of the commit */
|
||||
switch (placeholder[0]) {
|
||||
case 'C':
|
||||
switch (placeholder[3]) {
|
||||
case 'd': /* red */
|
||||
if (!prefixcmp(placeholder + 1, "red")) {
|
||||
strbuf_addstr(sb, "\033[31m");
|
||||
return;
|
||||
case 'e': /* green */
|
||||
return 4;
|
||||
} else if (!prefixcmp(placeholder + 1, "green")) {
|
||||
strbuf_addstr(sb, "\033[32m");
|
||||
return;
|
||||
case 'u': /* blue */
|
||||
return 6;
|
||||
} else if (!prefixcmp(placeholder + 1, "blue")) {
|
||||
strbuf_addstr(sb, "\033[34m");
|
||||
return;
|
||||
case 's': /* reset color */
|
||||
return 5;
|
||||
} else if (!prefixcmp(placeholder + 1, "reset")) {
|
||||
strbuf_addstr(sb, "\033[m");
|
||||
return;
|
||||
}
|
||||
return 6;
|
||||
} else
|
||||
return 0;
|
||||
case 'n': /* newline */
|
||||
strbuf_addch(sb, '\n');
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* these depend on the commit */
|
||||
@@ -477,34 +488,34 @@ static void format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
switch (placeholder[0]) {
|
||||
case 'H': /* commit hash */
|
||||
strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
|
||||
return;
|
||||
return 1;
|
||||
case 'h': /* abbreviated commit hash */
|
||||
if (add_again(sb, &c->abbrev_commit_hash))
|
||||
return;
|
||||
return 1;
|
||||
strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
|
||||
DEFAULT_ABBREV));
|
||||
c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
|
||||
return;
|
||||
return 1;
|
||||
case 'T': /* tree hash */
|
||||
strbuf_addstr(sb, sha1_to_hex(commit->tree->object.sha1));
|
||||
return;
|
||||
return 1;
|
||||
case 't': /* abbreviated tree hash */
|
||||
if (add_again(sb, &c->abbrev_tree_hash))
|
||||
return;
|
||||
return 1;
|
||||
strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1,
|
||||
DEFAULT_ABBREV));
|
||||
c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
|
||||
return;
|
||||
return 1;
|
||||
case 'P': /* parent hashes */
|
||||
for (p = commit->parents; p; p = p->next) {
|
||||
if (p != commit->parents)
|
||||
strbuf_addch(sb, ' ');
|
||||
strbuf_addstr(sb, sha1_to_hex(p->item->object.sha1));
|
||||
}
|
||||
return;
|
||||
return 1;
|
||||
case 'p': /* abbreviated parent hashes */
|
||||
if (add_again(sb, &c->abbrev_parent_hashes))
|
||||
return;
|
||||
return 1;
|
||||
for (p = commit->parents; p; p = p->next) {
|
||||
if (p != commit->parents)
|
||||
strbuf_addch(sb, ' ');
|
||||
@@ -513,14 +524,14 @@ static void format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
}
|
||||
c->abbrev_parent_hashes.len = sb->len -
|
||||
c->abbrev_parent_hashes.off;
|
||||
return;
|
||||
return 1;
|
||||
case 'm': /* left/right/bottom */
|
||||
strbuf_addch(sb, (commit->object.flags & BOUNDARY)
|
||||
? '-'
|
||||
: (commit->object.flags & SYMMETRIC_LEFT)
|
||||
? '<'
|
||||
: '>');
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* For the rest we have to parse the commit header. */
|
||||
@@ -528,66 +539,33 @@ static void format_commit_item(struct strbuf *sb, const char *placeholder,
|
||||
parse_commit_header(c);
|
||||
|
||||
switch (placeholder[0]) {
|
||||
case 's':
|
||||
case 's': /* subject */
|
||||
strbuf_add(sb, msg + c->subject.off, c->subject.len);
|
||||
return;
|
||||
case 'a':
|
||||
format_person_part(sb, placeholder[1],
|
||||
return 1;
|
||||
case 'a': /* author ... */
|
||||
return format_person_part(sb, placeholder[1],
|
||||
msg + c->author.off, c->author.len);
|
||||
return;
|
||||
case 'c':
|
||||
format_person_part(sb, placeholder[1],
|
||||
case 'c': /* committer ... */
|
||||
return format_person_part(sb, placeholder[1],
|
||||
msg + c->committer.off, c->committer.len);
|
||||
return;
|
||||
case 'e':
|
||||
case 'e': /* encoding */
|
||||
strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
|
||||
return;
|
||||
case 'b':
|
||||
return 1;
|
||||
case 'b': /* body */
|
||||
strbuf_addstr(sb, msg + c->body_off);
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
return 0; /* unknown placeholder */
|
||||
}
|
||||
|
||||
void format_commit_message(const struct commit *commit,
|
||||
const void *format, struct strbuf *sb)
|
||||
{
|
||||
const char *placeholders[] = {
|
||||
"H", /* commit hash */
|
||||
"h", /* abbreviated commit hash */
|
||||
"T", /* tree hash */
|
||||
"t", /* abbreviated tree hash */
|
||||
"P", /* parent hashes */
|
||||
"p", /* abbreviated parent hashes */
|
||||
"an", /* author name */
|
||||
"ae", /* author email */
|
||||
"ad", /* author date */
|
||||
"aD", /* author date, RFC2822 style */
|
||||
"ar", /* author date, relative */
|
||||
"at", /* author date, UNIX timestamp */
|
||||
"ai", /* author date, ISO 8601 */
|
||||
"cn", /* committer name */
|
||||
"ce", /* committer email */
|
||||
"cd", /* committer date */
|
||||
"cD", /* committer date, RFC2822 style */
|
||||
"cr", /* committer date, relative */
|
||||
"ct", /* committer date, UNIX timestamp */
|
||||
"ci", /* committer date, ISO 8601 */
|
||||
"e", /* encoding */
|
||||
"s", /* subject */
|
||||
"b", /* body */
|
||||
"Cred", /* red */
|
||||
"Cgreen", /* green */
|
||||
"Cblue", /* blue */
|
||||
"Creset", /* reset color */
|
||||
"n", /* newline */
|
||||
"m", /* left/right/bottom */
|
||||
NULL
|
||||
};
|
||||
struct format_commit_context context;
|
||||
|
||||
memset(&context, 0, sizeof(context));
|
||||
context.commit = commit;
|
||||
strbuf_expand(sb, format, placeholders, format_commit_item, &context);
|
||||
strbuf_expand(sb, format, format_commit_item, &context);
|
||||
}
|
||||
|
||||
static void pp_header(enum cmit_fmt fmt,
|
||||
|
||||
13
reachable.c
13
reachable.c
@@ -15,6 +15,8 @@ static void process_blob(struct blob *blob,
|
||||
{
|
||||
struct object *obj = &blob->object;
|
||||
|
||||
if (!blob)
|
||||
die("bad blob object");
|
||||
if (obj->flags & SEEN)
|
||||
return;
|
||||
obj->flags |= SEEN;
|
||||
@@ -39,6 +41,8 @@ static void process_tree(struct tree *tree,
|
||||
struct name_entry entry;
|
||||
struct name_path me;
|
||||
|
||||
if (!tree)
|
||||
die("bad tree object");
|
||||
if (obj->flags & SEEN)
|
||||
return;
|
||||
obj->flags |= SEEN;
|
||||
@@ -79,7 +83,8 @@ static void process_tag(struct tag *tag, struct object_array *p, const char *nam
|
||||
|
||||
if (parse_tag(tag) < 0)
|
||||
die("bad tag object %s", sha1_to_hex(obj->sha1));
|
||||
add_object(tag->tagged, p, NULL, name);
|
||||
if (tag->tagged)
|
||||
add_object(tag->tagged, p, NULL, name);
|
||||
}
|
||||
|
||||
static void walk_commit_list(struct rev_info *revs)
|
||||
@@ -150,7 +155,8 @@ static int add_one_reflog(const char *path, const unsigned char *sha1, int flag,
|
||||
static void add_one_tree(const unsigned char *sha1, struct rev_info *revs)
|
||||
{
|
||||
struct tree *tree = lookup_tree(sha1);
|
||||
add_pending_object(revs, &tree->object, "");
|
||||
if (tree)
|
||||
add_pending_object(revs, &tree->object, "");
|
||||
}
|
||||
|
||||
static void add_cache_tree(struct cache_tree *it, struct rev_info *revs)
|
||||
@@ -215,6 +221,7 @@ void mark_reachable_objects(struct rev_info *revs, int mark_reflog)
|
||||
* Set up the revision walk - this will move all commits
|
||||
* from the pending list to the commit walking list.
|
||||
*/
|
||||
prepare_revision_walk(revs);
|
||||
if (prepare_revision_walk(revs))
|
||||
die("revision walk setup failed");
|
||||
walk_commit_list(revs);
|
||||
}
|
||||
|
||||
28
revision.c
28
revision.c
@@ -46,6 +46,8 @@ void add_object(struct object *obj,
|
||||
|
||||
static void mark_blob_uninteresting(struct blob *blob)
|
||||
{
|
||||
if (!blob)
|
||||
return;
|
||||
if (blob->object.flags & UNINTERESTING)
|
||||
return;
|
||||
blob->object.flags |= UNINTERESTING;
|
||||
@@ -57,6 +59,8 @@ void mark_tree_uninteresting(struct tree *tree)
|
||||
struct name_entry entry;
|
||||
struct object *obj = &tree->object;
|
||||
|
||||
if (!tree)
|
||||
return;
|
||||
if (obj->flags & UNINTERESTING)
|
||||
return;
|
||||
obj->flags |= UNINTERESTING;
|
||||
@@ -173,6 +177,8 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
|
||||
struct tag *tag = (struct tag *) object;
|
||||
if (revs->tag_objects && !(flags & UNINTERESTING))
|
||||
add_pending_object(revs, object, tag->tag);
|
||||
if (!tag->tagged)
|
||||
die("bad tag");
|
||||
object = parse_object(tag->tagged->sha1);
|
||||
if (!object)
|
||||
die("bad object %s", sha1_to_hex(tag->tagged->sha1));
|
||||
@@ -558,6 +564,12 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
|
||||
free_patch_ids(&ids);
|
||||
}
|
||||
|
||||
static void add_to_list(struct commit_list **p, struct commit *commit, struct commit_list *n)
|
||||
{
|
||||
p = &commit_list_insert(commit, p)->next;
|
||||
*p = n;
|
||||
}
|
||||
|
||||
static int limit_list(struct rev_info *revs)
|
||||
{
|
||||
struct commit_list *list = revs->commits;
|
||||
@@ -579,9 +591,13 @@ static int limit_list(struct rev_info *revs)
|
||||
return -1;
|
||||
if (obj->flags & UNINTERESTING) {
|
||||
mark_parents_uninteresting(commit);
|
||||
if (everybody_uninteresting(list))
|
||||
if (everybody_uninteresting(list)) {
|
||||
if (revs->show_all)
|
||||
add_to_list(p, commit, list);
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (!revs->show_all)
|
||||
continue;
|
||||
}
|
||||
if (revs->min_age != -1 && (commit->date > revs->min_age))
|
||||
continue;
|
||||
@@ -685,6 +701,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
|
||||
it = get_reference(revs, arg, sha1, 0);
|
||||
if (it->type != OBJ_TAG)
|
||||
break;
|
||||
if (!((struct tag*)it)->tagged)
|
||||
return 0;
|
||||
hashcpy(sha1, ((struct tag*)it)->tagged->sha1);
|
||||
}
|
||||
if (it->type != OBJ_COMMIT)
|
||||
@@ -1055,6 +1073,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
revs->dense = 0;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--show-all")) {
|
||||
revs->show_all = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--remove-empty")) {
|
||||
revs->remove_empty_trees = 1;
|
||||
continue;
|
||||
@@ -1438,6 +1460,8 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
|
||||
return commit_ignore;
|
||||
if (revs->unpacked && has_sha1_pack(commit->object.sha1, revs->ignore_packed))
|
||||
return commit_ignore;
|
||||
if (revs->show_all)
|
||||
return commit_show;
|
||||
if (commit->object.flags & UNINTERESTING)
|
||||
return commit_ignore;
|
||||
if (revs->min_age != -1 && (commit->date > revs->min_age))
|
||||
|
||||
@@ -33,6 +33,7 @@ struct rev_info {
|
||||
prune:1,
|
||||
no_merges:1,
|
||||
no_walk:1,
|
||||
show_all:1,
|
||||
remove_empty_trees:1,
|
||||
simplify_history:1,
|
||||
lifo:1,
|
||||
|
||||
194
setup.c
194
setup.c
@@ -10,68 +10,131 @@ static inline int is_dir_sep(char c) { return c == '/' || c == '\\'; }
|
||||
static inline int is_dir_sep(char c) { return c == '/'; }
|
||||
#endif
|
||||
|
||||
static int sanitary_path_copy(char *dst, const char *src)
|
||||
{
|
||||
char *dst0 = dst;
|
||||
|
||||
#ifdef __MINGW32__
|
||||
if (isalpha(*src) && src[1] == ':') {
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
dst0 = dst;
|
||||
}
|
||||
#endif
|
||||
if (is_dir_sep(*src)) {
|
||||
*dst++ = '/';
|
||||
while (is_dir_sep(*src))
|
||||
src++;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
char c = *src;
|
||||
|
||||
/*
|
||||
* A path component that begins with . could be
|
||||
* special:
|
||||
* (1) "." and ends -- ignore and terminate.
|
||||
* (2) "./" -- ignore them, eat slash and continue.
|
||||
* (3) ".." and ends -- strip one and terminate.
|
||||
* (4) "../" -- strip one, eat slash and continue.
|
||||
*/
|
||||
if (c == '.') {
|
||||
switch (src[1]) {
|
||||
case '\0':
|
||||
/* (1) */
|
||||
src++;
|
||||
break;
|
||||
case '/':
|
||||
#ifdef __MINGW32__
|
||||
case '\\':
|
||||
#endif
|
||||
/* (2) */
|
||||
src += 2;
|
||||
while (is_dir_sep(*src))
|
||||
src++;
|
||||
continue;
|
||||
case '.':
|
||||
switch (src[2]) {
|
||||
case '\0':
|
||||
/* (3) */
|
||||
src += 2;
|
||||
goto up_one;
|
||||
case '/':
|
||||
#ifdef __MINGW32__
|
||||
case '\\':
|
||||
#endif
|
||||
/* (4) */
|
||||
src += 3;
|
||||
while (is_dir_sep(*src))
|
||||
src++;
|
||||
goto up_one;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* copy up to the next '/', and eat all '/' */
|
||||
while ((c = *src++) != '\0' && !is_dir_sep(c))
|
||||
*dst++ = c;
|
||||
if (is_dir_sep(c)) {
|
||||
*dst++ = '/';
|
||||
while (is_dir_sep(c))
|
||||
c = *src++;
|
||||
src--;
|
||||
} else if (!c)
|
||||
break;
|
||||
continue;
|
||||
|
||||
up_one:
|
||||
/*
|
||||
* dst0..dst is prefix portion, and dst[-1] is '/';
|
||||
* go up one level.
|
||||
*/
|
||||
dst -= 2; /* go past trailing '/' if any */
|
||||
if (dst < dst0)
|
||||
return -1;
|
||||
while (1) {
|
||||
if (dst <= dst0)
|
||||
break;
|
||||
c = *dst--;
|
||||
if (c == '/') { /* MinGW: cannot be '\\' anymore */
|
||||
dst += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*dst = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *prefix_path(const char *prefix, int len, const char *path)
|
||||
{
|
||||
const char *orig = path;
|
||||
int do_pfx;
|
||||
for (;;) {
|
||||
char c;
|
||||
if (*path != '.')
|
||||
break;
|
||||
c = path[1];
|
||||
/* "." */
|
||||
if (!c) {
|
||||
path++;
|
||||
break;
|
||||
}
|
||||
/* "./" */
|
||||
if (is_dir_sep(c)) {
|
||||
path += 2;
|
||||
continue;
|
||||
}
|
||||
if (c != '.')
|
||||
break;
|
||||
c = path[2];
|
||||
if (!c)
|
||||
path += 2;
|
||||
else if (is_dir_sep(c))
|
||||
path += 3;
|
||||
else
|
||||
break;
|
||||
/* ".." and "../" */
|
||||
/* Remove last component of the prefix */
|
||||
do {
|
||||
if (!len)
|
||||
die("'%s' is outside repository", orig);
|
||||
len--;
|
||||
} while (len && !is_dir_sep(prefix[len-1]));
|
||||
continue;
|
||||
char *sanitized = xmalloc(len + strlen(path) + 1);
|
||||
if (is_absolute_path(orig))
|
||||
strcpy(sanitized, path);
|
||||
else {
|
||||
if (len)
|
||||
memcpy(sanitized, prefix, len);
|
||||
strcpy(sanitized + len, path);
|
||||
}
|
||||
do_pfx = len;
|
||||
#ifdef __MINGW32__
|
||||
/* we want to convert '\' in path to '/' (prefix already has '/') */
|
||||
{
|
||||
const char *p = path;
|
||||
while (!do_pfx && *p) {
|
||||
do_pfx = *p++ == '\\';
|
||||
if (sanitary_path_copy(sanitized, sanitized))
|
||||
goto error_out;
|
||||
if (is_absolute_path(orig)) {
|
||||
const char *work_tree = get_git_work_tree();
|
||||
size_t len = strlen(work_tree);
|
||||
size_t total = strlen(sanitized) + 1;
|
||||
if (strncmp(sanitized, work_tree, len) ||
|
||||
(sanitized[len] != '\0' && sanitized[len] != '/')) {
|
||||
error_out:
|
||||
error("'%s' is outside repository", orig);
|
||||
free(sanitized);
|
||||
return NULL;
|
||||
}
|
||||
if (sanitized[len] == '/')
|
||||
len++;
|
||||
memmove(sanitized, sanitized + len, total - len);
|
||||
}
|
||||
#endif
|
||||
if (do_pfx) {
|
||||
int speclen = strlen(path);
|
||||
char *n = xmalloc(speclen + len + 1);
|
||||
char *p;
|
||||
|
||||
memcpy(n, prefix, len);
|
||||
memcpy(n + len, path, speclen+1);
|
||||
#ifdef __MINGW32__
|
||||
for (p = n + len; *p; p++)
|
||||
if (*p == '\\')
|
||||
*p = '/';
|
||||
#endif
|
||||
path = n;
|
||||
}
|
||||
return path;
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -150,7 +213,7 @@ void verify_non_filename(const char *prefix, const char *arg)
|
||||
const char **get_pathspec(const char *prefix, const char **pathspec)
|
||||
{
|
||||
const char *entry = *pathspec;
|
||||
const char **p;
|
||||
const char **src, **dst;
|
||||
int prefixlen;
|
||||
|
||||
if (!prefix && !entry)
|
||||
@@ -164,12 +227,19 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
|
||||
}
|
||||
|
||||
/* Otherwise we have to re-write the entries.. */
|
||||
p = pathspec;
|
||||
src = pathspec;
|
||||
dst = pathspec;
|
||||
prefixlen = prefix ? strlen(prefix) : 0;
|
||||
do {
|
||||
*p = prefix_path(prefix, prefixlen, entry);
|
||||
} while ((entry = *++p) != NULL);
|
||||
return (const char **) pathspec;
|
||||
while (*src) {
|
||||
const char *p = prefix_path(prefix, prefixlen, *src);
|
||||
if (p)
|
||||
*(dst++) = p;
|
||||
src++;
|
||||
}
|
||||
*dst = NULL;
|
||||
if (!*pathspec)
|
||||
return NULL;
|
||||
return pathspec;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
14
sha1_file.c
14
sha1_file.c
@@ -1855,6 +1855,15 @@ static struct cached_object {
|
||||
} *cached_objects;
|
||||
static int cached_object_nr, cached_object_alloc;
|
||||
|
||||
static struct cached_object empty_tree = {
|
||||
/* empty tree sha1: 4b825dc642cb6eb9a060e54bf8d69288fbee4904 */
|
||||
"\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60"
|
||||
"\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04",
|
||||
OBJ_TREE,
|
||||
"",
|
||||
0
|
||||
};
|
||||
|
||||
static struct cached_object *find_cached_object(const unsigned char *sha1)
|
||||
{
|
||||
int i;
|
||||
@@ -1864,6 +1873,8 @@ static struct cached_object *find_cached_object(const unsigned char *sha1)
|
||||
if (!hashcmp(co->sha1, sha1))
|
||||
return co;
|
||||
}
|
||||
if (!hashcmp(sha1, empty_tree.sha1))
|
||||
return &empty_tree;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1953,7 +1964,8 @@ void *read_object_with_reference(const unsigned char *sha1,
|
||||
}
|
||||
ref_length = strlen(ref_type);
|
||||
|
||||
if (memcmp(buffer, ref_type, ref_length) ||
|
||||
if (ref_length + 40 > isize ||
|
||||
memcmp(buffer, ref_type, ref_length) ||
|
||||
get_sha1_hex((char *) buffer + ref_length, actual_sha1)) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
|
||||
13
sha1_name.c
13
sha1_name.c
@@ -494,8 +494,11 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
|
||||
return error("%.*s: expected %s type, but the object dereferences to %s type",
|
||||
len, name, typename(expected_type),
|
||||
typename(o->type));
|
||||
if (!o)
|
||||
return -1;
|
||||
if (!o->parsed)
|
||||
parse_object(o->sha1);
|
||||
if (!parse_object(o->sha1))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -578,8 +581,11 @@ static int handle_one_ref(const char *path,
|
||||
struct object *object = parse_object(sha1);
|
||||
if (!object)
|
||||
return 0;
|
||||
if (object->type == OBJ_TAG)
|
||||
if (object->type == OBJ_TAG) {
|
||||
object = deref_tag(object, path, strlen(path));
|
||||
if (!object)
|
||||
return 0;
|
||||
}
|
||||
if (object->type != OBJ_COMMIT)
|
||||
return 0;
|
||||
insert_by_date((struct commit *)object, list);
|
||||
@@ -617,7 +623,8 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1)
|
||||
unsigned long size;
|
||||
|
||||
commit = pop_most_recent_commit(&list, ONELINE_SEEN);
|
||||
parse_object(commit->object.sha1);
|
||||
if (!parse_object(commit->object.sha1))
|
||||
continue;
|
||||
if (temp_commit_buffer)
|
||||
free(temp_commit_buffer);
|
||||
if (commit->buffer)
|
||||
|
||||
@@ -56,7 +56,7 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
|
||||
if (i < heads->nr) {
|
||||
commit = (struct commit *)
|
||||
deref_tag(heads->objects[i++].item, NULL, 0);
|
||||
if (commit->object.type != OBJ_COMMIT) {
|
||||
if (!commit || commit->object.type != OBJ_COMMIT) {
|
||||
commit = NULL;
|
||||
continue;
|
||||
}
|
||||
@@ -70,7 +70,8 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
|
||||
cur_depth = *(int *)commit->util;
|
||||
}
|
||||
}
|
||||
parse_commit(commit);
|
||||
if (parse_commit(commit))
|
||||
die("invalid commit");
|
||||
commit->object.flags |= not_shallow_flag;
|
||||
cur_depth++;
|
||||
for (p = commit->parents, commit = NULL; p; p = p->next) {
|
||||
|
||||
19
strbuf.c
19
strbuf.c
@@ -146,11 +146,12 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
|
||||
strbuf_setlen(sb, sb->len + len);
|
||||
}
|
||||
|
||||
void strbuf_expand(struct strbuf *sb, const char *format,
|
||||
const char **placeholders, expand_fn_t fn, void *context)
|
||||
void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
|
||||
void *context)
|
||||
{
|
||||
for (;;) {
|
||||
const char *percent, **p;
|
||||
const char *percent;
|
||||
size_t consumed;
|
||||
|
||||
percent = strchrnul(format, '%');
|
||||
strbuf_add(sb, format, percent - format);
|
||||
@@ -158,14 +159,10 @@ void strbuf_expand(struct strbuf *sb, const char *format,
|
||||
break;
|
||||
format = percent + 1;
|
||||
|
||||
for (p = placeholders; *p; p++) {
|
||||
if (!prefixcmp(format, *p))
|
||||
break;
|
||||
}
|
||||
if (*p) {
|
||||
fn(sb, *p, context);
|
||||
format += strlen(*p);
|
||||
} else
|
||||
consumed = fn(sb, format, context);
|
||||
if (consumed)
|
||||
format += consumed;
|
||||
else
|
||||
strbuf_addch(sb, '%');
|
||||
}
|
||||
}
|
||||
|
||||
4
strbuf.h
4
strbuf.h
@@ -103,8 +103,8 @@ static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) {
|
||||
}
|
||||
extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
|
||||
|
||||
typedef void (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
|
||||
extern void strbuf_expand(struct strbuf *sb, const char *format, const char **placeholders, expand_fn_t fn, void *context);
|
||||
typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
|
||||
extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);
|
||||
|
||||
__attribute__((format(printf,2,3)))
|
||||
extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
|
||||
|
||||
@@ -61,8 +61,8 @@ test_expect_success 'setup' '
|
||||
git tag I
|
||||
'
|
||||
|
||||
cat > fake-editor.sh <<\EOF
|
||||
#!/bin/sh
|
||||
echo "#!$SHELL" >fake-editor
|
||||
cat >> fake-editor.sh <<\EOF
|
||||
case "$1" in
|
||||
*/COMMIT_EDITMSG)
|
||||
test -z "$FAKE_COMMIT_MESSAGE" || echo "$FAKE_COMMIT_MESSAGE" > "$1"
|
||||
|
||||
69
t/t3701-add-interactive.sh
Executable file
69
t/t3701-add-interactive.sh
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='add -i basic tests'
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'setup (initial)' '
|
||||
echo content >file &&
|
||||
git add file &&
|
||||
echo more >>file &&
|
||||
echo lines >>file
|
||||
'
|
||||
test_expect_success 'status works (initial)' '
|
||||
git add -i </dev/null >output &&
|
||||
grep "+1/-0 *+2/-0 file" output
|
||||
'
|
||||
cat >expected <<EOF
|
||||
new file mode 100644
|
||||
index 0000000..d95f3ad
|
||||
--- /dev/null
|
||||
+++ b/file
|
||||
@@ -0,0 +1 @@
|
||||
+content
|
||||
EOF
|
||||
test_expect_success 'diff works (initial)' '
|
||||
(echo d; echo 1) | git add -i >output &&
|
||||
sed -ne "/new file/,/content/p" <output >diff &&
|
||||
diff -u expected diff
|
||||
'
|
||||
test_expect_success 'revert works (initial)' '
|
||||
git add file &&
|
||||
(echo r; echo 1) | git add -i &&
|
||||
git ls-files >output &&
|
||||
! grep . output
|
||||
'
|
||||
|
||||
test_expect_success 'setup (commit)' '
|
||||
echo baseline >file &&
|
||||
git add file &&
|
||||
git commit -m commit &&
|
||||
echo content >>file &&
|
||||
git add file &&
|
||||
echo more >>file &&
|
||||
echo lines >>file
|
||||
'
|
||||
test_expect_success 'status works (commit)' '
|
||||
git add -i </dev/null >output &&
|
||||
grep "+1/-0 *+2/-0 file" output
|
||||
'
|
||||
cat >expected <<EOF
|
||||
index 180b47c..b6f2c08 100644
|
||||
--- a/file
|
||||
+++ b/file
|
||||
@@ -1 +1,2 @@
|
||||
baseline
|
||||
+content
|
||||
EOF
|
||||
test_expect_success 'diff works (commit)' '
|
||||
(echo d; echo 1) | git add -i >output &&
|
||||
sed -ne "/^index/,/content/p" <output >diff &&
|
||||
diff -u expected diff
|
||||
'
|
||||
test_expect_success 'revert works (commit)' '
|
||||
git add file &&
|
||||
(echo r; echo 1) | git add -i &&
|
||||
git add -i </dev/null >output &&
|
||||
grep "unchanged *+3/-0 file" output
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -74,4 +74,12 @@ test_expect_success 'Even without -l, local will make a hardlink' '
|
||||
test 0 = $copied
|
||||
'
|
||||
|
||||
test_expect_success 'local clone of repo with nonexistent ref in HEAD' '
|
||||
cd "$D" &&
|
||||
echo "ref: refs/heads/nonexistent" > a.git/HEAD &&
|
||||
git clone a d &&
|
||||
cd d &&
|
||||
git fetch &&
|
||||
test ! -e .git/refs/remotes/origin/HEAD'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -118,4 +118,42 @@ test_expect_success "Sergey Vlasov's test case" '
|
||||
git mv ab a
|
||||
'
|
||||
|
||||
test_expect_success 'absolute pathname' '(
|
||||
|
||||
rm -fr mine &&
|
||||
mkdir mine &&
|
||||
cd mine &&
|
||||
test_create_repo one &&
|
||||
cd one &&
|
||||
mkdir sub &&
|
||||
>sub/file &&
|
||||
git add sub/file &&
|
||||
|
||||
git mv sub "$(pwd)/in" &&
|
||||
! test -d sub &&
|
||||
test -d in &&
|
||||
git ls-files --error-unmatch in/file
|
||||
|
||||
|
||||
)'
|
||||
|
||||
test_expect_success 'absolute pathname outside should fail' '(
|
||||
|
||||
rm -fr mine &&
|
||||
mkdir mine &&
|
||||
cd mine &&
|
||||
out=$(pwd) &&
|
||||
test_create_repo one &&
|
||||
cd one &&
|
||||
mkdir sub &&
|
||||
>sub/file &&
|
||||
git add sub/file &&
|
||||
|
||||
! git mv sub "$out/out" &&
|
||||
test -d sub &&
|
||||
! test -d ../in &&
|
||||
git ls-files --error-unmatch sub/file
|
||||
|
||||
)'
|
||||
|
||||
test_done
|
||||
|
||||
164
t/t7010-setup.sh
Executable file
164
t/t7010-setup.sh
Executable file
@@ -0,0 +1,164 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='setup taking and sanitizing funny paths'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
mkdir -p a/b/c a/e &&
|
||||
D=$(pwd) &&
|
||||
>a/b/c/d &&
|
||||
>a/e/f
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git add (absolute)' '
|
||||
|
||||
git add "$D/a/b/c/d" &&
|
||||
git ls-files >current &&
|
||||
echo a/b/c/d >expect &&
|
||||
diff -u expect current
|
||||
|
||||
'
|
||||
|
||||
|
||||
test_expect_success 'git add (funny relative)' '
|
||||
|
||||
rm -f .git/index &&
|
||||
(
|
||||
cd a/b &&
|
||||
git add "../e/./f"
|
||||
) &&
|
||||
git ls-files >current &&
|
||||
echo a/e/f >expect &&
|
||||
diff -u expect current
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git rm (absolute)' '
|
||||
|
||||
rm -f .git/index &&
|
||||
git add a &&
|
||||
git rm -f --cached "$D/a/b/c/d" &&
|
||||
git ls-files >current &&
|
||||
echo a/e/f >expect &&
|
||||
diff -u expect current
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git rm (funny relative)' '
|
||||
|
||||
rm -f .git/index &&
|
||||
git add a &&
|
||||
(
|
||||
cd a/b &&
|
||||
git rm -f --cached "../e/./f"
|
||||
) &&
|
||||
git ls-files >current &&
|
||||
echo a/b/c/d >expect &&
|
||||
diff -u expect current
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git ls-files (absolute)' '
|
||||
|
||||
rm -f .git/index &&
|
||||
git add a &&
|
||||
git ls-files "$D/a/e/../b" >current &&
|
||||
echo a/b/c/d >expect &&
|
||||
diff -u expect current
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git ls-files (relative #1)' '
|
||||
|
||||
rm -f .git/index &&
|
||||
git add a &&
|
||||
(
|
||||
cd a/b &&
|
||||
git ls-files "../b/c"
|
||||
) >current &&
|
||||
echo c/d >expect &&
|
||||
diff -u expect current
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git ls-files (relative #2)' '
|
||||
|
||||
rm -f .git/index &&
|
||||
git add a &&
|
||||
(
|
||||
cd a/b &&
|
||||
git ls-files --full-name "../e/f"
|
||||
) >current &&
|
||||
echo a/e/f >expect &&
|
||||
diff -u expect current
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'git ls-files (relative #3)' '
|
||||
|
||||
rm -f .git/index &&
|
||||
git add a &&
|
||||
(
|
||||
cd a/b &&
|
||||
if git ls-files "../e/f"
|
||||
then
|
||||
echo Gaah, should have failed
|
||||
exit 1
|
||||
else
|
||||
: happy
|
||||
fi
|
||||
)
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'commit using absolute path names' '
|
||||
git commit -m "foo" &&
|
||||
echo aa >>a/b/c/d &&
|
||||
git commit -m "aa" "$(pwd)/a/b/c/d"
|
||||
'
|
||||
|
||||
test_expect_success 'log using absolute path names' '
|
||||
echo bb >>a/b/c/d &&
|
||||
git commit -m "bb" $(pwd)/a/b/c/d &&
|
||||
|
||||
git log a/b/c/d >f1.txt &&
|
||||
git log "$(pwd)/a/b/c/d" >f2.txt &&
|
||||
diff -u f1.txt f2.txt
|
||||
'
|
||||
|
||||
test_expect_success 'blame using absolute path names' '
|
||||
git blame a/b/c/d >f1.txt &&
|
||||
git blame "$(pwd)/a/b/c/d" >f2.txt &&
|
||||
diff -u f1.txt f2.txt
|
||||
'
|
||||
|
||||
test_expect_success 'setup deeper work tree' '
|
||||
test_create_repo tester
|
||||
'
|
||||
|
||||
test_expect_success 'add a directory outside the work tree' '(
|
||||
cd tester &&
|
||||
d1="$(cd .. ; pwd)" &&
|
||||
git add "$d1"
|
||||
)'
|
||||
|
||||
test_expect_success 'add a file outside the work tree, nasty case 1' '(
|
||||
cd tester &&
|
||||
f="$(pwd)x" &&
|
||||
echo "$f" &&
|
||||
touch "$f" &&
|
||||
git add "$f"
|
||||
)'
|
||||
|
||||
test_expect_success 'add a file outside the work tree, nasty case 2' '(
|
||||
cd tester &&
|
||||
f="$(pwd | sed "s/.$//")x" &&
|
||||
echo "$f" &&
|
||||
touch "$f" &&
|
||||
git add "$f"
|
||||
)'
|
||||
|
||||
test_done
|
||||
46
t/t7104-reset.sh
Executable file
46
t/t7104-reset.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='reset --hard unmerged'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
mkdir before later &&
|
||||
>before/1 &&
|
||||
>before/2 &&
|
||||
>hello &&
|
||||
>later/3 &&
|
||||
git add before hello later &&
|
||||
git commit -m world &&
|
||||
|
||||
H=$(git rev-parse :hello) &&
|
||||
git rm --cached hello &&
|
||||
echo "100644 $H 2 hello" | git update-index --index-info &&
|
||||
|
||||
rm -f hello &&
|
||||
mkdir -p hello &&
|
||||
>hello/world &&
|
||||
test "$(git ls-files -o)" = hello/world
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'reset --hard should restore unmerged ones' '
|
||||
|
||||
git reset --hard &&
|
||||
git ls-files --error-unmatch before/1 before/2 hello later/3 &&
|
||||
test -f hello
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'reset --hard did not corrupt index nor cached-tree' '
|
||||
|
||||
T=$(git write-tree) &&
|
||||
rm -f .git/index &&
|
||||
git add before hello later &&
|
||||
U=$(git write-tree) &&
|
||||
test "$T" = "$U"
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -316,4 +316,14 @@ test_expect_success 'core.excludesfile' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'removal failure' '
|
||||
|
||||
mkdir foo &&
|
||||
touch foo/bar &&
|
||||
chmod 0 foo &&
|
||||
! git clean -f -d
|
||||
|
||||
'
|
||||
chmod 755 foo
|
||||
|
||||
test_done
|
||||
|
||||
@@ -112,4 +112,25 @@ test_expect_success 'allow long lines with --no-validate' '
|
||||
2>errors
|
||||
'
|
||||
|
||||
test_expect_success 'Invalid In-Reply-To' '
|
||||
git send-email \
|
||||
--from="Example <nobody@example.com>" \
|
||||
--to=nobody@example.com \
|
||||
--in-reply-to=" " \
|
||||
--smtp-server="$(pwd)/fake.sendmail" \
|
||||
$patches
|
||||
2>errors
|
||||
! grep "^In-Reply-To: < *>" msgtxt
|
||||
'
|
||||
|
||||
test_expect_success 'Valid In-Reply-To when prompting' '
|
||||
(echo "From Example <from@example.com>"
|
||||
echo "To Example <to@example.com>"
|
||||
echo ""
|
||||
) | env GIT_SEND_EMAIL_NOTTY=1 git send-email \
|
||||
--smtp-server="$(pwd)/fake.sendmail" \
|
||||
$patches 2>errors &&
|
||||
! grep "^In-Reply-To: < *>" msgtxt
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -266,4 +266,39 @@ test_expect_success '-w option should work with relative GIT_DIR' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'check files before directories' '
|
||||
|
||||
echo Notes > release-notes &&
|
||||
git add release-notes &&
|
||||
git commit -m "Add release notes" release-notes &&
|
||||
id=$(git rev-parse HEAD) &&
|
||||
git cvsexportcommit -w "$CVSWORK" -c $id &&
|
||||
|
||||
echo new > DS &&
|
||||
echo new > E/DS &&
|
||||
echo modified > release-notes &&
|
||||
git add DS E/DS release-notes &&
|
||||
git commit -m "Add two files with the same basename" &&
|
||||
id=$(git rev-parse HEAD) &&
|
||||
git cvsexportcommit -w "$CVSWORK" -c $id &&
|
||||
check_entries "$CVSWORK/E" "DS/1.1/|newfile5.txt/1.1/" &&
|
||||
check_entries "$CVSWORK" "DS/1.1/|release-notes/1.2/" &&
|
||||
diff -u "$CVSWORK/DS" DS &&
|
||||
diff -u "$CVSWORK/E/DS" E/DS &&
|
||||
diff -u "$CVSWORK/release-notes" release-notes
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'commit a file with leading spaces in the name' '
|
||||
|
||||
echo space > " space" &&
|
||||
git add " space" &&
|
||||
git commit -m "Add a file with a leading space" &&
|
||||
id=$(git rev-parse HEAD) &&
|
||||
git cvsexportcommit -w "$CVSWORK" -c $id &&
|
||||
check_entries "$CVSWORK" " space/1.1/|DS/1.1/|release-notes/1.2/" &&
|
||||
diff -u "$CVSWORK/ space" " space"
|
||||
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
5
tag.c
5
tag.c
@@ -9,7 +9,10 @@ const char *tag_type = "tag";
|
||||
struct object *deref_tag(struct object *o, const char *warn, int warnlen)
|
||||
{
|
||||
while (o && o->type == OBJ_TAG)
|
||||
o = parse_object(((struct tag *)o)->tagged->sha1);
|
||||
if (((struct tag *)o)->tagged)
|
||||
o = parse_object(((struct tag *)o)->tagged->sha1);
|
||||
else
|
||||
o = NULL;
|
||||
if (!o && warn) {
|
||||
if (!warnlen)
|
||||
warnlen = strlen(warn);
|
||||
|
||||
@@ -34,10 +34,10 @@ boilerplates.made : $(bpsrc)
|
||||
mkdir -p blt/$$dir && \
|
||||
case "$$boilerplate" in \
|
||||
*--) ;; \
|
||||
*) if head -1 $$boilerplate | grep -q '^#!/'; then \
|
||||
cp $$boilerplate blt/$${dst}$(NOEXECTEMPL); \
|
||||
*) if test -n "$$(sed -ne '/^#!\//p' -e '1q' < "$$boilerplate")"; then \
|
||||
cp "$$boilerplate" "blt/$${dst}$(NOEXECTEMPL)"; \
|
||||
else \
|
||||
cp $$boilerplate blt/$$dst; \
|
||||
cp "$$boilerplate" "blt/$$dst"; \
|
||||
fi ;; \
|
||||
esac || exit; \
|
||||
done && \
|
||||
|
||||
@@ -129,7 +129,8 @@ static int do_rev_list(int fd, void *create_full_pack)
|
||||
}
|
||||
setup_revisions(0, NULL, &revs, NULL);
|
||||
}
|
||||
prepare_revision_walk(&revs);
|
||||
if (prepare_revision_walk(&revs))
|
||||
die("revision walk setup failed");
|
||||
mark_edges_uninteresting(revs.commits, &revs, show_edge);
|
||||
traverse_commit_list(&revs, show_commit, show_object);
|
||||
fflush(pack_pipe);
|
||||
@@ -535,7 +536,8 @@ static void receive_needs(void)
|
||||
/* make sure the real parents are parsed */
|
||||
unregister_shallow(object->sha1);
|
||||
object->parsed = 0;
|
||||
parse_commit((struct commit *)object);
|
||||
if (parse_commit((struct commit *)object))
|
||||
die("invalid commit");
|
||||
parents = ((struct commit *)object)->parents;
|
||||
while (parents) {
|
||||
add_object_array(&parents->item->object,
|
||||
@@ -577,7 +579,8 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
|
||||
}
|
||||
if (o->type == OBJ_TAG) {
|
||||
o = deref_tag(o, refname, 0);
|
||||
packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname);
|
||||
if (o)
|
||||
packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "diffcore.h"
|
||||
|
||||
int wt_status_relative_paths = 1;
|
||||
int wt_status_use_color = 0;
|
||||
int wt_status_use_color = -1;
|
||||
static char wt_status_colors[][COLOR_MAXLEN] = {
|
||||
"", /* WT_STATUS_HEADER: normal */
|
||||
"\033[32m", /* WT_STATUS_UPDATED: green */
|
||||
@@ -40,7 +40,7 @@ static int parse_status_slot(const char *var, int offset)
|
||||
|
||||
static const char* color(int slot)
|
||||
{
|
||||
return wt_status_use_color ? wt_status_colors[slot] : "";
|
||||
return wt_status_use_color > 0 ? wt_status_colors[slot] : "";
|
||||
}
|
||||
|
||||
void wt_status_prepare(struct wt_status *s)
|
||||
@@ -403,5 +403,5 @@ int git_status_config(const char *k, const char *v)
|
||||
wt_status_relative_paths = git_config_bool(k, v);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(k, v);
|
||||
return git_color_default_config(k, v);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user