* [RFC] series headers
From: Daniel Barkalow @ 2007-07-10 6:14 UTC (permalink / raw)
To: git
I'd like to be able to get format-patch to produce a [PATCH 0/N] message,
with a message that's actually in my repository, plus various goodies
generated either from diffing the ends of the series or by running through
the log an extra time to pick up summary information.
The second best idea I have for this currently is to have a commit at the
end of the series which specifies which has the same tree as its parent
and has a message with a line "Since <sha1 of the first commit of the
series>" and has the text. This goes at the end of the series, because it
describes the state with all of the changes made, which is only a good
description of a commit at the end of the series, not a commit at the
start of the series. Making it [PATCH 0/N] is just because it belongs
first in presentation, regardless of whether the other commits are
presented with recent commits first or last.
The better idea I just had was to have format-patch notice if the "until"
side is a tag object instead of a commit, and generate a [0/N] with the
tag message.
As far as implementing this... would it be sane to make struct
rev_info.commit_format a callback, so that the code to generate an email
message can be somewhere that's easy to use to generate an email that
isn't for a commit in the log? I don't *think* git's quite fast enough for
the indirect jump to a callback instead of an if tree for an enum will
actually hurt us.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: "svn switch" equivalent when using git-svn -- git-filter-branch?
From: Eric Wong @ 2007-07-10 5:40 UTC (permalink / raw)
To: David Kastrup; +Cc: git
In-Reply-To: <86sl7x7nzq.fsf@lola.quinscape.zz>
David Kastrup <dak@gnu.org> wrote:
> Hi,
>
> an upstream svn repository that I access with git-svn has moved. I
> seem to be too stupid to use git-filter-branch and/or .git/config
> and/or git-reset to make my git mirror follow the switch.
Just changing the url key in the [svn-remote] section of the .git/config
file should be enough.
You'll probably need to fetch at least one revision from the new URL
before being able to dcommit, though.
I've never looked at git-filter-branch, either.
--
Eric Wong
^ permalink raw reply
* Re: [PATCH 2/2] Some cosmetic changes to remote library
From: Junio C Hamano @ 2007-07-10 5:33 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0707100045380.6977@iabervon.org>
Thanks for good readability improvements. Will apply.
^ permalink raw reply
* Re: [PATCH 1/2] Add for_each_remote() function, and extend remote_find_tracking()
From: Daniel Barkalow @ 2007-07-10 5:23 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Johannes Schindelin, git
In-Reply-To: <7vy7hosv7v.fsf@assigned-by-dhcp.cox.net>
On Mon, 9 Jul 2007, Junio C Hamano wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>
> > You're right. I completely missed that functionality. Well, a
> > few tweaks were needed. If this clashes too seriously with
> > Daniel's work, I will gladly redo it after his changes are
> > in "next".
>
> No offence meant to Daniel, but I am inclined to postpone the
> current round of changes from him to move the stuff further
> to get us closer to built-in git-fetch until 1.5.3 final is
> done. The amount of C code changes otherwise would be a bit too
> much for me to be comfortable between -rc0 and -rc1.
That's what I'd expect; I'm posting stuff now so that I'm not proposing it
unreviewed after 1.5.3. Certainly anything that's needed to fix current
issues should go ahead of these changes, and it doesn't look like there
would be any conflicts anyway, aside from maybe adding two functions in
the same place in the file, which is trivial to fix by hand.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: [PATCH 1/2] Add for_each_remote() function, and extend remote_find_tracking()
From: Junio C Hamano @ 2007-07-10 5:07 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Paolo Bonzini, git, Daniel Barkalow
In-Reply-To: <Pine.LNX.4.64.0707100401070.4131@racer.site>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> The function for_each_remote() does exactly what the name suggests.
>
> The function remote_find_tracking() was extended to be able to search
> remote refs for a given local ref. You have to set the parameter
> "reverse" to true for that behavior.
>
> Both changes are required for the next step: simplification of
> git-branch's --track functionality.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>
> You're right. I completely missed that functionality. Well, a
> few tweaks were needed. If this clashes too seriously with
> Daniel's work, I will gladly redo it after his changes are
> in "next".
No offence meant to Daniel, but I am inclined to postpone the
current round of changes from him to move the stuff further
to get us closer to built-in git-fetch until 1.5.3 final is
done. The amount of C code changes otherwise would be a bit too
much for me to be comfortable between -rc0 and -rc1.
> diff --git a/remote.c b/remote.c
> index cf98a44..21adb0d 100644
> --- a/remote.c
> +++ b/remote.c
> @@ -279,6 +279,26 @@ struct remote *remote_get(const char *name)
> return ret;
> }
>
> +int for_each_remote(each_remote_fn fn, void *priv)
> +{
> ...
> + if ((result = fn(r, priv)))
> + break;
Just a minor style, but (you know what comes)...
> @@ -289,34 +309,36 @@ int remote_has_uri(struct remote *remote, const char *uri)
> return 0;
> }
>
> +int remote_find_tracking(struct remote *remote, struct refspec *refspec,
> + int reverse)
> {
> int i;
> for (i = 0; i < remote->fetch_refspec_nr; i++) {
> struct refspec *fetch = &remote->fetch[i];
> + const char *src = reverse ? fetch->dst : fetch->src;
> + const char *dst = reverse ? fetch->src : fetch->dst;
I have to agree with Daniel here --- variable names src and dst
are quite confusing. It seems to mean that "we search with
'src' to fill 'dst', but if reverse incoming refspec is given
reversed so matching refspec->src with what in fact is 'dst' in
the configuration file is fine". Utterly confusing.
Even though this is a good opportunity for you to improve your
comment ratio in ohloh stats, I doubt any amount of explanation
can unconfuse readers of this code.
> if (!fetch->dst)
> continue;
>
> if (fetch->pattern) {
> + if (!prefixcmp(refspec->src, src)) {
> refspec->dst =
> + xmalloc(strlen(dst) +
> strlen(refspec->src) -
> + strlen(src) + 1);
> + strcpy(refspec->dst, dst);
> + strcpy(refspec->dst + strlen(dst),
> + refspec->src + strlen(src));
> refspec->force = fetch->force;
> return 0;
> }
> } else {
> + if (!strcmp(refspec->src, src)) {
> + refspec->dst = xstrdup(dst);
> refspec->force = fetch->force;
> return 0;
> }
> }
> }
> - refspec->dst = NULL;
> return -1;
> }
The original remote_find_tracking() took a single remote and a
refspec with src filled, and returned the given refspec after
filling its dst, if an appropriate tracking was configured for
the remote. What you want to do is from the same remote
information and a refspec with dst filled to find a src branch
that would be stored to that dst.
In either case, incoming refspec would not have both src and dst
filled. The caller has one side of the information and asking
for the other. As Daniel suggests, the 'reverse' parameter is
not needed. If you must have it, please do not call it
'reverse' -- it is more like "find_by_dst".
Following Daniel's suggestion might make the code a bit
lengthier, but I think that would not be as confusing.
> diff --git a/send-pack.c b/send-pack.c
> index fecbda9..9fdd7b4 100644
> --- a/send-pack.c
> +++ b/send-pack.c
> @@ -305,8 +305,7 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, cha
> if (remote) {
> struct refspec rs;
> rs.src = ref->name;
> - remote_find_tracking(remote, &rs);
> - if (rs.dst) {
> + if (!remote_find_tracking(remote, &rs, 0)) {
> struct ref_lock *lock;
> fprintf(stderr, " Also local %s\n", rs.dst);
> if (will_delete_ref) {
^ permalink raw reply
* [PATCH 2/2] Some cosmetic changes to remote library
From: Daniel Barkalow @ 2007-07-10 4:47 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Functions for managing ref lists were named based on their use in
match_refs (for push). For fetch, they will be used for other purposes, so
rename them as a separate patch to make the future code readable.
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
remote.c | 21 +++++++++++----------
1 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/remote.c b/remote.c
index ed39764..0b831c5 100644
--- a/remote.c
+++ b/remote.c
@@ -396,11 +396,12 @@ static int count_refspec_match(const char *pattern,
}
}
-static void link_dst_tail(struct ref *ref, struct ref ***tail)
+static void tail_link_ref(struct ref *ref, struct ref ***tail)
{
**tail = ref;
+ while (ref->next)
+ ref = ref->next;
*tail = &ref->next;
- **tail = NULL;
}
static struct ref *try_explicit_object_name(const char *name)
@@ -424,16 +425,16 @@ static struct ref *try_explicit_object_name(const char *name)
return ref;
}
-static struct ref *make_dst(const char *name, struct ref ***dst_tail)
+static struct ref *make_linked_ref(const char *name, struct ref ***tail)
{
- struct ref *dst;
+ struct ref *ret;
size_t len;
len = strlen(name) + 1;
- dst = alloc_ref(len);
- memcpy(dst->name, name, len);
- link_dst_tail(dst, dst_tail);
- return dst;
+ ret = alloc_ref(len);
+ memcpy(ret->name, name, len);
+ tail_link_ref(ret, tail);
+ return ret;
}
static int match_explicit(struct ref *src, struct ref *dst,
@@ -481,7 +482,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
break;
case 0:
if (!memcmp(dst_value, "refs/", 5))
- matched_dst = make_dst(dst_value, dst_tail);
+ matched_dst = make_linked_ref(dst_value, dst_tail);
else
error("dst refspec %s does not match any "
"existing ref on the remote and does "
@@ -584,7 +585,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
goto free_name;
if (!dst_peer) {
/* Create a new one and link it */
- dst_peer = make_dst(dst_name, dst_tail);
+ dst_peer = make_linked_ref(dst_name, dst_tail);
hashcpy(dst_peer->new_sha1, src->new_sha1);
}
dst_peer->peer_ref = src;
--
1.5.2.2.1399.g097d5-dirty
^ permalink raw reply related
* [PATCH 1/2] Add allocation and freeing functions for struct refs
From: Daniel Barkalow @ 2007-07-10 4:47 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Instead of open-coding allocation wherever it happens, have a function.
Also, add a function to free a list of refs, which we currently never
actually do.
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
connect.c | 2 +-
remote.c | 25 ++++++++++++++++++++++---
remote.h | 7 +++++++
3 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/connect.c b/connect.c
index 65e79ed..715cdc0 100644
--- a/connect.c
+++ b/connect.c
@@ -72,7 +72,7 @@ struct ref **get_remote_heads(int in, struct ref **list,
continue;
if (nr_match && !path_match(name, nr_match, match))
continue;
- ref = xcalloc(1, sizeof(*ref) + len - 40);
+ ref = alloc_ref(len - 40);
hashcpy(ref->old_sha1, old_sha1);
memcpy(ref->name, buffer + 41, len - 40);
*list = ref;
diff --git a/remote.c b/remote.c
index 500ca4d..ed39764 100644
--- a/remote.c
+++ b/remote.c
@@ -320,6 +320,25 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
return -1;
}
+struct ref *alloc_ref(unsigned namelen)
+{
+ struct ref *ret = xmalloc(sizeof(struct ref) + namelen);
+ memset(ret, 0, sizeof(struct ref) + namelen);
+ return ret;
+}
+
+void free_refs(struct ref *ref)
+{
+ struct ref *next;
+ while (ref) {
+ next = ref->next;
+ if (ref->peer_ref)
+ free(ref->peer_ref);
+ free(ref);
+ ref = next;
+ }
+}
+
static int count_refspec_match(const char *pattern,
struct ref *refs,
struct ref **matched_ref)
@@ -391,7 +410,7 @@ static struct ref *try_explicit_object_name(const char *name)
int len;
if (!*name) {
- ref = xcalloc(1, sizeof(*ref) + 20);
+ ref = alloc_ref(20);
strcpy(ref->name, "(delete)");
hashclr(ref->new_sha1);
return ref;
@@ -399,7 +418,7 @@ static struct ref *try_explicit_object_name(const char *name)
if (get_sha1(name, sha1))
return NULL;
len = strlen(name) + 1;
- ref = xcalloc(1, sizeof(*ref) + len);
+ ref = alloc_ref(len);
memcpy(ref->name, name, len);
hashcpy(ref->new_sha1, sha1);
return ref;
@@ -411,7 +430,7 @@ static struct ref *make_dst(const char *name, struct ref ***dst_tail)
size_t len;
len = strlen(name) + 1;
- dst = xcalloc(1, sizeof(*dst) + len);
+ dst = alloc_ref(len);
memcpy(dst->name, name, len);
link_dst_tail(dst, dst_tail);
return dst;
diff --git a/remote.h b/remote.h
index 01dbcef..080b7da 100644
--- a/remote.h
+++ b/remote.h
@@ -30,6 +30,13 @@ struct refspec {
char *dst;
};
+struct ref *alloc_ref(unsigned namelen);
+
+/*
+ * Frees the entire list and peers of elements.
+ */
+void free_refs(struct ref *ref);
+
int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
int nr_refspec, char **refspec, int all);
--
1.5.2.2.1399.g097d5-dirty
^ permalink raw reply related
* [PATCH v3] Make fetch-pack a builtin with an internal API
From: Daniel Barkalow @ 2007-07-10 4:38 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Rene Scharfe
In addition to making fetch-pack a builtin, this allows it to be called
directly from other built-in code without generating and parsing argument
lists, which will be useful for builtin-fetch.
Incidently, it makes git-fetch-pack not output lists of what it fetched
when it fails.
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
Okay, identifiers cleaned up and include guards normalized.
Makefile | 1 +
fetch-pack.c => builtin-fetch-pack.c | 84 +++++++++++++++++++++++++---------
builtin.h | 1 +
fetch-pack.h | 21 ++++++++
git.c | 1 +
5 files changed, 86 insertions(+), 22 deletions(-)
rename fetch-pack.c => builtin-fetch-pack.c (93%)
create mode 100644 fetch-pack.h
diff --git a/Makefile b/Makefile
index 4ea5e45..da750f8 100644
--- a/Makefile
+++ b/Makefile
@@ -342,6 +342,7 @@ BUILTIN_OBJS = \
builtin-diff-files.o \
builtin-diff-index.o \
builtin-diff-tree.o \
+ builtin-fetch-pack.o \
builtin-fetch--tool.o \
builtin-fmt-merge-msg.o \
builtin-for-each-ref.o \
diff --git a/fetch-pack.c b/builtin-fetch-pack.c
similarity index 93%
rename from fetch-pack.c
rename to builtin-fetch-pack.c
index 9c81305..3b217d9 100644
--- a/fetch-pack.c
+++ b/builtin-fetch-pack.c
@@ -6,6 +6,7 @@
#include "exec_cmd.h"
#include "pack.h"
#include "sideband.h"
+#include "fetch-pack.h"
static int keep_pack;
static int transfer_unpack_limit = -1;
@@ -573,7 +574,7 @@ static int get_pack(int xd[2])
die("%s died of unnatural causes %d", argv[0], status);
}
-static int fetch_pack(int fd[2], int nr_match, char **match)
+static struct ref *do_fetch_pack(int fd[2], int nr_match, char **match)
{
struct ref *ref;
unsigned char sha1[20];
@@ -615,12 +616,7 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
die("git-fetch-pack: fetch failed.");
all_done:
- while (ref) {
- printf("%s %s\n",
- sha1_to_hex(ref->old_sha1), ref->name);
- ref = ref->next;
- }
- return 0;
+ return ref;
}
static int remove_duplicates(int nr_heads, char **heads)
@@ -663,15 +659,28 @@ static int fetch_pack_config(const char *var, const char *value)
static struct lock_file lock;
-int main(int argc, char **argv)
+void setup_fetch_pack(struct fetch_pack_args *args)
+{
+ uploadpack = args->uploadpack;
+ quiet = args->quiet;
+ keep_pack = args->keep_pack;
+ if (args->unpacklimit >= 0)
+ unpack_limit = args->unpacklimit;
+ if (args->keep_pack)
+ unpack_limit = 0;
+ use_thin_pack = args->use_thin_pack;
+ fetch_all = args->fetch_all;
+ verbose = args->verbose;
+ depth = args->depth;
+ no_progress = args->no_progress;
+}
+
+int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
{
int i, ret, nr_heads;
+ struct ref *ref;
char *dest = NULL, **heads;
- int fd[2];
- pid_t pid;
- struct stat st;
- setup_git_directory();
git_config(fetch_pack_config);
if (0 <= transfer_unpack_limit)
@@ -682,7 +691,7 @@ int main(int argc, char **argv)
nr_heads = 0;
heads = NULL;
for (i = 1; i < argc; i++) {
- char *arg = argv[i];
+ const char *arg = argv[i];
if (*arg == '-') {
if (!prefixcmp(arg, "--upload-pack=")) {
@@ -716,8 +725,6 @@ int main(int argc, char **argv)
}
if (!prefixcmp(arg, "--depth=")) {
depth = strtol(arg + 8, NULL, 0);
- if (stat(git_path("shallow"), &st))
- st.st_mtime = 0;
continue;
}
if (!strcmp("--no-progress", arg)) {
@@ -726,22 +733,52 @@ int main(int argc, char **argv)
}
usage(fetch_pack_usage);
}
- dest = arg;
- heads = argv + i + 1;
+ dest = (char *)arg;
+ heads = (char **)(argv + i + 1);
nr_heads = argc - i - 1;
break;
}
if (!dest)
usage(fetch_pack_usage);
- pid = git_connect(fd, dest, uploadpack, verbose ? CONNECT_VERBOSE : 0);
+
+ ref = fetch_pack(dest, nr_heads, heads);
+
+ ret = !ref;
+
+ while (ref) {
+ printf("%s %s\n",
+ sha1_to_hex(ref->old_sha1), ref->name);
+ ref = ref->next;
+ }
+
+ return ret;
+}
+
+struct ref *fetch_pack(const char *dest, int nr_heads, char **heads)
+{
+ int i, ret;
+ int fd[2];
+ pid_t pid;
+ struct ref *ref;
+ struct stat st;
+
+ if (depth > 0) {
+ if (stat(git_path("shallow"), &st))
+ st.st_mtime = 0;
+ }
+
+ printf("connect to %s\n", dest);
+
+ pid = git_connect(fd, (char *)dest, uploadpack,
+ verbose ? CONNECT_VERBOSE : 0);
if (pid < 0)
- return 1;
+ return NULL;
if (heads && nr_heads)
nr_heads = remove_duplicates(nr_heads, heads);
- ret = fetch_pack(fd, nr_heads, heads);
+ ref = do_fetch_pack(fd, nr_heads, heads);
close(fd[0]);
close(fd[1]);
- ret |= finish_connect(pid);
+ ret = finish_connect(pid);
if (!ret && nr_heads) {
/* If the heads to pull were given, we should have
@@ -785,5 +822,8 @@ int main(int argc, char **argv)
}
}
- return !!ret;
+ if (ret)
+ ref = NULL;
+
+ return ref;
}
diff --git a/builtin.h b/builtin.h
index 661a92f..8fa38d4 100644
--- a/builtin.h
+++ b/builtin.h
@@ -31,6 +31,7 @@ extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
extern int cmd_diff(int argc, const char **argv, const char *prefix);
extern int cmd_diff_tree(int argc, const char **argv, const char *prefix);
+extern int cmd_fetch_pack(int argc, const char **argv, const char *prefix);
extern int cmd_fetch__tool(int argc, const char **argv, const char *prefix);
extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
extern int cmd_for_each_ref(int argc, const char **argv, const char *prefix);
diff --git a/fetch-pack.h b/fetch-pack.h
new file mode 100644
index 0000000..e06bf5b
--- /dev/null
+++ b/fetch-pack.h
@@ -0,0 +1,21 @@
+#ifndef FETCH_PACK_H
+#define FETCH_PACK_H
+
+struct fetch_pack_args
+{
+ const char *uploadpack;
+ int quiet;
+ int keep_pack;
+ int unpacklimit;
+ int use_thin_pack;
+ int fetch_all;
+ int verbose;
+ int depth;
+ int no_progress;
+};
+
+void setup_fetch_pack(struct fetch_pack_args *args);
+
+struct ref *fetch_pack(const char *dest, int nr_heads, char **heads);
+
+#endif
diff --git a/git.c b/git.c
index b949cbb..df45161 100644
--- a/git.c
+++ b/git.c
@@ -307,6 +307,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "diff-files", cmd_diff_files },
{ "diff-index", cmd_diff_index, RUN_SETUP },
{ "diff-tree", cmd_diff_tree, RUN_SETUP },
+ { "fetch-pack", cmd_fetch_pack, RUN_SETUP },
{ "fetch--tool", cmd_fetch__tool, RUN_SETUP },
{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
{ "for-each-ref", cmd_for_each_ref, RUN_SETUP },
--
1.5.2.2.1399.g097d5-dirty
^ permalink raw reply related
* Re: [PATCH] Support wholesale directory renames in fast-import
From: David Frech @ 2007-07-10 4:16 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: git
In-Reply-To: <20070710031036.GA9045@spearce.org>
This should do nicely! Thank you!
Now my challenge is that the svn dump doesn't *actually* say "rename
a/ to b/"; it says "copy a/ to b/; delete a/", so I have to infer the
rename.
But your patch makes my import possible, and it wasn't before!
Cheers,
- David
On 7/9/07, Shawn O. Pearce <spearce@spearce.org> wrote:
> Some source material (e.g. Subversion dump files) perform directory
> renames without telling us exactly which files in that subdirectory
> were moved. This makes it hard for a frontend to convert such data
> formats to a fast-import stream, as all the frontend has on hand
> is "Rename a/ to b/" with no details about what files are in a/,
> unless the frontend also kept track of all files.
>
> The new 'R' subcommand within a commit allows the frontend to
> rename either a file or an entire subdirectory, without needing to
> know the object's SHA-1 or the specific files contained within it.
> The rename is performed as efficiently as possible internally,
> making it cheaper than a 'D'/'M' pair for a file rename.
>
> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
> ---
>
> David Frech <david@nimblemachines.com> wrote:
> > Git can track file renames implicitly. If I delete and then add (under
> > a different name) the same content, git will figure that out.
> >
> > But if a directory was renamed, I have no way to tell fast-import
> > about it. I can't delete the directory (using a 'D' command) and then
> > add it back (with a different name) with all its contents, because my
> > source material (an svn dump file) doesn't tell me, at that point,
> > about all the files involved because nothing about them has changed.
> >
> > fast-import knows about the contents of the directory I want to
> > rename, but doesn't give me a primitive to do the rename. Is this
> > something we need to add? My frontend could keep track of this, but I
> > would duplicating work that fast-import is already doing.
>
> Does the following do the trick for you? It is also available
> from my fastimport.git master branch:
>
> git://repo.or.cz/git/fastimport.git master
> http://repo.or.cz/r/git/fastimport.git master
>
> Yes, it passes all tests...
>
[patch elided]
^ permalink raw reply
* Re: [PATCH 1/2] Add for_each_remote() function, and extend remote_find_tracking()
From: Daniel Barkalow @ 2007-07-10 3:55 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Junio C Hamano, Paolo Bonzini, git
In-Reply-To: <Pine.LNX.4.64.0707100401070.4131@racer.site>
On Tue, 10 Jul 2007, Johannes Schindelin wrote:
> The function for_each_remote() does exactly what the name suggests.
>
> The function remote_find_tracking() was extended to be able to search
> remote refs for a given local ref. You have to set the parameter
> "reverse" to true for that behavior.
I think I'd like this better if reverse meant that it looked at
refspec->dst and set refspec->src, rather than returning the refspec
reversed; the current version sets the refspec so that it's effectively
something from the list, which makes it easier to understand.
Maybe make it so the user calls it with at most one of src and dst NULL,
and it returns with neither NULL or returns -1 if it can't find anything?
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* [PATCH 2/2] branch --track: code cleanup and saner handling of local branches
From: Johannes Schindelin @ 2007-07-10 3:05 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Paolo Bonzini, git, Daniel Barkalow
In-Reply-To: <7vzm25tex6.fsf@assigned-by-dhcp.cox.net>
This patch cleans up some complicated code, and replaces it with a
cleaner version, using code from remote.[ch], which got extended a
little in the process. This also enables us to fix two cases:
The earlier "fix" to setup tracking only when the original ref started
with "refs/remotes" is wrong. You are absolutely allowed to use a
separate layout for your tracking branches. The correct fix, of course,
is to set up tracking information only when there is a matching
remote.<nick>.fetch line containing a colon.
Another corner case was not handled properly. If two remotes write to
the original ref, just warn the user and do not set up tracking.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
... and again I was bitten by the minimality of the script. The
original diff was _unreadable_, because it matched some empty
lines here and there, or some lonely curly brackets.
Therefore I manually tweaked it to show first the cruft that was
removed, and then the rewrite using remote.[ch]. As a consequence,
the diffstat is not the one of this patch, but the one "git show
--stat" showed.
builtin-branch.c | 167 ++++++++++++++++------------------------------------
t/t3200-branch.sh | 21 ++++---
2 files changed, 63 insertions(+), 125 deletions(-)
diff --git a/builtin-branch.c b/builtin-branch.c
index 49195a1..0dbd6d7 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -10,6 +10,7 @@
#include "refs.h"
#include "commit.h"
#include "builtin.h"
+#include "remote.h"
static const char builtin_branch_usage[] =
"git-branch [-r] (-d | -D) <branchname> | [--track | --no-track] [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]] [--sort-by-date]";
@@ -22,7 +23,7 @@ static const char builtin_branch_usage[] =
static const char *head;
static unsigned char head_sha1[20];
-static int branch_track = 1; /* 0 = none, 1 = remotes, 2 = all */
+static int branch_track = 1;
static int branch_use_color;
static char branch_colors[][COLOR_MAXLEN] = {
@@ -66,12 +67,8 @@ static int git_branch_config(const char *var, const char *value)
color_parse(value, var, branch_colors[slot]);
return 0;
}
- if (!strcmp(var, "branch.autosetupmerge")) {
- if (!strcmp(value, "all"))
- branch_track = 2;
- else
+ if (!strcmp(var, "branch.autosetupmerge"))
branch_track = git_config_bool(var, value);
- }
return git_default_config(var, value);
}
@@ -349,125 +346,67 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev,
free_ref_list(&ref_list);
}
-static char *config_repo;
-static char *config_remote;
-static const char *start_ref;
-
-static int get_remote_branch_name(const char *value)
-{
- const char *colon;
- const char *end;
-
- if (*value == '+')
- value++;
-
- colon = strchr(value, ':');
- if (!colon)
- return 0;
-
- end = value + strlen(value);
-
- /*
- * Try an exact match first. I.e. handle the case where the
- * value is "$anything:refs/foo/bar/baz" and start_ref is exactly
- * "refs/foo/bar/baz". Then the name at the remote is $anything.
- */
- if (!strcmp(colon + 1, start_ref)) {
- /* Truncate the value before the colon. */
- nfasprintf(&config_repo, "%.*s", colon - value, value);
- return 1;
- }
-
- /*
- * Is this a wildcard match?
- */
- if ((end - 2 <= value) || end[-2] != '/' || end[-1] != '*' ||
- (colon - 2 <= value) || colon[-2] != '/' || colon[-1] != '*')
- return 0;
-
- /*
- * Value is "refs/foo/bar/<asterisk>:refs/baz/boa/<asterisk>"
- * and start_ref begins with "refs/baz/boa/"; the name at the
- * remote is refs/foo/bar/ with the remaining part of the
- * start_ref. The length of the prefix on the RHS is (end -
- * colon - 2), including the slash immediately before the
- * asterisk.
- */
- if ((strlen(start_ref) < end - colon - 2) ||
- memcmp(start_ref, colon + 1, end - colon - 2))
- return 0; /* does not match prefix */
-
- /* Replace the asterisk with the remote branch name. */
- nfasprintf(&config_repo, "%.*s%s",
- (colon - 1) - value, value,
- start_ref + (end - colon - 2));
- return 1;
-}
-
-static int get_remote_config(const char *key, const char *value)
-{
- const char *var;
- if (prefixcmp(key, "remote."))
- return 0;
-
- var = strrchr(key, '.');
- if (var == key + 6 || strcmp(var, ".fetch"))
- return 0;
- /*
- * Ok, we are looking at key == "remote.$foo.fetch";
- */
- if (get_remote_branch_name(value))
- nfasprintf(&config_remote, "%.*s", var - (key + 7), key + 7);
-
- return 0;
-}
-
-static void set_branch_merge(const char *name, const char *config_remote,
- const char *config_repo)
-{
- char key[1024];
- if (sizeof(key) <=
- snprintf(key, sizeof(key), "branch.%s.remote", name))
- die("what a long branch name you have!");
- git_config_set(key, config_remote);
-
- /*
- * We do not have to check if we have enough space for
- * the 'merge' key, since it's shorter than the
- * previous 'remote' key, which we already checked.
- */
- snprintf(key, sizeof(key), "branch.%s.merge", name);
- git_config_set(key, config_repo);
-}
-
-static void set_branch_defaults(const char *name, const char *real_ref)
-{
- /*
- * name is the name of new branch under refs/heads;
- * real_ref is typically refs/remotes/$foo/$bar, where
- * $foo is the remote name (there typically are no slashes)
- * and $bar is the branch name we map from the remote
- * (it could have slashes).
- */
- start_ref = real_ref;
- git_config(get_remote_config);
- if (!config_repo && !config_remote &&
- !prefixcmp(real_ref, "refs/heads/")) {
- set_branch_merge(name, ".", real_ref);
- printf("Branch %s set up to track local branch %s.\n",
- name, real_ref);
- }
-
- if (config_repo && config_remote) {
- set_branch_merge(name, config_remote, config_repo);
- printf("Branch %s set up to track remote branch %s.\n",
- name, real_ref);
- }
-
- if (config_repo)
- free(config_repo);
- if (config_remote)
- free(config_remote);
+struct tracking {
+ struct refspec spec;
+ char *dst;
+ const char *remote;
+ int matches;
+};
+
+static int find_tracked_branch(struct remote *remote, void *priv)
+{
+ struct tracking *tracking = priv;
+
+ if (!remote_find_tracking(remote, &tracking->spec, 1)) {
+ if (++tracking->matches == 1) {
+ tracking->dst = tracking->spec.dst;
+ tracking->remote = remote->name;
+ } else {
+ free(tracking->spec.dst);
+ free(tracking->dst);
+ tracking->dst = NULL;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * This is called when new_ref is branched off of orig_ref, and tries
+ * to infer the settings for branch.<new_ref>.{remote,merge} from the
+ * config.
+ */
+static int setup_tracking(const char *new_ref, const char *orig_ref)
+{
+ char key[1024];
+ struct tracking tracking;
+
+ if (strlen(new_ref) > 1024 - 7 - 7 - 1)
+ return error("Tracking not set up: name too long: %s",
+ new_ref);
+
+ memset(&tracking, 0, sizeof(tracking));
+ tracking.spec.src = orig_ref;
+ if (for_each_remote(find_tracked_branch, &tracking) ||
+ !tracking.matches)
+ return 1;
+
+ if (tracking.matches > 1)
+ return error("Not tracking: ambiguous information for ref %s",
+ orig_ref);
+
+ if (tracking.matches == 1) {
+ sprintf(key, "branch.%s.remote", new_ref);
+ git_config_set(key, tracking.remote ? tracking.remote : ".");
+ sprintf(key, "branch.%s.merge", new_ref);
+ git_config_set(key, tracking.dst);
+ free(tracking.dst);
+ printf("Branch %s set up to track remote branch %s.\n",
+ new_ref, orig_ref);
+ }
+
+ return 0;
}
static void create_branch(const char *name, const char *start_name,
@@ -529,10 +468,8 @@ static void create_branch(const char *name, const char *start_name,
/* When branching off a remote branch, set up so that git-pull
automatically merges from there. So far, this is only done for
remotes registered via .git/config. */
- if (real_ref && (track == 2 ||
- (track == 1 &&
- !prefixcmp(real_ref, "refs/remotes/"))))
- set_branch_defaults(name, real_ref);
+ if (real_ref && track)
+ setup_tracking(name, real_ref);
if (write_ref_sha1(lock, sha1, msg) < 0)
die("Failed to write ref: %s.", strerror(errno));
@@ -604,7 +541,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
break;
}
if (!strcmp(arg, "--track")) {
- track = 2;
+ track = 1;
continue;
}
if (!strcmp(arg, "--no-track")) {
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index a19e961..ef1eeb7 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -148,13 +148,14 @@ test_expect_success 'test tracking setup via config' \
test $(git config branch.my3.remote) = local &&
test $(git config branch.my3.merge) = refs/heads/master'
-test_expect_success 'autosetupmerge = all' '
+test_expect_success 'avoid ambiguous track' '
git config branch.autosetupmerge true &&
+ git config remote.ambi1.url = lalala &&
+ git config remote.ambi1.fetch = refs/heads/lalala:refs/heads/master &&
+ git config remote.ambi2.url = lilili &&
+ git config remote.ambi2.fetch = refs/heads/lilili:refs/heads/master &&
git branch all1 master &&
- test -z "$(git config branch.all1.merge)" &&
- git config branch.autosetupmerge all &&
- git branch all2 master &&
- test $(git config branch.all2.merge) = refs/heads/master
+ test -z "$(git config branch.all1.merge)"
'
test_expect_success 'test overriding tracking setup via --no-track' \
@@ -167,10 +168,10 @@ test_expect_success 'test overriding tracking setup via --no-track' \
! test "$(git config branch.my2.remote)" = local &&
! test "$(git config branch.my2.merge)" = refs/heads/master'
-test_expect_success 'test local tracking setup' \
+test_expect_success 'no tracking without .fetch entries' \
'git branch --track my6 s &&
- test $(git config branch.my6.remote) = . &&
- test $(git config branch.my6.merge) = refs/heads/s'
+ test -z "$(git config branch.my6.remote)" &&
+ test -z "$(git config branch.my6.merge)"'
test_expect_success 'test tracking setup via --track but deeper' \
'git config remote.local.url . &&
@@ -182,8 +183,8 @@ test_expect_success 'test tracking setup via --track but deeper' \
test_expect_success 'test deleting branch deletes branch config' \
'git branch -d my7 &&
- test "$(git config branch.my7.remote)" = "" &&
- test "$(git config branch.my7.merge)" = ""'
+ test -z "$(git config branch.my7.remote)" &&
+ test -z "$(git config branch.my7.merge)"'
test_expect_success 'test deleting branch without config' \
'git branch my7 s &&
--
1.5.3.rc0.2769.gd9be2
^ permalink raw reply related
* [PATCH] Support wholesale directory renames in fast-import
From: Shawn O. Pearce @ 2007-07-10 3:10 UTC (permalink / raw)
To: David Frech; +Cc: git
In-Reply-To: <7154c5c60707091809y7e0b67d5u3f94658b7e814325@mail.gmail.com>
Some source material (e.g. Subversion dump files) perform directory
renames without telling us exactly which files in that subdirectory
were moved. This makes it hard for a frontend to convert such data
formats to a fast-import stream, as all the frontend has on hand
is "Rename a/ to b/" with no details about what files are in a/,
unless the frontend also kept track of all files.
The new 'R' subcommand within a commit allows the frontend to
rename either a file or an entire subdirectory, without needing to
know the object's SHA-1 or the specific files contained within it.
The rename is performed as efficiently as possible internally,
making it cheaper than a 'D'/'M' pair for a file rename.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
David Frech <david@nimblemachines.com> wrote:
> Git can track file renames implicitly. If I delete and then add (under
> a different name) the same content, git will figure that out.
>
> But if a directory was renamed, I have no way to tell fast-import
> about it. I can't delete the directory (using a 'D' command) and then
> add it back (with a different name) with all its contents, because my
> source material (an svn dump file) doesn't tell me, at that point,
> about all the files involved because nothing about them has changed.
>
> fast-import knows about the contents of the directory I want to
> rename, but doesn't give me a primitive to do the rename. Is this
> something we need to add? My frontend could keep track of this, but I
> would duplicating work that fast-import is already doing.
Does the following do the trick for you? It is also available
from my fastimport.git master branch:
git://repo.or.cz/git/fastimport.git master
http://repo.or.cz/r/git/fastimport.git master
Yes, it passes all tests...
Documentation/git-fast-import.txt | 28 ++++++++++-
fast-import.c | 91 ++++++++++++++++++++++++++++++-------
t/t9300-fast-import.sh | 68 +++++++++++++++++++++++++++
3 files changed, 168 insertions(+), 19 deletions(-)
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index c66af7c..80a8ee0 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -302,7 +302,7 @@ change to the project.
data
('from' SP <committish> LF)?
('merge' SP <committish> LF)?
- (filemodify | filedelete | filedeleteall)*
+ (filemodify | filedelete | filerename | filedeleteall)*
LF
....
@@ -325,11 +325,13 @@ commit message use a 0 length data. Commit messages are free-form
and are not interpreted by Git. Currently they must be encoded in
UTF-8, as fast-import does not permit other encodings to be specified.
-Zero or more `filemodify`, `filedelete` and `filedeleteall` commands
+Zero or more `filemodify`, `filedelete`, `filename` and
+`filedeleteall` commands
may be included to update the contents of the branch prior to
creating the commit. These commands may be supplied in any order.
However it is recommended that a `filedeleteall` command preceed
-all `filemodify` commands in the same commit, as `filedeleteall`
+all `filemodify` and `filerename` commands in the same commit, as
+`filedeleteall`
wipes the branch clean (see below).
`author`
@@ -495,6 +497,26 @@ here `<path>` is the complete path of the file or subdirectory to
be removed from the branch.
See `filemodify` above for a detailed description of `<path>`.
+`filerename`
+^^^^^^^^^^^^
+Renames an existing file or subdirectory to a different location
+within the branch. The existing file or directory must exist. If
+the destination exists it will be replaced by the source directory.
+
+....
+ 'R' SP <path> SP <path> LF
+....
+
+here the first `<path>` is the source location and the second
+`<path>` is the destination. See `filemodify` above for a detailed
+description of what `<path>` may look like. To use a source path
+that contains SP the path must be quoted.
+
+A `filerename` command takes effect immediately. Once the source
+location has been renamed to the destination any future commands
+applied to the source location will create new files there and not
+impact the destination of the rename.
+
`filedeleteall`
^^^^^^^^^^^^^^^
Included in a `commit` command to remove all files (and also all
diff --git a/fast-import.c b/fast-import.c
index f9bfcc7..a1cb13f 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -26,9 +26,10 @@ Format of STDIN stream:
lf;
commit_msg ::= data;
- file_change ::= file_clr | file_del | file_obm | file_inm;
+ file_change ::= file_clr | file_del | file_rnm | file_obm | file_inm;
file_clr ::= 'deleteall' lf;
file_del ::= 'D' sp path_str lf;
+ file_rnm ::= 'R' sp path_str sp path_str lf;
file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
data;
@@ -1154,7 +1155,8 @@ static int tree_content_set(
struct tree_entry *root,
const char *p,
const unsigned char *sha1,
- const uint16_t mode)
+ const uint16_t mode,
+ struct tree_content *subtree)
{
struct tree_content *t = root->tree;
const char *slash1;
@@ -1168,20 +1170,22 @@ static int tree_content_set(
n = strlen(p);
if (!n)
die("Empty path component found in input");
+ if (!slash1 && !S_ISDIR(mode) && subtree)
+ die("Non-directories cannot have subtrees");
for (i = 0; i < t->entry_count; i++) {
e = t->entries[i];
if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
if (!slash1) {
- if (e->versions[1].mode == mode
+ if (!S_ISDIR(mode)
+ && e->versions[1].mode == mode
&& !hashcmp(e->versions[1].sha1, sha1))
return 0;
e->versions[1].mode = mode;
hashcpy(e->versions[1].sha1, sha1);
- if (e->tree) {
+ if (e->tree)
release_tree_content_recursive(e->tree);
- e->tree = NULL;
- }
+ e->tree = subtree;
hashclr(root->versions[1].sha1);
return 1;
}
@@ -1191,7 +1195,7 @@ static int tree_content_set(
}
if (!e->tree)
load_tree(e);
- if (tree_content_set(e, slash1 + 1, sha1, mode)) {
+ if (tree_content_set(e, slash1 + 1, sha1, mode, subtree)) {
hashclr(root->versions[1].sha1);
return 1;
}
@@ -1209,9 +1213,9 @@ static int tree_content_set(
if (slash1) {
e->tree = new_tree_content(8);
e->versions[1].mode = S_IFDIR;
- tree_content_set(e, slash1 + 1, sha1, mode);
+ tree_content_set(e, slash1 + 1, sha1, mode, subtree);
} else {
- e->tree = NULL;
+ e->tree = subtree;
e->versions[1].mode = mode;
hashcpy(e->versions[1].sha1, sha1);
}
@@ -1219,7 +1223,10 @@ static int tree_content_set(
return 1;
}
-static int tree_content_remove(struct tree_entry *root, const char *p)
+static int tree_content_remove(
+ struct tree_entry *root,
+ const char *p,
+ struct tree_entry *backup_leaf)
{
struct tree_content *t = root->tree;
const char *slash1;
@@ -1239,13 +1246,14 @@ static int tree_content_remove(struct tree_entry *root, const char *p)
goto del_entry;
if (!e->tree)
load_tree(e);
- if (tree_content_remove(e, slash1 + 1)) {
+ if (tree_content_remove(e, slash1 + 1, backup_leaf)) {
for (n = 0; n < e->tree->entry_count; n++) {
if (e->tree->entries[n]->versions[1].mode) {
hashclr(root->versions[1].sha1);
return 1;
}
}
+ backup_leaf = NULL;
goto del_entry;
}
return 0;
@@ -1254,10 +1262,11 @@ static int tree_content_remove(struct tree_entry *root, const char *p)
return 0;
del_entry:
- if (e->tree) {
+ if (backup_leaf)
+ memcpy(backup_leaf, e, sizeof(*backup_leaf));
+ else if (e->tree)
release_tree_content_recursive(e->tree);
- e->tree = NULL;
- }
+ e->tree = NULL;
e->versions[1].mode = 0;
hashclr(e->versions[1].sha1);
hashclr(root->versions[1].sha1);
@@ -1629,7 +1638,7 @@ static void file_change_m(struct branch *b)
typename(type), command_buf.buf);
}
- tree_content_set(&b->branch_tree, p, sha1, S_IFREG | mode);
+ tree_content_set(&b->branch_tree, p, sha1, S_IFREG | mode, NULL);
free(p_uq);
}
@@ -1645,10 +1654,58 @@ static void file_change_d(struct branch *b)
die("Garbage after path in: %s", command_buf.buf);
p = p_uq;
}
- tree_content_remove(&b->branch_tree, p);
+ tree_content_remove(&b->branch_tree, p, NULL);
free(p_uq);
}
+static void file_change_r(struct branch *b)
+{
+ const char *s, *d;
+ char *s_uq, *d_uq;
+ const char *endp;
+ struct tree_entry leaf;
+
+ s = command_buf.buf + 2;
+ s_uq = unquote_c_style(s, &endp);
+ if (s_uq) {
+ if (*endp != ' ')
+ die("Missing space after source: %s", command_buf.buf);
+ }
+ else {
+ endp = strchr(s, ' ');
+ if (!endp)
+ die("Missing space after source: %s", command_buf.buf);
+ s_uq = xmalloc(endp - s + 1);
+ memcpy(s_uq, s, endp - s);
+ s_uq[endp - s] = 0;
+ }
+ s = s_uq;
+
+ endp++;
+ if (!*endp)
+ die("Missing dest: %s", command_buf.buf);
+
+ d = endp;
+ d_uq = unquote_c_style(d, &endp);
+ if (d_uq) {
+ if (*endp)
+ die("Garbage after dest in: %s", command_buf.buf);
+ d = d_uq;
+ }
+
+ memset(&leaf, 0, sizeof(leaf));
+ tree_content_remove(&b->branch_tree, s, &leaf);
+ if (!leaf.versions[1].mode)
+ die("Path %s not in branch", s);
+ tree_content_set(&b->branch_tree, d,
+ leaf.versions[1].sha1,
+ leaf.versions[1].mode,
+ leaf.tree);
+
+ free(s_uq);
+ free(d_uq);
+}
+
static void file_change_deleteall(struct branch *b)
{
release_tree_content_recursive(b->branch_tree.tree);
@@ -1816,6 +1873,8 @@ static void cmd_new_commit(void)
file_change_m(b);
else if (!prefixcmp(command_buf.buf, "D "))
file_change_d(b);
+ else if (!prefixcmp(command_buf.buf, "R "))
+ file_change_r(b);
else if (!strcmp("deleteall", command_buf.buf))
file_change_deleteall(b);
else
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 53774c8..bf3720d 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -580,4 +580,72 @@ test_expect_success \
git diff --raw L^ L >output &&
git diff expect output'
+###
+### series M
+###
+
+test_tick
+cat >input <<INPUT_END
+commit refs/heads/M1
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+file rename
+COMMIT
+
+from refs/heads/branch^0
+R file2/newf file2/n.e.w.f
+
+INPUT_END
+
+cat >expect <<EOF
+:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 file2/newf file2/n.e.w.f
+EOF
+test_expect_success \
+ 'M: rename file in same subdirectory' \
+ 'git-fast-import <input &&
+ git diff-tree -M -r M1^ M1 >actual &&
+ compare_diff_raw expect actual'
+
+cat >input <<INPUT_END
+commit refs/heads/M2
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+file rename
+COMMIT
+
+from refs/heads/branch^0
+R file2/newf i/am/new/to/you
+
+INPUT_END
+
+cat >expect <<EOF
+:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 file2/newf i/am/new/to/you
+EOF
+test_expect_success \
+ 'M: rename file to new subdirectory' \
+ 'git-fast-import <input &&
+ git diff-tree -M -r M2^ M2 >actual &&
+ compare_diff_raw expect actual'
+
+cat >input <<INPUT_END
+commit refs/heads/M3
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+file rename
+COMMIT
+
+from refs/heads/M2^0
+R i other/sub
+
+INPUT_END
+
+cat >expect <<EOF
+:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100 i/am/new/to/you other/sub/am/new/to/you
+EOF
+test_expect_success \
+ 'M: rename subdirectory to new subdirectory' \
+ 'git-fast-import <input &&
+ git diff-tree -M -r M3^ M3 >actual &&
+ compare_diff_raw expect actual'
+
test_done
--
1.5.3.rc0.879.g64b8
^ permalink raw reply related
* [PATCH 1/2] Add for_each_remote() function, and extend remote_find_tracking()
From: Johannes Schindelin @ 2007-07-10 3:02 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Paolo Bonzini, git, Daniel Barkalow
In-Reply-To: <7vzm25tex6.fsf@assigned-by-dhcp.cox.net>
The function for_each_remote() does exactly what the name suggests.
The function remote_find_tracking() was extended to be able to search
remote refs for a given local ref. You have to set the parameter
"reverse" to true for that behavior.
Both changes are required for the next step: simplification of
git-branch's --track functionality.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
You're right. I completely missed that functionality. Well, a
few tweaks were needed. If this clashes too seriously with
Daniel's work, I will gladly redo it after his changes are
in "next".
remote.c | 42 ++++++++++++++++++++++++++++++++----------
remote.h | 7 ++++++-
send-pack.c | 3 +--
3 files changed, 39 insertions(+), 13 deletions(-)
diff --git a/remote.c b/remote.c
index cf98a44..21adb0d 100644
--- a/remote.c
+++ b/remote.c
@@ -279,6 +279,26 @@ struct remote *remote_get(const char *name)
return ret;
}
+int for_each_remote(each_remote_fn fn, void *priv)
+{
+ int i, result = 0;
+ read_config();
+ for (i = 0; i < allocated_remotes; i++) {
+ struct remote *r = remotes[i];
+ if (!r)
+ continue;
+ if (!r->fetch)
+ r->fetch = parse_ref_spec(r->fetch_refspec_nr,
+ r->fetch_refspec);
+ if (!r->push)
+ r->push = parse_ref_spec(r->push_refspec_nr,
+ r->push_refspec);
+ if ((result = fn(r, priv)))
+ break;
+ }
+ return result;
+}
+
int remote_has_uri(struct remote *remote, const char *uri)
{
int i;
@@ -289,34 +309,36 @@ int remote_has_uri(struct remote *remote, const char *uri)
return 0;
}
-int remote_find_tracking(struct remote *remote, struct refspec *refspec)
+int remote_find_tracking(struct remote *remote, struct refspec *refspec,
+ int reverse)
{
int i;
for (i = 0; i < remote->fetch_refspec_nr; i++) {
struct refspec *fetch = &remote->fetch[i];
+ const char *src = reverse ? fetch->dst : fetch->src;
+ const char *dst = reverse ? fetch->src : fetch->dst;
if (!fetch->dst)
continue;
if (fetch->pattern) {
- if (!prefixcmp(refspec->src, fetch->src)) {
+ if (!prefixcmp(refspec->src, src)) {
refspec->dst =
- xmalloc(strlen(fetch->dst) +
+ xmalloc(strlen(dst) +
strlen(refspec->src) -
- strlen(fetch->src) + 1);
- strcpy(refspec->dst, fetch->dst);
- strcpy(refspec->dst + strlen(fetch->dst),
- refspec->src + strlen(fetch->src));
+ strlen(src) + 1);
+ strcpy(refspec->dst, dst);
+ strcpy(refspec->dst + strlen(dst),
+ refspec->src + strlen(src));
refspec->force = fetch->force;
return 0;
}
} else {
- if (!strcmp(refspec->src, fetch->src)) {
- refspec->dst = xstrdup(fetch->dst);
+ if (!strcmp(refspec->src, src)) {
+ refspec->dst = xstrdup(dst);
refspec->force = fetch->force;
return 0;
}
}
}
- refspec->dst = NULL;
return -1;
}
diff --git a/remote.h b/remote.h
index 01dbcef..9ab7eb6 100644
--- a/remote.h
+++ b/remote.h
@@ -20,6 +20,9 @@ struct remote {
struct remote *remote_get(const char *name);
+typedef int each_remote_fn(struct remote *remote, void *priv);
+int for_each_remote(each_remote_fn fn, void *priv);
+
int remote_has_uri(struct remote *remote, const char *uri);
struct refspec {
@@ -35,7 +38,9 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
/*
* For the given remote, reads the refspec's src and sets the other fields.
+ * If reverse is 1, the given src is the local ref, and we want the remote.
*/
-int remote_find_tracking(struct remote *remote, struct refspec *refspec);
+int remote_find_tracking(struct remote *remote, struct refspec *refspec,
+ int reverse);
#endif
diff --git a/send-pack.c b/send-pack.c
index fecbda9..9fdd7b4 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -305,8 +305,7 @@ static int send_pack(int in, int out, struct remote *remote, int nr_refspec, cha
if (remote) {
struct refspec rs;
rs.src = ref->name;
- remote_find_tracking(remote, &rs);
- if (rs.dst) {
+ if (!remote_find_tracking(remote, &rs, 0)) {
struct ref_lock *lock;
fprintf(stderr, " Also local %s\n", rs.dst);
if (will_delete_ref) {
--
1.5.3.rc0.2769.gd9be2
^ permalink raw reply related
* Re: how to combine two clones in a collection
From: Linus Torvalds @ 2007-07-10 2:35 UTC (permalink / raw)
To: martin f krafft; +Cc: git discussion list
In-Reply-To: <20070709222250.GA8007@piper.oerlikon.madduck.net>
On Tue, 10 Jul 2007, martin f krafft wrote:
>
> I am now ready to move to using git for most of my everyday work,
> but I am still unsure how to tackle one specific aspect of it, for
> which I used svn:externals in the past. I know about git
> subprojects, but these aren't what I want, really.
I really _think_ that what you want is to just use separate branches, if I
understand correctly. That makes it really easy to just have both lines of
development (both the "trunk" and your "debian" one) in one git
repository.
Of course, especially if you want to continue to work the way you probably
worked with SVN (ie you are used to seeing those two branches as two
separate directories), that means that while you can (and should) see it
as a single git project, you'd normally end up just having two copies of
that project: they'd _both_ have two branches, but they'd just en dup
having different branches checked out.
Of course, after you get comfy enough with the setup, you might end up
just deciding that you might as well just switch branches around in a
single repository (which is what a lot of git users end up doing), but at
least initially, it's probably easier from a conceptual standpoint to just
have the two branches checked out in separate copies of the repos.
> With SVN, I would have a directory with two external entries:
>
> upstream.trunk svn+ssh://svn.upstream.org/path/to/trunk
> upstream.trunk/debian svn+ssh://svn.debian.org/svn/pkg/trunk/debian
So in git, you'd have just one "project" with two branches - perhaps just
called "upstream" and "debian".
Of course, with git, that single "project" can then exist in a distributed
manner in many different places, and having two copies with different
branches checked out would just happen to be the one that most closely
resembles your current situation.
> How can I do this with git? I am aware that maybe the best way would
> be to use git-svn to track the upstream branch remotely and to add
> ./debian in a separate git branch (and to stop using SVN and switch
> to git for ./debian)
I don't think you'd have to stop using SVN. Just continue to track the
"upstream" branch with git-svn, and then you can merge in the upstream
into your "debian" branch that also has all the debian-specific stuff.
(And no, I don't know what the standard debian package management setup
looks like, but I would hope that your extra stuff would be just a few
files and package descriptions, and obviously any of the local debian
changes to the project).
Linus
^ permalink raw reply
* Extra Income! No School degree, work from home. NJVsX
From: Nik @ 2007-07-10 2:18 UTC (permalink / raw)
To: git
Hello! Please read this interesting offer if you are looking for an extra income or second job.
CPA Tools Company is currently seeking for people in Australia for "Transaction Handling" position, you do not have to have any school degree nor past experience.
This is a genuine offer that you can rely on until December the 25th 2007. You will be able to make 1100-1600 AUD a week spending only 2 hours a day Monday-Thursday.
Who Can Apply?
.>> 18+ y/o.
.>> You are located in Australia.
.>> You will be able to check your e-mail several times a day.
.>> You will have couple hours of free time Monday-Thursday.
If you meet requirements you are more than welcome to obtain more information by replying to: CPAtools.business@gmail.com Good Luck!
-----------------
oljDK
^ permalink raw reply
* Re: [PATCH] Makefile: rebuild git.o on version change, clean up git$X flags
From: Junio C Hamano @ 2007-07-10 1:55 UTC (permalink / raw)
To: Matt McCutchen; +Cc: git
In-Reply-To: <1184031039.14364.11.camel@mattlaptop2>
Thanks.
^ permalink raw reply
* [PATCH] Makefile: rebuild git.o on version change, clean up git$X flags
From: Matt McCutchen @ 2007-07-10 1:30 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Commit 334d28ae factored out git.o as an intermediate stage between
git.c and git$X. However:
- It left some no-longer-relevant flags in the rule for git$X.
- It failed to replace git$X with git.o in the list of files that
record GIT_VERSION. This broke incorporation of a changed
GIT_VERSION into git$X because, when GIT_VERSION changes, git.o isn't
remade and git$X is relinked from the git.o that still contains the
old GIT_VERSION.
This patch removes the irrelevant flags and fixes incorporation of a
changed GIT_VERSION into git$X.
Signed-off-by: Matt McCutchen <hashproduct@gmail.com>
---
Amusingly, I found this because, when I formatted my previous patch for
submission, I noticed that the "-dirty" in the version at the bottom
wouldn't go away even though I had committed my changes to my
git-development repository. (I was actually using the git tools from
that repository.)
Makefile | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
index 5b30e5c..d7541b4 100644
--- a/Makefile
+++ b/Makefile
@@ -753,8 +753,7 @@ git.o: git.c common-cmds.h GIT-CFLAGS
$(ALL_CFLAGS) -c $(filter %.c,$^)
git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
- $(QUIET_LINK)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
- $(ALL_CFLAGS) -o $@ $(filter %.c,$^) git.o \
+ $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
help.o: common-cmds.h
@@ -857,7 +856,7 @@ configure: configure.ac
rm -f $<+
# These can record GIT_VERSION
-git$X git.spec \
+git.o git.spec \
$(patsubst %.sh,%,$(SCRIPT_SH)) \
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
: GIT-VERSION-FILE
--
1.5.3.rc0.83.gb18a6
^ permalink raw reply related
* [PATCH] gitweb: snapshot cleanups & support for offering multiple formats
From: Matt McCutchen @ 2007-07-10 1:14 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vr6nht9yq.fsf@assigned-by-dhcp.cox.net>
- Centralize knowledge about snapshot formats (mime types, extensions,
commands) in %known_snapshot_formats and improve how some of that
information is specified. In particular, zip files are no longer a
special case.
- Add support for offering multiple snapshot formats to the user so
that he/she can download a snapshot in the format he/she prefers.
The site-wide or project configuration now gives a list of formats
to offer, and if more than one format is offered, the "_snapshot_"
link becomes something like "snapshot (_tbz2_ _zip_)".
- Fix out-of-date "tarball" -> "archive" in comment.
Alert for gitweb site administrators: This patch changes the format of
$feature{'snapshot'}{'default'} in gitweb_config.perl from a list of three
pieces of information about a single format to a list of one or more formats
you wish to offer from the set ('tgz', 'tbz2', 'zip'). Update your
gitweb_config.perl appropriately.
Signed-off-by: Matt McCutchen <hashproduct@gmail.com>
---
This third revision of the patch keeps the link as "_snapshot_" when only one
format is offered.
gitweb/gitweb.perl | 110 +++++++++++++++++++++++++++++-----------------------
1 files changed, 61 insertions(+), 49 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index dc609f4..b520342 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -101,6 +101,15 @@ our $mimetypes_file = undef;
# could be even 'utf-8' for the old behavior)
our $fallback_encoding = 'latin1';
+# information about snapshot formats that gitweb is capable of serving
+# name => [mime type, filename suffix, --format for git-archive,
+# compressor command suffix]
+our %known_snapshot_formats = (
+ 'tgz' => ['application/x-gzip' , '.tar.gz' , 'tar', '| gzip' ],
+ 'tbz2' => ['application/x-bzip2', '.tar.bz2', 'tar', '| bzip2'],
+ 'zip' => ['application/zip' , '.zip' , 'zip', '' ],
+);
+
# You define site-wide feature defaults here; override them with
# $GITWEB_CONFIG as necessary.
our %feature = (
@@ -131,20 +140,22 @@ our %feature = (
'override' => 0,
'default' => [0]},
- # Enable the 'snapshot' link, providing a compressed tarball of any
+ # Enable the 'snapshot' link, providing a compressed archive of any
# tree. This can potentially generate high traffic if you have large
# project.
+ # Value is a list of formats defined in %known_snapshot_formats that
+ # you wish to offer.
# To disable system wide have in $GITWEB_CONFIG
- # $feature{'snapshot'}{'default'} = [undef];
+ # $feature{'snapshot'}{'default'} = [];
# To have project specific config enable override in $GITWEB_CONFIG
# $feature{'snapshot'}{'override'} = 1;
- # and in project config gitweb.snapshot = none|gzip|bzip2|zip;
+ # and in project config, a comma-separated list of formats or "none"
+ # to disable. Example: gitweb.snapshot = tbz2,zip;
'snapshot' => {
'sub' => \&feature_snapshot,
'override' => 0,
- # => [content-encoding, suffix, program]
- 'default' => ['x-gzip', 'gz', 'gzip']},
+ 'default' => ['tgz']},
# Enable text search, which will list the commits which match author,
# committer or commit text to a given string. Enabled by default.
@@ -243,28 +254,15 @@ sub feature_blame {
}
sub feature_snapshot {
- my ($ctype, $suffix, $command) = @_;
+ my (@fmts) = @_;
my ($val) = git_get_project_config('snapshot');
- if ($val eq 'gzip') {
- return ('x-gzip', 'gz', 'gzip');
- } elsif ($val eq 'bzip2') {
- return ('x-bzip2', 'bz2', 'bzip2');
- } elsif ($val eq 'zip') {
- return ('x-zip', 'zip', '');
- } elsif ($val eq 'none') {
- return ();
+ if ($val) {
+ @fmts = ($val eq 'none' ? () : split /,/, $val);
}
- return ($ctype, $suffix, $command);
-}
-
-sub gitweb_have_snapshot {
- my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
- my $have_snapshot = (defined $ctype && defined $suffix);
-
- return $have_snapshot;
+ return grep exists $known_snapshot_formats{$_}, @fmts;
}
sub feature_grep {
@@ -542,6 +540,7 @@ sub href(%) {
order => "o",
searchtext => "s",
searchtype => "st",
+ snapshot_format => "sf",
);
my %mapping = @mapping;
@@ -1236,6 +1235,25 @@ sub format_diff_line {
return "<div class=\"diff$diff_class\">" . esc_html($line, -nbsp=>1) . "</div>\n";
}
+# Generates undef or something like "snapshot (tbz2 zip)", linked.
+# Pass the hash.
+sub format_snapshot_links {
+ my ($hash) = @_;
+ my @snapshot_fmts = gitweb_check_feature('snapshot');
+ my $num_fmts = @snapshot_fmts;
+ if ($num_fmts > 1) {
+ return "snapshot (" . join(' ', map $cgi->a(
+ {-href => href(action=>"snapshot", hash=>$hash, snapshot_format=>$_)}, "$_"),
+ @snapshot_fmts)
+ . ")";
+ } elsif ($num_fmts == 1) {
+ return $cgi->a({-href => href(action=>"snapshot", hash=>$hash,
+ snapshot_format=>$snapshot_fmts[0])}, "snapshot");
+ } else { # $num_fmts == 0
+ return undef;
+ }
+}
+
## ----------------------------------------------------------------------
## git utility subroutines, invoking git commands
@@ -3299,8 +3317,6 @@ sub git_shortlog_body {
# uses global variable $project
my ($commitlist, $from, $to, $refs, $extra) = @_;
- my $have_snapshot = gitweb_have_snapshot();
-
$from = 0 unless defined $from;
$to = $#{$commitlist} if (!defined $to || $#{$commitlist} < $to);
@@ -3327,8 +3343,9 @@ sub git_shortlog_body {
$cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
$cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " .
$cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree");
- if ($have_snapshot) {
- print " | " . $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
+ my $snapshot_links = format_snapshot_links($commit);
+ if (defined $snapshot_links) {
+ print " | " . $snapshot_links;
}
print "</td>\n" .
"</tr>\n";
@@ -4110,8 +4127,6 @@ sub git_blob {
}
sub git_tree {
- my $have_snapshot = gitweb_have_snapshot();
-
if (!defined $hash_base) {
$hash_base = "HEAD";
}
@@ -4145,11 +4160,10 @@ sub git_tree {
hash_base=>"HEAD", file_name=>$file_name)},
"HEAD"),
}
- if ($have_snapshot) {
+ my $snapshot_links = format_snapshot_links($hash);
+ if (defined $snapshot_links) {
# FIXME: Should be available when we have no hash base as well.
- push @views_nav,
- $cgi->a({-href => href(action=>"snapshot", hash=>$hash)},
- "snapshot");
+ push @views_nav, $snapshot_links;
}
git_print_page_nav('tree','', $hash_base, undef, undef, join(' | ', @views_nav));
git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
@@ -4213,11 +4227,16 @@ sub git_tree {
}
sub git_snapshot {
- my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
- my $have_snapshot = (defined $ctype && defined $suffix);
- if (!$have_snapshot) {
- die_error('403 Permission denied', "Permission denied");
+ my @supported_fmts = gitweb_check_feature('snapshot');
+
+ my $format = $cgi->param('sf');
+ unless ($format =~ m/[a-z0-9]+/
+ && exists($known_snapshot_formats{$format})
+ && grep($_ eq $format, @supported_fmts)) {
+ die_error(undef, "Unsupported snapshot format");
}
+ my ($ctype, $suffix, $ga_format, $pipe_compressor) =
+ @{$known_snapshot_formats{$format}};
if (!defined $hash) {
$hash = git_get_head_hash($project);
@@ -4230,16 +4249,11 @@ sub git_snapshot {
my $filename = to_utf8($name);
$name =~ s/\047/\047\\\047\047/g;
my $cmd;
- if ($suffix eq 'zip') {
- $filename .= "-$hash.$suffix";
- $cmd = "$git archive --format=zip --prefix=\'$name\'/ $hash";
- } else {
- $filename .= "-$hash.tar.$suffix";
- $cmd = "$git archive --format=tar --prefix=\'$name\'/ $hash | $command";
- }
+ $filename .= "-$hash$suffix";
+ $cmd = "$git archive --format=$ga_format --prefix=\'$name\'/ $hash $pipe_compressor";
print $cgi->header(
- -type => "application/$ctype",
+ -type => "$ctype",
-content_disposition => 'inline; filename="' . "$filename" . '"',
-status => '200 OK');
@@ -4368,8 +4382,6 @@ sub git_commit {
my $refs = git_get_references();
my $ref = format_ref_marker($refs, $co{'id'});
- my $have_snapshot = gitweb_have_snapshot();
-
git_header_html(undef, $expires);
git_print_page_nav('commit', '',
$hash, $co{'tree'}, $hash,
@@ -4408,9 +4420,9 @@ sub git_commit {
"<td class=\"link\">" .
$cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)},
"tree");
- if ($have_snapshot) {
- print " | " .
- $cgi->a({-href => href(action=>"snapshot", hash=>$hash)}, "snapshot");
+ my $snapshot_links = format_snapshot_links($hash);
+ if (defined $snapshot_links) {
+ print " | " . $snapshot_links;
}
print "</td>" .
"</tr>\n";
--
1.5.3.rc0.83.gb18a6
^ permalink raw reply related
* [PATCH] gitweb: snapshot cleanups & support for offering multiple formats
From: Matt McCutchen @ 2007-07-10 1:14 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vr6nht9yq.fsf@assigned-by-dhcp.cox.net>
- Centralize knowledge about snapshot formats (mime types, extensions,
commands) in %known_snapshot_formats and improve how some of that
information is specified. In particular, zip files are no longer a
special case.
- Add support for offering multiple snapshot formats to the user so
that he/she can download a snapshot in the format he/she prefers.
The site-wide or project configuration now gives a list of formats
to offer, and if more than one format is offered, the "_snapshot_"
link becomes something like "snapshot (_tbz2_ _zip_)".
- Fix out-of-date "tarball" -> "archive" in comment.
Alert for gitweb site administrators: This patch changes the format of
$feature{'snapshot'}{'default'} in gitweb_config.perl from a list of three
pieces of information about a single format to a list of one or more formats
you wish to offer from the set ('tgz', 'tbz2', 'zip'). Update your
gitweb_config.perl appropriately.
Signed-off-by: Matt McCutchen <hashproduct@gmail.com>
---
This third revision of the patch keeps the link as "_snapshot_" when only one
format is offered.
gitweb/gitweb.perl | 110 +++++++++++++++++++++++++++++-----------------------
1 files changed, 61 insertions(+), 49 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index dc609f4..b520342 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -101,6 +101,15 @@ our $mimetypes_file = undef;
# could be even 'utf-8' for the old behavior)
our $fallback_encoding = 'latin1';
+# information about snapshot formats that gitweb is capable of serving
+# name => [mime type, filename suffix, --format for git-archive,
+# compressor command suffix]
+our %known_snapshot_formats = (
+ 'tgz' => ['application/x-gzip' , '.tar.gz' , 'tar', '| gzip' ],
+ 'tbz2' => ['application/x-bzip2', '.tar.bz2', 'tar', '| bzip2'],
+ 'zip' => ['application/zip' , '.zip' , 'zip', '' ],
+);
+
# You define site-wide feature defaults here; override them with
# $GITWEB_CONFIG as necessary.
our %feature = (
@@ -131,20 +140,22 @@ our %feature = (
'override' => 0,
'default' => [0]},
- # Enable the 'snapshot' link, providing a compressed tarball of any
+ # Enable the 'snapshot' link, providing a compressed archive of any
# tree. This can potentially generate high traffic if you have large
# project.
+ # Value is a list of formats defined in %known_snapshot_formats that
+ # you wish to offer.
# To disable system wide have in $GITWEB_CONFIG
- # $feature{'snapshot'}{'default'} = [undef];
+ # $feature{'snapshot'}{'default'} = [];
# To have project specific config enable override in $GITWEB_CONFIG
# $feature{'snapshot'}{'override'} = 1;
- # and in project config gitweb.snapshot = none|gzip|bzip2|zip;
+ # and in project config, a comma-separated list of formats or "none"
+ # to disable. Example: gitweb.snapshot = tbz2,zip;
'snapshot' => {
'sub' => \&feature_snapshot,
'override' => 0,
- # => [content-encoding, suffix, program]
- 'default' => ['x-gzip', 'gz', 'gzip']},
+ 'default' => ['tgz']},
# Enable text search, which will list the commits which match author,
# committer or commit text to a given string. Enabled by default.
@@ -243,28 +254,15 @@ sub feature_blame {
}
sub feature_snapshot {
- my ($ctype, $suffix, $command) = @_;
+ my (@fmts) = @_;
my ($val) = git_get_project_config('snapshot');
- if ($val eq 'gzip') {
- return ('x-gzip', 'gz', 'gzip');
- } elsif ($val eq 'bzip2') {
- return ('x-bzip2', 'bz2', 'bzip2');
- } elsif ($val eq 'zip') {
- return ('x-zip', 'zip', '');
- } elsif ($val eq 'none') {
- return ();
+ if ($val) {
+ @fmts = ($val eq 'none' ? () : split /,/, $val);
}
- return ($ctype, $suffix, $command);
-}
-
-sub gitweb_have_snapshot {
- my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
- my $have_snapshot = (defined $ctype && defined $suffix);
-
- return $have_snapshot;
+ return grep exists $known_snapshot_formats{$_}, @fmts;
}
sub feature_grep {
@@ -542,6 +540,7 @@ sub href(%) {
order => "o",
searchtext => "s",
searchtype => "st",
+ snapshot_format => "sf",
);
my %mapping = @mapping;
@@ -1236,6 +1235,25 @@ sub format_diff_line {
return "<div class=\"diff$diff_class\">" . esc_html($line, -nbsp=>1) . "</div>\n";
}
+# Generates undef or something like "snapshot (tbz2 zip)", linked.
+# Pass the hash.
+sub format_snapshot_links {
+ my ($hash) = @_;
+ my @snapshot_fmts = gitweb_check_feature('snapshot');
+ my $num_fmts = @snapshot_fmts;
+ if ($num_fmts > 1) {
+ return "snapshot (" . join(' ', map $cgi->a(
+ {-href => href(action=>"snapshot", hash=>$hash, snapshot_format=>$_)}, "$_"),
+ @snapshot_fmts)
+ . ")";
+ } elsif ($num_fmts == 1) {
+ return $cgi->a({-href => href(action=>"snapshot", hash=>$hash,
+ snapshot_format=>$snapshot_fmts[0])}, "snapshot");
+ } else { # $num_fmts == 0
+ return undef;
+ }
+}
+
## ----------------------------------------------------------------------
## git utility subroutines, invoking git commands
@@ -3299,8 +3317,6 @@ sub git_shortlog_body {
# uses global variable $project
my ($commitlist, $from, $to, $refs, $extra) = @_;
- my $have_snapshot = gitweb_have_snapshot();
-
$from = 0 unless defined $from;
$to = $#{$commitlist} if (!defined $to || $#{$commitlist} < $to);
@@ -3327,8 +3343,9 @@ sub git_shortlog_body {
$cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
$cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " .
$cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree");
- if ($have_snapshot) {
- print " | " . $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
+ my $snapshot_links = format_snapshot_links($commit);
+ if (defined $snapshot_links) {
+ print " | " . $snapshot_links;
}
print "</td>\n" .
"</tr>\n";
@@ -4110,8 +4127,6 @@ sub git_blob {
}
sub git_tree {
- my $have_snapshot = gitweb_have_snapshot();
-
if (!defined $hash_base) {
$hash_base = "HEAD";
}
@@ -4145,11 +4160,10 @@ sub git_tree {
hash_base=>"HEAD", file_name=>$file_name)},
"HEAD"),
}
- if ($have_snapshot) {
+ my $snapshot_links = format_snapshot_links($hash);
+ if (defined $snapshot_links) {
# FIXME: Should be available when we have no hash base as well.
- push @views_nav,
- $cgi->a({-href => href(action=>"snapshot", hash=>$hash)},
- "snapshot");
+ push @views_nav, $snapshot_links;
}
git_print_page_nav('tree','', $hash_base, undef, undef, join(' | ', @views_nav));
git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
@@ -4213,11 +4227,16 @@ sub git_tree {
}
sub git_snapshot {
- my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
- my $have_snapshot = (defined $ctype && defined $suffix);
- if (!$have_snapshot) {
- die_error('403 Permission denied', "Permission denied");
+ my @supported_fmts = gitweb_check_feature('snapshot');
+
+ my $format = $cgi->param('sf');
+ unless ($format =~ m/[a-z0-9]+/
+ && exists($known_snapshot_formats{$format})
+ && grep($_ eq $format, @supported_fmts)) {
+ die_error(undef, "Unsupported snapshot format");
}
+ my ($ctype, $suffix, $ga_format, $pipe_compressor) =
+ @{$known_snapshot_formats{$format}};
if (!defined $hash) {
$hash = git_get_head_hash($project);
@@ -4230,16 +4249,11 @@ sub git_snapshot {
my $filename = to_utf8($name);
$name =~ s/\047/\047\\\047\047/g;
my $cmd;
- if ($suffix eq 'zip') {
- $filename .= "-$hash.$suffix";
- $cmd = "$git archive --format=zip --prefix=\'$name\'/ $hash";
- } else {
- $filename .= "-$hash.tar.$suffix";
- $cmd = "$git archive --format=tar --prefix=\'$name\'/ $hash | $command";
- }
+ $filename .= "-$hash$suffix";
+ $cmd = "$git archive --format=$ga_format --prefix=\'$name\'/ $hash $pipe_compressor";
print $cgi->header(
- -type => "application/$ctype",
+ -type => "$ctype",
-content_disposition => 'inline; filename="' . "$filename" . '"',
-status => '200 OK');
@@ -4368,8 +4382,6 @@ sub git_commit {
my $refs = git_get_references();
my $ref = format_ref_marker($refs, $co{'id'});
- my $have_snapshot = gitweb_have_snapshot();
-
git_header_html(undef, $expires);
git_print_page_nav('commit', '',
$hash, $co{'tree'}, $hash,
@@ -4408,9 +4420,9 @@ sub git_commit {
"<td class=\"link\">" .
$cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)},
"tree");
- if ($have_snapshot) {
- print " | " .
- $cgi->a({-href => href(action=>"snapshot", hash=>$hash)}, "snapshot");
+ my $snapshot_links = format_snapshot_links($hash);
+ if (defined $snapshot_links) {
+ print " | " . $snapshot_links;
}
print "</td>" .
"</tr>\n";
--
1.5.3.rc0.83.gb18a6
^ permalink raw reply related
* how to do directory renames in fast-import
From: David Frech @ 2007-07-10 1:09 UTC (permalink / raw)
To: git
Git can track file renames implicitly. If I delete and then add (under
a different name) the same content, git will figure that out.
But if a directory was renamed, I have no way to tell fast-import
about it. I can't delete the directory (using a 'D' command) and then
add it back (with a different name) with all its contents, because my
source material (an svn dump file) doesn't tell me, at that point,
about all the files involved because nothing about them has changed.
fast-import knows about the contents of the directory I want to
rename, but doesn't give me a primitive to do the rename. Is this
something we need to add? My frontend could keep track of this, but I
would duplicating work that fast-import is already doing.
Cheers,
- David
--
If I have not seen farther, it is because I have stood in the
footsteps of giants.
^ permalink raw reply
* Re: [PATCH] gitweb: snapshot cleanups & support for offering multiple formats
From: Junio C Hamano @ 2007-07-09 23:48 UTC (permalink / raw)
To: Matt McCutchen; +Cc: git
In-Reply-To: <3bbc18d20707091552l29fb81b6v34da9cef3ec0df58@mail.gmail.com>
"Matt McCutchen" <hashproduct@gmail.com> writes:
> On 7/8/07, Junio C Hamano <gitster@pobox.com> wrote:
>> Matt McCutchen <hashproduct@gmail.com> writes:
>>
>> > -sub gitweb_have_snapshot {
>> > - my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
>> > - my $have_snapshot = (defined $ctype && defined $suffix);
>> > -
>> > - return $have_snapshot;
>>
>> Although you are removing this function, you still have a couple
>> of callers left in the code.
>
> OK, I will revise the patch, submit it and see if I can get it to
> appear as a reply to this thread.
Thanks. For future reference, I caught it not by code
inspection, but by running one of the tests (t9500).
> Incidentally, when only one format
> is offered, would you prefer the snapshot link to appear as
> "_snapshot_" (the same as before) or "_snapshot (tgz)_" instead of the
> "snapshot (_tgz_)" that the current patch does?
When only one format is offerred by the site, it is not like the
end user has any choice, so "_snapshot_" is probably the most
appropriate from the screen real-estate point-of-view.
The end user _might_ complain "Geez, I cannot grok zip, I can
only expand tar. I would not have clicked the link if it said
'snapshot (_zip_)', but the stupid gitweb said '_snapshot_' and
nothing else." So in that sense, we are robbing one choice the
user has (i.e. "to decide not to click the link, based on the
format of the data that would be given"), but I do not think
that is something we would seriously want to worry about.
^ permalink raw reply
* [PATCH] gitweb: snapshot cleanups & support for offering multiple formats
From: Matt McCutchen @ 2007-07-09 23:21 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <3bbc18d20707091552l29fb81b6v34da9cef3ec0df58@mail.gmail.com>
- Centralize knowledge about snapshot formats (mime types, extensions,
commands) in %known_snapshot_formats and improve how some of that
information is specified. In particular, zip files are no longer a
special case.
- Add support for offering multiple snapshot formats to the user so
that he/she can download a snapshot in the format he/she prefers.
The site-wide or project configuration now gives a list of formats
to offer, and the "_snapshot_" link is replaced with, say,
"snapshot (_tbz2_ _zip_)".
- Fix out-of-date "tarball" -> "archive" in comment.
Alert for gitweb site administrators: This patch changes the format of
$feature{'snapshot'}{'default'} in gitweb_config.perl from a list of three
pieces of information about a single format to a list of one or more formats
you wish to offer from the set ('tgz', 'tbz2', 'zip'). Update your
gitweb_config.perl appropriately.
Signed-off-by: Matt McCutchen <hashproduct@gmail.com>
---
This revised patch converts the two remaining gitweb_have_snapshot callers and
adds the alert in the commit message.
gitweb/gitweb.perl | 106 ++++++++++++++++++++++++++++------------------------
1 files changed, 57 insertions(+), 49 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index dc609f4..4313671 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -101,6 +101,15 @@ our $mimetypes_file = undef;
# could be even 'utf-8' for the old behavior)
our $fallback_encoding = 'latin1';
+# information about snapshot formats that gitweb is capable of serving
+# name => [mime type, filename suffix, --format for git-archive,
+# compressor command suffix]
+our %known_snapshot_formats = (
+ 'tgz' => ['application/x-gzip' , '.tar.gz' , 'tar', '| gzip' ],
+ 'tbz2' => ['application/x-bzip2', '.tar.bz2', 'tar', '| bzip2'],
+ 'zip' => ['application/zip' , '.zip' , 'zip', '' ],
+);
+
# You define site-wide feature defaults here; override them with
# $GITWEB_CONFIG as necessary.
our %feature = (
@@ -131,20 +140,22 @@ our %feature = (
'override' => 0,
'default' => [0]},
- # Enable the 'snapshot' link, providing a compressed tarball of any
+ # Enable the 'snapshot' link, providing a compressed archive of any
# tree. This can potentially generate high traffic if you have large
# project.
+ # Value is a list of formats defined in %known_snapshot_formats that
+ # you wish to offer.
# To disable system wide have in $GITWEB_CONFIG
- # $feature{'snapshot'}{'default'} = [undef];
+ # $feature{'snapshot'}{'default'} = [];
# To have project specific config enable override in $GITWEB_CONFIG
# $feature{'snapshot'}{'override'} = 1;
- # and in project config gitweb.snapshot = none|gzip|bzip2|zip;
+ # and in project config, a comma-separated list of formats or "none"
+ # to disable. Example: gitweb.snapshot = tbz2,zip;
'snapshot' => {
'sub' => \&feature_snapshot,
'override' => 0,
- # => [content-encoding, suffix, program]
- 'default' => ['x-gzip', 'gz', 'gzip']},
+ 'default' => ['tgz']},
# Enable text search, which will list the commits which match author,
# committer or commit text to a given string. Enabled by default.
@@ -243,28 +254,15 @@ sub feature_blame {
}
sub feature_snapshot {
- my ($ctype, $suffix, $command) = @_;
+ my (@fmts) = @_;
my ($val) = git_get_project_config('snapshot');
- if ($val eq 'gzip') {
- return ('x-gzip', 'gz', 'gzip');
- } elsif ($val eq 'bzip2') {
- return ('x-bzip2', 'bz2', 'bzip2');
- } elsif ($val eq 'zip') {
- return ('x-zip', 'zip', '');
- } elsif ($val eq 'none') {
- return ();
+ if ($val) {
+ @fmts = ($val eq 'none' ? () : split /,/, $val);
}
- return ($ctype, $suffix, $command);
-}
-
-sub gitweb_have_snapshot {
- my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
- my $have_snapshot = (defined $ctype && defined $suffix);
-
- return $have_snapshot;
+ return grep exists $known_snapshot_formats{$_}, @fmts;
}
sub feature_grep {
@@ -542,6 +540,7 @@ sub href(%) {
order => "o",
searchtext => "s",
searchtype => "st",
+ snapshot_format => "sf",
);
my %mapping = @mapping;
@@ -1236,6 +1235,21 @@ sub format_diff_line {
return "<div class=\"diff$diff_class\">" . esc_html($line, -nbsp=>1) . "</div>\n";
}
+# Generates undef or something like "snapshot (tbz2 zip)", linked.
+# Pass the hash.
+sub format_snapshot_links {
+ my ($hash) = @_;
+ my @snapshot_fmts = gitweb_check_feature('snapshot');
+ if (@snapshot_fmts) {
+ return "snapshot (" . join(' ', map $cgi->a(
+ {-href => href(action=>"snapshot", hash=>$hash, snapshot_format=>$_)}, "$_"),
+ @snapshot_fmts)
+ . ")";
+ } else {
+ return undef;
+ }
+}
+
## ----------------------------------------------------------------------
## git utility subroutines, invoking git commands
@@ -3299,8 +3313,6 @@ sub git_shortlog_body {
# uses global variable $project
my ($commitlist, $from, $to, $refs, $extra) = @_;
- my $have_snapshot = gitweb_have_snapshot();
-
$from = 0 unless defined $from;
$to = $#{$commitlist} if (!defined $to || $#{$commitlist} < $to);
@@ -3327,8 +3339,9 @@ sub git_shortlog_body {
$cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
$cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " .
$cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree");
- if ($have_snapshot) {
- print " | " . $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
+ my $snapshot_links = format_snapshot_links($commit);
+ if (defined $snapshot_links) {
+ print " | " . $snapshot_links;
}
print "</td>\n" .
"</tr>\n";
@@ -4110,8 +4123,6 @@ sub git_blob {
}
sub git_tree {
- my $have_snapshot = gitweb_have_snapshot();
-
if (!defined $hash_base) {
$hash_base = "HEAD";
}
@@ -4145,11 +4156,10 @@ sub git_tree {
hash_base=>"HEAD", file_name=>$file_name)},
"HEAD"),
}
- if ($have_snapshot) {
+ my $snapshot_links = format_snapshot_links($hash);
+ if (defined $snapshot_links) {
# FIXME: Should be available when we have no hash base as well.
- push @views_nav,
- $cgi->a({-href => href(action=>"snapshot", hash=>$hash)},
- "snapshot");
+ push @views_nav, $snapshot_links;
}
git_print_page_nav('tree','', $hash_base, undef, undef, join(' | ', @views_nav));
git_print_header_div('commit', esc_html($co{'title'}) . $ref, $hash_base);
@@ -4213,11 +4223,16 @@ sub git_tree {
}
sub git_snapshot {
- my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
- my $have_snapshot = (defined $ctype && defined $suffix);
- if (!$have_snapshot) {
- die_error('403 Permission denied', "Permission denied");
+ my @supported_fmts = gitweb_check_feature('snapshot');
+
+ my $format = $cgi->param('sf');
+ unless ($format =~ m/[a-z0-9]+/
+ && exists($known_snapshot_formats{$format})
+ && grep($_ eq $format, @supported_fmts)) {
+ die_error(undef, "Unsupported snapshot format");
}
+ my ($ctype, $suffix, $ga_format, $pipe_compressor) =
+ @{$known_snapshot_formats{$format}};
if (!defined $hash) {
$hash = git_get_head_hash($project);
@@ -4230,16 +4245,11 @@ sub git_snapshot {
my $filename = to_utf8($name);
$name =~ s/\047/\047\\\047\047/g;
my $cmd;
- if ($suffix eq 'zip') {
- $filename .= "-$hash.$suffix";
- $cmd = "$git archive --format=zip --prefix=\'$name\'/ $hash";
- } else {
- $filename .= "-$hash.tar.$suffix";
- $cmd = "$git archive --format=tar --prefix=\'$name\'/ $hash | $command";
- }
+ $filename .= "-$hash$suffix";
+ $cmd = "$git archive --format=$ga_format --prefix=\'$name\'/ $hash $pipe_compressor";
print $cgi->header(
- -type => "application/$ctype",
+ -type => "$ctype",
-content_disposition => 'inline; filename="' . "$filename" . '"',
-status => '200 OK');
@@ -4368,8 +4378,6 @@ sub git_commit {
my $refs = git_get_references();
my $ref = format_ref_marker($refs, $co{'id'});
- my $have_snapshot = gitweb_have_snapshot();
-
git_header_html(undef, $expires);
git_print_page_nav('commit', '',
$hash, $co{'tree'}, $hash,
@@ -4408,9 +4416,9 @@ sub git_commit {
"<td class=\"link\">" .
$cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$hash)},
"tree");
- if ($have_snapshot) {
- print " | " .
- $cgi->a({-href => href(action=>"snapshot", hash=>$hash)}, "snapshot");
+ my $snapshot_links = format_snapshot_links($hash);
+ if (defined $snapshot_links) {
+ print " | " . $snapshot_links;
}
print "</td>" .
"</tr>\n";
--
1.5.3.rc0.82.g2bad2-dirty
^ permalink raw reply related
* how to combine two clones in a collection
From: martin f krafft @ 2007-07-09 22:22 UTC (permalink / raw)
To: git discussion list
[-- Attachment #1: Type: text/plain, Size: 1531 bytes --]
Dear list,
I am new to git but already quite sold on it. Especially git-svn
makes my heart jump.
I am now ready to move to using git for most of my everyday work,
but I am still unsure how to tackle one specific aspect of it, for
which I used svn:externals in the past. I know about git
subprojects, but these aren't what I want, really.
I am a Debian developer, and while the upstream trunk is usually
maintained in SVN by upstream him/herself, I maintain the ./debian
directory elsewhere.
With SVN, I would have a directory with two external entries:
upstream.trunk svn+ssh://svn.upstream.org/path/to/trunk
upstream.trunk/debian svn+ssh://svn.debian.org/svn/pkg/trunk/debian
I hope this makes what I mean obvious. GNU arch has a similar
concept called configs.
How can I do this with git? I am aware that maybe the best way would
be to use git-svn to track the upstream branch remotely and to add
./debian in a separate git branch (and to stop using SVN and switch
to git for ./debian), but I am not sure I want to mirror all
upstream projects in git repos published on svn.debian.org, and if
it's only for space reasons.
Do you know of other approaches, short of writing my own
config-manager?
Thanks,
--
martin; (greetings from the heart of the sun.)
\____ echo mailto: !#^."<*>"|tr "<*> mailto:" net@madduck
spamtraps: madduck.bogus@madduck.net
"never eat more than you can lift."
-- miss piggy
[-- Attachment #2: Digital signature (GPG/PGP) --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH] gitweb: snapshot cleanups & support for offering multiple formats
From: Matt McCutchen @ 2007-07-09 22:52 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7v1wfi1rz6.fsf@assigned-by-dhcp.cox.net>
On 7/8/07, Junio C Hamano <gitster@pobox.com> wrote:
> Matt McCutchen <hashproduct@gmail.com> writes:
>
> > -sub gitweb_have_snapshot {
> > - my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
> > - my $have_snapshot = (defined $ctype && defined $suffix);
> > -
> > - return $have_snapshot;
>
> Although you are removing this function, you still have a couple
> of callers left in the code.
OK, I will revise the patch, submit it and see if I can get it to
appear as a reply to this thread. Incidentally, when only one format
is offered, would you prefer the snapshot link to appear as
"_snapshot_" (the same as before) or "_snapshot (tgz)_" instead of the
"snapshot (_tgz_)" that the current patch does?
Matt
^ permalink raw reply
* Re: [PATCH] branch --track: code cleanup and saner handling of local branches
From: Junio C Hamano @ 2007-07-09 22:01 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Paolo Bonzini, git, Daniel Barkalow
In-Reply-To: <Pine.LNX.4.64.0707092203100.5546@racer.site>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>> It strikes me a bit odd if Daniel's remote.[ch] infrastructure
>> does not give you easy access to this kind of information...
>
> Yes, probably. However, at the time he was sending that patch, I was
> already preparing the patch.
I was talking about existing remote.[ch] patches, which has been
in tree since late May this year, not his recent round of
"approach to builtin git-fetch" series.
^ 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