* [RFC] Teach git-branch howto rename a branch
From: Lars Hjemli @ 2006-11-24 23:03 UTC (permalink / raw)
To: git
This adds a '--rename' option to git branch. If specified, branch
creation becomes branch renaming.
With a single branchname, the current branch is renamed and .git/HEAD is
updated.
With two branchnames, the second name is renamed to the first.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
---
builtin-branch.c | 117 +++++++++++++++++++++++++++++++++++------------------
1 files changed, 77 insertions(+), 40 deletions(-)
diff --git a/builtin-branch.c b/builtin-branch.c
index f14d814..e714569 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -11,7 +11,7 @@
#include "builtin.h"
static const char builtin_branch_usage[] =
-"git-branch (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | [-r | -a] [-v] [--abbrev=<length>] ";
+"git-branch (-d | -D) <branchname> | [-l] [-f] [--rename] <branchname> [<start-point>] | [-r | -a] [-v] [--abbrev=<length>] ";
static const char *head;
@@ -36,47 +36,55 @@ static int in_merge_bases(const unsigned
return ret;
}
-static void delete_branches(int argc, const char **argv, int force)
+static void delete_branch(const char *branch, int force, struct commit *head_rev)
{
- struct commit *rev, *head_rev;
- unsigned char sha1[20];
+ struct commit *rev;
char *name;
- int i;
+ unsigned char sha1[20];
- head_rev = lookup_commit_reference(head_sha1);
- for (i = 0; i < argc; i++) {
- if (!strcmp(head, argv[i]))
- die("Cannot delete the branch you are currently on.");
-
- name = xstrdup(mkpath("refs/heads/%s", argv[i]));
- if (!resolve_ref(name, sha1, 1, NULL))
- die("Branch '%s' not found.", argv[i]);
-
- rev = lookup_commit_reference(sha1);
- if (!rev || !head_rev)
- die("Couldn't look up commit objects.");
-
- /* This checks whether the merge bases of branch and
- * HEAD contains branch -- which means that the HEAD
- * contains everything in both.
- */
-
- if (!force &&
- !in_merge_bases(sha1, rev, head_rev)) {
- fprintf(stderr,
- "The branch '%s' is not a strict subset of your current HEAD.\n"
- "If you are sure you want to delete it, run 'git branch -D %s'.\n",
- argv[i], argv[i]);
- exit(1);
- }
+ if (!strcmp(head, branch))
+ die("Cannot delete the branch you are currently on.");
+
+ name = xstrdup(mkpath("refs/heads/%s", branch));
+ if (!resolve_ref(name, sha1, 1, NULL))
+ die("Branch '%s' not found.", branch);
+
+ rev = lookup_commit_reference(sha1);
+ if (!rev)
+ die("Couldn't look up commit objects for %s", branch);
+
+ /* This checks whether the merge bases of branch and
+ * HEAD contains branch -- which means that the HEAD
+ * contains everything in both.
+ */
+
+ if (head_rev && !force &&
+ !in_merge_bases(sha1, rev, head_rev)) {
+ fprintf(stderr,
+ "The branch '%s' is not a strict subset of your current HEAD.\n"
+ "If you are sure you want to delete it, run 'git branch -D %s'.\n",
+ branch, branch);
+ exit(1);
+ }
- if (delete_ref(name, sha1))
- printf("Error deleting branch '%s'\n", argv[i]);
- else
- printf("Deleted branch %s.\n", argv[i]);
+ if (delete_ref(name, sha1))
+ printf("Error deleting branch '%s'\n", branch);
+ else
+ printf("Deleted branch %s.\n", branch);
- free(name);
- }
+ free(name);
+}
+
+static void delete_branches(int argc, const char **argv, int force)
+{
+ struct commit *head_rev;
+ int i;
+
+ head_rev = lookup_commit_reference(head_sha1);
+ if (!head_rev)
+ die("Couldn't look up commit object for current HEAD.");
+ for (i = 0; i < argc; i++)
+ delete_branch(argv[i], force, head_rev);
}
#define REF_UNKNOWN_TYPE 0x00
@@ -200,15 +208,18 @@ static void print_ref_list(int kinds, in
free_ref_list(&ref_list);
}
-static void create_branch(const char *name, const char *start,
+static char *create_branch(const char *name, const char *start,
int force, int reflog)
{
struct ref_lock *lock;
struct commit *commit;
unsigned char sha1[20];
- char ref[PATH_MAX], msg[PATH_MAX + 20];
+ char *ref, msg[PATH_MAX + 20];
+ int reflen;
- snprintf(ref, sizeof ref, "refs/heads/%s", name);
+ reflen = strlen(name) + 12;
+ ref = xmalloc(reflen+1);
+ snprintf(ref, reflen, "refs/heads/%s", name);
if (check_ref_format(ref))
die("'%s' is not a valid branch name.", name);
@@ -235,12 +246,30 @@ static void create_branch(const char *na
if (write_ref_sha1(lock, sha1, msg) < 0)
die("Failed to write ref: %s.", strerror(errno));
+ return ref;
+}
+
+static void rename_branch(const char *newname, const char *oldname, int force, int reflog)
+{
+ char ref[PATH_MAX];
+
+ snprintf(ref, sizeof ref, "refs/heads/%s", oldname);
+ if (check_ref_format(ref))
+ die("'%s' is not a valid branch name.", oldname);
+
+ newname = create_branch(newname, oldname, force, reflog);
+ if (!strcmp(oldname, head)) {
+ create_symref("HEAD", newname);
+ head = newname + 11;
+ }
+ delete_branch(oldname, force, NULL);
}
int cmd_branch(int argc, const char **argv, const char *prefix)
{
int delete = 0, force_delete = 0, force_create = 0;
int verbose = 0, abbrev = DEFAULT_ABBREV;
+ int rename = 0;
int reflog = 0;
int kinds = REF_LOCAL_BRANCH;
int i;
@@ -269,6 +298,10 @@ int cmd_branch(int argc, const char **ar
force_create = 1;
continue;
}
+ if (!strcmp(arg, "--rename")) {
+ rename = 1;
+ continue;
+ }
if (!strcmp(arg, "-r")) {
kinds = REF_REMOTE_BRANCH;
continue;
@@ -303,6 +336,10 @@ int cmd_branch(int argc, const char **ar
delete_branches(argc - i, argv + i, force_delete);
else if (i == argc)
print_ref_list(kinds, verbose, abbrev);
+ else if (rename && (i == argc - 1))
+ rename_branch(argv[i], head, force_create, reflog);
+ else if (rename && (i == argc - 2))
+ rename_branch(argv[i], argv[i + 1], force_create, reflog);
else if (i == argc - 1)
create_branch(argv[i], head, force_create, reflog);
else if (i == argc - 2)
--
1.4.4
^ permalink raw reply related
* Re: [PATCH] Make git-clone --use-separate-remote the default
From: Salikh Zakirov @ 2006-11-24 23:28 UTC (permalink / raw)
To: git
In-Reply-To: <7vslg9axzv.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano wrote:
> The way this command:
>
> git push $remote $src:$dst
>
> is handled is:
>
> (0) send-pack gets ls-remote equivalent from the remote. This
> tells us the set of refs the remote has and the value of
> each of them.
>
> (1) $src can be a ref that is resolved locally the usual way.
> You could have any valid SHA-1 expression (e.g. HEAD~6).
> (2) $dst is compared with the list of refs that the remote
> has, and unique match is found.
I think that remote matching semantics is confusing, and the following change
would make understanding easier.
I was understanding the manual incorrectly for a long time until you've
explained its true meaning today (thanks!).
As a side effect, making 'git push repo master' unambiguously expanded
to 'git push repo refs/heads/master:refs/heads/master' will make
the syntax 'git push repo tag v1' unneeded at all, because it would be
exactly the same as 'git push repo v1'
(expanded to 'git push repo refs/tags/v1:refs/tags/v1').
--- connect.c
+++ connect.c
@@ -277,6 +277,16 @@ static int match_explicit_refs(struct re
rs[i].src);
break;
}
+ if (!strcmp(rs[i].src,rs[i].dst)) {
+ /* src refspec is the same as dst,
+ * take the remote refpath exactly the same
+ * as existing local reference
+ */
+ int len = strlen(matched_src->name) + 1;
+ matched_dst = xcalloc(1, sizeof(*dst) + len);
+ memcpy(matched_dst->name, matched_src->name, len);
+ link_dst_tail(matched_dst, dst_tail);
+ } else
switch (count_refspec_match(rs[i].dst, dst, &matched_dst)) {
case 1:
break;
^ permalink raw reply
* Re: Show remote branches on gitweb
From: Petr Baudis @ 2006-11-24 23:59 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <ek7m6m$qqd$1@sea.gmane.org>
On Fri, Nov 24, 2006 at 09:56:29PM CET, Jakub Narebski wrote:
> Jakub Narebski wrote:
>
> > Pazu wrote:
> >
> >> Is there any way to do it? I'm using git-svn to track a remote subversion
> >> repository, and it would be very nice to browse the history for a remote branch
> >> for which I didn't start a local branch yet.
> >
> > Planned, not implemented yet.
>
> The problem is that to implement it _well_ we have to get remotes, both
> $GIT_DIR/remotes and config remote.xxx, info. And the latter (config
> remotes info) needs config parsing, something we lack.
Does that mean we _can_ parse $GIT_DIR/remotes? ;-)
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
The meaning of Stonehenge in Traflamadorian, when viewed from above, is:
"Replacement part being rushed with all possible speed."
^ permalink raw reply
* Re: [PATCH] Make git-clone --use-separate-remote the default
From: Junio C Hamano @ 2006-11-25 0:04 UTC (permalink / raw)
To: Salikh Zakirov; +Cc: git
In-Reply-To: <ek7v61$k89$1@sea.gmane.org>
Salikh Zakirov <salikh@gmail.com> writes:
> I think that remote matching semantics is confusing, and the following change
> would make understanding easier.
Hmm. I think this is somewhat wrong.
Have you tested the patch with repositories with existing refs?
You do not seem to check if that fabricated matched_dst exists
on the other side, so matched_dst lacks "where was this ref
initially" information (aka old_sha1), if I am reading your
patch correctly. Wouldn't that mean that you would confuse the
fast-forward check logic?
One setup I have that would be broken with this change is that
the remote end has refs/heads/up/obsd and no refs/heads/obsd,
and local end has refs/heads/obsd. This is to work on
portability fix for OpenBSD. With the current git-push, I think
git push $remote_openbsd_box obsd
would correctly update the remote refs/heads/up/obsd with the
local tip of the obsd branch, so that then I can ssh into the
remote and say "git merge up/obsd" to continue on that OpenBSD
machine from where I left off on the local, non-OpenBSD machine.
I am not sure if people would mind breaking existing setups like
this.
By the way, there are other glitches with the current git-push
(rather, git-send-pack) that we need to tighten. For example:
git push $remote HEAD~6
does not error out as it should. 'HEAD~6' is expanded to
'HEAD~6:HEAD~6'; its left hand side is valid (6 revs before the
tip is used to update the remote side) but its right hand side
is not checked for validity ("HEAD~6" is not a valid refname)
and creates .git/HEAD~6 at the remote end which is completely
bogus.
^ permalink raw reply
* Re: Show remote branches on gitweb
From: Jakub Narebski @ 2006-11-25 0:12 UTC (permalink / raw)
To: git
In-Reply-To: <20061124235911.GO7201@pasky.or.cz>
Petr Baudis wrote:
> On Fri, Nov 24, 2006 at 09:56:29PM CET, Jakub Narebski wrote:
>> Jakub Narebski wrote:
>>
>>> Pazu wrote:
>>>
>>>> Is there any way to do it? I'm using git-svn to track a remote subversion
>>>> repository, and it would be very nice to browse the history for a remote branch
>>>> for which I didn't start a local branch yet.
>>>
>>> Planned, not implemented yet.
>>
>> The problem is that to implement it _well_ we have to get remotes, both
>> $GIT_DIR/remotes and config remote.xxx, info. And the latter (config
>> remotes info) needs config parsing, something we lack.
>
> Does that mean we _can_ parse $GIT_DIR/remotes? ;-)
No, but for implementing showing remote branches in gitweb _well_,
but without frills'n'whistles, it is enough to know files in
$GIT_DIR/remotes (Find::find those files), and don't need to parse
remotes/ files.
--
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
^ permalink raw reply
* Re: Show remote branches on gitweb
From: Junio C Hamano @ 2006-11-25 0:40 UTC (permalink / raw)
To: Petr Baudis; +Cc: git, Jakub Narebski
In-Reply-To: <20061124235911.GO7201@pasky.or.cz>
Petr Baudis <pasky@suse.cz> writes:
>> The problem is that to implement it _well_ we have to get remotes, both
>> $GIT_DIR/remotes and config remote.xxx, info. And the latter (config
>> remotes info) needs config parsing, something we lack.
>
> Does that mean we _can_ parse $GIT_DIR/remotes? ;-)
Surely you should be able to. You are working in Perl and the
remotes and config are trivially parsable text files.
^ permalink raw reply
* Re: Show remote branches on gitweb
From: Petr Baudis @ 2006-11-25 0:50 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Jakub Narebski
In-Reply-To: <7vy7q08iko.fsf@assigned-by-dhcp.cox.net>
On Sat, Nov 25, 2006 at 01:40:23AM CET, Junio C Hamano wrote:
> Petr Baudis <pasky@suse.cz> writes:
>
> >> The problem is that to implement it _well_ we have to get remotes, both
> >> $GIT_DIR/remotes and config remote.xxx, info. And the latter (config
> >> remotes info) needs config parsing, something we lack.
> >
> > Does that mean we _can_ parse $GIT_DIR/remotes? ;-)
>
> Surely you should be able to. You are working in Perl and the
> remotes and config are trivially parsable text files.
But so is the configuration file, unless I'm missing something...?
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
The meaning of Stonehenge in Traflamadorian, when viewed from above, is:
"Replacement part being rushed with all possible speed."
^ permalink raw reply
* Re: Show remote branches on gitweb
From: Junio C Hamano @ 2006-11-25 1:04 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
In-Reply-To: <20061125005029.GN4842@pasky.or.cz>
Petr Baudis <pasky@suse.cz> writes:
>> > Does that mean we _can_ parse $GIT_DIR/remotes? ;-)
>>
>> Surely you should be able to. You are working in Perl and the
>> remotes and config are trivially parsable text files.
>
> But so is the configuration file, unless I'm missing something...?
I do not think you are missing anything. I said that remotes
and config are simple trivially parsable text files and Perl
should be a pleasant tool to read them with.
So yes, we _can_ parse them, and we _can_ parse configuration
file.
Unless I'm missing something...?
^ permalink raw reply
* [PATCH] git-clone: stop dumb protocol from copying refs outside heads/ and tags/.
From: Junio C Hamano @ 2006-11-25 3:17 UTC (permalink / raw)
To: git
Most notably, the original code first copied refs/remotes/ that
remote side had to local, and overwrote them by mapping refs/heads/
from the remote when a dumb protocol transport was used.
This makes the clone behaviour by dumb protocol in line with the
git native and rsync transports.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
* This is another one of those patches I've been doing recently
after making --use-separate-remote the default. Judging from
my experience in the past few days, it is quite surprising
that none of these were found and reported earlier, given
that many people made loud noises to make separate-remote the
default layout. Maybe they do not eat their own dog food? I
honestly do not know...
git-clone.sh | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/git-clone.sh b/git-clone.sh
index 9ed4135..d4ee93f 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -48,6 +48,10 @@ Perhaps git-update-server-info needs to be run there?"
case "$name" in
*^*) continue;;
esac
+ case "$bare,$name" in
+ yes,* | ,heads/* | ,tags/*) ;;
+ *) continue ;;
+ esac
if test -n "$use_separate_remote" &&
branch_name=`expr "z$name" : 'zheads/\(.*\)'`
then
--
1.4.4.1.g61fba
^ permalink raw reply related
* Re: [RFC] Teach git-branch howto rename a branch
From: Junio C Hamano @ 2006-11-25 5:40 UTC (permalink / raw)
To: Lars Hjemli; +Cc: git
In-Reply-To: <1164409429445-git-send-email-hjemli@gmail.com>
Lars Hjemli <hjemli@gmail.com> writes:
> +static void delete_branch(const char *branch, int force, struct commit *head_rev)
> {
>...
> +}
Refactoring the single ref deletion into this function feels
sane. I think you do not need a separate force parameter to
this function anymore; if the caller wants to force the deletion
it can send in a NULL for head_rev to signal that there is no
need for the "subset" check.
> +static void delete_branches(int argc, const char **argv, int force)
> +{
> + struct commit *head_rev;
> + int i;
> +
> + head_rev = lookup_commit_reference(head_sha1);
> + if (!head_rev)
> + die("Couldn't look up commit object for current HEAD.");
> + for (i = 0; i < argc; i++)
> + delete_branch(argv[i], force, head_rev);
> }
I do not think this die() is a good idea. I think it is
reasonable to allow the following sequence:
$ mkdir newdir && cd newdir
$ git init-db
$ git fetch $other_repo refs/heads/master:refs/heads/othre
$ git branch -D othre ;# oops, typo
$ git fetch $other_repo refs/heads/master:refs/heads/other
When forcing a deletion, we do not care about ancestry relation
between the HEAD and the branch being deleted, so we should not
even bother checking if HEAD is already valid. The original
code before your patch shares the same problem.
> -static void create_branch(const char *name, const char *start,
> +static char *create_branch(const char *name, const char *start,
> int force, int reflog)
This makes the returned names leak but probably we do not care
about it too much. However, the only caller that cares about
the new refname is rename_branch, and we are talking only about
branches, so I think handcrafting the refname just like you
handcraft the refname for oldname in rename_branch() would be
a better solution without introducing new leaks.
> +static void rename_branch(const char *newname, const char *oldname, int force, int reflog)
> +{
> + char ref[PATH_MAX];
> +
> + snprintf(ref, sizeof ref, "refs/heads/%s", oldname);
> + if (check_ref_format(ref))
> + die("'%s' is not a valid branch name.", oldname);
> +
> + newname = create_branch(newname, oldname, force, reflog);
This does not feel right. The 'start' parameter to
create_branch is arbitrary SHA-1 expression so it can take
'master', 'heads/master' and 'refs/heads/master' to mean the
same thing, as long as they are unambiguous, but here you would
want to accept only 'master' because the paramter is supposed to
be the name of the branch you are renaming. create_branch()
does not want to do that check for its start parameter, so you
should do the checking yourself here, and check_ref_format() is
not good enough for that. Probably calling resolve_ref() on ref
(= "refs/heads/oldname") for reading (because you also want to
make sure oldname talks about an existing branch) is needed.
> + if (!strcmp(oldname, head)) {
> + create_symref("HEAD", newname);
> + head = newname + 11;
> + }
> + delete_branch(oldname, force, NULL);
> }
What is the right thing that should happen when newname talks
about an existing branch (I am not asking "what does your code
do?")?
Without -f, it should barf. With -f, we would want the rename
to happen. In the latter case, I think it should work the same
way as deleting it and creating it anew, and that would make
sure that reflog for the old one will be lost and a new log is
started afresh; otherwise, the log would say old history for
that branch and it won't be a "rename" anymore.
Also what happens when oldname is "frotz" and newname is
"frotz/nitfol"? You would need to read the value of "frotz",
make sure you can delete it (perhaps the usual fast-forward
check as needed), and delete it to make room and then create
"frotz/nitfol". I suspect your patch does not handle that
case.
^ permalink raw reply
* Re: filemode=false somewhat broken
From: Shawn Pearce @ 2006-11-25 6:10 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Juergen Ruehle, git
In-Reply-To: <7vodqzp0mh.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> wrote:
> Juergen Ruehle <j.ruehle@bmiag.de> writes:
>
> > Commit fd28b34afd9bbd58297a25edced3f504c9a5487a tried to ignore the
> > executable bit if filemode=false, but instead forced all files to be
> > regular with 644 permission bits nuking symlink support.
>
> Thanks for noticing. Yes, that change is _seriously_ broken. I
> should really raise the bar for patch acceptance.
Whoops.
I don't work with symlinks so I never noticed the breakage myself.
Clearly the test cases that I created in fd28b3 should also have
included symlinks, but they did not... and we see this breakage
occur.
--
^ permalink raw reply
* [PATCH] git-svn: exit with status 1 for test failures
From: Eric Wong @ 2006-11-25 6:38 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Eric Wong
In-Reply-To: <11644366982320-git-send-email-normalperson@yhbt.net>
Some versions of the SVN libraries cause die() to exit with 255,
and 40cf043389ef4cdf3e56e7c4268d6f302e387fa0 tightened up
test_expect_failure to reject return values >128.
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
git-svn.perl | 20 ++++++++++++--------
1 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/git-svn.perl b/git-svn.perl
index 5d67771..0a47b1f 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -21,6 +21,7 @@ $ENV{TZ} = 'UTC';
$ENV{LC_ALL} = 'C';
$| = 1; # unbuffer STDOUT
+sub fatal (@) { print STDERR $@; exit 1 }
# If SVN:: library support is added, please make the dependencies
# optional and preserve the capability to use the command-line client.
# use eval { require SVN::... } to make it lazy load
@@ -569,7 +570,7 @@ sub commit_lib {
$no = 1;
}
}
- close $fh or croak $?;
+ close $fh or exit 1;
if (! defined $r_new && ! defined $cmt_new) {
unless ($no) {
die "Failed to parse revision information\n";
@@ -868,13 +869,16 @@ sub commit_diff {
print "Committed $_[0]\n";
}, @lock)
);
- my $mods = libsvn_checkout_tree($ta, $tb, $ed);
- if (@$mods == 0) {
- print "No changes\n$ta == $tb\n";
- $ed->abort_edit;
- } else {
- $ed->close_edit;
- }
+ eval {
+ my $mods = libsvn_checkout_tree($ta, $tb, $ed);
+ if (@$mods == 0) {
+ print "No changes\n$ta == $tb\n";
+ $ed->abort_edit;
+ } else {
+ $ed->close_edit;
+ }
+ };
+ fatal "$@\n" if $@;
$_message = $_file = undef;
return $rev_committed;
}
--
1.4.4.1.g22a08
^ permalink raw reply related
* [PATCH] git-svn: correctly access repos when only given partial read permissions
From: Eric Wong @ 2006-11-25 6:38 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Eric Wong
Sometimes users are given only read access to a subtree inside a
repository, and git-svn could not read log information (and thus
fetch commits) when connecting a session to the root of the
repository. We now start an SVN::Ra session with the full URL
of what we're tracking, and not the repository root as before.
This change was made much easier with a cleanup of
repo_path_split() usage as well as improving the accounting of
authentication batons.
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
git-svn.perl | 137 +++++++++++++++++++++++++++------------------------------
1 files changed, 65 insertions(+), 72 deletions(-)
diff --git a/git-svn.perl b/git-svn.perl
index 47cd3e2..5d67771 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -39,7 +39,7 @@ memoize('revisions_eq');
memoize('cmt_metadata');
memoize('get_commit_time');
-my ($SVN_PATH, $SVN, $SVN_LOG, $_use_lib, $AUTH_BATON, $AUTH_CALLBACKS);
+my ($SVN, $_use_lib);
sub nag_lib {
print STDERR <<EOF;
@@ -381,10 +381,7 @@ sub fetch_cmd {
sub fetch_lib {
my (@parents) = @_;
$SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url");
- my $repo;
- ($repo, $SVN_PATH) = repo_path_split($SVN_URL);
- $SVN_LOG ||= libsvn_connect($repo);
- $SVN ||= libsvn_connect($repo);
+ $SVN ||= libsvn_connect($SVN_URL);
my ($last_rev, $last_commit) = svn_grab_base_rev();
my ($base, $head) = libsvn_parse_revision($last_rev);
if ($base > $head) {
@@ -426,7 +423,7 @@ sub fetch_lib {
# performance sucks with it enabled, so it's much
# faster to fetch revision ranges instead of relying
# on the limiter.
- libsvn_get_log($SVN_LOG, '/'.$SVN_PATH,
+ libsvn_get_log(libsvn_dup_ra($SVN), [''],
$min, $max, 0, 1, 1,
sub {
my $log_msg;
@@ -528,7 +525,6 @@ sub commit_lib {
my $commit_msg = "$GIT_SVN_DIR/.svn-commit.tmp.$$";
my $repo;
- ($repo, $SVN_PATH) = repo_path_split($SVN_URL);
set_svn_commit_env();
foreach my $c (@revs) {
my $log_msg = get_commit_message($c, $commit_msg);
@@ -537,13 +533,11 @@ sub commit_lib {
# can't track down... (it's probably in the SVN code)
defined(my $pid = open my $fh, '-|') or croak $!;
if (!$pid) {
- $SVN_LOG = libsvn_connect($repo);
- $SVN = libsvn_connect($repo);
my $ed = SVN::Git::Editor->new(
{ r => $r_last,
- ra => $SVN_LOG,
+ ra => libsvn_dup_ra($SVN),
c => $c,
- svn_path => $SVN_PATH
+ svn_path => $SVN->{svn_path},
},
$SVN->get_commit_editor(
$log_msg->{msg},
@@ -661,10 +655,9 @@ sub show_ignore_cmd {
sub show_ignore_lib {
my $repo;
- ($repo, $SVN_PATH) = repo_path_split($SVN_URL);
- $SVN ||= libsvn_connect($repo);
+ $SVN ||= libsvn_connect($SVN_URL);
my $r = defined $_revision ? $_revision : $SVN->get_latest_revnum;
- libsvn_traverse_ignore(\*STDOUT, $SVN_PATH, $r);
+ libsvn_traverse_ignore(\*STDOUT, $SVN->{svn_path}, $r);
}
sub graft_branches {
@@ -790,7 +783,7 @@ sub show_log {
} elsif (/^:\d{6} \d{6} $sha1_short/o) {
push @{$c->{raw}}, $_;
} elsif (/^[ACRMDT]\t/) {
- # we could add $SVN_PATH here, but that requires
+ # we could add $SVN->{svn_path} here, but that requires
# remote access at the moment (repo_path_split)...
s#^([ACRMDT])\t# $1 #;
push @{$c->{changed}}, $_;
@@ -856,10 +849,7 @@ sub commit_diff {
$_message ||= get_commit_message($tb,
"$GIT_DIR/.svn-commit.tmp.$$")->{msg};
}
- my $repo;
- ($repo, $SVN_PATH) = repo_path_split($SVN_URL);
- $SVN_LOG ||= libsvn_connect($repo);
- $SVN ||= libsvn_connect($repo);
+ $SVN ||= libsvn_connect($SVN_URL);
if ($r eq 'HEAD') {
$r = $SVN->get_latest_revnum;
} elsif ($r !~ /^\d+$/) {
@@ -868,8 +858,9 @@ sub commit_diff {
my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : ();
my $rev_committed;
my $ed = SVN::Git::Editor->new({ r => $r,
- ra => $SVN_LOG, c => $tb,
- svn_path => $SVN_PATH
+ ra => libsvn_dup_ra($SVN),
+ c => $tb,
+ svn_path => $SVN->{svn_path}
},
$SVN->get_commit_editor($_message,
sub {
@@ -1147,8 +1138,7 @@ sub graft_file_copy_lib {
my $tree_paths = $l_map->{$u};
my $pfx = common_prefix([keys %$tree_paths]);
my ($repo, $path) = repo_path_split($u.$pfx);
- $SVN_LOG ||= libsvn_connect($repo);
- $SVN ||= libsvn_connect($repo);
+ $SVN = libsvn_connect($repo);
my ($base, $head) = libsvn_parse_revision();
my $inc = 1000;
@@ -1157,7 +1147,8 @@ sub graft_file_copy_lib {
$SVN::Error::handler = \&libsvn_skip_unknown_revs;
while (1) {
my $pool = SVN::Pool->new;
- libsvn_get_log($SVN_LOG, "/$path", $min, $max, 0, 1, 1,
+ libsvn_get_log(libsvn_dup_ra($SVN), [$path],
+ $min, $max, 0, 1, 1,
sub {
libsvn_graft_file_copies($grafts, $tree_paths,
$path, @_);
@@ -1267,13 +1258,9 @@ sub repo_path_split {
return ($u, $full_url);
}
}
-
if ($_use_lib) {
my $tmp = libsvn_connect($full_url);
- my $url = $tmp->get_repos_root;
- $full_url =~ s#^\Q$url\E/*##;
- push @repo_path_split_cache, qr/^(\Q$url\E)/;
- return ($url, $full_url);
+ return ($tmp->{repos_root}, $tmp->{svn_path});
} else {
my ($url, $path) = ($full_url =~ m!^([a-z\+]+://[^/]*)(.*)$!i);
$path =~ s#^/+##;
@@ -2815,34 +2802,41 @@ sub _read_password {
sub libsvn_connect {
my ($url) = @_;
- if (!$AUTH_BATON || !$AUTH_CALLBACKS) {
- SVN::_Core::svn_config_ensure($_config_dir, undef);
- ($AUTH_BATON, $AUTH_CALLBACKS) = SVN::Core::auth_open_helper([
- SVN::Client::get_simple_provider(),
- SVN::Client::get_ssl_server_trust_file_provider(),
- SVN::Client::get_simple_prompt_provider(
- \&_simple_prompt, 2),
- SVN::Client::get_ssl_client_cert_prompt_provider(
- \&_ssl_client_cert_prompt, 2),
- SVN::Client::get_ssl_client_cert_pw_prompt_provider(
- \&_ssl_client_cert_pw_prompt, 2),
- SVN::Client::get_username_provider(),
- SVN::Client::get_ssl_server_trust_prompt_provider(
- \&_ssl_server_trust_prompt),
- SVN::Client::get_username_prompt_provider(
- \&_username_prompt, 2),
- ]);
- }
- SVN::Ra->new(url => $url, auth => $AUTH_BATON,
- auth_provider_callbacks => $AUTH_CALLBACKS);
+ SVN::_Core::svn_config_ensure($_config_dir, undef);
+ my ($baton, $callbacks) = SVN::Core::auth_open_helper([
+ SVN::Client::get_simple_provider(),
+ SVN::Client::get_ssl_server_trust_file_provider(),
+ SVN::Client::get_simple_prompt_provider(
+ \&_simple_prompt, 2),
+ SVN::Client::get_ssl_client_cert_prompt_provider(
+ \&_ssl_client_cert_prompt, 2),
+ SVN::Client::get_ssl_client_cert_pw_prompt_provider(
+ \&_ssl_client_cert_pw_prompt, 2),
+ SVN::Client::get_username_provider(),
+ SVN::Client::get_ssl_server_trust_prompt_provider(
+ \&_ssl_server_trust_prompt),
+ SVN::Client::get_username_prompt_provider(
+ \&_username_prompt, 2),
+ ]);
+ my $ra = SVN::Ra->new(url => $url, auth => $baton,
+ pool => SVN::Pool->new,
+ auth_provider_callbacks => $callbacks);
+ $ra->{svn_path} = $url;
+ $ra->{repos_root} = $ra->get_repos_root;
+ $ra->{svn_path} =~ s#^\Q$ra->{repos_root}\E/*##;
+ push @repo_path_split_cache, qr/^(\Q$ra->{repos_root}\E)/;
+ return $ra;
+}
+
+sub libsvn_dup_ra {
+ my ($ra) = @_;
+ SVN::Ra->new(map { $_ => $ra->{$_} }
+ qw/url auth auth_provider_callbacks repos_root svn_path/);
}
sub libsvn_get_file {
my ($gui, $f, $rev, $chg) = @_;
- my $p = $f;
- if (length $SVN_PATH > 0) {
- return unless ($p =~ s#^\Q$SVN_PATH\E/##);
- }
+ $f =~ s#^/##;
print "\t$chg\t$f\n" unless $_q;
my ($hash, $pid, $in, $out);
@@ -2879,7 +2873,7 @@ sub libsvn_get_file {
waitpid $pid, 0;
$hash =~ /^$sha1$/o or die "not a sha1: $hash\n";
}
- print $gui $mode,' ',$hash,"\t",$p,"\0" or croak $!;
+ print $gui $mode,' ',$hash,"\t",$f,"\0" or croak $!;
}
sub libsvn_log_entry {
@@ -2897,7 +2891,6 @@ sub libsvn_log_entry {
sub process_rm {
my ($gui, $last_commit, $f) = @_;
- $f =~ s#^\Q$SVN_PATH\E/?## or return;
# remove entire directories.
if (safe_qx('git-ls-tree',$last_commit,'--',$f) =~ /^040000 tree/) {
defined(my $pid = open my $ls, '-|') or croak $!;
@@ -2919,9 +2912,11 @@ sub libsvn_fetch {
my ($last_commit, $paths, $rev, $author, $date, $msg) = @_;
open my $gui, '| git-update-index -z --index-info' or croak $!;
my @amr;
+ my $p = $SVN->{svn_path};
foreach my $f (keys %$paths) {
my $m = $paths->{$f}->action();
- $f =~ s#^/+##;
+ $f =~ s#^/\Q$p\E/##;
+ next if $f =~ m#^/#;
if ($m =~ /^[DR]$/) {
print "\t$m\t$f\n" unless $_q;
process_rm($gui, $last_commit, $f);
@@ -3011,9 +3006,9 @@ sub libsvn_parse_revision {
sub libsvn_traverse {
my ($gui, $pfx, $path, $rev, $files) = @_;
- my $cwd = "$pfx/$path";
+ my $cwd = length $pfx ? "$pfx/$path" : $path;
my $pool = SVN::Pool->new;
- $cwd =~ s#^/+##g;
+ $cwd =~ s#^\Q$SVN->{svn_path}\E##;
my ($dirent, $r, $props) = $SVN->get_dir($cwd, $rev, $pool);
foreach my $d (keys %$dirent) {
my $t = $dirent->{$d}->kind;
@@ -3037,7 +3032,7 @@ sub libsvn_traverse_ignore {
my $pool = SVN::Pool->new;
my ($dirent, undef, $props) = $SVN->get_dir($path, $r, $pool);
my $p = $path;
- $p =~ s#^\Q$SVN_PATH\E/?##;
+ $p =~ s#^\Q$SVN->{svn_path}\E/##;
print $fh length $p ? "\n# $p\n" : "\n# /\n";
if (my $s = $props->{'svn:ignore'}) {
$s =~ s/[\r\n]+/\n/g;
@@ -3064,7 +3059,7 @@ sub revisions_eq {
if ($_use_lib) {
# should be OK to use Pool here (r1 - r0) should be small
my $pool = SVN::Pool->new;
- libsvn_get_log($SVN, "/$path", $r0, $r1,
+ libsvn_get_log($SVN, [$path], $r0, $r1,
0, 1, 1, sub {$nr++}, $pool);
$pool->clear;
} else {
@@ -3079,7 +3074,7 @@ sub revisions_eq {
sub libsvn_find_parent_branch {
my ($paths, $rev, $author, $date, $msg) = @_;
- my $svn_path = '/'.$SVN_PATH;
+ my $svn_path = '/'.$SVN->{svn_path};
# look for a parent from another branch:
my $i = $paths->{$svn_path} or return;
@@ -3090,7 +3085,7 @@ sub libsvn_find_parent_branch {
$branch_from =~ s#^/##;
my $l_map = {};
read_url_paths_all($l_map, '', "$GIT_DIR/svn");
- my $url = $SVN->{url};
+ my $url = $SVN->{repos_root};
defined $l_map->{$url} or return;
my $id = $l_map->{$url}->{$branch_from};
if (!defined $id && $_follow_parent) {
@@ -3112,7 +3107,7 @@ sub libsvn_find_parent_branch {
$GIT_SVN = $ENV{GIT_SVN_ID} = $id;
init_vars();
$SVN_URL = "$url/$branch_from";
- $SVN_LOG = $SVN = undef;
+ $SVN = undef;
setup_git_svn();
# we can't assume SVN_URL exists at r+1:
$_revision = "0:$r";
@@ -3149,7 +3144,7 @@ sub libsvn_new_tree {
}
my ($paths, $rev, $author, $date, $msg) = @_;
open my $gui, '| git-update-index -z --index-info' or croak $!;
- libsvn_traverse($gui, '', $SVN_PATH, $rev);
+ libsvn_traverse($gui, '', $SVN->{svn_path}, $rev);
close $gui or croak $?;
return libsvn_log_entry($rev, $author, $date, $msg);
}
@@ -3234,11 +3229,10 @@ sub libsvn_commit_cb {
sub libsvn_ls_fullurl {
my $fullurl = shift;
- my ($repo, $path) = repo_path_split($fullurl);
- $SVN ||= libsvn_connect($repo);
+ $SVN ||= libsvn_connect($fullurl);
my @ret;
my $pool = SVN::Pool->new;
- my ($dirent, undef, undef) = $SVN->get_dir($path,
+ my ($dirent, undef, undef) = $SVN->get_dir($SVN->{svn_path},
$SVN->get_latest_revnum, $pool);
foreach my $d (keys %$dirent) {
if ($dirent->{$d}->kind == $SVN::Node::dir) {
@@ -3260,8 +3254,9 @@ sub libsvn_skip_unknown_revs {
# Wonderfully consistent library, eh?
# 160013 - svn:// and file://
# 175002 - http(s)://
+ # 175007 - http(s):// (this repo required authorization, too...)
# More codes may be discovered later...
- if ($errno == 175002 || $errno == 160013) {
+ if ($errno == 175007 || $errno == 175002 || $errno == 160013) {
return;
}
croak "Error from SVN, ($errno): ", $err->expanded_message,"\n";
@@ -3349,8 +3344,7 @@ sub split_path {
}
sub repo_path {
- (defined $_[1] && length $_[1]) ? "$_[0]->{svn_path}/$_[1]"
- : $_[0]->{svn_path}
+ (defined $_[1] && length $_[1]) ? $_[1] : ''
}
sub url_path {
@@ -3382,10 +3376,9 @@ sub rmdirs {
exec qw/git-ls-tree --name-only -r -z/, $self->{c} or croak $!;
}
local $/ = "\0";
- my @svn_path = split m#/#, $self->{svn_path};
while (<$fh>) {
chomp;
- my @dn = (@svn_path, (split m#/#, $_));
+ my @dn = split m#/#, $_;
while (pop @dn) {
delete $rm->{join '/', @dn};
}
--
1.4.4.1.g22a08
^ permalink raw reply related
* Re: [RFC] Teach git-branch howto rename a branch
From: Shawn Pearce @ 2006-11-25 6:49 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Lars Hjemli, git
In-Reply-To: <7v1wns6q41.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> wrote:
> Without -f, it should barf. With -f, we would want the rename
> to happen. In the latter case, I think it should work the same
> way as deleting it and creating it anew, and that would make
> sure that reflog for the old one will be lost and a new log is
> started afresh; otherwise, the log would say old history for
> that branch and it won't be a "rename" anymore.
This patch doesn't rename the reflog when the branch renames.
Myself and a few other users I support want the reflog preserved
when a branch renames, we all see the reflog as part of the history
of that branch and a rename is the same branch but stored under a
different name...
I had planned to do a rename branch command myself, but its been
lower priority than everything else, so I have just never gotten
around to it. I'm glad to see someone is attempting it!
--
^ permalink raw reply
* Re: [RFC] Submodules in GIT
From: Shawn Pearce @ 2006-11-25 6:53 UTC (permalink / raw)
To: Yann Dirson; +Cc: Linus Torvalds, Junio C Hamano, Jakub Narebski, git
In-Reply-To: <20061123232313.GB24909@nan92-1-81-57-214-146.fbx.proxad.net>
Yann Dirson <ydirson@altern.org> wrote:
> On Tue, Nov 21, 2006 at 10:40:56PM -0500, Shawn Pearce wrote:
> > Yet we still want to be able to efficiently perform operations like
> > "git bisect" within the scope of that submodule, to help narrow down
> > a particular bug that is within that submodule. To do that we need
> > the commit chain (all 10,000 of those commits) in the submodule.
> > To get those we really need a commit-ish and not a tree-ish, as
> > going from a tree-ish to a commit-ish is not only not unique but
> > is also pretty infeasible to do (you need to scan *every* commit).
>
> We don't need to have commits in the tree for this. We'll just have
> submodule commits which are not attached to a supermodule commit, and we
> can access the whole submodule history through the submodule .git/HEAD,
> just like we do for a standard git project.
No. You cannot do that.
How do we setup .git/HEAD when bisecting the supermodule?
Or merging it? Or doing anything else with it?
Ideally the .git/HEAD of every submodule should seek to the commit
that points at the tree of the submodule which the supermodule
is referencing. This lets you then perform a bisect within the
submodule when you identify the supermodule commit which caused
the breakage.
We need the submodule commits to do this. Doing it without is
too expensive.
--
^ permalink raw reply
* Re: Some tips for doing a CVS importer
From: Shawn Pearce @ 2006-11-25 6:59 UTC (permalink / raw)
To: Robin Rosenberg
Cc: lamikr, Jon Smirl, Carl Worth, Martin Langhoff, Git Mailing List
In-Reply-To: <200611232045.06974.robin.rosenberg.lists@dewire.com>
Robin Rosenberg <robin.rosenberg.lists@dewire.com> wrote:
> Slow it is. It is somewhat usable though, especially the quickdiff. I worked
> the whole day with help from quickdiff today. The diff is computed against
> HEAD^ (i.e. I get to see the changes that my topmost StGit patch introduces).
That's good to hear!
> The project contains 20000+ files and six years of history. Reading the whole
> history is out of the question with the current performance so I restrict
> reading to 500 entries which is just about bearable. That's enough for
> practical use with quickdiff and compare though. Improving jgit's speed 50
> times will probably be enough to make jgit shine.
Yes. I have a plan on how to rewrite the pack reading code which
should help somewhat here. There's some fundamental limitations
of Java though that are going to keep us from performing as well
as core-Git does (due to the object memory overheads) but I would
like to get close. :-)
jgit also has a few quirks still. For example it assumes everything
is encoded as UTF-8 but this isn't true. The encoding is project
specific and can be set by any user, which isn't that portable.
This is a problem for jgit and I need to go back and refactor the
parsing code...
I'd like to get back to jgit sometime in mid-Decemeber. I'm trying
to push through git-gui first. :-)
> Activating the Git connection seems to be a problem with the egit projects,
> i.e. it works sometimes, but not with my much bigger repo. The only problem
> is that the first time is dog slow. The structure is different though, as my
> repo has .project at the top, not one level down.
Hmm. That's a bug. Sounds like a thread timing issue if it works
sometimes, as the logic should be completely deterministic.
--
^ permalink raw reply
* [PATCH] git-branch -D: make it work even when on a yet-to-be-born branch
From: Junio C Hamano @ 2006-11-25 7:12 UTC (permalink / raw)
To: Lars Hjemli; +Cc: git
In-Reply-To: <7v1wns6q41.fsf@assigned-by-dhcp.cox.net>
This makes "git branch -D other_branch" work even when HEAD
points at a yet-to-be-born branch.
Earlier, we checked the HEAD ref for the purpose of "subset"
check even when the deletion was forced (i.e. not -d but -D).
Because of this, you cannot delete a branch even with -D while
on a yet-to-be-born branch.
With this change, the following sequence that now works:
mkdir newdir && cd newdir
git init-db
git fetch -k $other_repo refs/heads/master:refs/heads/othre
# oops, typo
git branch other othre
git branch -D othre
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
Junio C Hamano <junkio@cox.net> writes:
> When forcing a deletion, we do not care about ancestry relation
> between the HEAD and the branch being deleted, so we should not
> even bother checking if HEAD is already valid. The original
> code before your patch shares the same problem.
And here is a fix for that. This is on top of your -v change
which I've applied.
builtin-branch.c | 12 ++++++++----
1 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/builtin-branch.c b/builtin-branch.c
index 69b7b55..3d5cb0e 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -38,12 +38,16 @@ static int in_merge_bases(const unsigned char *sha1,
static void delete_branches(int argc, const char **argv, int force)
{
- struct commit *rev, *head_rev;
+ struct commit *rev, *head_rev = head_rev;
unsigned char sha1[20];
char *name;
int i;
- head_rev = lookup_commit_reference(head_sha1);
+ if (!force) {
+ head_rev = lookup_commit_reference(head_sha1);
+ if (!head_rev)
+ die("Couldn't look up commit object for HEAD");
+ }
for (i = 0; i < argc; i++) {
if (!strcmp(head, argv[i]))
die("Cannot delete the branch you are currently on.");
@@ -53,8 +57,8 @@ static void delete_branches(int argc, const char **argv, int force)
die("Branch '%s' not found.", argv[i]);
rev = lookup_commit_reference(sha1);
- if (!rev || !head_rev)
- die("Couldn't look up commit objects.");
+ if (!rev)
+ die("Couldn't look up commit object for '%s'", name);
/* This checks whether the merge bases of branch and
* HEAD contains branch -- which means that the HEAD
--
1.4.4.1.g61fba
^ permalink raw reply related
* Re: Calling all bash completion experts..
From: Shawn Pearce @ 2006-11-25 7:13 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.64.0611230935520.27596@woody.osdl.org>
Linus Torvalds <torvalds@osdl.org> wrote:
> So I do "git repa<tab>" and get "git repack", which is fine, but I really
> _wanted_ to get "git repack " (with the space at the end), since I've now
> got a unique command, and that's the normal completion behaviour (ie I
> want it to act the same way that "git-repa<tab>" would have acted).
[snip]
> Now, without knowing the completion syntax, I assume it's the "-o nospace"
> things in the completion file. So I'm wondering _why_ that "nospace" is
> there, and whether this could be fixed?
Yes, its the "-o nospace".
I added the nospace option because of the completion for fetch/push,
cat-file, diff-tree and ls-tree.
The problem is the file completion for e.g. cat-file. We don't
want a space added after we complete a directory name, so you can
complete further, e.g.:
git cat-file -p ma<tab>con<tab>comp<tab>git-com<tab>
gives us:
git cat-file -p master:contrib/completion/git-completion.sh
but if I omitted the "-o nospace" then we would instead need:
git cat-file ma<tab><bs>con<tab><bs>comp<tab><bs>git-com<tab>
as each successive <tab> would add a trailing space that you would need
to remove before you can complete again.
So as a user I decided that adding the space myself was less
annoying then needing to delete the space during completion down
through a tree. But perhaps that was wrong.
I did try to inject the space myself in the completion code when
I knew something was unique, but bash didn't like that (it tossed
the space).
To be honest, I'm not really sure how to fix it.
One option would be to perform a `ls-tree -r` through whatever part
of the path we have now and offer up EVERYTHING in the tree as a
possible completion, but that is insane as it will take a little
while to generate and on a large tree (e.g. the Linux kernel) you
will get a large number of proposed completions back which aren't
really relevant.
--
^ permalink raw reply
* Re: Computing delta sizes in pack files
From: Shawn Pearce @ 2006-11-25 7:33 UTC (permalink / raw)
To: Jonas Fonseca; +Cc: git
In-Reply-To: <2c6b72b30611220844t4b341284q4bff914b91eac48d@mail.gmail.com>
Jonas Fonseca <jonas.fonseca@gmail.com> wrote:
> I will not post the numbers here. They are available in
> http://jonas.nitro.dk/tmp/stats.pdf for those interested. The following
> is my "analysis" of the numbers.
Thanks, this was interesting stuff.
> As expected, the randomness of the content of both commit and tag objects
> results in a very poor packing performance of only 2%.
This is one reason why Jon Smirl was pushing the idea of dictionary based
compression. git.git has only 276 unique author lines, yet 37 of them
are really the top committers. Not surprisingly Junio C Hamano leads
the pack with 3529+ commits... :-)
A dictionary based compression would allow us to easily compress
Junio's authorship line away from those 3529+ commits into a single
string, getting much better compression on the commits.
In trees this may work very well too for very common file names, e.g.
"Makefile". Yes each tree delta compresses very well against its
base (and likely copies the file name from the base even when the
SHA1 changed) but if the bases were able to use a common dictionary
that would help even more.
> The data show that for minimal index files, the packs need to contain
> more than 2500 objects. The 24 bytes per-object for the optimal case
> includes 20-bytes for the object SHA1, and thus cannot be expected to
> become lower.
This is just a fundamental property of the pack index file format.
The file *MUST* be 1064 bytes of fixed overhead, with 24 bytes of
data per object indexed. So the fixed overhead amortizes very
quickly over the individual object entries, at which point its
exactly 24 bytes per entry. This all of course assumes a 32 bit
index (which is the current format).
The thing is the Mozilla index is 44 MiB. That's roughly 1.9 million
objects. The index itself is larger than the entire git.git pack.
On a large repository the index ain't trivial... yet its essential
to performance!
On the other hand the 1064 bytes of fixed overhead in the index
is nothing compared to the overhead in say an RCS file. Or an
SVN repository... :-)
What I failed to point out in my script (or in my email) is that
the 24 bytes of index entry cannot be eliminated, and thus must
be added to the "revision cost". In some cases its about the same
size as the deltafied revision in the pack file. :-(
--
^ permalink raw reply
* Re: [PATCH] Store peeled refs in packed-refs (take 2).
From: Marco Costalba @ 2006-11-25 8:09 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <e5bfff550611220425x5cf9e33ds7b7b98229c6b408a@mail.gmail.com>
On 11/22/06, Marco Costalba <mcostalba@gmail.com> wrote:
> On 11/22/06, Junio C Hamano <junkio@cox.net> wrote:
> > there is only one such extension defined, "peeled". This stores
> > the "peeled tag" on a line that immediately follows a line for a
> > tag object itself in the format "^<sha-1>".
> >
>
> Thanks, I will try to do some performance tests this week end.
>
Cold cache tests with "git show-ref -d" on packed refs (after
"git-pack-refs --prune")
Before patch:
- git tree 2374ms
- linux tree 2225ms
After patch:
- git tree 1108ms
^ permalink raw reply
* [PATCH 1/2] git-shortlog: fix common repository prefix abbreviation.
From: Junio C Hamano @ 2006-11-25 8:10 UTC (permalink / raw)
To: git
The code to abbreviate the common repository prefix was totally
borked.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
builtin-shortlog.c | 13 +++++++++----
1 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index b760b47..bdd952c 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -130,12 +130,17 @@ static void insert_author_oneline(struct path_list *list,
memcpy(buffer, oneline, onelinelen);
buffer[onelinelen] = '\0';
- while ((p = strstr(buffer, dot3)) != NULL) {
- memcpy(p, "...", 3);
- strcpy(p + 2, p + sizeof(dot3) - 1);
+ if (dot3) {
+ int dot3len = strlen(dot3);
+ if (dot3len > 5) {
+ while ((p = strstr(buffer, dot3)) != NULL) {
+ int taillen = strlen(p) - dot3len;
+ memcpy(p, "/.../", 5);
+ memmove(p + 5, p + dot3len, taillen + 1);
+ }
+ }
}
-
onelines = item->util;
if (onelines->nr >= onelines->alloc) {
onelines->alloc = alloc_nr(onelines->nr);
--
1.4.4.1.g61fba
^ permalink raw reply related
* [PATCH 2/2] git-shortlog: make common repository prefix configurable with .mailmap
From: Junio C Hamano @ 2006-11-25 8:11 UTC (permalink / raw)
To: git
The code had "/pub/scm/linux/kernel/git/" hardcoded which was
too specific to the kernel project.
With this, a line in the .mailmap file:
# repo-abbrev: /pub/scm/linux/kernel/git/
can be used to cause the substring to be abbreviated to /.../
on the title line of the commit message.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
builtin-shortlog.c | 24 ++++++++++++++++++++++--
contrib/mailmap.linux | 2 ++
2 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index bdd952c..b5b13de 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -9,6 +9,8 @@
static const char shortlog_usage[] =
"git-shortlog [-n] [-s] [<commit-id>... ]";
+static char *common_repo_prefix;
+
static int compare_by_number(const void *a1, const void *a2)
{
const struct path_list_item *i1 = a1, *i2 = a2;
@@ -35,8 +37,26 @@ static int read_mailmap(const char *filename)
char *end_of_name, *left_bracket, *right_bracket;
char *name, *email;
int i;
- if (buffer[0] == '#')
+ if (buffer[0] == '#') {
+ static const char abbrev[] = "# repo-abbrev:";
+ int abblen = sizeof(abbrev) - 1;
+ int len = strlen(buffer);
+
+ if (len && buffer[len - 1] == '\n')
+ buffer[--len] = 0;
+ if (!strncmp(buffer, abbrev, abblen)) {
+ char *cp;
+
+ if (common_repo_prefix)
+ free(common_repo_prefix);
+ common_repo_prefix = xmalloc(len);
+
+ for (cp = buffer + abblen; isspace(*cp); cp++)
+ ; /* nothing */
+ strcpy(common_repo_prefix, cp);
+ }
continue;
+ }
if ((left_bracket = strchr(buffer, '<')) == NULL)
continue;
if ((right_bracket = strchr(left_bracket + 1, '>')) == NULL)
@@ -87,7 +107,7 @@ static void insert_author_oneline(struct path_list *list,
const char *author, int authorlen,
const char *oneline, int onelinelen)
{
- const char *dot3 = "/pub/scm/linux/kernel/git/";
+ const char *dot3 = common_repo_prefix;
char *buffer, *p;
struct path_list_item *item;
struct path_list *onelines;
diff --git a/contrib/mailmap.linux b/contrib/mailmap.linux
index 83927c9..e4907f8 100644
--- a/contrib/mailmap.linux
+++ b/contrib/mailmap.linux
@@ -3,6 +3,8 @@
# So have an email->real name table to translate the
# (hopefully few) missing names
#
+# repo-abbrev: /pub/scm/linux/kernel/git/
+#
Adrian Bunk <bunk@stusta.de>
Andreas Herrmann <aherrman@de.ibm.com>
Andrew Morton <akpm@osdl.org>
--
1.4.4.1.g61fba
^ permalink raw reply related
* [PATCH] gitweb: Do not use esc_html in esc_path
From: Jakub Narebski @ 2006-11-25 8:43 UTC (permalink / raw)
To: git; +Cc: Jakub Narebski
Do not use esc_html in esc_path subroutine to avoid double quoting;
expand esc_html body (except quoting) in esc_path.
Move esc_path before quot_cec and quot_upr. Add some comments.
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
This patch was send to git mailing list; I don't know if it
was missed, or rejected.
gitweb/gitweb.perl | 28 +++++++++++++++++-----------
1 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index ce185d9..53214b0 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -585,7 +585,21 @@ sub esc_html ($;%) {
return $str;
}
-# Make control characterss "printable".
+# quote control characters and escape filename to HTML
+sub esc_path {
+ my $str = shift;
+ my %opts = @_;
+
+ $str = to_utf8($str);
+ $str = escapeHTML($str);
+ if ($opts{'-nbsp'}) {
+ $str =~ s/ / /g;
+ }
+ $str =~ s|([[:cntrl:]])|quot_cec($1)|eg;
+ return $str;
+}
+
+# Make control characters "printable", using character escape codes (CEC)
sub quot_cec {
my $cntrl = shift;
my %es = ( # character escape codes, aka escape sequences
@@ -605,22 +619,14 @@ sub quot_cec {
return "<span class=\"cntrl\">$chr</span>";
}
-# Alternatively use unicode control pictures codepoints.
+# Alternatively use unicode control pictures codepoints,
+# Unicode "printable representation" (PR)
sub quot_upr {
my $cntrl = shift;
my $chr = sprintf('&#%04d;', 0x2400+ord($cntrl));
return "<span class=\"cntrl\">$chr</span>";
}
-# quote control characters and escape filename to HTML
-sub esc_path {
- my $str = shift;
-
- $str = esc_html($str);
- $str =~ s|([[:cntrl:]])|quot_cec($1)|eg;
- return $str;
-}
-
# git may return quoted and escaped filenames
sub unquote {
my $str = shift;
--
1.4.3.4
^ permalink raw reply related
* Re: [RFC] Teach git-branch howto rename a branch
From: Jakub Narebski @ 2006-11-25 8:53 UTC (permalink / raw)
To: git
In-Reply-To: <20061125064901.GB4528@spearce.org>
Shawn Pearce wrote:
> Junio C Hamano <junkio@cox.net> wrote:
>> Without -f, it should barf. With -f, we would want the rename
>> to happen. In the latter case, I think it should work the same
>> way as deleting it and creating it anew, and that would make
>> sure that reflog for the old one will be lost and a new log is
>> started afresh; otherwise, the log would say old history for
>> that branch and it won't be a "rename" anymore.
>
> This patch doesn't rename the reflog when the branch renames.
> Myself and a few other users I support want the reflog preserved
> when a branch renames, we all see the reflog as part of the history
> of that branch and a rename is the same branch but stored under a
> different name...
And of course reflog should store the fact of renaming branch.
> I had planned to do a rename branch command myself, but its been
> lower priority than everything else, so I have just never gotten
> around to it. I'm glad to see someone is attempting it!
I have thought that command to rename branch was created to deal
with simultaneous renaming of reflog + marking rename in reflog.
--
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
^ permalink raw reply
* Re: [RFC] Teach git-branch howto rename a branch
From: Lars Hjemli @ 2006-11-25 8:52 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Shawn Pearce
In-Reply-To: <7v1wns6q41.fsf@assigned-by-dhcp.cox.net>
On 11/25/06, Junio C Hamano <junkio@cox.net> wrote:
> Lars Hjemli <hjemli@gmail.com> writes:
>
> > +static void rename_branch(const char *newname, const char *oldname, int force, int reflog)
> > +{
> > + char ref[PATH_MAX];
> > +
> > + snprintf(ref, sizeof ref, "refs/heads/%s", oldname);
> > + if (check_ref_format(ref))
> > + die("'%s' is not a valid branch name.", oldname);
> > +
> > + newname = create_branch(newname, oldname, force, reflog);
>
> This does not feel right. The 'start' parameter to
> create_branch is arbitrary SHA-1 expression so it can take
> 'master', 'heads/master' and 'refs/heads/master' to mean the
> same thing, as long as they are unambiguous, but here you would
> want to accept only 'master' because the paramter is supposed to
> be the name of the branch you are renaming. create_branch()
> does not want to do that check for its start parameter, so you
> should do the checking yourself here, and check_ref_format() is
> not good enough for that. Probably calling resolve_ref() on ref
> (= "refs/heads/oldname") for reading (because you also want to
> make sure oldname talks about an existing branch) is needed.
I forgot to use the handcrafted ref when calling 'create_branch':
newname = create_branch(newname, ref, force, reflog);
This would force the 'refs/heads' prefix, but let 'create_branch'
check if it's a valid commit reference. I _think_ this would be good
enough....
>
> > + if (!strcmp(oldname, head)) {
> > + create_symref("HEAD", newname);
> > + head = newname + 11;
> > + }
> > + delete_branch(oldname, force, NULL);
> > }
>
> What is the right thing that should happen when newname talks
> about an existing branch (I am not asking "what does your code
> do?")?
>
> Without -f, it should barf. With -f, we would want the rename
> to happen. In the latter case, I think it should work the same
> way as deleting it and creating it anew, and that would make
> sure that reflog for the old one will be lost and a new log is
> started afresh; otherwise, the log would say old history for
> that branch and it won't be a "rename" anymore.
Yes, the missing piece here is to copy the 'old' reflog to it's new
location after the call to create_branch. I belive create_branch
handles the -f cases.
> Also what happens when oldname is "frotz" and newname is
> "frotz/nitfol"? You would need to read the value of "frotz",
> make sure you can delete it (perhaps the usual fast-forward
> check as needed), and delete it to make room and then create
> "frotz/nitfol". I suspect your patch does not handle that
> case.
Hmm, you're right, I didn't think of such renaming. But I don't want
to delete the old ref before the new one is in place. How about
renaming the old one to a temporary name first?
I'l redo the patch on top of your 'git-branch -D' fix
--
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox