Merge branch 'master' into next

* master:
  Remove unnecessary found variable from describe.
  Use inttypes.h rather than stdint.h.
  Documentation: pack-refs --all vs default behaviour
  show-branch -g: default to HEAD
  Add dangling objects tips.
  parse-remote: do not barf on a remote shorthand without any refs to fetch.
  diffcore-pickaxe: fix infinite loop on zero-length needle
  Allow non-developer to clone, checkout and fetch more easily.
  contrib/emacs/vc-git.el: support vc-version-other-window
  Fix seriously broken "git pack-refs"
  New files in git weren't being downloaded during CVS update
  make --upload-pack option to git-fetch configurable
This commit is contained in:
Junio C Hamano
2007-01-26 00:19:01 -08:00
18 changed files with 224 additions and 37 deletions

View File

@@ -429,9 +429,13 @@ remote.<name>.push::
gitlink:git-push[1].
remote.<name>.receivepack::
The default program to execute on the remote side when pulling. See
The default program to execute on the remote side when pushing. See
option \--exec of gitlink:git-push[1].
remote.<name>.uploadpack::
The default program to execute on the remote side when fetching. See
option \--exec of gitlink:git-fetch-pack[1].
repack.usedeltabaseoffset::
Allow gitlink:git-repack[1] to create packs that uses
delta-base offset. Defaults to false.

View File

@@ -29,12 +29,23 @@ file and used if found.
Subsequent updates to branches always creates new file under
`$GIT_DIR/refs` hierarchy.
A recommended practice to deal with a repository with too many
refs is to pack its refs with `--all --prune` once, and
occasionally run `git-pack-refs \--prune`. Tags are by
definition stationary and are not expected to change. Branch
heads will be packed with the initial `pack-refs --all`, but
only the currently active branch heads will become unpacked,
and next `pack-refs` (without `--all`) will leave them
unpacked.
OPTIONS
-------
\--all::
The command by default packs all tags and leaves branch tips
The command by default packs all tags and refs that are already
packed, and leaves other refs
alone. This is because branches are expected to be actively
developed and packing their tips does not help performance.
This option causes branch tips to be packed as well. Useful for

View File

