Merge branch 'master' into cc/trace
* master: Trace into a file or an open fd and refactor tracing code. Replace uses of strdup with xstrdup. consolidate two copies of new style object header parsing code. Documentation: Fix howto/revert-branch-rebase.html generation fmt-merge-msg: fix off-by-one bug git-rev-list(1): group options; reformat; document more options Constness tightening for move/link_temp_to_file() gitweb: Fix git_blame Include config.mak.autogen in the doc Makefile Use xmalloc instead of malloc git(7): move gitk(1) to the list of porcelain commands gitk: Fix some bugs in the new cherry-picking code gitk: Improve responsiveness while reading and layout out the graph gitk: Update preceding/following tag info when creating a tag gitk: Add a menu item for cherry-picking commits gitk: Fix a couple of buglets in the branch head menu items gitk: Add a context menu for heads gitk: Add a row context-menu item for creating a new branch gitk: Recompute ancestor/descendent heads/tags when rereading refs gitk: Minor cleanups
This commit is contained in:
commit
1bbb2cff62
@ -33,6 +33,8 @@ man7dir=$(mandir)/man7
|
||||
|
||||
INSTALL?=install
|
||||
|
||||
-include ../config.mak.autogen
|
||||
|
||||
#
|
||||
# Please note that there is a minor bug in asciidoc.
|
||||
# The version after 6.0.3 _will_ include the patch found here:
|
||||
@ -105,7 +107,7 @@ WEBDOC_DEST = /pub/software/scm/git/docs
|
||||
|
||||
$(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
|
||||
rm -f $@+ $@
|
||||
sed -e '1,/^$$/d' $? | asciidoc -b xhtml11 - >$@+
|
||||
sed -e '1,/^$$/d' $< | asciidoc -b xhtml11 - >$@+
|
||||
mv $@+ $@
|
||||
|
||||
install-webdoc : html
|
||||
|
@ -27,111 +27,233 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Lists commit objects in reverse chronological order starting at the
|
||||
given commit(s), taking ancestry relationship into account. This is
|
||||
useful to produce human-readable log output.
|
||||
|
||||
Commits which are stated with a preceding '{caret}' cause listing to stop at
|
||||
that point. Their parents are implied. "git-rev-list foo bar {caret}baz" thus
|
||||
Commits which are stated with a preceding '{caret}' cause listing to
|
||||
stop at that point. Their parents are implied. Thus the following
|
||||
command:
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
$ git-rev-list foo bar ^baz
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
means "list all the commits which are included in 'foo' and 'bar', but
|
||||
not in 'baz'".
|
||||
|
||||
A special notation <commit1>..<commit2> can be used as a
|
||||
short-hand for {caret}<commit1> <commit2>.
|
||||
A special notation "'<commit1>'..'<commit2>'" can be used as a
|
||||
short-hand for "{caret}'<commit1>' '<commit2>'". For example, either of
|
||||
the following may be used interchangeably:
|
||||
|
||||
Another special notation is <commit1>...<commit2> which is useful for
|
||||
merges. The resulting set of commits is the symmetric difference
|
||||
-----------------------------------------------------------------------
|
||||
$ git-rev-list origin..HEAD
|
||||
$ git-rev-list HEAD ^origin
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
Another special notation is "'<commit1>'...'<commit2>'" which is useful
|
||||
for merges. The resulting set of commits is the symmetric difference
|
||||
between the two operands. The following two commands are equivalent:
|
||||
|
||||
------------
|
||||
$ git-rev-list A B --not $(git-merge-base --all A B)
|
||||
$ git-rev-list A...B
|
||||
------------
|
||||
-----------------------------------------------------------------------
|
||||
$ git-rev-list A B --not $(git-merge-base --all A B)
|
||||
$ git-rev-list A...B
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
gitlink:git-rev-list[1] is a very essential git program, since it
|
||||
provides the ability to build and traverse commit ancestry graphs. For
|
||||
this reason, it has a lot of different options that enables it to be
|
||||
used by commands as different as gitlink:git-bisect[1] and
|
||||
gitlink:git-repack[1].
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
--pretty::
|
||||
Print the contents of the commit changesets in human-readable form.
|
||||
|
||||
Commit Formatting
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Using these options, gitlink:git-rev-list[1] will act similar to the
|
||||
more specialized family of commit log tools: gitlink:git-log[1],
|
||||
gitlink:git-show[1], and gitlink:git-whatchanged[1]
|
||||
|
||||
--pretty[='<format>']::
|
||||
|
||||
Pretty print the contents of the commit logs in a given format,
|
||||
where '<format>' can be one of 'raw', 'medium', 'short', 'full',
|
||||
and 'oneline'. When left out the format default to 'medium'.
|
||||
|
||||
--relative-date::
|
||||
|
||||
Show dates relative to the current time, e.g. "2 hours ago".
|
||||
Only takes effect for dates shown in human-readable format, such
|
||||
as when using "--pretty".
|
||||
|
||||
--header::
|
||||
Print the contents of the commit in raw-format; each
|
||||
record is separated with a NUL character.
|
||||
|
||||
Print the contents of the commit in raw-format; each record is
|
||||
separated with a NUL character.
|
||||
|
||||
--parents::
|
||||
|
||||
Print the parents of the commit.
|
||||
|
||||
--objects::
|
||||
Print the object IDs of any object referenced by the listed commits.
|
||||
'git-rev-list --objects foo ^bar' thus means "send me all object IDs
|
||||
which I need to download if I have the commit object 'bar', but
|
||||
not 'foo'".
|
||||
Diff Formatting
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
--objects-edge::
|
||||
Similar to `--objects`, but also print the IDs of
|
||||
excluded commits prefixed with a `-` character. This is
|
||||
used by `git-pack-objects` to build 'thin' pack, which
|
||||
records objects in deltified form based on objects
|
||||
contained in these excluded commits to reduce network
|
||||
traffic.
|
||||
Below are listed options that control the formatting of diff output.
|
||||
Some of them are specific to gitlink:git-rev-list[1], however other diff
|
||||
options may be given. See gitlink:git-diff-files[1] for more options.
|
||||
|
||||
--unpacked::
|
||||
Only useful with `--objects`; print the object IDs that
|
||||
are not in packs.
|
||||
-c::
|
||||
|
||||
--bisect::
|
||||
Limit output to the one commit object which is roughly halfway
|
||||
between the included and excluded commits. Thus, if 'git-rev-list
|
||||
--bisect foo {caret}bar {caret}baz' outputs 'midpoint', the output
|
||||
of 'git-rev-list foo {caret}midpoint' and 'git-rev-list midpoint
|
||||
{caret}bar {caret}baz' would be of roughly the same length.
|
||||
Finding the change
|
||||
which introduces a regression is thus reduced to a binary search:
|
||||
repeatedly generate and test new 'midpoint's until the commit chain
|
||||
is of length one.
|
||||
This flag changes the way a merge commit is displayed. It shows
|
||||
the differences from each of the parents to the merge result
|
||||
simultaneously instead of showing pairwise diff between a parent
|
||||
and the result one at a time. Furthermore, it lists only files
|
||||
which were modified from all parents.
|
||||
|
||||
--cc::
|
||||
|
||||
This flag implies the '-c' options and further compresses the
|
||||
patch output by omitting hunks that show differences from only
|
||||
one parent, or show the same change from all but one parent for
|
||||
an Octopus merge.
|
||||
|
||||
-r::
|
||||
|
||||
Show recursive diffs.
|
||||
|
||||
-t::
|
||||
|
||||
Show the tree objects in the diff output. This implies '-r'.
|
||||
|
||||
Commit Limiting
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Besides specifying a range of commits that should be listed using the
|
||||
special notations explained in the description, additional commit
|
||||
limiting may be applied.
|
||||
|
||||
--
|
||||
|
||||
-n 'number', --max-count='number'::
|
||||
|
||||
--max-count::
|
||||
Limit the number of commits output.
|
||||
|
||||
--max-age=timestamp, --min-age=timestamp::
|
||||
--since='date', --after='date'::
|
||||
|
||||
Show commits more recent than a specific date.
|
||||
|
||||
--until='date', --before='date'::
|
||||
|
||||
Show commits older than a specific date.
|
||||
|
||||
--max-age='timestamp', --min-age='timestamp'::
|
||||
|
||||
Limit the commits output to specified time range.
|
||||
|
||||
--sparse::
|
||||
When optional paths are given, the command outputs only
|
||||
the commits that changes at least one of them, and also
|
||||
ignores merges that do not touch the given paths. This
|
||||
flag makes the command output all eligible commits
|
||||
(still subject to count and age limitation), but apply
|
||||
merge simplification nevertheless.
|
||||
|
||||
--remove-empty::
|
||||
|
||||
Stop when a given path disappears from the tree.
|
||||
|
||||
--no-merges::
|
||||
|
||||
Do not print commits with more than one parent.
|
||||
|
||||
--not::
|
||||
Reverses the meaning of the '{caret}' prefix (or lack
|
||||
thereof) for all following revision specifiers, up to
|
||||
the next `--not`.
|
||||
|
||||
Reverses the meaning of the '{caret}' prefix (or lack thereof)
|
||||
for all following revision specifiers, up to the next '--not'.
|
||||
|
||||
--all::
|
||||
Pretend as if all the refs in `$GIT_DIR/refs/` are
|
||||
listed on the command line as <commit>.
|
||||
|
||||
--topo-order::
|
||||
By default, the commits are shown in reverse
|
||||
chronological order. This option makes them appear in
|
||||
topological order (i.e. descendant commits are shown
|
||||
before their parents).
|
||||
Pretend as if all the refs in `$GIT_DIR/refs/` are listed on the
|
||||
command line as '<commit>'.
|
||||
|
||||
--merge::
|
||||
|
||||
After a failed merge, show refs that touch files having a
|
||||
conflict and don't exist on all heads to merge.
|
||||
|
||||
--relative-date::
|
||||
Show dates relative to the current time, e.g. "2 hours ago".
|
||||
Only takes effect for dates shown in human-readable format,
|
||||
such as when using "--pretty".
|
||||
--boundary::
|
||||
|
||||
Output uninteresting commits at the boundary, which are usually
|
||||
not shown.
|
||||
|
||||
--dense, --sparse::
|
||||
|
||||
When optional paths are given, the default behaviour ('--dense') is to
|
||||
only output commits that changes at least one of them, and also ignore
|
||||
merges that do not touch the given paths.
|
||||
|
||||
Use the '--sparse' flag to makes the command output all eligible commits
|
||||
(still subject to count and age limitation), but apply merge
|
||||
simplification nevertheless.
|
||||
|
||||
--bisect::
|
||||
|
||||
Limit output to the one commit object which is roughly halfway between
|
||||
the included and excluded commits. Thus, if
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
$ git-rev-list --bisect foo ^bar ^baz
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
outputs 'midpoint', the output of the two commands
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
$ git-rev-list foo ^midpoint
|
||||
$ git-rev-list midpoint ^bar ^baz
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
would be of roughly the same length. Finding the change which
|
||||
introduces a regression is thus reduced to a binary search: repeatedly
|
||||
generate and test new 'midpoint's until the commit chain is of length
|
||||
one.
|
||||
|
||||
--
|
||||
|
||||
Commit Ordering
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
By default, the commits are shown in reverse chronological order.
|
||||
|
||||
--topo-order::
|
||||
|
||||
This option makes them appear in topological order (i.e.
|
||||
descendant commits are shown before their parents).
|
||||
|
||||
--date-order::
|
||||
|
||||
This option is similar to '--topo-order' in the sense that no
|
||||
parent comes before all of its children, but otherwise things
|
||||
are still ordered in the commit timestamp order.
|
||||
|
||||
Object Traversal
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
These options are mostly targeted for packing of git repositories.
|
||||
|
||||
--objects::
|
||||
|
||||
Print the object IDs of any object referenced by the listed
|
||||
commits. 'git-rev-list --objects foo ^bar' thus means "send me
|
||||
all object IDs which I need to download if I have the commit
|
||||
object 'bar', but not 'foo'".
|
||||
|
||||
--objects-edge::
|
||||
|
||||
Similar to '--objects', but also print the IDs of excluded
|
||||
commits prefixed with a "-" character. This is used by
|
||||
gitlink:git-pack-objects[1] to build "thin" pack, which records
|
||||
objects in deltified form based on objects contained in these
|
||||
excluded commits to reduce network traffic.
|
||||
|
||||
--unpacked::
|
||||
|
||||
Only useful with '--objects'; print the object IDs that are not
|
||||
in packs.
|
||||
|
||||
Author
|
||||
------
|
||||
@ -139,9 +261,9 @@ Written by Linus Torvalds <torvalds@osdl.org>
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
|
||||
Documentation by David Greaves, Junio C Hamano, Jonas Fonseca
|
||||
and the git-list <git@vger.kernel.org>.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the gitlink:git[7] suite
|
||||
|
||||
|
@ -303,6 +303,9 @@ gitlink:git-format-patch[1]::
|
||||
gitlink:git-grep[1]::
|
||||
Print lines matching a pattern.
|
||||
|
||||
gitlink:gitk[1]::
|
||||
The git repository browser.
|
||||
|
||||
gitlink:git-log[1]::
|
||||
Shows commit logs.
|
||||
|
||||
@ -483,13 +486,6 @@ gitlink:git-stripspace[1]::
|
||||
Filter out empty lines.
|
||||
|
||||
|
||||
Commands not yet documented
|
||||
---------------------------
|
||||
|
||||
gitlink:gitk[1]::
|
||||
The gitk repository browser.
|
||||
|
||||
|
||||
Configuration Mechanism
|
||||
-----------------------
|
||||
|
||||
|
2
blame.c
2
blame.c
@ -617,7 +617,7 @@ static void simplify_commit(struct rev_info *revs, struct commit *commit)
|
||||
if (new_name) {
|
||||
struct util_info* putil = get_util(p);
|
||||
if (!putil->pathname)
|
||||
putil->pathname = strdup(new_name);
|
||||
putil->pathname = xstrdup(new_name);
|
||||
} else {
|
||||
*pp = parent->next;
|
||||
continue;
|
||||
|
@ -2449,7 +2449,7 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
|
||||
static int git_apply_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "apply.whitespace")) {
|
||||
apply_default_whitespace = strdup(value);
|
||||
apply_default_whitespace = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(var, value);
|
||||
|
@ -111,43 +111,43 @@ static int handle_line(char *line)
|
||||
i = find_in_list(&srcs, src);
|
||||
if (i < 0) {
|
||||
i = srcs.nr;
|
||||
append_to_list(&srcs, strdup(src),
|
||||
append_to_list(&srcs, xstrdup(src),
|
||||
xcalloc(1, sizeof(struct src_data)));
|
||||
}
|
||||
src_data = srcs.payload[i];
|
||||
|
||||
if (pulling_head) {
|
||||
origin = strdup(src);
|
||||
origin = xstrdup(src);
|
||||
src_data->head_status |= 1;
|
||||
} else if (!strncmp(line, "branch ", 7)) {
|
||||
origin = strdup(line + 7);
|
||||
origin = xstrdup(line + 7);
|
||||
append_to_list(&src_data->branch, origin, NULL);
|
||||
src_data->head_status |= 2;
|
||||
} else if (!strncmp(line, "tag ", 4)) {
|
||||
origin = line;
|
||||
append_to_list(&src_data->tag, strdup(origin + 4), NULL);
|
||||
append_to_list(&src_data->tag, xstrdup(origin + 4), NULL);
|
||||
src_data->head_status |= 2;
|
||||
} else if (!strncmp(line, "remote branch ", 14)) {
|
||||
origin = strdup(line + 14);
|
||||
origin = xstrdup(line + 14);
|
||||
append_to_list(&src_data->r_branch, origin, NULL);
|
||||
src_data->head_status |= 2;
|
||||
} else {
|
||||
origin = strdup(src);
|
||||
append_to_list(&src_data->generic, strdup(line), NULL);
|
||||
origin = xstrdup(src);
|
||||
append_to_list(&src_data->generic, xstrdup(line), NULL);
|
||||
src_data->head_status |= 2;
|
||||
}
|
||||
|
||||
if (!strcmp(".", src) || !strcmp(src, origin)) {
|
||||
int len = strlen(origin);
|
||||
if (origin[0] == '\'' && origin[len - 1] == '\'') {
|
||||
char *new_origin = malloc(len - 1);
|
||||
char *new_origin = xmalloc(len - 1);
|
||||
memcpy(new_origin, origin + 1, len - 2);
|
||||
new_origin[len - 1] = 0;
|
||||
new_origin[len - 2] = 0;
|
||||
origin = new_origin;
|
||||
} else
|
||||
origin = strdup(origin);
|
||||
origin = xstrdup(origin);
|
||||
} else {
|
||||
char *new_origin = malloc(strlen(origin) + strlen(src) + 5);
|
||||
char *new_origin = xmalloc(strlen(origin) + strlen(src) + 5);
|
||||
sprintf(new_origin, "%s of %s", origin, src);
|
||||
origin = new_origin;
|
||||
}
|
||||
@ -203,7 +203,7 @@ static void shortlog(const char *name, unsigned char *sha1,
|
||||
|
||||
bol = strstr(commit->buffer, "\n\n");
|
||||
if (!bol) {
|
||||
append_to_list(&subjects, strdup(sha1_to_hex(
|
||||
append_to_list(&subjects, xstrdup(sha1_to_hex(
|
||||
commit->object.sha1)),
|
||||
NULL);
|
||||
continue;
|
||||
@ -214,11 +214,11 @@ static void shortlog(const char *name, unsigned char *sha1,
|
||||
|
||||
if (eol) {
|
||||
int len = eol - bol;
|
||||
oneline = malloc(len + 1);
|
||||
oneline = xmalloc(len + 1);
|
||||
memcpy(oneline, bol, len);
|
||||
oneline[len] = 0;
|
||||
} else
|
||||
oneline = strdup(bol);
|
||||
oneline = xstrdup(bol);
|
||||
append_to_list(&subjects, oneline, NULL);
|
||||
}
|
||||
|
||||
@ -277,7 +277,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
|
||||
usage(fmt_merge_msg_usage);
|
||||
|
||||
/* get current branch */
|
||||
head = strdup(git_path("HEAD"));
|
||||
head = xstrdup(git_path("HEAD"));
|
||||
current_branch = resolve_ref(head, head_sha1, 1);
|
||||
current_branch += strlen(head) - 4;
|
||||
free((char *)head);
|
||||
|
@ -1048,7 +1048,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
|
||||
/* ignore empty line like grep does */
|
||||
if (!buf[0])
|
||||
continue;
|
||||
add_pattern(&opt, strdup(buf), argv[1], ++lno,
|
||||
add_pattern(&opt, xstrdup(buf), argv[1], ++lno,
|
||||
GREP_PATTERN);
|
||||
}
|
||||
fclose(patterns);
|
||||
|
@ -100,7 +100,7 @@ static int name_ref(const char *path, const unsigned char *sha1)
|
||||
else if (!strncmp(path, "refs/", 5))
|
||||
path = path + 5;
|
||||
|
||||
name_rev(commit, strdup(path), 0, 0, deref);
|
||||
name_rev(commit, xstrdup(path), 0, 0, deref);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ static void process_tree(struct tree *tree,
|
||||
obj->flags |= SEEN;
|
||||
if (parse_tree(tree) < 0)
|
||||
die("bad tree object %s", sha1_to_hex(obj->sha1));
|
||||
name = strdup(name);
|
||||
name = xstrdup(name);
|
||||
add_object(obj, p, path, name);
|
||||
me.up = path;
|
||||
me.elem = name;
|
||||
|
@ -33,7 +33,7 @@ static int expand_one_ref(const char *ref, const unsigned char *sha1)
|
||||
ref += 5;
|
||||
|
||||
if (!strncmp(ref, "tags/", 5))
|
||||
add_refspec(strdup(ref));
|
||||
add_refspec(xstrdup(ref));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -100,12 +100,12 @@ static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
|
||||
|
||||
if (!is_refspec) {
|
||||
if (n < MAX_URI)
|
||||
uri[n++] = strdup(s);
|
||||
uri[n++] = xstrdup(s);
|
||||
else
|
||||
error("more than %d URL's specified, ignoring the rest", MAX_URI);
|
||||
}
|
||||
else if (is_refspec && !has_explicit_refspec)
|
||||
add_refspec(strdup(s));
|
||||
add_refspec(xstrdup(s));
|
||||
}
|
||||
fclose(f);
|
||||
if (!n)
|
||||
@ -125,13 +125,13 @@ static int get_remote_config(const char* key, const char* value)
|
||||
!strncmp(key + 7, config_repo, config_repo_len)) {
|
||||
if (!strcmp(key + 7 + config_repo_len, ".url")) {
|
||||
if (config_current_uri < MAX_URI)
|
||||
config_uri[config_current_uri++] = strdup(value);
|
||||
config_uri[config_current_uri++] = xstrdup(value);
|
||||
else
|
||||
error("more than %d URL's specified, ignoring the rest", MAX_URI);
|
||||
}
|
||||
else if (config_get_refspecs &&
|
||||
!strcmp(key + 7 + config_repo_len, ".push"))
|
||||
add_refspec(strdup(value));
|
||||
add_refspec(xstrdup(value));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -72,19 +72,19 @@ static int get_value(const char* key_, const char* regex_)
|
||||
const char *home = getenv("HOME");
|
||||
local = getenv("GIT_CONFIG_LOCAL");
|
||||
if (!local)
|
||||
local = repo_config = strdup(git_path("config"));
|
||||
local = repo_config = xstrdup(git_path("config"));
|
||||
if (home)
|
||||
global = strdup(mkpath("%s/.gitconfig", home));
|
||||
global = xstrdup(mkpath("%s/.gitconfig", home));
|
||||
}
|
||||
|
||||
key = strdup(key_);
|
||||
key = xstrdup(key_);
|
||||
for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
|
||||
*tl = tolower(*tl);
|
||||
for (tl=key; *tl && *tl != '.'; ++tl)
|
||||
*tl = tolower(*tl);
|
||||
|
||||
if (use_key_regexp) {
|
||||
key_regexp = (regex_t*)malloc(sizeof(regex_t));
|
||||
key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
|
||||
if (regcomp(key_regexp, key, REG_EXTENDED)) {
|
||||
fprintf(stderr, "Invalid key pattern: %s\n", key_);
|
||||
goto free_strings;
|
||||
@ -97,7 +97,7 @@ static int get_value(const char* key_, const char* regex_)
|
||||
regex_++;
|
||||
}
|
||||
|
||||
regexp = (regex_t*)malloc(sizeof(regex_t));
|
||||
regexp = (regex_t*)xmalloc(sizeof(regex_t));
|
||||
if (regcomp(regexp, regex_, REG_EXTENDED)) {
|
||||
fprintf(stderr, "Invalid pattern: %s\n", regex_);
|
||||
goto free_strings;
|
||||
|
@ -109,7 +109,7 @@ static void process_blob(struct blob *blob,
|
||||
if (obj->flags & (UNINTERESTING | SEEN))
|
||||
return;
|
||||
obj->flags |= SEEN;
|
||||
name = strdup(name);
|
||||
name = xstrdup(name);
|
||||
add_object(obj, p, path, name);
|
||||
}
|
||||
|
||||
@ -130,7 +130,7 @@ static void process_tree(struct tree *tree,
|
||||
if (parse_tree(tree) < 0)
|
||||
die("bad tree object %s", sha1_to_hex(obj->sha1));
|
||||
obj->flags |= SEEN;
|
||||
name = strdup(name);
|
||||
name = xstrdup(name);
|
||||
add_object(obj, p, path, name);
|
||||
me.up = path;
|
||||
me.elem = name;
|
||||
|
@ -32,7 +32,7 @@ static int remove_file(const char *name)
|
||||
|
||||
ret = unlink(name);
|
||||
if (!ret && (slash = strrchr(name, '/'))) {
|
||||
char *n = strdup(name);
|
||||
char *n = xstrdup(name);
|
||||
do {
|
||||
n[slash - name] = 0;
|
||||
name = n;
|
||||
|
@ -163,7 +163,7 @@ static void name_commits(struct commit_list *list,
|
||||
en += sprintf(en, "^");
|
||||
else
|
||||
en += sprintf(en, "^%d", nth);
|
||||
name_commit(p, strdup(newname), 0);
|
||||
name_commit(p, xstrdup(newname), 0);
|
||||
i++;
|
||||
name_first_parent_chain(p);
|
||||
}
|
||||
@ -364,7 +364,7 @@ static int append_ref(const char *refname, const unsigned char *sha1)
|
||||
refname, MAX_REVS);
|
||||
return 0;
|
||||
}
|
||||
ref_name[ref_name_cnt++] = strdup(refname);
|
||||
ref_name[ref_name_cnt++] = xstrdup(refname);
|
||||
ref_name[ref_name_cnt] = NULL;
|
||||
return 0;
|
||||
}
|
||||
@ -521,7 +521,7 @@ static int git_show_branch_config(const char *var, const char *value)
|
||||
default_alloc = default_alloc * 3 / 2 + 20;
|
||||
default_arg = xrealloc(default_arg, sizeof *default_arg * default_alloc);
|
||||
}
|
||||
default_arg[default_num++] = strdup(value);
|
||||
default_arg[default_num++] = xstrdup(value);
|
||||
default_arg[default_num] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ static const char git_symbolic_ref_usage[] =
|
||||
static void check_symref(const char *HEAD)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
const char *git_HEAD = strdup(git_path("%s", HEAD));
|
||||
const char *git_HEAD = xstrdup(git_path("%s", HEAD));
|
||||
const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 0);
|
||||
if (git_refs_heads_master) {
|
||||
/* we want to strip the .git/ part */
|
||||
@ -26,7 +26,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
|
||||
check_symref(argv[1]);
|
||||
break;
|
||||
case 3:
|
||||
create_symref(strdup(git_path("%s", argv[1])), argv[2]);
|
||||
create_symref(xstrdup(git_path("%s", argv[1])), argv[2]);
|
||||
break;
|
||||
default:
|
||||
usage(git_symbolic_ref_usage);
|
||||
|
@ -351,7 +351,7 @@ static int remote_tar(int argc, const char **argv)
|
||||
usage(tar_tree_usage);
|
||||
|
||||
/* --remote=<repo> */
|
||||
url = strdup(argv[1]+9);
|
||||
url = xstrdup(argv[1]+9);
|
||||
pid = git_connect(fd, url, exec);
|
||||
if (pid < 0)
|
||||
return 1;
|
||||
|
@ -53,7 +53,7 @@ int cmd_upload_tar(int argc, const char **argv, const char *prefix)
|
||||
return nak("expected (optional) base");
|
||||
if (buf[len-1] == '\n')
|
||||
buf[--len] = 0;
|
||||
base = strdup(buf + 5);
|
||||
base = xstrdup(buf + 5);
|
||||
len = packet_read_line(0, buf, sizeof(buf));
|
||||
}
|
||||
if (len)
|
||||
|
@ -311,11 +311,11 @@ int cmd_zip_tree(int argc, const char **argv, const char *prefix)
|
||||
|
||||
switch (argc) {
|
||||
case 3:
|
||||
base = strdup(argv[2]);
|
||||
base = xstrdup(argv[2]);
|
||||
baselen = strlen(base);
|
||||
break;
|
||||
case 2:
|
||||
base = strdup("");
|
||||
base = xstrdup("");
|
||||
baselen = 0;
|
||||
break;
|
||||
default:
|
||||
|
2
cache.h
2
cache.h
@ -257,7 +257,7 @@ extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned l
|
||||
extern int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
|
||||
size_t bufsize, size_t *bufposn);
|
||||
extern int write_sha1_to_fd(int fd, const unsigned char *sha1);
|
||||
extern int move_temp_to_file(const char *tmpfile, char *filename);
|
||||
extern int move_temp_to_file(const char *tmpfile, const char *filename);
|
||||
|
||||
extern int has_sha1_pack(const unsigned char *sha1);
|
||||
extern int has_sha1_file(const unsigned char *sha1);
|
||||
|
12
config.c
12
config.c
@ -350,11 +350,11 @@ int git_config(config_fn_t fn)
|
||||
home = getenv("HOME");
|
||||
filename = getenv("GIT_CONFIG_LOCAL");
|
||||
if (!filename)
|
||||
filename = repo_config = strdup(git_path("config"));
|
||||
filename = repo_config = xstrdup(git_path("config"));
|
||||
}
|
||||
|
||||
if (home) {
|
||||
char *user_config = strdup(mkpath("%s/.gitconfig", home));
|
||||
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
|
||||
if (!access(user_config, R_OK))
|
||||
ret = git_config_from_file(fn, user_config);
|
||||
free(user_config);
|
||||
@ -545,8 +545,8 @@ int git_config_set_multivar(const char* key, const char* value,
|
||||
if (!config_filename)
|
||||
config_filename = git_path("config");
|
||||
}
|
||||
config_filename = strdup(config_filename);
|
||||
lock_file = strdup(mkpath("%s.lock", config_filename));
|
||||
config_filename = xstrdup(config_filename);
|
||||
lock_file = xstrdup(mkpath("%s.lock", config_filename));
|
||||
|
||||
/*
|
||||
* Since "key" actually contains the section name and the real
|
||||
@ -565,7 +565,7 @@ int git_config_set_multivar(const char* key, const char* value,
|
||||
/*
|
||||
* Validate the key and while at it, lower case it for matching.
|
||||
*/
|
||||
store.key = (char*)malloc(strlen(key)+1);
|
||||
store.key = xmalloc(strlen(key) + 1);
|
||||
dot = 0;
|
||||
for (i = 0; key[i]; i++) {
|
||||
unsigned char c = key[i];
|
||||
@ -633,7 +633,7 @@ int git_config_set_multivar(const char* key, const char* value,
|
||||
} else
|
||||
store.do_not_match = 0;
|
||||
|
||||
store.value_regex = (regex_t*)malloc(sizeof(regex_t));
|
||||
store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
|
||||
if (regcomp(store.value_regex, value_regex,
|
||||
REG_EXTENDED)) {
|
||||
fprintf(stderr, "Invalid pattern: %s\n",
|
||||
|
@ -69,7 +69,7 @@ struct ref **get_remote_heads(int in, struct ref **list,
|
||||
if (len != name_len + 41) {
|
||||
if (server_capabilities)
|
||||
free(server_capabilities);
|
||||
server_capabilities = strdup(name + name_len + 1);
|
||||
server_capabilities = xstrdup(name + name_len + 1);
|
||||
}
|
||||
|
||||
if (!check_ref(name, name_len, flags))
|
||||
@ -661,7 +661,7 @@ int git_connect(int fd[2], char *url, const char *prog)
|
||||
if (path[1] == '~')
|
||||
path++;
|
||||
else {
|
||||
path = strdup(ptr);
|
||||
path = xstrdup(ptr);
|
||||
free_path = 1;
|
||||
}
|
||||
|
||||
@ -672,7 +672,7 @@ int git_connect(int fd[2], char *url, const char *prog)
|
||||
/* These underlying connection commands die() if they
|
||||
* cannot connect.
|
||||
*/
|
||||
char *target_host = strdup(host);
|
||||
char *target_host = xstrdup(host);
|
||||
if (git_use_proxy(host))
|
||||
git_proxy_connect(fd, host);
|
||||
else
|
||||
|
4
diff.c
4
diff.c
@ -216,7 +216,7 @@ static char *quote_one(const char *str)
|
||||
return NULL;
|
||||
needlen = quote_c_style(str, NULL, NULL, 0);
|
||||
if (!needlen)
|
||||
return strdup(str);
|
||||
return xstrdup(str);
|
||||
xp = xmalloc(needlen + 1);
|
||||
quote_c_style(str, xp, NULL, 0);
|
||||
return xp;
|
||||
@ -658,7 +658,7 @@ static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat,
|
||||
x->is_renamed = 1;
|
||||
}
|
||||
else
|
||||
x->name = strdup(name_a);
|
||||
x->name = xstrdup(name_a);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ static void setup_git_env(void)
|
||||
}
|
||||
git_graft_file = getenv(GRAFT_ENVIRONMENT);
|
||||
if (!git_graft_file)
|
||||
git_graft_file = strdup(git_path("info/grafts"));
|
||||
git_graft_file = xstrdup(git_path("info/grafts"));
|
||||
}
|
||||
|
||||
const char *get_git_dir(void)
|
||||
|
4
fetch.c
4
fetch.c
@ -234,8 +234,8 @@ int pull_targets_stdin(char ***target, const char ***write_ref)
|
||||
*target = xrealloc(*target, targets_alloc * sizeof(**target));
|
||||
*write_ref = xrealloc(*write_ref, targets_alloc * sizeof(**write_ref));
|
||||
}
|
||||
(*target)[targets] = strdup(tg_one);
|
||||
(*write_ref)[targets] = rf_one ? strdup(rf_one) : NULL;
|
||||
(*target)[targets] = xstrdup(tg_one);
|
||||
(*write_ref)[targets] = rf_one ? xstrdup(rf_one) : NULL;
|
||||
targets++;
|
||||
}
|
||||
return targets;
|
||||
|
@ -458,7 +458,7 @@ static void fsck_object_dir(const char *path)
|
||||
static int fsck_head_link(void)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
const char *git_HEAD = strdup(git_path("HEAD"));
|
||||
const char *git_HEAD = xstrdup(git_path("HEAD"));
|
||||
const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 1);
|
||||
int pfxlen = strlen(git_HEAD) - 4; /* strip .../.git/ part */
|
||||
|
||||
|
@ -84,6 +84,14 @@ extern char *gitstrcasestr(const char *haystack, const char *needle);
|
||||
extern size_t gitstrlcpy(char *, const char *, size_t);
|
||||
#endif
|
||||
|
||||
static inline char* xstrdup(const char *str)
|
||||
{
|
||||
char *ret = strdup(str);
|
||||
if (!ret)
|
||||
die("Out of memory, strdup failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void *xmalloc(size_t size)
|
||||
{
|
||||
void *ret = malloc(size);
|
||||
|
4
git.c
4
git.c
@ -29,7 +29,7 @@ static void prepend_to_path(const char *dir, int len)
|
||||
|
||||
path_len = len + strlen(old_path) + 1;
|
||||
|
||||
path = malloc(path_len + 1);
|
||||
path = xmalloc(path_len + 1);
|
||||
|
||||
memcpy(path, dir, len);
|
||||
path[len] = ':';
|
||||
@ -97,7 +97,7 @@ static char *alias_string;
|
||||
static int git_alias_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strncmp(var, "alias.", 6) && !strcmp(var + 6, alias_command)) {
|
||||
alias_string = strdup(value);
|
||||
alias_string = xstrdup(value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
682
gitk
682
gitk
@ -2,7 +2,7 @@
|
||||
# Tcl ignores the next line -*- tcl -*- \
|
||||
exec wish "$0" -- "$@"
|
||||
|
||||
# Copyright (C) 2005 Paul Mackerras. All rights reserved.
|
||||
# Copyright (C) 2005-2006 Paul Mackerras. All rights reserved.
|
||||
# This program is free software; it may be used, copied, modified
|
||||
# and distributed under the terms of the GNU General Public Licence,
|
||||
# either version 2, or (at your option) any later version.
|
||||
@ -17,13 +17,12 @@ proc gitdir {} {
|
||||
}
|
||||
|
||||
proc start_rev_list {view} {
|
||||
global startmsecs nextupdate ncmupdate
|
||||
global startmsecs nextupdate
|
||||
global commfd leftover tclencoding datemode
|
||||
global viewargs viewfiles commitidx
|
||||
|
||||
set startmsecs [clock clicks -milliseconds]
|
||||
set nextupdate [expr {$startmsecs + 100}]
|
||||
set ncmupdate 1
|
||||
set commitidx($view) 0
|
||||
set args $viewargs($view)
|
||||
if {$viewfiles($view) ne {}} {
|
||||
@ -79,7 +78,7 @@ proc getcommitlines {fd view} {
|
||||
global parentlist childlist children curview hlview
|
||||
global vparentlist vchildlist vdisporder vcmitlisted
|
||||
|
||||
set stuff [read $fd]
|
||||
set stuff [read $fd 500000]
|
||||
if {$stuff == {}} {
|
||||
if {![eof $fd]} return
|
||||
global viewname
|
||||
@ -185,7 +184,7 @@ proc getcommitlines {fd view} {
|
||||
}
|
||||
if {$gotsome} {
|
||||
if {$view == $curview} {
|
||||
layoutmore
|
||||
while {[layoutmore $nextupdate]} doupdate
|
||||
} elseif {[info exists hlview] && $view == $hlview} {
|
||||
vhighlightmore
|
||||
}
|
||||
@ -196,20 +195,13 @@ proc getcommitlines {fd view} {
|
||||
}
|
||||
|
||||
proc doupdate {} {
|
||||
global commfd nextupdate numcommits ncmupdate
|
||||
global commfd nextupdate numcommits
|
||||
|
||||
foreach v [array names commfd] {
|
||||
fileevent $commfd($v) readable {}
|
||||
}
|
||||
update
|
||||
set nextupdate [expr {[clock clicks -milliseconds] + 100}]
|
||||
if {$numcommits < 100} {
|
||||
set ncmupdate [expr {$numcommits + 1}]
|
||||
} elseif {$numcommits < 10000} {
|
||||
set ncmupdate [expr {$numcommits + 10}]
|
||||
} else {
|
||||
set ncmupdate [expr {$numcommits + 100}]
|
||||
}
|
||||
foreach v [array names commfd] {
|
||||
set fd $commfd($v)
|
||||
fileevent $fd readable [list getcommitlines $fd $v]
|
||||
@ -341,13 +333,13 @@ proc readrefs {} {
|
||||
set tag {}
|
||||
catch {
|
||||
set commit [exec git rev-parse "$id^0"]
|
||||
if {"$commit" != "$id"} {
|
||||
if {$commit != $id} {
|
||||
set tagids($name) $commit
|
||||
lappend idtags($commit) $name
|
||||
}
|
||||
}
|
||||
catch {
|
||||
set tagcontents($name) [exec git cat-file tag "$id"]
|
||||
set tagcontents($name) [exec git cat-file tag $id]
|
||||
}
|
||||
} elseif { $type == "heads" } {
|
||||
set headids($name) $id
|
||||
@ -384,6 +376,23 @@ proc error_popup msg {
|
||||
show_error $w $w $msg
|
||||
}
|
||||
|
||||
proc confirm_popup msg {
|
||||
global confirm_ok
|
||||
set confirm_ok 0
|
||||
set w .confirm
|
||||
toplevel $w
|
||||
wm transient $w .
|
||||
message $w.m -text $msg -justify center -aspect 400
|
||||
pack $w.m -side top -fill x -padx 20 -pady 20
|
||||
button $w.ok -text OK -command "set confirm_ok 1; destroy $w"
|
||||
pack $w.ok -side left -fill x
|
||||
button $w.cancel -text Cancel -command "destroy $w"
|
||||
pack $w.cancel -side right -fill x
|
||||
bind $w <Visibility> "grab $w; focus $w"
|
||||
tkwait window $w
|
||||
return $confirm_ok
|
||||
}
|
||||
|
||||
proc makewindow {} {
|
||||
global canv canv2 canv3 linespc charspc ctext cflist
|
||||
global textfont mainfont uifont
|
||||
@ -394,6 +403,7 @@ proc makewindow {} {
|
||||
global highlight_files gdttype
|
||||
global searchstring sstring
|
||||
global bgcolor fgcolor bglist fglist diffcolors
|
||||
global headctxmenu
|
||||
|
||||
menu .bar
|
||||
.bar add cascade -label "File" -menu .bar.file
|
||||
@ -711,6 +721,16 @@ proc makewindow {} {
|
||||
$rowctxmenu add command -label "Make patch" -command mkpatch
|
||||
$rowctxmenu add command -label "Create tag" -command mktag
|
||||
$rowctxmenu add command -label "Write commit to file" -command writecommit
|
||||
$rowctxmenu add command -label "Create new branch" -command mkbranch
|
||||
$rowctxmenu add command -label "Cherry-pick this commit" \
|
||||
-command cherrypick
|
||||
|
||||
set headctxmenu .headctxmenu
|
||||
menu $headctxmenu -tearoff 0
|
||||
$headctxmenu add command -label "Check out this branch" \
|
||||
-command cobranch
|
||||
$headctxmenu add command -label "Remove this branch" \
|
||||
-command rmbranch
|
||||
}
|
||||
|
||||
# mouse-2 makes all windows scan vertically, but only the one
|
||||
@ -1669,7 +1689,7 @@ proc showview {n} {
|
||||
show_status "Reading commits..."
|
||||
}
|
||||
if {[info exists commfd($n)]} {
|
||||
layoutmore
|
||||
layoutmore {}
|
||||
} else {
|
||||
finishcommits
|
||||
}
|
||||
@ -2350,20 +2370,38 @@ proc visiblerows {} {
|
||||
return [list $r0 $r1]
|
||||
}
|
||||
|
||||
proc layoutmore {} {
|
||||
proc layoutmore {tmax} {
|
||||
global rowlaidout rowoptim commitidx numcommits optim_delay
|
||||
global uparrowlen curview
|
||||
|
||||
set row $rowlaidout
|
||||
set rowlaidout [layoutrows $row $commitidx($curview) 0]
|
||||
set orow [expr {$rowlaidout - $uparrowlen - 1}]
|
||||
if {$orow > $rowoptim} {
|
||||
optimize_rows $rowoptim 0 $orow
|
||||
set rowoptim $orow
|
||||
}
|
||||
set canshow [expr {$rowoptim - $optim_delay}]
|
||||
if {$canshow > $numcommits} {
|
||||
showstuff $canshow
|
||||
while {1} {
|
||||
if {$rowoptim - $optim_delay > $numcommits} {
|
||||
showstuff [expr {$rowoptim - $optim_delay}]
|
||||
} elseif {$rowlaidout - $uparrowlen - 1 > $rowoptim} {
|
||||
set nr [expr {$rowlaidout - $uparrowlen - 1 - $rowoptim}]
|
||||
if {$nr > 100} {
|
||||
set nr 100
|
||||
}
|
||||
optimize_rows $rowoptim 0 [expr {$rowoptim + $nr}]
|
||||
incr rowoptim $nr
|
||||
} elseif {$commitidx($curview) > $rowlaidout} {
|
||||
set nr [expr {$commitidx($curview) - $rowlaidout}]
|
||||
# may need to increase this threshold if uparrowlen or
|
||||
# mingaplen are increased...
|
||||
if {$nr > 150} {
|
||||
set nr 150
|
||||
}
|
||||
set row $rowlaidout
|
||||
set rowlaidout [layoutrows $row [expr {$row + $nr}] 0]
|
||||
if {$rowlaidout == $row} {
|
||||
return 0
|
||||
}
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
if {$tmax ne {} && [clock clicks -milliseconds] >= $tmax} {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3236,6 +3274,8 @@ proc drawtags {id x xt y1} {
|
||||
-font $font -tags [list tag.$id text]]
|
||||
if {$ntags >= 0} {
|
||||
$canv bind $t <1> [list showtag $tag 1]
|
||||
} elseif {$nheads >= 0} {
|
||||
$canv bind $t <Button-3> [list headmenu %X %Y $id $tag]
|
||||
}
|
||||
}
|
||||
return $xt
|
||||
@ -3263,8 +3303,7 @@ proc show_status {msg} {
|
||||
|
||||
proc finishcommits {} {
|
||||
global commitidx phase curview
|
||||
global canv mainfont ctext maincursor textcursor
|
||||
global findinprogress pending_select
|
||||
global pending_select
|
||||
|
||||
if {$commitidx($curview) > 0} {
|
||||
drawrest
|
||||
@ -3275,6 +3314,108 @@ proc finishcommits {} {
|
||||
catch {unset pending_select}
|
||||
}
|
||||
|
||||
# Insert a new commit as the child of the commit on row $row.
|
||||
# The new commit will be displayed on row $row and the commits
|
||||
# on that row and below will move down one row.
|
||||
proc insertrow {row newcmit} {
|
||||
global displayorder parentlist childlist commitlisted
|
||||
global commitrow curview rowidlist rowoffsets numcommits
|
||||
global rowrangelist idrowranges rowlaidout rowoptim numcommits
|
||||
global linesegends selectedline
|
||||
|
||||
if {$row >= $numcommits} {
|
||||
puts "oops, inserting new row $row but only have $numcommits rows"
|
||||
return
|
||||
}
|
||||
set p [lindex $displayorder $row]
|
||||
set displayorder [linsert $displayorder $row $newcmit]
|
||||
set parentlist [linsert $parentlist $row $p]
|
||||
set kids [lindex $childlist $row]
|
||||
lappend kids $newcmit
|
||||
lset childlist $row $kids
|
||||
set childlist [linsert $childlist $row {}]
|
||||
set commitlisted [linsert $commitlisted $row 1]
|
||||
set l [llength $displayorder]
|
||||
for {set r $row} {$r < $l} {incr r} {
|
||||
set id [lindex $displayorder $r]
|
||||
set commitrow($curview,$id) $r
|
||||
}
|
||||
|
||||
set idlist [lindex $rowidlist $row]
|
||||
set offs [lindex $rowoffsets $row]
|
||||
set newoffs {}
|
||||
foreach x $idlist {
|
||||
if {$x eq {} || ($x eq $p && [llength $kids] == 1)} {
|
||||
lappend newoffs {}
|
||||
} else {
|
||||
lappend newoffs 0
|
||||
}
|
||||
}
|
||||
if {[llength $kids] == 1} {
|
||||
set col [lsearch -exact $idlist $p]
|
||||
lset idlist $col $newcmit
|
||||
} else {
|
||||
set col [llength $idlist]
|
||||
lappend idlist $newcmit
|
||||
lappend offs {}
|
||||
lset rowoffsets $row $offs
|
||||
}
|
||||
set rowidlist [linsert $rowidlist $row $idlist]
|
||||
set rowoffsets [linsert $rowoffsets [expr {$row+1}] $newoffs]
|
||||
|
||||
set rowrangelist [linsert $rowrangelist $row {}]
|
||||
set l [llength $rowrangelist]
|
||||
for {set r 0} {$r < $l} {incr r} {
|
||||
set ranges [lindex $rowrangelist $r]
|
||||
if {$ranges ne {} && [lindex $ranges end] >= $row} {
|
||||
set newranges {}
|
||||
foreach x $ranges {
|
||||
if {$x >= $row} {
|
||||
lappend newranges [expr {$x + 1}]
|
||||
} else {
|
||||
lappend newranges $x
|
||||
}
|
||||
}
|
||||
lset rowrangelist $r $newranges
|
||||
}
|
||||
}
|
||||
if {[llength $kids] > 1} {
|
||||
set rp1 [expr {$row + 1}]
|
||||
set ranges [lindex $rowrangelist $rp1]
|
||||
if {$ranges eq {}} {
|
||||
set ranges [list $row $rp1]
|
||||
} elseif {[lindex $ranges end-1] == $rp1} {
|
||||
lset ranges end-1 $row
|
||||
}
|
||||
lset rowrangelist $rp1 $ranges
|
||||
}
|
||||
foreach id [array names idrowranges] {
|
||||
set ranges $idrowranges($id)
|
||||
if {$ranges ne {} && [lindex $ranges end] >= $row} {
|
||||
set newranges {}
|
||||
foreach x $ranges {
|
||||
if {$x >= $row} {
|
||||
lappend newranges [expr {$x + 1}]
|
||||
} else {
|
||||
lappend newranges $x
|
||||
}
|
||||
}
|
||||
set idrowranges($id) $newranges
|
||||
}
|
||||
}
|
||||
|
||||
set linesegends [linsert $linesegends $row {}]
|
||||
|
||||
incr rowlaidout
|
||||
incr rowoptim
|
||||
incr numcommits
|
||||
|
||||
if {[info exists selectedline] && $selectedline >= $row} {
|
||||
incr selectedline
|
||||
}
|
||||
redisplay
|
||||
}
|
||||
|
||||
# Don't change the text pane cursor if it is currently the hand cursor,
|
||||
# showing that we are over a sha1 ID link.
|
||||
proc settextcursor {c} {
|
||||
@ -3307,9 +3448,7 @@ proc notbusy {what} {
|
||||
}
|
||||
|
||||
proc drawrest {} {
|
||||
global numcommits
|
||||
global startmsecs
|
||||
global canvy0 numcommits linespc
|
||||
global rowlaidout commitidx curview
|
||||
global pending_select
|
||||
|
||||
@ -3323,6 +3462,7 @@ proc drawrest {} {
|
||||
}
|
||||
|
||||
set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
|
||||
#global numcommits
|
||||
#puts "overall $drawmsecs ms for $numcommits commits"
|
||||
}
|
||||
|
||||
@ -3603,27 +3743,20 @@ proc viewnextline {dir} {
|
||||
|
||||
# add a list of tag or branch names at position pos
|
||||
# returns the number of names inserted
|
||||
proc appendrefs {pos l var} {
|
||||
global ctext commitrow linknum curview idtags $var
|
||||
proc appendrefs {pos tags var} {
|
||||
global ctext commitrow linknum curview $var
|
||||
|
||||
if {[catch {$ctext index $pos}]} {
|
||||
return 0
|
||||
}
|
||||
set tags {}
|
||||
foreach id $l {
|
||||
foreach tag [set $var\($id\)] {
|
||||
lappend tags [concat $tag $id]
|
||||
}
|
||||
}
|
||||
set tags [lsort -index 1 $tags]
|
||||
set tags [lsort $tags]
|
||||
set sep {}
|
||||
foreach tag $tags {
|
||||
set name [lindex $tag 0]
|
||||
set id [lindex $tag 1]
|
||||
set id [set $var\($tag\)]
|
||||
set lk link$linknum
|
||||
incr linknum
|
||||
$ctext insert $pos $sep
|
||||
$ctext insert $pos $name $lk
|
||||
$ctext insert $pos $tag $lk
|
||||
$ctext tag conf $lk -foreground blue
|
||||
if {[info exists commitrow($curview,$id)]} {
|
||||
$ctext tag bind $lk <1> \
|
||||
@ -3637,6 +3770,18 @@ proc appendrefs {pos l var} {
|
||||
return [llength $tags]
|
||||
}
|
||||
|
||||
proc taglist {ids} {
|
||||
global idtags
|
||||
|
||||
set tags {}
|
||||
foreach id $ids {
|
||||
foreach tag $idtags($id) {
|
||||
lappend tags $tag
|
||||
}
|
||||
}
|
||||
return $tags
|
||||
}
|
||||
|
||||
# called when we have finished computing the nearby tags
|
||||
proc dispneartags {} {
|
||||
global selectedline currentid ctext anc_tags desc_tags showneartags
|
||||
@ -3646,15 +3791,15 @@ proc dispneartags {} {
|
||||
set id $currentid
|
||||
$ctext conf -state normal
|
||||
if {[info exists desc_heads($id)]} {
|
||||
if {[appendrefs branch $desc_heads($id) idheads] > 1} {
|
||||
if {[appendrefs branch $desc_heads($id) headids] > 1} {
|
||||
$ctext insert "branch -2c" "es"
|
||||
}
|
||||
}
|
||||
if {[info exists anc_tags($id)]} {
|
||||
appendrefs follows $anc_tags($id) idtags
|
||||
appendrefs follows [taglist $anc_tags($id)] tagids
|
||||
}
|
||||
if {[info exists desc_tags($id)]} {
|
||||
appendrefs precedes $desc_tags($id) idtags
|
||||
appendrefs precedes [taglist $desc_tags($id)] tagids
|
||||
}
|
||||
$ctext conf -state disabled
|
||||
}
|
||||
@ -3787,7 +3932,7 @@ proc selectline {l isnew} {
|
||||
$ctext mark set branch "end -1c"
|
||||
$ctext mark gravity branch left
|
||||
if {[info exists desc_heads($id)]} {
|
||||
if {[appendrefs branch $desc_heads($id) idheads] > 1} {
|
||||
if {[appendrefs branch $desc_heads($id) headids] > 1} {
|
||||
# turn "Branch" into "Branches"
|
||||
$ctext insert "branch -2c" "es"
|
||||
}
|
||||
@ -3796,13 +3941,13 @@ proc selectline {l isnew} {
|
||||
$ctext mark set follows "end -1c"
|
||||
$ctext mark gravity follows left
|
||||
if {[info exists anc_tags($id)]} {
|
||||
appendrefs follows $anc_tags($id) idtags
|
||||
appendrefs follows [taglist $anc_tags($id)] tagids
|
||||
}
|
||||
$ctext insert end "\nPrecedes: "
|
||||
$ctext mark set precedes "end -1c"
|
||||
$ctext mark gravity precedes left
|
||||
if {[info exists desc_tags($id)]} {
|
||||
appendrefs precedes $desc_tags($id) idtags
|
||||
appendrefs precedes [taglist $desc_tags($id)] tagids
|
||||
}
|
||||
$ctext insert end "\n"
|
||||
}
|
||||
@ -4463,6 +4608,7 @@ proc redisplay {} {
|
||||
drawvisible
|
||||
if {[info exists selectedline]} {
|
||||
selectline $selectedline 0
|
||||
allcanvs yview moveto [lindex $span 0]
|
||||
}
|
||||
}
|
||||
|
||||
@ -4930,6 +5076,7 @@ proc domktag {} {
|
||||
set tagids($tag) $id
|
||||
lappend idtags($id) $tag
|
||||
redrawtags $id
|
||||
addedtag $id
|
||||
}
|
||||
|
||||
proc redrawtags {id} {
|
||||
@ -5020,10 +5167,164 @@ proc wrcomcan {} {
|
||||
unset wrcomtop
|
||||
}
|
||||
|
||||
proc mkbranch {} {
|
||||
global rowmenuid mkbrtop
|
||||
|
||||
set top .makebranch
|
||||
catch {destroy $top}
|
||||
toplevel $top
|
||||
label $top.title -text "Create new branch"
|
||||
grid $top.title - -pady 10
|
||||
label $top.id -text "ID:"
|
||||
entry $top.sha1 -width 40 -relief flat
|
||||
$top.sha1 insert 0 $rowmenuid
|
||||
$top.sha1 conf -state readonly
|
||||
grid $top.id $top.sha1 -sticky w
|
||||
label $top.nlab -text "Name:"
|
||||
entry $top.name -width 40
|
||||
grid $top.nlab $top.name -sticky w
|
||||
frame $top.buts
|
||||
button $top.buts.go -text "Create" -command [list mkbrgo $top]
|
||||
button $top.buts.can -text "Cancel" -command "catch {destroy $top}"
|
||||
grid $top.buts.go $top.buts.can
|
||||
grid columnconfigure $top.buts 0 -weight 1 -uniform a
|
||||
grid columnconfigure $top.buts 1 -weight 1 -uniform a
|
||||
grid $top.buts - -pady 10 -sticky ew
|
||||
focus $top.name
|
||||
}
|
||||
|
||||
proc mkbrgo {top} {
|
||||
global headids idheads
|
||||
|
||||
set name [$top.name get]
|
||||
set id [$top.sha1 get]
|
||||
if {$name eq {}} {
|
||||
error_popup "Please specify a name for the new branch"
|
||||
return
|
||||
}
|
||||
catch {destroy $top}
|
||||
nowbusy newbranch
|
||||
update
|
||||
if {[catch {
|
||||
exec git branch $name $id
|
||||
} err]} {
|
||||
notbusy newbranch
|
||||
error_popup $err
|
||||
} else {
|
||||
addedhead $id $name
|
||||
# XXX should update list of heads displayed for selected commit
|
||||
notbusy newbranch
|
||||
redrawtags $id
|
||||
}
|
||||
}
|
||||
|
||||
proc cherrypick {} {
|
||||
global rowmenuid curview commitrow
|
||||
global mainhead desc_heads anc_tags desc_tags allparents allchildren
|
||||
|
||||
if {[info exists desc_heads($rowmenuid)]
|
||||
&& [lsearch -exact $desc_heads($rowmenuid) $mainhead] >= 0} {
|
||||
set ok [confirm_popup "Commit [string range $rowmenuid 0 7] is already\
|
||||
included in branch $mainhead -- really re-apply it?"]
|
||||
if {!$ok} return
|
||||
}
|
||||
nowbusy cherrypick
|
||||
update
|
||||
set oldhead [exec git rev-parse HEAD]
|
||||
# Unfortunately git-cherry-pick writes stuff to stderr even when
|
||||
# no error occurs, and exec takes that as an indication of error...
|
||||
if {[catch {exec sh -c "git cherry-pick -r $rowmenuid 2>&1"} err]} {
|
||||
notbusy cherrypick
|
||||
error_popup $err
|
||||
return
|
||||
}
|
||||
set newhead [exec git rev-parse HEAD]
|
||||
if {$newhead eq $oldhead} {
|
||||
notbusy cherrypick
|
||||
error_popup "No changes committed"
|
||||
return
|
||||
}
|
||||
set allparents($newhead) $oldhead
|
||||
lappend allchildren($oldhead) $newhead
|
||||
set desc_heads($newhead) $mainhead
|
||||
if {[info exists anc_tags($oldhead)]} {
|
||||
set anc_tags($newhead) $anc_tags($oldhead)
|
||||
}
|
||||
set desc_tags($newhead) {}
|
||||
if {[info exists commitrow($curview,$oldhead)]} {
|
||||
insertrow $commitrow($curview,$oldhead) $newhead
|
||||
if {$mainhead ne {}} {
|
||||
movedhead $newhead $mainhead
|
||||
}
|
||||
redrawtags $oldhead
|
||||
redrawtags $newhead
|
||||
}
|
||||
notbusy cherrypick
|
||||
}
|
||||
|
||||
# context menu for a head
|
||||
proc headmenu {x y id head} {
|
||||
global headmenuid headmenuhead headctxmenu
|
||||
|
||||
set headmenuid $id
|
||||
set headmenuhead $head
|
||||
tk_popup $headctxmenu $x $y
|
||||
}
|
||||
|
||||
proc cobranch {} {
|
||||
global headmenuid headmenuhead mainhead headids
|
||||
|
||||
# check the tree is clean first??
|
||||
set oldmainhead $mainhead
|
||||
nowbusy checkout
|
||||
update
|
||||
if {[catch {
|
||||
exec git checkout $headmenuhead
|
||||
} err]} {
|
||||
notbusy checkout
|
||||
error_popup $err
|
||||
} else {
|
||||
notbusy checkout
|
||||
set mainhead $headmenuhead
|
||||
if {[info exists headids($oldmainhead)]} {
|
||||
redrawtags $headids($oldmainhead)
|
||||
}
|
||||
redrawtags $headmenuid
|
||||
}
|
||||
}
|
||||
|
||||
proc rmbranch {} {
|
||||
global desc_heads headmenuid headmenuhead mainhead
|
||||
global headids idheads
|
||||
|
||||
set head $headmenuhead
|
||||
set id $headmenuid
|
||||
if {$head eq $mainhead} {
|
||||
error_popup "Cannot delete the currently checked-out branch"
|
||||
return
|
||||
}
|
||||
if {$desc_heads($id) eq $head} {
|
||||
# the stuff on this branch isn't on any other branch
|
||||
if {![confirm_popup "The commits on branch $head aren't on any other\
|
||||
branch.\nReally delete branch $head?"]} return
|
||||
}
|
||||
nowbusy rmbranch
|
||||
update
|
||||
if {[catch {exec git branch -D $head} err]} {
|
||||
notbusy rmbranch
|
||||
error_popup $err
|
||||
return
|
||||
}
|
||||
removedhead $id $head
|
||||
redrawtags $id
|
||||
notbusy rmbranch
|
||||
}
|
||||
|
||||
# Stuff for finding nearby tags
|
||||
proc getallcommits {} {
|
||||
global allcstart allcommits allcfd
|
||||
global allcstart allcommits allcfd allids
|
||||
|
||||
set allids {}
|
||||
set fd [open [concat | git rev-list --all --topo-order --parents] r]
|
||||
set allcfd $fd
|
||||
fconfigure $fd -blocking 0
|
||||
@ -5107,10 +5408,52 @@ proc combine_atags {l1 l2} {
|
||||
return $res
|
||||
}
|
||||
|
||||
proc forward_pass {id children} {
|
||||
global idtags desc_tags idheads desc_heads alldtags tagisdesc
|
||||
|
||||
set dtags {}
|
||||
set dheads {}
|
||||
foreach child $children {
|
||||
if {[info exists idtags($child)]} {
|
||||
set ctags [list $child]
|
||||
} else {
|
||||
set ctags $desc_tags($child)
|
||||
}
|
||||
if {$dtags eq {}} {
|
||||
set dtags $ctags
|
||||
} elseif {$ctags ne $dtags} {
|
||||
set dtags [combine_dtags $dtags $ctags]
|
||||
}
|
||||
set cheads $desc_heads($child)
|
||||
if {$dheads eq {}} {
|
||||
set dheads $cheads
|
||||
} elseif {$cheads ne $dheads} {
|
||||
set dheads [lsort -unique [concat $dheads $cheads]]
|
||||
}
|
||||
}
|
||||
set desc_tags($id) $dtags
|
||||
if {[info exists idtags($id)]} {
|
||||
set adt $dtags
|
||||
foreach tag $dtags {
|
||||
set adt [concat $adt $alldtags($tag)]
|
||||
}
|
||||
set adt [lsort -unique $adt]
|
||||
set alldtags($id) $adt
|
||||
foreach tag $adt {
|
||||
set tagisdesc($id,$tag) -1
|
||||
set tagisdesc($tag,$id) 1
|
||||
}
|
||||
}
|
||||
if {[info exists idheads($id)]} {
|
||||
set dheads [concat $dheads $idheads($id)]
|
||||
}
|
||||
set desc_heads($id) $dheads
|
||||
}
|
||||
|
||||
proc getallclines {fd} {
|
||||
global allparents allchildren allcommits allcstart
|
||||
global desc_tags anc_tags idtags alldtags tagisdesc allids
|
||||
global desc_heads idheads
|
||||
global desc_tags anc_tags idtags tagisdesc allids
|
||||
global idheads travindex
|
||||
|
||||
while {[gets $fd line] >= 0} {
|
||||
set id [lindex $line 0]
|
||||
@ -5125,43 +5468,7 @@ proc getallclines {fd} {
|
||||
}
|
||||
# compute nearest tagged descendents as we go
|
||||
# also compute descendent heads
|
||||
set dtags {}
|
||||
set dheads {}
|
||||
foreach child $allchildren($id) {
|
||||
if {[info exists idtags($child)]} {
|
||||
set ctags [list $child]
|
||||
} else {
|
||||
set ctags $desc_tags($child)
|
||||
}
|
||||
if {$dtags eq {}} {
|
||||
set dtags $ctags
|
||||
} elseif {$ctags ne $dtags} {
|
||||
set dtags [combine_dtags $dtags $ctags]
|
||||
}
|
||||
set cheads $desc_heads($child)
|
||||
if {$dheads eq {}} {
|
||||
set dheads $cheads
|
||||
} elseif {$cheads ne $dheads} {
|
||||
set dheads [lsort -unique [concat $dheads $cheads]]
|
||||
}
|
||||
}
|
||||
set desc_tags($id) $dtags
|
||||
if {[info exists idtags($id)]} {
|
||||
set adt $dtags
|
||||
foreach tag $dtags {
|
||||
set adt [concat $adt $alldtags($tag)]
|
||||
}
|
||||
set adt [lsort -unique $adt]
|
||||
set alldtags($id) $adt
|
||||
foreach tag $adt {
|
||||
set tagisdesc($id,$tag) -1
|
||||
set tagisdesc($tag,$id) 1
|
||||
}
|
||||
}
|
||||
if {[info exists idheads($id)]} {
|
||||
lappend dheads $id
|
||||
}
|
||||
set desc_heads($id) $dheads
|
||||
forward_pass $id $allchildren($id)
|
||||
if {[clock clicks -milliseconds] - $allcstart >= 50} {
|
||||
fileevent $fd readable {}
|
||||
after idle restartgetall $fd
|
||||
@ -5169,7 +5476,9 @@ proc getallclines {fd} {
|
||||
}
|
||||
}
|
||||
if {[eof $fd]} {
|
||||
after idle restartatags [llength $allids]
|
||||
set travindex [llength $allids]
|
||||
set allcommits "traversing"
|
||||
after idle restartatags
|
||||
if {[catch {close $fd} err]} {
|
||||
error_popup "Error reading full commit graph: $err.\n\
|
||||
Results may be incomplete."
|
||||
@ -5178,10 +5487,11 @@ proc getallclines {fd} {
|
||||
}
|
||||
|
||||
# walk backward through the tree and compute nearest tagged ancestors
|
||||
proc restartatags {i} {
|
||||
global allids allparents idtags anc_tags t0
|
||||
proc restartatags {} {
|
||||
global allids allparents idtags anc_tags travindex
|
||||
|
||||
set t0 [clock clicks -milliseconds]
|
||||
set i $travindex
|
||||
while {[incr i -1] >= 0} {
|
||||
set id [lindex $allids $i]
|
||||
set atags {}
|
||||
@ -5199,17 +5509,195 @@ proc restartatags {i} {
|
||||
}
|
||||
set anc_tags($id) $atags
|
||||
if {[clock clicks -milliseconds] - $t0 >= 50} {
|
||||
after idle restartatags $i
|
||||
set travindex $i
|
||||
after idle restartatags
|
||||
return
|
||||
}
|
||||
}
|
||||
set allcommits "done"
|
||||
set travindex 0
|
||||
notbusy allcommits
|
||||
dispneartags
|
||||
}
|
||||
|
||||
# update the desc_tags and anc_tags arrays for a new tag just added
|
||||
proc addedtag {id} {
|
||||
global desc_tags anc_tags allparents allchildren allcommits
|
||||
global idtags tagisdesc alldtags
|
||||
|
||||
if {![info exists desc_tags($id)]} return
|
||||
set adt $desc_tags($id)
|
||||
foreach t $desc_tags($id) {
|
||||
set adt [concat $adt $alldtags($t)]
|
||||
}
|
||||
set adt [lsort -unique $adt]
|
||||
set alldtags($id) $adt
|
||||
foreach t $adt {
|
||||
set tagisdesc($id,$t) -1
|
||||
set tagisdesc($t,$id) 1
|
||||
}
|
||||
if {[info exists anc_tags($id)]} {
|
||||
set todo $anc_tags($id)
|
||||
while {$todo ne {}} {
|
||||
set do [lindex $todo 0]
|
||||
set todo [lrange $todo 1 end]
|
||||
if {[info exists tagisdesc($id,$do)]} continue
|
||||
set tagisdesc($do,$id) -1
|
||||
set tagisdesc($id,$do) 1
|
||||
if {[info exists anc_tags($do)]} {
|
||||
set todo [concat $todo $anc_tags($do)]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set lastold $desc_tags($id)
|
||||
set lastnew [list $id]
|
||||
set nup 0
|
||||
set nch 0
|
||||
set todo $allparents($id)
|
||||
while {$todo ne {}} {
|
||||
set do [lindex $todo 0]
|
||||
set todo [lrange $todo 1 end]
|
||||
if {![info exists desc_tags($do)]} continue
|
||||
if {$desc_tags($do) ne $lastold} {
|
||||
set lastold $desc_tags($do)
|
||||
set lastnew [combine_dtags $lastold [list $id]]
|
||||
incr nch
|
||||
}
|
||||
if {$lastold eq $lastnew} continue
|
||||
set desc_tags($do) $lastnew
|
||||
incr nup
|
||||
if {![info exists idtags($do)]} {
|
||||
set todo [concat $todo $allparents($do)]
|
||||
}
|
||||
}
|
||||
|
||||
if {![info exists anc_tags($id)]} return
|
||||
set lastold $anc_tags($id)
|
||||
set lastnew [list $id]
|
||||
set nup 0
|
||||
set nch 0
|
||||
set todo $allchildren($id)
|
||||
while {$todo ne {}} {
|
||||
set do [lindex $todo 0]
|
||||
set todo [lrange $todo 1 end]
|
||||
if {![info exists anc_tags($do)]} continue
|
||||
if {$anc_tags($do) ne $lastold} {
|
||||
set lastold $anc_tags($do)
|
||||
set lastnew [combine_atags $lastold [list $id]]
|
||||
incr nch
|
||||
}
|
||||
if {$lastold eq $lastnew} continue
|
||||
set anc_tags($do) $lastnew
|
||||
incr nup
|
||||
if {![info exists idtags($do)]} {
|
||||
set todo [concat $todo $allchildren($do)]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# update the desc_heads array for a new head just added
|
||||
proc addedhead {hid head} {
|
||||
global desc_heads allparents headids idheads
|
||||
|
||||
set headids($head) $hid
|
||||
lappend idheads($hid) $head
|
||||
|
||||
set todo [list $hid]
|
||||
while {$todo ne {}} {
|
||||
set do [lindex $todo 0]
|
||||
set todo [lrange $todo 1 end]
|
||||
if {![info exists desc_heads($do)] ||
|
||||
[lsearch -exact $desc_heads($do) $head] >= 0} continue
|
||||
set oldheads $desc_heads($do)
|
||||
lappend desc_heads($do) $head
|
||||
set heads $desc_heads($do)
|
||||
while {1} {
|
||||
set p $allparents($do)
|
||||
if {[llength $p] != 1 || ![info exists desc_heads($p)] ||
|
||||
$desc_heads($p) ne $oldheads} break
|
||||
set do $p
|
||||
set desc_heads($do) $heads
|
||||
}
|
||||
set todo [concat $todo $p]
|
||||
}
|
||||
}
|
||||
|
||||
# update the desc_heads array for a head just removed
|
||||
proc removedhead {hid head} {
|
||||
global desc_heads allparents headids idheads
|
||||
|
||||
unset headids($head)
|
||||
if {$idheads($hid) eq $head} {
|
||||
unset idheads($hid)
|
||||
} else {
|
||||
set i [lsearch -exact $idheads($hid) $head]
|
||||
if {$i >= 0} {
|
||||
set idheads($hid) [lreplace $idheads($hid) $i $i]
|
||||
}
|
||||
}
|
||||
|
||||
set todo [list $hid]
|
||||
while {$todo ne {}} {
|
||||
set do [lindex $todo 0]
|
||||
set todo [lrange $todo 1 end]
|
||||
if {![info exists desc_heads($do)]} continue
|
||||
set i [lsearch -exact $desc_heads($do) $head]
|
||||
if {$i < 0} continue
|
||||
set oldheads $desc_heads($do)
|
||||
set heads [lreplace $desc_heads($do) $i $i]
|
||||
while {1} {
|
||||
set desc_heads($do) $heads
|
||||
set p $allparents($do)
|
||||
if {[llength $p] != 1 || ![info exists desc_heads($p)] ||
|
||||
$desc_heads($p) ne $oldheads} break
|
||||
set do $p
|
||||
}
|
||||
set todo [concat $todo $p]
|
||||
}
|
||||
}
|
||||
|
||||
# update things for a head moved to a child of its previous location
|
||||
proc movedhead {id name} {
|
||||
global headids idheads
|
||||
|
||||
set oldid $headids($name)
|
||||
set headids($name) $id
|
||||
if {$idheads($oldid) eq $name} {
|
||||
unset idheads($oldid)
|
||||
} else {
|
||||
set i [lsearch -exact $idheads($oldid) $name]
|
||||
if {$i >= 0} {
|
||||
set idheads($oldid) [lreplace $idheads($oldid) $i $i]
|
||||
}
|
||||
}
|
||||
lappend idheads($id) $name
|
||||
}
|
||||
|
||||
proc changedrefs {} {
|
||||
global desc_heads desc_tags anc_tags allcommits allids
|
||||
global allchildren allparents idtags travindex
|
||||
|
||||
if {![info exists allcommits]} return
|
||||
catch {unset desc_heads}
|
||||
catch {unset desc_tags}
|
||||
catch {unset anc_tags}
|
||||
catch {unset alldtags}
|
||||
catch {unset tagisdesc}
|
||||
foreach id $allids {
|
||||
forward_pass $id $allchildren($id)
|
||||
}
|
||||
if {$allcommits ne "reading"} {
|
||||
set travindex [llength $allids]
|
||||
if {$allcommits ne "traversing"} {
|
||||
set allcommits "traversing"
|
||||
after idle restartatags
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc rereadrefs {} {
|
||||
global idtags idheads idotherrefs
|
||||
global idtags idheads idotherrefs mainhead
|
||||
|
||||
set refids [concat [array names idtags] \
|
||||
[array names idheads] [array names idotherrefs]]
|
||||
@ -5218,12 +5706,16 @@ proc rereadrefs {} {
|
||||
set ref($id) [listrefs $id]
|
||||
}
|
||||
}
|
||||
set oldmainhead $mainhead
|
||||
readrefs
|
||||
changedrefs
|
||||
set refids [lsort -unique [concat $refids [array names idtags] \
|
||||
[array names idheads] [array names idotherrefs]]]
|
||||
foreach id $refids {
|
||||
set v [listrefs $id]
|
||||
if {![info exists ref($id)] || $ref($id) != $v} {
|
||||
if {![info exists ref($id)] || $ref($id) != $v ||
|
||||
($id eq $oldmainhead && $id ne $mainhead) ||
|
||||
($id eq $mainhead && $id ne $oldmainhead)} {
|
||||
redrawtags $id
|
||||
}
|
||||
}
|
||||
|
@ -2251,7 +2251,8 @@ sub git_blame2 {
|
||||
my $fd;
|
||||
my $ftype;
|
||||
|
||||
if (!gitweb_check_feature('blame')) {
|
||||
my ($have_blame) = gitweb_check_feature('blame');
|
||||
if (!$have_blame) {
|
||||
die_error('403 Permission denied', "Permission denied");
|
||||
}
|
||||
die_error('404 Not Found', "File name not defined") if (!$file_name);
|
||||
@ -2320,7 +2321,8 @@ HTML
|
||||
sub git_blame {
|
||||
my $fd;
|
||||
|
||||
if (!gitweb_check_feature('blame')) {
|
||||
my ($have_blame) = gitweb_check_feature('blame');
|
||||
if (!$have_blame) {
|
||||
die_error('403 Permission denied', "Permission denied");
|
||||
}
|
||||
die_error('404 Not Found', "File name not defined") if (!$file_name);
|
||||
@ -2494,7 +2496,7 @@ sub git_blob {
|
||||
die_error(undef, "No file name defined");
|
||||
}
|
||||
}
|
||||
my $have_blame = gitweb_check_feature('blame');
|
||||
my ($have_blame) = gitweb_check_feature('blame');
|
||||
open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
|
||||
or die_error(undef, "Couldn't cat $file_name, $hash");
|
||||
my $mimetype = blob_mimetype($fd, $file_name);
|
||||
@ -2570,7 +2572,7 @@ sub git_tree {
|
||||
my $ref = format_ref_marker($refs, $hash_base);
|
||||
git_header_html();
|
||||
my $base = "";
|
||||
my $have_blame = gitweb_check_feature('blame');
|
||||
my ($have_blame) = gitweb_check_feature('blame');
|
||||
if (defined $hash_base && (my %co = parse_commit($hash_base))) {
|
||||
git_print_page_nav('tree','', $hash_base);
|
||||
git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
|
||||
|
2
help.c
2
help.c
@ -184,7 +184,7 @@ static void show_man_page(const char *git_cmd)
|
||||
page = git_cmd;
|
||||
else {
|
||||
int page_len = strlen(git_cmd) + 4;
|
||||
char *p = malloc(page_len + 1);
|
||||
char *p = xmalloc(page_len + 1);
|
||||
strcpy(p, "git-");
|
||||
strcpy(p + 4, git_cmd);
|
||||
p[page_len] = 0;
|
||||
|
@ -787,7 +787,7 @@ static int remote_ls(struct alt_base *repo, const char *path, int flags,
|
||||
|
||||
ls.flags = flags;
|
||||
ls.repo = repo;
|
||||
ls.path = strdup(path);
|
||||
ls.path = xstrdup(path);
|
||||
ls.dentry_name = NULL;
|
||||
ls.dentry_flags = 0;
|
||||
ls.userData = userData;
|
||||
|
@ -1539,7 +1539,7 @@ static void remote_ls(const char *path, int flags,
|
||||
struct remote_ls_ctx ls;
|
||||
|
||||
ls.flags = flags;
|
||||
ls.path = strdup(path);
|
||||
ls.path = xstrdup(path);
|
||||
ls.dentry_name = NULL;
|
||||
ls.dentry_flags = 0;
|
||||
ls.userData = userData;
|
||||
@ -1738,7 +1738,7 @@ static struct object_list **process_tree(struct tree *tree,
|
||||
die("bad tree object %s", sha1_to_hex(obj->sha1));
|
||||
|
||||
obj->flags |= SEEN;
|
||||
name = strdup(name);
|
||||
name = xstrdup(name);
|
||||
p = add_one_object(obj, p);
|
||||
me.up = path;
|
||||
me.elem = name;
|
||||
@ -2467,7 +2467,7 @@ int main(int argc, char **argv)
|
||||
|
||||
/* Set up revision info for this refspec */
|
||||
commit_argc = 3;
|
||||
new_sha1_hex = strdup(sha1_to_hex(ref->new_sha1));
|
||||
new_sha1_hex = xstrdup(sha1_to_hex(ref->new_sha1));
|
||||
old_sha1_hex = NULL;
|
||||
commit_argv[1] = "--objects";
|
||||
commit_argv[2] = new_sha1_hex;
|
||||
|
12
imap-send.c
12
imap-send.c
@ -1007,7 +1007,7 @@ imap_open_store( imap_server_conf_t *srvc )
|
||||
* getpass() returns a pointer to a static buffer. make a copy
|
||||
* for long term storage.
|
||||
*/
|
||||
srvc->pass = strdup( arg );
|
||||
srvc->pass = xstrdup( arg );
|
||||
}
|
||||
if (CAP(NOLOGIN)) {
|
||||
fprintf( stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host );
|
||||
@ -1263,7 +1263,7 @@ git_imap_config(const char *key, const char *val)
|
||||
key += sizeof imap_key - 1;
|
||||
|
||||
if (!strcmp( "folder", key )) {
|
||||
imap_folder = strdup( val );
|
||||
imap_folder = xstrdup( val );
|
||||
} else if (!strcmp( "host", key )) {
|
||||
{
|
||||
if (!strncmp( "imap:", val, 5 ))
|
||||
@ -1273,16 +1273,16 @@ git_imap_config(const char *key, const char *val)
|
||||
}
|
||||
if (!strncmp( "//", val, 2 ))
|
||||
val += 2;
|
||||
server.host = strdup( val );
|
||||
server.host = xstrdup( val );
|
||||
}
|
||||
else if (!strcmp( "user", key ))
|
||||
server.user = strdup( val );
|
||||
server.user = xstrdup( val );
|
||||
else if (!strcmp( "pass", key ))
|
||||
server.pass = strdup( val );
|
||||
server.pass = xstrdup( val );
|
||||
else if (!strcmp( "port", key ))
|
||||
server.port = git_config_int( key, val );
|
||||
else if (!strcmp( "tunnel", key ))
|
||||
server.tunnel = strdup( val );
|
||||
server.tunnel = xstrdup( val );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ static const char *write_temp_file(mmfile_t *f)
|
||||
fd = mkstemp(filename);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
filename = strdup(filename);
|
||||
filename = xstrdup(filename);
|
||||
if (f->size != xwrite(fd, f->ptr, f->size)) {
|
||||
rm_temp_file(filename);
|
||||
return NULL;
|
||||
|
@ -283,7 +283,7 @@ static int save_files_dirs(const unsigned char *sha1,
|
||||
unsigned int mode, int stage)
|
||||
{
|
||||
int len = strlen(path);
|
||||
char *newpath = malloc(baselen + len + 1);
|
||||
char *newpath = xmalloc(baselen + len + 1);
|
||||
memcpy(newpath, base, baselen);
|
||||
memcpy(newpath + baselen, path, len);
|
||||
newpath[baselen + len] = '\0';
|
||||
@ -455,7 +455,7 @@ static int remove_path(const char *name)
|
||||
if (ret)
|
||||
return ret;
|
||||
len = strlen(name);
|
||||
dirs = malloc(len+1);
|
||||
dirs = xmalloc(len+1);
|
||||
memcpy(dirs, name, len);
|
||||
dirs[len] = '\0';
|
||||
while ((slash = strrchr(name, '/'))) {
|
||||
@ -513,8 +513,8 @@ static char *unique_path(const char *path, const char *branch)
|
||||
|
||||
static int mkdir_p(const char *path, unsigned long mode)
|
||||
{
|
||||
/* path points to cache entries, so strdup before messing with it */
|
||||
char *buf = strdup(path);
|
||||
/* path points to cache entries, so xstrdup before messing with it */
|
||||
char *buf = xstrdup(path);
|
||||
int result = safe_create_leading_directories(buf);
|
||||
free(buf);
|
||||
return result;
|
||||
@ -572,7 +572,7 @@ void update_file_flags(const unsigned char *sha,
|
||||
flush_buffer(fd, buf, size);
|
||||
close(fd);
|
||||
} else if (S_ISLNK(mode)) {
|
||||
char *lnk = malloc(size + 1);
|
||||
char *lnk = xmalloc(size + 1);
|
||||
memcpy(lnk, buf, size);
|
||||
lnk[size] = '\0';
|
||||
mkdir_p(path, 0777);
|
||||
@ -668,9 +668,9 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
|
||||
git_unpack_file(a->sha1, src1);
|
||||
git_unpack_file(b->sha1, src2);
|
||||
|
||||
argv[2] = la = strdup(mkpath("%s/%s", branch1, a->path));
|
||||
argv[6] = lb = strdup(mkpath("%s/%s", branch2, b->path));
|
||||
argv[4] = lo = strdup(mkpath("orig/%s", o->path));
|
||||
argv[2] = la = xstrdup(mkpath("%s/%s", branch1, a->path));
|
||||
argv[6] = lb = xstrdup(mkpath("%s/%s", branch2, b->path));
|
||||
argv[4] = lo = xstrdup(mkpath("orig/%s", o->path));
|
||||
argv[7] = src1;
|
||||
argv[8] = orig;
|
||||
argv[9] = src2,
|
||||
@ -1314,9 +1314,9 @@ int main(int argc, char *argv[])
|
||||
original_index_file = getenv("GIT_INDEX_FILE");
|
||||
|
||||
if (!original_index_file)
|
||||
original_index_file = strdup(git_path("index"));
|
||||
original_index_file = xstrdup(git_path("index"));
|
||||
|
||||
temporary_index_file = strdup(git_path("mrg-rcrsv-tmp-idx"));
|
||||
temporary_index_file = xstrdup(git_path("mrg-rcrsv-tmp-idx"));
|
||||
|
||||
if (argc < 4)
|
||||
die("Usage: %s <base>... -- <head> <remote> ...\n", argv[0]);
|
||||
|
@ -177,7 +177,7 @@ static void resolve(const char *base, struct name_entry *branch1, struct name_en
|
||||
if (!branch1)
|
||||
return;
|
||||
|
||||
path = strdup(mkpath("%s%s", base, result->path));
|
||||
path = xstrdup(mkpath("%s%s", base, result->path));
|
||||
orig = create_entry(2, branch1->mode, branch1->sha1, path);
|
||||
final = create_entry(0, result->mode, result->sha1, path);
|
||||
|
||||
@ -233,7 +233,7 @@ static struct merge_list *link_entry(unsigned stage, const char *base, struct na
|
||||
if (entry)
|
||||
path = entry->path;
|
||||
else
|
||||
path = strdup(mkpath("%s%s", base, n->path));
|
||||
path = xstrdup(mkpath("%s%s", base, n->path));
|
||||
link = create_entry(stage, n->mode, n->sha1, path);
|
||||
link->link = entry;
|
||||
return link;
|
||||
|
2
mktag.c
2
mktag.c
@ -119,7 +119,7 @@ static int verify_tag(char *buffer, unsigned long size)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned long size = 4096;
|
||||
char *buffer = malloc(size);
|
||||
char *buffer = xmalloc(size);
|
||||
unsigned char result_sha1[20];
|
||||
|
||||
if (argc != 1)
|
||||
|
@ -45,7 +45,7 @@ static int add_entry(struct path_list *list, const char *path)
|
||||
(list->nr - index)
|
||||
* sizeof(struct path_list_item));
|
||||
list->items[index].path = list->strdup_paths ?
|
||||
strdup(path) : (char *)path;
|
||||
xstrdup(path) : (char *)path;
|
||||
list->items[index].util = NULL;
|
||||
list->nr++;
|
||||
|
||||
|
4
refs.c
4
refs.c
@ -313,8 +313,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *path,
|
||||
}
|
||||
lock->lk = xcalloc(1, sizeof(struct lock_file));
|
||||
|
||||
lock->ref_file = strdup(path);
|
||||
lock->log_file = strdup(git_path("logs/%s", lock->ref_file + plen));
|
||||
lock->ref_file = xstrdup(path);
|
||||
lock->log_file = xstrdup(git_path("logs/%s", lock->ref_file + plen));
|
||||
lock->force_write = lstat(lock->ref_file, &st) && errno == ENOENT;
|
||||
|
||||
if (safe_create_leading_directories(lock->ref_file))
|
||||
|
@ -53,7 +53,7 @@ static void exec_rev_list(struct ref *refs)
|
||||
if (900 < i)
|
||||
die("git-rev-list environment overflow");
|
||||
if (!is_zero_sha1(ref->new_sha1)) {
|
||||
char *buf = malloc(100);
|
||||
char *buf = xmalloc(100);
|
||||
args[i++] = buf;
|
||||
snprintf(buf, 50, "%s", sha1_to_hex(ref->new_sha1));
|
||||
buf += 50;
|
||||
@ -75,7 +75,7 @@ static void exec_rev_list(struct ref *refs)
|
||||
if (is_zero_sha1(ref->new_sha1) &&
|
||||
!is_zero_sha1(ref->old_sha1) &&
|
||||
has_sha1_file(ref->old_sha1)) {
|
||||
char *buf = malloc(42);
|
||||
char *buf = xmalloc(42);
|
||||
args[i++] = buf;
|
||||
snprintf(buf, 42, "^%s", sha1_to_hex(ref->old_sha1));
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ static int add_info_ref(const char *path, const unsigned char *sha1)
|
||||
|
||||
static int update_info_refs(int force)
|
||||
{
|
||||
char *path0 = strdup(git_path("info/refs"));
|
||||
char *path0 = xstrdup(git_path("info/refs"));
|
||||
int len = strlen(path0);
|
||||
char *path1 = xmalloc(len + 2);
|
||||
|
||||
|
95
sha1_file.c
95
sha1_file.c
@ -115,7 +115,7 @@ static void fill_sha1_path(char *pathbuf, const unsigned char *sha1)
|
||||
|
||||
/*
|
||||
* NOTE! This returns a statically allocated buffer, so you have to be
|
||||
* careful about using it. Do a "strdup()" if you need to save the
|
||||
* careful about using it. Do a "xstrdup()" if you need to save the
|
||||
* filename.
|
||||
*
|
||||
* Also note that this returns the location for creating. Reading
|
||||
@ -711,17 +711,39 @@ int legacy_loose_object(unsigned char *map)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep)
|
||||
{
|
||||
unsigned shift;
|
||||
unsigned char c;
|
||||
unsigned long size;
|
||||
unsigned long used = 0;
|
||||
|
||||
c = buf[used++];
|
||||
*type = (c >> 4) & 7;
|
||||
size = c & 15;
|
||||
shift = 4;
|
||||
while (c & 0x80) {
|
||||
if (len <= used)
|
||||
return 0;
|
||||
if (sizeof(long) * 8 <= shift)
|
||||
return 0;
|
||||
c = buf[used++];
|
||||
size += (c & 0x7f) << shift;
|
||||
shift += 7;
|
||||
}
|
||||
*sizep = size;
|
||||
return used;
|
||||
}
|
||||
|
||||
static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz)
|
||||
{
|
||||
unsigned char c;
|
||||
unsigned int bits;
|
||||
unsigned long size;
|
||||
static const char *typename[8] = {
|
||||
NULL, /* OBJ_EXT */
|
||||
"commit", "tree", "blob", "tag",
|
||||
NULL, NULL, NULL
|
||||
unsigned long size, used;
|
||||
static const char valid_loose_object_type[8] = {
|
||||
0, /* OBJ_EXT */
|
||||
1, 1, 1, 1, /* "commit", "tree", "blob", "tag" */
|
||||
0, /* "delta" and others are invalid in a loose object */
|
||||
};
|
||||
const char *type;
|
||||
enum object_type type;
|
||||
|
||||
/* Get the data stream */
|
||||
memset(stream, 0, sizeof(*stream));
|
||||
@ -735,22 +757,11 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon
|
||||
return inflate(stream, 0);
|
||||
}
|
||||
|
||||
c = *map++;
|
||||
mapsize--;
|
||||
type = typename[(c >> 4) & 7];
|
||||
if (!type)
|
||||
used = unpack_object_header_gently(map, mapsize, &type, &size);
|
||||
if (!used || !valid_loose_object_type[type])
|
||||
return -1;
|
||||
|
||||
bits = 4;
|
||||
size = c & 0xf;
|
||||
while ((c & 0x80)) {
|
||||
if (bits >= 8*sizeof(long))
|
||||
return -1;
|
||||
c = *map++;
|
||||
size += (c & 0x7f) << bits;
|
||||
bits += 7;
|
||||
mapsize--;
|
||||
}
|
||||
map += used;
|
||||
mapsize -= used;
|
||||
|
||||
/* Set up the stream for the rest.. */
|
||||
stream->next_in = map;
|
||||
@ -758,7 +769,8 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon
|
||||
inflateInit(stream);
|
||||
|
||||
/* And generate the fake traditional header */
|
||||
stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu", type, size);
|
||||
stream->total_out = 1 + snprintf(buffer, bufsiz, "%s %lu",
|
||||
type_names[type], size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -916,25 +928,18 @@ static int packed_delta_info(unsigned char *base_sha1,
|
||||
static unsigned long unpack_object_header(struct packed_git *p, unsigned long offset,
|
||||
enum object_type *type, unsigned long *sizep)
|
||||
{
|
||||
unsigned shift;
|
||||
unsigned char c;
|
||||
unsigned long size;
|
||||
unsigned long used;
|
||||
|
||||
if (offset >= p->pack_size)
|
||||
if (p->pack_size <= offset)
|
||||
die("object offset outside of pack file");
|
||||
c = *((unsigned char *)p->pack_base + offset++);
|
||||
*type = (c >> 4) & 7;
|
||||
size = c & 15;
|
||||
shift = 4;
|
||||
while (c & 0x80) {
|
||||
if (offset >= p->pack_size)
|
||||
die("object offset outside of pack file");
|
||||
c = *((unsigned char *)p->pack_base + offset++);
|
||||
size += (c & 0x7f) << shift;
|
||||
shift += 7;
|
||||
}
|
||||
*sizep = size;
|
||||
return offset;
|
||||
|
||||
used = unpack_object_header_gently((unsigned char *)p->pack_base +
|
||||
offset,
|
||||
p->pack_size - offset, type, sizep);
|
||||
if (!used)
|
||||
die("object offset outside of pack file");
|
||||
|
||||
return offset + used;
|
||||
}
|
||||
|
||||
int check_reuse_pack_delta(struct packed_git *p, unsigned long offset,
|
||||
@ -1348,7 +1353,7 @@ char *write_sha1_file_prepare(void *buf,
|
||||
*
|
||||
* Returns the errno on failure, 0 on success.
|
||||
*/
|
||||
static int link_temp_to_file(const char *tmpfile, char *filename)
|
||||
static int link_temp_to_file(const char *tmpfile, const char *filename)
|
||||
{
|
||||
int ret;
|
||||
char *dir;
|
||||
@ -1381,7 +1386,7 @@ static int link_temp_to_file(const char *tmpfile, char *filename)
|
||||
/*
|
||||
* Move the just written object into its final resting place
|
||||
*/
|
||||
int move_temp_to_file(const char *tmpfile, char *filename)
|
||||
int move_temp_to_file(const char *tmpfile, const char *filename)
|
||||
{
|
||||
int ret = link_temp_to_file(tmpfile, filename);
|
||||
|
||||
@ -1756,7 +1761,7 @@ int read_pipe(int fd, char** return_buf, unsigned long* return_size)
|
||||
int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
|
||||
{
|
||||
unsigned long size = 4096;
|
||||
char *buf = malloc(size);
|
||||
char *buf = xmalloc(size);
|
||||
int ret;
|
||||
unsigned char hdr[50];
|
||||
int hdrlen;
|
||||
|
@ -279,7 +279,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
||||
pathname = resolve_ref(git_path(*p, len, str), this_result, 1);
|
||||
if (pathname) {
|
||||
if (!refs_found++)
|
||||
real_path = strdup(pathname);
|
||||
real_path = xstrdup(pathname);
|
||||
if (!warn_ambiguous_refs)
|
||||
break;
|
||||
}
|
||||
|
@ -34,6 +34,15 @@ export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
|
||||
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
|
||||
export EDITOR VISUAL
|
||||
|
||||
case $(echo $GIT_TRACE |tr [A-Z] [a-z]) in
|
||||
1|2|true)
|
||||
echo "* warning: Some tests will not work if GIT_TRACE" \
|
||||
"is set as to trace on STDERR ! *"
|
||||
echo "* warning: Please set GIT_TRACE to something" \
|
||||
"other than 1, 2 or true ! *"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Each test should start with something like this, after copyright notices:
|
||||
#
|
||||
# test_description='Description of this test...
|
||||
|
30
trace.c
30
trace.c
@ -51,7 +51,7 @@ int nfvasprintf(char **str, const char *fmt, va_list va)
|
||||
}
|
||||
|
||||
/* Get a trace file descriptor from GIT_TRACE env variable. */
|
||||
static int get_trace_fd()
|
||||
static int get_trace_fd(int *need_close)
|
||||
{
|
||||
char *trace = getenv("GIT_TRACE");
|
||||
|
||||
@ -61,9 +61,25 @@ static int get_trace_fd()
|
||||
return STDERR_FILENO;
|
||||
if (strlen(trace) == 1 && isdigit(*trace))
|
||||
return atoi(trace);
|
||||
if (*trace == '/') {
|
||||
int fd = open(trace, O_WRONLY | O_APPEND | O_CREAT, 0666);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr,
|
||||
"Could not open '%s' for tracing: %s\n"
|
||||
"Defaulting to tracing on stderr...\n",
|
||||
trace, strerror(errno));
|
||||
return STDERR_FILENO;
|
||||
}
|
||||
*need_close = 1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
fprintf(stderr, "What does '%s' for GIT_TRACE means ?\n", trace);
|
||||
fprintf(stderr, "If you want to trace into a file, "
|
||||
"then please set GIT_TRACE to an absolute pathname "
|
||||
"(starting with /).\n");
|
||||
fprintf(stderr, "Defaulting to tracing on stderr...\n");
|
||||
|
||||
return STDERR_FILENO;
|
||||
}
|
||||
|
||||
@ -74,7 +90,8 @@ void trace_printf(const char *format, ...)
|
||||
{
|
||||
char *trace_str;
|
||||
va_list rest;
|
||||
int fd = get_trace_fd();
|
||||
int need_close = 0;
|
||||
int fd = get_trace_fd(&need_close);
|
||||
|
||||
if (!fd)
|
||||
return;
|
||||
@ -86,6 +103,9 @@ void trace_printf(const char *format, ...)
|
||||
write_or_whine(fd, trace_str, strlen(trace_str), err_msg);
|
||||
|
||||
free(trace_str);
|
||||
|
||||
if (need_close)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void trace_argv_printf(const char **argv, int count, const char *format, ...)
|
||||
@ -93,7 +113,8 @@ void trace_argv_printf(const char **argv, int count, const char *format, ...)
|
||||
char *argv_str, *format_str, *trace_str;
|
||||
size_t argv_len, format_len, trace_len;
|
||||
va_list rest;
|
||||
int fd = get_trace_fd();
|
||||
int need_close = 0;
|
||||
int fd = get_trace_fd(&need_close);
|
||||
|
||||
if (!fd)
|
||||
return;
|
||||
@ -122,4 +143,7 @@ void trace_argv_printf(const char **argv, int count, const char *format, ...)
|
||||
free(argv_str);
|
||||
free(format_str);
|
||||
free(trace_str);
|
||||
|
||||
if (need_close)
|
||||
close(fd);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user