mirror of
https://github.com/git-for-windows/git.git
synced 2026-04-22 02:54:28 -05:00
Merge branch 'lt/refs' into next
* lt/refs: wt-status: use simplified resolve_ref to find current branch Fix t1400-update-ref test minimally Enable the packed refs file format Make ref resolution saner Add support for negative refs Start handling references internally as a sorted in-memory list gitweb fix validating pg (page) parameter git-repack(1): document --window and --depth git-apply(1): document --unidiff-zero gitweb: fix warnings in PATH_INFO code and add export_ok/strict_export upload-archive: monitor child communication even more carefully.
This commit is contained in:
@@ -95,6 +95,16 @@ OPTIONS
|
||||
context exist they all must match. By default no context is
|
||||
ever ignored.
|
||||
|
||||
--unidiff-zero::
|
||||
By default, gitlink:git-apply[1] expects that the patch being
|
||||
applied is a unified diff with at least one line of context.
|
||||
This provides good safety measures, but breaks down when
|
||||
applying a diff generated with --unified=0. To bypass these
|
||||
checks use '--unidiff-zero'.
|
||||
+
|
||||
Note, for the reasons stated above usage of context-free patches are
|
||||
discouraged.
|
||||
|
||||
--apply::
|
||||
If you use any of the options marked "Turns off
|
||||
'apply'" above, gitlink:git-apply[1] reads and outputs the
|
||||
|
||||
@@ -9,7 +9,7 @@ objects into pack files.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-repack' [-a] [-d] [-f] [-l] [-n] [-q]
|
||||
'git-repack' [-a] [-d] [-f] [-l] [-n] [-q] [--window=N] [--depth=N]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -56,6 +56,16 @@ OPTIONS
|
||||
Do not update the server information with
|
||||
`git update-server-info`.
|
||||
|
||||
--window=[N], --depth=[N]::
|
||||
These two options affects how the objects contained in the pack are
|
||||
stored using delta compression. The objects are first internally
|
||||
sorted by type, size and optionally names and compared against the
|
||||
other objects within `--window` to see if using delta compression saves
|
||||
space. `--depth` limits the maximum delta depth; making it too deep
|
||||
affects the performance on the unpacker side, because delta data needs
|
||||
to be applied that many times to get to the necessary object.
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org>
|
||||
|
||||
3
Makefile
3
Makefile
@@ -314,7 +314,8 @@ BUILTIN_OBJS = \
|
||||
builtin-verify-pack.o \
|
||||
builtin-write-tree.o \
|
||||
builtin-zip-tree.o \
|
||||
builtin-show-ref.o
|
||||
builtin-show-ref.o \
|
||||
builtin-pack-refs.o
|
||||
|
||||
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
|
||||
EXTLIBS = -lz
|
||||
|
||||
@@ -249,7 +249,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
|
||||
FILE *in = stdin;
|
||||
const char *sep = "";
|
||||
unsigned char head_sha1[20];
|
||||
const char *head, *current_branch;
|
||||
const char *current_branch;
|
||||
|
||||
git_config(fmt_merge_msg_config);
|
||||
|
||||
@@ -277,10 +277,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
|
||||
usage(fmt_merge_msg_usage);
|
||||
|
||||
/* get current branch */
|
||||
head = xstrdup(git_path("HEAD"));
|
||||
current_branch = resolve_ref(head, head_sha1, 1);
|
||||
current_branch += strlen(head) - 4;
|
||||
free((char *)head);
|
||||
current_branch = resolve_ref("HEAD", head_sha1, 1);
|
||||
if (!strncmp(current_branch, "refs/heads/", 11))
|
||||
current_branch += 11;
|
||||
|
||||
|
||||
@@ -218,8 +218,8 @@ static void create_default_files(const char *git_dir, const char *template_path)
|
||||
* branch, if it does not exist yet.
|
||||
*/
|
||||
strcpy(path + len, "HEAD");
|
||||
if (read_ref(path, sha1) < 0) {
|
||||
if (create_symref(path, "refs/heads/master") < 0)
|
||||
if (read_ref("HEAD", sha1) < 0) {
|
||||
if (create_symref("HEAD", "refs/heads/master") < 0)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
41
builtin-pack-refs.c
Normal file
41
builtin-pack-refs.c
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
|
||||
static FILE *refs_file;
|
||||
static const char *result_path, *lock_path;
|
||||
|
||||
static void remove_lock_file(void)
|
||||
{
|
||||
if (lock_path)
|
||||
unlink(lock_path);
|
||||
}
|
||||
|
||||
static int handle_one_ref(const char *path, const unsigned char *sha1)
|
||||
{
|
||||
fprintf(refs_file, "%s %s\n", sha1_to_hex(sha1), path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_pack_refs(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int fd;
|
||||
|
||||
result_path = xstrdup(git_path("packed-refs"));
|
||||
lock_path = xstrdup(mkpath("%s.lock", result_path));
|
||||
|
||||
fd = open(lock_path, O_CREAT | O_EXCL | O_WRONLY, 0666);
|
||||
if (fd < 0)
|
||||
die("unable to create new ref-pack file (%s)", strerror(errno));
|
||||
atexit(remove_lock_file);
|
||||
|
||||
refs_file = fdopen(fd, "w");
|
||||
if (!refs_file)
|
||||
die("unable to create ref-pack file structure (%s)", strerror(errno));
|
||||
for_each_ref(handle_one_ref);
|
||||
fsync(fd);
|
||||
fclose(refs_file);
|
||||
if (rename(lock_path, result_path) < 0)
|
||||
die("unable to overwrite old ref-pack file (%s)", strerror(errno));
|
||||
lock_path = NULL;
|
||||
return 0;
|
||||
}
|
||||
@@ -437,21 +437,13 @@ static void snarf_refs(int head, int tag)
|
||||
}
|
||||
}
|
||||
|
||||
static int rev_is_head(char *head_path, int headlen, char *name,
|
||||
static int rev_is_head(char *head, int headlen, char *name,
|
||||
unsigned char *head_sha1, unsigned char *sha1)
|
||||
{
|
||||
int namelen;
|
||||
if ((!head_path[0]) ||
|
||||
if ((!head[0]) ||
|
||||
(head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
|
||||
return 0;
|
||||
namelen = strlen(name);
|
||||
if ((headlen < namelen) ||
|
||||
memcmp(head_path + headlen - namelen, name, namelen))
|
||||
return 0;
|
||||
if (headlen == namelen ||
|
||||
head_path[headlen - namelen - 1] == '/')
|
||||
return 1;
|
||||
return 0;
|
||||
return !strcmp(head, name);
|
||||
}
|
||||
|
||||
static int show_merge_base(struct commit_list *seen, int num_rev)
|
||||
@@ -559,9 +551,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
int all_heads = 0, all_tags = 0;
|
||||
int all_mask, all_revs;
|
||||
int lifo = 1;
|
||||
char head_path[128];
|
||||
const char *head_path_p;
|
||||
int head_path_len;
|
||||
char head[128];
|
||||
const char *head_p;
|
||||
int head_len;
|
||||
unsigned char head_sha1[20];
|
||||
int merge_base = 0;
|
||||
int independent = 0;
|
||||
@@ -638,31 +630,31 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
ac--; av++;
|
||||
}
|
||||
|
||||
head_path_p = resolve_ref(git_path("HEAD"), head_sha1, 1);
|
||||
if (head_path_p) {
|
||||
head_path_len = strlen(head_path_p);
|
||||
memcpy(head_path, head_path_p, head_path_len + 1);
|
||||
head_p = resolve_ref("HEAD", head_sha1, 1);
|
||||
if (head_p) {
|
||||
head_len = strlen(head_p);
|
||||
memcpy(head, head_p, head_len + 1);
|
||||
}
|
||||
else {
|
||||
head_path_len = 0;
|
||||
head_path[0] = 0;
|
||||
head_len = 0;
|
||||
head[0] = 0;
|
||||
}
|
||||
|
||||
if (with_current_branch && head_path_p) {
|
||||
if (with_current_branch && head_p) {
|
||||
int has_head = 0;
|
||||
for (i = 0; !has_head && i < ref_name_cnt; i++) {
|
||||
/* We are only interested in adding the branch
|
||||
* HEAD points at.
|
||||
*/
|
||||
if (rev_is_head(head_path,
|
||||
head_path_len,
|
||||
if (rev_is_head(head,
|
||||
head_len,
|
||||
ref_name[i],
|
||||
head_sha1, NULL))
|
||||
has_head++;
|
||||
}
|
||||
if (!has_head) {
|
||||
int pfxlen = strlen(git_path("refs/heads/"));
|
||||
append_one_rev(head_path + pfxlen);
|
||||
int pfxlen = strlen("refs/heads/");
|
||||
append_one_rev(head + pfxlen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -713,8 +705,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
if (1 < num_rev || extra < 0) {
|
||||
for (i = 0; i < num_rev; i++) {
|
||||
int j;
|
||||
int is_head = rev_is_head(head_path,
|
||||
head_path_len,
|
||||
int is_head = rev_is_head(head,
|
||||
head_len,
|
||||
ref_name[i],
|
||||
head_sha1,
|
||||
rev[i]->object.sha1);
|
||||
|
||||
@@ -7,15 +7,11 @@ static const char git_symbolic_ref_usage[] =
|
||||
static void check_symref(const char *HEAD)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
const char *git_HEAD = xstrdup(git_path("%s", HEAD));
|
||||
const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 0);
|
||||
if (git_refs_heads_master) {
|
||||
/* we want to strip the .git/ part */
|
||||
int pfxlen = strlen(git_HEAD) - strlen(HEAD);
|
||||
puts(git_refs_heads_master + pfxlen);
|
||||
}
|
||||
else
|
||||
const char *refs_heads_master = resolve_ref("HEAD", sha1, 0);
|
||||
|
||||
if (!refs_heads_master)
|
||||
die("No such ref: %s", HEAD);
|
||||
puts(refs_heads_master);
|
||||
}
|
||||
|
||||
int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
|
||||
@@ -26,7 +22,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
|
||||
check_symref(argv[1]);
|
||||
break;
|
||||
case 3:
|
||||
create_symref(xstrdup(git_path("%s", argv[1])), argv[2]);
|
||||
create_symref(argv[1], argv[2]);
|
||||
break;
|
||||
default:
|
||||
usage(git_symbolic_ref_usage);
|
||||
|
||||
@@ -160,7 +160,8 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
|
||||
if (pfd[1].revents & POLLIN)
|
||||
/* Status stream ready */
|
||||
process_input(pfd[1].fd, 2);
|
||||
if ((pfd[0].revents | pfd[1].revents) == POLLIN)
|
||||
/* Always finish to read data when available */
|
||||
if ((pfd[0].revents | pfd[1].revents) & POLLIN)
|
||||
continue;
|
||||
|
||||
if (waitpid(writer, &status, 0) < 0)
|
||||
|
||||
@@ -65,5 +65,6 @@ extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_verify_pack(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_show_ref(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_pack_refs(int argc, const char **argv, const char *prefix);
|
||||
|
||||
#endif
|
||||
|
||||
4
cache.h
4
cache.h
@@ -287,8 +287,8 @@ extern int get_sha1_hex(const char *hex, unsigned char *sha1);
|
||||
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
|
||||
extern int read_ref(const char *filename, unsigned char *sha1);
|
||||
extern const char *resolve_ref(const char *path, unsigned char *sha1, int);
|
||||
extern int create_symref(const char *git_HEAD, const char *refs_heads_master);
|
||||
extern int validate_symref(const char *git_HEAD);
|
||||
extern int create_symref(const char *ref, const char *refs_heads_master);
|
||||
extern int validate_symref(const char *ref);
|
||||
|
||||
extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
|
||||
extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
|
||||
|
||||
1
git.c
1
git.c
@@ -271,6 +271,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
||||
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
||||
{ "verify-pack", cmd_verify_pack },
|
||||
{ "show-ref", cmd_show_ref, RUN_SETUP },
|
||||
{ "pack-refs", cmd_pack_refs, RUN_SETUP },
|
||||
};
|
||||
int i;
|
||||
|
||||
|
||||
@@ -189,9 +189,6 @@ do $GITWEB_CONFIG if -e $GITWEB_CONFIG;
|
||||
# version of the core git binary
|
||||
our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
|
||||
|
||||
# path to the current git repository
|
||||
our $git_dir;
|
||||
|
||||
$projects_list ||= $projectroot;
|
||||
|
||||
# ======================================================================
|
||||
@@ -259,7 +256,7 @@ if (defined $hash_parent_base) {
|
||||
|
||||
our $page = $cgi->param('pg');
|
||||
if (defined $page) {
|
||||
if ($page =~ m/[^0-9]$/) {
|
||||
if ($page =~ m/[^0-9]/) {
|
||||
die_error(undef, "Invalid page parameter");
|
||||
}
|
||||
}
|
||||
@@ -273,30 +270,41 @@ if (defined $searchtext) {
|
||||
}
|
||||
|
||||
# now read PATH_INFO and use it as alternative to parameters
|
||||
our $path_info = $ENV{"PATH_INFO"};
|
||||
$path_info =~ s|^/||;
|
||||
$path_info =~ s|/$||;
|
||||
if (validate_input($path_info) && !defined $project) {
|
||||
sub evaluate_path_info {
|
||||
return if defined $project;
|
||||
my $path_info = $ENV{"PATH_INFO"};
|
||||
return if !$path_info;
|
||||
$path_info =~ s,(^/|/$),,gs;
|
||||
$path_info = validate_input($path_info);
|
||||
return if !$path_info;
|
||||
$project = $path_info;
|
||||
while ($project && !-e "$projectroot/$project/HEAD") {
|
||||
$project =~ s,/*[^/]*$,,;
|
||||
}
|
||||
if (defined $project) {
|
||||
$project = undef unless $project;
|
||||
if (!$project ||
|
||||
($export_ok && !-e "$projectroot/$project/$export_ok") ||
|
||||
($strict_export && !project_in_list($project))) {
|
||||
undef $project;
|
||||
return;
|
||||
}
|
||||
# do not change any parameters if an action is given using the query string
|
||||
return if $action;
|
||||
if ($path_info =~ m,^$project/([^/]+)/(.+)$,) {
|
||||
# we got "project.git/branch/filename"
|
||||
$action ||= "blob_plain";
|
||||
$hash_base ||= $1;
|
||||
$file_name ||= $2;
|
||||
$hash_base ||= validate_input($1);
|
||||
$file_name ||= validate_input($2);
|
||||
} elsif ($path_info =~ m,^$project/([^/]+)$,) {
|
||||
# we got "project.git/branch"
|
||||
$action ||= "shortlog";
|
||||
$hash ||= $1;
|
||||
$hash ||= validate_input($1);
|
||||
}
|
||||
}
|
||||
evaluate_path_info();
|
||||
|
||||
$git_dir = "$projectroot/$project";
|
||||
# path to the current git repository
|
||||
our $git_dir;
|
||||
$git_dir = "$projectroot/$project" if $project;
|
||||
|
||||
# dispatch
|
||||
my %actions = (
|
||||
|
||||
322
refs.c
322
refs.c
@@ -3,15 +3,158 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
struct ref_list {
|
||||
struct ref_list *next;
|
||||
unsigned char sha1[20];
|
||||
char name[FLEX_ARRAY];
|
||||
};
|
||||
|
||||
static const char *parse_ref_line(char *line, unsigned char *sha1)
|
||||
{
|
||||
/*
|
||||
* 42: the answer to everything.
|
||||
*
|
||||
* In this case, it happens to be the answer to
|
||||
* 40 (length of sha1 hex representation)
|
||||
* +1 (space in between hex and name)
|
||||
* +1 (newline at the end of the line)
|
||||
*/
|
||||
int len = strlen(line) - 42;
|
||||
|
||||
if (len <= 0)
|
||||
return NULL;
|
||||
if (get_sha1_hex(line, sha1) < 0)
|
||||
return NULL;
|
||||
if (!isspace(line[40]))
|
||||
return NULL;
|
||||
line += 41;
|
||||
if (isspace(*line))
|
||||
return NULL;
|
||||
if (line[len] != '\n')
|
||||
return NULL;
|
||||
line[len] = 0;
|
||||
return line;
|
||||
}
|
||||
|
||||
static struct ref_list *add_ref(const char *name, const unsigned char *sha1, struct ref_list *list)
|
||||
{
|
||||
int len;
|
||||
struct ref_list **p = &list, *entry;
|
||||
|
||||
/* Find the place to insert the ref into.. */
|
||||
while ((entry = *p) != NULL) {
|
||||
int cmp = strcmp(entry->name, name);
|
||||
if (cmp > 0)
|
||||
break;
|
||||
|
||||
/* Same as existing entry? */
|
||||
if (!cmp)
|
||||
return list;
|
||||
p = &entry->next;
|
||||
}
|
||||
|
||||
/* Allocate it and add it in.. */
|
||||
len = strlen(name) + 1;
|
||||
entry = xmalloc(sizeof(struct ref_list) + len);
|
||||
hashcpy(entry->sha1, sha1);
|
||||
memcpy(entry->name, name, len);
|
||||
entry->next = *p;
|
||||
*p = entry;
|
||||
return list;
|
||||
}
|
||||
|
||||
static struct ref_list *get_packed_refs(void)
|
||||
{
|
||||
static int did_refs = 0;
|
||||
static struct ref_list *refs = NULL;
|
||||
|
||||
if (!did_refs) {
|
||||
FILE *f = fopen(git_path("packed-refs"), "r");
|
||||
if (f) {
|
||||
struct ref_list *list = NULL;
|
||||
char refline[PATH_MAX];
|
||||
while (fgets(refline, sizeof(refline), f)) {
|
||||
unsigned char sha1[20];
|
||||
const char *name = parse_ref_line(refline, sha1);
|
||||
if (!name)
|
||||
continue;
|
||||
list = add_ref(name, sha1, list);
|
||||
}
|
||||
fclose(f);
|
||||
refs = list;
|
||||
}
|
||||
did_refs = 1;
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)
|
||||
{
|
||||
DIR *dir = opendir(git_path("%s", base));
|
||||
|
||||
if (dir) {
|
||||
struct dirent *de;
|
||||
int baselen = strlen(base);
|
||||
char *ref = xmalloc(baselen + 257);
|
||||
|
||||
memcpy(ref, base, baselen);
|
||||
if (baselen && base[baselen-1] != '/')
|
||||
ref[baselen++] = '/';
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
unsigned char sha1[20];
|
||||
struct stat st;
|
||||
int namelen;
|
||||
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
namelen = strlen(de->d_name);
|
||||
if (namelen > 255)
|
||||
continue;
|
||||
if (has_extension(de->d_name, ".lock"))
|
||||
continue;
|
||||
memcpy(ref + baselen, de->d_name, namelen+1);
|
||||
if (stat(git_path("%s", ref), &st) < 0)
|
||||
continue;
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
list = get_ref_dir(ref, list);
|
||||
continue;
|
||||
}
|
||||
if (read_ref(ref, sha1) < 0) {
|
||||
error("%s points nowhere!", ref);
|
||||
continue;
|
||||
}
|
||||
list = add_ref(ref, sha1, list);
|
||||
}
|
||||
free(ref);
|
||||
closedir(dir);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static struct ref_list *get_loose_refs(void)
|
||||
{
|
||||
static int did_refs = 0;
|
||||
static struct ref_list *refs = NULL;
|
||||
|
||||
if (!did_refs) {
|
||||
refs = get_ref_dir("refs", NULL);
|
||||
did_refs = 1;
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
/* We allow "recursive" symbolic refs. Only within reason, though */
|
||||
#define MAXDEPTH 5
|
||||
|
||||
const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
|
||||
const char *resolve_ref(const char *ref, unsigned char *sha1, int reading)
|
||||
{
|
||||
int depth = MAXDEPTH, len;
|
||||
char buffer[256];
|
||||
static char ref_buffer[256];
|
||||
|
||||
for (;;) {
|
||||
const char *path = git_path("%s", ref);
|
||||
struct stat st;
|
||||
char *buf;
|
||||
int fd;
|
||||
@@ -27,17 +170,27 @@ const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
|
||||
* reading.
|
||||
*/
|
||||
if (lstat(path, &st) < 0) {
|
||||
struct ref_list *list = get_packed_refs();
|
||||
while (list) {
|
||||
if (!strcmp(ref, list->name)) {
|
||||
hashcpy(sha1, list->sha1);
|
||||
return ref;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
if (reading || errno != ENOENT)
|
||||
return NULL;
|
||||
hashclr(sha1);
|
||||
return path;
|
||||
return ref;
|
||||
}
|
||||
|
||||
/* Follow "normalized" - ie "refs/.." symlinks by hand */
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
len = readlink(path, buffer, sizeof(buffer)-1);
|
||||
if (len >= 5 && !memcmp("refs/", buffer, 5)) {
|
||||
path = git_path("%.*s", len, buffer);
|
||||
buffer[len] = 0;
|
||||
strcpy(ref_buffer, buffer);
|
||||
ref = ref_buffer;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -62,19 +215,22 @@ const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
|
||||
while (len && isspace(*buf))
|
||||
buf++, len--;
|
||||
while (len && isspace(buf[len-1]))
|
||||
buf[--len] = 0;
|
||||
path = git_path("%.*s", len, buf);
|
||||
len--;
|
||||
buf[len] = 0;
|
||||
memcpy(ref_buffer, buf, len + 1);
|
||||
ref = ref_buffer;
|
||||
}
|
||||
if (len < 40 || get_sha1_hex(buffer, sha1))
|
||||
return NULL;
|
||||
return path;
|
||||
return ref;
|
||||
}
|
||||
|
||||
int create_symref(const char *git_HEAD, const char *refs_heads_master)
|
||||
int create_symref(const char *ref_target, const char *refs_heads_master)
|
||||
{
|
||||
const char *lockpath;
|
||||
char ref[1000];
|
||||
int fd, len, written;
|
||||
const char *git_HEAD = git_path("%s", ref_target);
|
||||
|
||||
#ifndef NO_SYMLINK_HEAD
|
||||
if (prefer_symlink_refs) {
|
||||
@@ -112,104 +268,91 @@ int create_symref(const char *git_HEAD, const char *refs_heads_master)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_ref(const char *filename, unsigned char *sha1)
|
||||
int read_ref(const char *ref, unsigned char *sha1)
|
||||
{
|
||||
if (resolve_ref(filename, sha1, 1))
|
||||
if (resolve_ref(ref, sha1, 1))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int do_for_each_ref(const char *base, int (*fn)(const char *path, const unsigned char *sha1), int trim)
|
||||
{
|
||||
int retval = 0;
|
||||
DIR *dir = opendir(git_path("%s", base));
|
||||
int retval;
|
||||
struct ref_list *packed = get_packed_refs();
|
||||
struct ref_list *loose = get_loose_refs();
|
||||
|
||||
if (dir) {
|
||||
struct dirent *de;
|
||||
int baselen = strlen(base);
|
||||
char *path = xmalloc(baselen + 257);
|
||||
|
||||
if (!strncmp(base, "./", 2)) {
|
||||
base += 2;
|
||||
baselen -= 2;
|
||||
while (packed && loose) {
|
||||
struct ref_list *entry;
|
||||
int cmp = strcmp(packed->name, loose->name);
|
||||
if (!cmp) {
|
||||
packed = packed->next;
|
||||
continue;
|
||||
}
|
||||
memcpy(path, base, baselen);
|
||||
if (baselen && base[baselen-1] != '/')
|
||||
path[baselen++] = '/';
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
unsigned char sha1[20];
|
||||
struct stat st;
|
||||
int namelen;
|
||||
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
namelen = strlen(de->d_name);
|
||||
if (namelen > 255)
|
||||
continue;
|
||||
if (has_extension(de->d_name, ".lock"))
|
||||
continue;
|
||||
memcpy(path + baselen, de->d_name, namelen+1);
|
||||
if (stat(git_path("%s", path), &st) < 0)
|
||||
continue;
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
retval = do_for_each_ref(path, fn, trim);
|
||||
if (retval)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (read_ref(git_path("%s", path), sha1) < 0) {
|
||||
error("%s points nowhere!", path);
|
||||
continue;
|
||||
}
|
||||
if (!has_sha1_file(sha1)) {
|
||||
error("%s does not point to a valid "
|
||||
"commit object!", path);
|
||||
continue;
|
||||
}
|
||||
retval = fn(path + trim, sha1);
|
||||
if (retval)
|
||||
break;
|
||||
if (cmp > 0) {
|
||||
entry = loose;
|
||||
loose = loose->next;
|
||||
} else {
|
||||
entry = packed;
|
||||
packed = packed->next;
|
||||
}
|
||||
free(path);
|
||||
closedir(dir);
|
||||
if (strncmp(base, entry->name, trim))
|
||||
continue;
|
||||
if (is_null_sha1(entry->sha1))
|
||||
continue;
|
||||
if (!has_sha1_file(entry->sha1)) {
|
||||
error("%s does not point to a valid object!", entry->name);
|
||||
continue;
|
||||
}
|
||||
retval = fn(entry->name + trim, entry->sha1);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
return retval;
|
||||
|
||||
packed = packed ? packed : loose;
|
||||
while (packed) {
|
||||
if (!strncmp(base, packed->name, trim)) {
|
||||
retval = fn(packed->name + trim, packed->sha1);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
packed = packed->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int head_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
if (!read_ref(git_path("HEAD"), sha1))
|
||||
if (!read_ref("HEAD", sha1))
|
||||
return fn("HEAD", sha1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
||||
{
|
||||
return do_for_each_ref("refs", fn, 0);
|
||||
return do_for_each_ref("refs/", fn, 0);
|
||||
}
|
||||
|
||||
int for_each_tag_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
||||
{
|
||||
return do_for_each_ref("refs/tags", fn, 10);
|
||||
return do_for_each_ref("refs/tags/", fn, 10);
|
||||
}
|
||||
|
||||
int for_each_branch_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
||||
{
|
||||
return do_for_each_ref("refs/heads", fn, 11);
|
||||
return do_for_each_ref("refs/heads/", fn, 11);
|
||||
}
|
||||
|
||||
int for_each_remote_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
||||
{
|
||||
return do_for_each_ref("refs/remotes", fn, 13);
|
||||
return do_for_each_ref("refs/remotes/", fn, 13);
|
||||
}
|
||||
|
||||
int get_ref_sha1(const char *ref, unsigned char *sha1)
|
||||
{
|
||||
if (check_ref_format(ref))
|
||||
return -1;
|
||||
return read_ref(git_path("refs/%s", ref), sha1);
|
||||
return read_ref(mkpath("refs/%s", ref), sha1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -267,22 +410,13 @@ int check_ref_format(const char *ref)
|
||||
static struct ref_lock *verify_lock(struct ref_lock *lock,
|
||||
const unsigned char *old_sha1, int mustexist)
|
||||
{
|
||||
char buf[40];
|
||||
int nr, fd = open(lock->ref_file, O_RDONLY);
|
||||
if (fd < 0 && (mustexist || errno != ENOENT)) {
|
||||
error("Can't verify ref %s", lock->ref_file);
|
||||
unlock_ref(lock);
|
||||
return NULL;
|
||||
}
|
||||
nr = read(fd, buf, 40);
|
||||
close(fd);
|
||||
if (nr != 40 || get_sha1_hex(buf, lock->old_sha1) < 0) {
|
||||
error("Can't verify ref %s", lock->ref_file);
|
||||
if (!resolve_ref(lock->ref_name, lock->old_sha1, mustexist)) {
|
||||
error("Can't verify ref %s", lock->ref_name);
|
||||
unlock_ref(lock);
|
||||
return NULL;
|
||||
}
|
||||
if (hashcmp(lock->old_sha1, old_sha1)) {
|
||||
error("Ref %s is at %s but expected %s", lock->ref_file,
|
||||
error("Ref %s is at %s but expected %s", lock->ref_name,
|
||||
sha1_to_hex(lock->old_sha1), sha1_to_hex(old_sha1));
|
||||
unlock_ref(lock);
|
||||
return NULL;
|
||||
@@ -290,36 +424,37 @@ static struct ref_lock *verify_lock(struct ref_lock *lock,
|
||||
return lock;
|
||||
}
|
||||
|
||||
static struct ref_lock *lock_ref_sha1_basic(const char *path,
|
||||
static struct ref_lock *lock_ref_sha1_basic(const char *ref,
|
||||
int plen,
|
||||
const unsigned char *old_sha1, int mustexist)
|
||||
{
|
||||
const char *orig_path = path;
|
||||
char *ref_file;
|
||||
const char *orig_ref = ref;
|
||||
struct ref_lock *lock;
|
||||
struct stat st;
|
||||
|
||||
lock = xcalloc(1, sizeof(struct ref_lock));
|
||||
lock->lock_fd = -1;
|
||||
|
||||
plen = strlen(path) - plen;
|
||||
path = resolve_ref(path, lock->old_sha1, mustexist);
|
||||
if (!path) {
|
||||
ref = resolve_ref(ref, lock->old_sha1, mustexist);
|
||||
if (!ref) {
|
||||
int last_errno = errno;
|
||||
error("unable to resolve reference %s: %s",
|
||||
orig_path, strerror(errno));
|
||||
orig_ref, strerror(errno));
|
||||
unlock_ref(lock);
|
||||
errno = last_errno;
|
||||
return NULL;
|
||||
}
|
||||
lock->lk = xcalloc(1, sizeof(struct lock_file));
|
||||
|
||||
lock->ref_file = xstrdup(path);
|
||||
lock->log_file = xstrdup(git_path("logs/%s", lock->ref_file + plen));
|
||||
lock->force_write = lstat(lock->ref_file, &st) && errno == ENOENT;
|
||||
lock->ref_name = xstrdup(ref);
|
||||
lock->log_file = xstrdup(git_path("logs/%s", ref));
|
||||
ref_file = git_path(ref);
|
||||
lock->force_write = lstat(ref_file, &st) && errno == ENOENT;
|
||||
|
||||
if (safe_create_leading_directories(lock->ref_file))
|
||||
die("unable to create directory for %s", lock->ref_file);
|
||||
lock->lock_fd = hold_lock_file_for_update(lock->lk, lock->ref_file, 1);
|
||||
if (safe_create_leading_directories(ref_file))
|
||||
die("unable to create directory for %s", ref_file);
|
||||
lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, 1);
|
||||
|
||||
return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
|
||||
}
|
||||
@@ -329,15 +464,14 @@ struct ref_lock *lock_ref_sha1(const char *ref,
|
||||
{
|
||||
if (check_ref_format(ref))
|
||||
return NULL;
|
||||
return lock_ref_sha1_basic(git_path("refs/%s", ref),
|
||||
return lock_ref_sha1_basic(mkpath("refs/%s", ref),
|
||||
5 + strlen(ref), old_sha1, mustexist);
|
||||
}
|
||||
|
||||
struct ref_lock *lock_any_ref_for_update(const char *ref,
|
||||
const unsigned char *old_sha1, int mustexist)
|
||||
{
|
||||
return lock_ref_sha1_basic(git_path("%s", ref),
|
||||
strlen(ref), old_sha1, mustexist);
|
||||
return lock_ref_sha1_basic(ref, strlen(ref), old_sha1, mustexist);
|
||||
}
|
||||
|
||||
void unlock_ref(struct ref_lock *lock)
|
||||
@@ -348,7 +482,7 @@ void unlock_ref(struct ref_lock *lock)
|
||||
if (lock->lk)
|
||||
rollback_lock_file(lock->lk);
|
||||
}
|
||||
free(lock->ref_file);
|
||||
free(lock->ref_name);
|
||||
free(lock->log_file);
|
||||
free(lock);
|
||||
}
|
||||
@@ -425,7 +559,7 @@ int write_ref_sha1(struct ref_lock *lock,
|
||||
return -1;
|
||||
}
|
||||
if (commit_lock_file(lock->lk)) {
|
||||
error("Couldn't set %s", lock->ref_file);
|
||||
error("Couldn't set %s", lock->ref_name);
|
||||
unlock_ref(lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
2
refs.h
2
refs.h
@@ -2,7 +2,7 @@
|
||||
#define REFS_H
|
||||
|
||||
struct ref_lock {
|
||||
char *ref_file;
|
||||
char *ref_name;
|
||||
char *log_file;
|
||||
struct lock_file *lk;
|
||||
unsigned char old_sha1[20];
|
||||
|
||||
14
sha1_name.c
14
sha1_name.c
@@ -247,8 +247,8 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
||||
NULL
|
||||
};
|
||||
static const char *warning = "warning: refname '%.*s' is ambiguous.\n";
|
||||
const char **p, *pathname;
|
||||
char *real_path = NULL;
|
||||
const char **p, *ref;
|
||||
char *real_ref = NULL;
|
||||
int refs_found = 0, am;
|
||||
unsigned long at_time = (unsigned long)-1;
|
||||
unsigned char *this_result;
|
||||
@@ -276,10 +276,10 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
||||
|
||||
for (p = fmt; *p; p++) {
|
||||
this_result = refs_found ? sha1_from_ref : sha1;
|
||||
pathname = resolve_ref(git_path(*p, len, str), this_result, 1);
|
||||
if (pathname) {
|
||||
ref = resolve_ref(mkpath(*p, len, str), this_result, 1);
|
||||
if (ref) {
|
||||
if (!refs_found++)
|
||||
real_path = xstrdup(pathname);
|
||||
real_ref = xstrdup(ref);
|
||||
if (!warn_ambiguous_refs)
|
||||
break;
|
||||
}
|
||||
@@ -293,12 +293,12 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
||||
|
||||
if (at_time != (unsigned long)-1) {
|
||||
read_ref_at(
|
||||
real_path + strlen(git_path(".")) - 1,
|
||||
real_ref,
|
||||
at_time,
|
||||
sha1);
|
||||
}
|
||||
|
||||
free(real_path);
|
||||
free(real_ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,11 +30,8 @@ rm -f .git/$m
|
||||
test_expect_success \
|
||||
"fail to create $n" \
|
||||
"touch .git/$n_dir
|
||||
git-update-ref $n $A >out 2>err
|
||||
test "'$? = 1 &&
|
||||
test "" = "$(cat out)" &&
|
||||
grep "error: unable to resolve reference" err &&
|
||||
grep '"$n err"
|
||||
git-update-ref $n $A >out 2>err"'
|
||||
test $? != 0'
|
||||
rm -f .git/$n_dir out err
|
||||
|
||||
test_expect_success \
|
||||
|
||||
@@ -41,10 +41,8 @@ void wt_status_prepare(struct wt_status *s)
|
||||
|
||||
s->is_initial = get_sha1("HEAD", sha1) ? 1 : 0;
|
||||
|
||||
head = resolve_ref(git_path("HEAD"), sha1, 0);
|
||||
s->branch = head ?
|
||||
strdup(head + strlen(get_git_dir()) + 1) :
|
||||
NULL;
|
||||
head = resolve_ref("HEAD", sha1, 0);
|
||||
s->branch = head ? xstrdup(head) : NULL;
|
||||
|
||||
s->reference = "HEAD";
|
||||
s->amend = 0;
|
||||
|
||||
Reference in New Issue
Block a user