Merge branch 'master' into jc/fmt-patch
* master: Split up builtin commands into separate files from git.c git-log produces no output fix pack-object buffer size mailinfo: decode underscore used in "Q" encoding properly. Reintroduce svn pools to solve the memory leak. pack-objects: do not stop at object that is "too small" git-commit --amend: two fixes. get_tree_entry(): make it available from tree-walk sha1_name.c: no need to include diff.h; tree-walk.h will do. sha1_name.c: prepare to make get_tree_entry() reusable from others. get_sha1() shorthands for blob/tree objects pre-commit hook: complain about conflict markers. git-merge: a bit more readable user guidance. diff: move diff.c to diff-lib.c to make room. git log: don't do merge diffs by default Allow "git repack" users to specify repacking window/depth Document git-clone --reference Fix filename scaling for binary files Fix uninteresting tags in new revision parsing Conflicts: Adjusted the addition of fmt-patch to match the recent split from git.c to builtin.log.c.
This commit is contained in:
commit
91efcf6065
@ -10,6 +10,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-clone' [-l [-s]] [-q] [-n] [--bare] [-o <name>] [-u <upload-pack>]
|
||||
[--reference <repository>]
|
||||
<repository> [<directory>]
|
||||
|
||||
DESCRIPTION
|
||||
@ -46,10 +47,18 @@ OPTIONS
|
||||
-s::
|
||||
When the repository to clone is on the local machine,
|
||||
instead of using hard links, automatically setup
|
||||
.git/objects/info/alternatives to share the objects
|
||||
.git/objects/info/alternates to share the objects
|
||||
with the source repository. The resulting repository
|
||||
starts out without any object of its own.
|
||||
|
||||
--reference <repository>::
|
||||
If the reference repository is on the local machine
|
||||
automatically setup .git/objects/info/alternates to
|
||||
obtain objects from the reference repository. Using
|
||||
an already existing repository as an alternate will
|
||||
require less objects to be copied from the repository
|
||||
being cloned, reducing network and local storage costs.
|
||||
|
||||
--quiet::
|
||||
-q::
|
||||
Operate quietly. This flag is passed to "rsync" and
|
||||
@ -112,6 +121,16 @@ $ git show-branch
|
||||
------------
|
||||
|
||||
|
||||
Clone from upstream while borrowing from an existing local directory::
|
||||
+
|
||||
------------
|
||||
$ git clone --reference my2.6 \
|
||||
git://git.kernel.org/pub/scm/.../linux-2.7 \
|
||||
my2.7
|
||||
$ cd my2.7
|
||||
------------
|
||||
|
||||
|
||||
Create a bare repository to publish your changes to the public::
|
||||
+
|
||||
------------
|
||||
|
11
Makefile
11
Makefile
@ -199,7 +199,7 @@ LIB_H = \
|
||||
tree-walk.h log-tree.h
|
||||
|
||||
DIFF_OBJS = \
|
||||
diff.o diffcore-break.o diffcore-order.o \
|
||||
diff-lib.o diffcore-break.o diffcore-order.o \
|
||||
diffcore-pickaxe.o diffcore-rename.o tree-diff.o combine-diff.o \
|
||||
diffcore-delta.o log-tree.o
|
||||
|
||||
@ -213,6 +213,9 @@ LIB_OBJS = \
|
||||
fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
|
||||
$(DIFF_OBJS)
|
||||
|
||||
BUILTIN_OBJS = \
|
||||
builtin-log.o builtin-help.o
|
||||
|
||||
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
|
||||
LIBS = $(GITLIBS) -lz
|
||||
|
||||
@ -462,10 +465,10 @@ all:
|
||||
strip: $(PROGRAMS) git$X
|
||||
$(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
|
||||
|
||||
git$X: git.c common-cmds.h $(GITLIBS)
|
||||
git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS)
|
||||
$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
|
||||
$(ALL_CFLAGS) -o $@ $(filter %.c,$^) \
|
||||
$(ALL_LDFLAGS) $(LIBS)
|
||||
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
|
||||
|
||||
$(BUILT_INS): git$X
|
||||
rm -f $@ && ln git$X $@
|
||||
@ -565,7 +568,7 @@ init-db.o: init-db.c
|
||||
$(CC) -c $(ALL_CFLAGS) \
|
||||
-DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c
|
||||
|
||||
$(LIB_OBJS): $(LIB_H)
|
||||
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
|
||||
$(patsubst git-%$X,%.o,$(PROGRAMS)): $(GITLIBS)
|
||||
$(DIFF_OBJS): diffcore.h
|
||||
|
||||
|
241
builtin-help.c
Normal file
241
builtin-help.c
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* builtin-help.c
|
||||
*
|
||||
* Builtin help-related commands (help, usage, version)
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "common-cmds.h"
|
||||
|
||||
static const char git_usage[] =
|
||||
"Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
|
||||
|
||||
/* most gui terms set COLUMNS (although some don't export it) */
|
||||
static int term_columns(void)
|
||||
{
|
||||
char *col_string = getenv("COLUMNS");
|
||||
int n_cols = 0;
|
||||
|
||||
if (col_string && (n_cols = atoi(col_string)) > 0)
|
||||
return n_cols;
|
||||
|
||||
#ifdef TIOCGWINSZ
|
||||
{
|
||||
struct winsize ws;
|
||||
if (!ioctl(1, TIOCGWINSZ, &ws)) {
|
||||
if (ws.ws_col)
|
||||
return ws.ws_col;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 80;
|
||||
}
|
||||
|
||||
static void oom(void)
|
||||
{
|
||||
fprintf(stderr, "git: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static inline void mput_char(char c, unsigned int num)
|
||||
{
|
||||
while(num--)
|
||||
putchar(c);
|
||||
}
|
||||
|
||||
static struct cmdname {
|
||||
size_t len;
|
||||
char name[1];
|
||||
} **cmdname;
|
||||
static int cmdname_alloc, cmdname_cnt;
|
||||
|
||||
static void add_cmdname(const char *name, int len)
|
||||
{
|
||||
struct cmdname *ent;
|
||||
if (cmdname_alloc <= cmdname_cnt) {
|
||||
cmdname_alloc = cmdname_alloc + 200;
|
||||
cmdname = realloc(cmdname, cmdname_alloc * sizeof(*cmdname));
|
||||
if (!cmdname)
|
||||
oom();
|
||||
}
|
||||
ent = malloc(sizeof(*ent) + len);
|
||||
if (!ent)
|
||||
oom();
|
||||
ent->len = len;
|
||||
memcpy(ent->name, name, len);
|
||||
ent->name[len] = 0;
|
||||
cmdname[cmdname_cnt++] = ent;
|
||||
}
|
||||
|
||||
static int cmdname_compare(const void *a_, const void *b_)
|
||||
{
|
||||
struct cmdname *a = *(struct cmdname **)a_;
|
||||
struct cmdname *b = *(struct cmdname **)b_;
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
static void pretty_print_string_list(struct cmdname **cmdname, int longest)
|
||||
{
|
||||
int cols = 1, rows;
|
||||
int space = longest + 1; /* min 1 SP between words */
|
||||
int max_cols = term_columns() - 1; /* don't print *on* the edge */
|
||||
int i, j;
|
||||
|
||||
if (space < max_cols)
|
||||
cols = max_cols / space;
|
||||
rows = (cmdname_cnt + cols - 1) / cols;
|
||||
|
||||
qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);
|
||||
|
||||
for (i = 0; i < rows; i++) {
|
||||
printf(" ");
|
||||
|
||||
for (j = 0; j < cols; j++) {
|
||||
int n = j * rows + i;
|
||||
int size = space;
|
||||
if (n >= cmdname_cnt)
|
||||
break;
|
||||
if (j == cols-1 || n + rows >= cmdname_cnt)
|
||||
size = 1;
|
||||
printf("%-*s", size, cmdname[n]->name);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
static void list_commands(const char *exec_path, const char *pattern)
|
||||
{
|
||||
unsigned int longest = 0;
|
||||
char path[PATH_MAX];
|
||||
int dirlen;
|
||||
DIR *dir = opendir(exec_path);
|
||||
struct dirent *de;
|
||||
|
||||
if (!dir) {
|
||||
fprintf(stderr, "git: '%s': %s\n", exec_path, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dirlen = strlen(exec_path);
|
||||
if (PATH_MAX - 20 < dirlen) {
|
||||
fprintf(stderr, "git: insanely long exec-path '%s'\n",
|
||||
exec_path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memcpy(path, exec_path, dirlen);
|
||||
path[dirlen++] = '/';
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
struct stat st;
|
||||
int entlen;
|
||||
|
||||
if (strncmp(de->d_name, "git-", 4))
|
||||
continue;
|
||||
strcpy(path+dirlen, de->d_name);
|
||||
if (stat(path, &st) || /* stat, not lstat */
|
||||
!S_ISREG(st.st_mode) ||
|
||||
!(st.st_mode & S_IXUSR))
|
||||
continue;
|
||||
|
||||
entlen = strlen(de->d_name);
|
||||
if (4 < entlen && !strcmp(de->d_name + entlen - 4, ".exe"))
|
||||
entlen -= 4;
|
||||
|
||||
if (longest < entlen)
|
||||
longest = entlen;
|
||||
|
||||
add_cmdname(de->d_name + 4, entlen-4);
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
printf("git commands available in '%s'\n", exec_path);
|
||||
printf("----------------------------");
|
||||
mput_char('-', strlen(exec_path));
|
||||
putchar('\n');
|
||||
pretty_print_string_list(cmdname, longest - 4);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void list_common_cmds_help(void)
|
||||
{
|
||||
int i, longest = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
|
||||
if (longest < strlen(common_cmds[i].name))
|
||||
longest = strlen(common_cmds[i].name);
|
||||
}
|
||||
|
||||
puts("The most commonly used git commands are:");
|
||||
for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
|
||||
printf(" %s", common_cmds[i].name);
|
||||
mput_char(' ', longest - strlen(common_cmds[i].name) + 4);
|
||||
puts(common_cmds[i].help);
|
||||
}
|
||||
puts("(use 'git help -a' to get a list of all installed git commands)");
|
||||
}
|
||||
|
||||
void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...)
|
||||
{
|
||||
if (fmt) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
printf("git: ");
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
putchar('\n');
|
||||
}
|
||||
else
|
||||
puts(git_usage);
|
||||
|
||||
if (exec_path) {
|
||||
putchar('\n');
|
||||
if (show_all)
|
||||
list_commands(exec_path, "git-*");
|
||||
else
|
||||
list_common_cmds_help();
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void show_man_page(const char *git_cmd)
|
||||
{
|
||||
const char *page;
|
||||
|
||||
if (!strncmp(git_cmd, "git", 3))
|
||||
page = git_cmd;
|
||||
else {
|
||||
int page_len = strlen(git_cmd) + 4;
|
||||
char *p = malloc(page_len + 1);
|
||||
strcpy(p, "git-");
|
||||
strcpy(p + 4, git_cmd);
|
||||
p[page_len] = 0;
|
||||
page = p;
|
||||
}
|
||||
|
||||
execlp("man", "man", page, NULL);
|
||||
}
|
||||
|
||||
int cmd_version(int argc, const char **argv, char **envp)
|
||||
{
|
||||
printf("git version %s\n", git_version_string);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_help(int argc, const char **argv, char **envp)
|
||||
{
|
||||
const char *help_cmd = argv[1];
|
||||
if (!help_cmd)
|
||||
cmd_usage(0, git_exec_path(), NULL);
|
||||
else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a"))
|
||||
cmd_usage(1, git_exec_path(), NULL);
|
||||
else
|
||||
show_man_page(help_cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
108
builtin-log.c
Normal file
108
builtin-log.c
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Builtin "git log" and related commands (show, whatchanged)
|
||||
*
|
||||
* (C) Copyright 2006 Linus Torvalds
|
||||
* 2006 Junio Hamano
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "log-tree.h"
|
||||
#include "builtin.h"
|
||||
|
||||
static int cmd_log_wc(int argc, const char **argv, char **envp,
|
||||
struct rev_info *rev)
|
||||
{
|
||||
struct commit *commit;
|
||||
|
||||
rev->abbrev = DEFAULT_ABBREV;
|
||||
rev->commit_format = CMIT_FMT_DEFAULT;
|
||||
rev->verbose_header = 1;
|
||||
argc = setup_revisions(argc, argv, rev, "HEAD");
|
||||
|
||||
if (argc > 1)
|
||||
die("unrecognized argument: %s", argv[1]);
|
||||
|
||||
prepare_revision_walk(rev);
|
||||
setup_pager();
|
||||
while ((commit = get_revision(rev)) != NULL) {
|
||||
log_tree_commit(rev, commit);
|
||||
free(commit->buffer);
|
||||
commit->buffer = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_whatchanged(int argc, const char **argv, char **envp)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
init_revisions(&rev);
|
||||
rev.diff = 1;
|
||||
rev.diffopt.recursive = 1;
|
||||
return cmd_log_wc(argc, argv, envp, &rev);
|
||||
}
|
||||
|
||||
int cmd_show(int argc, const char **argv, char **envp)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
init_revisions(&rev);
|
||||
rev.diff = 1;
|
||||
rev.diffopt.recursive = 1;
|
||||
rev.combine_merges = 1;
|
||||
rev.dense_combined_merges = 1;
|
||||
rev.always_show_header = 1;
|
||||
rev.ignore_merges = 0;
|
||||
rev.no_walk = 1;
|
||||
return cmd_log_wc(argc, argv, envp, &rev);
|
||||
}
|
||||
|
||||
int cmd_log(int argc, const char **argv, char **envp)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
init_revisions(&rev);
|
||||
rev.always_show_header = 1;
|
||||
rev.diffopt.recursive = 1;
|
||||
return cmd_log_wc(argc, argv, envp, &rev);
|
||||
}
|
||||
|
||||
int cmd_format_patch(int argc, const char **argv, char **envp)
|
||||
{
|
||||
struct commit *commit;
|
||||
struct commit **list = NULL;
|
||||
struct rev_info rev;
|
||||
int nr = 0;
|
||||
|
||||
init_revisions(&rev);
|
||||
rev.commit_format = CMIT_FMT_EMAIL;
|
||||
rev.verbose_header = 1;
|
||||
rev.diff = 1;
|
||||
rev.diffopt.with_raw = 0;
|
||||
rev.diffopt.with_stat = 1;
|
||||
rev.combine_merges = 0;
|
||||
rev.ignore_merges = 1;
|
||||
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
|
||||
argc = setup_revisions(argc, argv, &rev, "HEAD");
|
||||
|
||||
prepare_revision_walk(&rev);
|
||||
while ((commit = get_revision(&rev)) != NULL) {
|
||||
nr++;
|
||||
list = realloc(list, nr * sizeof(list[0]));
|
||||
list[nr - 1] = commit;
|
||||
}
|
||||
while (0 <= --nr) {
|
||||
int shown;
|
||||
commit = list[nr];
|
||||
shown = log_tree_commit(&rev, commit);
|
||||
free(commit->buffer);
|
||||
commit->buffer = NULL;
|
||||
if (shown)
|
||||
printf("-- \n%s\n\n", git_version_string);
|
||||
}
|
||||
free(list);
|
||||
return 0;
|
||||
}
|
||||
|
24
builtin.h
Normal file
24
builtin.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef BUILTIN_H
|
||||
#define BUILTIN_H
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
extern const char git_version_string[];
|
||||
|
||||
void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((__format__(__printf__, 3, 4), __noreturn__))
|
||||
#endif
|
||||
;
|
||||
|
||||
extern int cmd_help(int argc, const char **argv, char **envp);
|
||||
extern int cmd_version(int argc, const char **argv, char **envp);
|
||||
|
||||
extern int cmd_whatchanged(int argc, const char **argv, char **envp);
|
||||
extern int cmd_show(int argc, const char **argv, char **envp);
|
||||
extern int cmd_log(int argc, const char **argv, char **envp);
|
||||
extern int cmd_format_patch(int argc, const char **argv, char **envp);
|
||||
|
||||
#endif
|
@ -250,13 +250,14 @@ static void show_stats(struct diffstat_t* data)
|
||||
for (i = 0; i < data->nr; i++) {
|
||||
struct diffstat_file *file = data->files[i];
|
||||
|
||||
len = strlen(file->name);
|
||||
if (max_len < len)
|
||||
max_len = len;
|
||||
|
||||
if (file->is_binary || file->is_unmerged)
|
||||
continue;
|
||||
if (max_change < file->added + file->deleted)
|
||||
max_change = file->added + file->deleted;
|
||||
len = strlen(file->name);
|
||||
if (max_len < len)
|
||||
max_len = len;
|
||||
}
|
||||
|
||||
for (i = 0; i < data->nr; i++) {
|
@ -167,8 +167,13 @@ run_status () {
|
||||
fi
|
||||
case "$committable" in
|
||||
0)
|
||||
echo "nothing to commit"
|
||||
exit 1
|
||||
case "$amend" in
|
||||
t)
|
||||
echo "# No changes" ;;
|
||||
*)
|
||||
echo "nothing to commit" ;;
|
||||
esac
|
||||
exit 1 ;;
|
||||
esac
|
||||
exit 0
|
||||
)
|
||||
@ -365,14 +370,16 @@ tt*)
|
||||
die "Only one of -c/-C/-F/-m can be used." ;;
|
||||
esac
|
||||
|
||||
case "$#,$also$only" in
|
||||
*,tt)
|
||||
case "$#,$also,$only,$amend" in
|
||||
*,t,t,*)
|
||||
die "Only one of --include/--only can be used." ;;
|
||||
0,t)
|
||||
0,t,,* | 0,,t,)
|
||||
die "No paths with --include/--only does not make sense." ;;
|
||||
0,)
|
||||
0,,t,t)
|
||||
only_include_assumed="# Clever... amending the last one with dirty index." ;;
|
||||
0,,,*)
|
||||
;;
|
||||
*,)
|
||||
*,,,*)
|
||||
only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
|
||||
also=
|
||||
;;
|
||||
|
@ -335,5 +335,5 @@ Conflicts:
|
||||
then
|
||||
git-rerere
|
||||
fi
|
||||
die "Automatic merge failed; fix up by hand"
|
||||
die "Automatic merge failed; fix conflicts and then commit the result."
|
||||
fi
|
||||
|
@ -7,7 +7,7 @@ USAGE='[-a] [-d] [-f] [-l] [-n] [-q]'
|
||||
. git-sh-setup
|
||||
|
||||
no_update_info= all_into_one= remove_redundant=
|
||||
local= quiet= no_reuse_delta=
|
||||
local= quiet= no_reuse_delta= extra=
|
||||
while case "$#" in 0) break ;; esac
|
||||
do
|
||||
case "$1" in
|
||||
@ -17,6 +17,8 @@ do
|
||||
-q) quiet=-q ;;
|
||||
-f) no_reuse_delta=--no-reuse-delta ;;
|
||||
-l) local=--local ;;
|
||||
--window=*) extra="$extra $1" ;;
|
||||
--depth=*) extra="$extra $1" ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
shift
|
||||
@ -40,7 +42,7 @@ case ",$all_into_one," in
|
||||
find . -type f \( -name '*.pack' -o -name '*.idx' \) -print`
|
||||
;;
|
||||
esac
|
||||
pack_objects="$pack_objects $local $quiet $no_reuse_delta"
|
||||
pack_objects="$pack_objects $local $quiet $no_reuse_delta$extra"
|
||||
name=$(git-rev-list --objects --all $rev_list 2>&1 |
|
||||
git-pack-objects --non-empty $pack_objects .tmp-pack) ||
|
||||
exit 1
|
||||
|
@ -136,8 +136,10 @@ sub file {
|
||||
|
||||
print "... $rev $path ...\n" if $opt_v;
|
||||
my (undef, $properties);
|
||||
my $pool = SVN::Pool->new();
|
||||
eval { (undef, $properties)
|
||||
= $self->{'svn'}->get_file($path,$rev,$fh); };
|
||||
= $self->{'svn'}->get_file($path,$rev,$fh,$pool); };
|
||||
$pool->clear;
|
||||
if($@) {
|
||||
return undef if $@ =~ /Attempted to get checksum/;
|
||||
die $@;
|
||||
|
344
git.c
344
git.c
@ -11,215 +11,8 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include "git-compat-util.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "common-cmds.h"
|
||||
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "log-tree.h"
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
static const char git_usage[] =
|
||||
"Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
|
||||
|
||||
/* most gui terms set COLUMNS (although some don't export it) */
|
||||
static int term_columns(void)
|
||||
{
|
||||
char *col_string = getenv("COLUMNS");
|
||||
int n_cols = 0;
|
||||
|
||||
if (col_string && (n_cols = atoi(col_string)) > 0)
|
||||
return n_cols;
|
||||
|
||||
#ifdef TIOCGWINSZ
|
||||
{
|
||||
struct winsize ws;
|
||||
if (!ioctl(1, TIOCGWINSZ, &ws)) {
|
||||
if (ws.ws_col)
|
||||
return ws.ws_col;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 80;
|
||||
}
|
||||
|
||||
static void oom(void)
|
||||
{
|
||||
fprintf(stderr, "git: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static inline void mput_char(char c, unsigned int num)
|
||||
{
|
||||
while(num--)
|
||||
putchar(c);
|
||||
}
|
||||
|
||||
static struct cmdname {
|
||||
size_t len;
|
||||
char name[1];
|
||||
} **cmdname;
|
||||
static int cmdname_alloc, cmdname_cnt;
|
||||
|
||||
static void add_cmdname(const char *name, int len)
|
||||
{
|
||||
struct cmdname *ent;
|
||||
if (cmdname_alloc <= cmdname_cnt) {
|
||||
cmdname_alloc = cmdname_alloc + 200;
|
||||
cmdname = realloc(cmdname, cmdname_alloc * sizeof(*cmdname));
|
||||
if (!cmdname)
|
||||
oom();
|
||||
}
|
||||
ent = malloc(sizeof(*ent) + len);
|
||||
if (!ent)
|
||||
oom();
|
||||
ent->len = len;
|
||||
memcpy(ent->name, name, len);
|
||||
ent->name[len] = 0;
|
||||
cmdname[cmdname_cnt++] = ent;
|
||||
}
|
||||
|
||||
static int cmdname_compare(const void *a_, const void *b_)
|
||||
{
|
||||
struct cmdname *a = *(struct cmdname **)a_;
|
||||
struct cmdname *b = *(struct cmdname **)b_;
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
static void pretty_print_string_list(struct cmdname **cmdname, int longest)
|
||||
{
|
||||
int cols = 1, rows;
|
||||
int space = longest + 1; /* min 1 SP between words */
|
||||
int max_cols = term_columns() - 1; /* don't print *on* the edge */
|
||||
int i, j;
|
||||
|
||||
if (space < max_cols)
|
||||
cols = max_cols / space;
|
||||
rows = (cmdname_cnt + cols - 1) / cols;
|
||||
|
||||
qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);
|
||||
|
||||
for (i = 0; i < rows; i++) {
|
||||
printf(" ");
|
||||
|
||||
for (j = 0; j < cols; j++) {
|
||||
int n = j * rows + i;
|
||||
int size = space;
|
||||
if (n >= cmdname_cnt)
|
||||
break;
|
||||
if (j == cols-1 || n + rows >= cmdname_cnt)
|
||||
size = 1;
|
||||
printf("%-*s", size, cmdname[n]->name);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
static void list_commands(const char *exec_path, const char *pattern)
|
||||
{
|
||||
unsigned int longest = 0;
|
||||
char path[PATH_MAX];
|
||||
int dirlen;
|
||||
DIR *dir = opendir(exec_path);
|
||||
struct dirent *de;
|
||||
|
||||
if (!dir) {
|
||||
fprintf(stderr, "git: '%s': %s\n", exec_path, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
dirlen = strlen(exec_path);
|
||||
if (PATH_MAX - 20 < dirlen) {
|
||||
fprintf(stderr, "git: insanely long exec-path '%s'\n",
|
||||
exec_path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memcpy(path, exec_path, dirlen);
|
||||
path[dirlen++] = '/';
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
struct stat st;
|
||||
int entlen;
|
||||
|
||||
if (strncmp(de->d_name, "git-", 4))
|
||||
continue;
|
||||
strcpy(path+dirlen, de->d_name);
|
||||
if (stat(path, &st) || /* stat, not lstat */
|
||||
!S_ISREG(st.st_mode) ||
|
||||
!(st.st_mode & S_IXUSR))
|
||||
continue;
|
||||
|
||||
entlen = strlen(de->d_name);
|
||||
if (4 < entlen && !strcmp(de->d_name + entlen - 4, ".exe"))
|
||||
entlen -= 4;
|
||||
|
||||
if (longest < entlen)
|
||||
longest = entlen;
|
||||
|
||||
add_cmdname(de->d_name + 4, entlen-4);
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
printf("git commands available in '%s'\n", exec_path);
|
||||
printf("----------------------------");
|
||||
mput_char('-', strlen(exec_path));
|
||||
putchar('\n');
|
||||
pretty_print_string_list(cmdname, longest - 4);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void list_common_cmds_help(void)
|
||||
{
|
||||
int i, longest = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
|
||||
if (longest < strlen(common_cmds[i].name))
|
||||
longest = strlen(common_cmds[i].name);
|
||||
}
|
||||
|
||||
puts("The most commonly used git commands are:");
|
||||
for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
|
||||
printf(" %s", common_cmds[i].name);
|
||||
mput_char(' ', longest - strlen(common_cmds[i].name) + 4);
|
||||
puts(common_cmds[i].help);
|
||||
}
|
||||
puts("(use 'git help -a' to get a list of all installed git commands)");
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
static void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...)
|
||||
__attribute__((__format__(__printf__, 3, 4), __noreturn__));
|
||||
#endif
|
||||
static void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...)
|
||||
{
|
||||
if (fmt) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
printf("git: ");
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
putchar('\n');
|
||||
}
|
||||
else
|
||||
puts(git_usage);
|
||||
|
||||
if (exec_path) {
|
||||
putchar('\n');
|
||||
if (show_all)
|
||||
list_commands(exec_path, "git-*");
|
||||
else
|
||||
list_common_cmds_help();
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
#include "builtin.h"
|
||||
|
||||
static void prepend_to_path(const char *dir, int len)
|
||||
{
|
||||
@ -240,138 +33,7 @@ static void prepend_to_path(const char *dir, int len)
|
||||
setenv("PATH", path, 1);
|
||||
}
|
||||
|
||||
static void show_man_page(const char *git_cmd)
|
||||
{
|
||||
const char *page;
|
||||
|
||||
if (!strncmp(git_cmd, "git", 3))
|
||||
page = git_cmd;
|
||||
else {
|
||||
int page_len = strlen(git_cmd) + 4;
|
||||
char *p = malloc(page_len + 1);
|
||||
strcpy(p, "git-");
|
||||
strcpy(p + 4, git_cmd);
|
||||
p[page_len] = 0;
|
||||
page = p;
|
||||
}
|
||||
|
||||
execlp("man", "man", page, NULL);
|
||||
}
|
||||
|
||||
static int cmd_version(int argc, const char **argv, char **envp)
|
||||
{
|
||||
printf("git version %s\n", GIT_VERSION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_help(int argc, const char **argv, char **envp)
|
||||
{
|
||||
const char *help_cmd = argv[1];
|
||||
if (!help_cmd)
|
||||
cmd_usage(0, git_exec_path(), NULL);
|
||||
else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a"))
|
||||
cmd_usage(1, git_exec_path(), NULL);
|
||||
else
|
||||
show_man_page(help_cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_format_patch(int argc, const char **argv, char **envp)
|
||||
{
|
||||
struct commit *commit;
|
||||
struct commit **list = NULL;
|
||||
struct rev_info rev;
|
||||
int nr = 0;
|
||||
|
||||
init_revisions(&rev);
|
||||
rev.commit_format = CMIT_FMT_EMAIL;
|
||||
rev.verbose_header = 1;
|
||||
rev.diff = 1;
|
||||
rev.diffopt.with_raw = 0;
|
||||
rev.diffopt.with_stat = 1;
|
||||
rev.combine_merges = 0;
|
||||
rev.ignore_merges = 1;
|
||||
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
|
||||
argc = setup_revisions(argc, argv, &rev, "HEAD");
|
||||
|
||||
prepare_revision_walk(&rev);
|
||||
while ((commit = get_revision(&rev)) != NULL) {
|
||||
nr++;
|
||||
list = realloc(list, nr * sizeof(list[0]));
|
||||
list[nr - 1] = commit;
|
||||
}
|
||||
while (0 <= --nr) {
|
||||
int shown;
|
||||
commit = list[nr];
|
||||
shown = log_tree_commit(&rev, commit);
|
||||
free(commit->buffer);
|
||||
commit->buffer = NULL;
|
||||
if (shown)
|
||||
printf("-- \n%s\n\n", GIT_VERSION);
|
||||
}
|
||||
free(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_log_wc(int argc, const char **argv, char **envp,
|
||||
struct rev_info *rev)
|
||||
{
|
||||
struct commit *commit;
|
||||
|
||||
rev->abbrev = DEFAULT_ABBREV;
|
||||
rev->commit_format = CMIT_FMT_DEFAULT;
|
||||
rev->verbose_header = 1;
|
||||
argc = setup_revisions(argc, argv, rev, "HEAD");
|
||||
|
||||
if (argc > 1)
|
||||
die("unrecognized argument: %s", argv[1]);
|
||||
|
||||
prepare_revision_walk(rev);
|
||||
setup_pager();
|
||||
while ((commit = get_revision(rev)) != NULL) {
|
||||
log_tree_commit(rev, commit);
|
||||
free(commit->buffer);
|
||||
commit->buffer = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_wc(int argc, const char **argv, char **envp)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
init_revisions(&rev);
|
||||
rev.diff = 1;
|
||||
rev.diffopt.recursive = 1;
|
||||
return cmd_log_wc(argc, argv, envp, &rev);
|
||||
}
|
||||
|
||||
static int cmd_show(int argc, const char **argv, char **envp)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
init_revisions(&rev);
|
||||
rev.diff = 1;
|
||||
rev.diffopt.recursive = 1;
|
||||
rev.combine_merges = 1;
|
||||
rev.dense_combined_merges = 1;
|
||||
rev.always_show_header = 1;
|
||||
rev.ignore_merges = 0;
|
||||
rev.no_walk = 1;
|
||||
return cmd_log_wc(argc, argv, envp, &rev);
|
||||
}
|
||||
|
||||
static int cmd_log(int argc, const char **argv, char **envp)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
init_revisions(&rev);
|
||||
rev.always_show_header = 1;
|
||||
rev.diffopt.recursive = 1;
|
||||
rev.combine_merges = 1;
|
||||
rev.ignore_merges = 0;
|
||||
return cmd_log_wc(argc, argv, envp, &rev);
|
||||
}
|
||||
const char git_version_string[] = GIT_VERSION;
|
||||
|
||||
static void handle_internal_command(int argc, const char **argv, char **envp)
|
||||
{
|
||||
@ -383,7 +45,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
||||
{ "version", cmd_version },
|
||||
{ "help", cmd_help },
|
||||
{ "log", cmd_log },
|
||||
{ "whatchanged", cmd_wc },
|
||||
{ "whatchanged", cmd_whatchanged },
|
||||
{ "show", cmd_show },
|
||||
{ "fmt-patch", cmd_format_patch },
|
||||
};
|
||||
|
10
mailinfo.c
10
mailinfo.c
@ -405,7 +405,7 @@ static unsigned hexval(int c)
|
||||
return ~0;
|
||||
}
|
||||
|
||||
static int decode_q_segment(char *in, char *ot, char *ep)
|
||||
static int decode_q_segment(char *in, char *ot, char *ep, int rfc2047)
|
||||
{
|
||||
int c;
|
||||
while ((c = *in++) != 0 && (in <= ep)) {
|
||||
@ -414,8 +414,10 @@ static int decode_q_segment(char *in, char *ot, char *ep)
|
||||
if (d == '\n' || !d)
|
||||
break; /* drop trailing newline */
|
||||
*ot++ = ((hexval(d) << 4) | hexval(*in++));
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if (rfc2047 && c == '_') /* rfc2047 4.2 (2) */
|
||||
c = 0x20;
|
||||
*ot++ = c;
|
||||
}
|
||||
*ot = 0;
|
||||
@ -547,7 +549,7 @@ static void decode_header_bq(char *it)
|
||||
sz = decode_b_segment(cp + 3, piecebuf, ep);
|
||||
break;
|
||||
case 'q':
|
||||
sz = decode_q_segment(cp + 3, piecebuf, ep);
|
||||
sz = decode_q_segment(cp + 3, piecebuf, ep, 1);
|
||||
break;
|
||||
}
|
||||
if (sz < 0)
|
||||
@ -569,7 +571,7 @@ static void decode_transfer_encoding(char *line)
|
||||
switch (transfer_encoding) {
|
||||
case TE_QP:
|
||||
ep = line + strlen(line);
|
||||
decode_q_segment(line, line, ep);
|
||||
decode_q_segment(line, line, ep, 0);
|
||||
break;
|
||||
case TE_BASE64:
|
||||
ep = line + strlen(line);
|
||||
|
@ -1052,7 +1052,7 @@ static int try_delta(struct unpacked *cur, struct unpacked *old, unsigned max_de
|
||||
if (cur_entry->delta)
|
||||
max_size = cur_entry->delta_size-1;
|
||||
if (sizediff >= max_size)
|
||||
return -1;
|
||||
return 0;
|
||||
delta_buf = diff_delta(old->data, oldsize,
|
||||
cur->data, size, &delta_size, max_size);
|
||||
if (!delta_buf)
|
||||
@ -1231,7 +1231,7 @@ static void setup_progress_signal(void)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
SHA_CTX ctx;
|
||||
char line[PATH_MAX + 20];
|
||||
char line[40 + 1 + PATH_MAX + 2];
|
||||
int window = 10, depth = 10, pack_to_stdout = 0;
|
||||
struct object_entry **list;
|
||||
int num_preferred_base = 0;
|
||||
|
2
pager.c
2
pager.c
@ -8,6 +8,7 @@
|
||||
static void run_pager(const char *pager)
|
||||
{
|
||||
execlp(pager, pager, NULL);
|
||||
execl("/bin/sh", "sh", "-c", pager, NULL);
|
||||
}
|
||||
|
||||
void setup_pager(void)
|
||||
@ -47,5 +48,6 @@ void setup_pager(void)
|
||||
|
||||
setenv("LESS", "-S", 0);
|
||||
run_pager(pager);
|
||||
die("unable to execute pager '%s'", pager);
|
||||
exit(255);
|
||||
}
|
||||
|
@ -152,6 +152,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
|
||||
if (parse_commit(commit) < 0)
|
||||
die("unable to parse commit %s", name);
|
||||
if (flags & UNINTERESTING) {
|
||||
commit->object.flags |= UNINTERESTING;
|
||||
mark_parents_uninteresting(commit);
|
||||
revs->limited = 1;
|
||||
}
|
||||
|
16
sha1_name.c
16
sha1_name.c
@ -3,6 +3,7 @@
|
||||
#include "commit.h"
|
||||
#include "tree.h"
|
||||
#include "blob.h"
|
||||
#include "tree-walk.h"
|
||||
|
||||
static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
|
||||
{
|
||||
@ -455,6 +456,19 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1)
|
||||
*/
|
||||
int get_sha1(const char *name, unsigned char *sha1)
|
||||
{
|
||||
int ret;
|
||||
unsigned unused;
|
||||
|
||||
prepare_alt_odb();
|
||||
return get_sha1_1(name, strlen(name), sha1);
|
||||
ret = get_sha1_1(name, strlen(name), sha1);
|
||||
if (ret < 0) {
|
||||
const char *cp = strchr(name, ':');
|
||||
if (cp) {
|
||||
unsigned char tree_sha1[20];
|
||||
if (!get_sha1_1(name, cp-name, tree_sha1))
|
||||
return get_tree_entry(tree_sha1, cp+1, sha1,
|
||||
&unused);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -114,6 +114,8 @@ EOF
|
||||
|
||||
git commit -m 'Merged "mybranch" changes.' -i hello
|
||||
|
||||
test_done
|
||||
|
||||
cat > show-branch.expect << EOF
|
||||
* [master] Merged "mybranch" changes.
|
||||
! [mybranch] Some work.
|
||||
|
@ -61,6 +61,9 @@ perl -e '
|
||||
if (/^\s* /) {
|
||||
bad_line("indent SP followed by a TAB", $_);
|
||||
}
|
||||
if (/^(?:[<>=]){7}/) {
|
||||
bad_line("unresolved merge conflict", $_);
|
||||
}
|
||||
}
|
||||
}
|
||||
exit($found_bad);
|
||||
|
50
tree-walk.c
50
tree-walk.c
@ -115,3 +115,53 @@ void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callb
|
||||
free(entry);
|
||||
}
|
||||
|
||||
static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char *result, unsigned *mode)
|
||||
{
|
||||
int namelen = strlen(name);
|
||||
while (t->size) {
|
||||
const char *entry;
|
||||
const unsigned char *sha1;
|
||||
int entrylen, cmp;
|
||||
|
||||
sha1 = tree_entry_extract(t, &entry, mode);
|
||||
update_tree_entry(t);
|
||||
entrylen = strlen(entry);
|
||||
if (entrylen > namelen)
|
||||
continue;
|
||||
cmp = memcmp(name, entry, entrylen);
|
||||
if (cmp > 0)
|
||||
continue;
|
||||
if (cmp < 0)
|
||||
break;
|
||||
if (entrylen == namelen) {
|
||||
memcpy(result, sha1, 20);
|
||||
return 0;
|
||||
}
|
||||
if (name[entrylen] != '/')
|
||||
continue;
|
||||
if (!S_ISDIR(*mode))
|
||||
break;
|
||||
if (++entrylen == namelen) {
|
||||
memcpy(result, sha1, 20);
|
||||
return 0;
|
||||
}
|
||||
return get_tree_entry(sha1, name + entrylen, result, mode);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned char *sha1, unsigned *mode)
|
||||
{
|
||||
int retval;
|
||||
void *tree;
|
||||
struct tree_desc t;
|
||||
|
||||
tree = read_object_with_reference(tree_sha1, tree_type, &t.size, NULL);
|
||||
if (!tree)
|
||||
return -1;
|
||||
t.buf = tree;
|
||||
retval = find_tree_entry(&t, name, sha1, mode);
|
||||
free(tree);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -22,4 +22,6 @@ typedef void (*traverse_callback_t)(int n, unsigned long mask, struct name_entry
|
||||
|
||||
void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback);
|
||||
|
||||
int get_tree_entry(const unsigned char *, const char *, unsigned char *, unsigned *);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user