mirror of
https://github.com/git/git.git
synced 2026-03-13 18:33:25 +01:00
Merge branch 'master' of git://repo.or.cz/alt-git
This commit is contained in:
@@ -15,6 +15,9 @@ release, but users are again strongly encouraged to adjust their
|
||||
scripts to use "git xyzzy" form, as we will stop installing
|
||||
"git-xyzzy" hardlinks for built-in commands in later releases.
|
||||
|
||||
An earlier change to page "git status" output was overwhelmingly unpopular
|
||||
and has been reverted.
|
||||
|
||||
Source changes needed for porting to MinGW environment are now all in the
|
||||
main git.git codebase.
|
||||
|
||||
@@ -179,6 +182,10 @@ Updates since v1.5.6
|
||||
* "git rerere" can be told to update the index with auto-reused resolution
|
||||
with rerere.autoupdate configuration variable.
|
||||
|
||||
* git-rev-parse learned $commit^! and $commit^@ notations used in "log"
|
||||
family. These notations are available in gitk as well, because the gitk
|
||||
command internally uses rev-parse to interpret its arguments.
|
||||
|
||||
* git-rev-list learned --children option to show child commits it
|
||||
encountered during the traversal, instead of shoing parent commits.
|
||||
|
||||
@@ -196,6 +203,9 @@ Updates since v1.5.6
|
||||
* git-status gives the remote tracking statistics similar to the way
|
||||
git-checkout reports by how many commits your branch is ahead/behind.
|
||||
|
||||
* "git-svn dcommit" is now aware of auto-props setting the subversion user
|
||||
has.
|
||||
|
||||
* You can tell "git status -u" to even more aggressively omit checking
|
||||
untracked files with --untracked-files=no.
|
||||
|
||||
@@ -215,8 +225,15 @@ Fixes since v1.5.6
|
||||
All of the fixes in v1.5.6 maintenance series are included in
|
||||
this release, unless otherwise noted.
|
||||
|
||||
* git-clone ignored its -u option; the fix needs to be backported to
|
||||
'maint';
|
||||
|
||||
* git-mv used to lose the distinction between changes that are staged
|
||||
and that are only in the working tree, by staging both in the index
|
||||
after moving such a path.
|
||||
|
||||
---
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.6.4-432-g6796399
|
||||
O=v1.6.0-rc0-104-g81dc230
|
||||
echo O=$(git describe refs/heads/master)
|
||||
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
|
||||
|
||||
@@ -92,7 +92,7 @@ Example
|
||||
|
||||
# Our diff algorithm
|
||||
[diff]
|
||||
external = "/usr/local/bin/gnu-diff -u"
|
||||
external = /usr/local/bin/diff-wrapper
|
||||
renames = true
|
||||
|
||||
[branch "devel"]
|
||||
@@ -117,6 +117,13 @@ core.fileMode::
|
||||
the working copy are ignored; useful on broken filesystems like FAT.
|
||||
See linkgit:git-update-index[1]. True by default.
|
||||
|
||||
core.trustctime::
|
||||
If false, the ctime differences between the index and the
|
||||
working copy are ignored; useful when the inode change time
|
||||
is regularly modified by something outside Git (file system
|
||||
crawlers and some backup systems).
|
||||
See linkgit:git-update-index[1]. True by default.
|
||||
|
||||
core.quotepath::
|
||||
The commands that output paths (e.g. 'ls-files',
|
||||
'diff'), when not given the `-z` option, will quote
|
||||
@@ -563,9 +570,11 @@ diff.autorefreshindex::
|
||||
diff.external::
|
||||
If this config variable is set, diff generation is not
|
||||
performed using the internal diff machinery, but using the
|
||||
given command. Note: if you want to use an external diff
|
||||
program only on a subset of your files, you might want to
|
||||
use linkgit:gitattributes[5] instead.
|
||||
given command. Can be overridden with the `GIT_EXTERNAL_DIFF'
|
||||
environment variable. The command is called with parameters
|
||||
as described under "git Diffs" in linkgit:git[1]. Note: if
|
||||
you want to use an external diff program only on a subset of
|
||||
your files, you might want to use linkgit:gitattributes[5] instead.
|
||||
|
||||
diff.renameLimit::
|
||||
The number of files to consider when performing the copy/rename
|
||||
|
||||
@@ -222,7 +222,7 @@ Given a .git/config like this:
|
||||
|
||||
; Our diff algorithm
|
||||
[diff]
|
||||
external = "/usr/local/bin/gnu-diff -u"
|
||||
external = /usr/local/bin/diff-wrapper
|
||||
renames = true
|
||||
|
||||
; Proxy settings
|
||||
|
||||
@@ -58,7 +58,7 @@ include::diff-options.txt[]
|
||||
its size is not included.
|
||||
|
||||
<paths>...::
|
||||
Show only commits that affect the specified paths.
|
||||
Show only commits that affect any of the specified paths.
|
||||
|
||||
|
||||
include::rev-list-options.txt[]
|
||||
|
||||
@@ -53,7 +53,7 @@ OPTIONS
|
||||
|
||||
-s::
|
||||
--stage::
|
||||
Show stage files in the output
|
||||
Show staged contents' object name, mode bits and stage number in the output.
|
||||
|
||||
--directory::
|
||||
If a whole directory is classified as "other", show just its
|
||||
|
||||
@@ -16,10 +16,20 @@ SYNOPSIS
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Lists the contents of a given tree object, like what "/bin/ls -a" does
|
||||
in the current working directory. Note that the usage is subtly different,
|
||||
though - 'paths' denote just a list of patterns to match, e.g. so specifying
|
||||
directory name (without '-r') will behave differently, and order of the
|
||||
arguments does not matter.
|
||||
in the current working directory. Note that:
|
||||
|
||||
- the behaviour is slightly different from that of "/bin/ls" in that the
|
||||
'paths' denote just a list of patterns to match, e.g. so specifying
|
||||
directory name (without '-r') will behave differently, and order of the
|
||||
arguments does not matter.
|
||||
|
||||
- the behaviour is similar to that of "/bin/ls" in that the 'paths' is
|
||||
taken as relative to the current working directory. E.g. when you are
|
||||
in a directory 'sub' that has a directory 'dir', you can run 'git
|
||||
ls-tree -r HEAD dir' to list the contents of the tree (that is
|
||||
'sub/dir' in 'HEAD'). You don't want to give a tree that is not at the
|
||||
root level (e.g. 'git ls-tree -r HEAD:sub dir') in this case, as that
|
||||
would result in asking for 'sub/sub/dir' in the 'HEAD' commit.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
@@ -63,7 +63,7 @@ COMMANDS
|
||||
add::
|
||||
Add the given repository as a submodule at the given path
|
||||
to the changeset to be committed next to the current
|
||||
project: the current project is termed termed the "superproject".
|
||||
project: the current project is termed the "superproject".
|
||||
+
|
||||
This requires two arguments: <repository> and <path>.
|
||||
+
|
||||
|
||||
@@ -323,6 +323,11 @@ from symbolic link to regular file.
|
||||
The command looks at `core.ignorestat` configuration variable. See
|
||||
'Using "assume unchanged" bit' section above.
|
||||
|
||||
The command also looks at `core.trustctime` configuration variable.
|
||||
It can be useful when the inode change time is regularly modified by
|
||||
something outside Git (file system crawlers and backup systems use
|
||||
ctime for marking files processed) (see linkgit:git-config[1]).
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
7
Makefile
7
Makefile
@@ -1067,7 +1067,7 @@ endif
|
||||
|
||||
all::
|
||||
ifndef NO_TCLTK
|
||||
$(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) all
|
||||
$(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) gitexecdir='$(gitexec_instdir_SQ)' all
|
||||
$(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all
|
||||
endif
|
||||
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
|
||||
@@ -1362,7 +1362,10 @@ endif
|
||||
cp "$$bindir/git$X" "$$execdir/git$X"; \
|
||||
fi && \
|
||||
{ $(foreach p,$(BUILT_INS), $(RM) "$$execdir/$p" && ln "$$execdir/git$X" "$$execdir/$p" ;) } && \
|
||||
$(RM) "$$execdir/git$X" && \
|
||||
if test "z$$bindir" != "z$$execdir"; \
|
||||
then \
|
||||
$(RM) "$$execdir/git$X"; \
|
||||
fi && \
|
||||
./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
|
||||
|
||||
install-doc:
|
||||
|
||||
@@ -214,7 +214,6 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
|
||||
struct commit *commit;
|
||||
int kind;
|
||||
int len;
|
||||
static struct commit_list branch;
|
||||
|
||||
/* Detect kind */
|
||||
if (!prefixcmp(refname, "refs/heads/")) {
|
||||
@@ -238,13 +237,9 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
|
||||
if ((kind & ref_list->kinds) == 0)
|
||||
return 0;
|
||||
|
||||
if (merge_filter != NO_FILTER) {
|
||||
branch.item = lookup_commit_reference_gently(sha1, 1);
|
||||
if (!branch.item)
|
||||
die("Unable to lookup tip of branch %s", refname);
|
||||
if (merge_filter != NO_FILTER)
|
||||
add_pending_object(&ref_list->revs,
|
||||
(struct object *)branch.item, refname);
|
||||
}
|
||||
(struct object *)commit, refname);
|
||||
|
||||
/* Resize buffer */
|
||||
if (ref_list->index >= ref_list->alloc) {
|
||||
@@ -299,6 +294,17 @@ static void fill_tracking_info(char *stat, const char *branch_name)
|
||||
sprintf(stat, "[ahead %d, behind %d] ", ours, theirs);
|
||||
}
|
||||
|
||||
static int matches_merge_filter(struct commit *commit)
|
||||
{
|
||||
int is_merged;
|
||||
|
||||
if (merge_filter == NO_FILTER)
|
||||
return 1;
|
||||
|
||||
is_merged = !!(commit->object.flags & UNINTERESTING);
|
||||
return (is_merged == (merge_filter == SHOW_MERGED));
|
||||
}
|
||||
|
||||
static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
|
||||
int abbrev, int current)
|
||||
{
|
||||
@@ -306,11 +312,8 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
|
||||
int color;
|
||||
struct commit *commit = item->commit;
|
||||
|
||||
if (merge_filter != NO_FILTER) {
|
||||
int is_merged = !!(item->commit->object.flags & UNINTERESTING);
|
||||
if (is_merged != (merge_filter == SHOW_MERGED))
|
||||
return;
|
||||
}
|
||||
if (!matches_merge_filter(commit))
|
||||
return;
|
||||
|
||||
switch (item->kind) {
|
||||
case REF_LOCAL_BRANCH:
|
||||
@@ -360,6 +363,19 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
|
||||
}
|
||||
}
|
||||
|
||||
static int calc_maxwidth(struct ref_list *refs)
|
||||
{
|
||||
int i, l, w = 0;
|
||||
for (i = 0; i < refs->index; i++) {
|
||||
if (!matches_merge_filter(refs->list[i].commit))
|
||||
continue;
|
||||
l = strlen(refs->list[i].name);
|
||||
if (l > w)
|
||||
w = l;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit)
|
||||
{
|
||||
int i;
|
||||
@@ -380,6 +396,8 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str
|
||||
(struct object *) filter, "");
|
||||
ref_list.revs.limited = 1;
|
||||
prepare_revision_walk(&ref_list.revs);
|
||||
if (verbose)
|
||||
ref_list.maxwidth = calc_maxwidth(&ref_list);
|
||||
}
|
||||
|
||||
qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
|
||||
|
||||
@@ -377,10 +377,6 @@ static void fsck_dir(int i, char *path)
|
||||
if (de->d_name[0] != '.')
|
||||
break;
|
||||
continue;
|
||||
case 14:
|
||||
if (prefixcmp(de->d_name, "tmp_obj_"))
|
||||
break;
|
||||
continue;
|
||||
case 38:
|
||||
sprintf(name, "%02x", i);
|
||||
memcpy(name+2, de->d_name, len+1);
|
||||
@@ -389,6 +385,8 @@ static void fsck_dir(int i, char *path)
|
||||
add_sha1_list(sha1, DIRENT_SORT_HINT(de));
|
||||
continue;
|
||||
}
|
||||
if (prefixcmp(de->d_name, "tmp_obj_"))
|
||||
continue;
|
||||
fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
@@ -117,6 +117,8 @@ static void copy_templates(const char *template_dir)
|
||||
template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
|
||||
if (!template_dir)
|
||||
template_dir = system_path(DEFAULT_GIT_TEMPLATE_DIR);
|
||||
if (!template_dir[0])
|
||||
return;
|
||||
strcpy(template_path, template_dir);
|
||||
template_len = strlen(template_path);
|
||||
if (template_path[template_len-1] != '/') {
|
||||
|
||||
@@ -22,10 +22,23 @@ static int show_merge_base(struct commit *rev1, struct commit *rev2, int show_al
|
||||
static const char merge_base_usage[] =
|
||||
"git merge-base [--all] <commit-id> <commit-id>";
|
||||
|
||||
static struct commit *get_commit_reference(const char *arg)
|
||||
{
|
||||
unsigned char revkey[20];
|
||||
struct commit *r;
|
||||
|
||||
if (get_sha1(arg, revkey))
|
||||
die("Not a valid object name %s", arg);
|
||||
r = lookup_commit_reference(revkey);
|
||||
if (!r)
|
||||
die("Not a valid commit name %s", arg);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int cmd_merge_base(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct commit *rev1, *rev2;
|
||||
unsigned char rev1key[20], rev2key[20];
|
||||
int show_all = 0;
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
@@ -40,13 +53,8 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
if (argc != 3)
|
||||
usage(merge_base_usage);
|
||||
if (get_sha1(argv[1], rev1key))
|
||||
die("Not a valid object name %s", argv[1]);
|
||||
if (get_sha1(argv[2], rev2key))
|
||||
die("Not a valid object name %s", argv[2]);
|
||||
rev1 = lookup_commit_reference(rev1key);
|
||||
rev2 = lookup_commit_reference(rev2key);
|
||||
if (!rev1 || !rev2)
|
||||
return 1;
|
||||
rev1 = get_commit_reference(argv[1]);
|
||||
rev2 = get_commit_reference(argv[2]);
|
||||
|
||||
return show_merge_base(rev1, rev2, show_all);
|
||||
}
|
||||
|
||||
67
builtin-mv.c
67
builtin-mv.c
@@ -36,18 +36,6 @@ static const char **copy_pathspec(const char *prefix, const char **pathspec,
|
||||
return get_pathspec(prefix, result);
|
||||
}
|
||||
|
||||
static void show_list(const char *label, struct string_list *list)
|
||||
{
|
||||
if (list->nr > 0) {
|
||||
int i;
|
||||
printf("%s", label);
|
||||
for (i = 0; i < list->nr; i++)
|
||||
printf("%s%s", i > 0 ? ", " : "",
|
||||
list->items[i].string);
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
static const char *add_slash(const char *path)
|
||||
{
|
||||
int len = strlen(path);
|
||||
@@ -76,11 +64,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
const char **source, **destination, **dest_path;
|
||||
enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
|
||||
struct stat st;
|
||||
struct string_list overwritten = {NULL, 0, 0, 0};
|
||||
struct string_list src_for_dst = {NULL, 0, 0, 0};
|
||||
struct string_list added = {NULL, 0, 0, 0};
|
||||
struct string_list deleted = {NULL, 0, 0, 0};
|
||||
struct string_list changed = {NULL, 0, 0, 0};
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
@@ -185,12 +169,11 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
* only files can overwrite each other:
|
||||
* check both source and destination
|
||||
*/
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
|
||||
fprintf(stderr, "Warning: %s;"
|
||||
" will overwrite!\n",
|
||||
bad);
|
||||
bad = NULL;
|
||||
string_list_insert(dst, &overwritten);
|
||||
} else
|
||||
bad = "Cannot overwrite";
|
||||
}
|
||||
@@ -219,6 +202,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
for (i = 0; i < argc; i++) {
|
||||
const char *src = source[i], *dst = destination[i];
|
||||
enum update_mode mode = modes[i];
|
||||
int pos;
|
||||
if (show_only || verbose)
|
||||
printf("Renaming %s to %s\n", src, dst);
|
||||
if (!show_only && mode != INDEX &&
|
||||
@@ -228,47 +212,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
if (mode == WORKING_DIRECTORY)
|
||||
continue;
|
||||
|
||||
if (cache_name_pos(src, strlen(src)) >= 0) {
|
||||
string_list_insert(src, &deleted);
|
||||
|
||||
/* destination can be a directory with 1 file inside */
|
||||
if (string_list_has_string(&overwritten, dst))
|
||||
string_list_insert(dst, &changed);
|
||||
else
|
||||
string_list_insert(dst, &added);
|
||||
} else
|
||||
string_list_insert(dst, &added);
|
||||
pos = cache_name_pos(src, strlen(src));
|
||||
assert(pos >= 0);
|
||||
if (!show_only)
|
||||
rename_cache_entry_at(pos, dst);
|
||||
}
|
||||
|
||||
if (show_only) {
|
||||
show_list("Changed : ", &changed);
|
||||
show_list("Adding : ", &added);
|
||||
show_list("Deleting : ", &deleted);
|
||||
} else {
|
||||
for (i = 0; i < changed.nr; i++) {
|
||||
const char *path = changed.items[i].string;
|
||||
int j = cache_name_pos(path, strlen(path));
|
||||
struct cache_entry *ce = active_cache[j];
|
||||
|
||||
if (j < 0)
|
||||
die ("Huh? Cache entry for %s unknown?", path);
|
||||
refresh_cache_entry(ce, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < added.nr; i++) {
|
||||
const char *path = added.items[i].string;
|
||||
if (add_file_to_cache(path, verbose ? ADD_CACHE_VERBOSE : 0))
|
||||
die("updating index entries failed");
|
||||
}
|
||||
|
||||
for (i = 0; i < deleted.nr; i++)
|
||||
remove_file_from_cache(deleted.items[i].string);
|
||||
|
||||
if (active_cache_changed) {
|
||||
if (write_cache(newfd, active_cache, active_nr) ||
|
||||
commit_locked_index(&lock_file))
|
||||
die("Unable to write new index file");
|
||||
}
|
||||
if (active_cache_changed) {
|
||||
if (write_cache(newfd, active_cache, active_nr) ||
|
||||
commit_locked_index(&lock_file))
|
||||
die("Unable to write new index file");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -241,6 +241,36 @@ static int try_difference(const char *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int try_parent_shorthands(const char *arg)
|
||||
{
|
||||
char *dotdot;
|
||||
unsigned char sha1[20];
|
||||
struct commit *commit;
|
||||
struct commit_list *parents;
|
||||
int parents_only;
|
||||
|
||||
if ((dotdot = strstr(arg, "^!")))
|
||||
parents_only = 0;
|
||||
else if ((dotdot = strstr(arg, "^@")))
|
||||
parents_only = 1;
|
||||
|
||||
if (!dotdot || dotdot[2])
|
||||
return 0;
|
||||
|
||||
*dotdot = 0;
|
||||
if (get_sha1(arg, sha1))
|
||||
return 0;
|
||||
|
||||
if (!parents_only)
|
||||
show_rev(NORMAL, sha1, arg);
|
||||
commit = lookup_commit_reference(sha1);
|
||||
for (parents = commit->parents; parents; parents = parents->next)
|
||||
show_rev(parents_only ? NORMAL : REVERSED,
|
||||
parents->item->object.sha1, arg);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int parseopt_dump(const struct option *o, const char *arg, int unset)
|
||||
{
|
||||
struct strbuf *parsed = o->value;
|
||||
@@ -573,6 +603,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
/* Not a flag argument */
|
||||
if (try_difference(arg))
|
||||
continue;
|
||||
if (try_parent_shorthands(arg))
|
||||
continue;
|
||||
name = arg;
|
||||
type = NORMAL;
|
||||
if (*arg == '^') {
|
||||
|
||||
@@ -92,14 +92,15 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
if (argc == 1)
|
||||
usage(builtin_verify_tag_usage);
|
||||
|
||||
if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) {
|
||||
if (argc > 1 &&
|
||||
(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose"))) {
|
||||
verbose = 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (argc <= i)
|
||||
usage(builtin_verify_tag_usage);
|
||||
|
||||
/* sometimes the program was terminated because this signal
|
||||
* was received in the process of writing the gpg input: */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
3
cache.h
3
cache.h
@@ -260,6 +260,7 @@ static inline void remove_name_hash(struct cache_entry *ce)
|
||||
#define unmerged_cache() unmerged_index(&the_index)
|
||||
#define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen))
|
||||
#define add_cache_entry(ce, option) add_index_entry(&the_index, (ce), (option))
|
||||
#define rename_cache_entry_at(pos, new_name) rename_index_entry_at(&the_index, (pos), (new_name))
|
||||
#define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))
|
||||
#define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
|
||||
#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags))
|
||||
@@ -370,6 +371,7 @@ extern int index_name_pos(const struct index_state *, const char *name, int name
|
||||
#define ADD_CACHE_JUST_APPEND 8 /* Append only; tree.c::read_tree() */
|
||||
extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
|
||||
extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
|
||||
extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
|
||||
extern int remove_index_entry_at(struct index_state *, int pos);
|
||||
extern int remove_file_from_index(struct index_state *, const char *path);
|
||||
#define ADD_CACHE_VERBOSE 1
|
||||
@@ -421,6 +423,7 @@ extern int delete_ref(const char *, const unsigned char *sha1);
|
||||
|
||||
/* Environment bits from configuration mechanism */
|
||||
extern int trust_executable_bit;
|
||||
extern int trust_ctime;
|
||||
extern int quote_path_fully;
|
||||
extern int has_symlinks;
|
||||
extern int ignore_case;
|
||||
|
||||
4
config.c
4
config.c
@@ -341,6 +341,10 @@ static int git_default_core_config(const char *var, const char *value)
|
||||
trust_executable_bit = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "core.trustctime")) {
|
||||
trust_ctime = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.quotepath")) {
|
||||
quote_path_fully = git_config_bool(var, value);
|
||||
|
||||
@@ -349,14 +349,32 @@ __git_complete_revlist ()
|
||||
esac
|
||||
}
|
||||
|
||||
__git_commands ()
|
||||
__git_all_commands ()
|
||||
{
|
||||
if [ -n "$__git_commandlist" ]; then
|
||||
echo "$__git_commandlist"
|
||||
if [ -n "$__git_all_commandlist" ]; then
|
||||
echo "$__git_all_commandlist"
|
||||
return
|
||||
fi
|
||||
local i IFS=" "$'\n'
|
||||
for i in $(git help -a|egrep '^ ')
|
||||
do
|
||||
case $i in
|
||||
*--*) : helper pattern;;
|
||||
*) echo $i;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
__git_all_commandlist=
|
||||
__git_all_commandlist="$(__git_all_commands 2>/dev/null)"
|
||||
|
||||
__git_porcelain_commands ()
|
||||
{
|
||||
if [ -n "$__git_porcelain_commandlist" ]; then
|
||||
echo "$__git_porcelain_commandlist"
|
||||
return
|
||||
fi
|
||||
local i IFS=" "$'\n'
|
||||
for i in "help" $(__git_all_commands)
|
||||
do
|
||||
case $i in
|
||||
*--*) : helper pattern;;
|
||||
@@ -427,8 +445,8 @@ __git_commands ()
|
||||
esac
|
||||
done
|
||||
}
|
||||
__git_commandlist=
|
||||
__git_commandlist="$(__git_commands 2>/dev/null)"
|
||||
__git_porcelain_commandlist=
|
||||
__git_porcelain_commandlist="$(__git_porcelain_commands 2>/dev/null)"
|
||||
|
||||
__git_aliases ()
|
||||
{
|
||||
@@ -667,6 +685,15 @@ _git_commit ()
|
||||
|
||||
_git_describe ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--*)
|
||||
__gitcomp "
|
||||
--all --tags --contains --abbrev= --candidates=
|
||||
--exact-match --debug --long --match --always
|
||||
"
|
||||
return
|
||||
esac
|
||||
__gitcomp "$(__git_refs)"
|
||||
}
|
||||
|
||||
@@ -769,6 +796,18 @@ _git_gc ()
|
||||
COMPREPLY=()
|
||||
}
|
||||
|
||||
_git_help ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--*)
|
||||
__gitcomp "--all --info --man --web"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
__gitcomp "$(__git_all_commands)"
|
||||
}
|
||||
|
||||
_git_ls_remote ()
|
||||
{
|
||||
__gitcomp "$(__git_remotes)"
|
||||
@@ -1401,7 +1440,8 @@ _git ()
|
||||
case "$i" in
|
||||
--git-dir=*) __git_dir="${i#--git-dir=}" ;;
|
||||
--bare) __git_dir="." ;;
|
||||
--version|--help|-p|--paginate) ;;
|
||||
--version|-p|--paginate) ;;
|
||||
--help) command="help"; break ;;
|
||||
*) command="$i"; break ;;
|
||||
esac
|
||||
c=$((++c))
|
||||
@@ -1421,7 +1461,7 @@ _git ()
|
||||
--help
|
||||
"
|
||||
;;
|
||||
*) __gitcomp "$(__git_commands) $(__git_aliases)" ;;
|
||||
*) __gitcomp "$(__git_porcelain_commands) $(__git_aliases)" ;;
|
||||
esac
|
||||
return
|
||||
fi
|
||||
@@ -1446,6 +1486,7 @@ _git ()
|
||||
fetch) _git_fetch ;;
|
||||
format-patch) _git_format_patch ;;
|
||||
gc) _git_gc ;;
|
||||
help) _git_help ;;
|
||||
log) _git_log ;;
|
||||
ls-remote) _git_ls_remote ;;
|
||||
ls-tree) _git_ls_tree ;;
|
||||
|
||||
@@ -13,6 +13,7 @@ char git_default_email[MAX_GITNAME];
|
||||
char git_default_name[MAX_GITNAME];
|
||||
int user_ident_explicitly_given;
|
||||
int trust_executable_bit = 1;
|
||||
int trust_ctime = 1;
|
||||
int has_symlinks = 1;
|
||||
int ignore_case;
|
||||
int assume_unchanged;
|
||||
|
||||
@@ -78,7 +78,7 @@ void setup_path(void)
|
||||
strbuf_release(&new_path);
|
||||
}
|
||||
|
||||
int execv_git_cmd(const char **argv)
|
||||
const char **prepare_git_cmd(const char **argv)
|
||||
{
|
||||
int argc;
|
||||
const char **nargv;
|
||||
@@ -91,6 +91,11 @@ int execv_git_cmd(const char **argv)
|
||||
for (argc = 0; argv[argc]; argc++)
|
||||
nargv[argc + 1] = argv[argc];
|
||||
nargv[argc + 1] = NULL;
|
||||
return nargv;
|
||||
}
|
||||
|
||||
int execv_git_cmd(const char **argv) {
|
||||
const char **nargv = prepare_git_cmd(argv);
|
||||
trace_argv_printf(nargv, "trace: exec:");
|
||||
|
||||
/* execvp() can only ever return if it fails */
|
||||
|
||||
@@ -5,6 +5,7 @@ extern void git_set_argv_exec_path(const char *exec_path);
|
||||
extern void git_set_argv0_path(const char *path);
|
||||
extern const char* git_exec_path(void);
|
||||
extern void setup_path(void);
|
||||
extern const char **prepare_git_cmd(const char **argv);
|
||||
extern int execv_git_cmd(const char **argv); /* NULL terminated */
|
||||
extern int execl_git_cmd(const char *cmd, ...);
|
||||
extern const char *system_path(const char *path);
|
||||
|
||||
@@ -473,10 +473,10 @@ proc githook_read {hook_name args} {
|
||||
set pchook [gitdir hooks $hook_name]
|
||||
lappend args 2>@1
|
||||
|
||||
# On Cygwin [file executable] might lie so we need to ask
|
||||
# On Windows [file executable] might lie so we need to ask
|
||||
# the shell if the hook is executable. Yes that's annoying.
|
||||
#
|
||||
if {[is_Cygwin]} {
|
||||
if {[is_Windows]} {
|
||||
upvar #0 _sh interp
|
||||
if {![info exists interp]} {
|
||||
set interp [_which sh]
|
||||
@@ -497,6 +497,20 @@ proc githook_read {hook_name args} {
|
||||
return {}
|
||||
}
|
||||
|
||||
proc kill_file_process {fd} {
|
||||
set process [pid $fd]
|
||||
|
||||
catch {
|
||||
if {[is_Windows]} {
|
||||
# Use a Cygwin-specific flag to allow killing
|
||||
# native Windows processes
|
||||
exec kill -f $process
|
||||
} else {
|
||||
exec kill $process
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc sq {value} {
|
||||
regsub -all ' $value "'\\''" value
|
||||
return "'$value'"
|
||||
@@ -642,6 +656,8 @@ set default_config(user.email) {}
|
||||
set default_config(gui.matchtrackingbranch) false
|
||||
set default_config(gui.pruneduringfetch) false
|
||||
set default_config(gui.trustmtime) false
|
||||
set default_config(gui.fastcopyblame) false
|
||||
set default_config(gui.copyblamethreshold) 40
|
||||
set default_config(gui.diffcontext) 5
|
||||
set default_config(gui.commitmsgwidth) 75
|
||||
set default_config(gui.newbranchtemplate) {}
|
||||
@@ -1670,10 +1686,10 @@ proc do_gitk {revs} {
|
||||
# -- Always start gitk through whatever we were loaded with. This
|
||||
# lets us bypass using shell process on Windows systems.
|
||||
#
|
||||
set exe [file join [file dirname $::_git] gitk]
|
||||
set exe [_which gitk]
|
||||
set cmd [list [info nameofexecutable] $exe]
|
||||
if {! [file exists $exe]} {
|
||||
error_popup [mc "Unable to start gitk:\n\n%s does not exist" $exe]
|
||||
if {$exe eq {}} {
|
||||
error_popup [mc "Couldn't find gitk in PATH"]
|
||||
} else {
|
||||
global env
|
||||
|
||||
|
||||
@@ -33,13 +33,6 @@ variable group_colors {
|
||||
#ececec
|
||||
}
|
||||
|
||||
# Switches for original location detection
|
||||
#
|
||||
variable original_options [list -C -C]
|
||||
if {[git-version >= 1.5.3]} {
|
||||
lappend original_options -w ; # ignore indentation changes
|
||||
}
|
||||
|
||||
# Current blame data; cleared/reset on each load
|
||||
#
|
||||
field commit ; # input commit to blame
|
||||
@@ -263,6 +256,9 @@ constructor new {i_commit i_path} {
|
||||
$w.ctxm add command \
|
||||
-label [mc "Copy Commit"] \
|
||||
-command [cb _copycommit]
|
||||
$w.ctxm add command \
|
||||
-label [mc "Do Full Copy Detection"] \
|
||||
-command [cb _fullcopyblame]
|
||||
|
||||
foreach i $w_columns {
|
||||
for {set g 0} {$g < [llength $group_colors]} {incr g} {
|
||||
@@ -333,19 +329,27 @@ constructor new {i_commit i_path} {
|
||||
bind $w.file_pane <Configure> \
|
||||
"if {{$w.file_pane} eq {%W}} {[cb _resize %h]}"
|
||||
|
||||
wm protocol $top WM_DELETE_WINDOW "destroy $top"
|
||||
bind $top <Destroy> [cb _kill]
|
||||
|
||||
_load $this {}
|
||||
}
|
||||
|
||||
method _kill {} {
|
||||
if {$current_fd ne {}} {
|
||||
kill_file_process $current_fd
|
||||
catch {close $current_fd}
|
||||
set current_fd {}
|
||||
}
|
||||
}
|
||||
|
||||
method _load {jump} {
|
||||
variable group_colors
|
||||
|
||||
_hide_tooltip $this
|
||||
|
||||
if {$total_lines != 0 || $current_fd ne {}} {
|
||||
if {$current_fd ne {}} {
|
||||
catch {close $current_fd}
|
||||
set current_fd {}
|
||||
}
|
||||
_kill $this
|
||||
|
||||
foreach i $w_columns {
|
||||
$i conf -state normal
|
||||
@@ -511,7 +515,6 @@ method _exec_blame {cur_w cur_d options cur_s} {
|
||||
method _read_blame {fd cur_w cur_d} {
|
||||
upvar #0 $cur_d line_data
|
||||
variable group_colors
|
||||
variable original_options
|
||||
|
||||
if {$fd ne $current_fd} {
|
||||
catch {close $fd}
|
||||
@@ -684,6 +687,18 @@ method _read_blame {fd cur_w cur_d} {
|
||||
if {[eof $fd]} {
|
||||
close $fd
|
||||
if {$cur_w eq $w_asim} {
|
||||
# Switches for original location detection
|
||||
set threshold [get_config gui.copyblamethreshold]
|
||||
set original_options [list "-C$threshold"]
|
||||
|
||||
if {![is_config_true gui.fastcopyblame]} {
|
||||
# thorough copy search; insert before the threshold
|
||||
set original_options [linsert $original_options 0 -C]
|
||||
}
|
||||
if {[git-version >= 1.5.3]} {
|
||||
lappend original_options -w ; # ignore indentation changes
|
||||
}
|
||||
|
||||
_exec_blame $this $w_amov @amov_data \
|
||||
$original_options \
|
||||
[mc "Loading original location annotations..."]
|
||||
@@ -696,6 +711,72 @@ method _read_blame {fd cur_w cur_d} {
|
||||
}
|
||||
} ifdeleted { catch {close $fd} }
|
||||
|
||||
method _find_commit_bound {data_list start_idx delta} {
|
||||
upvar #0 $data_list line_data
|
||||
set pos $start_idx
|
||||
set limit [expr {[llength $line_data] - 1}]
|
||||
set base_commit [lindex $line_data $pos 0]
|
||||
|
||||
while {$pos > 0 && $pos < $limit} {
|
||||
set new_pos [expr {$pos + $delta}]
|
||||
if {[lindex $line_data $new_pos 0] ne $base_commit} {
|
||||
return $pos
|
||||
}
|
||||
|
||||
set pos $new_pos
|
||||
}
|
||||
|
||||
return $pos
|
||||
}
|
||||
|
||||
method _fullcopyblame {} {
|
||||
if {$current_fd ne {}} {
|
||||
tk_messageBox \
|
||||
-icon error \
|
||||
-type ok \
|
||||
-title [mc "Busy"] \
|
||||
-message [mc "Annotation process is already running."]
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
# Switches for original location detection
|
||||
set threshold [get_config gui.copyblamethreshold]
|
||||
set original_options [list -C -C "-C$threshold"]
|
||||
|
||||
if {[git-version >= 1.5.3]} {
|
||||
lappend original_options -w ; # ignore indentation changes
|
||||
}
|
||||
|
||||
# Find the line range
|
||||
set pos @$::cursorX,$::cursorY
|
||||
set lno [lindex [split [$::cursorW index $pos] .] 0]
|
||||
set min_amov_lno [_find_commit_bound $this @amov_data $lno -1]
|
||||
set max_amov_lno [_find_commit_bound $this @amov_data $lno 1]
|
||||
set min_asim_lno [_find_commit_bound $this @asim_data $lno -1]
|
||||
set max_asim_lno [_find_commit_bound $this @asim_data $lno 1]
|
||||
|
||||
if {$min_asim_lno < $min_amov_lno} {
|
||||
set min_amov_lno $min_asim_lno
|
||||
}
|
||||
|
||||
if {$max_asim_lno > $max_amov_lno} {
|
||||
set max_amov_lno $max_asim_lno
|
||||
}
|
||||
|
||||
lappend original_options -L "$min_amov_lno,$max_amov_lno"
|
||||
|
||||
# Clear lines
|
||||
for {set i $min_amov_lno} {$i <= $max_amov_lno} {incr i} {
|
||||
lset amov_data $i [list ]
|
||||
}
|
||||
|
||||
# Start the back-end process
|
||||
_exec_blame $this $w_amov @amov_data \
|
||||
$original_options \
|
||||
[mc "Running thorough copy detection..."]
|
||||
}
|
||||
|
||||
method _click {cur_w pos} {
|
||||
set lno [lindex [split [$cur_w index $pos] .] 0]
|
||||
_showcommit $this $cur_w $lno
|
||||
|
||||
@@ -411,6 +411,53 @@ proc apply_line {x y} {
|
||||
set hh [lindex [split $hh ,] 0]
|
||||
set hln [lindex [split $hh -] 1]
|
||||
|
||||
# There is a special situation to take care of. Consider this hunk:
|
||||
#
|
||||
# @@ -10,4 +10,4 @@
|
||||
# context before
|
||||
# -old 1
|
||||
# -old 2
|
||||
# +new 1
|
||||
# +new 2
|
||||
# context after
|
||||
#
|
||||
# We used to keep the context lines in the order they appear in the
|
||||
# hunk. But then it is not possible to correctly stage only
|
||||
# "-old 1" and "+new 1" - it would result in this staged text:
|
||||
#
|
||||
# context before
|
||||
# old 2
|
||||
# new 1
|
||||
# context after
|
||||
#
|
||||
# (By symmetry it is not possible to *un*stage "old 2" and "new 2".)
|
||||
#
|
||||
# We resolve the problem by introducing an asymmetry, namely, when
|
||||
# a "+" line is *staged*, it is moved in front of the context lines
|
||||
# that are generated from the "-" lines that are immediately before
|
||||
# the "+" block. That is, we construct this patch:
|
||||
#
|
||||
# @@ -10,4 +10,5 @@
|
||||
# context before
|
||||
# +new 1
|
||||
# old 1
|
||||
# old 2
|
||||
# context after
|
||||
#
|
||||
# But we do *not* treat "-" lines that are *un*staged in a special
|
||||
# way.
|
||||
#
|
||||
# With this asymmetry it is possible to stage the change
|
||||
# "old 1" -> "new 1" directly, and to stage the change
|
||||
# "old 2" -> "new 2" by first staging the entire hunk and
|
||||
# then unstaging the change "old 1" -> "new 1".
|
||||
|
||||
# This is non-empty if and only if we are _staging_ changes;
|
||||
# then it accumulates the consecutive "-" lines (after converting
|
||||
# them to context lines) in order to be moved after the "+" change
|
||||
# line.
|
||||
set pre_context {}
|
||||
|
||||
set n 0
|
||||
set i_l [$ui_diff index "$i_l + 1 lines"]
|
||||
set patch {}
|
||||
@@ -422,16 +469,27 @@ proc apply_line {x y} {
|
||||
[$ui_diff compare $the_l < $next_l]} {
|
||||
# the line to stage/unstage
|
||||
set ln [$ui_diff get $i_l $next_l]
|
||||
set patch "$patch$ln"
|
||||
if {$c1 eq {-}} {
|
||||
set n [expr $n+1]
|
||||
set patch "$patch$pre_context$ln"
|
||||
} else {
|
||||
set patch "$patch$ln$pre_context"
|
||||
}
|
||||
set pre_context {}
|
||||
} elseif {$c1 ne {-} && $c1 ne {+}} {
|
||||
# context line
|
||||
set ln [$ui_diff get $i_l $next_l]
|
||||
set patch "$patch$ln"
|
||||
set patch "$patch$pre_context$ln"
|
||||
set n [expr $n+1]
|
||||
set pre_context {}
|
||||
} elseif {$c1 eq $to_context} {
|
||||
# turn change line into context line
|
||||
set ln [$ui_diff get "$i_l + 1 chars" $next_l]
|
||||
set patch "$patch $ln"
|
||||
if {$c1 eq {-}} {
|
||||
set pre_context "$pre_context $ln"
|
||||
} else {
|
||||
set patch "$patch $ln"
|
||||
}
|
||||
set n [expr $n+1]
|
||||
}
|
||||
set i_l $next_l
|
||||
|
||||
@@ -123,6 +123,8 @@ proc do_options {} {
|
||||
{b gui.trustmtime {mc "Trust File Modification Timestamps"}}
|
||||
{b gui.pruneduringfetch {mc "Prune Tracking Branches During Fetch"}}
|
||||
{b gui.matchtrackingbranch {mc "Match Tracking Branches"}}
|
||||
{b gui.fastcopyblame {mc "Blame Copy Only On Changed Files"}}
|
||||
{i-20..200 gui.copyblamethreshold {mc "Minimum Letters To Blame Copy On"}}
|
||||
{i-0..99 gui.diffcontext {mc "Number of Diff Context Lines"}}
|
||||
{i-0..99 gui.commitmsgwidth {mc "Commit Message Text Width"}}
|
||||
{t gui.newbranchtemplate {mc "New Branch Name Template"}}
|
||||
|
||||
@@ -7,7 +7,7 @@ if {[string first -psn [lindex $argv 0]] == 0} {
|
||||
}
|
||||
|
||||
if {[file tail [lindex $argv 0]] eq {gitk}} {
|
||||
set argv0 [file join $gitexecdir gitk]
|
||||
set argv0 [lindex $argv 0]
|
||||
set AppMain_source $argv0
|
||||
} else {
|
||||
set argv0 [file join $gitexecdir [file tail [lindex $argv 0]]]
|
||||
|
||||
@@ -277,7 +277,8 @@ You can use the following files in repository:
|
||||
* gitweb.owner
|
||||
You can use the gitweb.owner repository configuration variable to set
|
||||
repository's owner. It is displayed in the project list and summary
|
||||
page. If it's not set, filesystem directory's owner is used.
|
||||
page. If it's not set, filesystem directory's owner is used
|
||||
(via GECOS field / real name field from getpwiud(3)).
|
||||
* various gitweb.* config variables (in config)
|
||||
Read description of %feature hash for detailed list, and some
|
||||
descriptions.
|
||||
|
||||
12
help.c
12
help.c
@@ -425,17 +425,24 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,
|
||||
int prefix_len = strlen(prefix);
|
||||
DIR *dir = opendir(path);
|
||||
struct dirent *de;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
int len;
|
||||
|
||||
if (!dir || chdir(path))
|
||||
if (!dir)
|
||||
return 0;
|
||||
|
||||
strbuf_addf(&buf, "%s/", path);
|
||||
len = buf.len;
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
int entlen;
|
||||
|
||||
if (prefixcmp(de->d_name, prefix))
|
||||
continue;
|
||||
|
||||
if (!is_executable(de->d_name))
|
||||
strbuf_setlen(&buf, len);
|
||||
strbuf_addstr(&buf, de->d_name);
|
||||
if (!is_executable(buf.buf))
|
||||
continue;
|
||||
|
||||
entlen = strlen(de->d_name) - prefix_len;
|
||||
@@ -448,6 +455,7 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds,
|
||||
add_cmdname(cmds, de->d_name + prefix_len, entlen);
|
||||
}
|
||||
closedir(dir);
|
||||
strbuf_release(&buf);
|
||||
|
||||
return longest;
|
||||
}
|
||||
|
||||
18
read-cache.c
18
read-cache.c
@@ -38,6 +38,22 @@ static void replace_index_entry(struct index_state *istate, int nr, struct cache
|
||||
istate->cache_changed = 1;
|
||||
}
|
||||
|
||||
void rename_index_entry_at(struct index_state *istate, int nr, const char *new_name)
|
||||
{
|
||||
struct cache_entry *old = istate->cache[nr], *new;
|
||||
int namelen = strlen(new_name);
|
||||
|
||||
new = xmalloc(cache_entry_size(namelen));
|
||||
copy_cache_entry(new, old);
|
||||
new->ce_flags &= ~(CE_STATE_MASK | CE_NAMEMASK);
|
||||
new->ce_flags |= (namelen >= CE_NAMEMASK ? CE_NAMEMASK : namelen);
|
||||
memcpy(new->name, new_name, namelen + 1);
|
||||
|
||||
cache_tree_invalidate_path(istate->cache_tree, old->name);
|
||||
remove_index_entry_at(istate, nr);
|
||||
add_index_entry(istate, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
|
||||
}
|
||||
|
||||
/*
|
||||
* This only updates the "non-critical" parts of the directory
|
||||
* cache, ie the parts that aren't tracked by GIT, and only used
|
||||
@@ -181,7 +197,7 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
|
||||
}
|
||||
if (ce->ce_mtime != (unsigned int) st->st_mtime)
|
||||
changed |= MTIME_CHANGED;
|
||||
if (ce->ce_ctime != (unsigned int) st->st_ctime)
|
||||
if (trust_ctime && ce->ce_ctime != (unsigned int) st->st_ctime)
|
||||
changed |= CTIME_CHANGED;
|
||||
|
||||
if (ce->ce_uid != (unsigned int) st->st_uid ||
|
||||
|
||||
52
remote.c
52
remote.c
@@ -427,6 +427,28 @@ static void read_config(void)
|
||||
alias_all_urls();
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to make sure the tracking branches are well formed, but a
|
||||
* wildcard refspec in "struct refspec" must have a trailing slash. We
|
||||
* temporarily drop the trailing '/' while calling check_ref_format(),
|
||||
* and put it back. The caller knows that a CHECK_REF_FORMAT_ONELEVEL
|
||||
* error return is Ok for a wildcard refspec.
|
||||
*/
|
||||
static int verify_refname(char *name, int is_glob)
|
||||
{
|
||||
int result, len = -1;
|
||||
|
||||
if (is_glob) {
|
||||
len = strlen(name);
|
||||
assert(name[len - 1] == '/');
|
||||
name[len - 1] = '\0';
|
||||
}
|
||||
result = check_ref_format(name);
|
||||
if (is_glob)
|
||||
name[len - 1] = '/';
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
|
||||
{
|
||||
int i;
|
||||
@@ -434,11 +456,11 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
|
||||
struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
|
||||
|
||||
for (i = 0; i < nr_refspec; i++) {
|
||||
size_t llen, rlen;
|
||||
size_t llen;
|
||||
int is_glob;
|
||||
const char *lhs, *rhs;
|
||||
|
||||
llen = rlen = is_glob = 0;
|
||||
llen = is_glob = 0;
|
||||
|
||||
lhs = refspec[i];
|
||||
if (*lhs == '+') {
|
||||
@@ -458,12 +480,9 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
|
||||
}
|
||||
|
||||
if (rhs) {
|
||||
rhs++;
|
||||
rlen = strlen(rhs);
|
||||
size_t rlen = strlen(++rhs);
|
||||
is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*"));
|
||||
if (is_glob)
|
||||
rlen -= 2;
|
||||
rs[i].dst = xstrndup(rhs, rlen);
|
||||
rs[i].dst = xstrndup(rhs, rlen - is_glob);
|
||||
}
|
||||
|
||||
llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
|
||||
@@ -471,7 +490,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
|
||||
if ((rhs && !is_glob) || (!rhs && fetch))
|
||||
goto invalid;
|
||||
is_glob = 1;
|
||||
llen -= 2;
|
||||
llen--;
|
||||
} else if (rhs && is_glob) {
|
||||
goto invalid;
|
||||
}
|
||||
@@ -488,7 +507,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
|
||||
if (!*rs[i].src)
|
||||
; /* empty is ok */
|
||||
else {
|
||||
st = check_ref_format(rs[i].src);
|
||||
st = verify_refname(rs[i].src, is_glob);
|
||||
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
|
||||
goto invalid;
|
||||
}
|
||||
@@ -503,7 +522,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
|
||||
} else if (!*rs[i].dst) {
|
||||
; /* ok */
|
||||
} else {
|
||||
st = check_ref_format(rs[i].dst);
|
||||
st = verify_refname(rs[i].dst, is_glob);
|
||||
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
|
||||
goto invalid;
|
||||
}
|
||||
@@ -518,7 +537,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
|
||||
if (!*rs[i].src)
|
||||
; /* empty is ok */
|
||||
else if (is_glob) {
|
||||
st = check_ref_format(rs[i].src);
|
||||
st = verify_refname(rs[i].src, is_glob);
|
||||
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
|
||||
goto invalid;
|
||||
}
|
||||
@@ -532,13 +551,13 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
|
||||
* - otherwise it must be a valid looking ref.
|
||||
*/
|
||||
if (!rs[i].dst) {
|
||||
st = check_ref_format(rs[i].src);
|
||||
st = verify_refname(rs[i].src, is_glob);
|
||||
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
|
||||
goto invalid;
|
||||
} else if (!*rs[i].dst) {
|
||||
goto invalid;
|
||||
} else {
|
||||
st = check_ref_format(rs[i].dst);
|
||||
st = verify_refname(rs[i].dst, is_glob);
|
||||
if (st && st != CHECK_REF_FORMAT_ONELEVEL)
|
||||
goto invalid;
|
||||
}
|
||||
@@ -687,8 +706,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
|
||||
if (!fetch->dst)
|
||||
continue;
|
||||
if (fetch->pattern) {
|
||||
if (!prefixcmp(needle, key) &&
|
||||
needle[strlen(key)] == '/') {
|
||||
if (!prefixcmp(needle, key)) {
|
||||
*result = xmalloc(strlen(value) +
|
||||
strlen(needle) -
|
||||
strlen(key) + 1);
|
||||
@@ -966,9 +984,7 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rs[i].pattern &&
|
||||
!prefixcmp(src->name, rs[i].src) &&
|
||||
src->name[strlen(rs[i].src)] == '/')
|
||||
if (rs[i].pattern && !prefixcmp(src->name, rs[i].src))
|
||||
return rs + i;
|
||||
}
|
||||
if (matching_refs != -1)
|
||||
|
||||
@@ -119,9 +119,8 @@ int start_command(struct child_process *cmd)
|
||||
}
|
||||
#else
|
||||
int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */
|
||||
const char *sargv0 = cmd->argv[0];
|
||||
const char **sargv = cmd->argv;
|
||||
char **env = environ;
|
||||
struct strbuf git_cmd;
|
||||
|
||||
if (cmd->no_stdin) {
|
||||
s0 = dup(0);
|
||||
@@ -165,9 +164,7 @@ int start_command(struct child_process *cmd)
|
||||
}
|
||||
|
||||
if (cmd->git_cmd) {
|
||||
strbuf_init(&git_cmd, 0);
|
||||
strbuf_addf(&git_cmd, "git-%s", cmd->argv[0]);
|
||||
cmd->argv[0] = git_cmd.buf;
|
||||
cmd->argv = prepare_git_cmd(cmd->argv);
|
||||
}
|
||||
|
||||
cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env);
|
||||
@@ -175,9 +172,9 @@ int start_command(struct child_process *cmd)
|
||||
if (cmd->env)
|
||||
free_environ(env);
|
||||
if (cmd->git_cmd)
|
||||
strbuf_release(&git_cmd);
|
||||
free(cmd->argv);
|
||||
|
||||
cmd->argv[0] = sargv0;
|
||||
cmd->argv = sargv;
|
||||
if (s0 >= 0)
|
||||
dup2(s0, 0), close(s0);
|
||||
if (s1 >= 0)
|
||||
|
||||
@@ -141,4 +141,30 @@ test_expect_success 'reinit' '
|
||||
test_cmp again/empty again/err2
|
||||
'
|
||||
|
||||
test_expect_success 'init with --template' '
|
||||
mkdir template-source &&
|
||||
echo content >template-source/file &&
|
||||
(
|
||||
mkdir template-custom &&
|
||||
cd template-custom &&
|
||||
git init --template=../template-source
|
||||
) &&
|
||||
test_cmp template-source/file template-custom/.git/file
|
||||
'
|
||||
|
||||
test_expect_success 'init with --template (blank)' '
|
||||
(
|
||||
mkdir template-plain &&
|
||||
cd template-plain &&
|
||||
git init
|
||||
) &&
|
||||
test -f template-plain/.git/info/exclude &&
|
||||
(
|
||||
mkdir template-blank &&
|
||||
cd template-blank &&
|
||||
git init --template=
|
||||
) &&
|
||||
! test -f template-blank/.git/info/exclude
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
30
t/t5513-fetch-track.sh
Executable file
30
t/t5513-fetch-track.sh
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='fetch follows remote tracking branches correctly'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup '
|
||||
>file &&
|
||||
git add . &&
|
||||
test_tick &&
|
||||
git commit -m Initial &&
|
||||
git branch b-0 &&
|
||||
git branch b1 &&
|
||||
git branch b/one &&
|
||||
test_create_repo other &&
|
||||
(
|
||||
cd other &&
|
||||
git config remote.origin.url .. &&
|
||||
git config remote.origin.fetch "+refs/heads/b/*:refs/remotes/b/*"
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success fetch '
|
||||
(
|
||||
cd other && git fetch origin &&
|
||||
test "$(git for-each-ref --format="%(refname)")" = refs/remotes/b/one
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -76,7 +76,7 @@ test_expect_success 'bisect fails if given any junk instead of revs' '
|
||||
test_must_fail git bisect start foo $HASH1 -- &&
|
||||
test_must_fail git bisect start $HASH4 $HASH1 bar -- &&
|
||||
test -z "$(git for-each-ref "refs/bisect/*")" &&
|
||||
test_must_fail ls .git/BISECT_* &&
|
||||
test -z "$(ls .git/BISECT_* 2>/dev/null)" &&
|
||||
git bisect start &&
|
||||
test_must_fail git bisect good foo $HASH1 &&
|
||||
test_must_fail git bisect good $HASH1 bar &&
|
||||
|
||||
@@ -28,6 +28,8 @@ test_expect_success 'final^1^2 != final^1^1' "test $(git rev-parse final^1^2) !=
|
||||
test_expect_success 'final^1^3 not valid' "if git rev-parse --verify final^1^3; then false; else :; fi"
|
||||
test_expect_success '--verify start2^1' 'test_must_fail git rev-parse --verify start2^1'
|
||||
test_expect_success '--verify start2^0' 'git rev-parse --verify start2^0'
|
||||
test_expect_success 'final^1^@ = final^1^1 final^1^2' "test \"$(git rev-parse final^1^@)\" = \"$(git rev-parse final^1^1 final^1^2)\""
|
||||
test_expect_success 'final^1^! = final^1 ^final^1^1 ^final^1^2' "test \"$(git rev-parse final^1^\!)\" = \"$(git rev-parse final^1 ^final^1^1 ^final^1^2)\""
|
||||
|
||||
test_expect_success 'repack for next test' 'git repack -a -d'
|
||||
test_expect_success 'short SHA-1 works' '
|
||||
|
||||
@@ -156,4 +156,58 @@ test_expect_success 'absolute pathname outside should fail' '(
|
||||
|
||||
)'
|
||||
|
||||
test_expect_success 'git mv should not change sha1 of moved cache entry' '
|
||||
|
||||
rm -fr .git &&
|
||||
git init &&
|
||||
echo 1 >dirty &&
|
||||
git add dirty &&
|
||||
entry="$(git ls-files --stage dirty | cut -f 1)"
|
||||
git mv dirty dirty2 &&
|
||||
[ "$entry" = "$(git ls-files --stage dirty2 | cut -f 1)" ] &&
|
||||
echo 2 >dirty2 &&
|
||||
git mv dirty2 dirty &&
|
||||
[ "$entry" = "$(git ls-files --stage dirty | cut -f 1)" ]
|
||||
|
||||
'
|
||||
|
||||
rm -f dirty dirty2
|
||||
|
||||
test_expect_success 'git mv should overwrite symlink to a file' '
|
||||
|
||||
rm -fr .git &&
|
||||
git init &&
|
||||
echo 1 >moved &&
|
||||
ln -s moved symlink &&
|
||||
git add moved symlink &&
|
||||
test_must_fail git mv moved symlink &&
|
||||
git mv -f moved symlink &&
|
||||
! test -e moved &&
|
||||
test -f symlink &&
|
||||
test "$(cat symlink)" = 1 &&
|
||||
git update-index --refresh &&
|
||||
git diff-files --quiet
|
||||
|
||||
'
|
||||
|
||||
rm -f moved symlink
|
||||
|
||||
test_expect_success 'git mv should overwrite file with a symlink' '
|
||||
|
||||
rm -fr .git &&
|
||||
git init &&
|
||||
echo 1 >moved &&
|
||||
ln -s moved symlink &&
|
||||
git add moved symlink &&
|
||||
test_must_fail git mv symlink moved &&
|
||||
git mv -f symlink moved &&
|
||||
! test -e symlink &&
|
||||
test -h moved &&
|
||||
git update-index --refresh &&
|
||||
git diff-files --quiet
|
||||
|
||||
'
|
||||
|
||||
rm -f moved symlink
|
||||
|
||||
test_done
|
||||
|
||||
Reference in New Issue
Block a user