Merge branch 'js/alias' into next
* js/alias: git alias: try alias last. If you have a config containing something like this: builtin-push: don't pass --thin to HTTP transport pack-objects: improve path grouping heuristics. rev-list: fix process_tree() conversion. Fix typo in tutorial-2.txt Fix Documentation/everyday.txt: Junio's workflow Add example xinetd(8) configuration to Documentation/everyday.txt read-tree: fix eye-candy. gitview: Add some useful keybindings.
This commit is contained in:
commit
c49b5a3c89
@ -336,15 +336,20 @@ master, nor exposed as a part of a stable branch.
|
|||||||
<11> make sure I did not accidentally rewind master beyond what I
|
<11> make sure I did not accidentally rewind master beyond what I
|
||||||
already pushed out. "ko" shorthand points at the repository I have
|
already pushed out. "ko" shorthand points at the repository I have
|
||||||
at kernel.org, and looks like this:
|
at kernel.org, and looks like this:
|
||||||
$ cat .git/remotes/ko
|
+
|
||||||
URL: kernel.org:/pub/scm/git/git.git
|
------------
|
||||||
Pull: master:refs/tags/ko-master
|
$ cat .git/remotes/ko
|
||||||
Pull: maint:refs/tags/ko-maint
|
URL: kernel.org:/pub/scm/git/git.git
|
||||||
Push: master
|
Pull: master:refs/tags/ko-master
|
||||||
Push: +pu
|
Pull: maint:refs/tags/ko-maint
|
||||||
Push: maint
|
Push: master
|
||||||
|
Push: +pu
|
||||||
|
Push: maint
|
||||||
|
------------
|
||||||
|
+
|
||||||
In the output from "git show-branch", "master" should have
|
In the output from "git show-branch", "master" should have
|
||||||
everything "ko-master" has.
|
everything "ko-master" has.
|
||||||
|
|
||||||
<12> push out the bleeding edge.
|
<12> push out the bleeding edge.
|
||||||
<13> push the tag out, too.
|
<13> push the tag out, too.
|
||||||
|
|
||||||
@ -377,6 +382,29 @@ git stream tcp nowait nobody \
|
|||||||
+
|
+
|
||||||
The actual configuration line should be on one line.
|
The actual configuration line should be on one line.
|
||||||
|
|
||||||
|
Run git-daemon to serve /pub/scm from xinetd.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ cat /etc/xinetd.d/git-daemon
|
||||||
|
# default: off
|
||||||
|
# description: The git server offers access to git repositories
|
||||||
|
service git
|
||||||
|
{
|
||||||
|
disable = no
|
||||||
|
type = UNLISTED
|
||||||
|
port = 9418
|
||||||
|
socket_type = stream
|
||||||
|
wait = no
|
||||||
|
user = nobody
|
||||||
|
server = /usr/bin/git-daemon
|
||||||
|
server_args = --inetd --syslog --export-all --base-path=/pub/scm
|
||||||
|
log_on_failure += USERID
|
||||||
|
}
|
||||||
|
------------
|
||||||
|
+
|
||||||
|
Check your xinetd(8) documentation and setup, this is from a Fedora system.
|
||||||
|
Others might be different.
|
||||||
|
|
||||||
Give push/pull only access to developers.::
|
Give push/pull only access to developers.::
|
||||||
+
|
+
|
||||||
------------
|
------------
|
||||||
|
@ -136,7 +136,7 @@ The "tree" object here refers to the new state of the tree:
|
|||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
$ git ls-tree d0492b36
|
$ git ls-tree d0492b36
|
||||||
100644 blob a0423896973644771497bdc03eb99d5281615b51 file.txt
|
100644 blob a0423896973644771497bdc03eb99d5281615b51 file.txt
|
||||||
$ git cat-file commit a0423896
|
$ git cat-file blob a0423896
|
||||||
hello world!
|
hello world!
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ static int do_push(const char *repo)
|
|||||||
{
|
{
|
||||||
const char *uri[MAX_URI];
|
const char *uri[MAX_URI];
|
||||||
int i, n;
|
int i, n;
|
||||||
int remote;
|
int common_argc;
|
||||||
const char **argv;
|
const char **argv;
|
||||||
int argc;
|
int argc;
|
||||||
|
|
||||||
@ -231,23 +231,25 @@ static int do_push(const char *repo)
|
|||||||
argv[argc++] = "--force";
|
argv[argc++] = "--force";
|
||||||
if (execute)
|
if (execute)
|
||||||
argv[argc++] = execute;
|
argv[argc++] = execute;
|
||||||
if (thin)
|
common_argc = argc;
|
||||||
argv[argc++] = "--thin";
|
|
||||||
remote = argc;
|
|
||||||
argv[argc++] = "dummy-remote";
|
|
||||||
while (refspec_nr--)
|
|
||||||
argv[argc++] = *refspec++;
|
|
||||||
argv[argc] = NULL;
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
int error;
|
int error;
|
||||||
|
int dest_argc = common_argc;
|
||||||
|
int dest_refspec_nr = refspec_nr;
|
||||||
|
const char **dest_refspec = refspec;
|
||||||
const char *dest = uri[i];
|
const char *dest = uri[i];
|
||||||
const char *sender = "git-send-pack";
|
const char *sender = "git-send-pack";
|
||||||
if (!strncmp(dest, "http://", 7) ||
|
if (!strncmp(dest, "http://", 7) ||
|
||||||
!strncmp(dest, "https://", 8))
|
!strncmp(dest, "https://", 8))
|
||||||
sender = "git-http-push";
|
sender = "git-http-push";
|
||||||
|
else if (thin)
|
||||||
|
argv[dest_argc++] = "--thin";
|
||||||
argv[0] = sender;
|
argv[0] = sender;
|
||||||
argv[remote] = dest;
|
argv[dest_argc++] = dest;
|
||||||
|
while (dest_refspec_nr--)
|
||||||
|
argv[dest_argc++] = *dest_refspec++;
|
||||||
|
argv[dest_argc] = NULL;
|
||||||
error = run_command_v(argc, argv);
|
error = run_command_v(argc, argv);
|
||||||
if (!error)
|
if (!error)
|
||||||
continue;
|
continue;
|
||||||
|
@ -377,6 +377,7 @@ static void check_updates(struct cache_entry **src, int nr)
|
|||||||
fprintf(stderr, "%4u%% (%u/%u) done\r",
|
fprintf(stderr, "%4u%% (%u/%u) done\r",
|
||||||
percent, cnt, total);
|
percent, cnt, total);
|
||||||
last_percent = percent;
|
last_percent = percent;
|
||||||
|
progress_update = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,9 +135,9 @@ static struct object_list **process_tree(struct tree *tree,
|
|||||||
|
|
||||||
while (tree_entry(&desc, &entry)) {
|
while (tree_entry(&desc, &entry)) {
|
||||||
if (S_ISDIR(entry.mode))
|
if (S_ISDIR(entry.mode))
|
||||||
p = process_tree(lookup_tree(entry.sha1), p, &me, name);
|
p = process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
|
||||||
else
|
else
|
||||||
p = process_blob(lookup_blob(entry.sha1), p, &me, name);
|
p = process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
|
||||||
}
|
}
|
||||||
free(tree->buffer);
|
free(tree->buffer);
|
||||||
tree->buffer = NULL;
|
tree->buffer = NULL;
|
||||||
|
@ -450,6 +450,9 @@ class GitView:
|
|||||||
self.accel_group = gtk.AccelGroup()
|
self.accel_group = gtk.AccelGroup()
|
||||||
self.window.add_accel_group(self.accel_group)
|
self.window.add_accel_group(self.accel_group)
|
||||||
self.accel_group.connect_group(0xffc2, 0, gtk.ACCEL_LOCKED, self.refresh);
|
self.accel_group.connect_group(0xffc2, 0, gtk.ACCEL_LOCKED, self.refresh);
|
||||||
|
self.accel_group.connect_group(0xffc1, 0, gtk.ACCEL_LOCKED, self.maximize);
|
||||||
|
self.accel_group.connect_group(0xffc8, 0, gtk.ACCEL_LOCKED, self.fullscreen);
|
||||||
|
self.accel_group.connect_group(0xffc9, 0, gtk.ACCEL_LOCKED, self.unfullscreen);
|
||||||
|
|
||||||
self.window.add(self.construct())
|
self.window.add(self.construct())
|
||||||
|
|
||||||
@ -461,6 +464,18 @@ class GitView:
|
|||||||
self.window.show()
|
self.window.show()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def maximize(self, widget, event=None, *arguments, **keywords):
|
||||||
|
self.window.maximize()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def fullscreen(self, widget, event=None, *arguments, **keywords):
|
||||||
|
self.window.fullscreen()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def unfullscreen(self, widget, event=None, *arguments, **keywords):
|
||||||
|
self.window.unfullscreen()
|
||||||
|
return True
|
||||||
|
|
||||||
def get_bt_sha1(self):
|
def get_bt_sha1(self):
|
||||||
""" Update the bt_sha1 dictionary with the
|
""" Update the bt_sha1 dictionary with the
|
||||||
respective sha1 details """
|
respective sha1 details """
|
||||||
|
@ -26,8 +26,14 @@ OPTIONS
|
|||||||
<args>
|
<args>
|
||||||
All the valid option for git-rev-list(1)
|
All the valid option for git-rev-list(1)
|
||||||
Key Bindings:
|
Key Bindings:
|
||||||
|
F4:
|
||||||
|
To maximize the window
|
||||||
F5:
|
F5:
|
||||||
To reread references.
|
To reread references.
|
||||||
|
F11:
|
||||||
|
Full screen
|
||||||
|
F12:
|
||||||
|
Leave full screen
|
||||||
|
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
------
|
------
|
||||||
|
127
git.c
127
git.c
@ -10,6 +10,7 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "git-compat-util.h"
|
#include "git-compat-util.h"
|
||||||
#include "exec_cmd.h"
|
#include "exec_cmd.h"
|
||||||
|
#include "cache.h"
|
||||||
|
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
|
||||||
@ -32,6 +33,113 @@ static void prepend_to_path(const char *dir, int len)
|
|||||||
setenv("PATH", path, 1);
|
setenv("PATH", path, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *alias_command;
|
||||||
|
static char *alias_string = NULL;
|
||||||
|
|
||||||
|
static int git_alias_config(const char *var, const char *value)
|
||||||
|
{
|
||||||
|
if (!strncmp(var, "alias.", 6) && !strcmp(var + 6, alias_command)) {
|
||||||
|
alias_string = strdup(value);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int split_cmdline(char *cmdline, const char ***argv)
|
||||||
|
{
|
||||||
|
int src, dst, count = 0, size = 16;
|
||||||
|
char quoted = 0;
|
||||||
|
|
||||||
|
*argv = malloc(sizeof(char*) * size);
|
||||||
|
|
||||||
|
/* split alias_string */
|
||||||
|
(*argv)[count++] = cmdline;
|
||||||
|
for (src = dst = 0; cmdline[src];) {
|
||||||
|
char c = cmdline[src];
|
||||||
|
if (!quoted && isspace(c)) {
|
||||||
|
cmdline[dst++] = 0;
|
||||||
|
while (cmdline[++src]
|
||||||
|
&& isspace(cmdline[src]))
|
||||||
|
; /* skip */
|
||||||
|
if (count >= size) {
|
||||||
|
size += 16;
|
||||||
|
*argv = realloc(*argv, sizeof(char*) * size);
|
||||||
|
}
|
||||||
|
(*argv)[count++] = cmdline + dst;
|
||||||
|
} else if(!quoted && (c == '\'' || c == '"')) {
|
||||||
|
quoted = c;
|
||||||
|
src++;
|
||||||
|
} else if (c == quoted) {
|
||||||
|
quoted = 0;
|
||||||
|
src++;
|
||||||
|
} else {
|
||||||
|
if (c == '\\' && quoted != '\'') {
|
||||||
|
src++;
|
||||||
|
c = cmdline[src];
|
||||||
|
if (!c) {
|
||||||
|
free(*argv);
|
||||||
|
*argv = NULL;
|
||||||
|
return error("cmdline ends with \\");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmdline[dst++] = c;
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdline[dst] = 0;
|
||||||
|
|
||||||
|
if (quoted) {
|
||||||
|
free(*argv);
|
||||||
|
*argv = NULL;
|
||||||
|
return error("unclosed quote");
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_alias(int *argcp, const char ***argv)
|
||||||
|
{
|
||||||
|
int nongit = 0, ret = 0;
|
||||||
|
const char *subdir;
|
||||||
|
|
||||||
|
subdir = setup_git_directory_gently(&nongit);
|
||||||
|
if (!nongit) {
|
||||||
|
int count;
|
||||||
|
const char** new_argv;
|
||||||
|
|
||||||
|
alias_command = (*argv)[0];
|
||||||
|
git_config(git_alias_config);
|
||||||
|
if (alias_string) {
|
||||||
|
|
||||||
|
count = split_cmdline(alias_string, &new_argv);
|
||||||
|
|
||||||
|
if (count < 1)
|
||||||
|
die("empty alias for %s", alias_command);
|
||||||
|
|
||||||
|
if (!strcmp(alias_command, new_argv[0]))
|
||||||
|
die("recursive alias: %s", alias_command);
|
||||||
|
|
||||||
|
/* insert after command name */
|
||||||
|
if (*argcp > 1) {
|
||||||
|
new_argv = realloc(new_argv, sizeof(char*) *
|
||||||
|
(count + *argcp - 1));
|
||||||
|
memcpy(new_argv + count, *argv, sizeof(char*) *
|
||||||
|
(*argcp - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
*argv = new_argv;
|
||||||
|
*argcp += count - 1;
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subdir)
|
||||||
|
chdir(subdir);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
const char git_version_string[] = GIT_VERSION;
|
const char git_version_string[] = GIT_VERSION;
|
||||||
|
|
||||||
static void handle_internal_command(int argc, const char **argv, char **envp)
|
static void handle_internal_command(int argc, const char **argv, char **envp)
|
||||||
@ -94,6 +202,7 @@ int main(int argc, const char **argv, char **envp)
|
|||||||
char *slash = strrchr(cmd, '/');
|
char *slash = strrchr(cmd, '/');
|
||||||
char git_command[PATH_MAX + 1];
|
char git_command[PATH_MAX + 1];
|
||||||
const char *exec_path = NULL;
|
const char *exec_path = NULL;
|
||||||
|
int done_alias = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Take the basename of argv[0] as the command
|
* Take the basename of argv[0] as the command
|
||||||
@ -178,11 +287,21 @@ int main(int argc, const char **argv, char **envp)
|
|||||||
exec_path = git_exec_path();
|
exec_path = git_exec_path();
|
||||||
prepend_to_path(exec_path, strlen(exec_path));
|
prepend_to_path(exec_path, strlen(exec_path));
|
||||||
|
|
||||||
/* See if it's an internal command */
|
while (1) {
|
||||||
handle_internal_command(argc, argv, envp);
|
/* See if it's an internal command */
|
||||||
|
handle_internal_command(argc, argv, envp);
|
||||||
|
|
||||||
/* .. then try the external ones */
|
/* .. then try the external ones */
|
||||||
execv_git_cmd(argv);
|
execv_git_cmd(argv);
|
||||||
|
|
||||||
|
/* It could be an alias -- this works around the insanity
|
||||||
|
* of overriding "git log" with "git show" by having
|
||||||
|
* alias.log = show
|
||||||
|
*/
|
||||||
|
if (done_alias || !handle_alias(&argc, &argv))
|
||||||
|
break;
|
||||||
|
done_alias = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
cmd_usage(0, exec_path, "'%s' is not a git-command", cmd);
|
cmd_usage(0, exec_path, "'%s' is not a git-command", cmd);
|
||||||
|
@ -463,48 +463,21 @@ static void rehash_objects(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct name_path {
|
static unsigned name_hash(const char *name)
|
||||||
struct name_path *up;
|
|
||||||
const char *elem;
|
|
||||||
int len;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DIRBITS 12
|
|
||||||
|
|
||||||
static unsigned name_hash(struct name_path *path, const char *name)
|
|
||||||
{
|
{
|
||||||
struct name_path *p = path;
|
unsigned char c;
|
||||||
const char *n = name + strlen(name);
|
unsigned hash = 0;
|
||||||
unsigned hash = 0, name_hash = 0, name_done = 0;
|
|
||||||
|
|
||||||
if (n != name && n[-1] == '\n')
|
|
||||||
n--;
|
|
||||||
while (name <= --n) {
|
|
||||||
unsigned char c = *n;
|
|
||||||
if (c == '/' && !name_done) {
|
|
||||||
name_hash = hash;
|
|
||||||
name_done = 1;
|
|
||||||
hash = 0;
|
|
||||||
}
|
|
||||||
hash = hash * 11 + c;
|
|
||||||
}
|
|
||||||
if (!name_done) {
|
|
||||||
name_hash = hash;
|
|
||||||
hash = 0;
|
|
||||||
}
|
|
||||||
for (p = path; p; p = p->up) {
|
|
||||||
hash = hash * 11 + '/';
|
|
||||||
n = p->elem + p->len;
|
|
||||||
while (p->elem <= --n) {
|
|
||||||
unsigned char c = *n;
|
|
||||||
hash = hash * 11 + c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* Make sure "Makefile" and "t/Makefile" are hashed separately
|
* This effectively just creates a sortable number from the
|
||||||
* but close enough.
|
* last sixteen non-whitespace characters. Last characters
|
||||||
|
* count "most", so things that end in ".c" sort together.
|
||||||
*/
|
*/
|
||||||
hash = (name_hash<<DIRBITS) | (hash & ((1U<<DIRBITS )-1));
|
while ((c = *name++) != 0) {
|
||||||
|
if (isspace(c))
|
||||||
|
continue;
|
||||||
|
hash = (hash >> 2) + (c << 24);
|
||||||
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,9 +659,9 @@ static int name_cmp_len(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void add_pbase_object(struct tree_desc *tree,
|
static void add_pbase_object(struct tree_desc *tree,
|
||||||
struct name_path *up,
|
|
||||||
const char *name,
|
const char *name,
|
||||||
int cmplen)
|
int cmplen,
|
||||||
|
const char *fullname)
|
||||||
{
|
{
|
||||||
struct name_entry entry;
|
struct name_entry entry;
|
||||||
|
|
||||||
@ -702,13 +675,12 @@ static void add_pbase_object(struct tree_desc *tree,
|
|||||||
sha1_object_info(entry.sha1, type, &size))
|
sha1_object_info(entry.sha1, type, &size))
|
||||||
continue;
|
continue;
|
||||||
if (name[cmplen] != '/') {
|
if (name[cmplen] != '/') {
|
||||||
unsigned hash = name_hash(up, name);
|
unsigned hash = name_hash(fullname);
|
||||||
add_object_entry(entry.sha1, hash, 1);
|
add_object_entry(entry.sha1, hash, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!strcmp(type, tree_type)) {
|
if (!strcmp(type, tree_type)) {
|
||||||
struct tree_desc sub;
|
struct tree_desc sub;
|
||||||
struct name_path me;
|
|
||||||
struct pbase_tree_cache *tree;
|
struct pbase_tree_cache *tree;
|
||||||
const char *down = name+cmplen+1;
|
const char *down = name+cmplen+1;
|
||||||
int downlen = name_cmp_len(down);
|
int downlen = name_cmp_len(down);
|
||||||
@ -719,10 +691,7 @@ static void add_pbase_object(struct tree_desc *tree,
|
|||||||
sub.buf = tree->tree_data;
|
sub.buf = tree->tree_data;
|
||||||
sub.size = tree->tree_size;
|
sub.size = tree->tree_size;
|
||||||
|
|
||||||
me.up = up;
|
add_pbase_object(&sub, down, downlen, fullname);
|
||||||
me.elem = entry.path;
|
|
||||||
me.len = entry.pathlen;
|
|
||||||
add_pbase_object(&sub, &me, down, downlen);
|
|
||||||
pbase_tree_put(tree);
|
pbase_tree_put(tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -778,14 +747,14 @@ static void add_preferred_base_object(char *name, unsigned hash)
|
|||||||
|
|
||||||
for (it = pbase_tree; it; it = it->next) {
|
for (it = pbase_tree; it; it = it->next) {
|
||||||
if (cmplen == 0) {
|
if (cmplen == 0) {
|
||||||
hash = name_hash(NULL, "");
|
hash = name_hash("");
|
||||||
add_object_entry(it->pcache.sha1, hash, 1);
|
add_object_entry(it->pcache.sha1, hash, 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
struct tree_desc tree;
|
struct tree_desc tree;
|
||||||
tree.buf = it->pcache.tree_data;
|
tree.buf = it->pcache.tree_data;
|
||||||
tree.size = it->pcache.tree_size;
|
tree.size = it->pcache.tree_size;
|
||||||
add_pbase_object(&tree, NULL, name, cmplen);
|
add_pbase_object(&tree, name, cmplen, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1328,7 +1297,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
if (get_sha1_hex(line, sha1))
|
if (get_sha1_hex(line, sha1))
|
||||||
die("expected sha1, got garbage:\n %s", line);
|
die("expected sha1, got garbage:\n %s", line);
|
||||||
hash = name_hash(NULL, line+41);
|
hash = name_hash(line+41);
|
||||||
add_preferred_base_object(line+41, hash);
|
add_preferred_base_object(line+41, hash);
|
||||||
add_object_entry(sha1, hash, 0);
|
add_object_entry(sha1, hash, 0);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user