@@ -0,0 +1,109 @@
From: Linus Torvalds <torvalds@linux-foundation.org>
Subject: Re: Question about fsck-objects output
Date: Thu, 25 Jan 2007 12:01:06 -0800 (PST)
Message-ID: <Pine.LNX.4.64.0701251144290.25027@woody.linux-foundation.org>
Archived-At: <http://permalink.gmane.org/gmane.comp.version-control.git/37754>
Abstract: Linus describes what dangling objects are, when they
are left behind, and how to view their relationship with branch
heads in gitk
On Thu, 25 Jan 2007, Larry Streepy wrote:
> Sorry to ask such a basic question, but I can't quite decipher the output of
> fsck-objects. When I run it, I get this:
>
> git fsck-objects
> dangling commit 2213f6d4dd39ca8baebd0427723723e63208521b
> dangling commit f0d4e00196bd5ee54463e9ea7a0f0e8303da767f
> dangling blob 6a6d0b01b3e96d49a8f2c7addd4ef8c3bd1f5761
>
>
> Even after a "repack -a -d" they still exist. The man page has a short
> explanation, but, at least for me, it wasn't fully enlightening. :-)
>
> The man page says that dangling commits could be "root" commits, but since my
> repo started as a clone of another repo, I don't see how I could have any root
> commits. Also, the page doesn't really describe what a dangling blob is.
>
> So, can someone explain what these artifacts are and if they are a problem
> that I should be worried about?
The most common situation is that you've rebased a branch (or you have
pulled from somebody else who rebased a branch, like the "pu" branch in
the git.git archive itself).
What happens is that the old head of the original branch still exists, as
does obviously everything it pointed to. The branch pointer itself just
doesn't, since you replaced it with another one.
However, there are certainly other situations too that cause dangling
objects. For example, the "dangling blob" situation you have tends to be
because you did a "git add" of a file, but then, before you actually
committed it and made it part of the bigger picture, you changed something
else in that file and committed that *updated* thing - the old state that
you added originally ends up not being pointed to by any commit/tree, so
it's now a dangling blob object.
Similarly, when the "recursive" merge strategy runs, and finds that there
are criss-cross merges and thus more than one merge base (which is fairly
unusual, but it does happen), it will generate one temporary midway tree
(or possibly even more, if you had lots of criss-crossing merges and
more than two merge bases) as a temporary internal merge base, and again,
those are real objects, but the end result will not end up pointing to
them, so they end up "dangling" in your repository.
Generally, dangling objects aren't anything to worry about. They can even
be very useful: if you screw something up, the dangling objects can be how
you recover your old tree (say, you did a rebase, and realized that you
really didn't want to - you can look at what dangling objects you have,
and decide to reset your head to some old dangling state).
For commits, the most useful thing to do with dangling objects tends to be
to do a simple
gitk <dangling-commit-sha-goes-here> --not --all
which means exactly what it sounds like: it says that you want to see the
commit history that is described by the dangling commit(s), but you do NOT
want to see the history that is described by all your branches and tags
(which are the things you normally reach). That basically shows you in a
nice way what the danglign commit was (and notice that it might not be
just one commit: we only report the "tip of the line" as being dangling,
but there might be a whole deep and complex commit history that has gotten
dropped - rebasing will do that).
For blobs and trees, you can't do the same, but you can examine them. You
can just do
git show <dangling-blob/tree-sha-goes-here>
to show what the contents of the blob were (or, for a tree, basically what
the "ls" for that directory was), and that may give you some idea of what
the operation was that left that dangling object.
Usually, dangling blobs and trees aren't very interesting. They're almost
always the result of either being a half-way mergebase (the blob will
often even have the conflict markers from a merge in it, if you have had
conflicting merges that you fixed up by hand), or simply because you
interrupted a "git fetch" with ^C or something like that, leaving _some_
of the new objects in the object database, but just dangling and useless.
Anyway, once you are sure that you're not interested in any dangling
state, you can just prune all unreachable objects:
git prune
and they'll be gone. But you should only run "git prune" on a quiescent
repository - it's kind of like doing a filesystem fsck recovery: you don't
want to do that while the filesystem is mounted.
(The same is true of "git-fsck-objects" itself, btw - but since
git-fsck-objects never actually *changes* the repository, it just reports
on what it found, git-fsck-objects itself is never "dangerous" to run.
Running it while somebody is actually changing the repository can cause
confusing and scary messages, but it won't actually do anything bad. In
contrast, running "git prune" while somebody is actively changing the
repository is a *BAD* idea).
Linus

View File

@@ -101,7 +101,6 @@ static void describe(const char *arg, int last_one)
struct possible_tag all_matches[MAX_TAGS];
unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
unsigned long seen_commits = 0;
int found = 0;
if (get_sha1(arg, sha1))
die("Not a valid object name %s", arg);
@@ -137,7 +136,7 @@ static void describe(const char *arg, int last_one)
t->name = n;
t->depth = seen_commits - 1;
t->flag_within = 1u << match_cnt;
t->found_order = found++;
t->found_order = match_cnt;
c->object.flags |= t->flag_within;
if (n->prio == 2)
annotated_cnt++;

View File

