* [PATCH] git-svn: add a message encouraging use of SVN::* libraries
From: Eric Wong @ 2006-10-12 1:19 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Eric Wong
I'm using svn 1.4.0-4 in Debian unstable and apparently there's
a regression on the SVN side that prevents a symlink from
becoming a regular file (which git supports, of course).
It's not a noticeable regression for most people, but this broke
the full-svn-tests target in t/Makefile for me.
The SVN::* Perl libraries seem to have matured and improved over
the past year, and git-svn has supported them for several months
now, so with that I encourage all users to start using the
SVN::* Perl libraries with git-svn.
Signed-off-by: Eric Wong <normalperson@yhbt.net>
---
git-svn.perl | 14 ++++++++++++++
1 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/git-svn.perl b/git-svn.perl
index 84d2c58..a128d90 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -40,8 +40,22 @@ memoize('cmt_metadata');
memoize('get_commit_time');
my ($SVN_PATH, $SVN, $SVN_LOG, $_use_lib);
+
+sub nag_lib {
+ print STDERR <<EOF;
+! Please consider installing the SVN Perl libraries (version 1.1.0 or
+! newer). You will generally get better performance and fewer bugs,
+! especially if you:
+! 1) have a case-insensitive filesystem
+! 2) replace symlinks with files (and vice-versa) in commits
+
+EOF
+}
+
$_use_lib = 1 unless $ENV{GIT_SVN_NO_LIB};
libsvn_load();
+nag_lib() unless $_use_lib;
+
my $_optimize_commits = 1 unless $ENV{GIT_SVN_NO_OPTIMIZE_COMMITS};
my $sha1 = qr/[a-f\d]{40}/;
my $sha1_short = qr/[a-f\d]{4,40}/;
--
1.4.3.rc2.g1cbb0
^ permalink raw reply related
* Re: [RFC] gitweb wishlist and TODO list
From: Luben Tuikov @ 2006-10-10 1:47 UTC (permalink / raw)
To: Jakub Narebski, git
In-Reply-To: <egdge3$t12$1@sea.gmane.org>
--- Jakub Narebski <jnareb@gmail.com> wrote:
> * Improve blame view, making use of --porcelain option to git-blame (for
> later). Perhaps change blame view from table based one to div based one.
> Use different colors for different commits (graph coloring problem).
Oh, no please no.
Why do you think I left the color list as a list? I did try to use
more colors when I wrote it, and it was ugly as h3ll and very distracting
when doing real work. So I ended up with the two color (shades) we have
now and this is what I submitted.
Also, any kind of "graph coloring problem" would make blame slow.
In any way, if you/someone does implement this "coloring" can you please
make it an option, because I'll never turn it on. Thanks!
Luben
^ permalink raw reply
* Re: [RFC] separate .git from working directory
From: Liu Yubao @ 2006-10-12 4:07 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy; +Cc: Sean, git
In-Reply-To: <fcaeb9bf0610111455y225237cmdbaadbf294686d8e@mail.gmail.com>
Nguyen Thai Ngoc Duy wrote:
> On 10/11/06, Sean <seanlkml@sympatico.ca> wrote:
>> You can export a GIT_DIR manually pretty easily if you want to move
>> the .git directory somewhere else. Also you could make a "git find"
>> shell script named "gf" that does something like:
>>
>> #/bin/sh
>> find "$@" ! -path '*/.git/*'
>>
>> Which would let you type "gf -name blah" and automatically ignore
>> the .git directory.
>
> It should work. However I would rather use "normal" find than
> specialized ones. Imagine somedays I hate find and start to love grep,
> I would have to find out --exclude option and create new "gg" script.
> In worse cases where recursive commands don't support filtering, I
> have no chance to filter out .git directories.
>
Subversion puts a .svn/ in every directory under control, I dislike this
feature, I have to use many wrapper scripts.
Maybe the svk way is worth considering, it maintains a map relation
between paths in repository and file system like this:
$ svk checkout --list
depot path path
==================================================================
//path/in/repos/hello/world.c /path/in/fs/hello/world.c
The problem is users must maintain this map when move or delete
/path/in/fs/hello/world.c, it's a bit annoying.
see http://svkbook.elixus.org/nightly/en/svk-book.html#svk.ref.svk.c.checkout
for more information.
^ permalink raw reply
* bug in "git diff -w" output?
From: Ray Lehtiniemi @ 2006-10-12 4:28 UTC (permalink / raw)
To: git
hi all
i'm not sure i understand the output of "git diff -w" in the example below.
to my eye, it seems incorrect around lines 53 and 54.
this example was done using the git version which originally introduced the -w
and -b flags to diff. the "dirty" in the version is a modified prefix in
Makefile. similar output is generated by the latest git version
1.4.3.rc2.ge19ff.
1 $ git version 1.4.1.rc1.g0d21e-dirty
2
3 $ git init-db
4 defaulting to local storage area
5 $ cat <<EOF > x
6 do {
7 nothing;
8 } while (0);
9 EOF
10 $ git add x
11 $ git commit -m "foo" x
12 Committing initial tree 30cd2f91b2797cd3b657a5a03f3e7468253d8dce
13 $ cat <<EOF > x
14 do
15 {
16 nothing;
17 }
18 while (0);
19 EOF
20 $ git diff
21 diff --git a/x b/x
22 index adf3937..64671c6 100644
23 --- a/x
24 +++ b/x
25 @@ -1,3 +1,5 @@
26 -do {
27 - nothing;
28 -} while (0);
29 +do
30 + {
31 + nothing;
32 +}
33 +while (0);
34 $ git diff -b
35 diff --git a/x b/x
36 index adf3937..64671c6 100644
37 --- a/x
38 +++ b/x
39 @@ -1,3 +1,5 @@
40 -do {
41 +do
42 + {
43 nothing;
44 -} while (0);
45 +}
46 +while (0);
47 $ git diff -w
48 diff --git a/x b/x
49 index adf3937..64671c6 100644
50 --- a/x
51 +++ b/x
52 @@ -1,3 +1,5 @@
53 do {
54 + {
55 nothing;
56 -} while (0);
57 +}
58 +while (0);
ray
^ permalink raw reply
* Re: [RFC] separate .git from working directory
From: Liu Yubao @ 2006-10-12 5:04 UTC (permalink / raw)
To: git; +Cc: Nguyen Thai Ngoc Duy, Sean
In-Reply-To: <452DBF9E.7010900@gmail.com>
Liu Yubao wrote:
> Maybe the svk way is worth considering, it maintains a map relation
> between paths in repository and file system like this:
>
> $ svk checkout --list
> depot path path
> ==================================================================
> //path/in/repos/hello/world.c /path/in/fs/hello/world.c
Sorry, I made a mistake, svk maintains a map of the top directory
of checkout, not each file:
depot path path
====================================================================
//path/in/repos/myproject /path/to/myproject
>
> The problem is users must maintain this map when move or delete
> /path/in/fs/hello/world.c, it's a bit annoying.
>
> see
> http://svkbook.elixus.org/nightly/en/svk-book.html#svk.ref.svk.c.checkout
> for more information.
>
^ permalink raw reply
* Re: [RFC] separate .git from working directory
From: Martin Waitz @ 2006-10-12 5:21 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy; +Cc: git
In-Reply-To: <fcaeb9bf0610111446i35251fc9i6517cc5b3b53fe84@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 342 bytes --]
hoi :)
On Thu, Oct 12, 2006 at 04:46:51AM +0700, Nguyen Thai Ngoc Duy wrote:
> I thought about symlinks. However find will follow symlinks and
> traverse .git directories again. My goal is to prevent looking into
> .git directories
only with -L.
By default, find will not recurse into a symlinked directory.
--
Martin Waitz
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH] Removes the <?xml?> declaration from gitweb.pl
From: Robin Rosenberg @ 2006-10-12 5:45 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <egjnk5$bpn$2@sea.gmane.org>
onsdag 11 oktober 2006 23:27 skrev Jakub Narebski:
> Pazu wrote:
> > The XML declaration forces IE6 into quirks mode, breaking our
> > nice standards compliant stylesheet.
>
> But isn't it _required_ by XML/XHTML?
For pure XML document it is required, but not for XHTML, unless the encoding
is something other than UTF-8 or (shudder) UTF-16. W3C recommends it though.
-- robin
^ permalink raw reply
* [PATCH] git-pickaxe: blame rewritten.
From: Junio C Hamano @ 2006-10-12 8:52 UTC (permalink / raw)
To: git
Currently it does what git-blame does, but only faster.
More importantly, its internal structure is designed to support
content movement (aka cut-and-paste) more easily by allowing
more than one paths to be taken from the same commit.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
I really hate to do this immediately after writing obituary for
annotate, but I had a solid 24-hour to work on git, which is a
rare opportunity for me these days, so here it is.
For 160+ *.c files in git.git repository, running git-blame and
git-pickaxe with "-n -f" options for all of them takes the
following:
*** blame ***
141.43user 1.41system 2:22.94elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+438667minor)pagefaults 0swaps
*** pickaxe ***
78.99user 2.22system 1:21.22elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+397307minor)pagefaults 0swaps
I have given only cursory check to its output (some files are
blamed slightly differently from how git-blame does), but it
appears that there is no major breakage. You can see for
example try annotating builtin-apply.c starting from v1.4.0;
there are two differences, which pickaxe assigns blame to older
commits and both of them seem to be sensible. This exercise
also revealed some mistakes I made earlier (number of same
patches were cherry-picked in separate branches and then later
merged: "gitk master --not e4c9327a 15b4d577 -- pack-objects.c"
would show an example of such a breakage.
Documentation/git-pickaxe.txt | 104 +++++
Documentation/git.txt | 3 +
Makefile | 1 +
builtin-pickaxe.c | 952 +++++++++++++++++++++++++++++++++++++++++
builtin.h | 1 +
git.c | 1 +
t/t8003-pickaxe.sh | 9 +
7 files changed, 1071 insertions(+), 0 deletions(-)
diff --git a/Documentation/git-pickaxe.txt b/Documentation/git-pickaxe.txt
new file mode 100644
index 0000000..7f30cdf
--- /dev/null
+++ b/Documentation/git-pickaxe.txt
@@ -0,0 +1,104 @@
+git-pickaxe(1)
+==============
+
+NAME
+----
+git-pickaxe - Show what revision and author last modified each line of a file
+
+SYNOPSIS
+--------
+'git-pickaxe' [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S <revs-file>] [--] <file> [<rev>]
+
+DESCRIPTION
+-----------
+
+Annotates each line in the given file with information from the revision which
+last modified the line. Optionally, start annotating from the given revision.
+
+Also it can limit the range of lines annotated.
+
+This report doesn't tell you anything about lines which have been deleted or
+replaced; you need to use a tool such as gitlink:git-diff[1] or the "pickaxe"
+interface briefly mentioned in the following paragraph.
+
+Apart from supporting file annotation, git also supports searching the
+development history for when a code snippet occured in a change. This makes it
+possible to track when a code snippet was added to a file, moved or copied
+between files, and eventually deleted or replaced. It works by searching for
+a text string in the diff. A small example:
+
+-----------------------------------------------------------------------------
+$ git log --pretty=oneline -S'blame_usage'
+5040f17eba15504bad66b14a645bddd9b015ebb7 blame -S <ancestry-file>
+ea4c7f9bf69e781dd0cd88d2bccb2bf5cc15c9a7 git-blame: Make the output
+-----------------------------------------------------------------------------
+
+OPTIONS
+-------
+-c, --compatibility::
+ Use the same output mode as gitlink:git-annotate[1] (Default: off).
+
+-L n,m::
+ Annotate only the specified line range (lines count from 1).
+
+-l, --long::
+ Show long rev (Default: off).
+
+-t, --time::
+ Show raw timestamp (Default: off).
+
+-S, --rev-file <revs-file>::
+ Use revs from revs-file instead of calling gitlink:git-rev-list[1].
+
+-f, --show-name::
+ Show filename in the original commit. By default
+ filename is shown if there is any line that came from a
+ file with different name, due to rename detection.
+
+-n, --show-number::
+ Show line number in the original commit (Default: off).
+
+-p, --porcelain::
+ Show in a format designed for machine consumption.
+
+-h, --help::
+ Show help message.
+
+
+THE PORCELAIN FORMAT
+--------------------
+
+In this format, each line is output after a header; the
+header at the minumum has the first line which has:
+
+- 40-byte SHA-1 of the commit the line is attributed to;
+- the line number of the line in the original file;
+- the line number of the line in the final file;
+- on a line that starts a group of line from a different
+ commit than the previous one, the number of lines in this
+ group. On subsequent lines this field is absent.
+
+This header line is followed by the following information
+at least once for each commit:
+
+- author name ("author"), email ("author-mail"), time
+ ("author-time"), and timezone ("author-tz"); similarly
+ for committer.
+- filename in the commit the line is attributed to.
+- the first line of the commit log message ("summary").
+
+The contents of the actual line is output after the above
+header, prefixed by a TAB. This is to allow adding more
+header elements later.
+
+SEE ALSO
+--------
+gitlink:git-blame[1]
+
+AUTHOR
+------
+Written by Junio C Hamano <junkio@cox.net>
+
+GIT
+---
+Part of the gitlink:git[7] suite
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 3af6fc6..7074e32 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -430,6 +430,9 @@ gitlink:git-annotate[1]::
gitlink:git-blame[1]::
Blame file lines on commits.
+gitlink:git-pickaxe[1]::
+ Find out where each line in a file came from.
+
gitlink:git-check-ref-format[1]::
Make sure ref name is well formed.
diff --git a/Makefile b/Makefile
index 2c7c338..bd99550 100644
--- a/Makefile
+++ b/Makefile
@@ -288,6 +288,7 @@ BUILTIN_OBJS = \
builtin-mv.o \
builtin-name-rev.o \
builtin-pack-objects.o \
+ builtin-pickaxe.o \
builtin-prune.o \
builtin-prune-packed.o \
builtin-push.o \
diff --git a/builtin-pickaxe.c b/builtin-pickaxe.c
new file mode 100644
index 0000000..0e26308
--- /dev/null
+++ b/builtin-pickaxe.c
@@ -0,0 +1,952 @@
+/*
+ * Pickaxe
+ *
+ * Copyright (c) 2006, Junio C Hamano
+ */
+
+#include "cache.h"
+#include "builtin.h"
+#include "blob.h"
+#include "commit.h"
+#include "tree-walk.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "xdiff-interface.h"
+
+#include <time.h>
+#include <sys/time.h>
+
+static char pickaxe_usage[] =
+"git-pickaxe [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S <revs-file>] [--] file [commit]\n"
+" -c, --compatibility Use the same output mode as git-annotate (Default: off)\n"
+" -l, --long Show long commit SHA1 (Default: off)\n"
+" -t, --time Show raw timestamp (Default: off)\n"
+" -f, --show-name Show original filename (Default: auto)\n"
+" -n, --show-number Show original linenumber (Default: off)\n"
+" -p, --porcelain Show in a format designed for machine consumption\n"
+" -L n,m Process only line range n,m, counting from 1\n"
+" -S revs-file Use revisions from revs-file instead of calling git-rev-list\n";
+
+static int longest_file;
+static int longest_author;
+static int max_orig_digits;
+static int max_digits;
+
+#define DEBUG 0
+/*
+ * One blob in a commit
+ */
+struct origin {
+ struct commit *commit;
+ unsigned char blob_sha1[20];
+ char metainfo_given;
+ char path[FLEX_ARRAY];
+};
+
+struct blame_entry {
+ /* the first line of this group in the final image;
+ * internally all line numbers are 0 based.
+ */
+ int lno;
+
+ /* how many lines this group has */
+ int num_lines;
+
+ /* the commit that introduced this group into the final image */
+ struct origin *suspect;
+
+ /* true if the suspect is truly guilty; false while we have not
+ * checked if the group came from one of its parents.
+ */
+ char guilty;
+
+ /* the line number of the first line of this group in the
+ * suspect's file; internally all line numbers are 0 based.
+ */
+ int s_lno;
+};
+
+struct scoreboard {
+ /* the final commit (i.e. where we started digging from) */
+ struct commit *final;
+
+ const char *path;
+
+ /* the contents in the final; pointed into by buf pointers of
+ * blame_entries
+ */
+ const char *final_buf;
+ unsigned long final_buf_size;
+
+ /* list of blames */
+ struct blame_entry **entries;
+ int num_entries;
+};
+
+static int blame_entry_sort(const void *a_, const void *b_)
+{
+ int a = (*(struct blame_entry **)a_)->lno;
+ int b = (*(struct blame_entry **)b_)->lno;
+ return a - b;
+}
+
+static void coalesce(struct scoreboard *sb)
+{
+ int i, o, num;
+ struct blame_entry **ent;
+
+ qsort(sb->entries, sb->num_entries, sizeof(struct blame_entry *),
+ blame_entry_sort);
+ ent = sb->entries;
+ num = sb->num_entries;
+
+ /*
+ * Look at i, and see if it is adjacent to the last one at (o-1);
+ * if so, extend the last one into a larger group and drop the
+ * current one at i. Copy the entry to remove gaps made by the
+ * coalescing process as we go.
+ */
+ for (o = 0, i = 0; i < num; i++) {
+ if (o &&
+ ent[o-1]->suspect == ent[i]->suspect &&
+ ent[o-1]->s_lno + ent[o-1]->num_lines == ent[i]->s_lno) {
+ ent[o-1]->num_lines += ent[i]->num_lines;
+ free(ent[i]);
+ continue;
+ }
+ if (o != i)
+ ent[o] = ent[i];
+ o++;
+ }
+ sb->num_entries = o;
+}
+
+static void free_origin(struct origin *o)
+{
+ free(o);
+}
+
+static struct origin *find_origin(struct scoreboard *sb,
+ struct commit *commit,
+ const char *path)
+{
+ int i, num;
+ struct blame_entry **ent;
+ struct origin *o;
+ unsigned mode;
+ char type[10];
+
+ ent = sb->entries;
+ num = sb->num_entries;
+ for (i = 0; i < num; i++) {
+ if (ent[i]->suspect->commit == commit &&
+ !strcmp(ent[i]->suspect->path, path))
+ return ent[i]->suspect;
+ }
+
+ o = xcalloc(1, sizeof(*o) + strlen(path) + 1);
+ o->commit = commit;
+ strcpy(o->path, path);
+ if (get_tree_entry(commit->object.sha1, path, o->blob_sha1, &mode))
+ goto err_out;
+ if (sha1_object_info(o->blob_sha1, type, NULL) ||
+ strcmp(type, blob_type))
+ goto err_out;
+ return o;
+ err_out:
+ free_origin(o);
+ return NULL;
+}
+
+static struct origin *find_rename(struct scoreboard *sb,
+ struct commit *parent,
+ struct origin *origin)
+{
+ struct origin *porigin = NULL;
+ struct diff_options diff_opts;
+ int i;
+ const char *paths[1];
+
+ diff_setup(&diff_opts);
+ diff_opts.recursive = 1;
+ diff_opts.detect_rename = DIFF_DETECT_RENAME;
+ diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+ paths[0] = NULL;
+ diff_tree_setup_paths(paths, &diff_opts);
+ if (diff_setup_done(&diff_opts) < 0)
+ die("diff-setup");
+ diff_tree_sha1(origin->commit->tree->object.sha1,
+ parent->tree->object.sha1,
+ "", &diff_opts);
+ diffcore_std(&diff_opts);
+
+ for (i = 0; i < diff_queued_diff.nr; i++) {
+ struct diff_filepair *p = diff_queued_diff.queue[i];
+ if (p->status == 'R' && !strcmp(p->one->path, origin->path)) {
+ porigin = find_origin(sb, parent, p->two->path);
+ break;
+ }
+ }
+ diff_flush(&diff_opts);
+ return porigin;
+}
+
+struct chunk {
+ /* line number in postimage; up to but not including this
+ * line is the same as preimage
+ */
+ int same;
+
+ /* preimage line number after this chunk */
+ int p_next;
+
+ /* postimage line number after this chunk */
+ int t_next;
+};
+
+struct patch {
+ struct chunk *chunks;
+ int num;
+};
+
+struct blame_diff_state {
+ struct xdiff_emit_state xm;
+ struct patch *ret;
+};
+
+static void process_u0_diff(void *state_, char *line, unsigned long len)
+{
+ struct blame_diff_state *state = state_;
+ struct chunk *chunk;
+ int off1, off2, len1, len2;
+
+if(DEBUG) fprintf(stderr, "%.*s", (int) len, line);
+
+ if (len < 4 || line[0] != '@' || line[1] != '@')
+ return;
+
+ state->ret->num++;
+ state->ret->chunks = xrealloc(state->ret->chunks,
+ sizeof(struct chunk) * state->ret->num);
+ chunk = &state->ret->chunks[state->ret->num - 1];
+
+ if (parse_hunk_header(line, len,
+ &off1, &len1,
+ &off2, &len2)) {
+ state->ret->num--;
+ return;
+ }
+
+ /* Line numbers in patch output are one based. */
+ off1--;
+ off2--;
+
+ chunk->same = len2 ? off2 : (off2 + 1);
+
+ chunk->p_next = off1 + (len1 ? len1 : 1);
+ chunk->t_next = chunk->same + len2;
+}
+
+static struct patch *get_patch(struct origin *parent,
+ struct origin *origin)
+{
+ struct blame_diff_state state;
+ xpparam_t xpp;
+ xdemitconf_t xecfg;
+ mmfile_t file_p, file_o;
+ xdemitcb_t ecb;
+ char type[10];
+
+if(DEBUG) fprintf(stderr, "get patch %.8s %.8s\n",
+ sha1_to_hex(parent->commit->object.sha1),
+ sha1_to_hex(origin->commit->object.sha1));
+
+ file_p.ptr = read_sha1_file(parent->blob_sha1, type,
+ (unsigned long *) &file_p.size);
+ file_o.ptr = read_sha1_file(origin->blob_sha1, type,
+ (unsigned long *) &file_o.size);
+ if (!file_p.ptr || !file_o.ptr)
+ return NULL;
+
+ xpp.flags = XDF_NEED_MINIMAL;
+ xecfg.ctxlen = 0;
+ xecfg.flags = 0;
+ ecb.outf = xdiff_outf;
+ ecb.priv = &state;
+ memset(&state, 0, sizeof(state));
+ state.xm.consume = process_u0_diff;
+ state.ret = xmalloc(sizeof(struct patch));
+ state.ret->chunks = NULL;
+ state.ret->num = 0;
+
+ xdl_diff(&file_p, &file_o, &xpp, &xecfg, &ecb);
+ return state.ret;
+}
+
+static void free_patch(struct patch *p)
+{
+ free(p->chunks);
+ free(p);
+}
+
+static void add_blame_entry(struct scoreboard *sb, struct blame_entry *e)
+{
+ sb->entries = xrealloc(sb->entries,
+ sizeof(struct blame_entry *) *
+ (sb->num_entries + 1));
+ sb->entries[sb->num_entries++] = e;
+}
+
+static void blame_overlap(struct scoreboard *sb, struct blame_entry *e,
+ int tlno, int plno, int same,
+ struct origin *parent)
+{
+ /* it is known that lines between tlno to same
+ * came from parent, and e has an overlap with that range.
+ * it also is known that parent's line plno corresponds to
+ * e's line tlno.
+ *
+ * <---- e ----->
+ * <------>
+ * <------------>
+ * <------------>
+ * <------------------>
+ *
+ * Potentially we need to split e into three parts; before
+ * this chunk, the chunk to be blamed for parent, and after
+ * that portion.
+ *
+ * When the function splits the blame_entry, it pushes the part
+ * that needs to be re-processed at the end of the queue.
+ */
+ int chunk_end_lno;
+ struct blame_entry split[3], *new_entry;
+ memset(split, 0, sizeof(split));
+
+ split[1].suspect = parent;
+ if (e->s_lno < tlno) {
+ /* there is a pre-chunk part not blamed on parent */
+ split[0].suspect = e->suspect;
+ split[0].lno = e->lno;
+ split[0].s_lno = e->s_lno;
+ split[0].num_lines = tlno - e->s_lno;
+ split[1].lno = e->lno + tlno - e->s_lno;
+ split[1].s_lno = plno;
+ }
+ else {
+ split[1].lno = e->lno;
+ split[1].s_lno = plno + (e->s_lno - tlno);
+ }
+
+ if (same < e->s_lno + e->num_lines) {
+ /* there is a post-chunk part not blamed on parent */
+ split[2].suspect = e->suspect;
+ split[2].lno = e->lno + (same - e->s_lno);
+ split[2].s_lno = e->s_lno + (same - e->s_lno);
+ split[2].num_lines = e->s_lno + e->num_lines - same;
+ chunk_end_lno = split[2].lno;
+ }
+ else
+ chunk_end_lno = e->lno + e->num_lines;
+ split[1].num_lines = chunk_end_lno - split[1].lno;
+
+ if (split[0].suspect && split[2].suspect) {
+ /* we need to split e into two and add another for parent */
+ memcpy(e, &(split[0]), sizeof(struct blame_entry));
+
+ new_entry = xmalloc(sizeof(*new_entry));
+ memcpy(new_entry, &(split[2]), sizeof(struct blame_entry));
+ add_blame_entry(sb, new_entry);
+
+ new_entry = xmalloc(sizeof(*new_entry));
+ memcpy(new_entry, &(split[1]), sizeof(struct blame_entry));
+ add_blame_entry(sb, new_entry);
+ }
+ else if (!split[0].suspect && !split[2].suspect)
+ /* parent covers the entire area */
+ memcpy(e, &(split[1]), sizeof(struct blame_entry));
+ else if (split[0].suspect) {
+ memcpy(e, &(split[0]), sizeof(struct blame_entry));
+
+ new_entry = xmalloc(sizeof(*new_entry));
+ memcpy(new_entry, &(split[1]), sizeof(struct blame_entry));
+ add_blame_entry(sb, new_entry);
+ }
+ else {
+ new_entry = xmalloc(sizeof(*new_entry));
+ memcpy(new_entry, &(split[1]), sizeof(struct blame_entry));
+ add_blame_entry(sb, new_entry);
+
+ memcpy(e, &(split[2]), sizeof(struct blame_entry));
+ }
+}
+
+static void blame_chunk(struct scoreboard *sb,
+ int tlno, int plno, int same,
+ struct origin *target, struct origin *parent)
+{
+ int i;
+ for (i = 0; i < sb->num_entries; i++) {
+ struct blame_entry *e = sb->entries[i];
+ if (e->guilty || e->suspect != target)
+ continue;
+ if (same <= e->s_lno)
+ continue;
+ if (tlno < e->s_lno + e->num_lines)
+ blame_overlap(sb, e, tlno, plno, same, parent);
+ }
+}
+
+static int pass_blame_to_parent(struct scoreboard *sb,
+ struct origin *target,
+ struct origin *parent)
+{
+ int i;
+ struct patch *patch;
+ int plno, tlno, last_in_target = -1;
+
+ for (i = 0; i < sb->num_entries; i++) {
+ struct blame_entry *e = sb->entries[i];
+ if (e->guilty || e->suspect != target)
+ continue;
+ if (last_in_target < e->s_lno + e->num_lines)
+ last_in_target = e->s_lno + e->num_lines;
+ }
+ patch = get_patch(parent, target);
+ plno = tlno = 0;
+ for (i = 0; i < patch->num; i++) {
+ struct chunk *chunk = &patch->chunks[i];
+
+if(DEBUG) fprintf(stderr,
+ "plno = %d, tlno = %d, "
+ "same as parent up to %d, resync %d and %d\n",
+ plno, tlno,
+ chunk->same, chunk->p_next, chunk->t_next);
+ blame_chunk(sb, tlno, plno, chunk->same, target, parent);
+ plno = chunk->p_next;
+ tlno = chunk->t_next;
+ }
+ /* rest (i.e. anything above tlno) are the same as parent */
+ blame_chunk(sb, tlno, plno, last_in_target, target, parent);
+
+ free_patch(patch);
+ return 0;
+}
+
+#define MAXPARENT 16
+static void pass_blame(struct scoreboard *sb, struct origin *origin)
+{
+ int i, parent_ix;
+ struct commit *commit = origin->commit;
+ struct commit_list *parent;
+ struct origin *parent_origin[MAXPARENT], *porigin;
+
+ if (parse_commit(commit))
+ exit(1);
+
+ memset(parent_origin, 0, sizeof(parent_origin));
+ for (parent_ix = 0, parent = commit->parents;
+ parent_ix < MAXPARENT && parent;
+ parent = parent->next, parent_ix++) {
+ if (parse_commit(parent->item))
+ continue;
+ porigin = find_origin(sb, parent->item, origin->path);
+ if (!porigin)
+ porigin = find_rename(sb, parent->item, origin);
+ if (!porigin)
+ continue;
+ if (!hashcmp(porigin->blob_sha1, origin->blob_sha1)) {
+ for (i = 0; i < sb->num_entries; i++) {
+ if (sb->entries[i]->suspect == origin)
+ sb->entries[i]->suspect = porigin;
+ }
+ /* now everything blamed for origin is blamed for
+ * porigin, we do not need to keep it anymore.
+ * Do not free porigin (or the ones we got from
+ * earlier round); they may still be used elsewhere.
+ */
+ free_origin(origin);
+ return;
+ }
+ parent_origin[parent_ix] = porigin;
+ }
+
+ for (parent_ix = 0, parent = commit->parents;
+ parent_ix < MAXPARENT && parent;
+ parent = parent->next, parent_ix++) {
+ struct origin *porigin = parent_origin[parent_ix];
+ if (!porigin)
+ continue;
+ if (pass_blame_to_parent(sb, origin, porigin))
+ break;
+ }
+
+ /* NEEDSWORK:
+ * Optionally run "ciff" to find copies from parents' files here
+ */
+
+ /* Take responsibility for the remaining entries */
+ for (i = 0; i < sb->num_entries; i++)
+ if (!sb->entries[i]->guilty &&
+ sb->entries[i]->suspect == origin)
+ sb->entries[i]->guilty = 1;
+}
+
+static void assign_blame(struct scoreboard *sb)
+{
+ while (1) {
+ int i;
+ struct origin *suspect = NULL;
+
+ /* find one suspect to break down */
+ for (i = 0; !suspect && i < sb->num_entries; i++) {
+ if (!sb->entries[i]->guilty)
+ suspect = sb->entries[i]->suspect;
+ }
+ if (!suspect)
+ return; /* all done */
+
+ pass_blame(sb, suspect);
+ }
+}
+
+static const char *format_time(unsigned long time, const char *tz_str,
+ int show_raw_time)
+{
+ static char time_buf[128];
+ time_t t = time;
+ int minutes, tz;
+ struct tm *tm;
+
+ if (show_raw_time) {
+ sprintf(time_buf, "%lu %s", time, tz_str);
+ return time_buf;
+ }
+
+ tz = atoi(tz_str);
+ minutes = tz < 0 ? -tz : tz;
+ minutes = (minutes / 100)*60 + (minutes % 100);
+ minutes = tz < 0 ? -minutes : minutes;
+ t = time + minutes * 60;
+ tm = gmtime(&t);
+
+ strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", tm);
+ strcat(time_buf, tz_str);
+ return time_buf;
+}
+
+struct commit_info
+{
+ char *author;
+ char *author_mail;
+ unsigned long author_time;
+ char *author_tz;
+
+ /* filled only when asked for details */
+ char *committer;
+ char *committer_mail;
+ unsigned long committer_time;
+ char *committer_tz;
+
+ char *summary;
+};
+
+static void get_ac_line(const char *inbuf, const char *what,
+ int bufsz, char *person, char **mail,
+ unsigned long *time, char **tz)
+{
+ int len;
+ char *tmp, *endp;
+
+ tmp = strstr(inbuf, what);
+ if (!tmp)
+ goto error_out;
+ tmp += strlen(what);
+ endp = strchr(tmp, '\n');
+ if (!endp)
+ len = strlen(tmp);
+ else
+ len = endp - tmp;
+ if (bufsz <= len) {
+ error_out:
+ /* Ugh */
+ person = *mail = *tz = "(unknown)";
+ *time = 0;
+ return;
+ }
+ memcpy(person, tmp, len);
+
+ tmp = person;
+ tmp += len;
+ *tmp = 0;
+ while (*tmp != ' ')
+ tmp--;
+ *tz = tmp+1;
+
+ *tmp = 0;
+ while (*tmp != ' ')
+ tmp--;
+ *time = strtoul(tmp, NULL, 10);
+
+ *tmp = 0;
+ while (*tmp != ' ')
+ tmp--;
+ *mail = tmp + 1;
+ *tmp = 0;
+}
+
+static void get_commit_info(struct commit *commit,
+ struct commit_info *ret,
+ int detailed)
+{
+ int len;
+ char *tmp, *endp;
+ static char author_buf[1024];
+ static char committer_buf[1024];
+ static char summary_buf[1024];
+
+ ret->author = author_buf;
+ get_ac_line(commit->buffer, "\nauthor ",
+ sizeof(author_buf), author_buf, &ret->author_mail,
+ &ret->author_time, &ret->author_tz);
+
+ if (!detailed)
+ return;
+
+ ret->committer = committer_buf;
+ get_ac_line(commit->buffer, "\ncommitter ",
+ sizeof(committer_buf), committer_buf, &ret->committer_mail,
+ &ret->committer_time, &ret->committer_tz);
+
+ ret->summary = summary_buf;
+ tmp = strstr(commit->buffer, "\n\n");
+ if (!tmp) {
+ error_out:
+ sprintf(summary_buf, "(%s)", sha1_to_hex(commit->object.sha1));
+ return;
+ }
+ tmp += 2;
+ endp = strchr(tmp, '\n');
+ if (!endp)
+ goto error_out;
+ len = endp - tmp;
+ if (len >= sizeof(summary_buf))
+ goto error_out;
+ memcpy(summary_buf, tmp, len);
+ summary_buf[len] = 0;
+}
+
+static const char *nth_line(const char *buf, unsigned long len, int lno)
+{
+ while (lno) {
+ if (*buf == '\n')
+ lno--;
+ buf++;
+ if (!--len)
+ die("internal error: buffer ran out");
+ }
+ return buf;
+}
+
+#define OUTPUT_ANNOTATE_COMPAT 001
+#define OUTPUT_LONG_OBJECT_NAME 002
+#define OUTPUT_RAW_TIMESTAMP 004
+#define OUTPUT_PORCELAIN 010
+#define OUTPUT_SHOW_NAME 020
+#define OUTPUT_SHOW_NUMBER 040
+
+static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
+{
+ int cnt;
+ const char *cp;
+ struct origin *suspect = ent->suspect;
+ char hex[41];
+
+ strcpy(hex, sha1_to_hex(suspect->commit->object.sha1));
+ printf("%s%c%d %d %d\n",
+ hex,
+ ent->guilty ? ' ' : '*', // purely for debugging
+ ent->s_lno + 1,
+ ent->lno + 1,
+ ent->num_lines);
+ if (!ent->suspect->metainfo_given) {
+ struct commit_info ci;
+ suspect->metainfo_given = 1;
+ get_commit_info(suspect->commit, &ci, 1);
+ printf("author %s\n", ci.author);
+ printf("author-mail %s\n", ci.author_mail);
+ printf("author-time %lu\n", ci.author_time);
+ printf("author-tz %s\n", ci.author_tz);
+ printf("committer %s\n", ci.committer);
+ printf("committer-mail %s\n", ci.committer_mail);
+ printf("committer-time %lu\n", ci.committer_time);
+ printf("committer-tz %s\n", ci.committer_tz);
+ printf("filename %s\n", suspect->path);
+ printf("summary %s\n", ci.summary);
+ }
+ cp = nth_line(sb->final_buf, sb->final_buf_size, ent->lno);
+ for (cnt = 0; cnt < ent->num_lines; cnt++) {
+ char ch;
+ if (cnt)
+ printf("%s %d %d\n", hex,
+ ent->s_lno + 1 + cnt,
+ ent->lno + 1 + cnt);
+ putchar('\t');
+ do {
+ ch = *cp++;
+ putchar(ch);
+ } while (ch != '\n' &&
+ cp < sb->final_buf + sb->final_buf_size);
+ }
+}
+
+static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
+{
+ int cnt;
+ const char *cp;
+ struct origin *suspect = ent->suspect;
+ struct commit_info ci;
+ char hex[41];
+ int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
+
+ get_commit_info(suspect->commit, &ci, 1);
+ strcpy(hex, sha1_to_hex(suspect->commit->object.sha1));
+
+ cp = nth_line(sb->final_buf, sb->final_buf_size, ent->lno);
+ for (cnt = 0; cnt < ent->num_lines; cnt++) {
+ char ch;
+
+ printf("%.*s", (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8, hex);
+ if (opt & OUTPUT_ANNOTATE_COMPAT)
+ printf("\t(%10s\t%10s\t%d)", ci.author,
+ format_time(ci.author_time, ci.author_tz,
+ show_raw_time),
+ ent->lno + 1 + cnt);
+ else {
+ if (opt & OUTPUT_SHOW_NAME)
+ printf(" %-*.*s", longest_file, longest_file,
+ suspect->path);
+ if (opt & OUTPUT_SHOW_NUMBER)
+ printf(" %*d", max_orig_digits,
+ ent->s_lno + 1 + cnt);
+ printf(" (%-*.*s %10s %*d) ",
+ longest_author, longest_author, ci.author,
+ format_time(ci.author_time, ci.author_tz,
+ show_raw_time),
+ max_digits, ent->lno + 1 + cnt);
+ }
+ do {
+ ch = *cp++;
+ putchar(ch);
+ } while (ch != '\n' &&
+ cp < sb->final_buf + sb->final_buf_size);
+ }
+}
+
+static void output(struct scoreboard *sb, int option)
+{
+ int i, num;
+ struct blame_entry **ent;
+ ent = sb->entries;
+ num = sb->num_entries;
+ for (i = 0; i < num; i++) {
+ if (option & OUTPUT_PORCELAIN)
+ emit_porcelain(sb, ent[i]);
+ else
+ emit_other(sb, ent[i], option);
+ }
+}
+
+static int count_lines(const char *buf, unsigned long len)
+{
+ int num = 0;
+ if (len && buf[len-1] != '\n')
+ num++; /* incomplete line at the end */
+ while (len--) {
+ if (*buf++ == '\n')
+ num++;
+ }
+ return num;
+}
+
+static int read_ancestry(const char *graft_file)
+{
+ FILE *fp = fopen(graft_file, "r");
+ char buf[1024];
+ if (!fp)
+ return -1;
+ while (fgets(buf, sizeof(buf), fp)) {
+ /* The format is just "Commit Parent1 Parent2 ...\n" */
+ int len = strlen(buf);
+ struct commit_graft *graft = read_graft_line(buf, len);
+ register_commit_graft(graft, 0);
+ }
+ fclose(fp);
+ return 0;
+}
+
+static int lineno_width(int lines)
+{
+ int i, width;
+
+ for (width = 1, i = 10; i <= lines + 1; width++)
+ i *= 10;
+ return width;
+}
+
+static void find_alignment(struct scoreboard *sb, int *option)
+{
+ int i;
+ int longest_src_lines = 0;
+ int longest_dst_lines = 0;
+
+ for (i = 0; i < sb->num_entries; i++) {
+ struct blame_entry *e = sb->entries[i];
+ struct origin *suspect = e->suspect;
+ struct commit_info ci;
+ int num;
+
+ if (!suspect->metainfo_given) {
+ suspect->metainfo_given = 1;
+ get_commit_info(suspect->commit, &ci, 1);
+ if (strcmp(suspect->path, sb->path))
+ *option |= OUTPUT_SHOW_NAME;
+ num = strlen(suspect->path);
+ if (longest_file < num)
+ longest_file = num;
+ num = strlen(ci.author);
+ if (longest_author < num)
+ longest_author = num;
+ }
+ num = e->s_lno + e->num_lines;
+ if (longest_src_lines < num)
+ longest_src_lines = num;
+ num = e->lno + e->num_lines;
+ if (longest_dst_lines < num)
+ longest_dst_lines = num;
+ }
+ max_orig_digits = lineno_width(longest_src_lines);
+ max_digits = lineno_width(longest_dst_lines);
+}
+
+int cmd_pickaxe(int argc, const char **argv, const char *prefix)
+{
+ const char *path = argv[1];
+ unsigned char sha1[20];
+ struct scoreboard sb;
+ struct origin *o;
+ struct blame_entry *ent;
+ int i, seen_dashdash;
+ long bottom, top, lno;
+ int output_option = 0;
+ const char *revs_file = NULL;
+ const char *final_commit_name = "HEAD";
+ char type[10];
+
+ bottom = top = 0;
+ seen_dashdash = 0;
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+ if (*arg != '-')
+ break;
+ else if (!strcmp("-c", arg))
+ output_option |= OUTPUT_ANNOTATE_COMPAT;
+ else if (!strcmp("-t", arg))
+ output_option |= OUTPUT_RAW_TIMESTAMP;
+ else if (!strcmp("-l", arg))
+ output_option |= OUTPUT_LONG_OBJECT_NAME;
+ else if (!strcmp("-S", arg) && ++i < argc)
+ revs_file = argv[i];
+ else if (!strcmp("-L", arg) && ++i < argc) {
+ char *term;
+ arg = argv[i];
+ if (bottom || top)
+ die("More than one '-L n,m' option given");
+ bottom = strtol(arg, &term, 10);
+ if (*term == ',') {
+ top = strtol(term + 1, &term, 10);
+ if (*term)
+ usage(pickaxe_usage);
+ }
+ if (bottom && top && top < bottom) {
+ unsigned long tmp;
+ tmp = top; top = bottom; bottom = tmp;
+ }
+ }
+ else if (!strcmp("-f", arg) ||
+ !strcmp("--show-name", arg))
+ output_option |= OUTPUT_SHOW_NAME;
+ else if (!strcmp("-n", arg) ||
+ !strcmp("--show-number", arg))
+ output_option |= OUTPUT_SHOW_NUMBER;
+ else if (!strcmp("--porcelain", arg))
+ output_option |= OUTPUT_PORCELAIN;
+ else if (!strcmp("--", arg)) {
+ seen_dashdash = 1;
+ i++;
+ break;
+ }
+ else
+ usage(pickaxe_usage);
+ }
+
+ /* argv[i] is filename, argv[i+1] if exists is the commit */
+ if (i >= argc)
+ usage(pickaxe_usage);
+ path = argv[i++];
+ if (!seen_dashdash) {
+ struct stat st;
+ if (lstat(path, &st))
+ die("cannot stat path %s: %s", path, strerror(errno));
+ }
+
+ if (i == argc - 1)
+ final_commit_name = argv[i];
+ else if (i != argc)
+ usage(pickaxe_usage);
+
+ memset(&sb, 0, sizeof(sb));
+ if (get_sha1(final_commit_name, sha1) ||
+ !(sb.final = lookup_commit_reference(sha1)))
+ die("no such commit %s", final_commit_name);
+ o = find_origin(&sb, sb.final, path);
+ if (!o)
+ die("no such path %s in %s", path, final_commit_name);
+
+ sb.final_buf = read_sha1_file(o->blob_sha1, type, &sb.final_buf_size);
+ lno = count_lines(sb.final_buf, sb.final_buf_size);
+
+ if (bottom < 1)
+ bottom = 1;
+ if (top < 1)
+ top = lno;
+ bottom--;
+ if (lno < top)
+ die("file %s has only %lu lines", path, lno);
+
+ ent = xcalloc(1, sizeof(*ent));
+ ent->lno = bottom;
+ ent->num_lines = top - bottom;
+ ent->suspect = o;
+ ent->s_lno = bottom;
+
+ sb.entries = xcalloc(10, sizeof(struct blame_entry *));
+ sb.entries[0] = ent;
+ sb.num_entries = 1;
+ sb.path = path;
+
+ if (revs_file && read_ancestry(revs_file))
+ die("reading graft file %s failed: %s",
+ revs_file, strerror(errno));
+
+ assign_blame(&sb);
+
+ coalesce(&sb);
+
+ if (!(output_option & OUTPUT_PORCELAIN))
+ find_alignment(&sb, &output_option);
+
+ output(&sb, output_option);
+
+ return 0;
+}
diff --git a/builtin.h b/builtin.h
index f9fa9ff..7451ce6 100644
--- a/builtin.h
+++ b/builtin.h
@@ -39,6 +39,7 @@ extern int cmd_mailsplit(int argc, const
extern int cmd_mv(int argc, const char **argv, const char *prefix);
extern int cmd_name_rev(int argc, const char **argv, const char *prefix);
extern int cmd_pack_objects(int argc, const char **argv, const char *prefix);
+extern int cmd_pickaxe(int argc, const char **argv, const char *prefix);
extern int cmd_prune(int argc, const char **argv, const char *prefix);
extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
extern int cmd_push(int argc, const char **argv, const char *prefix);
diff --git a/git.c b/git.c
index e089b53..6164380 100644
--- a/git.c
+++ b/git.c
@@ -245,6 +245,7 @@ static void handle_internal_command(int
{ "mv", cmd_mv, RUN_SETUP },
{ "name-rev", cmd_name_rev, RUN_SETUP },
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
+ { "pickaxe", cmd_pickaxe, RUN_SETUP },
{ "prune", cmd_prune, RUN_SETUP },
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
{ "push", cmd_push, RUN_SETUP },
diff --git a/t/t8003-pickaxe.sh b/t/t8003-pickaxe.sh
new file mode 100755
index 0000000..d09d1c9
--- /dev/null
+++ b/t/t8003-pickaxe.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+test_description='git-pickaxe'
+. ./test-lib.sh
+
+PROG='git pickaxe -c'
+. ../annotate-tests.sh
+
+test_done
--
1.4.3.rc2.gdce3
^ permalink raw reply related
* Re: [RFC] gitweb wishlist and TODO list
From: Junio C Hamano @ 2006-10-12 10:03 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <7v1wpfwg92.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> writes:
> Jakub Narebski <jnareb@gmail.com> writes:
>
>> * add summary of number of lines changed for each file (a la darcsview)
>> in the difftree part of commit and *diff* views, e.g.
>>
>> blame.c +1 -0 diff | history | blame
>>
>> or something like that.
>
> I'll place "diff --numstat" to the stack of "things to do on the
> core side". Should be trivial.
This is only lightly tested. I haven't done test suite nor
documentation, which the list should be able to take care of,
now my git day for this week is over ;-).
-- >8 --
[PATCH] diff --numstat
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
combine-diff.c | 9 ++++++---
diff.c | 29 +++++++++++++++++++++++++++--
diff.h | 15 ++++++++-------
3 files changed, 41 insertions(+), 12 deletions(-)
diff --git a/combine-diff.c b/combine-diff.c
index 46d9121..65c7868 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -856,8 +856,10 @@ void diff_tree_combined(const unsigned c
/* show stat against the first parent even
* when doing combined diff.
*/
- if (i == 0 && opt->output_format & DIFF_FORMAT_DIFFSTAT)
- diffopts.output_format = DIFF_FORMAT_DIFFSTAT;
+ int stat_opt = (opt->output_format &
+ (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT));
+ if (i == 0 && stat_opt)
+ diffopts.output_format = stat_opt;
else
diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
diff_tree_sha1(parent[i], sha1, "", &diffopts);
@@ -887,7 +889,8 @@ void diff_tree_combined(const unsigned c
}
needsep = 1;
}
- else if (opt->output_format & DIFF_FORMAT_DIFFSTAT)
+ else if (opt->output_format &
+ (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT))
needsep = 1;
if (opt->output_format & DIFF_FORMAT_PATCH) {
if (needsep)
diff --git a/diff.c b/diff.c
index fb82432..2dcad19 100644
--- a/diff.c
+++ b/diff.c
@@ -795,6 +795,23 @@ static void show_stats(struct diffstat_t
set, total_files, adds, dels, reset);
}
+static void show_numstat(struct diffstat_t* data, struct diff_options *options)
+{
+ int i;
+
+ for (i = 0; i < data->nr; i++) {
+ struct diffstat_file *file = data->files[i];
+
+ printf("%d\t%d\t", file->added, file->deleted);
+ if (options->line_termination &&
+ quote_c_style(file->name, NULL, NULL, 0))
+ quote_c_style(file->name, NULL, stdout, 0);
+ else
+ fputs(file->name, stdout);
+ putchar(options->line_termination);
+ }
+}
+
struct checkdiff_t {
struct xdiff_emit_state xm;
const char *filename;
@@ -1731,6 +1748,7 @@ int diff_setup_done(struct diff_options
DIFF_FORMAT_CHECKDIFF |
DIFF_FORMAT_NO_OUTPUT))
options->output_format &= ~(DIFF_FORMAT_RAW |
+ DIFF_FORMAT_NUMSTAT |
DIFF_FORMAT_DIFFSTAT |
DIFF_FORMAT_SUMMARY |
DIFF_FORMAT_PATCH);
@@ -1740,6 +1758,7 @@ int diff_setup_done(struct diff_options
* recursive bits for other formats here.
*/
if (options->output_format & (DIFF_FORMAT_PATCH |
+ DIFF_FORMAT_NUMSTAT |
DIFF_FORMAT_DIFFSTAT |
DIFF_FORMAT_CHECKDIFF))
options->recursive = 1;
@@ -1828,6 +1847,9 @@ int diff_opt_parse(struct diff_options *
else if (!strcmp(arg, "--patch-with-raw")) {
options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW;
}
+ else if (!strcmp(arg, "--numstat")) {
+ options->output_format |= DIFF_FORMAT_NUMSTAT;
+ }
else if (!strncmp(arg, "--stat", 6)) {
char *end;
int width = options->stat_width;
@@ -2602,7 +2624,7 @@ void diff_flush(struct diff_options *opt
separator++;
}
- if (output_format & DIFF_FORMAT_DIFFSTAT) {
+ if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_NUMSTAT)) {
struct diffstat_t diffstat;
memset(&diffstat, 0, sizeof(struct diffstat_t));
@@ -2612,7 +2634,10 @@ void diff_flush(struct diff_options *opt
if (check_pair_status(p))
diff_flush_stat(p, options, &diffstat);
}
- show_stats(&diffstat, options);
+ if (output_format & DIFF_FORMAT_NUMSTAT)
+ show_numstat(&diffstat, options);
+ if (output_format & DIFF_FORMAT_DIFFSTAT)
+ show_stats(&diffstat, options);
separator++;
}
diff --git a/diff.h b/diff.h
index b48c991..435c70c 100644
--- a/diff.h
+++ b/diff.h
@@ -26,20 +26,21 @@ typedef void (*diff_format_fn_t)(struct
#define DIFF_FORMAT_RAW 0x0001
#define DIFF_FORMAT_DIFFSTAT 0x0002
-#define DIFF_FORMAT_SUMMARY 0x0004
-#define DIFF_FORMAT_PATCH 0x0008
+#define DIFF_FORMAT_NUMSTAT 0x0004
+#define DIFF_FORMAT_SUMMARY 0x0008
+#define DIFF_FORMAT_PATCH 0x0010
/* These override all above */
-#define DIFF_FORMAT_NAME 0x0010
-#define DIFF_FORMAT_NAME_STATUS 0x0020
-#define DIFF_FORMAT_CHECKDIFF 0x0040
+#define DIFF_FORMAT_NAME 0x0100
+#define DIFF_FORMAT_NAME_STATUS 0x0200
+#define DIFF_FORMAT_CHECKDIFF 0x0400
/* Same as output_format = 0 but we know that -s flag was given
* and we should not give default value to output_format.
*/
-#define DIFF_FORMAT_NO_OUTPUT 0x0080
+#define DIFF_FORMAT_NO_OUTPUT 0x0800
-#define DIFF_FORMAT_CALLBACK 0x0100
+#define DIFF_FORMAT_CALLBACK 0x1000
struct diff_options {
const char *filter;
--
1.4.3.rc2.gdce3
^ permalink raw reply related
* Re: [RFC] separate .git from working directory
From: Sergio Callegari @ 2006-10-12 12:15 UTC (permalink / raw)
To: git
Possibly a bit different from the RFC, however,
Other than making find happy, I see other potential advantages in supporting
the two options of having .git be either
- a directory containing all the git stuff
- a single file with a pointer to the real directory containing the objects,
references, branches, etc.
1) It might make the life easier on platforms where symlinks are not the
easiest thing to do (are there any?)
2) it might make it easier to work with syncronization tools (some of you
might know that I got burnt with them recently). One of the issues of
syncronizatoin tools is that they typically recognize renames as the
non-atomical sequence of creation+deletion. Hence imagine the following
scenario. I have ProjectFoo with the .git dir in. I tell the syncronization
tool to ignore things called .git (not to get burned again!). I decide to
rename ProjectFoo into ProjectBar. When I sync, I get with a ProjectBar with
no .git directory since .git was meant to be ignored and is consequently lost
in the creation+deletion sequence. All objects are then lost at one of the
two hosts participating in the syncronization. If .git was only a file with a
pointer, it would at least be possible to recreate it by hand without
depending on the other syncronization host.
3) it might make it possible to have all the git archives in a single place,
where it is easy to program a script to scan all the archives and repack all
of them periodically or to scan all of them and backup them periodically,
etc.
Sergio
^ permalink raw reply
* [PATCH] diff: fix 2 whitespace issues
From: Johannes Schindelin @ 2006-10-12 12:22 UTC (permalink / raw)
To: git, junkio, Ray Lehtiniemi
When whitespace or whitespace change was ignored, the function
xdl_recmatch() returned memcmp() style differences, which is wrong,
since it should return 0 on non-match.
Also, there were three horrible off-by-one bugs, even leading to wrong
hashes in the whitespace special handling.
The issue was noticed by Ray Lehtiniemi.
For good measure, this commit adds a test.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
These bugs are embarassing. I have no idea how my tests succeeded
when I submitted the support for -b and -w...
Note that "git diff --check" complains about six whitespaces
at the end of line in the test, which are there on purpose.
t/t4015-diff-whitespace.sh | 122 ++++++++++++++++++++++++++++++++++++++++++++
xdiff/xutils.c | 29 ++++------
2 files changed, 134 insertions(+), 17 deletions(-)
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
new file mode 100755
index 0000000..c945085
--- /dev/null
+++ b/t/t4015-diff-whitespace.sh
@@ -0,0 +1,122 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Johannes E. Schindelin
+#
+
+test_description='Test special whitespace in diff engine.
+
+'
+. ./test-lib.sh
+. ../diff-lib.sh
+
+# Ray Lehtiniemi's example
+
+cat << EOF > x
+do {
+ nothing;
+} while (0);
+EOF
+
+git-update-index --add x
+
+cat << EOF > x
+do
+{
+ nothing;
+}
+while (0);
+EOF
+
+cat << EOF > expect
+diff --git a/x b/x
+index adf3937..6edc172 100644
+--- a/x
++++ b/x
+@@ -1,3 +1,5 @@
+-do {
++do
++{
+ nothing;
+-} while (0);
++}
++while (0);
+EOF
+
+git-diff > out
+test_expect_success "Ray's example without options" 'diff -u expect out'
+
+git-diff -w > out
+test_expect_success "Ray's example with -w" 'diff -u expect out'
+
+git-diff -b > out
+test_expect_success "Ray's example with -b" 'diff -u expect out'
+
+cat << EOF > x
+whitespace at beginning
+whitespace change
+whitespace in the middle
+whitespace at end
+unchanged line
+CR at end
+EOF
+
+git-update-index x
+
+cat << EOF > x
+ whitespace at beginning
+whitespace change
+white space in the middle
+whitespace at end
+unchanged line
+CR at end
+EOF
+
+cat << EOF > expect
+diff --git a/x b/x
+index d99af23..8b32fb5 100644
+--- a/x
++++ b/x
+@@ -1,6 +1,6 @@
+-whitespace at beginning
+-whitespace change
+-whitespace in the middle
+-whitespace at end
++ whitespace at beginning
++whitespace change
++white space in the middle
++whitespace at end
+ unchanged line
+-CR at end
++CR at end
+EOF
+git-diff > out
+test_expect_success 'another test, without options' 'diff -u expect out'
+
+cat << EOF > expect
+diff --git a/x b/x
+index d99af23..8b32fb5 100644
+EOF
+git-diff -w > out
+test_expect_success 'another test, with -w' 'diff -u expect out'
+
+cat << EOF > expect
+diff --git a/x b/x
+index d99af23..8b32fb5 100644
+--- a/x
++++ b/x
+@@ -1,6 +1,6 @@
+-whitespace at beginning
++ whitespace at beginning
+ whitespace change
+-whitespace in the middle
+-whitespace at end
++white space in the middle
++whitespace at end
+ unchanged line
+-CR at end
++CR at end
+EOF
+git-diff -b > out
+test_expect_success 'another test, with -b' 'diff -u expect out'
+
+test_done
diff --git a/xdiff/xutils.c b/xdiff/xutils.c
index f7bdd39..9e4bb47 100644
--- a/xdiff/xutils.c
+++ b/xdiff/xutils.c
@@ -191,36 +191,30 @@ int xdl_recmatch(const char *l1, long s1
int i1, i2;
if (flags & XDF_IGNORE_WHITESPACE) {
- for (i1 = i2 = 0; i1 < s1 && i2 < s2; i1++, i2++) {
+ for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) {
if (isspace(l1[i1]))
while (isspace(l1[i1]) && i1 < s1)
i1++;
- else if (isspace(l2[i2]))
+ if (isspace(l2[i2]))
while (isspace(l2[i2]) && i2 < s2)
i2++;
- else if (l1[i1] != l2[i2])
- return l2[i2] - l1[i1];
+ if (i1 < s1 && i2 < s2 && l1[i1++] != l2[i2++])
+ return 0;
}
- if (i1 >= s1)
- return 1;
- else if (i2 >= s2)
- return -1;
+ return (i1 >= s1 && i2 >= s2);
} else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {
- for (i1 = i2 = 0; i1 < s1 && i2 < s2; i1++, i2++) {
+ for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) {
if (isspace(l1[i1])) {
if (!isspace(l2[i2]))
- return -1;
+ return 0;
while (isspace(l1[i1]) && i1 < s1)
i1++;
while (isspace(l2[i2]) && i2 < s2)
i2++;
- } else if (l1[i1] != l2[i2])
- return l2[i2] - l1[i1];
+ } else if (l1[i1++] != l2[i2++])
+ return 0;
}
- if (i1 >= s1)
- return 1;
- else if (i2 >= s2)
- return -1;
+ return (i1 >= s1 && i2 >= s2);
} else
return s1 == s2 && !memcmp(l1, l2, s1);
@@ -233,7 +227,8 @@ unsigned long xdl_hash_record(char const
for (; ptr < top && *ptr != '\n'; ptr++) {
if (isspace(*ptr) && (flags & XDF_WHITESPACE_FLAGS)) {
- while (ptr < top && isspace(*ptr) && ptr[1] != '\n')
+ while (ptr + 1 < top && isspace(ptr[1])
+ && ptr[1] != '\n')
ptr++;
if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {
ha += (ha << 5);
--
1.4.3.rc2.g4e05
^ permalink raw reply related
* Re: [RFC] separate .git from working directory
From: Alex Riesen @ 2006-10-12 13:03 UTC (permalink / raw)
To: Sergio Callegari; +Cc: git
In-Reply-To: <200610121415.03086.scallegari@arces.unibo.it>
On 10/12/06, Sergio Callegari <scallegari@arces.unibo.it> wrote:
> 1) It might make the life easier on platforms where symlinks are not the
> easiest thing to do (are there any?)
yes. The most widespread one, for a start.
^ permalink raw reply
* Feature: add --force option to cg-push.
From: Pierre Marc Dumuid @ 2006-10-12 13:30 UTC (permalink / raw)
To: git
[-- Attachment #1: Type: text/plain, Size: 281 bytes --]
If I cg-push on a remote branch after changing my mind about how I
wanted the branch ordered, it will complain and say "maybee you need to
update"
I didn't know what to do, since I was on the "no" side of maybee.
Here is a patch that adds the --force option for those people.
[-- Attachment #2: cg_push_forceoption.diff --]
[-- Type: text/x-patch, Size: 1886 bytes --]
--- /home/pmdumuid/bin/cg-push2 2006-10-12 22:38:49.000000000 +0930
+++ /usr/bin/cg-push 2006-09-26 14:30:09.000000000 +0930
@@ -27,15 +27,8 @@
# future, cg-push should push tags automatically. Also note
# that even if you pass `cg-push` the '-t' arguments, your
# HEAD is still pushed as well in addition to the tags.
-#
-# --force
-# Usually, the command refuses to update a remote ref that is
-# not an ancestor of the local ref used to overwrite it. This
-# flag disables the check. What this means is that the remote
-# repository can lose commits; use it with care.
-#
-#
-USAGE="cg-push [--force] [-r LOCAL_BRANCH] [REMOTE_BRANCH] [-t TAG]..."
+
+USAGE="cg-push [-r LOCAL_BRANCH] [REMOTE_BRANCH] [-t TAG]..."
. "${COGITO_LIB:-/usr/lib/cogito/}"cg-Xlib || exit 1
@@ -44,12 +37,11 @@
{
name="$1"; shift
commit="$(cg-object-id -c "$locbranch")"; old="$(cat "$_git/refs/heads/$name" 2>/dev/null)"
- git-send-pack $force "$@" && git-update-ref refs/heads/"$name" "$commit" $old
+ git-send-pack "$@" && git-update-ref refs/heads/"$name" "$commit" $old
}
locbranch="$_git_head"
-force=""
tags=()
while optparse; do
if optparse -r=; then
@@ -57,8 +49,6 @@
[ "$(cg-object-id -c "$locbranch")" ] || exit 1
elif optparse -t=; then
tags[${#tags[@]}]="refs/tags/$OPTARG"
- elif optparse --force; then
- force="--force"
else
optfail
fi
@@ -79,7 +69,7 @@
sprembranch=":refs/heads/$rembranch"
if [ "${uri#http://}" != "$uri" -o "${uri#https://}" != "$uri" ]; then
- git-http-push $force "$uri/" "$locbranch$sprembranch" "${tags[@]}"
+ git-http-push "$uri/" "$locbranch$sprembranch" "${tags[@]}"
elif [ "${uri#git+ssh://}" != "$uri" ]; then
send_pack_update "$name" "$(echo "$uri" | sed 's#^git+ssh://\([^/]*\)\(/.*\)$#\1:\2#')" "$locbranch$sprembranch" "${tags[@]}"
elif [ "${uri#rsync://}" != "$uri" ]; then
^ permalink raw reply
* Re: cg-commit does not run pre-commit hook?
From: Wolfgang Denk @ 2006-10-12 14:27 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
In-Reply-To: <20061012011548.GT20017@pasky.or.cz>
Dear Petr,
in message <20061012011548.GT20017@pasky.or.cz> you wrote:
>
> historically, Git and Cogito use a different set of hooks (Cogito got
> hooks first but Git picked own names and usage and now is prevalent).
I see. And current versions of cogito don't support any pre-commit
script, right?
> I have plans for making Cogito support Git hooks and slowly deprecate
> those own ones for which Git has counterparts, but didn't get to it yet.
> I might do today during the more boring lectures... ;-)
Keeping my fingers crossed :-)
I'm looking for a way to register the commit message into some
changelog file which gets checked in with the same commit. Or is
there another way to do this?
Best regards,
Wolfgang Denk
--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
The goal of science is to build better mousetraps. The goal of nature
is to build better mice.
^ permalink raw reply
* Re: cg-commit does not run pre-commit hook?
From: Andreas Ericsson @ 2006-10-12 14:42 UTC (permalink / raw)
To: Wolfgang Denk; +Cc: Petr Baudis, git
In-Reply-To: <20061012142736.74DE7353BDE@atlas.denx.de>
Wolfgang Denk wrote:
> Dear Petr,
>
> in message <20061012011548.GT20017@pasky.or.cz> you wrote:
>> historically, Git and Cogito use a different set of hooks (Cogito got
>> hooks first but Git picked own names and usage and now is prevalent).
>
> I see. And current versions of cogito don't support any pre-commit
> script, right?
>
>> I have plans for making Cogito support Git hooks and slowly deprecate
>> those own ones for which Git has counterparts, but didn't get to it yet.
>> I might do today during the more boring lectures... ;-)
>
> Keeping my fingers crossed :-)
>
> I'm looking for a way to register the commit message into some
> changelog file which gets checked in with the same commit. Or is
> there another way to do this?
>
git log
The commit message is already saved and git (and cogito, I presume)
provide tools to fetch those messages in the relevant different orders
(although ordering by date is flakey sometimes; see list-archives for
discussion).
One part of why a proper SCM is so good to use is that you shouldn't
have to maintain a separate changelog. The SCM should create one for you
when you ask it, based on the comments you've entered when actually
making the changes.
That aside, for actual releases, I generally write a short, gisted
"what's new" thingie inside the tag, based on the shortlog output and my
own memory. This comes in handy when management wants to have their
version of the shortlog, and developers can pretty easily find new
features by just sifting through the tag-messages.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply
* gitk does not appreciate file names including spaces
From: Sergio Callegari @ 2006-10-12 14:45 UTC (permalink / raw)
To: git
Just a short notice about it. Not a big issue, really... just that in the
quadrant at the bottom right of the gitk screen, filenames including spaces
are not shown properly.
Sergio
--
----------------------------------------------------------------
Dr. Sergio Callegari Via Fontanelle 40
Researcher 47100 Forlì
II School of Engineering Tel. +39.0543.786927
University of Bologna Fax. +39.0543.786926
Affiliated with:
DEIS - Dept. of Electronics, Computer Sciences and Systems,
University of Bologna (www.deis.unibo.it)
ARCES - Advanced Research Center on Electronic Systems for
Information and Communication Technologies
Unversity of Bologna (www.arces.unibo.it)
================================================================
^ permalink raw reply
* Re: [PATCH 3/3] diff --stat: sometimes use non-linear scaling.
From: apodtele @ 2006-10-12 15:04 UTC (permalink / raw)
To: git
Sublinear solution without patch is below.
On Sept 28, 2006 Martin Waitz wrote:
> On Wed, Sep 27, 2006 at 08:12:49AM -0700, Linus Torvalds wrote:
>> No _way_ is it correct to show more than three characters if there were
>> three lines of changes.
>>
>> I think "nonlinear" is fine, but this is something that is "superlinear"
>> in small changes, and then sublinear in bigger ones (and then apparently
>> totally wrong for one-line changes).
>>
>> It should at least never be superlinear, I believe.
>
> So if we want to keep the logarithmic scale we can do some maths:
> Assume we use a formula ala
> length = a log(change + b) + c
You are probably looking for much simpler, log-less, and pure integer:
length = width * change / (width + change) + 1
Assuming target witdth of 40, for example, it will produce
Change Length
1 1
2 2
3 3
4 4
10 9
20 14
30 18
50 23
100 29
1000 39
10000 40
1000000 40
--
Alexei
^ permalink raw reply
* [PATCH] [PATCH] gitk: Handle spaces in filenames
From: Ray Lehtiniemi @ 2006-10-12 15:03 UTC (permalink / raw)
To: git; +Cc: Ray Lehtiniemi
In-Reply-To: <11606654193083-git-send-email-rayl@mail.com>
---
gitk | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/gitk b/gitk
index ebbeac6..3196719 100755
--- a/gitk
+++ b/gitk
@@ -4324,7 +4324,7 @@ proc gettreediffline {gdtf ids} {
}
return
}
- set file [lindex $line 5]
+ set file [lrange $line 5 end]
lappend treediff $file
}
--
1.4.3.rc2.ge19ff
^ permalink raw reply related
* Re: cg-commit does not run pre-commit hook?
From: Wolfgang Denk @ 2006-10-12 15:54 UTC (permalink / raw)
To: Andreas Ericsson; +Cc: Petr Baudis, git
In-Reply-To: <452E545F.6060406@op5.se>
Dear Andreas,
in message <452E545F.6060406@op5.se> you wrote:
>
> > I'm looking for a way to register the commit message into some
> > changelog file which gets checked in with the same commit. Or is
> > there another way to do this?
>
> git log
Sorry, this does not work, as I can access the commit message only
*after* the commit completed, and then it's too late to get it into a
file that shall be included with the very same commit.
> The commit message is already saved and git (and cogito, I presume)
> provide tools to fetch those messages in the relevant different orders
Yes, but only *after* doing the job. That's why I'm looking for a
pre-commit hook.
> One part of why a proper SCM is so good to use is that you shouldn't
> have to maintain a separate changelog. The SCM should create one for you
> when you ask it, based on the comments you've entered when actually
> making the changes.
True, as long as you can work within the SCM. The changelog file I'm
talking about is mostly for people who just work with exported trees
(for example, when they download a tarball).
Best regards,
Wolfgang Denk
--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Everyting looks interesting until you do it. Then you find it's just
another job. - Terry Pratchett, _Moving Pictures_
^ permalink raw reply
* Re: [PATCH] git-pickaxe: blame rewritten.
From: Linus Torvalds @ 2006-10-12 15:58 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7v7iz5rk4b.fsf@assigned-by-dhcp.cox.net>
On Thu, 12 Oct 2006, Junio C Hamano wrote:
> +
> +SYNOPSIS
> +--------
> +'git-pickaxe' [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S <revs-file>] [--] <file> [<rev>]
Btw, could we please get rid of this horrible command line syntax.
Pretty much _every_ other git command takes the form
git cmd [<rev>] [--] <path>
but for some reason annotate and blame (and now pickaxe) do it the wrong
way around, and do
git cmd [--] <path> [<rev>]
which is just irritating to somebody who has grown very used to being able
to specify revisions first.
(I'd actually also like to have a range-modifier, so that I could do
git annotate --since=2.weeks.ago v2.6.18.. <path>
that didn't go back beyond a certain point, so the command line syntax
actually _does_ matter - even if we don't support that now, having the
regular command line syntax means that we -could- support it some day).
Linus
^ permalink raw reply
* [PATCH] Documentation: add missing second colons and remove a typo
From: Rene Scharfe @ 2006-10-12 16:26 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git Mailing List
It takes two colons to mark text as item label.
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
---
Documentation/git-http-push.txt | 2 +-
Documentation/git-send-pack.txt | 2 +-
Documentation/git-shortlog.txt | 4 ++--
Documentation/glossary.txt | 4 ++--
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-http-push.txt b/Documentation/git-http-push.txt
index 7e1f894..c2485c6 100644
--- a/Documentation/git-http-push.txt
+++ b/Documentation/git-http-push.txt
@@ -34,7 +34,7 @@ OPTIONS
Report the list of objects being walked locally and the
list of objects successfully sent to the remote repository.
-<ref>...:
+<ref>...::
The remote refs to update.
diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt
index 9e67f17..5376f68 100644
--- a/Documentation/git-send-pack.txt
+++ b/Documentation/git-send-pack.txt
@@ -43,7 +43,7 @@ OPTIONS
<directory>::
The repository to update.
-<ref>...:
+<ref>...::
The remote refs to update.
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index 1601d22..d54fc3e 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -27,8 +27,8 @@ OPTIONS
Sort output according to the number of commits per author instead
of author alphabetic order.
--s:
- Supress commit description and Provide a commit count summary only.
+-s::
+ Supress commit description and provide a commit count summary only.
FILES
-----
diff --git a/Documentation/glossary.txt b/Documentation/glossary.txt
index 14449ca..7e560b0 100644
--- a/Documentation/glossary.txt
+++ b/Documentation/glossary.txt
@@ -179,7 +179,7 @@ object name::
character hexadecimal encoding of the hash of the object (possibly
followed by a white space).
-object type:
+object type::
One of the identifiers "commit","tree","tag" and "blob" describing
the type of an object.
@@ -324,7 +324,7 @@ tag::
A tag is most typically used to mark a particular point in the
commit ancestry chain.
-unmerged index:
+unmerged index::
An index which contains unmerged index entries.
working tree::
^ permalink raw reply related
* Re: [PATCH] diff: fix 2 whitespace issues
From: Junio C Hamano @ 2006-10-12 16:40 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0610121418180.14200@wbgn013.biozentrum.uni-wuerzburg.de>
I noticed this breakage sometime last week and it was sitting at
near the bottom of my stack of things to look at. Ray's
bugreport and your fix were quite timely. Thanks.
You mentioned six whitespace problems but I counted only three
and the test failed on "CR at the end"; the test vector was easy
to hand-fix thanks to the "index" line.
This patch is an example that we do not want to transmit files
that has CRs in e-mail. These CRs appear in format-patch
output, so either the user needs to do --attach (and perhaps the
option needs to do base64 or qp in such a case) or format-patch
needs to treat a blob with CR as binary and emit binary diff?
The latter is not appropriate since patches apply just fine with
CR in them.
^ permalink raw reply
* Re: cg-commit does not run pre-commit hook?
From: Linus Torvalds @ 2006-10-12 16:59 UTC (permalink / raw)
To: Wolfgang Denk; +Cc: Andreas Ericsson, Petr Baudis, git
In-Reply-To: <20061012155444.27391353BDE@atlas.denx.de>
On Thu, 12 Oct 2006, Wolfgang Denk wrote:
> >
> > git log
>
> Sorry, this does not work, as I can access the commit message only
> *after* the commit completed, and then it's too late to get it into a
> file that shall be included with the very same commit.
Why? That's just stupid.
If you want to have a ChangeLog file, it's _much_ better to just
auto-generate it after the fact. When you cut a tar-file, just have the
script autogenerate the changelog then and there. Why do it inside the
SCM that keeps track of the data _anyway_.
> True, as long as you can work within the SCM. The changelog file I'm
> talking about is mostly for people who just work with exported trees
> (for example, when they download a tarball).
Right - but it's easy enough to add it to the tar-ball, so..
Linus
^ permalink raw reply
* Re: cg-commit does not run pre-commit hook?
From: Josef Weidendorfer @ 2006-10-12 17:02 UTC (permalink / raw)
To: Wolfgang Denk; +Cc: Andreas Ericsson, Petr Baudis, git
In-Reply-To: <20061012155444.27391353BDE@atlas.denx.de>
On Thursday 12 October 2006 17:54, Wolfgang Denk wrote:
> Yes, but only *after* doing the job. That's why I'm looking for a
> pre-commit hook.
pre-commit is not good either, as it runs *before* the editor pops up.
So it can not access the commit message.
You ask for a "pre-commit-post-edit" hook, which AFAIK currently
is not available in git.
> True, as long as you can work within the SCM. The changelog file I'm
> talking about is mostly for people who just work with exported trees
> (for example, when they download a tarball).
Can't you create the Changelog directly before preparing such an
tarball?
Usually when making a release/snapshot for a typical project, you
can not directly take the newest tree from the SCM, but need
to generate some files (like configure with automake/autoconf).
Josef
>
>
> Best regards,
>
> Wolfgang Denk
>
^ permalink raw reply
* Re: cg-commit does not run pre-commit hook?
From: Linus Torvalds @ 2006-10-12 17:20 UTC (permalink / raw)
To: Wolfgang Denk; +Cc: Andreas Ericsson, Petr Baudis, git
In-Reply-To: <Pine.LNX.4.64.0610120957460.3952@g5.osdl.org>
On Thu, 12 Oct 2006, Linus Torvalds wrote:
>
> Why? That's just stupid.
Btw, let me explain that strong statement, because it _is_ a strong
statement, but it's true.
The problem with trying to generate a changelog entry at commit time is
that it is fundamentally a broken concept in a distributed environment.
What happens at a merge event? Sure, you can have special merge magic to
try to sort out the mess, but it _is_ a mess. You can make things "work",
but you can never actually make the result really make _sense_. The
changelog is fundamentally a serialization of something that wasn't
serial.
Now, the same serialization problem obviously exists when you
auto-generate the changelog file when doing a release tar-ball or
something like that, but at that point you basically "fix" it in time, so
at that point the changelog actually makes sense.
It also turns out that in many situations, you can sort the result in
other ways: the shortlog format, for example, is often superior to the
default "git log" ordering, just because sorting things by person tends to
actually result in a better view of what changed (it tells you something
new: clumping by author not onyl tends to clump similar commits together
and thus tell more of a "story", but it also has the added advantage of
telling people who does what).
Generating things after-the-fact would also allow ordering things by what
files (or subdirectories) they touch, although we've never done such a
script. I do that quite often privately by just restricting the log to
certain subsystems, though, and it's a damn useful thing to have. I would
not be surprised at all if it might make sense to actually do a "tar-ball"
changelog that way for certain projects - especially if they have clearly
separated sub-components.
[ Btw, this whole "do things by pathname" has been so successful, that
I've come to realize that I would probably never accept an SCM that
doesn't allow something like that. Being able to do
gitk some/random/set of/directories and/files
is just _incredibly_ useful. Maybe others don't do it as much as I do,
but as a top-level maintainer, being able to look at history from the
viewpoint of just a random subset of the tree is incredibly powerful.
I very strongly suspect that doing logs that way is often a good idea
too. ]
Linus
^ 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