Merge branch 'jc/test-clone' into jc/clone
* jc/test-clone: (35 commits) Introduce GIT_TEMPLATE_DIR Revert "fix testsuite: make sure they use templates freshly built from the source" fix testsuite: make sure they use templates freshly built from the source rerere: fix breakage of resolving. Add config example with respect to branch Add documentation for show-branch --topics make git a bit less cryptic on fetch errors make patch_delta() error cases a bit more verbose racy-git: documentation updates. show-ref: fix --exclude-existing parse-remote::expand_refs_wildcard() vim syntax: follow recent changes to commit template show-ref: fix --verify --hash=length show-ref: fix --quiet --verify avoid accessing _all_ loose refs in git-show-ref --verify git-fetch: Avoid reading packed refs over and over again Teach show-branch how to show ref-log data. markup fix in svnimport documentation. Documentation: new option -P for git-svnimport Fix mis-mark-up in git-merge-file.txt documentation ...
This commit is contained in:
commit
5fed466815
@ -31,6 +31,11 @@ Example
|
|||||||
external = "/usr/local/bin/gnu-diff -u"
|
external = "/usr/local/bin/gnu-diff -u"
|
||||||
renames = true
|
renames = true
|
||||||
|
|
||||||
|
[branch "devel"]
|
||||||
|
remote = origin
|
||||||
|
merge = refs/heads/devel
|
||||||
|
|
||||||
|
|
||||||
Variables
|
Variables
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
git-merge-file(1)
|
git-merge-file(1)
|
||||||
============
|
=================
|
||||||
|
|
||||||
NAME
|
NAME
|
||||||
----
|
----
|
||||||
git-merge-file - threeway file merge
|
git-merge-file - three-way file merge
|
||||||
|
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
|
@ -10,7 +10,7 @@ SYNOPSIS
|
|||||||
[verse]
|
[verse]
|
||||||
'git-show-branch' [--all] [--heads] [--tags] [--topo-order] [--current]
|
'git-show-branch' [--all] [--heads] [--tags] [--topo-order] [--current]
|
||||||
[--more=<n> | --list | --independent | --merge-base]
|
[--more=<n> | --list | --independent | --merge-base]
|
||||||
[--no-name | --sha1-name] [<rev> | <glob>]...
|
[--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -86,6 +86,14 @@ OPTIONS
|
|||||||
of "master"), name them with the unique prefix of their
|
of "master"), name them with the unique prefix of their
|
||||||
object names.
|
object names.
|
||||||
|
|
||||||
|
--topics::
|
||||||
|
Shows only commits that are NOT on the first branch given.
|
||||||
|
This helps track topic branches by hiding any commit that
|
||||||
|
is already in the main line of development. When given
|
||||||
|
"git show-branch --topics master topic1 topic2", this
|
||||||
|
will show the revisions given by "git rev-list {caret}master
|
||||||
|
topic1 topic2"
|
||||||
|
|
||||||
Note that --more, --list, --independent and --merge-base options
|
Note that --more, --list, --independent and --merge-base options
|
||||||
are mutually exclusive.
|
are mutually exclusive.
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ SYNOPSIS
|
|||||||
[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
|
[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
|
||||||
[ -s start_chg ] [ -m ] [ -r ] [ -M regex ]
|
[ -s start_chg ] [ -m ] [ -r ] [ -M regex ]
|
||||||
[ -I <ignorefile_name> ] [ -A <author_file> ]
|
[ -I <ignorefile_name> ] [ -A <author_file> ]
|
||||||
|
[ -P <path_from_trunk> ]
|
||||||
<SVN_repository_URL> [ <path> ]
|
<SVN_repository_URL> [ <path> ]
|
||||||
|
|
||||||
|
|
||||||
@ -103,10 +104,18 @@ repository without -A.
|
|||||||
|
|
||||||
-l <max_rev>::
|
-l <max_rev>::
|
||||||
Specify a maximum revision number to pull.
|
Specify a maximum revision number to pull.
|
||||||
|
+
|
||||||
Formerly, this option controlled how many revisions to pull,
|
Formerly, this option controlled how many revisions to pull,
|
||||||
due to SVN memory leaks. (These have been worked around.)
|
due to SVN memory leaks. (These have been worked around.)
|
||||||
|
|
||||||
|
-P <path_from_trunk>::
|
||||||
|
Partial import of the SVN tree.
|
||||||
|
+
|
||||||
|
By default, the whole tree on the SVN trunk (/trunk) is imported.
|
||||||
|
'-P my/proj' will import starting only from '/trunk/my/proj'.
|
||||||
|
This option is useful when you want to import one project from a
|
||||||
|
svn repo which hosts multiple projects under the same trunk.
|
||||||
|
|
||||||
-v::
|
-v::
|
||||||
Verbosity: let 'svnimport' report what it is doing.
|
Verbosity: let 'svnimport' report what it is doing.
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ Use of index and Racy git problem
|
|||||||
Background
|
Background
|
||||||
----------
|
----------
|
||||||
|
|
||||||
The index is one of the most important data structure in git.
|
The index is one of the most important data structures in git.
|
||||||
It represents a virtual working tree state by recording list of
|
It represents a virtual working tree state by recording list of
|
||||||
paths and their object names and serves as a staging area to
|
paths and their object names and serves as a staging area to
|
||||||
write out the next tree object to be committed. The state is
|
write out the next tree object to be committed. The state is
|
||||||
@ -16,7 +16,7 @@ virtual working tree state in the index and the files in the
|
|||||||
working tree. The most obvious case is when the user asks `git
|
working tree. The most obvious case is when the user asks `git
|
||||||
diff` (or its low level implementation, `git diff-files`) or
|
diff` (or its low level implementation, `git diff-files`) or
|
||||||
`git-ls-files --modified`. In addition, git internally checks
|
`git-ls-files --modified`. In addition, git internally checks
|
||||||
if the files in the working tree is different from what are
|
if the files in the working tree are different from what are
|
||||||
recorded in the index to avoid stomping on local changes in them
|
recorded in the index to avoid stomping on local changes in them
|
||||||
during patch application, switching branches, and merging.
|
during patch application, switching branches, and merging.
|
||||||
|
|
||||||
@ -24,9 +24,9 @@ In order to speed up this comparison between the files in the
|
|||||||
working tree and the index entries, the index entries record the
|
working tree and the index entries, the index entries record the
|
||||||
information obtained from the filesystem via `lstat(2)` system
|
information obtained from the filesystem via `lstat(2)` system
|
||||||
call when they were last updated. When checking if they differ,
|
call when they were last updated. When checking if they differ,
|
||||||
git first runs `lstat(2)` on the files and compare the result
|
git first runs `lstat(2)` on the files and compares the result
|
||||||
with this information (this is what was originally done by the
|
with this information (this is what was originally done by the
|
||||||
`ce_match_stat()` function, which the current code does in
|
`ce_match_stat()` function, but the current code does it in
|
||||||
`ce_match_stat_basic()` function). If some of these "cached
|
`ce_match_stat_basic()` function). If some of these "cached
|
||||||
stat information" fields do not match, git can tell that the
|
stat information" fields do not match, git can tell that the
|
||||||
files are modified without even looking at their contents.
|
files are modified without even looking at their contents.
|
||||||
@ -53,8 +53,9 @@ Racy git
|
|||||||
There is one slight problem with the optimization based on the
|
There is one slight problem with the optimization based on the
|
||||||
cached stat information. Consider this sequence:
|
cached stat information. Consider this sequence:
|
||||||
|
|
||||||
|
: modify 'foo'
|
||||||
$ git update-index 'foo'
|
$ git update-index 'foo'
|
||||||
: modify 'foo' in-place without changing its size
|
: modify 'foo' again, in-place, without changing its size
|
||||||
|
|
||||||
The first `update-index` computes the object name of the
|
The first `update-index` computes the object name of the
|
||||||
contents of file `foo` and updates the index entry for `foo`
|
contents of file `foo` and updates the index entry for `foo`
|
||||||
@ -62,7 +63,8 @@ along with the `struct stat` information. If the modification
|
|||||||
that follows it happens very fast so that the file's `st_mtime`
|
that follows it happens very fast so that the file's `st_mtime`
|
||||||
timestamp does not change, after this sequence, the cached stat
|
timestamp does not change, after this sequence, the cached stat
|
||||||
information the index entry records still exactly match what you
|
information the index entry records still exactly match what you
|
||||||
can obtain from the filesystem, but the file `foo` is modified.
|
would see in the filesystem, even though the file `foo` is now
|
||||||
|
different.
|
||||||
This way, git can incorrectly think files in the working tree
|
This way, git can incorrectly think files in the working tree
|
||||||
are unmodified even though they actually are. This is called
|
are unmodified even though they actually are. This is called
|
||||||
the "racy git" problem (discovered by Pasky), and the entries
|
the "racy git" problem (discovered by Pasky), and the entries
|
||||||
@ -87,7 +89,7 @@ the stat information from updated paths, `st_mtime` timestamp of
|
|||||||
it is usually the same as or newer than any of the paths the
|
it is usually the same as or newer than any of the paths the
|
||||||
index contains. And no matter how quick the modification that
|
index contains. And no matter how quick the modification that
|
||||||
follows `git update-index foo` finishes, the resulting
|
follows `git update-index foo` finishes, the resulting
|
||||||
`st_mtime` timestamp on `foo` cannot get the timestamp earlier
|
`st_mtime` timestamp on `foo` cannot get a value earlier
|
||||||
than the index file. Therefore, index entries that can be
|
than the index file. Therefore, index entries that can be
|
||||||
racily clean are limited to the ones that have the same
|
racily clean are limited to the ones that have the same
|
||||||
timestamp as the index file itself.
|
timestamp as the index file itself.
|
||||||
@ -111,7 +113,7 @@ value, and falsely clean entry `foo` would not be caught by the
|
|||||||
timestamp comparison check done with the former logic anymore.
|
timestamp comparison check done with the former logic anymore.
|
||||||
The latter makes sure that the cached stat information for `foo`
|
The latter makes sure that the cached stat information for `foo`
|
||||||
would never match with the file in the working tree, so later
|
would never match with the file in the working tree, so later
|
||||||
checks by `ce_match_stat_basic()` would report the index entry
|
checks by `ce_match_stat_basic()` would report that the index entry
|
||||||
does not match the file and git does not have to fall back on more
|
does not match the file and git does not have to fall back on more
|
||||||
expensive `ce_modified_check_fs()`.
|
expensive `ce_modified_check_fs()`.
|
||||||
|
|
||||||
@ -155,17 +157,16 @@ of the cached stat information.
|
|||||||
Avoiding runtime penalty
|
Avoiding runtime penalty
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
In order to avoid the above runtime penalty, the recent "master"
|
In order to avoid the above runtime penalty, post 1.4.2 git used
|
||||||
branch (post 1.4.2) has a code that makes sure the index file
|
to have a code that made sure the index file
|
||||||
gets timestamp newer than the youngest files in the index when
|
got timestamp newer than the youngest files in the index when
|
||||||
there are many young files with the same timestamp as the
|
there are many young files with the same timestamp as the
|
||||||
resulting index file would otherwise would have by waiting
|
resulting index file would otherwise would have by waiting
|
||||||
before finishing writing the index file out.
|
before finishing writing the index file out.
|
||||||
|
|
||||||
I suspect that in practice the situation where many paths in the
|
I suspected that in practice the situation where many paths in the
|
||||||
index are all racily clean is quite rare. The only code paths
|
index are all racily clean was quite rare. The only code paths
|
||||||
that can record recent timestamp for large number of paths I
|
that can record recent timestamp for large number of paths are:
|
||||||
know of are:
|
|
||||||
|
|
||||||
. Initial `git add .` of a large project.
|
. Initial `git add .` of a large project.
|
||||||
|
|
||||||
@ -188,6 +189,7 @@ youngest file in the working tree. This means that in these
|
|||||||
cases there actually will not be any racily clean entry in
|
cases there actually will not be any racily clean entry in
|
||||||
the resulting index.
|
the resulting index.
|
||||||
|
|
||||||
So in summary I think we should not worry about avoiding the
|
Based on this discussion, the current code does not use the
|
||||||
runtime penalty and get rid of the "wait before finishing
|
"workaround" to avoid the runtime penalty that does not exist in
|
||||||
writing" code out.
|
practice anymore. This was done with commit 0fc82cff on Aug 15,
|
||||||
|
2006.
|
||||||
|
4
Makefile
4
Makefile
@ -796,8 +796,8 @@ test: all
|
|||||||
test-date$X: test-date.c date.o ctype.o
|
test-date$X: test-date.c date.o ctype.o
|
||||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) test-date.c date.o ctype.o
|
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) test-date.c date.o ctype.o
|
||||||
|
|
||||||
test-delta$X: test-delta.c diff-delta.o patch-delta.o
|
test-delta$X: test-delta.o diff-delta.o patch-delta.o $(GITLIBS)
|
||||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^
|
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
|
||||||
|
|
||||||
test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
|
test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
|
||||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
|
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
|
||||||
|
@ -1090,6 +1090,11 @@ static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
|
|||||||
if (!(commit->object.flags & UNINTERESTING) &&
|
if (!(commit->object.flags & UNINTERESTING) &&
|
||||||
!(revs->max_age != -1 && commit->date < revs->max_age))
|
!(revs->max_age != -1 && commit->date < revs->max_age))
|
||||||
pass_blame(sb, suspect, opt);
|
pass_blame(sb, suspect, opt);
|
||||||
|
else {
|
||||||
|
commit->object.flags |= UNINTERESTING;
|
||||||
|
if (commit->object.parsed)
|
||||||
|
mark_parents_uninteresting(commit);
|
||||||
|
}
|
||||||
|
|
||||||
/* Take responsibility for the remaining entries */
|
/* Take responsibility for the remaining entries */
|
||||||
for (ent = sb->ent; ent; ent = ent->next)
|
for (ent = sb->ent; ent; ent = ent->next)
|
||||||
@ -1273,6 +1278,8 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
|
|||||||
printf("committer-tz %s\n", ci.committer_tz);
|
printf("committer-tz %s\n", ci.committer_tz);
|
||||||
printf("filename %s\n", suspect->path);
|
printf("filename %s\n", suspect->path);
|
||||||
printf("summary %s\n", ci.summary);
|
printf("summary %s\n", ci.summary);
|
||||||
|
if (suspect->commit->object.flags & UNINTERESTING)
|
||||||
|
printf("boundary\n");
|
||||||
}
|
}
|
||||||
else if (suspect->commit->object.flags & MORE_THAN_ONE_PATH)
|
else if (suspect->commit->object.flags & MORE_THAN_ONE_PATH)
|
||||||
printf("filename %s\n", suspect->path);
|
printf("filename %s\n", suspect->path);
|
||||||
@ -1308,8 +1315,14 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
|
|||||||
cp = nth_line(sb, ent->lno);
|
cp = nth_line(sb, ent->lno);
|
||||||
for (cnt = 0; cnt < ent->num_lines; cnt++) {
|
for (cnt = 0; cnt < ent->num_lines; cnt++) {
|
||||||
char ch;
|
char ch;
|
||||||
|
int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8;
|
||||||
|
|
||||||
printf("%.*s", (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8, hex);
|
if (suspect->commit->object.flags & UNINTERESTING) {
|
||||||
|
length--;
|
||||||
|
putchar('^');
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%.*s", length, hex);
|
||||||
if (opt & OUTPUT_ANNOTATE_COMPAT)
|
if (opt & OUTPUT_ANNOTATE_COMPAT)
|
||||||
printf("\t(%10s\t%10s\t%d)", ci.author,
|
printf("\t(%10s\t%10s\t%d)", ci.author,
|
||||||
format_time(ci.author_time, ci.author_tz,
|
format_time(ci.author_time, ci.author_tz,
|
||||||
|
@ -124,8 +124,11 @@ static void copy_templates(const char *git_dir, int len, const char *template_di
|
|||||||
int template_len;
|
int template_len;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
|
||||||
|
if (!template_dir) {
|
||||||
|
template_dir = getenv("GIT_TEMPLATE_DIR");
|
||||||
if (!template_dir)
|
if (!template_dir)
|
||||||
template_dir = DEFAULT_GIT_TEMPLATE_DIR;
|
template_dir = DEFAULT_GIT_TEMPLATE_DIR;
|
||||||
|
}
|
||||||
strcpy(template_path, template_dir);
|
strcpy(template_path, template_dir);
|
||||||
template_len = strlen(template_path);
|
template_len = strlen(template_path);
|
||||||
if (template_path[template_len-1] != '/') {
|
if (template_path[template_len-1] != '/') {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
|
||||||
static const char git_config_set_usage[] =
|
static const char git_config_set_usage[] =
|
||||||
"git-repo-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --list";
|
"git-repo-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --list";
|
||||||
|
|
||||||
static char *key;
|
static char *key;
|
||||||
static regex_t *key_regexp;
|
static regex_t *key_regexp;
|
||||||
@ -148,6 +148,18 @@ int cmd_repo_config(int argc, const char **argv, const char *prefix)
|
|||||||
} else {
|
} else {
|
||||||
die("$HOME not set");
|
die("$HOME not set");
|
||||||
}
|
}
|
||||||
|
} else if (!strcmp(argv[1], "--rename-section")) {
|
||||||
|
int ret;
|
||||||
|
if (argc != 4)
|
||||||
|
usage(git_config_set_usage);
|
||||||
|
ret = git_config_rename_section(argv[2], argv[3]);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
if (ret == 0) {
|
||||||
|
fprintf(stderr, "No such section!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
argc--;
|
argc--;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
|
||||||
static const char show_branch_usage[] =
|
static const char show_branch_usage[] =
|
||||||
"git-show-branch [--sparse] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
|
"git-show-branch [--sparse] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n] <branch>";
|
||||||
|
|
||||||
static int default_num;
|
static int default_num;
|
||||||
static int default_alloc;
|
static int default_alloc;
|
||||||
@ -17,6 +17,8 @@ static const char **default_arg;
|
|||||||
#define REV_SHIFT 2
|
#define REV_SHIFT 2
|
||||||
#define MAX_REVS (FLAG_BITS - REV_SHIFT) /* should not exceed bits_per_int - REV_SHIFT */
|
#define MAX_REVS (FLAG_BITS - REV_SHIFT) /* should not exceed bits_per_int - REV_SHIFT */
|
||||||
|
|
||||||
|
#define DEFAULT_REFLOG 4
|
||||||
|
|
||||||
static struct commit *interesting(struct commit_list *list)
|
static struct commit *interesting(struct commit_list *list)
|
||||||
{
|
{
|
||||||
while (list) {
|
while (list) {
|
||||||
@ -570,6 +572,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
|||||||
int head_at = -1;
|
int head_at = -1;
|
||||||
int topics = 0;
|
int topics = 0;
|
||||||
int dense = 1;
|
int dense = 1;
|
||||||
|
int reflog = 0;
|
||||||
|
|
||||||
git_config(git_show_branch_config);
|
git_config(git_show_branch_config);
|
||||||
|
|
||||||
@ -615,6 +618,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
|||||||
dense = 0;
|
dense = 0;
|
||||||
else if (!strcmp(arg, "--date-order"))
|
else if (!strcmp(arg, "--date-order"))
|
||||||
lifo = 0;
|
lifo = 0;
|
||||||
|
else if (!strcmp(arg, "--reflog")) {
|
||||||
|
reflog = DEFAULT_REFLOG;
|
||||||
|
}
|
||||||
|
else if (!strncmp(arg, "--reflog=", 9)) {
|
||||||
|
char *end;
|
||||||
|
reflog = strtoul(arg + 9, &end, 10);
|
||||||
|
if (*end != '\0')
|
||||||
|
die("unrecognized reflog count '%s'", arg + 9);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
usage(show_branch_usage);
|
usage(show_branch_usage);
|
||||||
ac--; av++;
|
ac--; av++;
|
||||||
@ -622,7 +634,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
|||||||
ac--; av++;
|
ac--; av++;
|
||||||
|
|
||||||
/* Only one of these is allowed */
|
/* Only one of these is allowed */
|
||||||
if (1 < independent + merge_base + (extra != 0))
|
if (1 < independent + merge_base + (extra != 0) + (!!reflog))
|
||||||
usage(show_branch_usage);
|
usage(show_branch_usage);
|
||||||
|
|
||||||
/* If nothing is specified, show all branches by default */
|
/* If nothing is specified, show all branches by default */
|
||||||
@ -631,10 +643,23 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
|||||||
|
|
||||||
if (all_heads + all_tags)
|
if (all_heads + all_tags)
|
||||||
snarf_refs(all_heads, all_tags);
|
snarf_refs(all_heads, all_tags);
|
||||||
|
if (reflog) {
|
||||||
|
int reflen;
|
||||||
|
if (!ac)
|
||||||
|
die("--reflog option needs one branch name");
|
||||||
|
reflen = strlen(*av);
|
||||||
|
for (i = 0; i < reflog; i++) {
|
||||||
|
char *name = xmalloc(reflen + 20);
|
||||||
|
sprintf(name, "%s@{%d}", *av, i);
|
||||||
|
append_one_rev(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
while (0 < ac) {
|
while (0 < ac) {
|
||||||
append_one_rev(*av);
|
append_one_rev(*av);
|
||||||
ac--; av++;
|
ac--; av++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
head_p = resolve_ref("HEAD", head_sha1, 1, NULL);
|
head_p = resolve_ref("HEAD", head_sha1, 1, NULL);
|
||||||
if (head_p) {
|
if (head_p) {
|
||||||
|
@ -2,13 +2,23 @@
|
|||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
|
#include "path-list.h"
|
||||||
|
|
||||||
static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*]";
|
static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*] < ref-list";
|
||||||
|
|
||||||
static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0,
|
static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0,
|
||||||
found_match = 0, verify = 0, quiet = 0, hash_only = 0, abbrev = 0;
|
found_match = 0, verify = 0, quiet = 0, hash_only = 0, abbrev = 0;
|
||||||
static const char **pattern;
|
static const char **pattern;
|
||||||
|
|
||||||
|
static void show_one(const char *refname, const unsigned char *sha1)
|
||||||
|
{
|
||||||
|
const char *hex = find_unique_abbrev(sha1, abbrev);
|
||||||
|
if (hash_only)
|
||||||
|
printf("%s\n", hex);
|
||||||
|
else
|
||||||
|
printf("%s %s\n", hex, refname);
|
||||||
|
}
|
||||||
|
|
||||||
static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
|
static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
|
||||||
{
|
{
|
||||||
struct object *obj;
|
struct object *obj;
|
||||||
@ -57,11 +67,7 @@ match:
|
|||||||
if (quiet)
|
if (quiet)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
hex = find_unique_abbrev(sha1, abbrev);
|
show_one(refname, sha1);
|
||||||
if (hash_only)
|
|
||||||
printf("%s\n", hex);
|
|
||||||
else
|
|
||||||
printf("%s %s\n", hex, refname);
|
|
||||||
|
|
||||||
if (!deref_tags)
|
if (!deref_tags)
|
||||||
return 0;
|
return 0;
|
||||||
@ -86,6 +92,60 @@ match:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int add_existing(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
|
||||||
|
{
|
||||||
|
struct path_list *list = (struct path_list *)cbdata;
|
||||||
|
path_list_insert(refname, list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read "^(?:<anything>\s)?<refname>(?:\^\{\})?$" from the standard input,
|
||||||
|
* and
|
||||||
|
* (1) strip "^{}" at the end of line if any;
|
||||||
|
* (2) ignore if match is provided and does not head-match refname;
|
||||||
|
* (3) warn if refname is not a well-formed refname and skip;
|
||||||
|
* (4) ignore if refname is a ref that exists in the local repository;
|
||||||
|
* (5) otherwise output the line.
|
||||||
|
*/
|
||||||
|
static int exclude_existing(const char *match)
|
||||||
|
{
|
||||||
|
static struct path_list existing_refs = { NULL, 0, 0, 0 };
|
||||||
|
char buf[1024];
|
||||||
|
int matchlen = match ? strlen(match) : 0;
|
||||||
|
|
||||||
|
for_each_ref(add_existing, &existing_refs);
|
||||||
|
while (fgets(buf, sizeof(buf), stdin)) {
|
||||||
|
char *ref;
|
||||||
|
int len = strlen(buf);
|
||||||
|
|
||||||
|
if (len > 0 && buf[len - 1] == '\n')
|
||||||
|
buf[--len] = '\0';
|
||||||
|
if (3 <= len && !strcmp(buf + len - 3, "^{}")) {
|
||||||
|
len -= 3;
|
||||||
|
buf[len] = '\0';
|
||||||
|
}
|
||||||
|
for (ref = buf + len; buf < ref; ref--)
|
||||||
|
if (isspace(ref[-1]))
|
||||||
|
break;
|
||||||
|
if (match) {
|
||||||
|
int reflen = buf + len - ref;
|
||||||
|
if (reflen < matchlen)
|
||||||
|
continue;
|
||||||
|
if (strncmp(ref, match, matchlen))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (check_ref_format(ref)) {
|
||||||
|
fprintf(stderr, "warning: ref '%s' ignored\n", ref);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!path_list_has_path(&existing_refs, ref)) {
|
||||||
|
printf("%s\n", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int cmd_show_ref(int argc, const char **argv, const char *prefix)
|
int cmd_show_ref(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -121,13 +181,13 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
|
|||||||
if (!strncmp(arg, "--hash=", 7) ||
|
if (!strncmp(arg, "--hash=", 7) ||
|
||||||
(!strncmp(arg, "--abbrev", 8) &&
|
(!strncmp(arg, "--abbrev", 8) &&
|
||||||
(arg[8] == '=' || arg[8] == '\0'))) {
|
(arg[8] == '=' || arg[8] == '\0'))) {
|
||||||
if (arg[3] != 'h' && !arg[8])
|
if (arg[2] != 'h' && !arg[8])
|
||||||
/* --abbrev only */
|
/* --abbrev only */
|
||||||
abbrev = DEFAULT_ABBREV;
|
abbrev = DEFAULT_ABBREV;
|
||||||
else {
|
else {
|
||||||
/* --hash= or --abbrev= */
|
/* --hash= or --abbrev= */
|
||||||
char *end;
|
char *end;
|
||||||
if (arg[3] == 'h') {
|
if (arg[2] == 'h') {
|
||||||
hash_only = 1;
|
hash_only = 1;
|
||||||
arg += 7;
|
arg += 7;
|
||||||
}
|
}
|
||||||
@ -153,8 +213,31 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
|
|||||||
heads_only = 1;
|
heads_only = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(arg, "--exclude-existing"))
|
||||||
|
return exclude_existing(NULL);
|
||||||
|
if (!strncmp(arg, "--exclude-existing=", 19))
|
||||||
|
return exclude_existing(arg + 19);
|
||||||
usage(show_ref_usage);
|
usage(show_ref_usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (verify) {
|
||||||
|
unsigned char sha1[20];
|
||||||
|
|
||||||
|
while (*pattern) {
|
||||||
|
if (!strncmp(*pattern, "refs/", 5) &&
|
||||||
|
resolve_ref(*pattern, sha1, 1, NULL)) {
|
||||||
|
if (!quiet)
|
||||||
|
show_one(*pattern, sha1);
|
||||||
|
}
|
||||||
|
else if (!quiet)
|
||||||
|
die("'%s' - not a valid ref", *pattern);
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
pattern++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (show_head)
|
if (show_head)
|
||||||
head_ref(show_ref, NULL);
|
head_ref(show_ref, NULL);
|
||||||
for_each_ref(show_ref, NULL);
|
for_each_ref(show_ref, NULL);
|
||||||
|
2
cache.h
2
cache.h
@ -309,6 +309,7 @@ void datestamp(char *buf, int bufsize);
|
|||||||
unsigned long approxidate(const char *);
|
unsigned long approxidate(const char *);
|
||||||
|
|
||||||
extern int setup_ident(void);
|
extern int setup_ident(void);
|
||||||
|
extern void ignore_missing_committer_name();
|
||||||
extern const char *git_author_info(int);
|
extern const char *git_author_info(int);
|
||||||
extern const char *git_committer_info(int);
|
extern const char *git_committer_info(int);
|
||||||
|
|
||||||
@ -404,6 +405,7 @@ extern int git_config_int(const char *, const char *);
|
|||||||
extern int git_config_bool(const char *, const char *);
|
extern int git_config_bool(const char *, const char *);
|
||||||
extern int git_config_set(const char *, const char *);
|
extern int git_config_set(const char *, const char *);
|
||||||
extern int git_config_set_multivar(const char *, const char *, const char *, int);
|
extern int git_config_set_multivar(const char *, const char *, const char *, int);
|
||||||
|
extern int git_config_rename_section(const char *, const char *);
|
||||||
extern int check_repository_format_version(const char *var, const char *value);
|
extern int check_repository_format_version(const char *var, const char *value);
|
||||||
|
|
||||||
#define MAX_GITNAME (1000)
|
#define MAX_GITNAME (1000)
|
||||||
|
64
config.c
64
config.c
@ -746,4 +746,68 @@ out_free:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_config_rename_section(const char *old_name, const char *new_name)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
const char *config_filename;
|
||||||
|
struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1);
|
||||||
|
int out_fd;
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
config_filename = getenv("GIT_CONFIG");
|
||||||
|
if (!config_filename) {
|
||||||
|
config_filename = getenv("GIT_CONFIG_LOCAL");
|
||||||
|
if (!config_filename)
|
||||||
|
config_filename = git_path("config");
|
||||||
|
}
|
||||||
|
config_filename = xstrdup(config_filename);
|
||||||
|
out_fd = hold_lock_file_for_update(lock, config_filename, 0);
|
||||||
|
if (out_fd < 0)
|
||||||
|
return error("Could not lock config file!");
|
||||||
|
|
||||||
|
if (!(config_file = fopen(config_filename, "rb")))
|
||||||
|
return error("Could not open config file!");
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), config_file)) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; buf[i] && isspace(buf[i]); i++)
|
||||||
|
; /* do nothing */
|
||||||
|
if (buf[i] == '[') {
|
||||||
|
/* it's a section */
|
||||||
|
int j = 0, dot = 0;
|
||||||
|
for (i++; buf[i] && buf[i] != ']'; i++) {
|
||||||
|
if (!dot && isspace(buf[i])) {
|
||||||
|
dot = 1;
|
||||||
|
if (old_name[j++] != '.')
|
||||||
|
break;
|
||||||
|
for (i++; isspace(buf[i]); i++)
|
||||||
|
; /* do nothing */
|
||||||
|
if (buf[i] != '"')
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (buf[i] == '\\' && dot)
|
||||||
|
i++;
|
||||||
|
else if (buf[i] == '"' && dot) {
|
||||||
|
for (i++; isspace(buf[i]); i++)
|
||||||
|
; /* do_nothing */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (buf[i] != old_name[j++])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (buf[i] == ']') {
|
||||||
|
/* old_name matches */
|
||||||
|
ret++;
|
||||||
|
store.baselen = strlen(new_name);
|
||||||
|
store_write_section(out_fd, new_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write(out_fd, buf, strlen(buf));
|
||||||
|
}
|
||||||
|
if (close(out_fd) || commit_lock_file(lock) < 0)
|
||||||
|
return error("Cannot commit config file!");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
syn region gitLine start=/^#/ end=/$/
|
syn region gitLine start=/^#/ end=/$/
|
||||||
syn region gitCommit start=/^# Updated but not checked in:$/ end=/^#$/ contains=gitHead,gitCommitFile
|
syn region gitCommit start=/^# Added but not yet committed:$/ end=/^#$/ contains=gitHead,gitCommitFile
|
||||||
syn region gitHead contained start=/^# (.*)/ end=/^#$/
|
syn region gitHead contained start=/^# (.*)/ end=/^#$/
|
||||||
syn region gitChanged start=/^# Changed but not updated:/ end=/^#$/ contains=gitHead,gitChangedFile
|
syn region gitChanged start=/^# Changed but not added:/ end=/^#$/ contains=gitHead,gitChangedFile
|
||||||
syn region gitUntracked start=/^# Untracked files:/ end=/^#$/ contains=gitHead,gitUntrackedFile
|
syn region gitUntracked start=/^# Untracked files:/ end=/^#$/ contains=gitHead,gitUntrackedFile
|
||||||
|
|
||||||
syn match gitCommitFile contained /^#\t.*/hs=s+2
|
syn match gitCommitFile contained /^#\t.*/hs=s+2
|
||||||
|
14
git-fetch.sh
14
git-fetch.sh
@ -96,7 +96,7 @@ fi
|
|||||||
|
|
||||||
# Global that is reused later
|
# Global that is reused later
|
||||||
ls_remote_result=$(git ls-remote $upload_pack "$remote") ||
|
ls_remote_result=$(git ls-remote $upload_pack "$remote") ||
|
||||||
die "Cannot find the reflist at $remote"
|
die "Cannot get the repository state from $remote"
|
||||||
|
|
||||||
append_fetch_head () {
|
append_fetch_head () {
|
||||||
head_="$1"
|
head_="$1"
|
||||||
@ -242,7 +242,7 @@ esac
|
|||||||
reflist=$(get_remote_refs_for_fetch "$@")
|
reflist=$(get_remote_refs_for_fetch "$@")
|
||||||
if test "$tags"
|
if test "$tags"
|
||||||
then
|
then
|
||||||
taglist=`IFS=" " &&
|
taglist=`IFS=' ' &&
|
||||||
echo "$ls_remote_result" |
|
echo "$ls_remote_result" |
|
||||||
while read sha1 name
|
while read sha1 name
|
||||||
do
|
do
|
||||||
@ -438,17 +438,11 @@ case "$no_tags$tags" in
|
|||||||
*:refs/*)
|
*:refs/*)
|
||||||
# effective only when we are following remote branch
|
# effective only when we are following remote branch
|
||||||
# using local tracking branch.
|
# using local tracking branch.
|
||||||
taglist=$(IFS=" " &&
|
taglist=$(IFS=' ' &&
|
||||||
echo "$ls_remote_result" |
|
echo "$ls_remote_result" |
|
||||||
sed -n -e 's|^\('"$_x40"'\) \(refs/tags/.*\)^{}$|\1 \2|p' \
|
git-show-ref --exclude-existing=refs/tags/ |
|
||||||
-e 's|^\('"$_x40"'\) \(refs/tags/.*\)$|\1 \2|p' |
|
|
||||||
while read sha1 name
|
while read sha1 name
|
||||||
do
|
do
|
||||||
git-show-ref --verify --quiet -- "$name" && continue
|
|
||||||
git-check-ref-format "$name" || {
|
|
||||||
echo >&2 "warning: tag ${name} ignored"
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
git-cat-file -t "$sha1" >/dev/null 2>&1 || continue
|
git-cat-file -t "$sha1" >/dev/null 2>&1 || continue
|
||||||
echo >&2 "Auto-following $name"
|
echo >&2 "Auto-following $name"
|
||||||
echo ".${name}:${name}"
|
echo ".${name}:${name}"
|
||||||
|
@ -94,7 +94,7 @@ while read sha1 path
|
|||||||
do
|
do
|
||||||
case "$sha1" in
|
case "$sha1" in
|
||||||
failed)
|
failed)
|
||||||
die "Failed to find remote refs"
|
exit 1 ;;
|
||||||
esac
|
esac
|
||||||
case "$path" in
|
case "$path" in
|
||||||
refs/heads/*)
|
refs/heads/*)
|
||||||
|
@ -111,16 +111,14 @@ expand_refs_wildcard () {
|
|||||||
local_force=
|
local_force=
|
||||||
test "z$lref" = "z$ref" || local_force='+'
|
test "z$lref" = "z$ref" || local_force='+'
|
||||||
echo "$ls_remote_result" |
|
echo "$ls_remote_result" |
|
||||||
|
sed -e '/\^{}$/d' |
|
||||||
(
|
(
|
||||||
IFS=' '
|
IFS=' '
|
||||||
while read sha1 name
|
while read sha1 name
|
||||||
do
|
do
|
||||||
|
# ignore the ones that do not start with $from
|
||||||
mapped=${name#"$from"}
|
mapped=${name#"$from"}
|
||||||
if test "z$name" != "z${name%'^{}'}" ||
|
test "z$name" = "z$mapped" && continue
|
||||||
test "z$name" = "z$mapped"
|
|
||||||
then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
echo "${local_force}${name}:${to}${mapped}"
|
echo "${local_force}${name}:${to}${mapped}"
|
||||||
done
|
done
|
||||||
)
|
)
|
||||||
|
@ -154,7 +154,7 @@ sub find_conflict {
|
|||||||
sub merge {
|
sub merge {
|
||||||
my ($name, $path) = @_;
|
my ($name, $path) = @_;
|
||||||
record_preimage($path, "$rr_dir/$name/thisimage");
|
record_preimage($path, "$rr_dir/$name/thisimage");
|
||||||
unless (system('git merge-file', map { "$rr_dir/$name/${_}image" }
|
unless (system('git', 'merge-file', map { "$rr_dir/$name/${_}image" }
|
||||||
qw(this pre post))) {
|
qw(this pre post))) {
|
||||||
my $in;
|
my $in;
|
||||||
open $in, "<$rr_dir/$name/thisimage" or
|
open $in, "<$rr_dir/$name/thisimage" or
|
||||||
|
@ -434,6 +434,7 @@ my %actions = (
|
|||||||
"tags" => \&git_tags,
|
"tags" => \&git_tags,
|
||||||
"tree" => \&git_tree,
|
"tree" => \&git_tree,
|
||||||
"snapshot" => \&git_snapshot,
|
"snapshot" => \&git_snapshot,
|
||||||
|
"object" => \&git_object,
|
||||||
# those below don't need $project
|
# those below don't need $project
|
||||||
"opml" => \&git_opml,
|
"opml" => \&git_opml,
|
||||||
"project_list" => \&git_project_list,
|
"project_list" => \&git_project_list,
|
||||||
@ -827,15 +828,13 @@ sub format_log_line_html {
|
|||||||
my $line = shift;
|
my $line = shift;
|
||||||
|
|
||||||
$line = esc_html($line, -nbsp=>1);
|
$line = esc_html($line, -nbsp=>1);
|
||||||
if ($line =~ m/([0-9a-fA-F]{40})/) {
|
if ($line =~ m/([0-9a-fA-F]{8,40})/) {
|
||||||
my $hash_text = $1;
|
my $hash_text = $1;
|
||||||
if (git_get_type($hash_text) eq "commit") {
|
|
||||||
my $link =
|
my $link =
|
||||||
$cgi->a({-href => href(action=>"commit", hash=>$hash_text),
|
$cgi->a({-href => href(action=>"object", hash=>$hash_text),
|
||||||
-class => "text"}, $hash_text);
|
-class => "text"}, $hash_text);
|
||||||
$line =~ s/$hash_text/$link/;
|
$line =~ s/$hash_text/$link/;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return $line;
|
return $line;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -856,7 +855,8 @@ sub format_ref_marker {
|
|||||||
$name = $ref;
|
$name = $ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
$markers .= " <span class=\"$type\">" . esc_html($name) . "</span>";
|
$markers .= " <span class=\"$type\" title=\"$ref\">" .
|
||||||
|
esc_html($name) . "</span>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1989,12 +1989,73 @@ sub git_print_log ($;%) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# return link target (what link points to)
|
||||||
|
sub git_get_link_target {
|
||||||
|
my $hash = shift;
|
||||||
|
my $link_target;
|
||||||
|
|
||||||
|
# read link
|
||||||
|
open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
|
||||||
|
or return;
|
||||||
|
{
|
||||||
|
local $/;
|
||||||
|
$link_target = <$fd>;
|
||||||
|
}
|
||||||
|
close $fd
|
||||||
|
or return;
|
||||||
|
|
||||||
|
return $link_target;
|
||||||
|
}
|
||||||
|
|
||||||
|
# given link target, and the directory (basedir) the link is in,
|
||||||
|
# return target of link relative to top directory (top tree);
|
||||||
|
# return undef if it is not possible (including absolute links).
|
||||||
|
sub normalize_link_target {
|
||||||
|
my ($link_target, $basedir, $hash_base) = @_;
|
||||||
|
|
||||||
|
# we can normalize symlink target only if $hash_base is provided
|
||||||
|
return unless $hash_base;
|
||||||
|
|
||||||
|
# absolute symlinks (beginning with '/') cannot be normalized
|
||||||
|
return if (substr($link_target, 0, 1) eq '/');
|
||||||
|
|
||||||
|
# normalize link target to path from top (root) tree (dir)
|
||||||
|
my $path;
|
||||||
|
if ($basedir) {
|
||||||
|
$path = $basedir . '/' . $link_target;
|
||||||
|
} else {
|
||||||
|
# we are in top (root) tree (dir)
|
||||||
|
$path = $link_target;
|
||||||
|
}
|
||||||
|
|
||||||
|
# remove //, /./, and /../
|
||||||
|
my @path_parts;
|
||||||
|
foreach my $part (split('/', $path)) {
|
||||||
|
# discard '.' and ''
|
||||||
|
next if (!$part || $part eq '.');
|
||||||
|
# handle '..'
|
||||||
|
if ($part eq '..') {
|
||||||
|
if (@path_parts) {
|
||||||
|
pop @path_parts;
|
||||||
|
} else {
|
||||||
|
# link leads outside repository (outside top dir)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
push @path_parts, $part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$path = join('/', @path_parts);
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
# print tree entry (row of git_tree), but without encompassing <tr> element
|
# print tree entry (row of git_tree), but without encompassing <tr> element
|
||||||
sub git_print_tree_entry {
|
sub git_print_tree_entry {
|
||||||
my ($t, $basedir, $hash_base, $have_blame) = @_;
|
my ($t, $basedir, $hash_base, $have_blame) = @_;
|
||||||
|
|
||||||
my %base_key = ();
|
my %base_key = ();
|
||||||
$base_key{hash_base} = $hash_base if defined $hash_base;
|
$base_key{'hash_base'} = $hash_base if defined $hash_base;
|
||||||
|
|
||||||
# The format of a table row is: mode list link. Where mode is
|
# The format of a table row is: mode list link. Where mode is
|
||||||
# the mode of the entry, list is the name of the entry, an href,
|
# the mode of the entry, list is the name of the entry, an href,
|
||||||
@ -2005,7 +2066,22 @@ sub git_print_tree_entry {
|
|||||||
print "<td class=\"list\">" .
|
print "<td class=\"list\">" .
|
||||||
$cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
|
$cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
|
||||||
file_name=>"$basedir$t->{'name'}", %base_key),
|
file_name=>"$basedir$t->{'name'}", %base_key),
|
||||||
-class => "list"}, esc_path($t->{'name'})) . "</td>\n";
|
-class => "list"}, esc_path($t->{'name'}));
|
||||||
|
if (S_ISLNK(oct $t->{'mode'})) {
|
||||||
|
my $link_target = git_get_link_target($t->{'hash'});
|
||||||
|
if ($link_target) {
|
||||||
|
my $norm_target = normalize_link_target($link_target, $basedir, $hash_base);
|
||||||
|
if (defined $norm_target) {
|
||||||
|
print " -> " .
|
||||||
|
$cgi->a({-href => href(action=>"object", hash_base=>$hash_base,
|
||||||
|
file_name=>$norm_target),
|
||||||
|
-title => $norm_target}, esc_path($link_target));
|
||||||
|
} else {
|
||||||
|
print " -> " . esc_path($link_target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print "</td>\n";
|
||||||
print "<td class=\"link\">";
|
print "<td class=\"link\">";
|
||||||
print $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
|
print $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
|
||||||
file_name=>"$basedir$t->{'name'}", %base_key)},
|
file_name=>"$basedir$t->{'name'}", %base_key)},
|
||||||
@ -3414,8 +3490,7 @@ sub git_snapshot {
|
|||||||
my $filename = basename($project) . "-$hash.tar.$suffix";
|
my $filename = basename($project) . "-$hash.tar.$suffix";
|
||||||
|
|
||||||
print $cgi->header(
|
print $cgi->header(
|
||||||
-type => 'application/x-tar',
|
-type => "application/$ctype",
|
||||||
-content_encoding => $ctype,
|
|
||||||
-content_disposition => 'inline; filename="' . "$filename" . '"',
|
-content_disposition => 'inline; filename="' . "$filename" . '"',
|
||||||
-status => '200 OK');
|
-status => '200 OK');
|
||||||
|
|
||||||
@ -3498,14 +3573,45 @@ sub git_commit {
|
|||||||
my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'});
|
my %cd = parse_date($co{'committer_epoch'}, $co{'committer_tz'});
|
||||||
|
|
||||||
my $parent = $co{'parent'};
|
my $parent = $co{'parent'};
|
||||||
|
my $parents = $co{'parents'}; # listref
|
||||||
|
|
||||||
|
# we need to prepare $formats_nav before any parameter munging
|
||||||
|
my $formats_nav;
|
||||||
|
if (!defined $parent) {
|
||||||
|
# --root commitdiff
|
||||||
|
$formats_nav .= '(initial)';
|
||||||
|
} elsif (@$parents == 1) {
|
||||||
|
# single parent commit
|
||||||
|
$formats_nav .=
|
||||||
|
'(parent: ' .
|
||||||
|
$cgi->a({-href => href(action=>"commit",
|
||||||
|
hash=>$parent)},
|
||||||
|
esc_html(substr($parent, 0, 7))) .
|
||||||
|
')';
|
||||||
|
} else {
|
||||||
|
# merge commit
|
||||||
|
$formats_nav .=
|
||||||
|
'(merge: ' .
|
||||||
|
join(' ', map {
|
||||||
|
$cgi->a({-href => href(action=>"commitdiff",
|
||||||
|
hash=>$_)},
|
||||||
|
esc_html(substr($_, 0, 7)));
|
||||||
|
} @$parents ) .
|
||||||
|
')';
|
||||||
|
}
|
||||||
|
|
||||||
if (!defined $parent) {
|
if (!defined $parent) {
|
||||||
$parent = "--root";
|
$parent = "--root";
|
||||||
}
|
}
|
||||||
|
my @difftree;
|
||||||
|
if (@$parents <= 1) {
|
||||||
|
# difftree output is not printed for merges
|
||||||
open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id",
|
open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id",
|
||||||
@diff_opts, $parent, $hash, "--"
|
@diff_opts, $parent, $hash, "--"
|
||||||
or die_error(undef, "Open git-diff-tree failed");
|
or die_error(undef, "Open git-diff-tree failed");
|
||||||
my @difftree = map { chomp; $_ } <$fd>;
|
@difftree = map { chomp; $_ } <$fd>;
|
||||||
close $fd or die_error(undef, "Reading git-diff-tree failed");
|
close $fd or die_error(undef, "Reading git-diff-tree failed");
|
||||||
|
}
|
||||||
|
|
||||||
# non-textual hash id's can be cached
|
# non-textual hash id's can be cached
|
||||||
my $expires;
|
my $expires;
|
||||||
@ -3517,16 +3623,10 @@ sub git_commit {
|
|||||||
|
|
||||||
my $have_snapshot = gitweb_have_snapshot();
|
my $have_snapshot = gitweb_have_snapshot();
|
||||||
|
|
||||||
my @views_nav = ();
|
|
||||||
if (defined $file_name && defined $co{'parent'}) {
|
|
||||||
push @views_nav,
|
|
||||||
$cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)},
|
|
||||||
"blame");
|
|
||||||
}
|
|
||||||
git_header_html(undef, $expires);
|
git_header_html(undef, $expires);
|
||||||
git_print_page_nav('commit', '',
|
git_print_page_nav('commit', '',
|
||||||
$hash, $co{'tree'}, $hash,
|
$hash, $co{'tree'}, $hash,
|
||||||
join (' | ', @views_nav));
|
$formats_nav);
|
||||||
|
|
||||||
if (defined $co{'parent'}) {
|
if (defined $co{'parent'}) {
|
||||||
git_print_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
|
git_print_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
|
||||||
@ -3567,7 +3667,7 @@ sub git_commit {
|
|||||||
}
|
}
|
||||||
print "</td>" .
|
print "</td>" .
|
||||||
"</tr>\n";
|
"</tr>\n";
|
||||||
my $parents = $co{'parents'};
|
|
||||||
foreach my $par (@$parents) {
|
foreach my $par (@$parents) {
|
||||||
print "<tr>" .
|
print "<tr>" .
|
||||||
"<td>parent</td>" .
|
"<td>parent</td>" .
|
||||||
@ -3589,11 +3689,61 @@ sub git_commit {
|
|||||||
git_print_log($co{'comment'});
|
git_print_log($co{'comment'});
|
||||||
print "</div>\n";
|
print "</div>\n";
|
||||||
|
|
||||||
|
if (@$parents <= 1) {
|
||||||
|
# do not output difftree/whatchanged for merges
|
||||||
git_difftree_body(\@difftree, $hash, $parent);
|
git_difftree_body(\@difftree, $hash, $parent);
|
||||||
|
}
|
||||||
|
|
||||||
git_footer_html();
|
git_footer_html();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub git_object {
|
||||||
|
# object is defined by:
|
||||||
|
# - hash or hash_base alone
|
||||||
|
# - hash_base and file_name
|
||||||
|
my $type;
|
||||||
|
|
||||||
|
# - hash or hash_base alone
|
||||||
|
if ($hash || ($hash_base && !defined $file_name)) {
|
||||||
|
my $object_id = $hash || $hash_base;
|
||||||
|
|
||||||
|
my $git_command = git_cmd_str();
|
||||||
|
open my $fd, "-|", "$git_command cat-file -t $object_id 2>/dev/null"
|
||||||
|
or die_error('404 Not Found', "Object does not exist");
|
||||||
|
$type = <$fd>;
|
||||||
|
chomp $type;
|
||||||
|
close $fd
|
||||||
|
or die_error('404 Not Found', "Object does not exist");
|
||||||
|
|
||||||
|
# - hash_base and file_name
|
||||||
|
} elsif ($hash_base && defined $file_name) {
|
||||||
|
$file_name =~ s,/+$,,;
|
||||||
|
|
||||||
|
system(git_cmd(), "cat-file", '-e', $hash_base) == 0
|
||||||
|
or die_error('404 Not Found', "Base object does not exist");
|
||||||
|
|
||||||
|
# here errors should not hapen
|
||||||
|
open my $fd, "-|", git_cmd(), "ls-tree", $hash_base, "--", $file_name
|
||||||
|
or die_error(undef, "Open git-ls-tree failed");
|
||||||
|
my $line = <$fd>;
|
||||||
|
close $fd;
|
||||||
|
|
||||||
|
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
|
||||||
|
unless ($line && $line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/) {
|
||||||
|
die_error('404 Not Found', "File or directory for given base does not exist");
|
||||||
|
}
|
||||||
|
$type = $2;
|
||||||
|
$hash = $3;
|
||||||
|
} else {
|
||||||
|
die_error('404 Not Found', "Not enough information to find object");
|
||||||
|
}
|
||||||
|
|
||||||
|
print $cgi->redirect(-uri => href(action=>$type, -full=>1,
|
||||||
|
hash=>$hash, hash_base=>$hash_base,
|
||||||
|
file_name=>$file_name),
|
||||||
|
-status => '302 Found');
|
||||||
|
}
|
||||||
|
|
||||||
sub git_blobdiff {
|
sub git_blobdiff {
|
||||||
my $format = shift || 'html';
|
my $format = shift || 'html';
|
||||||
|
|
||||||
|
15
ident.c
15
ident.c
@ -221,3 +221,18 @@ const char *git_committer_info(int error_on_no_name)
|
|||||||
getenv("GIT_COMMITTER_DATE"),
|
getenv("GIT_COMMITTER_DATE"),
|
||||||
error_on_no_name);
|
error_on_no_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ignore_missing_committer_name()
|
||||||
|
{
|
||||||
|
/* If we did not get a name from the user's gecos entry then
|
||||||
|
* git_default_name is empty; so instead load the username
|
||||||
|
* into it as a 'good enough for now' approximation of who
|
||||||
|
* this user is.
|
||||||
|
*/
|
||||||
|
if (!*git_default_name) {
|
||||||
|
struct passwd *pw = getpwuid(getuid());
|
||||||
|
if (!pw)
|
||||||
|
die("You don't exist. Go away!");
|
||||||
|
strlcpy(git_default_name, pw->pw_name, sizeof(git_default_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include "git-compat-util.h"
|
||||||
#include <string.h>
|
|
||||||
#include "delta.h"
|
#include "delta.h"
|
||||||
|
|
||||||
void *patch_delta(const void *src_buf, unsigned long src_size,
|
void *patch_delta(const void *src_buf, unsigned long src_size,
|
||||||
@ -34,9 +33,7 @@ void *patch_delta(const void *src_buf, unsigned long src_size,
|
|||||||
|
|
||||||
/* now the result size */
|
/* now the result size */
|
||||||
size = get_delta_hdr_size(&data, top);
|
size = get_delta_hdr_size(&data, top);
|
||||||
dst_buf = malloc(size + 1);
|
dst_buf = xmalloc(size + 1);
|
||||||
if (!dst_buf)
|
|
||||||
return NULL;
|
|
||||||
dst_buf[size] = 0;
|
dst_buf[size] = 0;
|
||||||
|
|
||||||
out = dst_buf;
|
out = dst_buf;
|
||||||
@ -55,13 +52,13 @@ void *patch_delta(const void *src_buf, unsigned long src_size,
|
|||||||
if (cp_off + cp_size < cp_size ||
|
if (cp_off + cp_size < cp_size ||
|
||||||
cp_off + cp_size > src_size ||
|
cp_off + cp_size > src_size ||
|
||||||
cp_size > size)
|
cp_size > size)
|
||||||
goto bad;
|
break;
|
||||||
memcpy(out, (char *) src_buf + cp_off, cp_size);
|
memcpy(out, (char *) src_buf + cp_off, cp_size);
|
||||||
out += cp_size;
|
out += cp_size;
|
||||||
size -= cp_size;
|
size -= cp_size;
|
||||||
} else if (cmd) {
|
} else if (cmd) {
|
||||||
if (cmd > size)
|
if (cmd > size)
|
||||||
goto bad;
|
break;
|
||||||
memcpy(out, data, cmd);
|
memcpy(out, data, cmd);
|
||||||
out += cmd;
|
out += cmd;
|
||||||
data += cmd;
|
data += cmd;
|
||||||
@ -72,12 +69,14 @@ void *patch_delta(const void *src_buf, unsigned long src_size,
|
|||||||
* extensions. In the mean time we must fail when
|
* extensions. In the mean time we must fail when
|
||||||
* encountering them (might be data corruption).
|
* encountering them (might be data corruption).
|
||||||
*/
|
*/
|
||||||
|
error("unexpected delta opcode 0");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sanity check */
|
/* sanity check */
|
||||||
if (data != top || size != 0) {
|
if (data != top || size != 0) {
|
||||||
|
error("delta replay has gone wild");
|
||||||
bad:
|
bad:
|
||||||
free(dst_buf);
|
free(dst_buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -72,7 +72,7 @@ static void safe_read(int fd, void *buffer, unsigned size)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
die("read error (%s)", strerror(errno));
|
die("read error (%s)", strerror(errno));
|
||||||
if (!ret)
|
if (!ret)
|
||||||
die("unexpected EOF");
|
die("The remote end hung up unexpectedly");
|
||||||
n += ret;
|
n += ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,7 +358,7 @@ int add_file_to_index(const char *path, int verbose)
|
|||||||
|
|
||||||
if (index_path(ce->sha1, path, &st, 1))
|
if (index_path(ce->sha1, path, &st, 1))
|
||||||
die("unable to index file %s", path);
|
die("unable to index file %s", path);
|
||||||
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD))
|
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
|
||||||
die("unable to add %s to index",path);
|
die("unable to add %s to index",path);
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf("add '%s'\n", path);
|
printf("add '%s'\n", path);
|
||||||
@ -517,7 +517,7 @@ static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace
|
|||||||
pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
|
pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
|
||||||
if (pos >= 0) {
|
if (pos >= 0) {
|
||||||
retval = -1;
|
retval = -1;
|
||||||
if (ok_to_replace)
|
if (!ok_to_replace)
|
||||||
break;
|
break;
|
||||||
remove_cache_entry_at(pos);
|
remove_cache_entry_at(pos);
|
||||||
continue;
|
continue;
|
||||||
@ -609,7 +609,7 @@ int add_cache_entry(struct cache_entry *ce, int option)
|
|||||||
if (!skip_df_check &&
|
if (!skip_df_check &&
|
||||||
check_file_directory_conflict(ce, pos, ok_to_replace)) {
|
check_file_directory_conflict(ce, pos, ok_to_replace)) {
|
||||||
if (!ok_to_replace)
|
if (!ok_to_replace)
|
||||||
return -1;
|
return error("'%s' appears as both a file and as a directory", ce->name);
|
||||||
pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
|
pos = cache_name_pos(ce->name, ntohs(ce->ce_flags));
|
||||||
pos = -pos-1;
|
pos = -pos-1;
|
||||||
}
|
}
|
||||||
|
@ -420,6 +420,8 @@ int main(int argc, char **argv)
|
|||||||
die("'%s': unable to chdir or not a git archive", dir);
|
die("'%s': unable to chdir or not a git archive", dir);
|
||||||
|
|
||||||
setup_ident();
|
setup_ident();
|
||||||
|
/* don't die if gecos is empty */
|
||||||
|
ignore_missing_committer_name();
|
||||||
git_config(receive_pack_config);
|
git_config(receive_pack_config);
|
||||||
|
|
||||||
write_head_info();
|
write_head_info();
|
||||||
|
10
refs.c
10
refs.c
@ -867,6 +867,16 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
|
|||||||
goto rollback;
|
goto rollback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strncmp(oldref, "refs/heads/", 11) &&
|
||||||
|
!strncmp(newref, "refs/heads/", 11)) {
|
||||||
|
char oldsection[1024], newsection[1024];
|
||||||
|
|
||||||
|
snprintf(oldsection, 1024, "branch.%s", oldref + 11);
|
||||||
|
snprintf(newsection, 1024, "branch.%s", newref + 11);
|
||||||
|
if (git_config_rename_section(oldsection, newsection) < 0)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rollback:
|
rollback:
|
||||||
|
@ -272,4 +272,13 @@ test_expect_success \
|
|||||||
wc -l) &&
|
wc -l) &&
|
||||||
test $numparent = 1'
|
test $numparent = 1'
|
||||||
|
|
||||||
|
test_expect_success 'update-index D/F conflict' '
|
||||||
|
mv path0 tmp &&
|
||||||
|
mv path2 path0 &&
|
||||||
|
mv tmp path2 &&
|
||||||
|
git update-index --add --replace path2 path0/file2 &&
|
||||||
|
numpath0=$(git ls-files path0 | wc -l) &&
|
||||||
|
test $numpath0 = 1
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
@ -343,5 +343,53 @@ EOF
|
|||||||
|
|
||||||
test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect'
|
test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect'
|
||||||
|
|
||||||
|
cat > .git/config << EOF
|
||||||
|
# Hallo
|
||||||
|
#Bello
|
||||||
|
[branch "eins"]
|
||||||
|
x = 1
|
||||||
|
[branch.eins]
|
||||||
|
y = 1
|
||||||
|
[branch "1 234 blabl/a"]
|
||||||
|
weird
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success "rename section" \
|
||||||
|
"git-repo-config --rename-section branch.eins branch.zwei"
|
||||||
|
|
||||||
|
cat > expect << EOF
|
||||||
|
# Hallo
|
||||||
|
#Bello
|
||||||
|
[branch "zwei"]
|
||||||
|
x = 1
|
||||||
|
[branch "zwei"]
|
||||||
|
y = 1
|
||||||
|
[branch "1 234 blabl/a"]
|
||||||
|
weird
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success "rename succeeded" "diff -u expect .git/config"
|
||||||
|
|
||||||
|
test_expect_failure "rename non-existing section" \
|
||||||
|
'git-repo-config --rename-section branch."world domination" branch.drei'
|
||||||
|
|
||||||
|
test_expect_success "rename succeeded" "diff -u expect .git/config"
|
||||||
|
|
||||||
|
test_expect_success "rename another section" \
|
||||||
|
'git-repo-config --rename-section branch."1 234 blabl/a" branch.drei'
|
||||||
|
|
||||||
|
cat > expect << EOF
|
||||||
|
# Hallo
|
||||||
|
#Bello
|
||||||
|
[branch "zwei"]
|
||||||
|
x = 1
|
||||||
|
[branch "zwei"]
|
||||||
|
y = 1
|
||||||
|
[branch "drei"]
|
||||||
|
weird
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success "rename succeeded" "diff -u expect .git/config"
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
||||||
|
@ -94,6 +94,8 @@ test_expect_failure \
|
|||||||
git-branch r &&
|
git-branch r &&
|
||||||
git-branch -m q r/q'
|
git-branch -m q r/q'
|
||||||
|
|
||||||
|
git-repo-config branch.s/s.dummy Hello
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'git branch -m s/s s should work when s/t is deleted' \
|
'git branch -m s/s s should work when s/t is deleted' \
|
||||||
'git-branch -l s/s &&
|
'git-branch -l s/s &&
|
||||||
@ -104,6 +106,10 @@ test_expect_success \
|
|||||||
git-branch -m s/s s &&
|
git-branch -m s/s s &&
|
||||||
test -f .git/logs/refs/heads/s'
|
test -f .git/logs/refs/heads/s'
|
||||||
|
|
||||||
|
test_expect_success 'config information was renamed, too' \
|
||||||
|
"test $(git-repo-config branch.s.dummy) = Hello &&
|
||||||
|
! git-repo-config branch.s/s/dummy"
|
||||||
|
|
||||||
test_expect_failure \
|
test_expect_failure \
|
||||||
'git-branch -m u v should fail when the reflog for u is a symlink' \
|
'git-branch -m u v should fail when the reflog for u is a symlink' \
|
||||||
'git-branch -l u &&
|
'git-branch -l u &&
|
||||||
|
@ -208,8 +208,9 @@ test_done () {
|
|||||||
# t/ subdirectory and are run in trash subdirectory.
|
# t/ subdirectory and are run in trash subdirectory.
|
||||||
PATH=$(pwd)/..:$PATH
|
PATH=$(pwd)/..:$PATH
|
||||||
GIT_EXEC_PATH=$(pwd)/..
|
GIT_EXEC_PATH=$(pwd)/..
|
||||||
|
GIT_TEMPLATE_DIR=$(pwd)/../templates/blt
|
||||||
HOME=$(pwd)/trash
|
HOME=$(pwd)/trash
|
||||||
export PATH GIT_EXEC_PATH HOME
|
export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR HOME
|
||||||
|
|
||||||
GITPERLLIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git
|
GITPERLLIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git
|
||||||
export GITPERLLIB
|
export GITPERLLIB
|
||||||
|
Loading…
Reference in New Issue
Block a user