@@ -352,7 +352,7 @@ static void get_patch_ids(struct rev_info *rev, struct diff_options *options, co
static void gen_message_id(char *dest, unsigned int length, char *base)
{
const char *committer = git_committer_info(1);
const char *committer = git_committer_info(-1);
const char *email_start = strrchr(committer, '<');
const char *email_end = strrchr(committer, '>');
if(!email_start || !email_end || email_start > email_end - 1)

View File

@@ -37,7 +37,9 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
if ((flags & REF_ISSYMREF))
return 0;
is_tag_ref = !strncmp(path, "refs/tags/", 10);
if (!cb->all && !is_tag_ref)
/* ALWAYS pack refs that were already packed or are tags */
if (!cb->all && !is_tag_ref && !(flags & REF_ISPACKED))
return 0;
fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);

View File

@@ -662,13 +662,13 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
}
ac--; av++;
if (!!extra || !!reflog) {
if (extra || reflog) {
/* "listing" mode is incompatible with
* independent nor merge-base modes.
*/
if (independent || merge_base)
usage(show_branch_usage);
if (!!reflog && ((0 < extra) || all_heads || all_remotes))
if (reflog && ((0 < extra) || all_heads || all_remotes))
/*
* Asking for --more in reflog mode does not
* make sense. --list is Ok.
@@ -682,15 +682,22 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
if (ac + all_heads + all_remotes == 0)
all_heads = 1;
if (all_heads + all_remotes)
snarf_refs(all_heads, all_remotes);
if (reflog) {
unsigned char sha1[20];
char nth_desc[256];
char *ref;
int base = 0;
if (ac == 0) {
static const char *fake_av[2];
fake_av[0] = "HEAD";
fake_av[1] = NULL;
av = fake_av;
ac = 1;
}
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);
@@ -735,6 +742,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
append_ref(nth_desc, sha1, 1);
}
}
else if (all_heads + all_remotes)
snarf_refs(all_heads, all_remotes);
else {
while (0 < ac) {
append_one_rev(*av);

View File

@@ -320,7 +320,6 @@ void datestamp(char *buf, int bufsize);
unsigned long approxidate(const char *);
extern int setup_ident(void);
extern void ignore_missing_committer_name(void);
extern const char *git_author_info(int);
extern const char *git_committer_info(int);

View File

@@ -53,6 +53,10 @@
(let ((name (file-relative-name file)))
(eq 0 (apply #'call-process "git" nil (get-buffer "*Messages") nil (append args (list name))))))
(defun vc-git--run-command-out (output &rest args)
"Run a git command, output to output."
(eq 0 (apply #'call-process "git" nil output nil (append args))))
(defun vc-git-registered (file)
"Check whether FILE is registered with git."
(with-temp-buffer
@@ -120,7 +124,28 @@
(vc-git--run-command file "commit" "-m" comment "--only" "--")))
(defun vc-git-checkout (file &optional editable rev destfile)
(vc-git--run-command file "checkout" (or rev "HEAD")))
(if destfile
(let ((mybuff (get-buffer-create "vc-git-checkout-tmp")))
(let ((rv
(vc-git--run-command-out
mybuff "cat-file" "blob"
(concat (or rev "HEAD")
":"
(let ((output (vc-git--run-command-string
(file-relative-name file)
"ls-files" "--full-name")))
(string-match "\\(.*\\)" output)
(match-string 1 output))
)))
)
(if rv
(save-current-buffer
(set-buffer mybuff)
(set-visited-file-name destfile t)
(save-buffer)
)
rv)))
(vc-git--run-command file "checkout" (or rev "HEAD"))))
(defun vc-git-annotate-command (file buf &optional rev)
; FIXME: rev is ignored

View File

@@ -14,6 +14,8 @@ static unsigned int contains(struct diff_filespec *one,
const char *data;
if (diff_populate_filespec(one, 0))
return 0;
if (!len)
return 0;
sz = one->size;
data = one->data;

View File

@@ -46,7 +46,7 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <pwd.h>
#include <stdint.h>
#include <inttypes.h>
#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
#include <grp.h>
#define _ALL_SOURCE 1

View File

@@ -876,9 +876,9 @@ sub req_update
print "MT newline\n";
next;
}
elsif ( !defined($wrev) || $wrev == 0 )
elsif ( (!defined($wrev) || $wrev == 0) && (!defined($meta->{revision}) || $meta->{revision} == 0) )
{
$log->info("Tell the client the file will be added");
$log->info("Tell the client the file is scheduled for addition");
print "MT text A \n";
print "MT fname $filename\n";
print "MT newline\n";
@@ -886,7 +886,7 @@ sub req_update
}
else {
$log->info("Updating '$filename' $wrev");
$log->info("Updating '$filename' to ".$meta->{revision});
print "MT +updated\n";
print "MT text U \n";
print "MT fname $filename\n";

View File

@@ -85,6 +85,12 @@ case "$#" in
set x $origin ; shift ;;
esac
if test -z "$exec"
then
# No command line override and we have configuration for the remote.
exec="--upload-pack=$(get_uploadpack $1)"
fi
remote_nick="$1"
remote=$(get_remote_url "$@")
refs=

View File

@@ -81,7 +81,14 @@ get_remote_default_refs_for_push () {
# is to help prevent randomly "globbed" ref from being chosen as
# a merge candidate
expand_refs_wildcard () {
remote="$1"
shift
first_one=yes
if test "$#" = 0
then
echo empty
echo >&2 "Nothing specified for fetching with remote.$remote.fetch"
fi
for ref
do
lref=${ref#'+'}
@@ -132,7 +139,7 @@ canon_refs_list_for_fetch () {
if test "$1" = "-d"
then
shift ; remote="$1" ; shift
set $(expand_refs_wildcard "$@")
set $(expand_refs_wildcard "$remote" "$@")
is_explicit="$1"
shift
if test "$remote" = "$(get_default_remote)"
@@ -279,3 +286,16 @@ resolve_alternates () {
esac
done
}
get_uploadpack () {
data_source=$(get_data_source "$1")
case "$data_source" in
config)
uplp=$(git-repo-config --get "remote.$1.uploadpack")
echo ${uplp:-git-upload-pack}
;;
*)
echo "git-upload-pack"
;;
esac
}

28
ident.c
View File

@@ -180,12 +180,21 @@ static const char *get_ident(const char *name, const char *email,
email = git_default_email;
if (!*name) {
if (name == git_default_name && env_hint) {
struct passwd *pw;
if (0 <= error_on_no_name &&
name == git_default_name && env_hint) {
fprintf(stderr, env_hint, au_env, co_env);
env_hint = NULL; /* warn only once, for "git-var -l" */
}
if (error_on_no_name)
if (0 < error_on_no_name)
die("empty ident %s <%s> not allowed", name, email);
pw = getpwuid(getuid());
if (!pw)
die("You don't exist. Go away!");
strlcpy(git_default_name, pw->pw_name,
sizeof(git_default_name));
name = git_default_name;
}
strcpy(date, git_default_date);
@@ -218,18 +227,3 @@ const char *git_committer_info(int error_on_no_name)
getenv("GIT_COMMITTER_DATE"),
error_on_no_name);
}
void ignore_missing_committer_name()
{
/* If we did not get a name from the user's gecos entry then
* git_default_name is empty; so instead load the username
* into it as a 'good enough for now' approximation of who
* this user is.
*/
if (!*git_default_name) {
struct passwd *pw = getpwuid(getuid());
if (!pw)
die("You don't exist. Go away!");
strlcpy(git_default_name, pw->pw_name, sizeof(git_default_name));
}
}

View File

@@ -430,8 +430,6 @@ int main(int argc, char **argv)
die("attempt to push into a shallow repository");
setup_ident();
/* don't die if gecos is empty */
ignore_missing_committer_name();
git_config(receive_pack_config);
if (0 <= transfer_unpack_limit)

2
refs.c
View File

@@ -958,7 +958,7 @@ static int log_ref_write(struct ref_lock *lock,
lock->log_file, strerror(errno));
}
committer = git_committer_info(1);
committer = git_committer_info(-1);
if (msg) {
maxlen = strlen(committer) + strlen(msg) + 2*40 + 5;
logrec = xmalloc(maxlen);

View File

@@ -96,4 +96,13 @@ test_expect_success \
git-branch -d n/o/p &&
git-branch n'
test_expect_success 'pack, prune and repack' '
git-tag foo &&
git-pack-refs --all --prune &&
git-show-ref >all-of-them &&
git-pack-refs &&
git-show-ref >again &&
diff all-of-them again
'
test_done