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"
|
||||
renames = true
|
||||
|
||||
[branch "devel"]
|
||||
remote = origin
|
||||
merge = refs/heads/devel
|
||||
|
||||
|
||||
Variables
|
||||
~~~~~~~~~
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
git-merge-file(1)
|
||||
============
|
||||
=================
|
||||
|
||||
NAME
|
||||
----
|
||||
git-merge-file - threeway file merge
|
||||
git-merge-file - three-way file merge
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
|
@ -10,7 +10,7 @@ SYNOPSIS
|
||||
[verse]
|
||||
'git-show-branch' [--all] [--heads] [--tags] [--topo-order] [--current]
|
||||
[--more=<n> | --list | --independent | --merge-base]
|
||||
[--no-name | --sha1-name] [<rev> | <glob>]...
|
||||
[--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -86,6 +86,14 @@ OPTIONS
|
||||
of "master"), name them with the unique prefix of their
|
||||
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
|
||||
are mutually exclusive.
|
||||
|
||||
|
@ -15,6 +15,7 @@ SYNOPSIS
|
||||
[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
|
||||
[ -s start_chg ] [ -m ] [ -r ] [ -M regex ]
|
||||
[ -I <ignorefile_name> ] [ -A <author_file> ]
|
||||
[ -P <path_from_trunk> ]
|
||||
<SVN_repository_URL> [ <path> ]
|
||||
|
||||
|
||||
@ -103,9 +104,17 @@ repository without -A.
|
||||
|
||||
-l <max_rev>::
|
||||
Specify a maximum revision number to pull.
|
||||
+
|
||||
Formerly, this option controlled how many revisions to pull,
|
||||
due to SVN memory leaks. (These have been worked around.)
|
||||
|
||||
Formerly, this option controlled how many revisions to pull,
|
||||
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::
|
||||
Verbosity: let 'svnimport' report what it is doing.
|
||||
|
@ -4,7 +4,7 @@ Use of index and Racy git problem
|
||||
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
|
||||
paths and their object names and serves as a staging area to
|
||||
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
|
||||
diff` (or its low level implementation, `git diff-files`) or
|
||||
`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
|
||||
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
|
||||
information obtained from the filesystem via `lstat(2)` system
|
||||
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
|
||||
`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
|
||||
stat information" fields do not match, git can tell that the
|
||||
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
|
||||
cached stat information. Consider this sequence:
|
||||
|
||||
: modify '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
|
||||
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`
|
||||
timestamp does not change, after this sequence, the cached stat
|
||||
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
|
||||
are unmodified even though they actually are. This is called
|
||||
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
|
||||
index contains. And no matter how quick the modification that
|
||||
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
|
||||
racily clean are limited to the ones that have the same
|
||||
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.
|
||||
The latter makes sure that the cached stat information for `foo`
|
||||
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
|
||||
expensive `ce_modified_check_fs()`.
|
||||
|
||||
@ -155,17 +157,16 @@ of the cached stat information.
|
||||
Avoiding runtime penalty
|
||||
------------------------
|
||||
|
||||
In order to avoid the above runtime penalty, the recent "master"
|
||||
branch (post 1.4.2) has a code that makes sure the index file
|
||||
gets timestamp newer than the youngest files in the index when
|
||||
In order to avoid the above runtime penalty, post 1.4.2 git used
|
||||
to have a code that made sure the index file
|
||||
got timestamp newer than the youngest files in the index when
|
||||
there are many young files with the same timestamp as the
|
||||
resulting index file would otherwise would have by waiting
|
||||
before finishing writing the index file out.
|
||||
|
||||
I suspect that in practice the situation where many paths in the
|
||||
index are all racily clean is quite rare. The only code paths
|
||||
that can record recent timestamp for large number of paths I
|
||||
know of are:
|
||||
I suspected that in practice the situation where many paths in the
|
||||
index are all racily clean was quite rare. The only code paths
|
||||
that can record recent timestamp for large number of paths are:
|
||||
|
||||
. 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
|
||||
the resulting index.
|
||||
|
||||
So in summary I think we should not worry about avoiding the
|
||||
runtime penalty and get rid of the "wait before finishing
|
||||
writing" code out.
|
||||
Based on this discussion, the current code does not use the
|
||||
"workaround" to avoid the runtime penalty that does not exist in
|
||||
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
|
||||
$(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
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^
|
||||
test-delta$X: test-delta.o diff-delta.o patch-delta.o $(GITLIBS)
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
|
||||
|
||||
test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
|
||||
$(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) &&
|
||||
!(revs->max_age != -1 && commit->date < revs->max_age))
|
||||
pass_blame(sb, suspect, opt);
|
||||
else {
|
||||
commit->object.flags |= UNINTERESTING;
|
||||
if (commit->object.parsed)
|
||||
mark_parents_uninteresting(commit);
|
||||
}
|
||||
|
||||
/* Take responsibility for the remaining entries */
|
||||
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("filename %s\n", suspect->path);
|
||||
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)
|
||||
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);
|
||||
for (cnt = 0; cnt < ent->num_lines; cnt++) {
|
||||
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)
|
||||
printf("\t(%10s\t%10s\t%d)", ci.author,
|
||||
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;
|
||||
DIR *dir;
|
||||
|
||||
if (!template_dir)
|
||||
template_dir = DEFAULT_GIT_TEMPLATE_DIR;
|
||||
if (!template_dir) {
|
||||
template_dir = getenv("GIT_TEMPLATE_DIR");
|
||||
if (!template_dir)
|
||||
template_dir = DEFAULT_GIT_TEMPLATE_DIR;
|
||||
}
|
||||
strcpy(template_path, template_dir);
|
||||
template_len = strlen(template_path);
|
||||
if (template_path[template_len-1] != '/') {
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <regex.h>
|
||||
|
||||
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 regex_t *key_regexp;
|
||||
@ -148,6 +148,18 @@ int cmd_repo_config(int argc, const char **argv, const char *prefix)
|
||||
} else {
|
||||
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
|
||||
break;
|
||||
argc--;
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "builtin.h"
|
||||
|
||||
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_alloc;
|
||||
@ -17,6 +17,8 @@ static const char **default_arg;
|
||||
#define REV_SHIFT 2
|
||||
#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)
|
||||
{
|
||||
while (list) {
|
||||
@ -570,6 +572,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
int head_at = -1;
|
||||
int topics = 0;
|
||||
int dense = 1;
|
||||
int reflog = 0;
|
||||
|
||||
git_config(git_show_branch_config);
|
||||
|
||||
@ -615,6 +618,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
dense = 0;
|
||||
else if (!strcmp(arg, "--date-order"))
|
||||
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
|
||||
usage(show_branch_usage);
|
||||
ac--; av++;
|
||||
@ -622,7 +634,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
ac--; av++;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* If nothing is specified, show all branches by default */
|
||||
@ -631,9 +643,22 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
|
||||
if (all_heads + all_tags)
|
||||
snarf_refs(all_heads, all_tags);
|
||||
while (0 < ac) {
|
||||
append_one_rev(*av);
|
||||
ac--; av++;
|
||||
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) {
|
||||
append_one_rev(*av);
|
||||
ac--; av++;
|
||||
}
|
||||
}
|
||||
|
||||
head_p = resolve_ref("HEAD", head_sha1, 1, NULL);
|
||||
|
@ -2,13 +2,23 @@
|
||||
#include "refs.h"
|
||||
#include "object.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,
|
||||
found_match = 0, verify = 0, quiet = 0, hash_only = 0, abbrev = 0;
|
||||
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)
|
||||
{
|
||||
struct object *obj;
|
||||
@ -57,11 +67,7 @@ match:
|
||||
if (quiet)
|
||||
return 0;
|
||||
|
||||
hex = find_unique_abbrev(sha1, abbrev);
|
||||
if (hash_only)
|
||||
printf("%s\n", hex);
|
||||
else
|
||||
printf("%s %s\n", hex, refname);
|
||||
show_one(refname, sha1);
|
||||
|
||||
if (!deref_tags)
|
||||
return 0;
|
||||
@ -86,6 +92,60 @@ match:
|
||||
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 i;
|
||||
@ -121,13 +181,13 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
|
||||
if (!strncmp(arg, "--hash=", 7) ||
|
||||
(!strncmp(arg, "--abbrev", 8) &&
|
||||
(arg[8] == '=' || arg[8] == '\0'))) {
|
||||
if (arg[3] != 'h' && !arg[8])
|
||||
if (arg[2] != 'h' && !arg[8])
|
||||
/* --abbrev only */
|
||||
abbrev = DEFAULT_ABBREV;
|
||||
else {
|
||||
/* --hash= or --abbrev= */
|
||||
char *end;
|
||||
if (arg[3] == 'h') {
|
||||
if (arg[2] == 'h') {
|
||||
hash_only = 1;
|
||||
arg += 7;
|
||||
}
|
||||
@ -153,8 +213,31 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
|
||||
heads_only = 1;
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
head_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 *);
|
||||
|
||||
extern int setup_ident(void);
|
||||
extern void ignore_missing_committer_name();
|
||||
extern const char *git_author_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_set(const char *, const char *);
|
||||
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);
|
||||
|
||||
#define MAX_GITNAME (1000)
|
||||
|
64
config.c
64
config.c
@ -746,4 +746,68 @@ out_free:
|
||||
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 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 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 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
|
||||
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 () {
|
||||
head_="$1"
|
||||
@ -242,7 +242,7 @@ esac
|
||||
reflist=$(get_remote_refs_for_fetch "$@")
|
||||
if test "$tags"
|
||||
then
|
||||
taglist=`IFS=" " &&
|
||||
taglist=`IFS=' ' &&
|
||||
echo "$ls_remote_result" |
|
||||
while read sha1 name
|
||||
do
|
||||
@ -438,17 +438,11 @@ case "$no_tags$tags" in
|
||||
*:refs/*)
|
||||
# effective only when we are following remote branch
|
||||
# using local tracking branch.
|
||||
taglist=$(IFS=" " &&
|
||||
taglist=$(IFS=' ' &&
|
||||
echo "$ls_remote_result" |
|
||||
sed -n -e 's|^\('"$_x40"'\) \(refs/tags/.*\)^{}$|\1 \2|p' \
|
||||
-e 's|^\('"$_x40"'\) \(refs/tags/.*\)$|\1 \2|p' |
|
||||
git-show-ref --exclude-existing=refs/tags/ |
|
||||
while read sha1 name
|
||||
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
|
||||
echo >&2 "Auto-following $name"
|
||||
echo ".${name}:${name}"
|
||||
|
@ -94,7 +94,7 @@ while read sha1 path
|
||||
do
|
||||
case "$sha1" in
|
||||
failed)
|
||||
die "Failed to find remote refs"
|
||||
exit 1 ;;
|
||||
esac
|
||||
case "$path" in
|
||||
refs/heads/*)
|
||||
|
@ -111,16 +111,14 @@ expand_refs_wildcard () {
|
||||
local_force=
|
||||
test "z$lref" = "z$ref" || local_force='+'
|
||||
echo "$ls_remote_result" |
|
||||
sed -e '/\^{}$/d' |
|
||||
(
|
||||
IFS=' '
|
||||
while read sha1 name
|
||||
do
|
||||
# ignore the ones that do not start with $from
|
||||
mapped=${name#"$from"}
|
||||
if test "z$name" != "z${name%'^{}'}" ||
|
||||
test "z$name" = "z$mapped"
|
||||
then
|
||||
continue
|
||||
fi
|
||||
test "z$name" = "z$mapped" && continue
|
||||
echo "${local_force}${name}:${to}${mapped}"
|
||||
done
|
||||
)
|
||||
|
@ -154,7 +154,7 @@ sub find_conflict {
|
||||
sub merge {
|
||||
my ($name, $path) = @_;
|
||||
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))) {
|
||||
my $in;
|
||||
open $in, "<$rr_dir/$name/thisimage" or
|
||||
|
@ -434,6 +434,7 @@ my %actions = (
|
||||
"tags" => \&git_tags,
|
||||
"tree" => \&git_tree,
|
||||
"snapshot" => \&git_snapshot,
|
||||
"object" => \&git_object,
|
||||
# those below don't need $project
|
||||
"opml" => \&git_opml,
|
||||
"project_list" => \&git_project_list,
|
||||
@ -827,14 +828,12 @@ sub format_log_line_html {
|
||||
my $line = shift;
|
||||
|
||||
$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;
|
||||
if (git_get_type($hash_text) eq "commit") {
|
||||
my $link =
|
||||
$cgi->a({-href => href(action=>"commit", hash=>$hash_text),
|
||||
-class => "text"}, $hash_text);
|
||||
$line =~ s/$hash_text/$link/;
|
||||
}
|
||||
my $link =
|
||||
$cgi->a({-href => href(action=>"object", hash=>$hash_text),
|
||||
-class => "text"}, $hash_text);
|
||||
$line =~ s/$hash_text/$link/;
|
||||
}
|
||||
return $line;
|
||||
}
|
||||
@ -856,7 +855,8 @@ sub format_ref_marker {
|
||||
$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
|
||||
sub git_print_tree_entry {
|
||||
my ($t, $basedir, $hash_base, $have_blame) = @_;
|
||||
|
||||
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 mode of the entry, list is the name of the entry, an href,
|
||||
@ -2005,16 +2066,31 @@ sub git_print_tree_entry {
|
||||
print "<td class=\"list\">" .
|
||||
$cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
|
||||
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 $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
|
||||
file_name=>"$basedir$t->{'name'}", %base_key)},
|
||||
"blob");
|
||||
file_name=>"$basedir$t->{'name'}", %base_key)},
|
||||
"blob");
|
||||
if ($have_blame) {
|
||||
print " | " .
|
||||
$cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'},
|
||||
file_name=>"$basedir$t->{'name'}", %base_key)},
|
||||
"blame");
|
||||
file_name=>"$basedir$t->{'name'}", %base_key)},
|
||||
"blame");
|
||||
}
|
||||
if (defined $hash_base) {
|
||||
print " | " .
|
||||
@ -2036,8 +2112,8 @@ sub git_print_tree_entry {
|
||||
print "</td>\n";
|
||||
print "<td class=\"link\">";
|
||||
print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
|
||||
file_name=>"$basedir$t->{'name'}", %base_key)},
|
||||
"tree");
|
||||
file_name=>"$basedir$t->{'name'}", %base_key)},
|
||||
"tree");
|
||||
if (defined $hash_base) {
|
||||
print " | " .
|
||||
$cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
|
||||
@ -3414,8 +3490,7 @@ sub git_snapshot {
|
||||
my $filename = basename($project) . "-$hash.tar.$suffix";
|
||||
|
||||
print $cgi->header(
|
||||
-type => 'application/x-tar',
|
||||
-content_encoding => $ctype,
|
||||
-type => "application/$ctype",
|
||||
-content_disposition => 'inline; filename="' . "$filename" . '"',
|
||||
-status => '200 OK');
|
||||
|
||||
@ -3497,15 +3572,46 @@ sub git_commit {
|
||||
my %ad = parse_date($co{'author_epoch'}, $co{'author_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) {
|
||||
$parent = "--root";
|
||||
}
|
||||
open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id",
|
||||
@diff_opts, $parent, $hash, "--"
|
||||
or die_error(undef, "Open git-diff-tree failed");
|
||||
my @difftree = map { chomp; $_ } <$fd>;
|
||||
close $fd or die_error(undef, "Reading git-diff-tree failed");
|
||||
my @difftree;
|
||||
if (@$parents <= 1) {
|
||||
# difftree output is not printed for merges
|
||||
open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id",
|
||||
@diff_opts, $parent, $hash, "--"
|
||||
or die_error(undef, "Open git-diff-tree failed");
|
||||
@difftree = map { chomp; $_ } <$fd>;
|
||||
close $fd or die_error(undef, "Reading git-diff-tree failed");
|
||||
}
|
||||
|
||||
# non-textual hash id's can be cached
|
||||
my $expires;
|
||||
@ -3517,16 +3623,10 @@ sub git_commit {
|
||||
|
||||
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_print_page_nav('commit', '',
|
||||
$hash, $co{'tree'}, $hash,
|
||||
join (' | ', @views_nav));
|
||||
$formats_nav);
|
||||
|
||||
if (defined $co{'parent'}) {
|
||||
git_print_header_div('commitdiff', esc_html($co{'title'}) . $ref, $hash);
|
||||
@ -3567,7 +3667,7 @@ sub git_commit {
|
||||
}
|
||||
print "</td>" .
|
||||
"</tr>\n";
|
||||
my $parents = $co{'parents'};
|
||||
|
||||
foreach my $par (@$parents) {
|
||||
print "<tr>" .
|
||||
"<td>parent</td>" .
|
||||
@ -3589,11 +3689,61 @@ sub git_commit {
|
||||
git_print_log($co{'comment'});
|
||||
print "</div>\n";
|
||||
|
||||
git_difftree_body(\@difftree, $hash, $parent);
|
||||
if (@$parents <= 1) {
|
||||
# do not output difftree/whatchanged for merges
|
||||
git_difftree_body(\@difftree, $hash, $parent);
|
||||
}
|
||||
|
||||
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 {
|
||||
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"),
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "git-compat-util.h"
|
||||
#include "delta.h"
|
||||
|
||||
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 */
|
||||
size = get_delta_hdr_size(&data, top);
|
||||
dst_buf = malloc(size + 1);
|
||||
if (!dst_buf)
|
||||
return NULL;
|
||||
dst_buf = xmalloc(size + 1);
|
||||
dst_buf[size] = 0;
|
||||
|
||||
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 ||
|
||||
cp_off + cp_size > src_size ||
|
||||
cp_size > size)
|
||||
goto bad;
|
||||
break;
|
||||
memcpy(out, (char *) src_buf + cp_off, cp_size);
|
||||
out += cp_size;
|
||||
size -= cp_size;
|
||||
} else if (cmd) {
|
||||
if (cmd > size)
|
||||
goto bad;
|
||||
break;
|
||||
memcpy(out, data, cmd);
|
||||
out += 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
|
||||
* encountering them (might be data corruption).
|
||||
*/
|
||||
error("unexpected delta opcode 0");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
if (data != top || size != 0) {
|
||||
error("delta replay has gone wild");
|
||||
bad:
|
||||
free(dst_buf);
|
||||
return NULL;
|
||||
|
@ -72,7 +72,7 @@ static void safe_read(int fd, void *buffer, unsigned size)
|
||||
if (ret < 0)
|
||||
die("read error (%s)", strerror(errno));
|
||||
if (!ret)
|
||||
die("unexpected EOF");
|
||||
die("The remote end hung up unexpectedly");
|
||||
n += ret;
|
||||
}
|
||||
}
|
||||
|
@ -358,7 +358,7 @@ int add_file_to_index(const char *path, int verbose)
|
||||
|
||||
if (index_path(ce->sha1, path, &st, 1))
|
||||
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);
|
||||
if (verbose)
|
||||
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)));
|
||||
if (pos >= 0) {
|
||||
retval = -1;
|
||||
if (ok_to_replace)
|
||||
if (!ok_to_replace)
|
||||
break;
|
||||
remove_cache_entry_at(pos);
|
||||
continue;
|
||||
@ -609,7 +609,7 @@ int add_cache_entry(struct cache_entry *ce, int option)
|
||||
if (!skip_df_check &&
|
||||
check_file_directory_conflict(ce, pos, 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 = -pos-1;
|
||||
}
|
||||
|
@ -420,6 +420,8 @@ int main(int argc, char **argv)
|
||||
die("'%s': unable to chdir or not a git archive", dir);
|
||||
|
||||
setup_ident();
|
||||
/* don't die if gecos is empty */
|
||||
ignore_missing_committer_name();
|
||||
git_config(receive_pack_config);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
rollback:
|
||||
|
@ -272,4 +272,13 @@ test_expect_success \
|
||||
wc -l) &&
|
||||
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
|
||||
|
@ -343,5 +343,53 @@ EOF
|
||||
|
||||
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
|
||||
|
||||
|
@ -94,6 +94,8 @@ test_expect_failure \
|
||||
git-branch r &&
|
||||
git-branch -m q r/q'
|
||||
|
||||
git-repo-config branch.s/s.dummy Hello
|
||||
|
||||
test_expect_success \
|
||||
'git branch -m s/s s should work when s/t is deleted' \
|
||||
'git-branch -l s/s &&
|
||||
@ -104,6 +106,10 @@ test_expect_success \
|
||||
git-branch -m s/s 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 \
|
||||
'git-branch -m u v should fail when the reflog for u is a symlink' \
|
||||
'git-branch -l u &&
|
||||
|
@ -208,8 +208,9 @@ test_done () {
|
||||
# t/ subdirectory and are run in trash subdirectory.
|
||||
PATH=$(pwd)/..:$PATH
|
||||
GIT_EXEC_PATH=$(pwd)/..
|
||||
GIT_TEMPLATE_DIR=$(pwd)/../templates/blt
|
||||
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
|
||||
export GITPERLLIB
|
||||
|
Loading…
Reference in New Issue
Block a user