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
|
||||
already pushed out. "ko" shorthand points at the repository I have
|
||||
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
|
||||
Pull: maint:refs/tags/ko-maint
|
||||
Push: master
|
||||
Push: +pu
|
||||
Push: maint
|
||||
+
|
||||
------------
|
||||
$ cat .git/remotes/ko
|
||||
URL: kernel.org:/pub/scm/git/git.git
|
||||
Pull: master:refs/tags/ko-master
|
||||
Pull: maint:refs/tags/ko-maint
|
||||
Push: master
|
||||
Push: +pu
|
||||
Push: maint
|
||||
------------
|
||||
+
|
||||
In the output from "git show-branch", "master" should have
|
||||
everything "ko-master" has.
|
||||
|
||||
<12> push out the bleeding edge.
|
||||
<13> push the tag out, too.
|
||||
|
||||
@ -377,6 +382,29 @@ git stream tcp nowait nobody \
|
||||
+
|
||||
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.::
|
||||
+
|
||||
------------
|
||||
|
@ -136,7 +136,7 @@ The "tree" object here refers to the new state of the tree:
|
||||
------------------------------------------------
|
||||
$ git ls-tree d0492b36
|
||||
100644 blob a0423896973644771497bdc03eb99d5281615b51 file.txt
|
||||
$ git cat-file commit a0423896
|
||||
$ git cat-file blob a0423896
|
||||
hello world!
|
||||
------------------------------------------------
|
||||
|
||||
|
@ -214,7 +214,7 @@ static int do_push(const char *repo)
|
||||
{
|
||||
const char *uri[MAX_URI];
|
||||
int i, n;
|
||||
int remote;
|
||||
int common_argc;
|
||||
const char **argv;
|
||||
int argc;
|
||||
|
||||
@ -231,23 +231,25 @@ static int do_push(const char *repo)
|
||||
argv[argc++] = "--force";
|
||||
if (execute)
|
||||
argv[argc++] = execute;
|
||||
if (thin)
|
||||
argv[argc++] = "--thin";
|
||||
remote = argc;
|
||||
argv[argc++] = "dummy-remote";
|
||||
while (refspec_nr--)
|
||||
argv[argc++] = *refspec++;
|
||||
argv[argc] = NULL;
|
||||
common_argc = argc;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
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 *sender = "git-send-pack";
|
||||
if (!strncmp(dest, "http://", 7) ||
|
||||
!strncmp(dest, "https://", 8))
|
||||
sender = "git-http-push";
|
||||
else if (thin)
|
||||
argv[dest_argc++] = "--thin";
|
||||
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);
|
||||
if (!error)
|
||||
continue;
|
||||
|
@ -377,6 +377,7 @@ static void check_updates(struct cache_entry **src, int nr)
|
||||
fprintf(stderr, "%4u%% (%u/%u) done\r",
|
||||
percent, cnt, total);
|
||||
last_percent = percent;
|
||||
progress_update = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -135,9 +135,9 @@ static struct object_list **process_tree(struct tree *tree,
|
||||
|
||||
while (tree_entry(&desc, &entry)) {
|
||||
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
|
||||
p = process_blob(lookup_blob(entry.sha1), p, &me, name);
|
||||
p = process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
|
||||
}
|
||||
free(tree->buffer);
|
||||
tree->buffer = NULL;
|
||||
|
@ -450,6 +450,9 @@ class GitView:
|
||||
self.accel_group = gtk.AccelGroup()
|
||||
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(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())
|
||||
|
||||
@ -461,6 +464,18 @@ class GitView:
|
||||
self.window.show()
|
||||
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):
|
||||
""" Update the bt_sha1 dictionary with the
|
||||
respective sha1 details """
|
||||
|
@ -26,8 +26,14 @@ OPTIONS
|
||||
<args>
|
||||
All the valid option for git-rev-list(1)
|
||||
Key Bindings:
|
||||
F4:
|
||||
To maximize the window
|
||||
F5:
|
||||
To reread references.
|
||||
F11:
|
||||
Full screen
|
||||
F12:
|
||||
Leave full screen
|
||||
|
||||
EXAMPLES
|
||||
------
|
||||
|
127
git.c
127
git.c
@ -10,6 +10,7 @@
|
||||
#include <stdarg.h>
|
||||
#include "git-compat-util.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "cache.h"
|
||||
|
||||
#include "builtin.h"
|
||||
|
||||
@ -32,6 +33,113 @@ static void prepend_to_path(const char *dir, int len)
|
||||
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;
|
||||
|
||||
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 git_command[PATH_MAX + 1];
|
||||
const char *exec_path = NULL;
|
||||
int done_alias = 0;
|
||||
|
||||
/*
|
||||
* 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();
|
||||
prepend_to_path(exec_path, strlen(exec_path));
|
||||
|
||||
/* See if it's an internal command */
|
||||
handle_internal_command(argc, argv, envp);
|
||||
while (1) {
|
||||
/* See if it's an internal command */
|
||||
handle_internal_command(argc, argv, envp);
|
||||
|
||||
/* .. then try the external ones */
|
||||
execv_git_cmd(argv);
|
||||
/* .. then try the external ones */
|
||||
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)
|
||||
cmd_usage(0, exec_path, "'%s' is not a git-command", cmd);
|
||||
|
@ -463,48 +463,21 @@ static void rehash_objects(void)
|
||||
}
|
||||
}
|
||||
|
||||
struct name_path {
|
||||
struct name_path *up;
|
||||
const char *elem;
|
||||
int len;
|
||||
};
|
||||
|
||||
#define DIRBITS 12
|
||||
|
||||
static unsigned name_hash(struct name_path *path, const char *name)
|
||||
static unsigned name_hash(const char *name)
|
||||
{
|
||||
struct name_path *p = path;
|
||||
const char *n = name + strlen(name);
|
||||
unsigned hash = 0, name_hash = 0, name_done = 0;
|
||||
unsigned char c;
|
||||
unsigned hash = 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
|
||||
* but close enough.
|
||||
* This effectively just creates a sortable number from the
|
||||
* 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;
|
||||
}
|
||||
|
||||
@ -686,9 +659,9 @@ static int name_cmp_len(const char *name)
|
||||
}
|
||||
|
||||
static void add_pbase_object(struct tree_desc *tree,
|
||||
struct name_path *up,
|
||||
const char *name,
|
||||
int cmplen)
|
||||
int cmplen,
|
||||
const char *fullname)
|
||||
{
|
||||
struct name_entry entry;
|
||||
|
||||
@ -702,13 +675,12 @@ static void add_pbase_object(struct tree_desc *tree,
|
||||
sha1_object_info(entry.sha1, type, &size))
|
||||
continue;
|
||||
if (name[cmplen] != '/') {
|
||||
unsigned hash = name_hash(up, name);
|
||||
unsigned hash = name_hash(fullname);
|
||||
add_object_entry(entry.sha1, hash, 1);
|
||||
return;
|
||||
}
|
||||
if (!strcmp(type, tree_type)) {
|
||||
struct tree_desc sub;
|
||||
struct name_path me;
|
||||
struct pbase_tree_cache *tree;
|
||||
const char *down = name+cmplen+1;
|
||||
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.size = tree->tree_size;
|
||||
|
||||
me.up = up;
|
||||
me.elem = entry.path;
|
||||
me.len = entry.pathlen;
|
||||
add_pbase_object(&sub, &me, down, downlen);
|
||||
add_pbase_object(&sub, down, downlen, fullname);
|
||||
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) {
|
||||
if (cmplen == 0) {
|
||||
hash = name_hash(NULL, "");
|
||||
hash = name_hash("");
|
||||
add_object_entry(it->pcache.sha1, hash, 1);
|
||||
}
|
||||
else {
|
||||
struct tree_desc tree;
|
||||
tree.buf = it->pcache.tree_data;
|
||||
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))
|
||||
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_object_entry(sha1, hash, 0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user