mirror of
https://github.com/git/git.git
synced 2026-03-13 18:33:25 +01:00
Merge branch 'js/reverse' into next
* js/reverse: Teach revision machinery about --reverse GIT v1.5.0-rc2 prune: --grace=time --walk-reflogs: do not crash with cyclic reflog ancestry --walk-reflogs: actually find the right commit by date. Fix --walk-reflog with --pretty=oneline reflog-walk: build fixes log --walk-reflog: documentation --walk-reflogs: disallow uninteresting commits Teach the revision walker to walk by reflogs with --walk-reflogs git-rebase: allow rebasing a detached HEAD. branch -f: no reason to forbid updating the current branch in a bare repo. git-tag -d: allow deleting multiple tags at once. Do not verify filenames in a bare repository Stop ignoring Documentation/README apply --cached: fix crash in subdirectory show-branch --reflog: fix show_date() call show_date(): fix relative dates show-branch --reflog: tighten input validation.
This commit is contained in:
1
Documentation/.gitignore
vendored
1
Documentation/.gitignore
vendored
@@ -4,5 +4,4 @@
|
||||
*.7
|
||||
howto-index.txt
|
||||
doc.dep
|
||||
README
|
||||
cmds-*.txt
|
||||
|
||||
@@ -8,7 +8,7 @@ git-prune - Prunes all unreachable objects from the object database
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-prune' [-n] [--] [<head>...]
|
||||
'git-prune' [-n] [--grace=<time>]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -28,6 +28,12 @@ OPTIONS
|
||||
Do not remove anything; just report what it would
|
||||
remove.
|
||||
|
||||
--grace=<time>::
|
||||
Do not prune loose objects that are younger than the
|
||||
specified time. This gives a grace period to newly
|
||||
created objects from getting pruned.
|
||||
|
||||
////////////////////////////////////////////
|
||||
\--::
|
||||
Do not interpret any more arguments as options.
|
||||
|
||||
@@ -46,6 +52,7 @@ borrows from your repository via its
|
||||
------------
|
||||
$ git prune $(cd ../another && $(git-rev-parse --all))
|
||||
------------
|
||||
////////////////////////////////////////////
|
||||
|
||||
Author
|
||||
------
|
||||
|
||||
@@ -27,6 +27,8 @@ SYNOPSIS
|
||||
[ \--pretty | \--header ]
|
||||
[ \--bisect ]
|
||||
[ \--merge ]
|
||||
[ \--reverse ]
|
||||
[ \--walk-reflogs ]
|
||||
<commit>... [ \-- <paths>... ]
|
||||
|
||||
DESCRIPTION
|
||||
@@ -190,6 +192,22 @@ limiting may be applied.
|
||||
In addition to the '<commit>' listed on the command
|
||||
line, read them from the standard input.
|
||||
|
||||
--walk-reflogs::
|
||||
|
||||
Instead of walking the commit ancestry chain, walk
|
||||
reflog entries from the most recent one to older ones.
|
||||
When this option is used you cannot specify commits to
|
||||
exclude (that is, '{caret}commit', 'commit1..commit2',
|
||||
nor 'commit1...commit2' notations cannot be used).
|
||||
+
|
||||
With '\--pretty' format other than oneline (for obvious reasons),
|
||||
this causes the output to have two extra lines of information
|
||||
taken from the reflog. By default, 'commit@{Nth}' notation is
|
||||
used in the output. When the starting commit is specified as
|
||||
'commit@{now}', output also uses 'commit@{timestamp}' notation
|
||||
instead. Under '\--pretty=oneline', the commit message is
|
||||
prefixed with this information on the same line.
|
||||
|
||||
--merge::
|
||||
|
||||
After a failed merge, show refs that touch files having a
|
||||
@@ -249,6 +267,10 @@ By default, the commits are shown in reverse chronological order.
|
||||
parent comes before all of its children, but otherwise things
|
||||
are still ordered in the commit timestamp order.
|
||||
|
||||
--reverse::
|
||||
|
||||
Output the commits in reverse order.
|
||||
|
||||
Object Traversal
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@ git-tag(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-tag - Create or verify a tag object signed with GPG
|
||||
git-tag - Create, list, delete or verify a tag object signed with GPG
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-tag' [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg> | -F <file>]
|
||||
<name> [<head>]
|
||||
'git-tag' [-a | -s | -u <key-id>] [-f | -v] [-m <msg> | -F <file>] <name> [<head>]
|
||||
'git-tag' -d <name>...
|
||||
'git-tag' -l [<pattern>]
|
||||
|
||||
DESCRIPTION
|
||||
@@ -55,7 +55,7 @@ OPTIONS
|
||||
Replace an existing tag with the given name (instead of failing)
|
||||
|
||||
-d::
|
||||
Delete an existing tag with the given name
|
||||
Delete existing tags with the given names.
|
||||
|
||||
-v::
|
||||
Verify the gpg signature of given the tag
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.5.0-rc1.GIT
|
||||
DEF_VER=v1.5.0-rc2.GIT
|
||||
|
||||
LF='
|
||||
'
|
||||
|
||||
4
Makefile
4
Makefile
@@ -240,7 +240,7 @@ LIB_H = \
|
||||
diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
|
||||
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
|
||||
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
|
||||
utf8.h
|
||||
utf8.h reflog-walk.h
|
||||
|
||||
DIFF_OBJS = \
|
||||
diff.o diff-lib.o diffcore-break.o diffcore-order.o \
|
||||
@@ -253,7 +253,7 @@ LIB_OBJS = \
|
||||
interpolate.o \
|
||||
lockfile.o \
|
||||
object.o pack-check.o patch-delta.o path.o pkt-line.o sideband.o \
|
||||
reachable.o \
|
||||
reachable.o reflog-walk.o \
|
||||
quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \
|
||||
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
|
||||
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
|
||||
|
||||
@@ -2589,7 +2589,7 @@ static int git_apply_config(const char *var, const char *value)
|
||||
}
|
||||
|
||||
|
||||
int cmd_apply(int argc, const char **argv, const char *prefix)
|
||||
int cmd_apply(int argc, const char **argv, const char *unused_prefix)
|
||||
{
|
||||
int i;
|
||||
int read_stdin = 1;
|
||||
|
||||
@@ -324,7 +324,7 @@ static void create_branch(const char *name, const char *start_name,
|
||||
if (resolve_ref(ref, sha1, 1, NULL)) {
|
||||
if (!force)
|
||||
die("A branch named '%s' already exists.", name);
|
||||
else if (!strcmp(head, name))
|
||||
else if (!is_bare_repository() && !strcmp(head, name))
|
||||
die("Cannot force update the current branch.");
|
||||
}
|
||||
|
||||
|
||||
@@ -50,8 +50,11 @@ static int cmd_log_walk(struct rev_info *rev)
|
||||
prepare_revision_walk(rev);
|
||||
while ((commit = get_revision(rev)) != NULL) {
|
||||
log_tree_commit(rev, commit);
|
||||
free(commit->buffer);
|
||||
commit->buffer = NULL;
|
||||
if (!rev->reflog_info) {
|
||||
/* we allow cycles in reflog ancestry */
|
||||
free(commit->buffer);
|
||||
commit->buffer = NULL;
|
||||
}
|
||||
free_commit_list(commit->parents);
|
||||
commit->parents = NULL;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
#include "builtin.h"
|
||||
#include "reachable.h"
|
||||
|
||||
static const char prune_usage[] = "git-prune [-n]";
|
||||
static const char prune_usage[] = "git-prune [-n] [--grace=time]";
|
||||
static int show_only;
|
||||
static int prune_grace_period;
|
||||
|
||||
static int prune_object(char *path, const char *filename, const unsigned char *sha1)
|
||||
{
|
||||
@@ -38,6 +39,7 @@ static int prune_dir(int i, char *path)
|
||||
char name[100];
|
||||
unsigned char sha1[20];
|
||||
int len = strlen(de->d_name);
|
||||
struct stat st;
|
||||
|
||||
switch (len) {
|
||||
case 2:
|
||||
@@ -60,6 +62,11 @@ static int prune_dir(int i, char *path)
|
||||
if (lookup_object(sha1))
|
||||
continue;
|
||||
|
||||
if (prune_grace_period > 0 &&
|
||||
!stat(mkpath("%s/%s", path, de->d_name), &st) &&
|
||||
st.st_mtime > prune_grace_period)
|
||||
continue;
|
||||
|
||||
prune_object(path, de->d_name, sha1);
|
||||
continue;
|
||||
}
|
||||
@@ -79,10 +86,25 @@ static void prune_object_dir(const char *path)
|
||||
}
|
||||
}
|
||||
|
||||
static int git_prune_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "gc.prunegrace")) {
|
||||
if (!strcmp(value, "off"))
|
||||
prune_grace_period = 0;
|
||||
else
|
||||
prune_grace_period = approxidate(value);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
int cmd_prune(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
struct rev_info revs;
|
||||
prune_grace_period = time(NULL)-24*60*60;
|
||||
|
||||
git_config(git_prune_config);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
@@ -90,6 +112,13 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
|
||||
show_only = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(arg, "--grace=", 8)) {
|
||||
if (!strcmp(arg+8, "off"))
|
||||
prune_grace_period = 0;
|
||||
else
|
||||
prune_grace_period = approxidate(arg+8);
|
||||
continue;
|
||||
}
|
||||
usage(prune_usage);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
#include "builtin.h"
|
||||
|
||||
static const char show_branch_usage[] =
|
||||
"git-show-branch [--sparse] [--current] [--all] [--remotes] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n] <branch>";
|
||||
"git-show-branch [--sparse] [--current] [--all] [--remotes] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n[,b]] <branch>";
|
||||
static const char show_branch_usage_reflog[] =
|
||||
"--reflog is incompatible with --all, --remotes, --independent or --merge-base";
|
||||
|
||||
static int default_num;
|
||||
static int default_alloc;
|
||||
@@ -664,12 +666,14 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
*/
|
||||
if (independent || merge_base)
|
||||
usage(show_branch_usage);
|
||||
if (!!reflog && (0 < extra))
|
||||
if (!!reflog && ((0 < extra) || all_heads || all_remotes))
|
||||
/*
|
||||
* Asking for --more in reflog mode does not
|
||||
* make sense.
|
||||
* make sense. --list is Ok.
|
||||
*
|
||||
* Also --all and --remotes do not make sense either.
|
||||
*/
|
||||
usage(show_branch_usage);
|
||||
usage(show_branch_usage_reflog);
|
||||
}
|
||||
|
||||
/* If nothing is specified, show all branches by default */
|
||||
@@ -685,6 +689,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
int base = 0;
|
||||
if (ac != 1)
|
||||
die("--reflog option needs one branch name");
|
||||
if (MAX_REVS < reflog)
|
||||
die("Only %d entries can be shown at one time.",
|
||||
MAX_REVS);
|
||||
if (!dwim_ref(*av, strlen(*av), sha1, &ref))
|
||||
die("No such ref %s", *av);
|
||||
|
||||
@@ -718,7 +725,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
msg++;
|
||||
m = xmalloc(strlen(msg) + 200);
|
||||
sprintf(m, "(%s) %s",
|
||||
show_date(timestamp, 0, 1),
|
||||
show_date(timestamp, tz, 1),
|
||||
msg);
|
||||
reflog_msg[i] = m;
|
||||
free(logmsg);
|
||||
|
||||
1
cache.h
1
cache.h
@@ -129,6 +129,7 @@ extern int cache_errno;
|
||||
|
||||
extern int is_bare_repository_cfg;
|
||||
extern int is_bare_repository(void);
|
||||
extern int is_inside_git_dir(void);
|
||||
extern const char *get_git_dir(void);
|
||||
extern char *get_object_directory(void);
|
||||
extern char *get_refs_directory(void);
|
||||
|
||||
5
date.c
5
date.c
@@ -62,12 +62,11 @@ const char *show_date(unsigned long time, int tz, int relative)
|
||||
|
||||
if (relative) {
|
||||
unsigned long diff;
|
||||
time_t t = gm_time_t(time, tz);
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
if (now.tv_sec < t)
|
||||
if (now.tv_sec < time)
|
||||
return "in the future";
|
||||
diff = now.tv_sec - t;
|
||||
diff = now.tv_sec - time;
|
||||
if (diff < 90) {
|
||||
snprintf(timebuf, sizeof(timebuf), "%lu seconds ago", diff);
|
||||
return timebuf;
|
||||
|
||||
@@ -275,8 +275,12 @@ case "$#" in
|
||||
git-checkout "$2" || usage
|
||||
;;
|
||||
*)
|
||||
branch_name=`git symbolic-ref HEAD` || die "No current branch"
|
||||
branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
|
||||
if branch_name=`git symbolic-ref -q HEAD`
|
||||
then
|
||||
branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
|
||||
else
|
||||
branch_name=HEAD ;# detached
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
branch=$(git-rev-parse --verify "${branch_name}^0") || exit
|
||||
|
||||
21
git-tag.sh
21
git-tag.sh
@@ -63,12 +63,21 @@ do
|
||||
;;
|
||||
-d)
|
||||
shift
|
||||
tag_name="$1"
|
||||
tag=$(git-show-ref --verify --hash -- "refs/tags/$tag_name") ||
|
||||
die "Seriously, what tag are you talking about?"
|
||||
git-update-ref -m 'tag: delete' -d "refs/tags/$tag_name" "$tag" &&
|
||||
echo "Deleted tag $tag_name."
|
||||
exit $?
|
||||
had_error=0
|
||||
for tag
|
||||
do
|
||||
cur=$(git-show-ref --verify --hash -- "refs/tags/$tag") || {
|
||||
echo >&2 "Seriously, what tag are you talking about?"
|
||||
had_error=1
|
||||
continue
|
||||
}
|
||||
git-update-ref -m 'tag: delete' -d "refs/tags/$tag" "$cur" || {
|
||||
had_error=1
|
||||
continue
|
||||
}
|
||||
echo "Deleted tag $tag."
|
||||
done
|
||||
exit $had_error
|
||||
;;
|
||||
-v)
|
||||
shift
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "diff.h"
|
||||
#include "commit.h"
|
||||
#include "log-tree.h"
|
||||
#include "reflog-walk.h"
|
||||
|
||||
static void show_parents(struct commit *commit, int abbrev)
|
||||
{
|
||||
@@ -223,6 +224,9 @@ void show_log(struct rev_info *opt, const char *sep)
|
||||
printf("%s",
|
||||
diff_get_color(opt->diffopt.color_diff, DIFF_RESET));
|
||||
putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
|
||||
if (opt->reflog_info)
|
||||
show_reflog_message(opt->reflog_info,
|
||||
opt->commit_format == CMIT_FMT_ONELINE);;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
250
reflog-walk.c
Normal file
250
reflog-walk.c
Normal file
@@ -0,0 +1,250 @@
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "refs.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "path-list.h"
|
||||
#include "reflog-walk.h"
|
||||
|
||||
struct complete_reflogs {
|
||||
char *ref;
|
||||
struct reflog_info {
|
||||
unsigned char osha1[20], nsha1[20];
|
||||
char *email;
|
||||
unsigned long timestamp;
|
||||
int tz;
|
||||
char *message;
|
||||
} *items;
|
||||
int nr, alloc;
|
||||
};
|
||||
|
||||
static int read_one_reflog(unsigned char *osha1, unsigned char *nsha1,
|
||||
const char *email, unsigned long timestamp, int tz,
|
||||
const char *message, void *cb_data)
|
||||
{
|
||||
struct complete_reflogs *array = cb_data;
|
||||
struct reflog_info *item;
|
||||
|
||||
if (array->nr >= array->alloc) {
|
||||
array->alloc = alloc_nr(array->nr + 1);
|
||||
array->items = xrealloc(array->items, array->alloc *
|
||||
sizeof(struct reflog_info));
|
||||
}
|
||||
item = array->items + array->nr;
|
||||
memcpy(item->osha1, osha1, 20);
|
||||
memcpy(item->nsha1, nsha1, 20);
|
||||
item->email = xstrdup(email);
|
||||
item->timestamp = timestamp;
|
||||
item->tz = tz;
|
||||
item->message = xstrdup(message);
|
||||
array->nr++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct complete_reflogs *read_complete_reflog(const char *ref)
|
||||
{
|
||||
struct complete_reflogs *reflogs =
|
||||
xcalloc(sizeof(struct complete_reflogs), 1);
|
||||
reflogs->ref = xstrdup(ref);
|
||||
for_each_reflog_ent(ref, read_one_reflog, reflogs);
|
||||
if (reflogs->nr == 0) {
|
||||
unsigned char sha1[20];
|
||||
const char *name = resolve_ref(ref, sha1, 1, NULL);
|
||||
if (name)
|
||||
for_each_reflog_ent(name, read_one_reflog, reflogs);
|
||||
}
|
||||
if (reflogs->nr == 0) {
|
||||
int len = strlen(ref);
|
||||
char *refname = xmalloc(len + 12);
|
||||
sprintf(refname, "refs/%s", ref);
|
||||
for_each_reflog_ent(refname, read_one_reflog, reflogs);
|
||||
if (reflogs->nr == 0) {
|
||||
sprintf(refname, "refs/heads/%s", ref);
|
||||
for_each_reflog_ent(refname, read_one_reflog, reflogs);
|
||||
}
|
||||
free(refname);
|
||||
}
|
||||
return reflogs;
|
||||
}
|
||||
|
||||
static int get_reflog_recno_by_time(struct complete_reflogs *array,
|
||||
unsigned long timestamp)
|
||||
{
|
||||
int i;
|
||||
for (i = array->nr - 1; i >= 0; i--)
|
||||
if (timestamp >= array->items[i].timestamp)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct commit_info_lifo {
|
||||
struct commit_info {
|
||||
struct commit *commit;
|
||||
void *util;
|
||||
} *items;
|
||||
int nr, alloc;
|
||||
};
|
||||
|
||||
static struct commit_info *get_commit_info(struct commit *commit,
|
||||
struct commit_info_lifo *lifo, int pop)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < lifo->nr; i++)
|
||||
if (lifo->items[i].commit == commit) {
|
||||
struct commit_info *result = &lifo->items[i];
|
||||
if (pop) {
|
||||
if (i + 1 < lifo->nr)
|
||||
memmove(lifo->items + i,
|
||||
lifo->items + i + 1,
|
||||
(lifo->nr - i) *
|
||||
sizeof(struct commit_info));
|
||||
lifo->nr--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void add_commit_info(struct commit *commit, void *util,
|
||||
struct commit_info_lifo *lifo)
|
||||
{
|
||||
struct commit_info *info;
|
||||
if (lifo->nr >= lifo->alloc) {
|
||||
lifo->alloc = alloc_nr(lifo->nr + 1);
|
||||
lifo->items = xrealloc(lifo->items,
|
||||
lifo->alloc * sizeof(struct commit_info));
|
||||
}
|
||||
info = lifo->items + lifo->nr;
|
||||
info->commit = commit;
|
||||
info->util = util;
|
||||
lifo->nr++;
|
||||
}
|
||||
|
||||
struct commit_reflog {
|
||||
int flag, recno;
|
||||
struct complete_reflogs *reflogs;
|
||||
};
|
||||
|
||||
struct reflog_walk_info {
|
||||
struct commit_info_lifo reflogs;
|
||||
struct path_list complete_reflogs;
|
||||
struct commit_reflog *last_commit_reflog;
|
||||
};
|
||||
|
||||
void init_reflog_walk(struct reflog_walk_info** info)
|
||||
{
|
||||
*info = xcalloc(sizeof(struct reflog_walk_info), 1);
|
||||
}
|
||||
|
||||
void add_reflog_for_walk(struct reflog_walk_info *info,
|
||||
struct commit *commit, const char *name)
|
||||
{
|
||||
unsigned long timestamp = 0;
|
||||
int recno = -1;
|
||||
struct path_list_item *item;
|
||||
struct complete_reflogs *reflogs;
|
||||
char *branch, *at = strchr(name, '@');
|
||||
struct commit_reflog *commit_reflog;
|
||||
|
||||
if (commit->object.flags & UNINTERESTING)
|
||||
die ("Cannot walk reflogs for %s", name);
|
||||
|
||||
branch = xstrdup(name);
|
||||
if (at && at[1] == '{') {
|
||||
char *ep;
|
||||
branch[at - name] = '\0';
|
||||
recno = strtoul(at + 2, &ep, 10);
|
||||
if (*ep != '}') {
|
||||
recno = -1;
|
||||
timestamp = approxidate(at + 2);
|
||||
}
|
||||
} else
|
||||
recno = 0;
|
||||
|
||||
item = path_list_lookup(branch, &info->complete_reflogs);
|
||||
if (item)
|
||||
reflogs = item->util;
|
||||
else {
|
||||
reflogs = read_complete_reflog(branch);
|
||||
if (!reflogs || reflogs->nr == 0)
|
||||
die("No reflogs found for '%s'", branch);
|
||||
path_list_insert(branch, &info->complete_reflogs)->util
|
||||
= reflogs;
|
||||
}
|
||||
|
||||
commit_reflog = xcalloc(sizeof(struct commit_reflog), 1);
|
||||
if (recno < 0) {
|
||||
commit_reflog->flag = 1;
|
||||
commit_reflog->recno = get_reflog_recno_by_time(reflogs, timestamp);
|
||||
if (commit_reflog->recno < 0) {
|
||||
free(branch);
|
||||
free(commit_reflog);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
commit_reflog->recno = reflogs->nr - recno - 1;
|
||||
commit_reflog->reflogs = reflogs;
|
||||
|
||||
add_commit_info(commit, commit_reflog, &info->reflogs);
|
||||
}
|
||||
|
||||
void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
|
||||
{
|
||||
struct commit_info *commit_info =
|
||||
get_commit_info(commit, &info->reflogs, 0);
|
||||
struct commit_reflog *commit_reflog;
|
||||
struct reflog_info *reflog;
|
||||
|
||||
info->last_commit_reflog = NULL;
|
||||
if (!commit_info)
|
||||
return;
|
||||
|
||||
commit_reflog = commit_info->util;
|
||||
if (commit_reflog->recno < 0) {
|
||||
commit->parents = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
|
||||
info->last_commit_reflog = commit_reflog;
|
||||
commit_reflog->recno--;
|
||||
commit_info->commit = (struct commit *)parse_object(reflog->osha1);
|
||||
if (!commit_info->commit) {
|
||||
commit->parents = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
commit->parents = xcalloc(sizeof(struct commit_list), 1);
|
||||
commit->parents->item = commit_info->commit;
|
||||
commit->object.flags &= ~(ADDED | SEEN | SHOWN);
|
||||
}
|
||||
|
||||
void show_reflog_message(struct reflog_walk_info* info, int oneline)
|
||||
{
|
||||
if (info && info->last_commit_reflog) {
|
||||
struct commit_reflog *commit_reflog = info->last_commit_reflog;
|
||||
struct reflog_info *info;
|
||||
|
||||
info = &commit_reflog->reflogs->items[commit_reflog->recno+1];
|
||||
if (oneline) {
|
||||
printf("%s@{", commit_reflog->reflogs->ref);
|
||||
if (commit_reflog->flag)
|
||||
printf("%s", show_date(info->timestamp, 0, 1));
|
||||
else
|
||||
printf("%d", commit_reflog->reflogs->nr
|
||||
- 2 - commit_reflog->recno);
|
||||
printf("}: ");
|
||||
}
|
||||
else {
|
||||
printf("Reflog: %s@{", commit_reflog->reflogs->ref);
|
||||
if (commit_reflog->flag)
|
||||
printf("%s", show_rfc2822_date(info->timestamp,
|
||||
info->tz));
|
||||
else
|
||||
printf("%d", commit_reflog->reflogs->nr
|
||||
- 2 - commit_reflog->recno);
|
||||
printf("} (%s)\nReflog message: %s",
|
||||
info->email, info->message);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
reflog-walk.h
Normal file
11
reflog-walk.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef REFLOG_WALK_H
|
||||
#define REFLOG_WALK_H
|
||||
|
||||
extern void init_reflog_walk(struct reflog_walk_info** info);
|
||||
extern void add_reflog_for_walk(struct reflog_walk_info *info,
|
||||
struct commit *commit, const char *name);
|
||||
extern void fake_reflog_parent(struct reflog_walk_info *info,
|
||||
struct commit *commit);
|
||||
extern void show_reflog_message(struct reflog_walk_info *info, int);
|
||||
|
||||
#endif
|
||||
49
revision.c
49
revision.c
@@ -7,6 +7,7 @@
|
||||
#include "refs.h"
|
||||
#include "revision.h"
|
||||
#include "grep.h"
|
||||
#include "reflog-walk.h"
|
||||
|
||||
static char *path_name(struct name_path *path, const char *name)
|
||||
{
|
||||
@@ -116,6 +117,9 @@ void mark_parents_uninteresting(struct commit *commit)
|
||||
void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
|
||||
{
|
||||
add_object_array(obj, name, &revs->pending);
|
||||
if (revs->reflog_info && obj->type == OBJ_COMMIT)
|
||||
add_reflog_for_walk(revs->reflog_info,
|
||||
(struct commit *)obj, name);
|
||||
}
|
||||
|
||||
static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
|
||||
@@ -864,6 +868,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
handle_reflog(revs, flags);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--walk-reflogs")) {
|
||||
init_reflog_walk(&revs->reflog_info);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--not")) {
|
||||
flags ^= UNINTERESTING;
|
||||
continue;
|
||||
@@ -1049,6 +1057,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
git_log_output_encoding = "";
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--reverse")) {
|
||||
revs->reverse ^= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i);
|
||||
if (opts > 0) {
|
||||
@@ -1210,6 +1222,9 @@ static struct commit *get_revision_1(struct rev_info *revs)
|
||||
revs->commits = entry->next;
|
||||
free(entry);
|
||||
|
||||
if (revs->reflog_info)
|
||||
fake_reflog_parent(revs->reflog_info, commit);
|
||||
|
||||
/*
|
||||
* If we haven't done the list limiting, we need to look at
|
||||
* the parents here. We also need to do the date-based limiting
|
||||
@@ -1274,6 +1289,40 @@ struct commit *get_revision(struct rev_info *revs)
|
||||
{
|
||||
struct commit *c = NULL;
|
||||
|
||||
if (revs->reverse) {
|
||||
struct commit_list *list;
|
||||
|
||||
/*
|
||||
* rev_info.reverse is used to note the fact that we
|
||||
* want to output the list of revisions in reverse
|
||||
* order. To accomplish this goal, reverse can have
|
||||
* different values:
|
||||
*
|
||||
* 0 do nothing
|
||||
* 1 reverse the list
|
||||
* 2 internal use: we have already obtained and
|
||||
* reversed the list, now we only need to yield
|
||||
* its items.
|
||||
*/
|
||||
|
||||
if (revs->reverse == 1) {
|
||||
revs->reverse = 0;
|
||||
list = NULL;
|
||||
while ((c = get_revision(revs)))
|
||||
commit_list_insert(c, &list);
|
||||
revs->commits = list;
|
||||
revs->reverse = 2;
|
||||
}
|
||||
|
||||
if (!revs->commits)
|
||||
return NULL;
|
||||
c = revs->commits->item;
|
||||
list = revs->commits->next;
|
||||
free(revs->commits);
|
||||
revs->commits = list;
|
||||
return c;
|
||||
}
|
||||
|
||||
if (0 < revs->skip_count) {
|
||||
while ((c = get_revision_1(revs)) != NULL) {
|
||||
if (revs->skip_count-- <= 0)
|
||||
|
||||
@@ -42,7 +42,8 @@ struct rev_info {
|
||||
unpacked:1, /* see also ignore_packed below */
|
||||
boundary:1,
|
||||
left_right:1,
|
||||
parents:1;
|
||||
parents:1,
|
||||
reverse:2;
|
||||
|
||||
/* Diff flags */
|
||||
unsigned int diff:1,
|
||||
@@ -89,6 +90,8 @@ struct rev_info {
|
||||
|
||||
topo_sort_set_fn_t topo_setter;
|
||||
topo_sort_get_fn_t topo_getter;
|
||||
|
||||
struct reflog_walk_info *reflog_info;
|
||||
};
|
||||
|
||||
#define REV_TREE_SAME 0
|
||||
|
||||
26
setup.c
26
setup.c
@@ -95,6 +95,8 @@ void verify_non_filename(const char *prefix, const char *arg)
|
||||
const char *name;
|
||||
struct stat st;
|
||||
|
||||
if (is_inside_git_dir())
|
||||
return;
|
||||
if (*arg == '-')
|
||||
return; /* flag */
|
||||
name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
|
||||
@@ -168,6 +170,28 @@ static int is_git_directory(const char *suspect)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int inside_git_dir = -1;
|
||||
|
||||
int is_inside_git_dir(void)
|
||||
{
|
||||
if (inside_git_dir < 0) {
|
||||
char buffer[1024];
|
||||
|
||||
if (is_bare_repository())
|
||||
return (inside_git_dir = 1);
|
||||
if (getcwd(buffer, sizeof(buffer))) {
|
||||
const char *git_dir = get_git_dir(), *cwd = buffer;
|
||||
while (*git_dir && *git_dir == *cwd) {
|
||||
git_dir++;
|
||||
cwd++;
|
||||
}
|
||||
inside_git_dir = !*git_dir;
|
||||
} else
|
||||
inside_git_dir = 0;
|
||||
}
|
||||
return inside_git_dir;
|
||||
}
|
||||
|
||||
const char *setup_git_directory_gently(int *nongit_ok)
|
||||
{
|
||||
static char cwd[PATH_MAX+1];
|
||||
@@ -206,6 +230,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
||||
if (chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
|
||||
inside_git_dir = 1;
|
||||
return NULL;
|
||||
}
|
||||
if (nongit_ok) {
|
||||
@@ -226,6 +251,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
||||
offset++;
|
||||
cwd[len++] = '/';
|
||||
cwd[len] = 0;
|
||||
inside_git_dir = !strncmp(cwd + offset, ".git/", 5);
|
||||
return cwd + offset;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,4 +106,33 @@ test_expect_success 'read-tree' '
|
||||
cmp ../one ../original.one
|
||||
'
|
||||
|
||||
test_expect_success 'no file/rev ambuguity check inside .git' '
|
||||
cd $HERE &&
|
||||
git commit -a -m 1 &&
|
||||
cd $HERE/.git &&
|
||||
git show -s HEAD
|
||||
'
|
||||
|
||||
test_expect_success 'no file/rev ambuguity check inside a bare repo' '
|
||||
cd $HERE &&
|
||||
git clone -s --bare .git foo.git &&
|
||||
cd foo.git && GIT_DIR=. git show -s HEAD
|
||||
'
|
||||
|
||||
# This still does not work as it should...
|
||||
: test_expect_success 'no file/rev ambuguity check inside a bare repo' '
|
||||
cd $HERE &&
|
||||
git clone -s --bare .git foo.git &&
|
||||
cd foo.git && git show -s HEAD
|
||||
'
|
||||
|
||||
test_expect_success 'detection should not be fooled by a symlink' '
|
||||
cd $HERE &&
|
||||
rm -fr foo.git &&
|
||||
git clone -s .git another &&
|
||||
ln -s another yetanother &&
|
||||
cd yetanother/.git &&
|
||||
git show -s HEAD
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -96,7 +96,7 @@ test_expect_success setup '
|
||||
|
||||
check_have A B C D E F G H I J K L &&
|
||||
|
||||
git prune &&
|
||||
git prune --grace=off &&
|
||||
|
||||
check_have A B C D E F G H I J K L &&
|
||||
|
||||
@@ -115,7 +115,7 @@ test_expect_success rewind '
|
||||
|
||||
check_have A B C D E F G H I J K L &&
|
||||
|
||||
git prune &&
|
||||
git prune --grace=off &&
|
||||
|
||||
check_have A B C D E F G H I J K L &&
|
||||
|
||||
@@ -160,7 +160,7 @@ test_expect_success 'reflog expire' '
|
||||
|
||||
test_expect_success 'prune and fsck' '
|
||||
|
||||
git prune &&
|
||||
git prune --grace=off &&
|
||||
check_fsck &&
|
||||
|
||||
check_have A B C D E H L &&
|
||||
|
||||
@@ -55,13 +55,13 @@ test_expect_success setup '
|
||||
|
||||
test_expect_success 'pack the source repository' '
|
||||
git repack -a -d &&
|
||||
git prune
|
||||
git prune --grace=off
|
||||
'
|
||||
|
||||
test_expect_success 'pack the destination repository' '
|
||||
cd victim &&
|
||||
git repack -a -d &&
|
||||
git prune &&
|
||||
git prune --grace=off &&
|
||||
cd ..
|
||||
'
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ echo second > file2 &&
|
||||
git add file2 &&
|
||||
git commit -m addition &&
|
||||
git repack -a -d &&
|
||||
git prune'
|
||||
git prune --grace=off'
|
||||
|
||||
cd "$base_dir"
|
||||
|
||||
@@ -56,7 +56,7 @@ echo third > file3 &&
|
||||
git add file3 &&
|
||||
git commit -m update &&
|
||||
git repack -a -d &&
|
||||
git prune'
|
||||
git prune --grace=off'
|
||||
|
||||
cd "$base_dir"
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ echo "Hello World" > file1 &&
|
||||
git add file1 &&
|
||||
git commit -m "Initial commit" file1 &&
|
||||
git repack -a -d &&
|
||||
git prune'
|
||||
git prune --grace=off'
|
||||
|
||||
cd "$base_dir"
|
||||
|
||||
@@ -39,7 +39,7 @@ echo "foo bar" > file2 &&
|
||||
git add file2 &&
|
||||
git commit -m "next commit" file2 &&
|
||||
git repack -a -d -l &&
|
||||
git prune'
|
||||
git prune --grace=off'
|
||||
|
||||
cd "$base_dir"
|
||||
|
||||
@@ -49,7 +49,7 @@ echo "Goodbye, cruel world" > file3 &&
|
||||
git add file3 &&
|
||||
git commit -m "one more" file3 &&
|
||||
git repack -a -d -l &&
|
||||
git prune'
|
||||
git prune --grace=off'
|
||||
|
||||
cd "$base_dir"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user