* [PATCH] builtin-push: --all and --tags _are_ explicit refspecs
From: Johannes Schindelin @ 2006-05-04 21:18 UTC (permalink / raw)
To: git, junkio
... so do not get refspecs from remotes/* or the config if one of them
was specified.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
builtin-push.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
42859edd0156479786e5bc4184e462a0307a67eb
diff --git a/builtin-push.c b/builtin-push.c
index 06d06ff..e530022 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -72,7 +72,7 @@ static int get_remotes_uri(const char *r
{
int n = 0;
FILE *f = fopen(git_path("remotes/%s", repo), "r");
- int has_explicit_refspec = refspec_nr;
+ int has_explicit_refspec = refspec_nr || all || tags;
if (!f)
return -1;
@@ -144,7 +144,7 @@ static int get_config_remotes_uri(const
config_repo = repo;
config_current_uri = 0;
config_uri = uri;
- config_get_refspecs = !refspec_nr;
+ config_get_refspecs = !(refspec_nr || all || tags);
git_config(get_remote_config);
return config_current_uri;
--
1.3.2.gec86-dirty
^ permalink raw reply related
* Re: Unresolved issues #2
From: Linus Torvalds @ 2006-05-04 21:33 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: Junio C Hamano, Git Mailing List
In-Reply-To: <Pine.LNX.4.64.0605041627310.6713@iabervon.org>
On Thu, 4 May 2006, Daniel Barkalow wrote:
>
> I think it shouldn't be on fetch, though; I think a "git remote" command
> for describing, creating, and modifying remotes would be better, since you
> also sometimes want to add a "Push:" line.
I don't think this is wrong, but I think it's more important to try to
decide on how we want to represent this information first, and stabilize
that.
I realize that git has gotten a lot more porcelainish over time, but at
the same time, now you're really starting to argue about syntax that
really ends up being often a feature of the development environment. If
you did development using an IDE that knows about git, I think the
"remote" information ends up being not necessarily a git command at all,
but really an interface in the IDE.
I'm actually growing pretty fond of the config file interfaces that Dscho
is pushing. I really like the idea of "git pull" doing different things
depending on which branch is active at the time, because different
branches really can have different sources they come from.
Always pulling from the same default source seems wrong, and having to
remember whose source some branch is associated with is just not all that
user-friendly, but perhaps more importantly, it's also going to result in
people making mistakes, pulling from the wrong branch (because they didn't
think about where they were), and then having strange merges that they
might not notice were wrong until it's too late and they pushed the result
out.
So Johannes' patches seem to move into that direction, and having it all
in the config file actually seems to be quite readable.
And that, in turn, may mean that a lot of porcelains really only care
about that syntax, and then they may update the config file any way they
please (whether by hand, or by using "git repo-config" or by using "git
remote").
So I'd argue that (a) yes, we do want to have the "proto porcelain" that
sets remote branch information without the user having to know the magic
"git repo-config" incantation, or know which file in .git/remotes/ to
edit, but that (b) it's even more important to try to decide on what the
remote description format _is_.
I personally have just two preferences:
- I'd like each branch I'm on to have a "default source" for pulling (and
_maybe_ for pushing too). I'd like to just say "git pull", and it would
automatically select the appropriate thing to pull from.
- maybe the same per-branch thing for "push", but more importantly for
me, I like to push to multiple destinations, and I'd like the
description format to be sane. I think it may already be sane in the
form it is in now (supporting both config file _and_ .git/remotes/
formats), I'd just like us to decide on exactly what the meaning is,
and hopefully get to the point where we can tell porcelain how to use
that meaning to their advantage (and not change it)
Others may disagree, or (equally importantly), may have additional
preferences. We should try to find something that works for everybody, and
that is easy to work with.
Linus
^ permalink raw reply
* [PATCH] Fix linking with OpenSSL
From: Alexey Dobriyan @ 2006-05-04 22:25 UTC (permalink / raw)
To: git
For those who put it into interesting (read: default) place.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
--- a/Makefile
+++ b/Makefile
@@ -559,7 +559,7 @@ git-http-push$X: revision.o http.o http-
git-rev-list$X: rev-list.o $(LIB_FILE)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
- $(LIBS) $(OPENSSL_LIBSSL)
+ $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
init-db.o: init-db.c
$(CC) -c $(ALL_CFLAGS) \
^ permalink raw reply
* Re: [PATCH] Fix linking with OpenSSL
From: Junio C Hamano @ 2006-05-04 22:38 UTC (permalink / raw)
To: Alexey Dobriyan; +Cc: git
In-Reply-To: <20060504222550.GA7236@mipter.zuzino.mipt.ru>
Alexey Dobriyan <adobriyan@gmail.com> writes:
> For those who put it into interesting (read: default) place.
>
> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
>
> --- a/Makefile
> +++ b/Makefile
> @@ -559,7 +559,7 @@ git-http-push$X: revision.o http.o http-
>
> git-rev-list$X: rev-list.o $(LIB_FILE)
> $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
> - $(LIBS) $(OPENSSL_LIBSSL)
> + $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
>
> init-db.o: init-db.c
> $(CC) -c $(ALL_CFLAGS) \
We used to depend on bignum from openssl for rev-list
(merge-order), and if I remember correctly that was the only
reason built recipe for rev-list is different from other
programs. I wonder if we can just get rid of this thing, and
have it built with git-%$X rule like everybody else.
Can somebody try that out and report what happens?
^ permalink raw reply
* Re: [PATCH] Fix linking with OpenSSL
From: Junio C Hamano @ 2006-05-04 23:00 UTC (permalink / raw)
To: Alexey Dobriyan; +Cc: git
In-Reply-To: <7vwtd12z6h.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> writes:
> Alexey Dobriyan <adobriyan@gmail.com> writes:
>
>> For those who put it into interesting (read: default) place.
>>
>> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
>>
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -559,7 +559,7 @@ git-http-push$X: revision.o http.o http-
>>
>> git-rev-list$X: rev-list.o $(LIB_FILE)
>> $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
>> - $(LIBS) $(OPENSSL_LIBSSL)
>> + $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
>>
>> init-db.o: init-db.c
>> $(CC) -c $(ALL_CFLAGS) \
>
> We used to depend on bignum from openssl for rev-list
> (merge-order), and if I remember correctly that was the only
> reason built recipe for rev-list is different from other
> programs. I wonder if we can just get rid of this thing, and
> have it built with git-%$X rule like everybody else.
>
> Can somebody try that out and report what happens?
Well, I did. Alexey, does this work for you?
-- >8 --
diff --git a/Makefile b/Makefile
index a3f7e92..814010d 100644
--- a/Makefile
+++ b/Makefile
@@ -564,10 +564,6 @@ git-http-push$X: revision.o http.o http-
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
-git-rev-list$X: rev-list.o $(LIB_FILE)
- $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
- $(LIBS) $(OPENSSL_LIBSSL)
-
init-db.o: init-db.c
$(CC) -c $(ALL_CFLAGS) \
-DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c
^ permalink raw reply related
* [PATCH] Teach fmt-patch to write individual files.
From: Johannes Schindelin @ 2006-05-04 23:07 UTC (permalink / raw)
To: git, junkio
When called with "--stdout", it still writes to standard output.
Notable differences to git-format-patch:
- since fmt-patch uses the standardized logging machinery, it is
no longer "From nobody", but "From <commit_sha1>",
- the empty lines before and after the "---" just before the
diffstat are no longer there,
- git-format-patch outputs the commit_sha1 just before the first
diff, which fmt-patch does not,
- the file names are no longer output to stdout, but to stderr
(since stdout is freopen()ed all the time), and
- "git fmt-patch HEAD^" does not work as expected: it outputs
*all* commits reachable from HEAD^!
The last one is possibly a showstopper. At least I used to call that
command quite often...
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
builtin-log.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 60 insertions(+), 1 deletions(-)
diff --git a/builtin-log.c b/builtin-log.c
index a39aed6..a75a37f 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -69,12 +69,54 @@ int cmd_log(int argc, const char **argv,
return cmd_log_wc(argc, argv, envp, &rev);
}
+static int istitlechar(char c)
+{
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') || c == '.' || c == '_';
+}
+
+static void reopen_stdout(struct commit *commit, int nr)
+{
+ char filename[1024];
+ char *sol;
+ int len;
+
+
+ sprintf(filename, "%04d", nr);
+ len = strlen(filename);
+
+ sol = strstr(commit->buffer, "\n\n");
+ if (sol) {
+ int j, space = 1;
+
+ sol += 2;
+ for (j = 0; len < 1024 - 6 && sol[j] && sol[j] != '\n'; j++) {
+ if (istitlechar(sol[j])) {
+ if (space) {
+ filename[len++] = '-';
+ space = 0;
+ }
+ filename[len++] = sol[j];
+ if (sol[j] == '.')
+ while (sol[++j] == '.');
+ } else
+ space = 1;
+ }
+ while (filename[len - 1] == '.')
+ len--;
+ }
+ strcpy(filename + len, ".txt");
+ fprintf(stderr, "%s\n", filename);
+ freopen(filename, "w", stdout);
+}
+
int cmd_format_patch(int argc, const char **argv, char **envp)
{
struct commit *commit;
struct commit **list = NULL;
struct rev_info rev;
- int nr = 0;
+ int nr = 0, total;
+ int use_stdout = 0;
init_revisions(&rev);
rev.commit_format = CMIT_FMT_EMAIL;
@@ -87,20 +129,37 @@ int cmd_format_patch(int argc, const cha
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
argc = setup_revisions(argc, argv, &rev, "HEAD");
+ while (argc > 1) {
+ if (!strcmp(argv[1], "--stdout"))
+ use_stdout = 1;
+ else
+ die ("unrecognized argument: %s", argv[1]);
+ argc--;
+ argv++;
+ }
+
prepare_revision_walk(&rev);
while ((commit = get_revision(&rev)) != NULL) {
+ /* ignore merges */
+ if (commit->parents && commit->parents->next)
+ continue;
nr++;
list = realloc(list, nr * sizeof(list[0]));
list[nr - 1] = commit;
}
+ total = nr;
while (0 <= --nr) {
int shown;
commit = list[nr];
+ if (!use_stdout)
+ reopen_stdout(commit, total - nr);
shown = log_tree_commit(&rev, commit);
free(commit->buffer);
commit->buffer = NULL;
if (shown)
printf("-- \n%s\n\n", git_version_string);
+ if (!use_stdout)
+ fclose(stdout);
}
free(list);
return 0;
--
1.3.1.g42859-dirty
^ permalink raw reply related
* Re: [PATCH] Teach fmt-patch to write individual files.
From: Johannes Schindelin @ 2006-05-04 23:15 UTC (permalink / raw)
To: git, junkio
In-Reply-To: <Pine.LNX.4.63.0605050106180.12713@wbgn013.biozentrum.uni-wuerzburg.de>
Hi,
this patch is faulty. I'll send a fixed patch in one minute.
Sorry,
Dscho
^ permalink raw reply
* [PATCH] Teach fmt-patch to write individual files.
From: Johannes Schindelin @ 2006-05-04 23:16 UTC (permalink / raw)
To: git, junkio
When called with "--stdout", it still writes to standard output.
Notable differences to git-format-patch:
- since fmt-patch uses the standardized logging machinery, it is
no longer "From nobody", but "From <commit_sha1>",
- the empty lines before and after the "---" just before the
diffstat are no longer there,
- git-format-patch outputs the commit_sha1 just before the first
diff, which fmt-patch does not,
- the file names are no longer output to stdout, but to stderr
(since stdout is freopen()ed all the time), and
- "git fmt-patch HEAD^" does not work as expected: it outputs
*all* commits reachable from HEAD^!
The last one is possibly a showstopper. At least I used to call that
command quite often...
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
I forgot to "git-update-index builtin-log.c"...
builtin-log.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 71 insertions(+), 1 deletions(-)
diff --git a/builtin-log.c b/builtin-log.c
index a39aed6..576703c 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -69,12 +69,65 @@ int cmd_log(int argc, const char **argv,
return cmd_log_wc(argc, argv, envp, &rev);
}
+static int istitlechar(char c)
+{
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') || c == '.' || c == '_';
+}
+
+static void reopen_stdout(struct commit *commit, int nr)
+{
+ char filename[1024];
+ char *sol;
+ int len;
+
+
+ sprintf(filename, "%04d", nr);
+ len = strlen(filename);
+
+ sol = strstr(commit->buffer, "\n\n");
+ if (sol) {
+ int j, space = 1;
+
+ sol += 2;
+ /* strip [PATCH] or [PATCH blabla] */
+ if (!strncmp(sol, "[PATCH", 6)) {
+ char *eos = strchr(sol + 6, ']');
+ if (eos) {
+ while (isspace(*eos))
+ eos++;
+ sol = eos;
+ }
+ }
+
+ for (j = 0; len < 1024 - 6 && sol[j] && sol[j] != '\n'; j++) {
+ if (istitlechar(sol[j])) {
+ if (space) {
+ filename[len++] = '-';
+ space = 0;
+ }
+ filename[len++] = sol[j];
+ if (sol[j] == '.')
+ while (sol[j + 1] == '.')
+ j++;
+ } else
+ space = 1;
+ }
+ while (filename[len - 1] == '.' || filename[len - 1] == '-')
+ len--;
+ }
+ strcpy(filename + len, ".txt");
+ fprintf(stderr, "%s\n", filename);
+ freopen(filename, "w", stdout);
+}
+
int cmd_format_patch(int argc, const char **argv, char **envp)
{
struct commit *commit;
struct commit **list = NULL;
struct rev_info rev;
- int nr = 0;
+ int nr = 0, total;
+ int use_stdout = 0;
init_revisions(&rev);
rev.commit_format = CMIT_FMT_EMAIL;
@@ -87,20 +140,37 @@ int cmd_format_patch(int argc, const cha
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
argc = setup_revisions(argc, argv, &rev, "HEAD");
+ while (argc > 1) {
+ if (!strcmp(argv[1], "--stdout"))
+ use_stdout = 1;
+ else
+ die ("unrecognized argument: %s", argv[1]);
+ argc--;
+ argv++;
+ }
+
prepare_revision_walk(&rev);
while ((commit = get_revision(&rev)) != NULL) {
+ /* ignore merges */
+ if (commit->parents && commit->parents->next)
+ continue;
nr++;
list = realloc(list, nr * sizeof(list[0]));
list[nr - 1] = commit;
}
+ total = nr;
while (0 <= --nr) {
int shown;
commit = list[nr];
+ if (!use_stdout)
+ reopen_stdout(commit, total - nr);
shown = log_tree_commit(&rev, commit);
free(commit->buffer);
commit->buffer = NULL;
if (shown)
printf("-- \n%s\n\n", git_version_string);
+ if (!use_stdout)
+ fclose(stdout);
}
free(list);
return 0;
--
1.3.1.g42859-dirty
^ permalink raw reply related
* [PATCH] binary patch.
From: Junio C Hamano @ 2006-05-04 23:52 UTC (permalink / raw)
To: git
This adds "binary patch" to the diff output and teaches apply
what to do with them.
On the diff generation side, traditionally, we said "Binary
files differ\n" without giving anything other than the preimage
and postimage object name on the index line. This was good
enough for applying a patch generated from your own repository
(very useful while rebasing), because the postimage would be
available in such a case. However, this was not useful when the
recipient of such a patch via e-mail were to apply it, even if
the preimage was available.
This patch allows the diff to generate "binary" patch when
operating under --full-index option. The binary patch follows
the usual extended git diff headers, and looks like this:
"GIT binary patch\n"
<length byte><data>"\n"
...
"\n"
Each line is prefixed with a "length-byte", whose value is upper
or lowercase alphabet that encodes number of bytes that the data
on the line decodes to (1..52 -- 'A' means 1, 'B' means 2, ...,
'Z' means 26, 'a' means 27, ...). <data> is 1 or more groups of
5-byte sequence, each of which encodes up to 4 bytes in base85
encoding. Because 52 / 4 * 5 = 65 and we have the length byte,
an output line is capped to 66 characters. The payload is the
same diff-delta as we use in the packfiles.
On the consumption side, git-apply now can decode and apply the
binary patch when --allow-binary-replacement is given, the diff
was generated with --full-index, and the receiving repository
has the preimage blob, which is the same condition as it always
required when accepting an "Binary files differ\n" patch.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
Makefile | 2 -
apply.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++----------------
cache.h | 3 +
diff.c | 106 ++++++++++++++++++++++++++--
4 files changed, 275 insertions(+), 68 deletions(-)
diff --git a/Makefile b/Makefile
index a3f7e92..b6be520 100644
--- a/Makefile
+++ b/Makefile
@@ -205,7 +205,7 @@ DIFF_OBJS = \
diffcore-delta.o log-tree.o
LIB_OBJS = \
- blob.o commit.o connect.o csum-file.o \
+ blob.o commit.o connect.o csum-file.o base85.o \
date.o diff-delta.o entry.o exec_cmd.o ident.o index.o \
object.o pack-check.o patch-delta.o path.o pkt-line.o \
quote.o read-cache.o refs.o run-command.o \
diff --git a/apply.c b/apply.c
index 269210a..e37c4eb 100644
--- a/apply.c
+++ b/apply.c
@@ -10,6 +10,7 @@ #include <fnmatch.h>
#include "cache.h"
#include "quote.h"
#include "blob.h"
+#include "delta.h"
// --check turns on checking that the working tree matches the
// files that are being modified, but doesn't apply the patch
@@ -966,6 +967,70 @@ static inline int metadata_changes(struc
patch->old_mode != patch->new_mode);
}
+static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
+{
+ /* We have read "GIT binary patch\n"; what follows is a
+ * sequence of 'length-byte' followed by base-85 encoded
+ * delta data.
+ *
+ * Each 5-byte sequence of base-85 encodes up to 4 bytes,
+ * and we would limit the patch line to 66 characters,
+ * so one line can fit up to 13 groups that would decode
+ * to 52 bytes max. The length byte 'A'-'Z' corresponds
+ * to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes.
+ * The end of binary is signalled with an empty line.
+ */
+ int llen, used;
+ struct fragment *fragment;
+ char *delta = NULL;
+
+ patch->is_binary = 1;
+ patch->fragments = fragment = xcalloc(1, sizeof(*fragment));
+ used = 0;
+ while (1) {
+ int byte_length, max_byte_length, newsize;
+ llen = linelen(buffer, size);
+ used += llen;
+ linenr++;
+ if (llen == 1)
+ break;
+ /* Minimum line is "A00000\n" which is 7-byte long,
+ * and the line length must be multiple of 5 plus 2.
+ */
+ if ((llen < 7) || (llen-2) % 5)
+ goto corrupt;
+ max_byte_length = (llen - 2) / 5 * 4;
+ byte_length = *buffer;
+ if ('A' <= byte_length && byte_length <= 'Z')
+ byte_length = byte_length - 'A' + 1;
+ else if ('a' <= byte_length && byte_length <= 'z')
+ byte_length = byte_length - 'a' + 27;
+ else
+ goto corrupt;
+ /* if the input length was not multiple of 4, we would
+ * have filler at the end but the filler should never
+ * exceed 3 bytes
+ */
+ if (max_byte_length < byte_length ||
+ byte_length <= max_byte_length - 4)
+ goto corrupt;
+ newsize = fragment->size + byte_length;
+ delta = xrealloc(delta, newsize);
+ if (decode_85(delta + fragment->size,
+ buffer + 1,
+ byte_length))
+ goto corrupt;
+ fragment->size = newsize;
+ buffer += llen;
+ size -= llen;
+ }
+ fragment->patch = delta;
+ return used;
+ corrupt:
+ return error("corrupt binary patch at line %d: %.*s",
+ linenr-1, llen-1, buffer);
+}
+
static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
{
int hdrsize, patchsize;
@@ -982,19 +1047,34 @@ static int parse_chunk(char *buffer, uns
"Files ",
NULL,
};
+ static const char git_binary[] = "GIT binary patch\n";
int i;
int hd = hdrsize + offset;
unsigned long llen = linelen(buffer + hd, size - hd);
- if (!memcmp(" differ\n", buffer + hd + llen - 8, 8))
+ if (llen == sizeof(git_binary) - 1 &&
+ !memcmp(git_binary, buffer + hd, llen)) {
+ int used;
+ linenr++;
+ used = parse_binary(buffer + hd + llen,
+ size - hd - llen, patch);
+ if (used)
+ patchsize = used + llen;
+ else
+ patchsize = 0;
+ }
+ else if (!memcmp(" differ\n", buffer + hd + llen - 8, 8)) {
for (i = 0; binhdr[i]; i++) {
int len = strlen(binhdr[i]);
if (len < size - hd &&
!memcmp(binhdr[i], buffer + hd, len)) {
+ linenr++;
patch->is_binary = 1;
+ patchsize = llen;
break;
}
}
+ }
/* Empty patch cannot be applied if:
* - it is a binary patch and we do not do binary_replace, or
@@ -1345,76 +1425,108 @@ #endif
return offset;
}
-static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
+static int apply_binary(struct buffer_desc *desc, struct patch *patch)
{
- struct fragment *frag = patch->fragments;
const char *name = patch->old_name ? patch->old_name : patch->new_name;
+ unsigned char sha1[20];
+ unsigned char hdr[50];
+ int hdrlen;
- if (patch->is_binary) {
- unsigned char sha1[20];
+ if (!allow_binary_replacement)
+ return error("cannot apply binary patch to '%s' "
+ "without --allow-binary-replacement",
+ name);
- if (!allow_binary_replacement)
- return error("cannot apply binary patch to '%s' "
- "without --allow-binary-replacement",
- name);
+ /* For safety, we require patch index line to contain
+ * full 40-byte textual SHA1 for old and new, at least for now.
+ */
+ if (strlen(patch->old_sha1_prefix) != 40 ||
+ strlen(patch->new_sha1_prefix) != 40 ||
+ get_sha1_hex(patch->old_sha1_prefix, sha1) ||
+ get_sha1_hex(patch->new_sha1_prefix, sha1))
+ return error("cannot apply binary patch to '%s' "
+ "without full index line", name);
- /* For safety, we require patch index line to contain
- * full 40-byte textual SHA1 for old and new, at least for now.
+ if (patch->old_name) {
+ /* See if the old one matches what the patch
+ * applies to.
*/
- if (strlen(patch->old_sha1_prefix) != 40 ||
- strlen(patch->new_sha1_prefix) != 40 ||
- get_sha1_hex(patch->old_sha1_prefix, sha1) ||
- get_sha1_hex(patch->new_sha1_prefix, sha1))
- return error("cannot apply binary patch to '%s' "
- "without full index line", name);
-
- if (patch->old_name) {
- unsigned char hdr[50];
- int hdrlen;
-
- /* See if the old one matches what the patch
- * applies to.
- */
- write_sha1_file_prepare(desc->buffer, desc->size,
- blob_type, sha1, hdr, &hdrlen);
- if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
- return error("the patch applies to '%s' (%s), "
- "which does not match the "
- "current contents.",
- name, sha1_to_hex(sha1));
- }
- else {
- /* Otherwise, the old one must be empty. */
- if (desc->size)
- return error("the patch applies to an empty "
- "'%s' but it is not empty", name);
- }
+ write_sha1_file_prepare(desc->buffer, desc->size,
+ blob_type, sha1, hdr, &hdrlen);
+ if (strcmp(sha1_to_hex(sha1), patch->old_sha1_prefix))
+ return error("the patch applies to '%s' (%s), "
+ "which does not match the "
+ "current contents.",
+ name, sha1_to_hex(sha1));
+ }
+ else {
+ /* Otherwise, the old one must be empty. */
+ if (desc->size)
+ return error("the patch applies to an empty "
+ "'%s' but it is not empty", name);
+ }
+
+ if (desc->buffer) {
+ free(desc->buffer);
+ desc->alloc = desc->size = 0;
+ }
+ get_sha1_hex(patch->new_sha1_prefix, sha1);
+ if (!memcmp(sha1, null_sha1, 20))
+ return 0; /* deletion patch */
+
+ if (has_sha1_file(sha1)) {
+ char type[10];
+ unsigned long size;
- /* For now, we do not record post-image data in the patch,
- * and require the object already present in the recipient's
- * object database.
+ desc->buffer = read_sha1_file(sha1, type, &size);
+ if (!desc->buffer)
+ return error("the necessary postimage %s for "
+ "'%s' cannot be read",
+ patch->new_sha1_prefix, name);
+ desc->alloc = desc->size = size;
+ }
+ else {
+ char type[10];
+ unsigned long src_size, dst_size;
+ void *src;
+
+ get_sha1_hex(patch->old_sha1_prefix, sha1);
+ src = read_sha1_file(sha1, type, &src_size);
+ if (!src)
+ return error("the necessary preimage %s for "
+ "'%s' cannot be read",
+ patch->old_sha1_prefix, name);
+
+ /* patch->fragment->patch has the delta data and
+ * we should apply it to the preimage.
*/
- if (desc->buffer) {
- free(desc->buffer);
- desc->alloc = desc->size = 0;
- }
- get_sha1_hex(patch->new_sha1_prefix, sha1);
-
- if (memcmp(sha1, null_sha1, 20)) {
- char type[10];
- unsigned long size;
-
- desc->buffer = read_sha1_file(sha1, type, &size);
- if (!desc->buffer)
- return error("the necessary postimage %s for "
- "'%s' does not exist",
- patch->new_sha1_prefix, name);
- desc->alloc = desc->size = size;
- }
+ desc->buffer = patch_delta(src, src_size,
+ (void*) patch->fragments->patch,
+ patch->fragments->size,
+ &dst_size);
+ if (!desc->buffer)
+ return error("binary patch does not apply to '%s'",
+ name);
+ desc->size = desc->alloc = dst_size;
- return 0;
+ /* verify that the result matches */
+ write_sha1_file_prepare(desc->buffer, desc->size, blob_type,
+ sha1, hdr, &hdrlen);
+ if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix))
+ return error("binary patch to '%s' creates incorrect result", name);
}
+ return 0;
+}
+
+static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
+{
+ struct fragment *frag = patch->fragments;
+ const char *name = patch->old_name ? patch->old_name : patch->new_name;
+
+ if (patch->is_binary)
+ return apply_binary(desc, patch);
+
while (frag) {
if (apply_one_fragment(desc, frag) < 0)
return error("patch failed: %s:%ld",
diff --git a/cache.h b/cache.h
index 9d0ddcf..2f32f3d 100644
--- a/cache.h
+++ b/cache.h
@@ -363,4 +363,7 @@ extern int receive_keep_pack(int fd[2],
/* pager.c */
extern void setup_pager(void);
+/* base85 */
+int decode_85(char *dst, char *line, int linelen);
+
#endif /* CACHE_H */
diff --git a/diff.c b/diff.c
index c845c87..b14d897 100644
--- a/diff.c
+++ b/diff.c
@@ -8,6 +8,7 @@ #include "cache.h"
#include "quote.h"
#include "diff.h"
#include "diffcore.h"
+#include "delta.h"
#include "xdiff-interface.h"
static int use_size_cache;
@@ -391,6 +392,90 @@ static void show_stats(struct diffstat_t
total_files, adds, dels);
}
+static void *encode_delta_size(void *data, unsigned long size)
+{
+ unsigned char *cp = data;
+ *cp++ = size;
+ size >>= 7;
+ while (size) {
+ cp[-1] |= 0x80;
+ *cp++ = size;
+ size >>= 7;
+ }
+ return cp;
+}
+
+static void *safe_diff_delta(const unsigned char *src, unsigned long src_size,
+ const unsigned char *dst, unsigned long dst_size,
+ unsigned long *delta_size)
+{
+ unsigned long bufsize;
+ unsigned char *data;
+ unsigned char *cp;
+
+ if (src_size && dst_size)
+ return diff_delta(src, src_size, dst, dst_size, delta_size, 0);
+
+ /* diff-delta does not like to do delta with empty, so
+ * we do that by hand here. Sigh...
+ */
+
+ if (!src_size)
+ /* literal copy can be done only 127-byte at a time.
+ */
+ bufsize = dst_size + (dst_size / 127) + 40;
+ else
+ bufsize = 40;
+ data = xmalloc(bufsize);
+ cp = encode_delta_size(data, src_size);
+ cp = encode_delta_size(cp, dst_size);
+
+ if (dst_size) {
+ /* copy out literally */
+ while (dst_size) {
+ int sz = (127 < dst_size) ? 127 : dst_size;
+ *cp++ = sz;
+ dst_size -= sz;
+ while (sz) {
+ *cp++ = *dst++;
+ sz--;
+ }
+ }
+ }
+ *delta_size = (cp - data);
+ return data;
+}
+
+static void emit_binary_diff(mmfile_t *one, mmfile_t *two)
+{
+ void *delta, *cp;
+ unsigned long delta_size;
+
+ printf("GIT binary patch\n");
+ delta = safe_diff_delta(one->ptr, one->size,
+ two->ptr, two->size,
+ &delta_size);
+ if (!delta)
+ die("unable to generate binary diff");
+
+ /* emit delta encoded in base85 */
+ cp = delta;
+ while (delta_size) {
+ int bytes = (52 < delta_size) ? 52 : delta_size;
+ char line[70];
+ delta_size -= bytes;
+ if (bytes <= 26)
+ line[0] = bytes + 'A' - 1;
+ else
+ line[0] = bytes - 26 + 'a' - 1;
+ encode_85(line + 1, cp, bytes);
+ cp += bytes;
+ puts(line);
+ }
+ printf("\n");
+ free(delta);
+}
+
#define FIRST_FEW_BYTES 8000
static int mmfile_is_binary(mmfile_t *mf)
{
@@ -407,6 +492,7 @@ static void builtin_diff(const char *nam
struct diff_filespec *one,
struct diff_filespec *two,
const char *xfrm_msg,
+ struct diff_options *o,
int complete_rewrite)
{
mmfile_t mf1, mf2;
@@ -451,8 +537,13 @@ static void builtin_diff(const char *nam
if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
die("unable to read files to diff");
- if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2))
- printf("Binary files %s and %s differ\n", lbl[0], lbl[1]);
+ if (mmfile_is_binary(&mf1) || mmfile_is_binary(&mf2)) {
+ if (o->full_index)
+ emit_binary_diff(&mf1, &mf2);
+ else
+ printf("Binary files %s and %s differ\n",
+ lbl[0], lbl[1]);
+ }
else {
/* Crazy xdl interfaces.. */
const char *diffopts = getenv("GIT_DIFF_OPTS");
@@ -928,6 +1019,7 @@ static void run_diff_cmd(const char *pgm
struct diff_filespec *one,
struct diff_filespec *two,
const char *xfrm_msg,
+ struct diff_options *o,
int complete_rewrite)
{
if (pgm) {
@@ -937,7 +1029,7 @@ static void run_diff_cmd(const char *pgm
}
if (one && two)
builtin_diff(name, other ? other : name,
- one, two, xfrm_msg, complete_rewrite);
+ one, two, xfrm_msg, o, complete_rewrite);
else
printf("* Unmerged path %s\n", name);
}
@@ -971,7 +1063,7 @@ static void run_diff(struct diff_filepai
if (DIFF_PAIR_UNMERGED(p)) {
/* unmerged */
- run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, 0);
+ run_diff_cmd(pgm, p->one->path, NULL, NULL, NULL, NULL, o, 0);
return;
}
@@ -1041,14 +1133,14 @@ static void run_diff(struct diff_filepai
* needs to be split into deletion and creation.
*/
struct diff_filespec *null = alloc_filespec(two->path);
- run_diff_cmd(NULL, name, other, one, null, xfrm_msg, 0);
+ run_diff_cmd(NULL, name, other, one, null, xfrm_msg, o, 0);
free(null);
null = alloc_filespec(one->path);
- run_diff_cmd(NULL, name, other, null, two, xfrm_msg, 0);
+ run_diff_cmd(NULL, name, other, null, two, xfrm_msg, o, 0);
free(null);
}
else
- run_diff_cmd(pgm, name, other, one, two, xfrm_msg,
+ run_diff_cmd(pgm, name, other, one, two, xfrm_msg, o,
complete_rewrite);
free(name_munged);
--
1.3.1.g25a9
^ permalink raw reply related
* Bad error message
From: Robin Rosenberg (list subscriber) @ 2006-05-04 23:57 UTC (permalink / raw)
To: git
Hi,
While playing with git I got the following "impossible" error message:
$ git commit --amend
fatal: Ref HEAD is at 3cec3036287d6b24f7ad7f724f8bb9d4032fb1a3 but expected
3cec3036287d6b24f7ad7f724f8bb9d4032fb1a3
Since impossible things happen rarely, I was somewhat puzzled and it turned
out not to be so impossible after all, but a rather typical C bug. Since I
fixed my working directory using git-reset, I'm not sure how to verify the
code (suggestions welcome), but I'm not sure if that's important since the
code being replaced by this patch probably wasn't tested either. :/
Maybe someone could explain what might have been wrong with my work space (git
status turned up nothing wrong or missing).
-- robin
--- git-1.3.1.orig/update-ref.c 2006-04-25 08:07:54.000000000 +0200
+++ git-1.3.1/update-ref.c 2006-05-04 16:30:04.000000000 +0200
@@ -43,8 +43,13 @@
die("No such ref: %s", refname);
if (oldval) {
- if (memcmp(currsha1, oldsha1, 20))
- die("Ref %s is at %s but expected %s", refname, sha1_to_hex(currsha1), sha1_to_hex(oldsha1));
+ if (memcmp(currsha1, oldsha1, 20)) {
+ char sha1str1[41];
+ char sha1str2[41];
+ strcpy(sha1str1, sha1_to_hex(currsha1));
+ strcpy(sha1str2, sha1_to_hex(oldsha1));
+ die("Ref %s is at %s but expected %s", refname, sha1str1, sha1str2);
+ }
/* Nothing to do? */
if (!memcmp(oldsha1, sha1, 20))
exit(0);
^ permalink raw reply
* Re: [PATCH] Teach fmt-patch to write individual files.
From: Junio C Hamano @ 2006-05-05 0:09 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0605050115440.12795@wbgn013.biozentrum.uni-wuerzburg.de>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> When called with "--stdout", it still writes to standard output.
>
> Notable differences to git-format-patch:
>
> - since fmt-patch uses the standardized logging machinery, it is
> no longer "From nobody", but "From <commit_sha1>",
Yes, and the date on that UNIX-From line has been updated ;-).
> - the empty lines before and after the "---" just before the
> diffstat are no longer there,
Personally, I find this the most annoying myself. I am not
complaining to you because as you know you inherited this
behaviour from my code.
> - git-format-patch outputs the commit_sha1 just before the first
> diff, which fmt-patch does not,
Which should be fine.
> - the file names are no longer output to stdout, but to stderr
> (since stdout is freopen()ed all the time), and
Which might be a bigger deal; I suspect people capture that while
dumping patches into individual files, and do their
postprocessing using the list of filenames.
> - "git fmt-patch HEAD^" does not work as expected: it outputs
> *all* commits reachable from HEAD^!
If we really wanted to handle this, you could do something like
what builtin-diff does before letting the revision machinery
start walking the revision tree. Look at pending objects, and
if you find only one UNINTERESTING commit, add_object the
current HEAD there as well. Personally I do not think it is
worth it; rather we would probably want to standardize on rev-list
syntax.
Two major differences you forgot to mention.
One is that it does not do the "git cherry" filtering. It is
not a big deal for me personally, but some people may be
depending on it. I dunno.
Another is -o outdir, which should be trivial to add once you
have implemented output switching with freopen().
Anyhow, thanks for starting this.
^ permalink raw reply
* Re: Bad error message
From: Junio C Hamano @ 2006-05-05 0:20 UTC (permalink / raw)
To: Robin Rosenberg (list subscriber); +Cc: git
In-Reply-To: <200605041957.26194.robin.rosenberg.lists@dewire.com>
"Robin Rosenberg (list subscriber)" <robin.rosenberg.lists@dewire.com> writes:
> @@ -43,8 +43,13 @@
> die("No such ref: %s", refname);
>
> if (oldval) {
> - if (memcmp(currsha1, oldsha1, 20))
> - die("Ref %s is at %s but expected %s", refname, sha1_to_hex(currsha1), sha1_to_hex(oldsha1));
> + if (memcmp(currsha1, oldsha1, 20)) {
> + char sha1str1[41];
> + char sha1str2[41];
> + strcpy(sha1str1, sha1_to_hex(currsha1));
> + strcpy(sha1str2, sha1_to_hex(oldsha1));
> + die("Ref %s is at %s but expected %s", refname, sha1str1, sha1str2);
> + }
Your patch looks correct, but probably is made unnecessary with
the "you can use up to 4 sha1_to_hex() safely" patch Linus did.
We have it in "master" and my plan is to cherry-pick it to
"maint" branch and included it in the next stale release 1.3.3,
along with core.prefersymlinkrefs patch also only in "master",
if we do not hear somebody scream in the next few days.
^ permalink raw reply
* Re: Unresolved issues #2 (shallow clone again)
From: Junio C Hamano @ 2006-05-05 0:25 UTC (permalink / raw)
To: Carl Worth; +Cc: git
In-Reply-To: <87mzdx7mh9.wl%cworth@cworth.org>
Carl Worth <cworth@cworth.org> writes:
> ... So the conversation changes from "I WANT
> <fetch-heads> and I HAVE <heads>" to one of "I WANT <fetch-heads>, and
> I HAVE <heads>, except that I'm MISSING <cauterized-commits>".
>
> Finally, whenever a fetch receives an commit object that is in its
> list of cauterized commits, it should remove that commit from the
> list. This allows a shallow clone to be naturally migrated to
> something unshallow. And the user can do this as incrementally as
> desired based on the need to see more history:
>
> get a bit:
> git fetch somewhere --since=2.weeks.ago
>
> then a bit more:
> git fetch somewhere --since=1.year.ago
>
> then get it all:
> git fetch somewhere
>
> Maybe that's no different from Junio's original proposal. If not, what
> do you see in the above that wouldn't work?
Lack of actual code to do all that ;-)
Jokes aside, I think listing the updated conversation elements
like you did above is a good step forward.
The vocabulary we would want from the requestor side is probably
(at least):
I WANT to have these
I HAVE these
I'm MISSING these
Don't bother with these this time around (--since, ^v2.6.16, ...)
I am not sure how we would want to encode the last one and have
it used by rev-list on the upload-pack end safely and sanely.
And the responder side needs to be able to say, "Now you are
MISSING these, remember it and tell me you are missing them next
time you make a request". That would be, in the simplest case,
a list of commit IDs to cauterize, but I am not sure what is the
right way to come up with that list. Especially I do not know
if --boundary would/should work with --objects.
^ permalink raw reply
* Re: [PATCH] Teach fmt-patch to write individual files.
From: Johannes Schindelin @ 2006-05-05 0:56 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vhd452uzn.fsf@assigned-by-dhcp.cox.net>
Hi,
On Thu, 4 May 2006, Junio C Hamano wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>
> > When called with "--stdout", it still writes to standard output.
> >
> > Notable differences to git-format-patch:
> >
> > - since fmt-patch uses the standardized logging machinery, it is
> > no longer "From nobody", but "From <commit_sha1>",
>
> Yes, and the date on that UNIX-From line has been updated ;-).
Right.
> > - the empty lines before and after the "---" just before the
> > diffstat are no longer there,
>
> Personally, I find this the most annoying myself. I am not
> complaining to you because as you know you inherited this
> behaviour from my code.
How about this?
-- snip --
diff --git a/log-tree.c b/log-tree.c
index d92abaf..6379d43 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -86,7 +86,7 @@ int log_tree_diff_flush(struct rev_info
}
if (opt->loginfo && !opt->no_commit_id)
- show_log(opt, opt->loginfo, opt->diffopt.with_stat ? "---\n" : "\n");
+ show_log(opt, opt->loginfo, opt->diffopt.with_stat ? "\n---\n\n" : "\n");
diff_flush(&opt->diffopt);
return 1;
}
-- snap --
> > - git-format-patch outputs the commit_sha1 just before the first
> > diff, which fmt-patch does not,
>
> Which should be fine.
Yeah, I just wanted to mention it in case people rely on it.
> > - the file names are no longer output to stdout, but to stderr
> > (since stdout is freopen()ed all the time), and
>
> Which might be a bigger deal; I suspect people capture that while
> dumping patches into individual files, and do their
> postprocessing using the list of filenames.
I hoped it is not necessary to "FILE *realstdout = fdopen(dup(1));" but I
can do it if this is wanted.
> > - "git fmt-patch HEAD^" does not work as expected: it outputs
> > *all* commits reachable from HEAD^!
>
> If we really wanted to handle this, you could do something like
> what builtin-diff does before letting the revision machinery
> start walking the revision tree. Look at pending objects, and
> if you find only one UNINTERESTING commit, add_object the
> current HEAD there as well. Personally I do not think it is
> worth it; rather we would probably want to standardize on rev-list
> syntax.
Well, I have to get used to add ".." after HEAD^, but that is probably not
very difficult. I would like fmt-patch to error out without a range,
though.
> Two major differences you forgot to mention.
>
> One is that it does not do the "git cherry" filtering. It is
> not a big deal for me personally, but some people may be
> depending on it. I dunno.
Oops. I really did not think of that.
> Another is -o outdir, which should be trivial to add once you
> have implemented output switching with freopen().
Yes, this becomes easy now. I'll do that next.
Ciao,
Dscho
^ permalink raw reply related
* Re: [ANNOUNCE] Git wiki
From: linux @ 2006-05-05 0:56 UTC (permalink / raw)
To: git; +Cc: linux
Actually, AFAICT from looking at the mailing list history, it's not dirty
politics: the tie-breaker was the support and enthusiasm of the mercurial
developers. It passed with only minor comment on the git mailing list,
but it was a Big Thing to the hg folks.
There are ups and downs. OpenSolaris is definitely the big fish in
the mercurial pond (that wasn't *meant* to sound like a recipe for
heavy metal toxicity), and will get lots of attention, but git has more
real-world experience. The big fish in the git pond is Linus and Linux.
In any case, mercurial and git are really very similar, far closer
to each other than any third system, so it's not like the decision is
a descent into heresy. Hopefully some useful cross-pollination
can occur, and converting history from one to the other would be
simple if anyone ever wanted to.
As for explicit renames, people are confused on the subject.
IMHO, the two most revolutionary things about git are:
- Finally, a complete break from file-oriented history. History is made
of trees, and trees are made of files. There is no direct connection
between files in different commits.
- An explicit representation of an in-progress merge.
This is what makes multiple merge strategies easily implementable.
Third, I suppose, is the raw diff format and the diffcore pipeline.
But finally getting away from the SCCS & RCS idea that the file is the
unit of history is one of git's Great Features, and it shouldn't be
thrown away.
What people who are asking for explicit rename tracking actually want
is automatic rename merging. If branch A renames a file, and branch B
corrects a typo on a comment somewhere, they'd like the merge to
both patch and rename the file. If you can do that, you have met the
need, even if your solution isn't the one the feature requester
imagined.
(This is the general consulting problem: a client calls when they've
been trying a solution and can't get past some problem. Usually, this
is because they've wandered into a blind alley, and what they're asking
for is either far more difficult than necessary, or will just lead them
into greater problems. The first thing you have to determine is what
they actually want to do, as distinct from how they've decided to do it.)
But, as Linus has pointed out, this is a very partial solution which
introduces a lot of difficulties elsewhere. File renaming is a subset of
the general class of code reorganizations. Source files will be split,
merged, and have functions moved back and forth. You want the patch to
find the code it applies to even if that code was moved.
And that can be done by taking a more global view of the patch.
Identical file names is only a heuristic. If the hunk on branch A
can't find a place to apply on the same file in branch B, then
you have to look a little harder, either at changes from branch B
that introduce matching code elsewhere, or perhaps looking
through history for a change that removed the match from the
obvious place to see if it added a match elsewhere.
The one thing that makes this difficult is git-read-tree's automatic
collapse of "trivial" merges. If branch B moves foo() unchanged from
x.c to y.c, while branch A doesn't touch y.c, but edits foo() in x.c,
git-read-tree will collapse the changes to y.c before even invoking
the advanced resolve script.
(The solution might be to keep *four* versions of the file in the index:
the three pre-merge, *and* the post-merge. Then git-write-tree makes
sure everything has a stage 0 entry and strips out the stage 1, 2 and
3 entries. This way, one merge algorithm can use another as a
subroutine but decide not to accept something it did.)
But anyway, it's the merging that's the desired feature. Explicitly
recording renames is only the means to that end, and is superfluous
if there's another way of getting there. (And the place to look for
interesting new ideas in that area Darcs.)
^ permalink raw reply
* [PATCH] fmt-patch: output file names to stdout
From: Johannes Schindelin @ 2006-05-05 1:33 UTC (permalink / raw)
To: git, junkio
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
builtin-log.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/builtin-log.c b/builtin-log.c
index 576703c..1649f49 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -75,6 +75,8 @@ static int istitlechar(char c)
(c >= '0' && c <= '9') || c == '.' || c == '_';
}
+static FILE *realstdout = NULL;
+
static void reopen_stdout(struct commit *commit, int nr)
{
char filename[1024];
@@ -117,7 +119,7 @@ static void reopen_stdout(struct commit
len--;
}
strcpy(filename + len, ".txt");
- fprintf(stderr, "%s\n", filename);
+ fprintf(realstdout, "%s\n", filename);
freopen(filename, "w", stdout);
}
@@ -149,6 +151,9 @@ int cmd_format_patch(int argc, const cha
argv++;
}
+ if (!use_stdout)
+ realstdout = fdopen(dup(1), "w");
+
prepare_revision_walk(&rev);
while ((commit = get_revision(&rev)) != NULL) {
/* ignore merges */
--
1.3.1.g6d0e-dirty
^ permalink raw reply related
* [PATCH] fmt-patch: implement -o <dir>
From: Johannes Schindelin @ 2006-05-05 1:33 UTC (permalink / raw)
To: git, junkio
I had to move the command line parsing around a little; setup_revisions()
could mistaken <dir> for a valid ref.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
builtin-log.c | 44 ++++++++++++++++++++++++++++++++++----------
1 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/builtin-log.c b/builtin-log.c
index 1649f49..53a47c9 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -76,15 +76,22 @@ static int istitlechar(char c)
}
static FILE *realstdout = NULL;
+static char *output_directory = NULL;
static void reopen_stdout(struct commit *commit, int nr)
{
char filename[1024];
char *sol;
- int len;
+ int len = 0;
+ if (output_directory) {
+ strncpy(filename, output_directory, 1010);
+ len = strlen(filename);
+ if (filename[len - 1] != '/')
+ filename[len++] = '/';
+ }
- sprintf(filename, "%04d", nr);
+ sprintf(filename + len, "%04d", nr);
len = strlen(filename);
sol = strstr(commit->buffer, "\n\n");
@@ -128,7 +135,7 @@ int cmd_format_patch(int argc, const cha
struct commit *commit;
struct commit **list = NULL;
struct rev_info rev;
- int nr = 0, total;
+ int nr = 0, total, i, j;
int use_stdout = 0;
init_revisions(&rev);
@@ -140,16 +147,31 @@ int cmd_format_patch(int argc, const cha
rev.combine_merges = 0;
rev.ignore_merges = 1;
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
- argc = setup_revisions(argc, argv, &rev, "HEAD");
- while (argc > 1) {
- if (!strcmp(argv[1], "--stdout"))
+ /*
+ * Parse the arguments before setup_revisions(), or something
+ * like "git fmt-patch -o a123 HEAD^.." may fail; a123 is
+ * possibly a valid SHA1.
+ */
+ for (i = 1, j = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "--stdout"))
use_stdout = 1;
- else
- die ("unrecognized argument: %s", argv[1]);
- argc--;
- argv++;
+ else if (!strcmp(argv[i], "-o")) {
+ if (argc < 3)
+ die ("Which directory?");
+ if (mkdir(argv[i + 1], 0777) < 0 && errno != EEXIST)
+ die("Could not create directory %s",
+ argv[i + 1]);
+ output_directory = strdup(argv[i + 1]);
+ i++;
+ } else
+ argv[j++] = argv[i];
}
+ argc = j;
+
+ argc = setup_revisions(argc, argv, &rev, "HEAD");
+ if (argc > 1)
+ die ("unrecognized argument: %s", argv[1]);
if (!use_stdout)
realstdout = fdopen(dup(1), "w");
@@ -177,6 +199,8 @@ int cmd_format_patch(int argc, const cha
if (!use_stdout)
fclose(stdout);
}
+ if (output_directory)
+ free(output_directory);
free(list);
return 0;
}
--
1.3.1.g6d0e-dirty
^ permalink raw reply related
* [PATCH] Teach fmt-patch about --numbered
From: Johannes Schindelin @ 2006-05-05 2:30 UTC (permalink / raw)
To: git, junkio
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
builtin-log.c | 9 ++++++++-
commit.c | 5 +----
commit.h | 2 +-
log-tree.c | 15 ++++++++++++---
rev-list.c | 2 +-
revision.h | 1 +
show-branch.c | 2 +-
7 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/builtin-log.c b/builtin-log.c
index 53a47c9..43c7ecd 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -137,6 +137,7 @@ int cmd_format_patch(int argc, const cha
struct rev_info rev;
int nr = 0, total, i, j;
int use_stdout = 0;
+ int numbered = 0;
init_revisions(&rev);
rev.commit_format = CMIT_FMT_EMAIL;
@@ -156,6 +157,9 @@ int cmd_format_patch(int argc, const cha
for (i = 1, j = 1; i < argc; i++) {
if (!strcmp(argv[i], "--stdout"))
use_stdout = 1;
+ else if (!strcmp(argv[i], "-n") ||
+ !strcmp(argv[i], "--numbered"))
+ numbered = 1;
else if (!strcmp(argv[i], "-o")) {
if (argc < 3)
die ("Which directory?");
@@ -186,11 +190,14 @@ int cmd_format_patch(int argc, const cha
list[nr - 1] = commit;
}
total = nr;
+ if (numbered)
+ rev.total = total;
while (0 <= --nr) {
int shown;
commit = list[nr];
+ rev.nr = total - nr;
if (!use_stdout)
- reopen_stdout(commit, total - nr);
+ reopen_stdout(commit, rev.nr);
shown = log_tree_commit(&rev, commit);
free(commit->buffer);
commit->buffer = NULL;
diff --git a/commit.c b/commit.c
index 42b44bb..93b3903 100644
--- a/commit.c
+++ b/commit.c
@@ -489,17 +489,14 @@ static int add_merge_info(enum cmit_fmt
return offset;
}
-unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, unsigned long len, char *buf, unsigned long space, int abbrev)
+unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject)
{
int hdr = 1, body = 0;
unsigned long offset = 0;
int indent = 4;
int parents_shown = 0;
const char *msg = commit->buffer;
- const char *subject = NULL;
- if (fmt == CMIT_FMT_EMAIL)
- subject = "Subject: [PATCH] ";
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
indent = 0;
diff --git a/commit.h b/commit.h
index 01eec60..8d7514c 100644
--- a/commit.h
+++ b/commit.h
@@ -51,7 +51,7 @@ enum cmit_fmt {
};
extern enum cmit_fmt get_commit_format(const char *arg);
-extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev);
+extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject);
/** Removes the first commit from a list sorted by date, and adds all
* of its parents.
diff --git a/log-tree.c b/log-tree.c
index d92abaf..cec7068 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -20,6 +20,7 @@ void show_log(struct rev_info *opt, stru
int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40;
const char *extra;
int len;
+ char* subject = NULL;
opt->loginfo = NULL;
if (!opt->verbose_header) {
@@ -50,10 +51,18 @@ void show_log(struct rev_info *opt, stru
* Print header line of header..
*/
- if (opt->commit_format == CMIT_FMT_EMAIL)
+ if (opt->commit_format == CMIT_FMT_EMAIL) {
+ if (opt->total > 0) {
+ static char buffer[64];
+ snprintf(buffer, sizeof(buffer),
+ "Subject: [PATCH %d/%d] ",
+ opt->nr, opt->total);
+ subject = buffer;
+ } else
+ subject = "Subject: [PATCH] ";
printf("From %s Thu Apr 7 15:13:13 2005\n",
sha1_to_hex(commit->object.sha1));
- else {
+ } else {
printf("%s%s",
opt->commit_format == CMIT_FMT_ONELINE ? "" : "commit ",
diff_unique_abbrev(commit->object.sha1, abbrev_commit));
@@ -69,7 +78,7 @@ void show_log(struct rev_info *opt, stru
/*
* And then the pretty-printed message itself
*/
- len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header, sizeof(this_header), abbrev);
+ len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header, sizeof(this_header), abbrev, subject);
printf("%s%s%s", this_header, extra, sep);
}
diff --git a/rev-list.c b/rev-list.c
index 89b3343..347f627 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -83,7 +83,7 @@ static void show_commit(struct commit *c
static char pretty_header[16384];
pretty_print_commit(revs.commit_format, commit, ~0,
pretty_header, sizeof(pretty_header),
- revs.abbrev);
+ revs.abbrev, NULL);
printf("%s%c", pretty_header, hdr_termination);
}
fflush(stdout);
diff --git a/revision.h b/revision.h
index 48d7b4c..62759f7 100644
--- a/revision.h
+++ b/revision.h
@@ -58,6 +58,7 @@ struct rev_info {
unsigned int abbrev;
enum cmit_fmt commit_format;
struct log_info *loginfo;
+ int nr, total;
/* special limits */
int max_count;
diff --git a/show-branch.c b/show-branch.c
index 268c57b..bbe26c2 100644
--- a/show-branch.c
+++ b/show-branch.c
@@ -259,7 +259,7 @@ static void show_one_commit(struct commi
struct commit_name *name = commit->object.util;
if (commit->object.parsed)
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
- pretty, sizeof(pretty), 0);
+ pretty, sizeof(pretty), 0, NULL);
else
strcpy(pretty, "(unavailable)");
if (!strncmp(pretty, "[PATCH] ", 8))
--
1.3.1.g5f039
^ permalink raw reply related
* [PATCH] Teach fmt-patch about --keep-subject
From: Johannes Schindelin @ 2006-05-05 2:31 UTC (permalink / raw)
To: git, junkio
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
builtin-log.c | 16 ++++++++++++----
log-tree.c | 5 ++++-
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/builtin-log.c b/builtin-log.c
index 43c7ecd..0027998 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -78,7 +78,7 @@ static int istitlechar(char c)
static FILE *realstdout = NULL;
static char *output_directory = NULL;
-static void reopen_stdout(struct commit *commit, int nr)
+static void reopen_stdout(struct commit *commit, int nr, int keep_subject)
{
char filename[1024];
char *sol;
@@ -100,7 +100,7 @@ static void reopen_stdout(struct commit
sol += 2;
/* strip [PATCH] or [PATCH blabla] */
- if (!strncmp(sol, "[PATCH", 6)) {
+ if (!keep_subject && !strncmp(sol, "[PATCH", 6)) {
char *eos = strchr(sol + 6, ']');
if (eos) {
while (isspace(*eos))
@@ -138,6 +138,7 @@ int cmd_format_patch(int argc, const cha
int nr = 0, total, i, j;
int use_stdout = 0;
int numbered = 0;
+ int keep_subject = 0;
init_revisions(&rev);
rev.commit_format = CMIT_FMT_EMAIL;
@@ -160,7 +161,11 @@ int cmd_format_patch(int argc, const cha
else if (!strcmp(argv[i], "-n") ||
!strcmp(argv[i], "--numbered"))
numbered = 1;
- else if (!strcmp(argv[i], "-o")) {
+ else if (!strcmp(argv[i], "-k") ||
+ !strcmp(argv[i], "--keep-subject")) {
+ keep_subject = 1;
+ rev.total = -1;
+ } else if (!strcmp(argv[i], "-o")) {
if (argc < 3)
die ("Which directory?");
if (mkdir(argv[i + 1], 0777) < 0 && errno != EEXIST)
@@ -173,6 +178,9 @@ int cmd_format_patch(int argc, const cha
}
argc = j;
+ if (numbered && keep_subject < 0)
+ die ("-n and -k are mutually exclusive.");
+
argc = setup_revisions(argc, argv, &rev, "HEAD");
if (argc > 1)
die ("unrecognized argument: %s", argv[1]);
@@ -197,7 +205,7 @@ int cmd_format_patch(int argc, const cha
commit = list[nr];
rev.nr = total - nr;
if (!use_stdout)
- reopen_stdout(commit, rev.nr);
+ reopen_stdout(commit, rev.nr, keep_subject);
shown = log_tree_commit(&rev, commit);
free(commit->buffer);
commit->buffer = NULL;
diff --git a/log-tree.c b/log-tree.c
index cec7068..526d578 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -58,8 +58,11 @@ void show_log(struct rev_info *opt, stru
"Subject: [PATCH %d/%d] ",
opt->nr, opt->total);
subject = buffer;
- } else
+ } else if (opt->total == 0)
subject = "Subject: [PATCH] ";
+ else
+ subject = "Subject: ";
+
printf("From %s Thu Apr 7 15:13:13 2005\n",
sha1_to_hex(commit->object.sha1));
} else {
--
1.3.1.g5f039
^ permalink raw reply related
* Re: [PATCH] binary patch.
From: Nicolas Pitre @ 2006-05-05 2:47 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vodyd2vqn.fsf@assigned-by-dhcp.cox.net>
On Thu, 4 May 2006, Junio C Hamano wrote:
> This adds "binary patch" to the diff output and teaches apply
> what to do with them.
This is nice.
However I'd deflate the delta data before encoding it with base85.
Nicolas
^ permalink raw reply
* Re: Unresolved issues #2 (shallow clone again)
From: Martin Langhoff @ 2006-05-05 5:17 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Carl Worth, git
In-Reply-To: <7v1wv92u7o.fsf@assigned-by-dhcp.cox.net>
On 5/5/06, Junio C Hamano <junkio@cox.net> wrote:
> The vocabulary we would want from the requestor side is probably
> (at least):
>
> I WANT to have these
> I HAVE these
> I'm MISSING these
> Don't bother with these this time around (--since, ^v2.6.16, ...)
Thinking... does the MISSING part matter at all? It seems that what
really matters are the "ignore rules". The pull may bring in a new
merge of a long-running branch, whose mergebase falls out of the
ignore rules.
In that case, the server should apply the ignore rules. Except that
later merges in the local repo would perhaps have to deal with missing
part of the history. I suspect it should refuse to merge something we
don't have all the merging parts for.
cheers,
martin
^ permalink raw reply
* Re: Unresolved issues #2 (shallow clone again)
From: Carl Worth @ 2006-05-05 5:23 UTC (permalink / raw)
To: Martin Langhoff; +Cc: Junio C Hamano, git
In-Reply-To: <46a038f90605042217n3261b14cxd63f35a31223848e@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1119 bytes --]
On Fri, 5 May 2006 17:17:10 +1200, "Martin Langhoff" wrote:
> > I WANT to have these
> > I HAVE these
> > I'm MISSING these
> > Don't bother with these this time around (--since, ^v2.6.16, ...)
>
> Thinking... does the MISSING part matter at all?
Yes.
Imagine doing a shallow clone and then fetching a tree that includes a
blob that existed before MISSING. If we say HAVE without MISSING then
the server will not send that blob and we'll be left with a broken
tree.
> In that case, the server should apply the ignore rules. Except that
> later merges in the local repo would perhaps have to deal with missing
> part of the history. I suspect it should refuse to merge something we
> don't have all the merging parts for.
Yeah, shallow clones can shake up the conventions a bit. It's
definitely common for a repository to only have a single parent-less
commit, such that there is always an identifiable merge base for any
pair of revisions. Shallow clones would make (effectively) parent-less
commits much more common.
Should be fun to see what things fall over with this...
-Carl
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: Unresolved issues #2 (shallow clone again)
From: Jakub Narebski @ 2006-05-05 5:48 UTC (permalink / raw)
To: git
In-Reply-To: <87bqud6o4p.wl%cworth@cworth.org>
Carl Worth wrote:
> On Fri, 5 May 2006 17:17:10 +1200, "Martin Langhoff" wrote:
>> In that case, the server should apply the ignore rules. Except that
>> later merges in the local repo would perhaps have to deal with missing
>> part of the history. I suspect it should refuse to merge something we
>> don't have all the merging parts for.
>
> Yeah, shallow clones can shake up the conventions a bit. It's
> definitely common for a repository to only have a single parent-less
> commit, such that there is always an identifiable merge base for any
> pair of revisions. Shallow clones would make (effectively) parent-less
> commits much more common.
I wonder if it would be possible for git to:
a) as for a fetch which would bring all the commits up to the merge base
(and merge base has to be calculated on the server side I think),
i.e. give command to use (for fetch or for force baseless merge)
b) fetch the commits
c) do merge
d) optionally re-cauterize history again
--
Jakub Narebski
Warsaw, Poland
^ permalink raw reply
* Re: [ANNOUNCE] Git wiki
From: Fredrik Kuivinen @ 2006-05-05 6:22 UTC (permalink / raw)
To: linux; +Cc: git
In-Reply-To: <20060505005659.9092.qmail@science.horizon.com>
On Thu, May 04, 2006 at 08:56:59PM -0400, linux@horizon.com wrote:
> What people who are asking for explicit rename tracking actually want
> is automatic rename merging. If branch A renames a file, and branch B
> corrects a typo on a comment somewhere, they'd like the merge to
> both patch and rename the file. If you can do that, you have met the
> need, even if your solution isn't the one the feature requester
> imagined.
I don't know if you already know this, if you do it might be valuable
for other readers.
If the rename is detected by the current rename detection code
(git-diff-tree -M) then the merge case described above is handled
perfectly fine by the current git. That is, the rename is followed and
the patch fixing the typo is applied to the renamed file. This assumes
that the default merge strategy (recursive) is used.
- Fredrik
^ permalink raw reply
* Re: [ANNOUNCE] Git wiki
From: Jakub Narebski @ 2006-05-05 6:26 UTC (permalink / raw)
To: git
In-Reply-To: <20060505062236.GA4544@c165.ib.student.liu.se>
Fredrik Kuivinen wrote:
> On Thu, May 04, 2006 at 08:56:59PM -0400, linux@horizon.com wrote:
>> What people who are asking for explicit rename tracking actually want
>> is automatic rename merging. If branch A renames a file, and branch B
>> corrects a typo on a comment somewhere, they'd like the merge to
>> both patch and rename the file. If you can do that, you have met the
>> need, even if your solution isn't the one the feature requester
>> imagined.
>
> I don't know if you already know this, if you do it might be valuable
> for other readers.
>
> If the rename is detected by the current rename detection code
> (git-diff-tree -M) then the merge case described above is handled
> perfectly fine by the current git. That is, the rename is followed and
> the patch fixing the typo is applied to the renamed file. This assumes
> that the default merge strategy (recursive) is used.
And if you do 'commit - rename, no changes - commit' sequence then rename
will be detected.
--
Jakub Narebski
Warsaw, Poland
^ 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