Browse Source
* jc/dirwalk-n-cache-tree: (212 commits) builtin-rm: squelch compiler warnings. Add builtin "git rm" command Move pathspec matching from builtin-add.c into dir.c Prevent bogus paths from being added to the index. builtin-add: fix unmatched pathspec warnings. Remove old "git-add.sh" remnants builtin-add: warn on unmatched pathspecs Do "git add" as a builtin Clean up git-ls-file directory walking library interface libify git-ls-files directory traversal Add a conversion tool to migrate remote information into the config fetch, pull: ask config for remote information Fix build procedure for builtin-init-db read-tree -m -u: do not overwrite or remove untracked working tree files. apply --cached: do not check newly added file in the working tree Implement a --dry-run option to git-quiltimport Implement git-quiltimport Revert "builtin-grep: workaround for non GNU grep." builtin-grep: workaround for non GNU grep. builtin-grep: workaround for non GNU grep. ...maint
Junio C Hamano
19 years ago
148 changed files with 7935 additions and 2560 deletions
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
<!-- callout.xsl: converts asciidoc callouts to man page format --> |
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> |
||||
<xsl:template match="co"> |
||||
<xsl:value-of select="concat('\fB(',substring-after(@id,'-'),')\fR')"/> |
||||
</xsl:template> |
||||
<xsl:template match="calloutlist"> |
||||
<xsl:text>.sp </xsl:text> |
||||
<xsl:apply-templates/> |
||||
<xsl:text> </xsl:text> |
||||
</xsl:template> |
||||
<xsl:template match="callout"> |
||||
<xsl:value-of select="concat('\fB',substring-after(@arearefs,'-'),'. \fR')"/> |
||||
<xsl:apply-templates/> |
||||
<xsl:text>.br </xsl:text> |
||||
</xsl:template> |
||||
</xsl:stylesheet> |
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
git-quiltimport(1) |
||||
================ |
||||
|
||||
NAME |
||||
---- |
||||
git-quiltimport - Applies a quilt patchset onto the current branch |
||||
|
||||
|
||||
SYNOPSIS |
||||
-------- |
||||
[verse] |
||||
'git-quiltimport' [--dry-run] [--author <author>] [--patches <dir>] |
||||
|
||||
|
||||
DESCRIPTION |
||||
----------- |
||||
Applies a quilt patchset onto the current git branch, preserving |
||||
the patch boundaries, patch order, and patch descriptions present |
||||
in the quilt patchset. |
||||
|
||||
For each patch the code attempts to extract the author from the |
||||
patch description. If that fails it falls back to the author |
||||
specified with --author. If the --author flag was not given |
||||
the patch description is displayed and the user is asked to |
||||
interactively enter the author of the patch. |
||||
|
||||
If a subject is not found in the patch description the patch name is |
||||
preserved as the 1 line subject in the git description. |
||||
|
||||
OPTIONS |
||||
------- |
||||
--dry-run:: |
||||
Walk through the patches in the series and warn |
||||
if we cannot find all of the necessary information to commit |
||||
a patch. At the time of this writing only missing author |
||||
information is warned about. |
||||
|
||||
--author Author Name <Author Email>:: |
||||
The author name and email address to use when no author |
||||
information can be found in the patch description. |
||||
|
||||
--patches <dir>:: |
||||
The directory to find the quilt patches and the |
||||
quilt series file. |
||||
|
||||
The default for the patch directory is patches |
||||
or the value of the $QUILT_PATCHES environment |
||||
variable. |
||||
|
||||
Author |
||||
------ |
||||
Written by Eric Biederman <ebiederm@lnxi.com> |
||||
|
||||
Documentation |
||||
-------------- |
||||
Documentation by Eric Biederman <ebiederm@lnxi.com> |
||||
|
||||
GIT |
||||
--- |
||||
Part of the gitlink:git[7] suite |
||||
|
@ -0,0 +1,140 @@
@@ -0,0 +1,140 @@
|
||||
#include "cache.h" |
||||
|
||||
#undef DEBUG_85 |
||||
|
||||
#ifdef DEBUG_85 |
||||
#define say(a) fprintf(stderr, a) |
||||
#define say1(a,b) fprintf(stderr, a, b) |
||||
#define say2(a,b,c) fprintf(stderr, a, b, c) |
||||
#else |
||||
#define say(a) do {} while(0) |
||||
#define say1(a,b) do {} while(0) |
||||
#define say2(a,b,c) do {} while(0) |
||||
#endif |
||||
|
||||
static const char en85[] = { |
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', |
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', |
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', |
||||
'U', 'V', 'W', 'X', 'Y', 'Z', |
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', |
||||
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', |
||||
'u', 'v', 'w', 'x', 'y', 'z', |
||||
'!', '#', '$', '%', '&', '(', ')', '*', '+', '-', |
||||
';', '<', '=', '>', '?', '@', '^', '_', '`', '{', |
||||
'|', '}', '~' |
||||
}; |
||||
|
||||
static char de85[256]; |
||||
static void prep_base85(void) |
||||
{ |
||||
int i; |
||||
if (de85['Z']) |
||||
return; |
||||
for (i = 0; i < ARRAY_SIZE(en85); i++) { |
||||
int ch = en85[i]; |
||||
de85[ch] = i + 1; |
||||
} |
||||
} |
||||
|
||||
int decode_85(char *dst, char *buffer, int len) |
||||
{ |
||||
prep_base85(); |
||||
|
||||
say2("decode 85 <%.*s>", len/4*5, buffer); |
||||
while (len) { |
||||
unsigned acc = 0; |
||||
int de, cnt = 4; |
||||
unsigned char ch; |
||||
do { |
||||
ch = *buffer++; |
||||
de = de85[ch]; |
||||
if (--de < 0) |
||||
return error("invalid base85 alphabet %c", ch); |
||||
acc = acc * 85 + de; |
||||
} while (--cnt); |
||||
ch = *buffer++; |
||||
de = de85[ch]; |
||||
if (--de < 0) |
||||
return error("invalid base85 alphabet %c", ch); |
||||
/* |
||||
* Detect overflow. The largest |
||||
* 5-letter possible is "|NsC0" to |
||||
* encode 0xffffffff, and "|NsC" gives |
||||
* 0x03030303 at this point (i.e. |
||||
* 0xffffffff = 0x03030303 * 85). |
||||
*/ |
||||
if (0x03030303 < acc || |
||||
0xffffffff - de < (acc *= 85)) |
||||
error("invalid base85 sequence %.5s", buffer-5); |
||||
acc += de; |
||||
say1(" %08x", acc); |
||||
|
||||
cnt = (len < 4) ? len : 4; |
||||
len -= cnt; |
||||
do { |
||||
acc = (acc << 8) | (acc >> 24); |
||||
*dst++ = acc; |
||||
} while (--cnt); |
||||
} |
||||
say("\n"); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void encode_85(char *buf, unsigned char *data, int bytes) |
||||
{ |
||||
prep_base85(); |
||||
|
||||
say("encode 85"); |
||||
while (bytes) { |
||||
unsigned acc = 0; |
||||
int cnt; |
||||
for (cnt = 24; cnt >= 0; cnt -= 8) { |
||||
int ch = *data++; |
||||
acc |= ch << cnt; |
||||
if (--bytes == 0) |
||||
break; |
||||
} |
||||
say1(" %08x", acc); |
||||
for (cnt = 4; cnt >= 0; cnt--) { |
||||
int val = acc % 85; |
||||
acc /= 85; |
||||
buf[cnt] = en85[val]; |
||||
} |
||||
buf += 5; |
||||
} |
||||
say("\n"); |
||||
|
||||
*buf = 0; |
||||
} |
||||
|
||||
#ifdef DEBUG_85 |
||||
int main(int ac, char **av) |
||||
{ |
||||
char buf[1024]; |
||||
|
||||
if (!strcmp(av[1], "-e")) { |
||||
int len = strlen(av[2]); |
||||
encode_85(buf, av[2], len); |
||||
if (len <= 26) len = len + 'A' - 1; |
||||
else len = len + 'a' - 26 + 1; |
||||
printf("encoded: %c%s\n", len, buf); |
||||
return 0; |
||||
} |
||||
if (!strcmp(av[1], "-d")) { |
||||
int len = *av[2]; |
||||
if ('A' <= len && len <= 'Z') len = len - 'A' + 1; |
||||
else len = len - 'a' + 26 + 1; |
||||
decode_85(buf, av[2]+1, len); |
||||
printf("decoded: %.*s\n", len, buf); |
||||
return 0; |
||||
} |
||||
if (!strcmp(av[1], "-t")) { |
||||
char t[4] = { -1,-1,-1,-1 }; |
||||
encode_85(buf, t, 4); |
||||
printf("encoded: D%s\n", buf); |
||||
return 0; |
||||
} |
||||
} |
||||
#endif |
@ -0,0 +1,189 @@
@@ -0,0 +1,189 @@
|
||||
/* |
||||
* "git add" builtin command |
||||
* |
||||
* Copyright (C) 2006 Linus Torvalds |
||||
*/ |
||||
#include <fnmatch.h> |
||||
|
||||
#include "cache.h" |
||||
#include "builtin.h" |
||||
#include "dir.h" |
||||
#include "cache-tree.h" |
||||
|
||||
static const char builtin_add_usage[] = |
||||
"git-add [-n] [-v] <filepattern>..."; |
||||
|
||||
static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix) |
||||
{ |
||||
char *seen; |
||||
int i, specs; |
||||
struct dir_entry **src, **dst; |
||||
|
||||
for (specs = 0; pathspec[specs]; specs++) |
||||
/* nothing */; |
||||
seen = xmalloc(specs); |
||||
memset(seen, 0, specs); |
||||
|
||||
src = dst = dir->entries; |
||||
i = dir->nr; |
||||
while (--i >= 0) { |
||||
struct dir_entry *entry = *src++; |
||||
if (!match_pathspec(pathspec, entry->name, entry->len, prefix, seen)) { |
||||
free(entry); |
||||
continue; |
||||
} |
||||
*dst++ = entry; |
||||
} |
||||
dir->nr = dst - dir->entries; |
||||
|
||||
for (i = 0; i < specs; i++) { |
||||
struct stat st; |
||||
const char *match; |
||||
if (seen[i]) |
||||
continue; |
||||
|
||||
/* Existing file? We must have ignored it */ |
||||
match = pathspec[i]; |
||||
if (!match[0] || !lstat(match, &st)) |
||||
continue; |
||||
die("pathspec '%s' did not match any files", match); |
||||
} |
||||
} |
||||
|
||||
static void fill_directory(struct dir_struct *dir, const char **pathspec) |
||||
{ |
||||
const char *path, *base; |
||||
int baselen; |
||||
|
||||
/* Set up the default git porcelain excludes */ |
||||
memset(dir, 0, sizeof(*dir)); |
||||
dir->exclude_per_dir = ".gitignore"; |
||||
path = git_path("info/exclude"); |
||||
if (!access(path, R_OK)) |
||||
add_excludes_from_file(dir, path); |
||||
|
||||
/* |
||||
* Calculate common prefix for the pathspec, and |
||||
* use that to optimize the directory walk |
||||
*/ |
||||
baselen = common_prefix(pathspec); |
||||
path = "."; |
||||
base = ""; |
||||
if (baselen) { |
||||
char *common = xmalloc(baselen + 1); |
||||
common = xmalloc(baselen + 1); |
||||
memcpy(common, *pathspec, baselen); |
||||
common[baselen] = 0; |
||||
path = base = common; |
||||
} |
||||
|
||||
/* Read the directory and prune it */ |
||||
read_directory(dir, path, base, baselen); |
||||
if (pathspec) |
||||
prune_directory(dir, pathspec, baselen); |
||||
} |
||||
|
||||
static int add_file_to_index(const char *path, int verbose) |
||||
{ |
||||
int size, namelen; |
||||
struct stat st; |
||||
struct cache_entry *ce; |
||||
|
||||
if (lstat(path, &st)) |
||||
die("%s: unable to stat (%s)", path, strerror(errno)); |
||||
|
||||
if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) |
||||
die("%s: can only add regular files or symbolic links", path); |
||||
|
||||
namelen = strlen(path); |
||||
size = cache_entry_size(namelen); |
||||
ce = xcalloc(1, size); |
||||
memcpy(ce->name, path, namelen); |
||||
ce->ce_flags = htons(namelen); |
||||
fill_stat_cache_info(ce, &st); |
||||
|
||||
ce->ce_mode = create_ce_mode(st.st_mode); |
||||
if (!trust_executable_bit) { |
||||
/* If there is an existing entry, pick the mode bits |
||||
* from it. |
||||
*/ |
||||
int pos = cache_name_pos(path, namelen); |
||||
if (pos >= 0) |
||||
ce->ce_mode = active_cache[pos]->ce_mode; |
||||
} |
||||
|
||||
if (index_path(ce->sha1, path, &st, 1)) |
||||
die("unable to index file %s", path); |
||||
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD)) |
||||
die("unable to add %s to index",path); |
||||
if (verbose) |
||||
printf("add '%s'\n", path); |
||||
cache_tree_invalidate_path(active_cache_tree, path); |
||||
return 0; |
||||
} |
||||
|
||||
static struct cache_file cache_file; |
||||
|
||||
int cmd_add(int argc, const char **argv, char **envp) |
||||
{ |
||||
int i, newfd; |
||||
int verbose = 0, show_only = 0; |
||||
const char *prefix = setup_git_directory(); |
||||
const char **pathspec; |
||||
struct dir_struct dir; |
||||
|
||||
git_config(git_default_config); |
||||
|
||||
newfd = hold_index_file_for_update(&cache_file, get_index_file()); |
||||
if (newfd < 0) |
||||
die("unable to create new cachefile"); |
||||
|
||||
if (read_cache() < 0) |
||||
die("index file corrupt"); |
||||
|
||||
for (i = 1; i < argc; i++) { |
||||
const char *arg = argv[i]; |
||||
|
||||
if (arg[0] != '-') |
||||
break; |
||||
if (!strcmp(arg, "--")) { |
||||
i++; |
||||
break; |
||||
} |
||||
if (!strcmp(arg, "-n")) { |
||||
show_only = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp(arg, "-v")) { |
||||
verbose = 1; |
||||
continue; |
||||
} |
||||
die(builtin_add_usage); |
||||
} |
||||
git_config(git_default_config); |
||||
pathspec = get_pathspec(prefix, argv + i); |
||||
|
||||
fill_directory(&dir, pathspec); |
||||
|
||||
if (show_only) { |
||||
const char *sep = "", *eof = ""; |
||||
for (i = 0; i < dir.nr; i++) { |
||||
printf("%s%s", sep, dir.entries[i]->name); |
||||
sep = " "; |
||||
eof = "\n"; |
||||
} |
||||
fputs(eof, stdout); |
||||
return 0; |
||||
} |
||||
|
||||
for (i = 0; i < dir.nr; i++) |
||||
add_file_to_index(dir.entries[i]->name, verbose); |
||||
|
||||
if (active_cache_changed) { |
||||
if (write_cache(newfd, active_cache, active_nr) || |
||||
commit_index_file(&cache_file)) |
||||
die("Unable to write new index file"); |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
/* |
||||
* GIT - The information manager from hell |
||||
*/ |
||||
|
||||
#include "cache.h" |
||||
#include "refs.h" |
||||
#include "builtin.h" |
||||
|
||||
int cmd_check_ref_format(int argc, const char **argv, char **envp) |
||||
{ |
||||
if (argc != 2) |
||||
usage("git check-ref-format refname"); |
||||
return !!check_ref_format(argv[1]); |
||||
} |
@ -0,0 +1,125 @@
@@ -0,0 +1,125 @@
|
||||
/* |
||||
* Builtin "git count-objects". |
||||
* |
||||
* Copyright (c) 2006 Junio C Hamano |
||||
*/ |
||||
|
||||
#include "cache.h" |
||||
#include "builtin.h" |
||||
|
||||
static const char count_objects_usage[] = "git-count-objects [-v]"; |
||||
|
||||
static void count_objects(DIR *d, char *path, int len, int verbose, |
||||
unsigned long *loose, |
||||
unsigned long *loose_size, |
||||
unsigned long *packed_loose, |
||||
unsigned long *garbage) |
||||
{ |
||||
struct dirent *ent; |
||||
while ((ent = readdir(d)) != NULL) { |
||||
char hex[41]; |
||||
unsigned char sha1[20]; |
||||
const char *cp; |
||||
int bad = 0; |
||||
|
||||
if ((ent->d_name[0] == '.') && |
||||
(ent->d_name[1] == 0 || |
||||
((ent->d_name[1] == '.') && (ent->d_name[2] == 0)))) |
||||
continue; |
||||
for (cp = ent->d_name; *cp; cp++) { |
||||
int ch = *cp; |
||||
if (('0' <= ch && ch <= '9') || |
||||
('a' <= ch && ch <= 'f')) |
||||
continue; |
||||
bad = 1; |
||||
break; |
||||
} |
||||
if (cp - ent->d_name != 38) |
||||
bad = 1; |
||||
else { |
||||
struct stat st; |
||||
memcpy(path + len + 3, ent->d_name, 38); |
||||
path[len + 2] = '/'; |
||||
path[len + 41] = 0; |
||||
if (lstat(path, &st) || !S_ISREG(st.st_mode)) |
||||
bad = 1; |
||||
else |
||||
(*loose_size) += st.st_blocks; |
||||
} |
||||
if (bad) { |
||||
if (verbose) { |
||||
error("garbage found: %.*s/%s", |
||||
len + 2, path, ent->d_name); |
||||
(*garbage)++; |
||||
} |
||||
continue; |
||||
} |
||||
(*loose)++; |
||||
if (!verbose) |
||||
continue; |
||||
memcpy(hex, path+len, 2); |
||||
memcpy(hex+2, ent->d_name, 38); |
||||
hex[40] = 0; |
||||
if (get_sha1_hex(hex, sha1)) |
||||
die("internal error"); |
||||
if (has_sha1_pack(sha1)) |
||||
(*packed_loose)++; |
||||
} |
||||
} |
||||
|
||||
int cmd_count_objects(int ac, const char **av, char **ep) |
||||
{ |
||||
int i; |
||||
int verbose = 0; |
||||
const char *objdir = get_object_directory(); |
||||
int len = strlen(objdir); |
||||
char *path = xmalloc(len + 50); |
||||
unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0; |
||||
unsigned long loose_size = 0; |
||||
|
||||
for (i = 1; i < ac; i++) { |
||||
const char *arg = av[i]; |
||||
if (*arg != '-') |
||||
break; |
||||
else if (!strcmp(arg, "-v")) |
||||
verbose = 1; |
||||
else |
||||
usage(count_objects_usage); |
||||
} |
||||
|
||||
/* we do not take arguments other than flags for now */ |
||||
if (i < ac) |
||||
usage(count_objects_usage); |
||||
memcpy(path, objdir, len); |
||||
if (len && objdir[len-1] != '/') |
||||
path[len++] = '/'; |
||||
for (i = 0; i < 256; i++) { |
||||
DIR *d; |
||||
sprintf(path + len, "%02x", i); |
||||
d = opendir(path); |
||||
if (!d) |
||||
continue; |
||||
count_objects(d, path, len, verbose, |
||||
&loose, &loose_size, &packed_loose, &garbage); |
||||
closedir(d); |
||||
} |
||||
if (verbose) { |
||||
struct packed_git *p; |
||||
if (!packed_git) |
||||
prepare_packed_git(); |
||||
for (p = packed_git; p; p = p->next) { |
||||
if (!p->pack_local) |
||||
continue; |
||||
packed += num_packed_objects(p); |
||||
} |
||||
printf("count: %lu\n", loose); |
||||
printf("size: %lu\n", loose_size / 2); |
||||
printf("in-pack: %lu\n", packed); |
||||
printf("prune-packable: %lu\n", packed_loose); |
||||
printf("garbage: %lu\n", garbage); |
||||
} |
||||
else |
||||
printf("%lu objects, %lu kilobytes\n", |
||||
loose, loose_size / 2); |
||||
return 0; |
||||
} |
@ -0,0 +1,370 @@
@@ -0,0 +1,370 @@
|
||||
/* |
||||
* Builtin "git diff" |
||||
* |
||||
* Copyright (c) 2006 Junio C Hamano |
||||
*/ |
||||
#include "cache.h" |
||||
#include "commit.h" |
||||
#include "blob.h" |
||||
#include "tag.h" |
||||
#include "diff.h" |
||||
#include "diffcore.h" |
||||
#include "revision.h" |
||||
#include "log-tree.h" |
||||
#include "builtin.h" |
||||
|
||||
/* NEEDSWORK: struct object has place for name but we _do_ |
||||
* know mode when we extracted the blob out of a tree, which |
||||
* we currently lose. |
||||
*/ |
||||
struct blobinfo { |
||||
unsigned char sha1[20]; |
||||
const char *name; |
||||
}; |
||||
|
||||
static const char builtin_diff_usage[] = |
||||
"diff <options> <rev>{0,2} -- <path>*"; |
||||
|
||||
static int builtin_diff_files(struct rev_info *revs, |
||||
int argc, const char **argv) |
||||
{ |
||||
int silent = 0; |
||||
while (1 < argc) { |
||||
const char *arg = argv[1]; |
||||
if (!strcmp(arg, "--base")) |
||||
revs->max_count = 1; |
||||
else if (!strcmp(arg, "--ours")) |
||||
revs->max_count = 2; |
||||
else if (!strcmp(arg, "--theirs")) |
||||
revs->max_count = 3; |
||||
else if (!strcmp(arg, "-q")) |
||||
silent = 1; |
||||
else if (!strcmp(arg, "--raw")) |
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW; |
||||
else |
||||
usage(builtin_diff_usage); |
||||
argv++; argc--; |
||||
} |
||||
/* |
||||
* Make sure there are NO revision (i.e. pending object) parameter, |
||||
* specified rev.max_count is reasonable (0 <= n <= 3), and |
||||
* there is no other revision filtering parameter. |
||||
*/ |
||||
if (revs->pending_objects || |
||||
revs->min_age != -1 || |
||||
revs->max_age != -1 || |
||||
3 < revs->max_count) |
||||
usage(builtin_diff_usage); |
||||
if (revs->max_count < 0 && |
||||
(revs->diffopt.output_format == DIFF_FORMAT_PATCH)) |
||||
revs->combine_merges = revs->dense_combined_merges = 1; |
||||
/* |
||||
* Backward compatibility wart - "diff-files -s" used to |
||||
* defeat the common diff option "-s" which asked for |
||||
* DIFF_FORMAT_NO_OUTPUT. |
||||
*/ |
||||
if (revs->diffopt.output_format == DIFF_FORMAT_NO_OUTPUT) |
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW; |
||||
return run_diff_files(revs, silent); |
||||
} |
||||
|
||||
static void stuff_change(struct diff_options *opt, |
||||
unsigned old_mode, unsigned new_mode, |
||||
const unsigned char *old_sha1, |
||||
const unsigned char *new_sha1, |
||||
const char *old_name, |
||||
const char *new_name) |
||||
{ |
||||
struct diff_filespec *one, *two; |
||||
|
||||
if (memcmp(null_sha1, old_sha1, 20) && |
||||
memcmp(null_sha1, new_sha1, 20) && |
||||
!memcmp(old_sha1, new_sha1, 20)) |
||||
return; |
||||
|
||||
if (opt->reverse_diff) { |
||||
unsigned tmp; |
||||
const unsigned char *tmp_u; |
||||
const char *tmp_c; |
||||
tmp = old_mode; old_mode = new_mode; new_mode = tmp; |
||||
tmp_u = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_u; |
||||
tmp_c = old_name; old_name = new_name; new_name = tmp_c; |
||||
} |
||||
one = alloc_filespec(old_name); |
||||
two = alloc_filespec(new_name); |
||||
fill_filespec(one, old_sha1, old_mode); |
||||
fill_filespec(two, new_sha1, new_mode); |
||||
|
||||
/* NEEDSWORK: shouldn't this part of diffopt??? */ |
||||
diff_queue(&diff_queued_diff, one, two); |
||||
} |
||||
|
||||
static int builtin_diff_b_f(struct rev_info *revs, |
||||
int argc, const char **argv, |
||||
struct blobinfo *blob, |
||||
const char *path) |
||||
{ |
||||
/* Blob vs file in the working tree*/ |
||||
struct stat st; |
||||
|
||||
while (1 < argc) { |
||||
const char *arg = argv[1]; |
||||
if (!strcmp(arg, "--raw")) |
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW; |
||||
else |
||||
usage(builtin_diff_usage); |
||||
argv++; argc--; |
||||
} |
||||
if (lstat(path, &st)) |
||||
die("'%s': %s", path, strerror(errno)); |
||||
if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) |
||||
die("'%s': not a regular file or symlink", path); |
||||
stuff_change(&revs->diffopt, |
||||
canon_mode(st.st_mode), canon_mode(st.st_mode), |
||||
blob[0].sha1, null_sha1, |
||||
path, path); |
||||
diffcore_std(&revs->diffopt); |
||||
diff_flush(&revs->diffopt); |
||||
return 0; |
||||
} |
||||
|
||||
static int builtin_diff_blobs(struct rev_info *revs, |
||||
int argc, const char **argv, |
||||
struct blobinfo *blob) |
||||
{ |
||||
/* Blobs: the arguments are reversed when setup_revisions() |
||||
* picked them up. |
||||
*/ |
||||
unsigned mode = canon_mode(S_IFREG | 0644); |
||||
|
||||
while (1 < argc) { |
||||
const char *arg = argv[1]; |
||||
if (!strcmp(arg, "--raw")) |
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW; |
||||
else |
||||
usage(builtin_diff_usage); |
||||
argv++; argc--; |
||||
} |
||||
stuff_change(&revs->diffopt, |
||||
mode, mode, |
||||
blob[1].sha1, blob[0].sha1, |
||||
blob[0].name, blob[0].name); |
||||
diffcore_std(&revs->diffopt); |
||||
diff_flush(&revs->diffopt); |
||||
return 0; |
||||
} |
||||
|
||||
static int builtin_diff_index(struct rev_info *revs, |
||||
int argc, const char **argv) |
||||
{ |
||||
int cached = 0; |
||||
while (1 < argc) { |
||||
const char *arg = argv[1]; |
||||
if (!strcmp(arg, "--cached")) |
||||
cached = 1; |
||||
else if (!strcmp(arg, "--raw")) |
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW; |
||||
else |
||||
usage(builtin_diff_usage); |
||||
argv++; argc--; |
||||
} |
||||
/* |
||||
* Make sure there is one revision (i.e. pending object), |
||||
* and there is no revision filtering parameters. |
||||
*/ |
||||
if (!revs->pending_objects || revs->pending_objects->next || |
||||
revs->max_count != -1 || revs->min_age != -1 || |
||||
revs->max_age != -1) |
||||
usage(builtin_diff_usage); |
||||
return run_diff_index(revs, cached); |
||||
} |
||||
|
||||
static int builtin_diff_tree(struct rev_info *revs, |
||||
int argc, const char **argv, |
||||
struct object_list *ent) |
||||
{ |
||||
const unsigned char *(sha1[2]); |
||||
int swap = 1; |
||||
while (1 < argc) { |
||||
const char *arg = argv[1]; |
||||
if (!strcmp(arg, "--raw")) |
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW; |
||||
else |
||||
usage(builtin_diff_usage); |
||||
argv++; argc--; |
||||
} |
||||
|
||||
/* We saw two trees, ent[0] and ent[1]. |
||||
* unless ent[0] is unintesting, they are swapped |
||||
*/ |
||||
if (ent[0].item->flags & UNINTERESTING) |
||||
swap = 0; |
||||
sha1[swap] = ent[0].item->sha1; |
||||
sha1[1-swap] = ent[1].item->sha1; |
||||
diff_tree_sha1(sha1[0], sha1[1], "", &revs->diffopt); |
||||
log_tree_diff_flush(revs); |
||||
return 0; |
||||
} |
||||
|
||||
static int builtin_diff_combined(struct rev_info *revs, |
||||
int argc, const char **argv, |
||||
struct object_list *ent, |
||||
int ents) |
||||
{ |
||||
const unsigned char (*parent)[20]; |
||||
int i; |
||||
|
||||
while (1 < argc) { |
||||
const char *arg = argv[1]; |
||||
if (!strcmp(arg, "--raw")) |
||||
revs->diffopt.output_format = DIFF_FORMAT_RAW; |
||||
else |
||||
usage(builtin_diff_usage); |
||||
argv++; argc--; |
||||
} |
||||
if (!revs->dense_combined_merges && !revs->combine_merges) |
||||
revs->dense_combined_merges = revs->combine_merges = 1; |
||||
parent = xmalloc(ents * sizeof(*parent)); |
||||
/* Again, the revs are all reverse */ |
||||
for (i = 0; i < ents; i++) |
||||
memcpy(parent + i, ent[ents - 1 - i].item->sha1, 20); |
||||
diff_tree_combined(parent[0], parent + 1, ents - 1, |
||||
revs->dense_combined_merges, revs); |
||||
return 0; |
||||
} |
||||
|
||||
static void add_head(struct rev_info *revs) |
||||
{ |
||||
unsigned char sha1[20]; |
||||
struct object *obj; |
||||
if (get_sha1("HEAD", sha1)) |
||||
return; |
||||
obj = parse_object(sha1); |
||||
if (!obj) |
||||
return; |
||||
add_object(obj, &revs->pending_objects, NULL, "HEAD"); |
||||
} |
||||
|
||||
int cmd_diff(int argc, const char **argv, char **envp) |
||||
{ |
||||
struct rev_info rev; |
||||
struct object_list *list, ent[100]; |
||||
int ents = 0, blobs = 0, paths = 0; |
||||
const char *path = NULL; |
||||
struct blobinfo blob[2]; |
||||
|
||||
/* |
||||
* We could get N tree-ish in the rev.pending_objects list. |
||||
* Also there could be M blobs there, and P pathspecs. |
||||
* |
||||
* N=0, M=0: |
||||
* cache vs files (diff-files) |
||||
* N=0, M=2: |
||||
* compare two random blobs. P must be zero. |
||||
* N=0, M=1, P=1: |
||||
* compare a blob with a working tree file. |
||||
* |
||||
* N=1, M=0: |
||||
* tree vs cache (diff-index --cached) |
||||
* |
||||
* N=2, M=0: |
||||
* tree vs tree (diff-tree) |
||||
* |
||||
* Other cases are errors. |
||||
*/ |
||||
|
||||
git_config(git_diff_config); |
||||
init_revisions(&rev); |
||||
rev.diffopt.output_format = DIFF_FORMAT_PATCH; |
||||
|
||||
argc = setup_revisions(argc, argv, &rev, NULL); |
||||
/* Do we have --cached and not have a pending object, then |
||||
* default to HEAD by hand. Eek. |
||||
*/ |
||||
if (!rev.pending_objects) { |
||||
int i; |
||||
for (i = 1; i < argc; i++) { |
||||
const char *arg = argv[i]; |
||||
if (!strcmp(arg, "--")) |
||||
break; |
||||
else if (!strcmp(arg, "--cached")) { |
||||
add_head(&rev); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
for (list = rev.pending_objects; list; list = list->next) { |
||||
struct object *obj = list->item; |
||||
const char *name = list->name; |
||||
int flags = (obj->flags & UNINTERESTING); |
||||
if (!obj->parsed) |
||||
obj = parse_object(obj->sha1); |
||||
obj = deref_tag(obj, NULL, 0); |
||||
if (!obj) |
||||
die("invalid object '%s' given.", name); |
||||
if (!strcmp(obj->type, commit_type)) |
||||
obj = &((struct commit *)obj)->tree->object; |
||||
if (!strcmp(obj->type, tree_type)) { |
||||
if (ARRAY_SIZE(ent) <= ents) |
||||
die("more than %d trees given: '%s'", |
||||
(int) ARRAY_SIZE(ent), name); |
||||
obj->flags |= flags; |
||||
ent[ents].item = obj; |
||||
ent[ents].name = name; |
||||
ents++; |
||||
continue; |
||||
} |
||||
if (!strcmp(obj->type, blob_type)) { |
||||
if (2 <= blobs) |
||||
die("more than two blobs given: '%s'", name); |
||||
memcpy(blob[blobs].sha1, obj->sha1, 20); |
||||
blob[blobs].name = name; |
||||
blobs++; |
||||
continue; |
||||
|
||||
} |
||||
die("unhandled object '%s' given.", name); |
||||
} |
||||
if (rev.prune_data) { |
||||
const char **pathspec = rev.prune_data; |
||||
while (*pathspec) { |
||||
if (!path) |
||||
path = *pathspec; |
||||
paths++; |
||||
pathspec++; |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* Now, do the arguments look reasonable? |
||||
*/ |
||||
if (!ents) { |
||||
switch (blobs) { |
||||
case 0: |
||||
return builtin_diff_files(&rev, argc, argv); |
||||
break; |
||||
case 1: |
||||
if (paths != 1) |
||||
usage(builtin_diff_usage); |
||||
return builtin_diff_b_f(&rev, argc, argv, blob, path); |
||||
break; |
||||
case 2: |
||||
if (paths) |
||||
usage(builtin_diff_usage); |
||||
return builtin_diff_blobs(&rev, argc, argv, blob); |
||||
break; |
||||
default: |
||||
usage(builtin_diff_usage); |
||||
} |
||||
} |
||||
else if (blobs) |
||||
usage(builtin_diff_usage); |
||||
else if (ents == 1) |
||||
return builtin_diff_index(&rev, argc, argv); |
||||
else if (ents == 2) |
||||
return builtin_diff_tree(&rev, argc, argv, ent); |
||||
else |
||||
return builtin_diff_combined(&rev, argc, argv, ent, ents); |
||||
usage(builtin_diff_usage); |
||||
} |
@ -0,0 +1,902 @@
@@ -0,0 +1,902 @@
|
||||
/* |
||||
* Builtin "git grep" |
||||
* |
||||
* Copyright (c) 2006 Junio C Hamano |
||||
*/ |
||||
#include "cache.h" |
||||
#include "blob.h" |
||||
#include "tree.h" |
||||
#include "commit.h" |
||||
#include "tag.h" |
||||
#include "tree-walk.h" |
||||
#include "builtin.h" |
||||
#include <regex.h> |
||||
#include <fnmatch.h> |
||||
#include <sys/wait.h> |
||||
|
||||
/* |
||||
* git grep pathspecs are somewhat different from diff-tree pathspecs; |
||||
* pathname wildcards are allowed. |
||||
*/ |
||||
static int pathspec_matches(const char **paths, const char *name) |
||||
{ |
||||
int namelen, i; |
||||
if (!paths || !*paths) |
||||
return 1; |
||||
namelen = strlen(name); |
||||
for (i = 0; paths[i]; i++) { |
||||
const char *match = paths[i]; |
||||
int matchlen = strlen(match); |
||||
const char *cp, *meta; |
||||
|
||||
if ((matchlen <= namelen) && |
||||
!strncmp(name, match, matchlen) && |
||||
(match[matchlen-1] == '/' || |
||||
name[matchlen] == '\0' || name[matchlen] == '/')) |
||||
return 1; |
||||
if (!fnmatch(match, name, 0)) |
||||
return 1; |
||||
if (name[namelen-1] != '/') |
||||
continue; |
||||
|
||||
/* We are being asked if the directory ("name") is worth |
||||
* descending into. |
||||
* |
||||
* Find the longest leading directory name that does |
||||
* not have metacharacter in the pathspec; the name |
||||
* we are looking at must overlap with that directory. |
||||
*/ |
||||
for (cp = match, meta = NULL; cp - match < matchlen; cp++) { |
||||
char ch = *cp; |
||||
if (ch == '*' || ch == '[' || ch == '?') { |
||||
meta = cp; |
||||
break; |
||||
} |
||||
} |
||||
if (!meta) |
||||
meta = cp; /* fully literal */ |
||||
|
||||
if (namelen <= meta - match) { |
||||
/* Looking at "Documentation/" and |
||||
* the pattern says "Documentation/howto/", or |
||||
* "Documentation/diff*.txt". The name we |
||||
* have should match prefix. |
||||
*/ |
||||
if (!memcmp(match, name, namelen)) |
||||
return 1; |
||||
continue; |
||||
} |
||||
|
||||
if (meta - match < namelen) { |
||||
/* Looking at "Documentation/howto/" and |
||||
* the pattern says "Documentation/h*"; |
||||
* match up to "Do.../h"; this avoids descending |
||||
* into "Documentation/technical/". |
||||
*/ |
||||
if (!memcmp(match, name, meta - match)) |
||||
return 1; |
||||
continue; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
struct grep_pat { |
||||
struct grep_pat *next; |
||||
const char *origin; |
||||
int no; |
||||
const char *pattern; |
||||
regex_t regexp; |
||||
}; |
||||
|
||||
struct grep_opt { |
||||
struct grep_pat *pattern_list; |
||||
struct grep_pat **pattern_tail; |
||||
regex_t regexp; |
||||
unsigned linenum:1; |
||||
unsigned invert:1; |
||||
unsigned name_only:1; |
||||
unsigned unmatch_name_only:1; |
||||
unsigned count:1; |
||||
unsigned word_regexp:1; |
||||
unsigned fixed:1; |
||||
#define GREP_BINARY_DEFAULT 0 |
||||
#define GREP_BINARY_NOMATCH 1 |
||||
#define GREP_BINARY_TEXT 2 |
||||
unsigned binary:2; |
||||
int regflags; |
||||
unsigned pre_context; |
||||
unsigned post_context; |
||||
}; |
||||
|
||||
static void add_pattern(struct grep_opt *opt, const char *pat, |
||||
const char *origin, int no) |
||||
{ |
||||
struct grep_pat *p = xcalloc(1, sizeof(*p)); |
||||
p->pattern = pat; |
||||
p->origin = origin; |
||||
p->no = no; |
||||
*opt->pattern_tail = p; |
||||
opt->pattern_tail = &p->next; |
||||
p->next = NULL; |
||||
} |
||||
|
||||
static void compile_patterns(struct grep_opt *opt) |
||||
{ |
||||
struct grep_pat *p; |
||||
for (p = opt->pattern_list; p; p = p->next) { |
||||
int err = regcomp(&p->regexp, p->pattern, opt->regflags); |
||||
if (err) { |
||||
char errbuf[1024]; |
||||
char where[1024]; |
||||
if (p->no) |
||||
sprintf(where, "In '%s' at %d, ", |
||||
p->origin, p->no); |
||||
else if (p->origin) |
||||
sprintf(where, "%s, ", p->origin); |
||||
else |
||||
where[0] = 0; |
||||
regerror(err, &p->regexp, errbuf, 1024); |
||||
regfree(&p->regexp); |
||||
die("%s'%s': %s", where, p->pattern, errbuf); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static char *end_of_line(char *cp, unsigned long *left) |
||||
{ |
||||
unsigned long l = *left; |
||||
while (l && *cp != '\n') { |
||||
l--; |
||||
cp++; |
||||
} |
||||
*left = l; |
||||
return cp; |
||||
} |
||||
|
||||
static int word_char(char ch) |
||||
{ |
||||
return isalnum(ch) || ch == '_'; |
||||
} |
||||
|
||||
static void show_line(struct grep_opt *opt, const char *bol, const char *eol, |
||||
const char *name, unsigned lno, char sign) |
||||
{ |
||||
printf("%s%c", name, sign); |
||||
if (opt->linenum) |
||||
printf("%d%c", lno, sign); |
||||
printf("%.*s\n", (int)(eol-bol), bol); |
||||
} |
||||
|
||||
/* |
||||
* NEEDSWORK: share code with diff.c |
||||
*/ |
||||
#define FIRST_FEW_BYTES 8000 |
||||
static int buffer_is_binary(const char *ptr, unsigned long size) |
||||
{ |
||||
if (FIRST_FEW_BYTES < size) |
||||
size = FIRST_FEW_BYTES; |
||||
if (memchr(ptr, 0, size)) |
||||
return 1; |
||||
return 0; |
||||
} |
||||
|
||||
static int fixmatch(const char *pattern, char *line, regmatch_t *match) |
||||
{ |
||||
char *hit = strstr(line, pattern); |
||||
if (!hit) { |
||||
match->rm_so = match->rm_eo = -1; |
||||
return REG_NOMATCH; |
||||
} |
||||
else { |
||||
match->rm_so = hit - line; |
||||
match->rm_eo = match->rm_so + strlen(pattern); |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
static int grep_buffer(struct grep_opt *opt, const char *name, |
||||
char *buf, unsigned long size) |
||||
{ |
||||
char *bol = buf; |
||||
unsigned long left = size; |
||||
unsigned lno = 1; |
||||
struct pre_context_line { |
||||
char *bol; |
||||
char *eol; |
||||
} *prev = NULL, *pcl; |
||||
unsigned last_hit = 0; |
||||
unsigned last_shown = 0; |
||||
int binary_match_only = 0; |
||||
const char *hunk_mark = ""; |
||||
unsigned count = 0; |
||||
|
||||
if (buffer_is_binary(buf, size)) { |
||||
switch (opt->binary) { |
||||
case GREP_BINARY_DEFAULT: |
||||
binary_match_only = 1; |
||||
break; |
||||
case GREP_BINARY_NOMATCH: |
||||
return 0; /* Assume unmatch */ |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (opt->pre_context) |
||||
prev = xcalloc(opt->pre_context, sizeof(*prev)); |
||||
if (opt->pre_context || opt->post_context) |
||||
hunk_mark = "--\n"; |
||||
|
||||
while (left) { |
||||
regmatch_t pmatch[10]; |
||||
char *eol, ch; |
||||
int hit = 0; |
||||
struct grep_pat *p; |
||||
|
||||
eol = end_of_line(bol, &left); |
||||
ch = *eol; |
||||
*eol = 0; |
||||
|
||||
for (p = opt->pattern_list; p; p = p->next) { |
||||
if (!opt->fixed) { |
||||
regex_t *exp = &p->regexp; |
||||
hit = !regexec(exp, bol, ARRAY_SIZE(pmatch), |
||||
pmatch, 0); |
||||
} |
||||
else { |
||||
hit = !fixmatch(p->pattern, bol, pmatch); |
||||
} |
||||
|
||||
if (hit && opt->word_regexp) { |
||||
/* Match beginning must be either |
||||
* beginning of the line, or at word |
||||
* boundary (i.e. the last char must |
||||
* not be alnum or underscore). |
||||
*/ |
||||
if ((pmatch[0].rm_so < 0) || |
||||
(eol - bol) <= pmatch[0].rm_so || |
||||
(pmatch[0].rm_eo < 0) || |
||||
(eol - bol) < pmatch[0].rm_eo) |
||||
die("regexp returned nonsense"); |
||||
if (pmatch[0].rm_so != 0 && |
||||
word_char(bol[pmatch[0].rm_so-1])) |
||||
hit = 0; |
||||
if (pmatch[0].rm_eo != (eol-bol) && |
||||
word_char(bol[pmatch[0].rm_eo])) |
||||
hit = 0; |
||||
} |
||||
if (hit) |
||||
break; |
||||
} |
||||
/* "grep -v -e foo -e bla" should list lines |
||||
* that do not have either, so inversion should |
||||
* be done outside. |
||||
*/ |
||||
if (opt->invert) |
||||
hit = !hit; |
||||
if (opt->unmatch_name_only) { |
||||
if (hit) |
||||
return 0; |
||||
goto next_line; |
||||
} |
||||
if (hit) { |
||||
count++; |
||||
if (binary_match_only) { |
||||
printf("Binary file %s matches\n", name); |
||||
return 1; |
||||
} |
||||
if (opt->name_only) { |
||||
printf("%s\n", name); |
||||
return 1; |
||||
} |
||||
/* Hit at this line. If we haven't shown the |
||||
* pre-context lines, we would need to show them. |
||||
* When asked to do "count", this still show |
||||
* the context which is nonsense, but the user |
||||
* deserves to get that ;-). |
||||
*/ |
||||
if (opt->pre_context) { |
||||
unsigned from; |
||||
if (opt->pre_context < lno) |
||||
from = lno - opt->pre_context; |
||||
else |
||||
from = 1; |
||||
if (from <= last_shown) |
||||
from = last_shown + 1; |
||||
if (last_shown && from != last_shown + 1) |
||||
printf(hunk_mark); |
||||
while (from < lno) { |
||||
pcl = &prev[lno-from-1]; |
||||
show_line(opt, pcl->bol, pcl->eol, |
||||
name, from, '-'); |
||||
from++; |
||||
} |
||||
last_shown = lno-1; |
||||
} |
||||
if (last_shown && lno != last_shown + 1) |
||||
printf(hunk_mark); |
||||
if (!opt->count) |
||||
show_line(opt, bol, eol, name, lno, ':'); |
||||
last_shown = last_hit = lno; |
||||
} |
||||
else if (last_hit && |
||||
lno <= last_hit + opt->post_context) { |
||||
/* If the last hit is within the post context, |
||||
* we need to show this line. |
||||
*/ |
||||
if (last_shown && lno != last_shown + 1) |
||||
printf(hunk_mark); |
||||
show_line(opt, bol, eol, name, lno, '-'); |
||||
last_shown = lno; |
||||
} |
||||
if (opt->pre_context) { |
||||
memmove(prev+1, prev, |
||||
(opt->pre_context-1) * sizeof(*prev)); |
||||
prev->bol = bol; |
||||
prev->eol = eol; |
||||
} |
||||
|
||||
next_line: |
||||
*eol = ch; |
||||
bol = eol + 1; |
||||
if (!left) |
||||
break; |
||||
left--; |
||||
lno++; |
||||
} |
||||
|
||||
if (opt->unmatch_name_only) { |
||||
/* We did not see any hit, so we want to show this */ |
||||
printf("%s\n", name); |
||||
return 1; |
||||
} |
||||
|
||||
/* NEEDSWORK: |
||||
* The real "grep -c foo *.c" gives many "bar.c:0" lines, |
||||
* which feels mostly useless but sometimes useful. Maybe |
||||
* make it another option? For now suppress them. |
||||
*/ |
||||
if (opt->count && count) |
||||
printf("%s:%u\n", name, count); |
||||
return !!last_hit; |
||||
} |
||||
|
||||
static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char *name) |
||||
{ |
||||
unsigned long size; |
||||
char *data; |
||||
char type[20]; |
||||
int hit; |
||||
data = read_sha1_file(sha1, type, &size); |
||||
if (!data) { |
||||
error("'%s': unable to read %s", name, sha1_to_hex(sha1)); |
||||
return 0; |
||||
} |
||||
hit = grep_buffer(opt, name, data, size); |
||||
free(data); |
||||
return hit; |
||||
} |
||||
|
||||
static int grep_file(struct grep_opt *opt, const char *filename) |
||||
{ |
||||
struct stat st; |
||||
int i; |
||||
char *data; |
||||
if (lstat(filename, &st) < 0) { |
||||
err_ret: |
||||
if (errno != ENOENT) |
||||
error("'%s': %s", filename, strerror(errno)); |
||||
return 0; |
||||
} |
||||
if (!st.st_size) |
||||
return 0; /* empty file -- no grep hit */ |
||||
if (!S_ISREG(st.st_mode)) |
||||
return 0; |
||||
i = open(filename, O_RDONLY); |
||||
if (i < 0) |
||||
goto err_ret; |
||||
data = xmalloc(st.st_size + 1); |
||||
if (st.st_size != xread(i, data, st.st_size)) { |
||||
error("'%s': short read %s", filename, strerror(errno)); |
||||
close(i); |
||||
free(data); |
||||
return 0; |
||||
} |
||||
close(i); |
||||
i = grep_buffer(opt, filename, data, st.st_size); |
||||
free(data); |
||||
return i; |
||||
} |
||||
|
||||
static int exec_grep(int argc, const char **argv) |
||||
{ |
||||
pid_t pid; |
||||
int status; |
||||
|
||||
argv[argc] = NULL; |
||||
pid = fork(); |
||||
if (pid < 0) |
||||
return pid; |
||||
if (!pid) { |
||||
execvp("grep", (char **) argv); |
||||
exit(255); |
||||
} |
||||
while (waitpid(pid, &status, 0) < 0) { |
||||
if (errno == EINTR) |
||||
continue; |
||||
return -1; |
||||
} |
||||
if (WIFEXITED(status)) { |
||||
if (!WEXITSTATUS(status)) |
||||
return 1; |
||||
return 0; |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
#define MAXARGS 1000 |
||||
#define ARGBUF 4096 |
||||
#define push_arg(a) do { \ |
||||
if (nr < MAXARGS) argv[nr++] = (a); \ |
||||
else die("maximum number of args exceeded"); \ |
||||
} while (0) |
||||
|
||||
static int external_grep(struct grep_opt *opt, const char **paths, int cached) |
||||
{ |
||||
int i, nr, argc, hit, len; |
||||
const char *argv[MAXARGS+1]; |
||||
char randarg[ARGBUF]; |
||||
char *argptr = randarg; |
||||
struct grep_pat *p; |
||||
|
||||
len = nr = 0; |
||||
push_arg("grep"); |
||||
if (opt->fixed) |
||||
push_arg("-F"); |
||||
if (opt->linenum) |
||||
push_arg("-n"); |
||||
if (opt->regflags & REG_EXTENDED) |
||||
push_arg("-E"); |
||||
if (opt->word_regexp) |
||||
push_arg("-w"); |
||||
if (opt->name_only) |
||||
push_arg("-l"); |
||||
if (opt->unmatch_name_only) |
||||
push_arg("-L"); |
||||
if (opt->count) |
||||
push_arg("-c"); |
||||
if (opt->post_context || opt->pre_context) { |
||||
if (opt->post_context != opt->pre_context) { |
||||
if (opt->pre_context) { |
||||
push_arg("-B"); |
||||
len += snprintf(argptr, sizeof(randarg)-len, |
||||
"%u", opt->pre_context); |
||||
if (sizeof(randarg) <= len) |
||||
die("maximum length of args exceeded"); |
||||
push_arg(argptr); |
||||
argptr += len; |
||||
} |
||||
if (opt->post_context) { |
||||
push_arg("-A"); |
||||
len += snprintf(argptr, sizeof(randarg)-len, |
||||
"%u", opt->post_context); |
||||
if (sizeof(randarg) <= len) |
||||
die("maximum length of args exceeded"); |
||||
push_arg(argptr); |
||||
argptr += len; |
||||
} |
||||
} |
||||
else { |
||||
push_arg("-C"); |
||||
len += snprintf(argptr, sizeof(randarg)-len, |
||||
"%u", opt->post_context); |
||||
if (sizeof(randarg) <= len) |
||||
die("maximum length of args exceeded"); |
||||
push_arg(argptr); |
||||
argptr += len; |
||||
} |
||||
} |
||||
for (p = opt->pattern_list; p; p = p->next) { |
||||
push_arg("-e"); |
||||
push_arg(p->pattern); |
||||
} |
||||
|
||||
/* |
||||
* To make sure we get the header printed out when we want it, |
||||
* add /dev/null to the paths to grep. This is unnecessary |
||||
* (and wrong) with "-l" or "-L", which always print out the |
||||
* name anyway. |
||||
* |
||||
* GNU grep has "-H", but this is portable. |
||||
*/ |
||||
if (!opt->name_only && !opt->unmatch_name_only) |
||||
push_arg("/dev/null"); |
||||
|
||||
hit = 0; |
||||
argc = nr; |
||||
for (i = 0; i < active_nr; i++) { |
||||
struct cache_entry *ce = active_cache[i]; |
||||
const char *name; |
||||
if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode))) |
||||
continue; |
||||
if (!pathspec_matches(paths, ce->name)) |
||||
continue; |
||||
name = ce->name; |
||||
if (name[0] == '-') { |
||||
int len = ce_namelen(ce); |
||||
name = xmalloc(len + 3); |
||||
memcpy(name, "./", 2); |
||||
memcpy(name + 2, ce->name, len + 1); |
||||
} |
||||
argv[argc++] = name; |
||||
if (argc < MAXARGS) |
||||
continue; |
||||
hit += exec_grep(argc, argv); |
||||
argc = nr; |
||||
} |
||||
if (argc > nr) |
||||
hit += exec_grep(argc, argv); |
||||
return 0; |
||||
} |
||||
|
||||
static int grep_cache(struct grep_opt *opt, const char **paths, int cached) |
||||
{ |
||||
int hit = 0; |
||||
int nr; |
||||
read_cache(); |
||||
|
||||
#ifdef __unix__ |
||||
/* |
||||
* Use the external "grep" command for the case where |
||||
* we grep through the checked-out files. It tends to |
||||
* be a lot more optimized |
||||
*/ |
||||
if (!cached) { |
||||
hit = external_grep(opt, paths, cached); |
||||
if (hit >= 0) |
||||
return hit; |
||||
} |
||||
#endif |
||||
|
||||
for (nr = 0; nr < active_nr; nr++) { |
||||
struct cache_entry *ce = active_cache[nr]; |
||||
if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode))) |
||||
continue; |
||||
if (!pathspec_matches(paths, ce->name)) |
||||
continue; |
||||
if (cached) |
||||
hit |= grep_sha1(opt, ce->sha1, ce->name); |
||||
else |
||||
hit |= grep_file(opt, ce->name); |
||||
} |
||||
return hit; |
||||
} |
||||
|
||||
static int grep_tree(struct grep_opt *opt, const char **paths, |
||||
struct tree_desc *tree, |
||||
const char *tree_name, const char *base) |
||||
{ |
||||
unsigned mode; |
||||
int len; |
||||
int hit = 0; |
||||
const char *path; |
||||
const unsigned char *sha1; |
||||
char *down; |
||||
char *path_buf = xmalloc(PATH_MAX + strlen(tree_name) + 100); |
||||
|
||||
if (tree_name[0]) { |
||||
int offset = sprintf(path_buf, "%s:", tree_name); |
||||
down = path_buf + offset; |
||||
strcat(down, base); |
||||
} |
||||
else { |
||||
down = path_buf; |
||||
strcpy(down, base); |
||||
} |
||||
len = strlen(path_buf); |
||||
|
||||
while (tree->size) { |
||||
int pathlen; |
||||
sha1 = tree_entry_extract(tree, &path, &mode); |
||||
pathlen = strlen(path); |
||||
strcpy(path_buf + len, path); |
||||
|
||||
if (S_ISDIR(mode)) |
||||
/* Match "abc/" against pathspec to |
||||
* decide if we want to descend into "abc" |
||||
* directory. |
||||
*/ |
||||
strcpy(path_buf + len + pathlen, "/"); |
||||
|
||||
if (!pathspec_matches(paths, down)) |
||||
; |
||||
else if (S_ISREG(mode)) |
||||
hit |= grep_sha1(opt, sha1, path_buf); |
||||
else if (S_ISDIR(mode)) { |
||||
char type[20]; |
||||
struct tree_desc sub; |
||||
void *data; |
||||
data = read_sha1_file(sha1, type, &sub.size); |
||||
if (!data) |
||||
die("unable to read tree (%s)", |
||||
sha1_to_hex(sha1)); |
||||
sub.buf = data; |
||||
hit |= grep_tree(opt, paths, &sub, tree_name, down); |
||||
free(data); |
||||
} |
||||
update_tree_entry(tree); |
||||
} |
||||
return hit; |
||||
} |
||||
|
||||
static int grep_object(struct grep_opt *opt, const char **paths, |
||||
struct object *obj, const char *name) |
||||
{ |
||||
if (!strcmp(obj->type, blob_type)) |
||||
return grep_sha1(opt, obj->sha1, name); |
||||
if (!strcmp(obj->type, commit_type) || |
||||
!strcmp(obj->type, tree_type)) { |
||||
struct tree_desc tree; |
||||
void *data; |
||||
int hit; |
||||
data = read_object_with_reference(obj->sha1, tree_type, |
||||
&tree.size, NULL); |
||||
if (!data) |
||||
die("unable to read tree (%s)", sha1_to_hex(obj->sha1)); |
||||
tree.buf = data; |
||||
hit = grep_tree(opt, paths, &tree, name, ""); |
||||
free(data); |
||||
return hit; |
||||
} |
||||
die("unable to grep from object of type %s", obj->type); |
||||
} |
||||
|
||||
static const char builtin_grep_usage[] = |
||||
"git-grep <option>* <rev>* [-e] <pattern> [<path>...]"; |
||||
|
||||
int cmd_grep(int argc, const char **argv, char **envp) |
||||
{ |
||||
int hit = 0; |
||||
int cached = 0; |
||||
int seen_dashdash = 0; |
||||
struct grep_opt opt; |
||||
struct object_list *list, **tail, *object_list = NULL; |
||||
const char *prefix = setup_git_directory(); |
||||
const char **paths = NULL; |
||||
int i; |
||||
|
||||
memset(&opt, 0, sizeof(opt)); |
||||
opt.pattern_tail = &opt.pattern_list; |
||||
opt.regflags = REG_NEWLINE; |
||||
|
||||
/* |
||||
* If there is no -- then the paths must exist in the working |
||||
* tree. If there is no explicit pattern specified with -e or |
||||
* -f, we take the first unrecognized non option to be the |
||||
* pattern, but then what follows it must be zero or more |
||||
* valid refs up to the -- (if exists), and then existing |
||||
* paths. If there is an explicit pattern, then the first |
||||
* unrecocnized non option is the beginning of the refs list |
||||
* that continues up to the -- (if exists), and then paths. |
||||
*/ |
||||
|
||||
tail = &object_list; |
||||
while (1 < argc) { |
||||
const char *arg = argv[1]; |
||||
argc--; argv++; |
||||
if (!strcmp("--cached", arg)) { |
||||
cached = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp("-a", arg) || |
||||
!strcmp("--text", arg)) { |
||||
opt.binary = GREP_BINARY_TEXT; |
||||
continue; |
||||
} |
||||
if (!strcmp("-i", arg) || |
||||
!strcmp("--ignore-case", arg)) { |
||||
opt.regflags |= REG_ICASE; |
||||
continue; |
||||
} |
||||
if (!strcmp("-I", arg)) { |
||||
opt.binary = GREP_BINARY_NOMATCH; |
||||
continue; |
||||
} |
||||
if (!strcmp("-v", arg) || |
||||
!strcmp("--invert-match", arg)) { |
||||
opt.invert = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp("-E", arg) || |
||||
!strcmp("--extended-regexp", arg)) { |
||||
opt.regflags |= REG_EXTENDED; |
||||
continue; |
||||
} |
||||
if (!strcmp("-F", arg) || |
||||
!strcmp("--fixed-strings", arg)) { |
||||
opt.fixed = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp("-G", arg) || |
||||
!strcmp("--basic-regexp", arg)) { |
||||
opt.regflags &= ~REG_EXTENDED; |
||||
continue; |
||||
} |
||||
if (!strcmp("-n", arg)) { |
||||
opt.linenum = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp("-H", arg)) { |
||||
/* We always show the pathname, so this |
||||
* is a noop. |
||||
*/ |
||||
continue; |
||||
} |
||||
if (!strcmp("-l", arg) || |
||||
!strcmp("--files-with-matches", arg)) { |
||||
opt.name_only = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp("-L", arg) || |
||||
!strcmp("--files-without-match", arg)) { |
||||
opt.unmatch_name_only = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp("-c", arg) || |
||||
!strcmp("--count", arg)) { |
||||
opt.count = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp("-w", arg) || |
||||
!strcmp("--word-regexp", arg)) { |
||||
opt.word_regexp = 1; |
||||
continue; |
||||
} |
||||
if (!strncmp("-A", arg, 2) || |
||||
!strncmp("-B", arg, 2) || |
||||
!strncmp("-C", arg, 2) || |
||||
(arg[0] == '-' && '1' <= arg[1] && arg[1] <= '9')) { |
||||
unsigned num; |
||||
const char *scan; |
||||
switch (arg[1]) { |
||||
case 'A': case 'B': case 'C': |
||||
if (!arg[2]) { |
||||
if (argc <= 1) |
||||
usage(builtin_grep_usage); |
||||
scan = *++argv; |
||||
argc--; |
||||
} |
||||
else |
||||
scan = arg + 2; |
||||
break; |
||||
default: |
||||
scan = arg + 1; |
||||
break; |
||||
} |
||||
if (sscanf(scan, "%u", &num) != 1) |
||||
usage(builtin_grep_usage); |
||||
switch (arg[1]) { |
||||
case 'A': |
||||
opt.post_context = num; |
||||
break; |
||||
default: |
||||
case 'C': |
||||
opt.post_context = num; |
||||
case 'B': |
||||
opt.pre_context = num; |
||||
break; |
||||
} |
||||
continue; |
||||
} |
||||
if (!strcmp("-f", arg)) { |
||||
FILE *patterns; |
||||
int lno = 0; |
||||
char buf[1024]; |
||||
if (argc <= 1) |
||||
usage(builtin_grep_usage); |
||||
patterns = fopen(argv[1], "r"); |
||||
if (!patterns) |
||||
die("'%s': %s", argv[1], strerror(errno)); |
||||
while (fgets(buf, sizeof(buf), patterns)) { |
||||
int len = strlen(buf); |
||||
if (buf[len-1] == '\n') |
||||
buf[len-1] = 0; |
||||
/* ignore empty line like grep does */ |
||||
if (!buf[0]) |
||||
continue; |
||||
add_pattern(&opt, strdup(buf), argv[1], ++lno); |
||||
} |
||||
fclose(patterns); |
||||
argv++; |
||||
argc--; |
||||
continue; |
||||
} |
||||
if (!strcmp("-e", arg)) { |
||||
if (1 < argc) { |
||||
add_pattern(&opt, argv[1], "-e option", 0); |
||||
argv++; |
||||
argc--; |
||||
continue; |
||||
} |
||||
usage(builtin_grep_usage); |
||||
} |
||||
if (!strcmp("--", arg)) |
||||
break; |
||||
if (*arg == '-') |
||||
usage(builtin_grep_usage); |
||||
|
||||
/* First unrecognized non-option token */ |
||||
if (!opt.pattern_list) { |
||||
add_pattern(&opt, arg, "command line", 0); |
||||
break; |
||||
} |
||||
else { |
||||
/* We are looking at the first path or rev; |
||||
* it is found at argv[1] after leaving the |
||||
* loop. |
||||
*/ |
||||
argc++; argv--; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!opt.pattern_list) |
||||
die("no pattern given."); |
||||
if ((opt.regflags != REG_NEWLINE) && opt.fixed) |
||||
die("cannot mix --fixed-strings and regexp"); |
||||
if (!opt.fixed) |
||||
compile_patterns(&opt); |
||||
|
||||
/* Check revs and then paths */ |
||||
for (i = 1; i < argc; i++) { |
||||
const char *arg = argv[i]; |
||||
unsigned char sha1[20]; |
||||
/* Is it a rev? */ |
||||
if (!get_sha1(arg, sha1)) { |
||||
struct object *object = parse_object(sha1); |
||||
struct object_list *elem; |
||||
if (!object) |
||||
die("bad object %s", arg); |
||||
elem = object_list_insert(object, tail); |
||||
elem->name = arg; |
||||
tail = &elem->next; |
||||
continue; |
||||
} |
||||
if (!strcmp(arg, "--")) { |
||||
i++; |
||||
seen_dashdash = 1; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
/* The rest are paths */ |
||||
if (!seen_dashdash) { |
||||
int j; |
||||
for (j = i; j < argc; j++) |
||||
verify_filename(prefix, argv[j]); |
||||
} |
||||
|
||||
if (i < argc) |
||||
paths = get_pathspec(prefix, argv + i); |
||||
else if (prefix) { |
||||
paths = xcalloc(2, sizeof(const char *)); |
||||
paths[0] = prefix; |
||||
paths[1] = NULL; |
||||
} |
||||
|
||||
if (!object_list) |
||||
return !grep_cache(&opt, paths, cached); |
||||
|
||||
if (cached) |
||||
die("both --cached and trees are given."); |
||||
|
||||
for (list = object_list; list; list = list->next) { |
||||
struct object *real_obj; |
||||
real_obj = deref_tag(list->item, NULL, 0); |
||||
if (grep_object(&opt, paths, real_obj, list->name)) |
||||
hit = 1; |
||||
} |
||||
return !hit; |
||||
} |
@ -0,0 +1,312 @@
@@ -0,0 +1,312 @@
|
||||
/* |
||||
* "git push" |
||||
*/ |
||||
#include "cache.h" |
||||
#include "refs.h" |
||||
#include "run-command.h" |
||||
#include "builtin.h" |
||||
|
||||
#define MAX_URI (16) |
||||
|
||||
static const char push_usage[] = "git push [--all] [--tags] [--force] <repository> [<refspec>...]"; |
||||
|
||||
static int all = 0, tags = 0, force = 0, thin = 1; |
||||
static const char *execute = NULL; |
||||
|
||||
#define BUF_SIZE (2084) |
||||
static char buffer[BUF_SIZE]; |
||||
|
||||
static const char **refspec = NULL; |
||||
static int refspec_nr = 0; |
||||
|
||||
static void add_refspec(const char *ref) |
||||
{ |
||||
int nr = refspec_nr + 1; |
||||
refspec = xrealloc(refspec, nr * sizeof(char *)); |
||||
refspec[nr-1] = ref; |
||||
refspec_nr = nr; |
||||
} |
||||
|
||||
static int expand_one_ref(const char *ref, const unsigned char *sha1) |
||||
{ |
||||
/* Ignore the "refs/" at the beginning of the refname */ |
||||
ref += 5; |
||||
|
||||
if (strncmp(ref, "tags/", 5)) |
||||
return 0; |
||||
|
||||
add_refspec(strdup(ref)); |
||||
return 0; |
||||
} |
||||
|
||||
static void expand_refspecs(void) |
||||
{ |
||||
if (all) { |
||||
if (refspec_nr) |
||||
die("cannot mix '--all' and a refspec"); |
||||
|
||||
/* |
||||
* No need to expand "--all" - we'll just use |
||||
* the "--all" flag to send-pack |
||||
*/ |
||||
return; |
||||
} |
||||
if (!tags) |
||||
return; |
||||
for_each_ref(expand_one_ref); |
||||
} |
||||
|
||||
static void set_refspecs(const char **refs, int nr) |
||||
{ |
||||
if (nr) { |
||||
size_t bytes = nr * sizeof(char *); |
||||
|
||||
refspec = xrealloc(refspec, bytes); |
||||
memcpy(refspec, refs, bytes); |
||||
refspec_nr = nr; |
||||
} |
||||
expand_refspecs(); |
||||
} |
||||
|
||||
static int get_remotes_uri(const char *repo, const char *uri[MAX_URI]) |
||||
{ |
||||
int n = 0; |
||||
FILE *f = fopen(git_path("remotes/%s", repo), "r"); |
||||
int has_explicit_refspec = refspec_nr || all || tags; |
||||
|
||||
if (!f) |
||||
return -1; |
||||
while (fgets(buffer, BUF_SIZE, f)) { |
||||
int is_refspec; |
||||
char *s, *p; |
||||
|
||||
if (!strncmp("URL: ", buffer, 5)) { |
||||
is_refspec = 0; |
||||
s = buffer + 5; |
||||
} else if (!strncmp("Push: ", buffer, 6)) { |
||||
is_refspec = 1; |
||||
s = buffer + 6; |
||||
} else |
||||
continue; |
||||
|
||||
/* Remove whitespace at the head.. */ |
||||
while (isspace(*s)) |
||||
s++; |
||||
if (!*s) |
||||
continue; |
||||
|
||||
/* ..and at the end */ |
||||
p = s + strlen(s); |
||||
while (isspace(p[-1])) |
||||
*--p = 0; |
||||
|
||||
if (!is_refspec) { |
||||
if (n < MAX_URI) |
||||
uri[n++] = strdup(s); |
||||
else |
||||
error("more than %d URL's specified, ignoreing the rest", MAX_URI); |
||||
} |
||||
else if (is_refspec && !has_explicit_refspec) |
||||
add_refspec(strdup(s)); |
||||
} |
||||
fclose(f); |
||||
if (!n) |
||||
die("remote '%s' has no URL", repo); |
||||
return n; |
||||
} |
||||
|
||||
static const char **config_uri; |
||||
static const char *config_repo; |
||||
static int config_repo_len; |
||||
static int config_current_uri; |
||||
static int config_get_refspecs; |
||||
|
||||
static int get_remote_config(const char* key, const char* value) |
||||
{ |
||||
if (!strncmp(key, "remote.", 7) && |
||||
!strncmp(key + 7, config_repo, config_repo_len)) { |
||||
if (!strcmp(key + 7 + config_repo_len, ".url")) { |
||||
if (config_current_uri < MAX_URI) |
||||
config_uri[config_current_uri++] = strdup(value); |
||||
else |
||||
error("more than %d URL's specified, ignoring the rest", MAX_URI); |
||||
} |
||||
else if (config_get_refspecs && |
||||
!strcmp(key + 7 + config_repo_len, ".push")) |
||||
add_refspec(strdup(value)); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int get_config_remotes_uri(const char *repo, const char *uri[MAX_URI]) |
||||
{ |
||||
config_repo_len = strlen(repo); |
||||
config_repo = repo; |
||||
config_current_uri = 0; |
||||
config_uri = uri; |
||||
config_get_refspecs = !(refspec_nr || all || tags); |
||||
|
||||
git_config(get_remote_config); |
||||
return config_current_uri; |
||||
} |
||||
|
||||
static int get_branches_uri(const char *repo, const char *uri[MAX_URI]) |
||||
{ |
||||
const char *slash = strchr(repo, '/'); |
||||
int n = slash ? slash - repo : 1000; |
||||
FILE *f = fopen(git_path("branches/%.*s", n, repo), "r"); |
||||
char *s, *p; |
||||
int len; |
||||
|
||||
if (!f) |
||||
return 0; |
||||
s = fgets(buffer, BUF_SIZE, f); |
||||
fclose(f); |
||||
if (!s) |
||||
return 0; |
||||
while (isspace(*s)) |
||||
s++; |
||||
if (!*s) |
||||
return 0; |
||||
p = s + strlen(s); |
||||
while (isspace(p[-1])) |
||||
*--p = 0; |
||||
len = p - s; |
||||
if (slash) |
||||
len += strlen(slash); |
||||
p = xmalloc(len + 1); |
||||
strcpy(p, s); |
||||
if (slash) |
||||
strcat(p, slash); |
||||
uri[0] = p; |
||||
return 1; |
||||
} |
||||
|
||||
/* |
||||
* Read remotes and branches file, fill the push target URI |
||||
* list. If there is no command line refspecs, read Push: lines |
||||
* to set up the *refspec list as well. |
||||
* return the number of push target URIs |
||||
*/ |
||||
static int read_config(const char *repo, const char *uri[MAX_URI]) |
||||
{ |
||||
int n; |
||||
|
||||
if (*repo != '/') { |
||||
n = get_remotes_uri(repo, uri); |
||||
if (n > 0) |
||||
return n; |
||||
|
||||
n = get_config_remotes_uri(repo, uri); |
||||
if (n > 0) |
||||
return n; |
||||
|
||||
n = get_branches_uri(repo, uri); |
||||
if (n > 0) |
||||
return n; |
||||
} |
||||
|
||||
uri[0] = repo; |
||||
return 1; |
||||
} |
||||
|
||||
static int do_push(const char *repo) |
||||
{ |
||||
const char *uri[MAX_URI]; |
||||
int i, n; |
||||
int remote; |
||||
const char **argv; |
||||
int argc; |
||||
|
||||
n = read_config(repo, uri); |
||||
if (n <= 0) |
||||
die("bad repository '%s'", repo); |
||||
|
||||
argv = xmalloc((refspec_nr + 10) * sizeof(char *)); |
||||
argv[0] = "dummy-send-pack"; |
||||
argc = 1; |
||||
if (all) |
||||
argv[argc++] = "--all"; |
||||
if (force) |
||||
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; |
||||
|
||||
for (i = 0; i < n; i++) { |
||||
int error; |
||||
const char *dest = uri[i]; |
||||
const char *sender = "git-send-pack"; |
||||
if (!strncmp(dest, "http://", 7) || |
||||
!strncmp(dest, "https://", 8)) |
||||
sender = "git-http-push"; |
||||
argv[0] = sender; |
||||
argv[remote] = dest; |
||||
error = run_command_v(argc, argv); |
||||
if (!error) |
||||
continue; |
||||
switch (error) { |
||||
case -ERR_RUN_COMMAND_FORK: |
||||
die("unable to fork for %s", sender); |
||||
case -ERR_RUN_COMMAND_EXEC: |
||||
die("unable to exec %s", sender); |
||||
case -ERR_RUN_COMMAND_WAITPID: |
||||
case -ERR_RUN_COMMAND_WAITPID_WRONG_PID: |
||||
case -ERR_RUN_COMMAND_WAITPID_SIGNAL: |
||||
case -ERR_RUN_COMMAND_WAITPID_NOEXIT: |
||||
die("%s died with strange error", sender); |
||||
default: |
||||
return -error; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
int cmd_push(int argc, const char **argv, char **envp) |
||||
{ |
||||
int i; |
||||
const char *repo = "origin"; // default repository |
||||
|
||||
for (i = 1; i < argc; i++) { |
||||
const char *arg = argv[i]; |
||||
|
||||
if (arg[0] != '-') { |
||||
repo = arg; |
||||
i++; |
||||
break; |
||||
} |
||||
if (!strcmp(arg, "--all")) { |
||||
all = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp(arg, "--tags")) { |
||||
tags = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp(arg, "--force")) { |
||||
force = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp(arg, "--thin")) { |
||||
thin = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp(arg, "--no-thin")) { |
||||
thin = 0; |
||||
continue; |
||||
} |
||||
if (!strncmp(arg, "--exec=", 7)) { |
||||
execute = arg; |
||||
continue; |
||||
} |
||||
usage(push_usage); |
||||
} |
||||
set_refspecs(argv + i, argc - i); |
||||
return do_push(repo); |
||||
} |
@ -0,0 +1,152 @@
@@ -0,0 +1,152 @@
|
||||
/* |
||||
* "git rm" builtin command |
||||
* |
||||
* Copyright (C) Linus Torvalds 2006 |
||||
*/ |
||||
#include "cache.h" |
||||
#include "builtin.h" |
||||
#include "dir.h" |
||||
#include "cache-tree.h" |
||||
|
||||
static const char builtin_rm_usage[] = |
||||
"git-rm [-n] [-v] [-f] <filepattern>..."; |
||||
|
||||
static struct { |
||||
int nr, alloc; |
||||
const char **name; |
||||
} list; |
||||
|
||||
static void add_list(const char *name) |
||||
{ |
||||
if (list.nr >= list.alloc) { |
||||
list.alloc = alloc_nr(list.alloc); |
||||
list.name = xrealloc(list.name, list.alloc * sizeof(const char *)); |
||||
} |
||||
list.name[list.nr++] = name; |
||||
} |
||||
|
||||
static int remove_file(const char *name) |
||||
{ |
||||
int ret; |
||||
char *slash; |
||||
|
||||
ret = unlink(name); |
||||
if (!ret && (slash = strrchr(name, '/'))) { |
||||
char *n = strdup(name); |
||||
do { |
||||
n[slash - name] = 0; |
||||
name = n; |
||||
} while (!rmdir(name) && (slash = strrchr(name, '/'))); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
static struct cache_file cache_file; |
||||
|
||||
int cmd_rm(int argc, const char **argv, char **envp) |
||||
{ |
||||
int i, newfd; |
||||
int verbose = 0, show_only = 0, force = 0; |
||||
const char *prefix = setup_git_directory(); |
||||
const char **pathspec; |
||||
char *seen; |
||||
|
||||
git_config(git_default_config); |
||||
|
||||
newfd = hold_index_file_for_update(&cache_file, get_index_file()); |
||||
if (newfd < 0) |
||||
die("unable to create new index file"); |
||||
|
||||
if (read_cache() < 0) |
||||
die("index file corrupt"); |
||||
|
||||
for (i = 1 ; i < argc ; i++) { |
||||
const char *arg = argv[i]; |
||||
|
||||
if (*arg != '-') |
||||
break; |
||||
if (!strcmp(arg, "--")) { |
||||
i++; |
||||
break; |
||||
} |
||||
if (!strcmp(arg, "-n")) { |
||||
show_only = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp(arg, "-v")) { |
||||
verbose = 1; |
||||
continue; |
||||
} |
||||
if (!strcmp(arg, "-f")) { |
||||
force = 1; |
||||
continue; |
||||
} |
||||
die(builtin_rm_usage); |
||||
} |
||||
pathspec = get_pathspec(prefix, argv + i); |
||||
|
||||
seen = NULL; |
||||
if (pathspec) { |
||||
for (i = 0; pathspec[i] ; i++) |
||||
/* nothing */; |
||||
seen = xmalloc(i); |
||||
memset(seen, 0, i); |
||||
} |
||||
|
||||
for (i = 0; i < active_nr; i++) { |
||||
struct cache_entry *ce = active_cache[i]; |
||||
if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen)) |
||||
continue; |
||||
add_list(ce->name); |
||||
} |
||||
|
||||
if (pathspec) { |
||||
const char *match; |
||||
for (i = 0; (match = pathspec[i]) != NULL ; i++) { |
||||
if (*match && !seen[i]) |
||||
die("pathspec '%s' did not match any files", match); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* First remove the names from the index: we won't commit |
||||
* the index unless all of them succeed |
||||
*/ |
||||
for (i = 0; i < list.nr; i++) { |
||||
const char *path = list.name[i]; |
||||
printf("rm '%s'\n", path); |
||||
|
||||
if (remove_file_from_cache(path)) |
||||
die("git rm: unable to remove %s", path); |
||||
cache_tree_invalidate_path(active_cache_tree, path); |
||||
} |
||||
|
||||
/* |
||||
* Then, if we used "-f", remove the filenames from the |
||||
* workspace. If we fail to remove the first one, we |
||||
* abort the "git rm" (but once we've successfully removed |
||||
* any file at all, we'll go ahead and commit to it all: |
||||
* by then we've already committed ourself and can't fail |
||||
* in the middle) |
||||
*/ |
||||
if (force) { |
||||
int removed = 0; |
||||
for (i = 0; i < list.nr; i++) { |
||||
const char *path = list.name[i]; |
||||
if (!remove_file(path)) { |
||||
removed = 1; |
||||
continue; |
||||
} |
||||
if (!removed) |
||||
die("git rm: %s: %s", path, strerror(errno)); |
||||
} |
||||
} |
||||
|
||||
if (active_cache_changed) { |
||||
if (write_cache(newfd, active_cache, active_nr) || |
||||
commit_index_file(&cache_file)) |
||||
die("Unable to write new index file"); |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -1,17 +0,0 @@
@@ -1,17 +0,0 @@
|
||||
/* |
||||
* GIT - The information manager from hell |
||||
*/ |
||||
|
||||
#include "cache.h" |
||||
#include "refs.h" |
||||
|
||||
#include <stdio.h> |
||||
|
||||
int main(int ac, char **av) |
||||
{ |
||||
if (ac != 2) |
||||
usage("git-check-ref-format refname"); |
||||
if (check_ref_format(av[1])) |
||||
exit(1); |
||||
return 0; |
||||
} |
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
#!/bin/sh |
||||
|
||||
# Use this tool to rewrite your .git/remotes/ files into the config. |
||||
|
||||
. git-sh-setup |
||||
|
||||
if [ -d "$GIT_DIR"/remotes ]; then |
||||
echo "Rewriting $GIT_DIR/remotes" >&2 |
||||
error=0 |
||||
# rewrite into config |
||||
{ |
||||
cd "$GIT_DIR"/remotes |
||||
ls | while read f; do |
||||
name=$(echo -n "$f" | tr -c "A-Za-z0-9" ".") |
||||
sed -n \ |
||||
-e "s/^URL: \(.*\)$/remote.$name.url \1 ./p" \ |
||||
-e "s/^Pull: \(.*\)$/remote.$name.fetch \1 ^$ /p" \ |
||||
-e "s/^Push: \(.*\)$/remote.$name.push \1 ^$ /p" \ |
||||
< "$f" |
||||
done |
||||
echo done |
||||
} | while read key value regex; do |
||||
case $key in |
||||
done) |
||||
if [ $error = 0 ]; then |
||||
mv "$GIT_DIR"/remotes "$GIT_DIR"/remotes.old |
||||
fi ;; |
||||
*) |
||||
echo "git-repo-config $key "$value" $regex" |
||||
git-repo-config $key "$value" $regex || error=1 ;; |
||||
esac |
||||
done |
||||
fi |
||||
|
||||
|
@ -0,0 +1,401 @@
@@ -0,0 +1,401 @@
|
||||
/* |
||||
* This handles recursive filename detection with exclude |
||||
* files, index knowledge etc.. |
||||
* |
||||
* Copyright (C) Linus Torvalds, 2005-2006 |
||||
* Junio Hamano, 2005-2006 |
||||
*/ |
||||
#include <dirent.h> |
||||
#include <fnmatch.h> |
||||
|
||||
#include "cache.h" |
||||
#include "dir.h" |
||||
|
||||
int common_prefix(const char **pathspec) |
||||
{ |
||||
const char *path, *slash, *next; |
||||
int prefix; |
||||
|
||||
if (!pathspec) |
||||
return 0; |
||||
|
||||
path = *pathspec; |
||||
slash = strrchr(path, '/'); |
||||
if (!slash) |
||||
return 0; |
||||
|
||||
prefix = slash - path + 1; |
||||
while ((next = *++pathspec) != NULL) { |
||||
int len = strlen(next); |
||||
if (len >= prefix && !memcmp(path, next, len)) |
||||
continue; |
||||
for (;;) { |
||||
if (!len) |
||||
return 0; |
||||
if (next[--len] != '/') |
||||
continue; |
||||
if (memcmp(path, next, len+1)) |
||||
continue; |
||||
prefix = len + 1; |
||||
break; |
||||
} |
||||
} |
||||
return prefix; |
||||
} |
||||
|
||||
static int match_one(const char *match, const char *name, int namelen) |
||||
{ |
||||
int matchlen; |
||||
|
||||
/* If the match was just the prefix, we matched */ |
||||
matchlen = strlen(match); |
||||
if (!matchlen) |
||||
return 1; |
||||
|
||||
/* |
||||
* If we don't match the matchstring exactly, |
||||
* we need to match by fnmatch |
||||
*/ |
||||
if (strncmp(match, name, matchlen)) |
||||
return !fnmatch(match, name, 0); |
||||
|
||||
/* |
||||
* If we did match the string exactly, we still |
||||
* need to make sure that it happened on a path |
||||
* component boundary (ie either the last character |
||||
* of the match was '/', or the next character of |
||||
* the name was '/' or the terminating NUL. |
||||
*/ |
||||
return match[matchlen-1] == '/' || |
||||
name[matchlen] == '/' || |
||||
!name[matchlen]; |
||||
} |
||||
|
||||
int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen) |
||||
{ |
||||
int retval; |
||||
const char *match; |
||||
|
||||
name += prefix; |
||||
namelen -= prefix; |
||||
|
||||
for (retval = 0; (match = *pathspec++) != NULL; seen++) { |
||||
if (retval & *seen) |
||||
continue; |
||||
match += prefix; |
||||
if (match_one(match, name, namelen)) { |
||||
retval = 1; |
||||
*seen = 1; |
||||
} |
||||
} |
||||
return retval; |
||||
} |
||||
|
||||
void add_exclude(const char *string, const char *base, |
||||
int baselen, struct exclude_list *which) |
||||
{ |
||||
struct exclude *x = xmalloc(sizeof (*x)); |
||||
|
||||
x->pattern = string; |
||||
x->base = base; |
||||
x->baselen = baselen; |
||||
if (which->nr == which->alloc) { |
||||
which->alloc = alloc_nr(which->alloc); |
||||
which->excludes = realloc(which->excludes, |
||||
which->alloc * sizeof(x)); |
||||
} |
||||
which->excludes[which->nr++] = x; |
||||
} |
||||
|
||||
static int add_excludes_from_file_1(const char *fname, |
||||
const char *base, |
||||
int baselen, |
||||
struct exclude_list *which) |
||||
{ |
||||
int fd, i; |
||||
long size; |
||||
char *buf, *entry; |
||||
|
||||
fd = open(fname, O_RDONLY); |
||||
if (fd < 0) |
||||
goto err; |
||||
size = lseek(fd, 0, SEEK_END); |
||||
if (size < 0) |
||||
goto err; |
||||
lseek(fd, 0, SEEK_SET); |
||||
if (size == 0) { |
||||
close(fd); |
||||
return 0; |
||||
} |
||||
buf = xmalloc(size+1); |
||||
if (read(fd, buf, size) != size) |
||||
goto err; |
||||
close(fd); |
||||
|
||||
buf[size++] = '\n'; |
||||
entry = buf; |
||||
for (i = 0; i < size; i++) { |
||||
if (buf[i] == '\n') { |
||||
if (entry != buf + i && entry[0] != '#') { |
||||
buf[i - (i && buf[i-1] == '\r')] = 0; |
||||
add_exclude(entry, base, baselen, which); |
||||
} |
||||
entry = buf + i + 1; |
||||
} |
||||
} |
||||
return 0; |
||||
|
||||
err: |
||||
if (0 <= fd) |
||||
close(fd); |
||||
return -1; |
||||
} |
||||
|
||||
void add_excludes_from_file(struct dir_struct *dir, const char *fname) |
||||
{ |
||||
if (add_excludes_from_file_1(fname, "", 0, |
||||
&dir->exclude_list[EXC_FILE]) < 0) |
||||
die("cannot use %s as an exclude file", fname); |
||||
} |
||||
|
||||
static int push_exclude_per_directory(struct dir_struct *dir, const char *base, int baselen) |
||||
{ |
||||
char exclude_file[PATH_MAX]; |
||||
struct exclude_list *el = &dir->exclude_list[EXC_DIRS]; |
||||
int current_nr = el->nr; |
||||
|
||||
if (dir->exclude_per_dir) { |
||||
memcpy(exclude_file, base, baselen); |
||||
strcpy(exclude_file + baselen, dir->exclude_per_dir); |
||||
add_excludes_from_file_1(exclude_file, base, baselen, el); |
||||
} |
||||
return current_nr; |
||||
} |
||||
|
||||
static void pop_exclude_per_directory(struct dir_struct *dir, int stk) |
||||
{ |
||||
struct exclude_list *el = &dir->exclude_list[EXC_DIRS]; |
||||
|
||||
while (stk < el->nr) |
||||
free(el->excludes[--el->nr]); |
||||
} |
||||
|
||||
/* Scan the list and let the last match determines the fate. |
||||
* Return 1 for exclude, 0 for include and -1 for undecided. |
||||
*/ |
||||
static int excluded_1(const char *pathname, |
||||
int pathlen, |
||||
struct exclude_list *el) |
||||
{ |
||||
int i; |
||||
|
||||
if (el->nr) { |
||||
for (i = el->nr - 1; 0 <= i; i--) { |
||||
struct exclude *x = el->excludes[i]; |
||||
const char *exclude = x->pattern; |
||||
int to_exclude = 1; |
||||
|
||||
if (*exclude == '!') { |
||||
to_exclude = 0; |
||||
exclude++; |
||||
} |
||||
|
||||
if (!strchr(exclude, '/')) { |
||||
/* match basename */ |
||||
const char *basename = strrchr(pathname, '/'); |
||||
basename = (basename) ? basename+1 : pathname; |
||||
if (fnmatch(exclude, basename, 0) == 0) |
||||
return to_exclude; |
||||
} |
||||
else { |
||||
/* match with FNM_PATHNAME: |
||||
* exclude has base (baselen long) implicitly |
||||
* in front of it. |
||||
*/ |
||||
int baselen = x->baselen; |
||||
if (*exclude == '/') |
||||
exclude++; |
||||
|
||||
if (pathlen < baselen || |
||||
(baselen && pathname[baselen-1] != '/') || |
||||
strncmp(pathname, x->base, baselen)) |
||||
continue; |
||||
|
||||
if (fnmatch(exclude, pathname+baselen, |
||||
FNM_PATHNAME) == 0) |
||||
return to_exclude; |
||||
} |
||||
} |
||||
} |
||||
return -1; /* undecided */ |
||||
} |
||||
|
||||
int excluded(struct dir_struct *dir, const char *pathname) |
||||
{ |
||||
int pathlen = strlen(pathname); |
||||
int st; |
||||
|
||||
for (st = EXC_CMDL; st <= EXC_FILE; st++) { |
||||
switch (excluded_1(pathname, pathlen, &dir->exclude_list[st])) { |
||||
case 0: |
||||
return 0; |
||||
case 1: |
||||
return 1; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static void add_name(struct dir_struct *dir, const char *pathname, int len) |
||||
{ |
||||
struct dir_entry *ent; |
||||
|
||||
if (cache_name_pos(pathname, len) >= 0) |
||||
return; |
||||
|
||||
if (dir->nr == dir->alloc) { |
||||
int alloc = alloc_nr(dir->alloc); |
||||
dir->alloc = alloc; |
||||
dir->entries = xrealloc(dir->entries, alloc*sizeof(ent)); |
||||
} |
||||
ent = xmalloc(sizeof(*ent) + len + 1); |
||||
ent->len = len; |
||||
memcpy(ent->name, pathname, len); |
||||
ent->name[len] = 0; |
||||
dir->entries[dir->nr++] = ent; |
||||
} |
||||
|
||||
static int dir_exists(const char *dirname, int len) |
||||
{ |
||||
int pos = cache_name_pos(dirname, len); |
||||
if (pos >= 0) |
||||
return 1; |
||||
pos = -pos-1; |
||||
if (pos >= active_nr) /* can't */ |
||||
return 0; |
||||
return !strncmp(active_cache[pos]->name, dirname, len); |
||||
} |
||||
|
||||
/* |
||||
* Read a directory tree. We currently ignore anything but |
||||
* directories, regular files and symlinks. That's because git |
||||
* doesn't handle them at all yet. Maybe that will change some |
||||
* day. |
||||
* |
||||
* Also, we ignore the name ".git" (even if it is not a directory). |
||||
* That likely will not change. |
||||
*/ |
||||
static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen) |
||||
{ |
||||
DIR *fdir = opendir(path); |
||||
int contents = 0; |
||||
|
||||
if (fdir) { |
||||
int exclude_stk; |
||||
struct dirent *de; |
||||
char fullname[MAXPATHLEN + 1]; |
||||
memcpy(fullname, base, baselen); |
||||
|
||||
exclude_stk = push_exclude_per_directory(dir, base, baselen); |
||||
|
||||
while ((de = readdir(fdir)) != NULL) { |
||||
int len; |
||||
|
||||
if ((de->d_name[0] == '.') && |
||||
(de->d_name[1] == 0 || |
||||
!strcmp(de->d_name + 1, ".") || |
||||
!strcmp(de->d_name + 1, "git"))) |
||||
continue; |
||||
len = strlen(de->d_name); |
||||
memcpy(fullname + baselen, de->d_name, len+1); |
||||
if (excluded(dir, fullname) != dir->show_ignored) { |
||||
if (!dir->show_ignored || DTYPE(de) != DT_DIR) { |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
switch (DTYPE(de)) { |
||||
struct stat st; |
||||
int subdir, rewind_base; |
||||
default: |
||||
continue; |
||||
case DT_UNKNOWN: |
||||
if (lstat(fullname, &st)) |
||||
continue; |
||||
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) |
||||
break; |
||||
if (!S_ISDIR(st.st_mode)) |
||||
continue; |
||||
/* fallthrough */ |
||||
case DT_DIR: |
||||
memcpy(fullname + baselen + len, "/", 2); |
||||
len++; |
||||
rewind_base = dir->nr; |
||||
subdir = read_directory_recursive(dir, fullname, fullname, |
||||
baselen + len); |
||||
if (dir->show_other_directories && |
||||
(subdir || !dir->hide_empty_directories) && |
||||
!dir_exists(fullname, baselen + len)) { |
||||
// Rewind the read subdirectory |
||||
while (dir->nr > rewind_base) |
||||
free(dir->entries[--dir->nr]); |
||||
break; |
||||
} |
||||
contents += subdir; |
||||
continue; |
||||
case DT_REG: |
||||
case DT_LNK: |
||||
break; |
||||
} |
||||
add_name(dir, fullname, baselen + len); |
||||
contents++; |
||||
} |
||||
closedir(fdir); |
||||
|
||||
pop_exclude_per_directory(dir, exclude_stk); |
||||
} |
||||
|
||||
return contents; |
||||
} |
||||
|
||||
static int cmp_name(const void *p1, const void *p2) |
||||
{ |
||||
const struct dir_entry *e1 = *(const struct dir_entry **)p1; |
||||
const struct dir_entry *e2 = *(const struct dir_entry **)p2; |
||||
|
||||
return cache_name_compare(e1->name, e1->len, |
||||
e2->name, e2->len); |
||||
} |
||||
|
||||
int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen) |
||||
{ |
||||
/* |
||||
* Make sure to do the per-directory exclude for all the |
||||
* directories leading up to our base. |
||||
*/ |
||||
if (baselen) { |
||||
if (dir->exclude_per_dir) { |
||||
char *p, *pp = xmalloc(baselen+1); |
||||
memcpy(pp, base, baselen+1); |
||||
p = pp; |
||||
while (1) { |
||||
char save = *p; |
||||
*p = 0; |
||||
push_exclude_per_directory(dir, pp, p-pp); |
||||
*p++ = save; |
||||
if (!save) |
||||
break; |
||||
p = strchr(p, '/'); |
||||
if (p) |
||||
p++; |
||||
else |
||||
p = pp + baselen; |
||||
} |
||||
free(pp); |
||||
} |
||||
} |
||||
|
||||
read_directory_recursive(dir, path, base, baselen); |
||||
qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name); |
||||
return dir->nr; |
||||
} |
@ -0,0 +1,51 @@
@@ -0,0 +1,51 @@
|
||||
#ifndef DIR_H |
||||
#define DIR_H |
||||
|
||||
/* |
||||
* We maintain three exclude pattern lists: |
||||
* EXC_CMDL lists patterns explicitly given on the command line. |
||||
* EXC_DIRS lists patterns obtained from per-directory ignore files. |
||||
* EXC_FILE lists patterns from fallback ignore files. |
||||
*/ |
||||
#define EXC_CMDL 0 |
||||
#define EXC_DIRS 1 |
||||
#define EXC_FILE 2 |
||||
|
||||
|
||||
struct dir_entry { |
||||
int len; |
||||
char name[FLEX_ARRAY]; /* more */ |
||||
}; |
||||
|
||||
struct exclude_list { |
||||
int nr; |
||||
int alloc; |
||||
struct exclude { |
||||
const char *pattern; |
||||
const char *base; |
||||
int baselen; |
||||
} **excludes; |
||||
}; |
||||
|
||||
struct dir_struct { |
||||
int nr, alloc; |
||||
unsigned int show_ignored:1, |
||||
show_other_directories:1, |
||||
hide_empty_directories:1; |
||||
struct dir_entry **entries; |
||||
|
||||
/* Exclude info */ |
||||
const char *exclude_per_dir; |
||||
struct exclude_list exclude_list[3]; |
||||
}; |
||||
|
||||
extern int common_prefix(const char **pathspec); |
||||
extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen); |
||||
|
||||
extern int read_directory(struct dir_struct *, const char *path, const char *base, int baselen); |
||||
extern int excluded(struct dir_struct *, const char *); |
||||
extern void add_excludes_from_file(struct dir_struct *, const char *fname); |
||||
extern void add_exclude(const char *string, const char *base, |
||||
int baselen, struct exclude_list *which); |
||||
|
||||
#endif |
@ -1,56 +0,0 @@
@@ -1,56 +0,0 @@
|
||||
#!/bin/sh |
||||
|
||||
USAGE='[-n] [-v] <file>...' |
||||
SUBDIRECTORY_OK='Yes' |
||||
. git-sh-setup |
||||
|
||||
show_only= |
||||
verbose= |
||||
while : ; do |
||||
case "$1" in |
||||
-n) |
||||
show_only=true |
||||
;; |
||||
-v) |
||||
verbose=--verbose |
||||
;; |
||||
--) |
||||
shift |
||||
break |
||||
;; |
||||
-*) |
||||
usage |
||||
;; |
||||
*) |
||||
break |
||||
;; |
||||
esac |
||||
shift |
||||
done |
||||
|
||||
# Check misspelled pathspec |
||||
case "$#" in |
||||
0) ;; |
||||
*) |
||||
git-ls-files --error-unmatch --others --cached -- "$@" >/dev/null || { |
||||
echo >&2 "Maybe you misspelled it?" |
||||
exit 1 |
||||
} |
||||
;; |
||||
esac |
||||
|
||||
if test -f "$GIT_DIR/info/exclude" |
||||
then |
||||
git-ls-files -z \ |
||||
--exclude-from="$GIT_DIR/info/exclude" \ |
||||
--others --exclude-per-directory=.gitignore -- "$@" |
||||
else |
||||
git-ls-files -z \ |
||||
--others --exclude-per-directory=.gitignore -- "$@" |
||||
fi | |
||||
case "$show_only" in |
||||
true) |
||||
xargs -0 echo ;; |
||||
*) |
||||
git-update-index --add $verbose -z --stdin ;; |
||||
esac |
@ -1,31 +0,0 @@
@@ -1,31 +0,0 @@
|
||||
#!/bin/sh |
||||
# |
||||
# Copyright (c) 2005 Junio C Hamano |
||||
# |
||||
|
||||
GIT_DIR=`git-rev-parse --git-dir` || exit $? |
||||
|
||||
dc </dev/null 2>/dev/null || { |
||||
# This is not a real DC at all -- it just knows how |
||||
# this script feeds DC and does the computation itself. |
||||
dc () { |
||||
while read a b |
||||
do |
||||
case $a,$b in |
||||
0,) acc=0 ;; |
||||
*,+) acc=$(($acc + $a)) ;; |
||||
p,) echo "$acc" ;; |
||||
esac |
||||
done |
||||
} |
||||
} |
||||
|
||||
echo $(find "$GIT_DIR/objects"/?? -type f -print 2>/dev/null | wc -l) objects, \ |
||||
$({ |
||||
echo 0 |
||||
# "no-such" is to help Darwin folks by not using xargs -r. |
||||
find "$GIT_DIR/objects"/?? -type f -print 2>/dev/null | |
||||
xargs du -k "$GIT_DIR/objects/no-such" 2>/dev/null | |
||||
sed -e 's/[ ].*/ +/' |
||||
echo p |
||||
} | dc) kilobytes |
@ -1,74 +0,0 @@
@@ -1,74 +0,0 @@
|
||||
#!/bin/sh |
||||
# |
||||
# Copyright (c) 2005 Linus Torvalds |
||||
# Copyright (c) 2005 Junio C Hamano |
||||
|
||||
USAGE='[ --diff-options ] <ent>{0,2} [<path>...]' |
||||
SUBDIRECTORY_OK='Yes' |
||||
. git-sh-setup |
||||
|
||||
rev=$(git-rev-parse --revs-only --no-flags --sq "$@") || exit |
||||
flags=$(git-rev-parse --no-revs --flags --sq "$@") |
||||
files=$(git-rev-parse --no-revs --no-flags --sq "$@") |
||||
|
||||
# I often say 'git diff --cached -p' and get scolded by git-diff-files, but |
||||
# obviously I mean 'git diff --cached -p HEAD' in that case. |
||||
case "$rev" in |
||||
'') |
||||
case " $flags " in |
||||
*" '--cached' "*) |
||||
rev='HEAD ' |
||||
;; |
||||
esac |
||||
esac |
||||
|
||||
# If we have -[123] --ours --theirs --base, don't do --cc by default. |
||||
case " $flags " in |
||||
*" '-"[123]"' "* | *" '--ours' "* | *" '--base' "* | *" '--theirs' "*) |
||||
cc_or_p=-p ;; |
||||
*) |
||||
cc_or_p=--cc ;; |
||||
esac |
||||
|
||||
# If we do not have --name-status, --name-only, -r, -c or --stat, |
||||
# default to --cc. |
||||
case " $flags " in |
||||
*" '--name-status' "* | *" '--name-only' "* | *" '-r' "* | *" '-c' "* | \ |
||||
*" '--stat' "*) |
||||
;; |
||||
*) |
||||
flags="$flags'$cc_or_p' " ;; |
||||
esac |
||||
|
||||
# If we do not have -B, -C, -r, nor -p, default to -M. |
||||
case " $flags " in |
||||
*" '-"[BCMrp]* | *" '--find-copies-harder' "*) |
||||
;; # something like -M50. |
||||
*) |
||||
flags="$flags'-M' " ;; |
||||
esac |
||||
|
||||
case "$rev" in |
||||
?*' '?*' '?*) |
||||
usage |
||||
;; |
||||
?*' '^?*) |
||||
begin=$(expr "$rev" : '.*^.\([0-9a-f]*\).*') && |
||||
end=$(expr "$rev" : '.\([0-9a-f]*\). .*') || exit |
||||
cmd="git-diff-tree $flags $begin $end -- $files" |
||||
;; |
||||
?*' '?*) |
||||
cmd="git-diff-tree $flags $rev -- $files" |
||||
;; |
||||
?*' ') |
||||
cmd="git-diff-index $flags $rev -- $files" |
||||
;; |
||||
'') |
||||
cmd="git-diff-files $flags -- $files" |
||||
;; |
||||
*) |
||||
usage |
||||
;; |
||||
esac |
||||
|
||||
eval "$cmd" |
@ -1,62 +0,0 @@
@@ -1,62 +0,0 @@
|
||||
#!/bin/sh |
||||
# |
||||
# Copyright (c) Linus Torvalds, 2005 |
||||
# |
||||
|
||||
USAGE='[<option>...] [-e] <pattern> [<path>...]' |
||||
SUBDIRECTORY_OK='Yes' |
||||
. git-sh-setup |
||||
|
||||
got_pattern () { |
||||
if [ -z "$no_more_patterns" ] |
||||
then |
||||
pattern="$1" no_more_patterns=yes |
||||
else |
||||
die "git-grep: do not specify more than one pattern" |
||||
fi |
||||
} |
||||
|
||||
no_more_patterns= |
||||
pattern= |
||||
flags=() |
||||
git_flags=() |
||||
while : ; do |
||||
case "$1" in |
||||
-o|--cached|--deleted|--others|--killed|\ |
||||
--ignored|--modified|--exclude=*|\ |
||||
--exclude-from=*|\--exclude-per-directory=*) |
||||
git_flags=("${git_flags[@]}" "$1") |
||||
;; |
||||
-e) |
||||
got_pattern "$2" |
||||
shift |
||||
;; |
||||
-A|-B|-C|-D|-d|-f|-m) |
||||
flags=("${flags[@]}" "$1" "$2") |
||||
shift |
||||
;; |
||||
--) |
||||
# The rest are git-ls-files paths |
||||
shift |
||||
break |
||||
;; |
||||
-*) |
||||
flags=("${flags[@]}" "$1") |
||||
;; |
||||
*) |
||||
if [ -z "$no_more_patterns" ] |
||||
then |
||||
got_pattern "$1" |
||||
shift |
||||
fi |
||||
[ "$1" = -- ] && shift |
||||
break |
||||
;; |
||||
esac |
||||
shift |
||||
done |
||||
[ "$pattern" ] || { |
||||
usage |
||||
} |
||||
git-ls-files -z "${git_flags[@]}" -- "$@" | |
||||
xargs -0 grep "${flags[@]}" -e "$pattern" -- |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue