mirror of
https://github.com/git/git.git
synced 2026-03-14 02:43:25 +01:00
Merge branch 'np/index-pack' into next
* np/index-pack: remove .keep pack lock files when done with refs update have index-pack create .keep file more carefully improve fetch-pack's handling of kept packs git-fetch can use both --thin and --keep with fetch-pack now Teach receive-pack how to keep pack files based on object count. Allow pack header preprocessing before unpack-objects/index-pack. gitweb: Better support for non-CSS aware web browsers gitweb: Output also empty patches in "commitdiff" view gitweb: Use git-for-each-ref to generate list of heads and/or tags for-each-ref: "creator" and "creatordate" fields Add --global option to git-repo-config. pack-refs: Store the full name of the ref even when packing only tags. git-clone documentation didn't mention --origin as equivalent of -o Minor grammar fixes for git-diff-index.txt link_temp_to_file: call adjust_shared_perm() only when we created the directory Remove uneccessarily similar printf() from print_ref_list() in builtin-branch
This commit is contained in:
@@ -301,7 +301,16 @@ imap::
|
||||
The configuration variables in the 'imap' section are described
|
||||
in gitlink:git-imap-send[1].
|
||||
|
||||
receive.denyNonFastforwads::
|
||||
receive.unpackLimit::
|
||||
If the number of objects received in a push is below this
|
||||
limit then the objects will be unpacked into loose object
|
||||
files. However if the number of received objects equals or
|
||||
exceeds this limit then the received pack will be stored as
|
||||
a pack, after adding any missing delta bases. Storing the
|
||||
pack from a push can make the push operation complete faster,
|
||||
especially on slow filesystems.
|
||||
|
||||
receive.denyNonFastForwards::
|
||||
If set to true, git-receive-pack will deny a ref update which is
|
||||
not a fast forward. Use this to prevent such an update via a push,
|
||||
even if that push is forced. This configuration variable is
|
||||
|
||||
@@ -75,6 +75,7 @@ OPTIONS
|
||||
this option is used, neither the `origin` branch nor the
|
||||
default `remotes/origin` file is created.
|
||||
|
||||
--origin <name>::
|
||||
-o <name>::
|
||||
Instead of using the branch name 'origin' to keep track
|
||||
of the upstream repository, use <name> instead. Note
|
||||
|
||||
@@ -54,7 +54,7 @@ If '--cached' is specified, it allows you to ask:
|
||||
|
||||
For example, let's say that you have worked on your working directory, updated
|
||||
some files in the index and are ready to commit. You want to see exactly
|
||||
*what* you are going to commit is without having to write a new tree
|
||||
*what* you are going to commit, without having to write a new tree
|
||||
object and compare it that way, and to do that, you just do
|
||||
|
||||
git-diff-index --cached HEAD
|
||||
@@ -68,7 +68,7 @@ matches my working directory. But doing a "git-diff-index" does:
|
||||
-100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 commit.c
|
||||
+100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 git-commit.c
|
||||
|
||||
You can trivially see that the above is a rename.
|
||||
You can see easily that the above is a rename.
|
||||
|
||||
In fact, "git-diff-index --cached" *should* always be entirely equivalent to
|
||||
actually doing a "git-write-tree" and comparing that. Except this one is much
|
||||
|
||||
@@ -32,7 +32,8 @@ OPTIONS
|
||||
-k::
|
||||
Do not invoke 'git-unpack-objects' on received data, but
|
||||
create a single packfile out of it instead, and store it
|
||||
in the object database.
|
||||
in the object database. If provided twice then the pack is
|
||||
locked against repacking.
|
||||
|
||||
--exec=<git-upload-pack>::
|
||||
Use this to specify the path to 'git-upload-pack' on the
|
||||
|
||||
@@ -69,6 +69,17 @@ OPTIONS
|
||||
locate any which have outlived their usefulness.
|
||||
|
||||
|
||||
Note
|
||||
----
|
||||
|
||||
Once the index has been created, the list of object names is sorted
|
||||
and the SHA1 hash of that list is printed to stdout. If --stdin was
|
||||
also used then this is prefixed by either "pack\t", or "keep\t" if a
|
||||
new .keep file was successfully created. This is useful to remove a
|
||||
.keep file used as a lock to prevent the race with gitlink:git-repack[1]
|
||||
mentioned above.
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Sergey Vlasov <vsu@altlinux.ru>
|
||||
|
||||
@@ -3,19 +3,19 @@ git-repo-config(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-repo-config - Get and set options in .git/config
|
||||
git-repo-config - Get and set repository or global options.
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-repo-config' [type] name [value [value_regex]]
|
||||
'git-repo-config' [type] --replace-all name [value [value_regex]]
|
||||
'git-repo-config' [type] --get name [value_regex]
|
||||
'git-repo-config' [type] --get-all name [value_regex]
|
||||
'git-repo-config' [type] --unset name [value_regex]
|
||||
'git-repo-config' [type] --unset-all name [value_regex]
|
||||
'git-repo-config' -l | --list
|
||||
'git-repo-config' [--global] [type] name [value [value_regex]]
|
||||
'git-repo-config' [--global] [type] --replace-all name [value [value_regex]]
|
||||
'git-repo-config' [--global] [type] --get name [value_regex]
|
||||
'git-repo-config' [--global] [type] --get-all name [value_regex]
|
||||
'git-repo-config' [--global] [type] --unset name [value_regex]
|
||||
'git-repo-config' [--global] [type] --unset-all name [value_regex]
|
||||
'git-repo-config' [--global] -l | --list
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -41,8 +41,9 @@ This command will fail if:
|
||||
. Can not write to .git/config,
|
||||
. no section was provided,
|
||||
. the section or key is invalid,
|
||||
. you try to unset an option which does not exist, or
|
||||
. you try to unset/set an option for which multiple lines match.
|
||||
. you try to unset an option which does not exist,
|
||||
. you try to unset/set an option for which multiple lines match, or
|
||||
. you use --global option without $HOME being properly set.
|
||||
|
||||
|
||||
OPTIONS
|
||||
@@ -64,14 +65,17 @@ OPTIONS
|
||||
--get-regexp::
|
||||
Like --get-all, but interprets the name as a regular expression.
|
||||
|
||||
--global::
|
||||
Use global ~/.gitconfig file rather than the repository .git/config.
|
||||
|
||||
--unset::
|
||||
Remove the line matching the key from .git/config.
|
||||
Remove the line matching the key from config file.
|
||||
|
||||
--unset-all::
|
||||
Remove all matching lines from .git/config.
|
||||
Remove all matching lines from config file.
|
||||
|
||||
-l, --list::
|
||||
List all variables set in .git/config.
|
||||
List all variables set in config file.
|
||||
|
||||
|
||||
ENVIRONMENT
|
||||
@@ -79,6 +83,7 @@ ENVIRONMENT
|
||||
|
||||
GIT_CONFIG::
|
||||
Take the configuration from the given file instead of .git/config.
|
||||
Using the "--global" option forces this to ~/.gitconfig.
|
||||
|
||||
GIT_CONFIG_LOCAL::
|
||||
Currently the same as $GIT_CONFIG; when Git will support global
|
||||
|
||||
2
Makefile
2
Makefile
@@ -260,7 +260,7 @@ LIB_OBJS = \
|
||||
quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
|
||||
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
|
||||
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
|
||||
fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
|
||||
revision.o pager.o tree-walk.o xdiff-interface.o \
|
||||
write_or_die.o trace.o list-objects.o grep.o \
|
||||
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
|
||||
color.o wt-status.o archive-zip.o archive-tar.o
|
||||
|
||||
@@ -103,6 +103,7 @@ static int ref_cmp(const void *r1, const void *r2)
|
||||
static void print_ref_list(int remote_only)
|
||||
{
|
||||
int i;
|
||||
char c;
|
||||
|
||||
if (remote_only)
|
||||
for_each_remote_ref(append_ref, NULL);
|
||||
@@ -112,10 +113,11 @@ static void print_ref_list(int remote_only)
|
||||
qsort(ref_list, ref_index, sizeof(char *), ref_cmp);
|
||||
|
||||
for (i = 0; i < ref_index; i++) {
|
||||
c = ' ';
|
||||
if (!strcmp(ref_list[i], head))
|
||||
printf("* %s\n", ref_list[i]);
|
||||
else
|
||||
printf(" %s\n", ref_list[i]);
|
||||
c = '*';
|
||||
|
||||
printf("%c %s\n", c, ref_list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ static struct {
|
||||
{ "taggername" },
|
||||
{ "taggeremail" },
|
||||
{ "taggerdate", FIELD_TIME },
|
||||
{ "creator" },
|
||||
{ "creatordate", FIELD_TIME },
|
||||
{ "subject" },
|
||||
{ "body" },
|
||||
{ "contents" },
|
||||
@@ -401,6 +403,29 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
|
||||
else if (!strcmp(name + wholen, "date"))
|
||||
grab_date(wholine, v);
|
||||
}
|
||||
|
||||
/* For a tag or a commit object, if "creator" or "creatordate" is
|
||||
* requested, do something special.
|
||||
*/
|
||||
if (strcmp(who, "tagger") && strcmp(who, "committer"))
|
||||
return; /* "author" for commit object is not wanted */
|
||||
if (!wholine)
|
||||
wholine = find_wholine(who, wholen, buf, sz);
|
||||
if (!wholine)
|
||||
return;
|
||||
for (i = 0; i < used_atom_cnt; i++) {
|
||||
const char *name = used_atom[i];
|
||||
struct atom_value *v = &val[i];
|
||||
if (!!deref != (*name == '*'))
|
||||
continue;
|
||||
if (deref)
|
||||
name++;
|
||||
|
||||
if (!strcmp(name, "creatordate"))
|
||||
grab_date(wholine, v);
|
||||
else if (!strcmp(name, "creator"))
|
||||
v->s = copy_line(wholine);
|
||||
}
|
||||
}
|
||||
|
||||
static void find_subpos(const char *buf, unsigned long sz, const char **sub, const char **body)
|
||||
|
||||
@@ -12,6 +12,7 @@ struct ref_to_prune {
|
||||
|
||||
struct pack_refs_cb_data {
|
||||
int prune;
|
||||
int all;
|
||||
struct ref_to_prune *ref_to_prune;
|
||||
FILE *refs_file;
|
||||
};
|
||||
@@ -29,6 +30,8 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
|
||||
{
|
||||
struct pack_refs_cb_data *cb = cb_data;
|
||||
|
||||
if (!cb->all && strncmp(path, "refs/tags/", 10))
|
||||
return 0;
|
||||
/* Do not pack the symbolic refs */
|
||||
if (!(flags & REF_ISSYMREF))
|
||||
fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
|
||||
@@ -68,7 +71,6 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int fd, i;
|
||||
struct pack_refs_cb_data cbdata;
|
||||
int (*iterate_ref)(each_ref_fn, void *) = for_each_tag_ref;
|
||||
|
||||
memset(&cbdata, 0, sizeof(cbdata));
|
||||
|
||||
@@ -79,7 +81,7 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--all")) {
|
||||
iterate_ref = for_each_ref;
|
||||
cbdata.all = 1;
|
||||
continue;
|
||||
}
|
||||
/* perhaps other parameters later... */
|
||||
@@ -93,7 +95,7 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
|
||||
if (!cbdata.refs_file)
|
||||
die("unable to create ref-pack file structure (%s)",
|
||||
strerror(errno));
|
||||
iterate_ref(handle_one_ref, &cbdata);
|
||||
for_each_ref(handle_one_ref, &cbdata);
|
||||
fflush(cbdata.refs_file);
|
||||
fsync(fd);
|
||||
fclose(cbdata.refs_file);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <regex.h>
|
||||
|
||||
static const char git_config_set_usage[] =
|
||||
"git-repo-config [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
|
||||
"git-repo-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
|
||||
|
||||
static char *key;
|
||||
static regex_t *key_regexp;
|
||||
@@ -139,7 +139,16 @@ int cmd_repo_config(int argc, const char **argv, const char *prefix)
|
||||
type = T_BOOL;
|
||||
else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
|
||||
return git_config(show_all_config);
|
||||
else
|
||||
else if (!strcmp(argv[1], "--global")) {
|
||||
char *home = getenv("HOME");
|
||||
if (home) {
|
||||
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
|
||||
setenv("GIT_CONFIG", user_config, 1);
|
||||
free(user_config);
|
||||
} else {
|
||||
die("$HOME not set");
|
||||
}
|
||||
} else
|
||||
break;
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
@@ -371,6 +371,21 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
|
||||
recover = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(arg, "--pack_header=", 14)) {
|
||||
struct pack_header *hdr;
|
||||
char *c;
|
||||
|
||||
hdr = (struct pack_header *)buffer;
|
||||
hdr->hdr_signature = htonl(PACK_SIGNATURE);
|
||||
hdr->hdr_version = htonl(strtoul(arg + 14, &c, 10));
|
||||
if (*c != ',')
|
||||
die("bad %s", arg);
|
||||
hdr->hdr_entries = htonl(strtoul(c + 1, &c, 10));
|
||||
if (*c)
|
||||
die("bad %s", arg);
|
||||
len = sizeof(*hdr);
|
||||
continue;
|
||||
}
|
||||
usage(unpack_usage);
|
||||
}
|
||||
|
||||
|
||||
5
cache.h
5
cache.h
@@ -376,6 +376,7 @@ extern struct packed_git *parse_pack_index_file(const unsigned char *sha1,
|
||||
char *idx_path);
|
||||
|
||||
extern void prepare_packed_git(void);
|
||||
extern void reprepare_packed_git(void);
|
||||
extern void install_packed_git(struct packed_git *pack);
|
||||
|
||||
extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
|
||||
@@ -415,10 +416,6 @@ extern int copy_fd(int ifd, int ofd);
|
||||
extern void write_or_die(int fd, const void *buf, size_t count);
|
||||
extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
|
||||
|
||||
/* Finish off pack transfer receiving end */
|
||||
extern int receive_unpack_pack(int fd[2], const char *me, int quiet, int);
|
||||
extern int receive_keep_pack(int fd[2], const char *me, int quiet, int);
|
||||
|
||||
/* pager.c */
|
||||
extern void setup_pager(void);
|
||||
extern int pager_in_use;
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
#include "cache.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "pkt-line.h"
|
||||
#include "sideband.h"
|
||||
#include <sys/wait.h>
|
||||
|
||||
static pid_t setup_sideband(int sideband, const char *me, int fd[2], int xd[2])
|
||||
{
|
||||
pid_t side_pid;
|
||||
|
||||
if (!sideband) {
|
||||
fd[0] = xd[0];
|
||||
fd[1] = xd[1];
|
||||
return 0;
|
||||
}
|
||||
/* xd[] is talking with upload-pack; subprocess reads from
|
||||
* xd[0], spits out band#2 to stderr, and feeds us band#1
|
||||
* through our fd[0].
|
||||
*/
|
||||
if (pipe(fd) < 0)
|
||||
die("%s: unable to set up pipe", me);
|
||||
side_pid = fork();
|
||||
if (side_pid < 0)
|
||||
die("%s: unable to fork off sideband demultiplexer", me);
|
||||
if (!side_pid) {
|
||||
/* subprocess */
|
||||
close(fd[0]);
|
||||
if (xd[0] != xd[1])
|
||||
close(xd[1]);
|
||||
if (recv_sideband(me, xd[0], fd[1], 2))
|
||||
exit(1);
|
||||
exit(0);
|
||||
}
|
||||
close(xd[0]);
|
||||
close(fd[1]);
|
||||
fd[1] = xd[1];
|
||||
return side_pid;
|
||||
}
|
||||
|
||||
static int get_pack(int xd[2], const char *me, int sideband, const char **argv)
|
||||
{
|
||||
int status;
|
||||
pid_t pid, side_pid;
|
||||
int fd[2];
|
||||
|
||||
side_pid = setup_sideband(sideband, me, fd, xd);
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
die("%s: unable to fork off %s", me, argv[0]);
|
||||
if (!pid) {
|
||||
dup2(fd[0], 0);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
execv_git_cmd(argv);
|
||||
die("%s exec failed", argv[0]);
|
||||
}
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
while (waitpid(pid, &status, 0) < 0) {
|
||||
if (errno != EINTR)
|
||||
die("waiting for %s: %s", argv[0], strerror(errno));
|
||||
}
|
||||
if (WIFEXITED(status)) {
|
||||
int code = WEXITSTATUS(status);
|
||||
if (code)
|
||||
die("%s died with error code %d", argv[0], code);
|
||||
return 0;
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
int sig = WTERMSIG(status);
|
||||
die("%s died of signal %d", argv[0], sig);
|
||||
}
|
||||
die("%s died of unnatural causes %d", argv[0], status);
|
||||
}
|
||||
|
||||
int receive_unpack_pack(int xd[2], const char *me, int quiet, int sideband)
|
||||
{
|
||||
const char *argv[3] = { "unpack-objects", quiet ? "-q" : NULL, NULL };
|
||||
return get_pack(xd, me, sideband, argv);
|
||||
}
|
||||
|
||||
int receive_keep_pack(int xd[2], const char *me, int quiet, int sideband)
|
||||
{
|
||||
const char *argv[5] = { "index-pack", "--stdin", "--fix-thin",
|
||||
quiet ? NULL : "-v", NULL };
|
||||
return get_pack(xd, me, sideband, argv);
|
||||
}
|
||||
110
fetch-pack.c
110
fetch-pack.c
@@ -3,6 +3,9 @@
|
||||
#include "pkt-line.h"
|
||||
#include "commit.h"
|
||||
#include "tag.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "sideband.h"
|
||||
#include <sys/wait.h>
|
||||
|
||||
static int keep_pack;
|
||||
static int quiet;
|
||||
@@ -416,6 +419,103 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static pid_t setup_sideband(int fd[2], int xd[2])
|
||||
{
|
||||
pid_t side_pid;
|
||||
|
||||
if (!use_sideband) {
|
||||
fd[0] = xd[0];
|
||||
fd[1] = xd[1];
|
||||
return 0;
|
||||
}
|
||||
/* xd[] is talking with upload-pack; subprocess reads from
|
||||
* xd[0], spits out band#2 to stderr, and feeds us band#1
|
||||
* through our fd[0].
|
||||
*/
|
||||
if (pipe(fd) < 0)
|
||||
die("fetch-pack: unable to set up pipe");
|
||||
side_pid = fork();
|
||||
if (side_pid < 0)
|
||||
die("fetch-pack: unable to fork off sideband demultiplexer");
|
||||
if (!side_pid) {
|
||||
/* subprocess */
|
||||
close(fd[0]);
|
||||
if (xd[0] != xd[1])
|
||||
close(xd[1]);
|
||||
if (recv_sideband("fetch-pack", xd[0], fd[1], 2))
|
||||
exit(1);
|
||||
exit(0);
|
||||
}
|
||||
close(xd[0]);
|
||||
close(fd[1]);
|
||||
fd[1] = xd[1];
|
||||
return side_pid;
|
||||
}
|
||||
|
||||
static int get_pack(int xd[2], const char **argv)
|
||||
{
|
||||
int status;
|
||||
pid_t pid, side_pid;
|
||||
int fd[2];
|
||||
|
||||
side_pid = setup_sideband(fd, xd);
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
die("fetch-pack: unable to fork off %s", argv[0]);
|
||||
if (!pid) {
|
||||
dup2(fd[0], 0);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
execv_git_cmd(argv);
|
||||
die("%s exec failed", argv[0]);
|
||||
}
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
while (waitpid(pid, &status, 0) < 0) {
|
||||
if (errno != EINTR)
|
||||
die("waiting for %s: %s", argv[0], strerror(errno));
|
||||
}
|
||||
if (WIFEXITED(status)) {
|
||||
int code = WEXITSTATUS(status);
|
||||
if (code)
|
||||
die("%s died with error code %d", argv[0], code);
|
||||
return 0;
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
int sig = WTERMSIG(status);
|
||||
die("%s died of signal %d", argv[0], sig);
|
||||
}
|
||||
die("%s died of unnatural causes %d", argv[0], status);
|
||||
}
|
||||
|
||||
static int explode_rx_pack(int xd[2])
|
||||
{
|
||||
const char *argv[3] = { "unpack-objects", quiet ? "-q" : NULL, NULL };
|
||||
return get_pack(xd, argv);
|
||||
}
|
||||
|
||||
static int keep_rx_pack(int xd[2])
|
||||
{
|
||||
const char *argv[6];
|
||||
char keep_arg[256];
|
||||
int n = 0;
|
||||
|
||||
argv[n++] = "index-pack";
|
||||
argv[n++] = "--stdin";
|
||||
if (!quiet)
|
||||
argv[n++] = "-v";
|
||||
if (use_thin_pack)
|
||||
argv[n++] = "--fix-thin";
|
||||
if (keep_pack > 1) {
|
||||
int s = sprintf(keep_arg, "--keep=fetch-pack %i on ", getpid());
|
||||
if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
|
||||
strcpy(keep_arg + s, "localhost");
|
||||
argv[n++] = keep_arg;
|
||||
}
|
||||
argv[n] = NULL;
|
||||
return get_pack(xd, argv);
|
||||
}
|
||||
|
||||
static int fetch_pack(int fd[2], int nr_match, char **match)
|
||||
{
|
||||
struct ref *ref;
|
||||
@@ -447,17 +547,13 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
|
||||
goto all_done;
|
||||
}
|
||||
if (find_common(fd, sha1, ref) < 0)
|
||||
if (!keep_pack)
|
||||
if (keep_pack != 1)
|
||||
/* When cloning, it is not unusual to have
|
||||
* no common commit.
|
||||
*/
|
||||
fprintf(stderr, "warning: no common commits\n");
|
||||
|
||||
if (keep_pack)
|
||||
status = receive_keep_pack(fd, "git-fetch-pack", quiet, use_sideband);
|
||||
else
|
||||
status = receive_unpack_pack(fd, "git-fetch-pack", quiet, use_sideband);
|
||||
|
||||
status = (keep_pack) ? keep_rx_pack(fd) : explode_rx_pack(fd);
|
||||
if (status)
|
||||
die("git-fetch-pack: fetch failed.");
|
||||
|
||||
@@ -494,7 +590,7 @@ int main(int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
|
||||
keep_pack = 1;
|
||||
keep_pack++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("--thin", arg)) {
|
||||
|
||||
14
git-fetch.sh
14
git-fetch.sh
@@ -20,7 +20,7 @@ verbose=
|
||||
update_head_ok=
|
||||
exec=
|
||||
upload_pack=
|
||||
keep=--thin
|
||||
keep=
|
||||
while case "$#" in 0) break ;; esac
|
||||
do
|
||||
case "$1" in
|
||||
@@ -51,7 +51,7 @@ do
|
||||
verbose=Yes
|
||||
;;
|
||||
-k|--k|--ke|--kee|--keep)
|
||||
keep=--keep
|
||||
keep='-k -k'
|
||||
;;
|
||||
--reflog-action=*)
|
||||
rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'`
|
||||
@@ -368,9 +368,10 @@ fetch_main () {
|
||||
;; # we are already done.
|
||||
*)
|
||||
( : subshell because we muck with IFS
|
||||
pack_lockfile=
|
||||
IFS=" $LF"
|
||||
(
|
||||
git-fetch-pack $exec $keep "$remote" $rref || echo failed "$remote"
|
||||
git-fetch-pack --thin $exec $keep "$remote" $rref || echo failed "$remote"
|
||||
) |
|
||||
while read sha1 remote_name
|
||||
do
|
||||
@@ -378,6 +379,12 @@ fetch_main () {
|
||||
failed)
|
||||
echo >&2 "Fetch failure: $remote"
|
||||
exit 1 ;;
|
||||
# special line coming from index-pack with the pack name
|
||||
pack)
|
||||
continue ;;
|
||||
keep)
|
||||
pack_lockfile="$GIT_OBJECT_DIRECTORY/pack/pack-$remote_name.keep"
|
||||
continue ;;
|
||||
esac
|
||||
found=
|
||||
single_force=
|
||||
@@ -408,6 +415,7 @@ fetch_main () {
|
||||
append_fetch_head "$sha1" "$remote" \
|
||||
"$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
|
||||
done
|
||||
if [ "$pack_lockfile" ]; then rm -f "$pack_lockfile"; fi
|
||||
) || exit ;;
|
||||
esac
|
||||
|
||||
|
||||
@@ -570,12 +570,17 @@ sub esc_url {
|
||||
}
|
||||
|
||||
# replace invalid utf8 character with SUBSTITUTION sequence
|
||||
sub esc_html {
|
||||
sub esc_html ($;%) {
|
||||
my $str = shift;
|
||||
my %opts = @_;
|
||||
|
||||
$str = to_utf8($str);
|
||||
$str = escapeHTML($str);
|
||||
$str =~ s/\014/^L/g; # escape FORM FEED (FF) character (e.g. in COPYING file)
|
||||
$str =~ s/\033/^[/g; # "escape" ESCAPE (\e) character (e.g. commit 20a3847d8a5032ce41f90dcc68abfb36e6fee9b1)
|
||||
if ($opts{'-nbsp'}) {
|
||||
$str =~ s/ / /g;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
@@ -800,7 +805,7 @@ sub format_diff_line {
|
||||
$diff_class = " incomplete";
|
||||
}
|
||||
$line = untabify($line);
|
||||
return "<div class=\"diff$diff_class\">" . esc_html($line) . "</div>\n";
|
||||
return "<div class=\"diff$diff_class\">" . esc_html($line, -nbsp=>1) . "</div>\n";
|
||||
}
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
@@ -1318,47 +1323,88 @@ sub parse_ls_tree_line ($;%) {
|
||||
## ......................................................................
|
||||
## parse to array of hashes functions
|
||||
|
||||
sub git_get_refs_list {
|
||||
my $type = shift || "";
|
||||
my %refs;
|
||||
my @reflist;
|
||||
sub git_get_heads_list {
|
||||
my $limit = shift;
|
||||
my @headslist;
|
||||
|
||||
my @refs;
|
||||
open my $fd, "-|", $GIT, "peek-remote", "$projectroot/$project/"
|
||||
open my $fd, '-|', git_cmd(), 'for-each-ref',
|
||||
($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate',
|
||||
'--format=%(objectname) %(refname) %(subject)%00%(committer)',
|
||||
'refs/heads'
|
||||
or return;
|
||||
while (my $line = <$fd>) {
|
||||
chomp $line;
|
||||
if ($line =~ m/^([0-9a-fA-F]{40})\trefs\/($type\/?([^\^]+))(\^\{\})?$/) {
|
||||
if (defined $refs{$1}) {
|
||||
push @{$refs{$1}}, $2;
|
||||
} else {
|
||||
$refs{$1} = [ $2 ];
|
||||
}
|
||||
my %ref_item;
|
||||
|
||||
if (! $4) { # unpeeled, direct reference
|
||||
push @refs, { hash => $1, name => $3 }; # without type
|
||||
} elsif ($3 eq $refs[-1]{'name'}) {
|
||||
# most likely a tag is followed by its peeled
|
||||
# (deref) one, and when that happens we know the
|
||||
# previous one was of type 'tag'.
|
||||
$refs[-1]{'type'} = "tag";
|
||||
}
|
||||
chomp $line;
|
||||
my ($refinfo, $committerinfo) = split(/\0/, $line);
|
||||
my ($hash, $name, $title) = split(' ', $refinfo, 3);
|
||||
my ($committer, $epoch, $tz) =
|
||||
($committerinfo =~ /^(.*) ([0-9]+) (.*)$/);
|
||||
$name =~ s!^refs/heads/!!;
|
||||
|
||||
$ref_item{'name'} = $name;
|
||||
$ref_item{'id'} = $hash;
|
||||
$ref_item{'title'} = $title || '(no commit message)';
|
||||
$ref_item{'epoch'} = $epoch;
|
||||
if ($epoch) {
|
||||
$ref_item{'age'} = age_string(time - $ref_item{'epoch'});
|
||||
} else {
|
||||
$ref_item{'age'} = "unknown";
|
||||
}
|
||||
|
||||
push @headslist, \%ref_item;
|
||||
}
|
||||
close $fd;
|
||||
|
||||
foreach my $ref (@refs) {
|
||||
my $ref_file = $ref->{'name'};
|
||||
my $ref_id = $ref->{'hash'};
|
||||
return wantarray ? @headslist : \@headslist;
|
||||
}
|
||||
|
||||
my $type = $ref->{'type'} || git_get_type($ref_id) || next;
|
||||
my %ref_item = parse_ref($ref_file, $ref_id, $type);
|
||||
sub git_get_tags_list {
|
||||
my $limit = shift;
|
||||
my @tagslist;
|
||||
|
||||
push @reflist, \%ref_item;
|
||||
open my $fd, '-|', git_cmd(), 'for-each-ref',
|
||||
($limit ? '--count='.($limit+1) : ()), '--sort=-creatordate',
|
||||
'--format=%(objectname) %(objecttype) %(refname) '.
|
||||
'%(*objectname) %(*objecttype) %(subject)%00%(creator)',
|
||||
'refs/tags'
|
||||
or return;
|
||||
while (my $line = <$fd>) {
|
||||
my %ref_item;
|
||||
|
||||
chomp $line;
|
||||
my ($refinfo, $creatorinfo) = split(/\0/, $line);
|
||||
my ($id, $type, $name, $refid, $reftype, $title) = split(' ', $refinfo, 6);
|
||||
my ($creator, $epoch, $tz) =
|
||||
($creatorinfo =~ /^(.*) ([0-9]+) (.*)$/);
|
||||
$name =~ s!^refs/tags/!!;
|
||||
|
||||
$ref_item{'type'} = $type;
|
||||
$ref_item{'id'} = $id;
|
||||
$ref_item{'name'} = $name;
|
||||
if ($type eq "tag") {
|
||||
$ref_item{'subject'} = $title;
|
||||
$ref_item{'reftype'} = $reftype;
|
||||
$ref_item{'refid'} = $refid;
|
||||
} else {
|
||||
$ref_item{'reftype'} = $type;
|
||||
$ref_item{'refid'} = $id;
|
||||
}
|
||||
|
||||
if ($type eq "tag" || $type eq "commit") {
|
||||
$ref_item{'epoch'} = $epoch;
|
||||
if ($epoch) {
|
||||
$ref_item{'age'} = age_string(time - $ref_item{'epoch'});
|
||||
} else {
|
||||
$ref_item{'age'} = "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
push @tagslist, \%ref_item;
|
||||
}
|
||||
# sort refs by age
|
||||
@reflist = sort {$b->{'epoch'} <=> $a->{'epoch'}} @reflist;
|
||||
return (\@reflist, \%refs);
|
||||
close $fd;
|
||||
|
||||
return wantarray ? @tagslist : \@tagslist;
|
||||
}
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
@@ -1969,19 +2015,19 @@ sub git_difftree_body {
|
||||
print "</td>\n";
|
||||
print "<td>$mode_chnge</td>\n";
|
||||
print "<td class=\"link\">";
|
||||
if ($diff{'to_id'} ne $diff{'from_id'}) { # modified
|
||||
if ($action eq 'commitdiff') {
|
||||
# link to patch
|
||||
$patchno++;
|
||||
print $cgi->a({-href => "#patch$patchno"}, "patch");
|
||||
} else {
|
||||
print $cgi->a({-href => href(action=>"blobdiff",
|
||||
hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
|
||||
hash_base=>$hash, hash_parent_base=>$parent,
|
||||
file_name=>$diff{'file'})},
|
||||
"diff");
|
||||
}
|
||||
print " | ";
|
||||
if ($action eq 'commitdiff') {
|
||||
# link to patch
|
||||
$patchno++;
|
||||
print $cgi->a({-href => "#patch$patchno"}, "patch") .
|
||||
" | ";
|
||||
} elsif ($diff{'to_id'} ne $diff{'from_id'}) {
|
||||
# "commit" view and modified file (not onlu mode changed)
|
||||
print $cgi->a({-href => href(action=>"blobdiff",
|
||||
hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
|
||||
hash_base=>$hash, hash_parent_base=>$parent,
|
||||
file_name=>$diff{'file'})},
|
||||
"diff") .
|
||||
" | ";
|
||||
}
|
||||
print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
|
||||
hash_base=>$hash, file_name=>$diff{'file'})},
|
||||
@@ -2012,19 +2058,19 @@ sub git_difftree_body {
|
||||
-class => "list"}, esc_html($diff{'from_file'})) .
|
||||
" with " . (int $diff{'similarity'}) . "% similarity$mode_chng]</span></td>\n" .
|
||||
"<td class=\"link\">";
|
||||
if ($diff{'to_id'} ne $diff{'from_id'}) {
|
||||
if ($action eq 'commitdiff') {
|
||||
# link to patch
|
||||
$patchno++;
|
||||
print $cgi->a({-href => "#patch$patchno"}, "patch");
|
||||
} else {
|
||||
print $cgi->a({-href => href(action=>"blobdiff",
|
||||
hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
|
||||
hash_base=>$hash, hash_parent_base=>$parent,
|
||||
file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})},
|
||||
"diff");
|
||||
}
|
||||
print " | ";
|
||||
if ($action eq 'commitdiff') {
|
||||
# link to patch
|
||||
$patchno++;
|
||||
print $cgi->a({-href => "#patch$patchno"}, "patch") .
|
||||
" | ";
|
||||
} elsif ($diff{'to_id'} ne $diff{'from_id'}) {
|
||||
# "commit" view and modified file (not only pure rename or copy)
|
||||
print $cgi->a({-href => href(action=>"blobdiff",
|
||||
hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
|
||||
hash_base=>$hash, hash_parent_base=>$parent,
|
||||
file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})},
|
||||
"diff") .
|
||||
" | ";
|
||||
}
|
||||
print $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'},
|
||||
hash_base=>$parent, file_name=>$diff{'from_file'})},
|
||||
@@ -2075,13 +2121,6 @@ sub git_patchset_body {
|
||||
}
|
||||
$patch_idx++;
|
||||
|
||||
# for now, no extended header, hence we skip empty patches
|
||||
# companion to next LINE if $in_header;
|
||||
if ($diffinfo->{'from_id'} eq $diffinfo->{'to_id'}) { # no change
|
||||
$in_header = 1;
|
||||
next LINE;
|
||||
}
|
||||
|
||||
if ($diffinfo->{'status'} eq "A") { # added
|
||||
print "<div class=\"diff_info\">" . file_type($diffinfo->{'to_mode'}) . ":" .
|
||||
$cgi->a({-href => href(action=>"blob", hash_base=>$hash,
|
||||
@@ -2406,8 +2445,7 @@ sub git_tags_body {
|
||||
for (my $i = $from; $i <= $to; $i++) {
|
||||
my $entry = $taglist->[$i];
|
||||
my %tag = %$entry;
|
||||
my $comment_lines = $tag{'comment'};
|
||||
my $comment = shift @$comment_lines;
|
||||
my $comment = $tag{'subject'};
|
||||
my $comment_short;
|
||||
if (defined $comment) {
|
||||
$comment_short = chop_str($comment, 30, 5);
|
||||
@@ -2440,7 +2478,7 @@ sub git_tags_body {
|
||||
$cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'})}, $tag{'reftype'});
|
||||
if ($tag{'reftype'} eq "commit") {
|
||||
print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") .
|
||||
" | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'refid'})}, "log");
|
||||
" | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log");
|
||||
} elsif ($tag{'reftype'} eq "blob") {
|
||||
print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$tag{'refid'})}, "raw");
|
||||
}
|
||||
@@ -2465,23 +2503,23 @@ sub git_heads_body {
|
||||
my $alternate = 1;
|
||||
for (my $i = $from; $i <= $to; $i++) {
|
||||
my $entry = $headlist->[$i];
|
||||
my %tag = %$entry;
|
||||
my $curr = $tag{'id'} eq $head;
|
||||
my %ref = %$entry;
|
||||
my $curr = $ref{'id'} eq $head;
|
||||
if ($alternate) {
|
||||
print "<tr class=\"dark\">\n";
|
||||
} else {
|
||||
print "<tr class=\"light\">\n";
|
||||
}
|
||||
$alternate ^= 1;
|
||||
print "<td><i>$tag{'age'}</i></td>\n" .
|
||||
($tag{'id'} eq $head ? "<td class=\"current_head\">" : "<td>") .
|
||||
$cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'}),
|
||||
-class => "list name"},esc_html($tag{'name'})) .
|
||||
print "<td><i>$ref{'age'}</i></td>\n" .
|
||||
($curr ? "<td class=\"current_head\">" : "<td>") .
|
||||
$cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'}),
|
||||
-class => "list name"},esc_html($ref{'name'})) .
|
||||
"</td>\n" .
|
||||
"<td class=\"link\">" .
|
||||
$cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . " | " .
|
||||
$cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log") . " | " .
|
||||
$cgi->a({-href => href(action=>"tree", hash=>$tag{'name'}, hash_base=>$tag{'name'})}, "tree") .
|
||||
$cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'})}, "shortlog") . " | " .
|
||||
$cgi->a({-href => href(action=>"log", hash=>$ref{'name'})}, "log") . " | " .
|
||||
$cgi->a({-href => href(action=>"tree", hash=>$ref{'name'}, hash_base=>$ref{'name'})}, "tree") .
|
||||
"</td>\n" .
|
||||
"</tr>";
|
||||
}
|
||||
@@ -2570,18 +2608,9 @@ sub git_summary {
|
||||
|
||||
my $owner = git_get_project_owner($project);
|
||||
|
||||
my ($reflist, $refs) = git_get_refs_list();
|
||||
|
||||
my @taglist;
|
||||
my @headlist;
|
||||
foreach my $ref (@$reflist) {
|
||||
if ($ref->{'name'} =~ s!^heads/!!) {
|
||||
push @headlist, $ref;
|
||||
} else {
|
||||
$ref->{'name'} =~ s!^tags/!!;
|
||||
push @taglist, $ref;
|
||||
}
|
||||
}
|
||||
my $refs = git_get_references();
|
||||
my @taglist = git_get_tags_list(15);
|
||||
my @headlist = git_get_heads_list(15);
|
||||
my @forklist;
|
||||
if (gitweb_check_feature('forks')) {
|
||||
@forklist = git_get_projects_list($project);
|
||||
@@ -2884,9 +2913,9 @@ sub git_tags {
|
||||
git_print_page_nav('','', $head,undef,$head);
|
||||
git_print_header_div('summary', $project);
|
||||
|
||||
my ($taglist) = git_get_refs_list("tags");
|
||||
if (@$taglist) {
|
||||
git_tags_body($taglist);
|
||||
my @tagslist = git_get_tags_list();
|
||||
if (@tagslist) {
|
||||
git_tags_body(\@tagslist);
|
||||
}
|
||||
git_footer_html();
|
||||
}
|
||||
@@ -2897,9 +2926,9 @@ sub git_heads {
|
||||
git_print_page_nav('','', $head,undef,$head);
|
||||
git_print_header_div('summary', $project);
|
||||
|
||||
my ($headlist) = git_get_refs_list("heads");
|
||||
if (@$headlist) {
|
||||
git_heads_body($headlist, $head);
|
||||
my @headslist = git_get_heads_list();
|
||||
if (@headslist) {
|
||||
git_heads_body(\@headslist, $head);
|
||||
}
|
||||
git_footer_html();
|
||||
}
|
||||
@@ -3012,7 +3041,7 @@ sub git_blob {
|
||||
$nr++;
|
||||
$line = untabify($line);
|
||||
printf "<div class=\"pre\"><a id=\"l%i\" href=\"#l%i\" class=\"linenr\">%4i</a> %s</div>\n",
|
||||
$nr, $nr, $nr, esc_html($line);
|
||||
$nr, $nr, $nr, esc_html($line, -nbsp=>1);
|
||||
}
|
||||
close $fd
|
||||
or print "Reading blob failed.\n";
|
||||
|
||||
68
index-pack.c
68
index-pack.c
@@ -757,6 +757,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
|
||||
const char *keep_name, const char *keep_msg,
|
||||
unsigned char *sha1)
|
||||
{
|
||||
char *report = "pack";
|
||||
char name[PATH_MAX];
|
||||
int err;
|
||||
|
||||
@@ -767,18 +768,6 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
|
||||
if (err)
|
||||
die("error while closing pack file: %s", strerror(errno));
|
||||
chmod(curr_pack_name, 0444);
|
||||
|
||||
/*
|
||||
* Let's just mimic git-unpack-objects here and write
|
||||
* the last part of the buffer to stdout.
|
||||
*/
|
||||
while (input_len) {
|
||||
err = xwrite(1, input_buffer + input_offset, input_len);
|
||||
if (err <= 0)
|
||||
break;
|
||||
input_len -= err;
|
||||
input_offset += err;
|
||||
}
|
||||
}
|
||||
|
||||
if (keep_msg) {
|
||||
@@ -788,14 +777,18 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
|
||||
get_object_directory(), sha1_to_hex(sha1));
|
||||
keep_name = name;
|
||||
}
|
||||
keep_fd = open(keep_name, O_RDWR | O_CREAT, 0600);
|
||||
if (keep_fd < 0)
|
||||
die("cannot write keep file");
|
||||
if (keep_msg_len > 0) {
|
||||
write_or_die(keep_fd, keep_msg, keep_msg_len);
|
||||
write_or_die(keep_fd, "\n", 1);
|
||||
keep_fd = open(keep_name, O_RDWR|O_CREAT|O_EXCL, 0600);
|
||||
if (keep_fd < 0) {
|
||||
if (errno != EEXIST)
|
||||
die("cannot write keep file");
|
||||
} else {
|
||||
if (keep_msg_len > 0) {
|
||||
write_or_die(keep_fd, keep_msg, keep_msg_len);
|
||||
write_or_die(keep_fd, "\n", 1);
|
||||
}
|
||||
close(keep_fd);
|
||||
report = "keep";
|
||||
}
|
||||
close(keep_fd);
|
||||
}
|
||||
|
||||
if (final_pack_name != curr_pack_name) {
|
||||
@@ -818,6 +811,27 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
|
||||
if (move_temp_to_file(curr_index_name, final_index_name))
|
||||
die("cannot store index file");
|
||||
}
|
||||
|
||||
if (!from_stdin) {
|
||||
printf("%s\n", sha1_to_hex(sha1));
|
||||
} else {
|
||||
char buf[48];
|
||||
int len = snprintf(buf, sizeof(buf), "%s\t%s\n",
|
||||
report, sha1_to_hex(sha1));
|
||||
xwrite(1, buf, len);
|
||||
|
||||
/*
|
||||
* Let's just mimic git-unpack-objects here and write
|
||||
* the last part of the input buffer to stdout.
|
||||
*/
|
||||
while (input_len) {
|
||||
err = xwrite(1, input_buffer + input_offset, input_len);
|
||||
if (err <= 0)
|
||||
break;
|
||||
input_len -= err;
|
||||
input_offset += err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -841,6 +855,19 @@ int main(int argc, char **argv)
|
||||
keep_msg = "";
|
||||
} else if (!strncmp(arg, "--keep=", 7)) {
|
||||
keep_msg = arg + 7;
|
||||
} else if (!strncmp(arg, "--pack_header=", 14)) {
|
||||
struct pack_header *hdr;
|
||||
char *c;
|
||||
|
||||
hdr = (struct pack_header *)input_buffer;
|
||||
hdr->hdr_signature = htonl(PACK_SIGNATURE);
|
||||
hdr->hdr_version = htonl(strtoul(arg + 14, &c, 10));
|
||||
if (*c != ',')
|
||||
die("bad %s", arg);
|
||||
hdr->hdr_entries = htonl(strtoul(c + 1, &c, 10));
|
||||
if (*c)
|
||||
die("bad %s", arg);
|
||||
input_len = sizeof(*hdr);
|
||||
} else if (!strcmp(arg, "-v")) {
|
||||
verbose = 1;
|
||||
} else if (!strcmp(arg, "-o")) {
|
||||
@@ -921,8 +948,5 @@ int main(int argc, char **argv)
|
||||
free(index_name_buf);
|
||||
free(keep_name_buf);
|
||||
|
||||
if (!from_stdin)
|
||||
printf("%s\n", sha1_to_hex(sha1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
150
receive-pack.c
150
receive-pack.c
@@ -1,15 +1,17 @@
|
||||
#include "cache.h"
|
||||
#include "pack.h"
|
||||
#include "refs.h"
|
||||
#include "pkt-line.h"
|
||||
#include "run-command.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "commit.h"
|
||||
#include "object.h"
|
||||
#include <sys/wait.h>
|
||||
|
||||
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
|
||||
|
||||
static const char *unpacker[] = { "unpack-objects", NULL };
|
||||
|
||||
static int deny_non_fast_forwards = 0;
|
||||
static int unpack_limit = 5000;
|
||||
static int report_status;
|
||||
|
||||
static char capabilities[] = "report-status";
|
||||
@@ -25,6 +27,12 @@ static int receive_pack_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(var, "receive.unpacklimit") == 0)
|
||||
{
|
||||
unpack_limit = git_config_int(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -227,27 +235,127 @@ static void read_head_info(void)
|
||||
}
|
||||
}
|
||||
|
||||
static const char *parse_pack_header(struct pack_header *hdr)
|
||||
{
|
||||
char *c = (char*)hdr;
|
||||
ssize_t remaining = sizeof(struct pack_header);
|
||||
do {
|
||||
ssize_t r = xread(0, c, remaining);
|
||||
if (r <= 0)
|
||||
return "eof before pack header was fully read";
|
||||
remaining -= r;
|
||||
c += r;
|
||||
} while (remaining > 0);
|
||||
if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
|
||||
return "protocol error (pack signature mismatch detected)";
|
||||
if (!pack_version_ok(hdr->hdr_version))
|
||||
return "protocol error (pack version unsupported)";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *pack_lockfile;
|
||||
|
||||
static const char *unpack(void)
|
||||
{
|
||||
int code = run_command_v_opt(1, unpacker, RUN_GIT_CMD);
|
||||
struct pack_header hdr;
|
||||
const char *hdr_err;
|
||||
char hdr_arg[38];
|
||||
|
||||
switch (code) {
|
||||
case 0:
|
||||
return NULL;
|
||||
case -ERR_RUN_COMMAND_FORK:
|
||||
return "unpack fork failed";
|
||||
case -ERR_RUN_COMMAND_EXEC:
|
||||
return "unpack execute failed";
|
||||
case -ERR_RUN_COMMAND_WAITPID:
|
||||
return "waitpid failed";
|
||||
case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
|
||||
return "waitpid is confused";
|
||||
case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
|
||||
return "unpacker died of signal";
|
||||
case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
|
||||
return "unpacker died strangely";
|
||||
default:
|
||||
return "unpacker exited with error code";
|
||||
hdr_err = parse_pack_header(&hdr);
|
||||
if (hdr_err)
|
||||
return hdr_err;
|
||||
snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u",
|
||||
ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
|
||||
|
||||
if (ntohl(hdr.hdr_entries) < unpack_limit) {
|
||||
int code;
|
||||
const char *unpacker[3];
|
||||
unpacker[0] = "unpack-objects";
|
||||
unpacker[1] = hdr_arg;
|
||||
unpacker[2] = NULL;
|
||||
code = run_command_v_opt(1, unpacker, RUN_GIT_CMD);
|
||||
switch (code) {
|
||||
case 0:
|
||||
return NULL;
|
||||
case -ERR_RUN_COMMAND_FORK:
|
||||
return "unpack fork failed";
|
||||
case -ERR_RUN_COMMAND_EXEC:
|
||||
return "unpack execute failed";
|
||||
case -ERR_RUN_COMMAND_WAITPID:
|
||||
return "waitpid failed";
|
||||
case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
|
||||
return "waitpid is confused";
|
||||
case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
|
||||
return "unpacker died of signal";
|
||||
case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
|
||||
return "unpacker died strangely";
|
||||
default:
|
||||
return "unpacker exited with error code";
|
||||
}
|
||||
} else {
|
||||
const char *keeper[6];
|
||||
int fd[2], s, len, status;
|
||||
pid_t pid;
|
||||
char keep_arg[256];
|
||||
char packname[46];
|
||||
|
||||
s = sprintf(keep_arg, "--keep=receive-pack %i on ", getpid());
|
||||
if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
|
||||
strcpy(keep_arg + s, "localhost");
|
||||
|
||||
keeper[0] = "index-pack";
|
||||
keeper[1] = "--stdin";
|
||||
keeper[2] = "--fix-thin";
|
||||
keeper[3] = hdr_arg;
|
||||
keeper[4] = keep_arg;
|
||||
keeper[5] = NULL;
|
||||
|
||||
if (pipe(fd) < 0)
|
||||
return "index-pack pipe failed";
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return "index-pack fork failed";
|
||||
if (!pid) {
|
||||
dup2(fd[1], 1);
|
||||
close(fd[1]);
|
||||
close(fd[0]);
|
||||
execv_git_cmd(keeper);
|
||||
die("execv of index-pack failed");
|
||||
}
|
||||
close(fd[1]);
|
||||
|
||||
/*
|
||||
* The first thing we expects from index-pack's output
|
||||
* is "pack\t%40s\n" or "keep\t%40s\n" (46 bytes) where
|
||||
* %40s is the newly created pack SHA1 name. In the "keep"
|
||||
* case, we need it to remove the corresponding .keep file
|
||||
* later on. If we don't get that then tough luck with it.
|
||||
*/
|
||||
for (len = 0;
|
||||
len < 46 && (s = xread(fd[0], packname+len, 46-len)) > 0;
|
||||
len += s);
|
||||
close(fd[0]);
|
||||
if (len == 46 && packname[45] == '\n' &&
|
||||
memcmp(packname, "keep\t", 5) == 0) {
|
||||
char path[PATH_MAX];
|
||||
packname[45] = 0;
|
||||
snprintf(path, sizeof(path), "%s/pack/pack-%s.keep",
|
||||
get_object_directory(), packname + 5);
|
||||
pack_lockfile = xstrdup(path);
|
||||
}
|
||||
|
||||
/* Then wrap our index-pack process. */
|
||||
while (waitpid(pid, &status, 0) < 0)
|
||||
if (errno != EINTR)
|
||||
return "waitpid failed";
|
||||
if (WIFEXITED(status)) {
|
||||
int code = WEXITSTATUS(status);
|
||||
if (code)
|
||||
return "index-pack exited with error code";
|
||||
reprepare_packed_git();
|
||||
return NULL;
|
||||
}
|
||||
return "index-pack abnormal exit";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,6 +411,8 @@ int main(int argc, char **argv)
|
||||
const char *unpack_status = unpack();
|
||||
if (!unpack_status)
|
||||
execute_commands();
|
||||
if (pack_lockfile)
|
||||
unlink(pack_lockfile);
|
||||
if (report_status)
|
||||
report(unpack_status);
|
||||
}
|
||||
|
||||
@@ -663,7 +663,7 @@ void prepare_packed_git(void)
|
||||
prepare_packed_git_run_once = 1;
|
||||
}
|
||||
|
||||
static void reprepare_packed_git(void)
|
||||
void reprepare_packed_git(void)
|
||||
{
|
||||
prepare_packed_git_run_once = 0;
|
||||
prepare_packed_git();
|
||||
@@ -1417,8 +1417,7 @@ static int link_temp_to_file(const char *tmpfile, const char *filename)
|
||||
dir = strrchr(filename, '/');
|
||||
if (dir) {
|
||||
*dir = 0;
|
||||
mkdir(filename, 0777);
|
||||
if (adjust_shared_perm(filename)) {
|
||||
if (!mkdir(filename, 0777) && adjust_shared_perm(filename)) {
|
||||
*dir = '/';
|
||||
return -2;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user