* [PATCH/RFC v4 5/5] interpret_nth_last_branch(): avoid traversing the reflogs twice
From: Thomas Rast @ 2009-01-17 16:09 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Johannes Schindelin, Johannes Sixt, Johan Herland,
Johannes Schindelin
In-Reply-To: <1232208597-29249-5-git-send-email-trast@student.ethz.ch>
From: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Instead of traversing them twice, we just build a list of branch switches,
pick the one we're interested in, and free the list again.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
sha1_name.c | 61 ++++++++++++++++++++++++----------------------------------
1 files changed, 25 insertions(+), 36 deletions(-)
diff --git a/sha1_name.c b/sha1_name.c
index 9e1538e..b21a1f0 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -5,6 +5,8 @@
#include "blob.h"
#include "tree-walk.h"
#include "refs.h"
+#include "cache-tree.h"
+#include "string-list.h"
static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
{
@@ -684,43 +686,31 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1)
return retval;
}
-struct grab_nth_branch_switch_cbdata {
- int counting;
- int nth;
- struct strbuf *buf;
-};
-
-static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
+static int add_one_branch_switch(unsigned char *osha1, unsigned char *nsha1,
const char *email, unsigned long timestamp, int tz,
const char *message, void *cb_data)
{
- struct grab_nth_branch_switch_cbdata *cb = cb_data;
+ struct string_list *list = cb_data;
const char *match = NULL, *target = NULL;
size_t len;
- if (!prefixcmp(message, "checkout: moving from ")) {
- match = message + strlen("checkout: moving from ");
- if ((target = strstr(match, " to ")) != NULL)
- target += 4;
- }
-
- if (!match)
+ if (prefixcmp(message, "checkout: moving from "))
return 0;
- len = target - match - 4;
- if (target[len] == '\n' && !strncmp(match, target, len))
- return 0;
+ match = message + strlen("checkout: moving from ");
- if (cb->counting) {
- cb->nth++;
- return 0;
+ /* Is it "moving" from a branch to itself? Then ignore it. */
+ if ((target = strstr(match, " to ")) != NULL) {
+ target += 4;
+ len = target - match - 4;
+ if (target[len] == '\n' && !strncmp(match, target, len))
+ return 0;
}
+ else
+ len = strchrnul(match, ' ') - match;
+
+ string_list_append(xstrndup(match, len), list);
- if (cb->nth-- <= 0) {
- strbuf_reset(cb->buf);
- strbuf_add(cb->buf, match, len);
- return 1;
- }
return 0;
}
@@ -738,7 +728,7 @@ static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
int interpret_nth_last_branch(const char *name, struct strbuf *buf)
{
int nth;
- struct grab_nth_branch_switch_cbdata cb;
+ struct string_list branch_list = { NULL, 0, 0, 0 };
const char *brace;
char *num_end;
@@ -751,18 +741,17 @@ int interpret_nth_last_branch(const char *name, struct strbuf *buf)
if (num_end != brace)
return -1;
- cb.counting = 1;
- cb.nth = 0;
- cb.buf = buf;
- for_each_reflog_ent("HEAD", grab_nth_branch_switch, &cb);
+ for_each_reflog_ent("HEAD", add_one_branch_switch, &branch_list);
- if (cb.nth < nth)
+ if (branch_list.nr < nth)
return 0;
- cb.counting = 0;
- cb.nth -= nth;
- cb.buf = buf;
- for_each_reflog_ent("HEAD", grab_nth_branch_switch, &cb);
+ strbuf_reset(buf);
+ strbuf_addstr(buf, branch_list.items[branch_list.nr - nth].string);
+
+ /* force free()ing the items */
+ branch_list.strdup_strings = 1;
+ string_list_clear(&branch_list, 0);
return brace-name+1;
}
--
1.6.1.315.g92577
^ permalink raw reply related
* [PATCH/RFC v4 3/5] sha1_name: support @{-N} syntax in get_sha1()
From: Thomas Rast @ 2009-01-17 16:09 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Johannes Schindelin, Johannes Sixt, Johan Herland
In-Reply-To: <1232208597-29249-3-git-send-email-trast@student.ethz.ch>
Let get_sha1() parse the @{-N} syntax, with docs and tests.
Note that while @{-1}^2, @{-2}~5 and such are supported, @{-1}@{1} is
currently not allowed.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
Documentation/git-rev-parse.txt | 3 ++
sha1_name.c | 16 +++++++--
t/t1505-rev-parse-last.sh | 71 +++++++++++++++++++++++++++++++++++++++
3 files changed, 87 insertions(+), 3 deletions(-)
create mode 100755 t/t1505-rev-parse-last.sh
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 2921da3..3ccef2f 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -212,6 +212,9 @@ when you run 'git-merge'.
reflog of the current branch. For example, if you are on the
branch 'blabla', then '@\{1\}' means the same as 'blabla@\{1\}'.
+* The special construct '@\{-<n>\}' means the <n>th branch checked out
+ before the current one.
+
* A suffix '{caret}' to a revision parameter means the first parent of
that commit object. '{caret}<n>' means the <n>th parent (i.e.
'rev{caret}'
diff --git a/sha1_name.c b/sha1_name.c
index 34e39db..9e1538e 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -297,6 +297,8 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
return logs_found;
}
+static int get_sha1_1(const char *name, int len, unsigned char *sha1);
+
static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
{
static const char *warning = "warning: refname '%.*s' is ambiguous.\n";
@@ -307,7 +309,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
if (len == 40 && !get_sha1_hex(str, sha1))
return 0;
- /* basic@{time or number} format to query ref-log */
+ /* basic@{time or number or -number} format to query ref-log */
reflog_len = at = 0;
if (str[len-1] == '}') {
for (at = 0; at < len - 1; at++) {
@@ -324,6 +326,16 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
return -1;
if (!len && reflog_len) {
+ struct strbuf buf = STRBUF_INIT;
+ int ret;
+ /* try the @{-N} syntax for n-th checkout */
+ ret = interpret_nth_last_branch(str+at, &buf);
+ if (ret > 0) {
+ /* substitute this branch name and restart */
+ return get_sha1_1(buf.buf, buf.len, sha1);
+ } else if (ret == 0) {
+ return -1;
+ }
/* allow "@{...}" to mean the current branch reflog */
refs_found = dwim_ref("HEAD", 4, sha1, &real_ref);
} else if (reflog_len)
@@ -379,8 +391,6 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
return 0;
}
-static int get_sha1_1(const char *name, int len, unsigned char *sha1);
-
static int get_parent(const char *name, int len,
unsigned char *result, int idx)
{
diff --git a/t/t1505-rev-parse-last.sh b/t/t1505-rev-parse-last.sh
new file mode 100755
index 0000000..1e49dd2
--- /dev/null
+++ b/t/t1505-rev-parse-last.sh
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+test_description='test @{-N} syntax'
+
+. ./test-lib.sh
+
+
+make_commit () {
+ echo "$1" > "$1" &&
+ git add "$1" &&
+ git commit -m "$1"
+}
+
+
+test_expect_success 'setup' '
+
+ make_commit 1 &&
+ git branch side &&
+ make_commit 2 &&
+ make_commit 3 &&
+ git checkout side &&
+ make_commit 4 &&
+ git merge master &&
+ git checkout master
+
+'
+
+# 1 -- 2 -- 3 master
+# \ \
+# \ \
+# --- 4 --- 5 side
+#
+# and 'side' should be the last branch
+
+git log --graph --all --pretty=oneline --decorate
+
+test_rev_equivalent () {
+
+ git rev-parse "$1" > expect &&
+ git rev-parse "$2" > output &&
+ test_cmp expect output
+
+}
+
+test_expect_success '@{-1} works' '
+ test_rev_equivalent side @{-1}
+'
+
+test_expect_success '@{-1}~2 works' '
+ test_rev_equivalent side~2 @{-1}~2
+'
+
+test_expect_success '@{-1}^2 works' '
+ test_rev_equivalent side^2 @{-1}^2
+'
+
+test_expect_failure '@{-1}@{1} works' '
+ test_rev_equivalent side@{1} @{-1}@{1}
+'
+
+test_expect_success '@{-2} works' '
+ test_rev_equivalent master @{-2}
+'
+
+test_expect_success '@{-3} fails' '
+ test_must_fail git rev-parse @{-3}
+'
+
+test_done
+
+
--
1.6.1.315.g92577
^ permalink raw reply related
* [PATCH] contrib/workdir: create logs/refs and rr-cache in the origin repository
From: Adeodato Simó @ 2009-01-17 16:15 UTC (permalink / raw)
To: git, gitster; +Cc: Adeodato Simó
If logs/refs or rr-cache are dangling symlinks in the workdir, and reflogs
and/or rerere are enabled, commit will die with "fatal: Could not create
directory". (In the case of rr-cache, it will die after having created the
commit.)
This commit just creates logs/refs and rr-cache in the origin repository if
they don't exist already.
Signed-off-by: Adeodato Simó <dato@net.com.org.es>
---
contrib/workdir/git-new-workdir | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/contrib/workdir/git-new-workdir b/contrib/workdir/git-new-workdir
index 993cacf..a4e89d0 100755
--- a/contrib/workdir/git-new-workdir
+++ b/contrib/workdir/git-new-workdir
@@ -66,6 +66,12 @@ mkdir -p "$new_workdir/.git" || die "unable to create \"$new_workdir\"!"
for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache svn
do
case $x in
+ logs/refs|rr-cache)
+ if [ ! -e "$git_dir/$x" ]; then
+ mkdir -p "$git_dir/$x"
+ fi
+ esac
+ case $x in
*/*)
mkdir -p "$(dirname "$new_workdir/.git/$x")"
;;
--
1.6.1.263.g35eb3c
^ permalink raw reply related
* [PATCH v4 0/7] customizable --color-words
From: Thomas Rast @ 2009-01-17 16:29 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Johannes Schindelin, Santi Béjar,
Boyd Stephen Smith Jr., Teemu Likonen
In-Reply-To: <alpine.DEB.1.00.0901162208180.3586@pacific.mpi-cbg.de>
Johannes Schindelin wrote:
> Thomas, could you pick up the patches from my 'my-next' branch and
> maintain an "official" topic branch?
I cherry-picked the three commits you had there, and rebuilt on top.
I pushed them to
git://repo.or.cz/git/trast.git tr/word-diff-p2
again (js/word-diff-p1 again points directly at your half).
The changes on your side since my last push (hence your last sent
patches&squashes I collected) were only a pair of quotes changed from
double to single.
On my side I mainly tweaked the TeX pattern since I noticed it didn't
match many non-alnums such as (), and therefore declare them
unchanged:
- "\\\\[a-zA-Z@]+|[][{}]|\\\\.|[a-zA-Z0-9\x80-\xff]+"),
+ "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+|[^[:space:]]"),
I also added a clause to the C++ pattern to allow it to match
declarations such as
int Foo::bar(...)
(it would give up on the :: before).
Johannes Schindelin (4):
Add color_fwrite_lines(), a function coloring each line individually
color-words: refactor word splitting and use ALLOC_GROW()
color-words: change algorithm to allow for 0-character word
boundaries
color-words: take an optional regular expression describing words
Thomas Rast (3):
color-words: enable REG_NEWLINE to help user
color-words: expand docs with precise semantics
color-words: make regex configurable via attributes
Documentation/diff-options.txt | 17 +++-
Documentation/gitattributes.txt | 21 ++++
color.c | 28 +++++
color.h | 1 +
diff.c | 222 ++++++++++++++++++++++++++-------------
diff.h | 1 +
t/t4034-diff-words.sh | 159 ++++++++++++++++++++++++++++
userdiff.c | 78 +++++++++++---
userdiff.h | 1 +
9 files changed, 440 insertions(+), 88 deletions(-)
create mode 100755 t/t4034-diff-words.sh
^ permalink raw reply
* [PATCH v4 2/7] color-words: refactor word splitting and use ALLOC_GROW()
From: Thomas Rast @ 2009-01-17 16:29 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Johannes Schindelin, Santi Béjar,
Boyd Stephen Smith Jr., Teemu Likonen
In-Reply-To: <1232209788-10408-2-git-send-email-trast@student.ethz.ch>
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Word splitting is now performed by the function diff_words_fill(),
avoiding having the same code twice.
In the same spirit, avoid duplicating the code of ALLOC_GROW().
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
diff.c | 40 +++++++++++++++++++---------------------
1 files changed, 19 insertions(+), 21 deletions(-)
diff --git a/diff.c b/diff.c
index d235482..c111eef 100644
--- a/diff.c
+++ b/diff.c
@@ -326,10 +326,7 @@ struct diff_words_buffer {
static void diff_words_append(char *line, unsigned long len,
struct diff_words_buffer *buffer)
{
- if (buffer->text.size + len > buffer->alloc) {
- buffer->alloc = (buffer->text.size + len) * 3 / 2;
- buffer->text.ptr = xrealloc(buffer->text.ptr, buffer->alloc);
- }
+ ALLOC_GROW(buffer->text.ptr, buffer->text.size + len, buffer->alloc);
line++;
len--;
memcpy(buffer->text.ptr + buffer->text.size, line, len);
@@ -398,6 +395,22 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
}
}
+/*
+ * This function splits the words in buffer->text, and stores the list with
+ * newline separator into out.
+ */
+static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out)
+{
+ int i;
+ out->size = buffer->text.size;
+ out->ptr = xmalloc(out->size);
+ memcpy(out->ptr, buffer->text.ptr, out->size);
+ for (i = 0; i < out->size; i++)
+ if (isspace(out->ptr[i]))
+ out->ptr[i] = '\n';
+ buffer->current = 0;
+}
+
/* this executes the word diff on the accumulated buffers */
static void diff_words_show(struct diff_words_data *diff_words)
{
@@ -405,26 +418,11 @@ static void diff_words_show(struct diff_words_data *diff_words)
xdemitconf_t xecfg;
xdemitcb_t ecb;
mmfile_t minus, plus;
- int i;
memset(&xpp, 0, sizeof(xpp));
memset(&xecfg, 0, sizeof(xecfg));
- minus.size = diff_words->minus.text.size;
- minus.ptr = xmalloc(minus.size);
- memcpy(minus.ptr, diff_words->minus.text.ptr, minus.size);
- for (i = 0; i < minus.size; i++)
- if (isspace(minus.ptr[i]))
- minus.ptr[i] = '\n';
- diff_words->minus.current = 0;
-
- plus.size = diff_words->plus.text.size;
- plus.ptr = xmalloc(plus.size);
- memcpy(plus.ptr, diff_words->plus.text.ptr, plus.size);
- for (i = 0; i < plus.size; i++)
- if (isspace(plus.ptr[i]))
- plus.ptr[i] = '\n';
- diff_words->plus.current = 0;
-
+ diff_words_fill(&diff_words->minus, &minus);
+ diff_words_fill(&diff_words->plus, &plus);
xpp.flags = XDF_NEED_MINIMAL;
xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc;
xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
--
1.6.1.315.g92577
^ permalink raw reply related
* [PATCH v4 1/7] Add color_fwrite_lines(), a function coloring each line individually
From: Thomas Rast @ 2009-01-17 16:29 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Johannes Schindelin, Santi Béjar,
Boyd Stephen Smith Jr., Teemu Likonen
In-Reply-To: <1232209788-10408-1-git-send-email-trast@student.ethz.ch>
From: Johannes Schindelin <johannes.schindelin@gmx.de>
We have to set the color before every line and reset it before every
newline. Add a function color_fwrite_lines() which does that for us.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
color.c | 28 ++++++++++++++++++++++++++++
color.h | 1 +
2 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/color.c b/color.c
index fc0b72a..d4ae83f 100644
--- a/color.c
+++ b/color.c
@@ -191,3 +191,31 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
va_end(args);
return r;
}
+
+/*
+ * This function splits the buffer by newlines and colors the lines individually.
+ *
+ * Returns 0 on success.
+ */
+int color_fwrite_lines(FILE *fp, const char *color,
+ size_t count, const char *buf)
+{
+ if (!*color)
+ return fwrite(buf, count, 1, fp) != 1;
+ while (count) {
+ char *p = memchr(buf, '\n', count);
+ if (p != buf && (fputs(color, fp) < 0 ||
+ fwrite(buf, p ? p - buf : count, 1, fp) != 1 ||
+ fputs(COLOR_RESET, fp) < 0))
+ return -1;
+ if (!p)
+ return 0;
+ if (fputc('\n', fp) < 0)
+ return -1;
+ count -= p + 1 - buf;
+ buf = p + 1;
+ }
+ return 0;
+}
+
+
diff --git a/color.h b/color.h
index 6cf5c88..cd5c985 100644
--- a/color.h
+++ b/color.h
@@ -19,5 +19,6 @@
void color_parse(const char *var, const char *value, char *dst);
int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
+int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
#endif /* COLOR_H */
--
1.6.1.315.g92577
^ permalink raw reply related
* [PATCH v4 4/7] color-words: take an optional regular expression describing words
From: Thomas Rast @ 2009-01-17 16:29 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Johannes Schindelin, Santi Béjar,
Boyd Stephen Smith Jr., Teemu Likonen
In-Reply-To: <1232209788-10408-4-git-send-email-trast@student.ethz.ch>
From: Johannes Schindelin <johannes.schindelin@gmx.de>
In some applications, words are not delimited by white space. To
allow for that, you can specify a regular expression describing
what makes a word with
git diff --color-words='[A-Za-z0-9]+'
Note that words cannot contain newline characters.
As suggested by Thomas Rast, the words are the exact matches of the
regular expression.
Note that a regular expression beginning with a '^' will match only
a word at the beginning of the hunk, not a word at the beginning of
a line, and is probably not what you want.
This commit contains a quoting fix by Thomas Rast.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
Documentation/diff-options.txt | 6 +++-
diff.c | 64 ++++++++++++++++++++++++++++++++++-----
diff.h | 1 +
t/t4034-diff-words.sh | 57 +++++++++++++++++++++++++++++++++++
4 files changed, 118 insertions(+), 10 deletions(-)
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 43793d7..2c1fa4b 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -91,8 +91,12 @@ endif::git-format-patch[]
Turn off colored diff, even when the configuration file
gives the default to color output.
---color-words::
+--color-words[=regex]::
Show colored word diff, i.e. color words which have changed.
++
+Optionally, you can pass a regular expression that tells Git what the
+words are that you are looking for; The default is to interpret any
+stretch of non-whitespace as a word.
--no-renames::
Turn off rename detection, even when the configuration
diff --git a/diff.c b/diff.c
index 37c886a..9fb3d0d 100644
--- a/diff.c
+++ b/diff.c
@@ -333,12 +333,14 @@ static void diff_words_append(char *line, unsigned long len,
len--;
memcpy(buffer->text.ptr + buffer->text.size, line, len);
buffer->text.size += len;
+ buffer->text.ptr[buffer->text.size] = '\0';
}
struct diff_words_data {
struct diff_words_buffer minus, plus;
const char *current_plus;
FILE *file;
+ regex_t *word_regex;
};
static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
@@ -382,17 +384,49 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
diff_words->current_plus = plus_end;
}
+/* This function starts looking at *begin, and returns 0 iff a word was found. */
+static int find_word_boundaries(mmfile_t *buffer, regex_t *word_regex,
+ int *begin, int *end)
+{
+ if (word_regex && *begin < buffer->size) {
+ regmatch_t match[1];
+ if (!regexec(word_regex, buffer->ptr + *begin, 1, match, 0)) {
+ char *p = memchr(buffer->ptr + *begin + match[0].rm_so,
+ '\n', match[0].rm_eo - match[0].rm_so);
+ *end = p ? p - buffer->ptr : match[0].rm_eo + *begin;
+ *begin += match[0].rm_so;
+ return *begin >= *end;
+ }
+ return -1;
+ }
+
+ /* find the next word */
+ while (*begin < buffer->size && isspace(buffer->ptr[*begin]))
+ (*begin)++;
+ if (*begin >= buffer->size)
+ return -1;
+
+ /* find the end of the word */
+ *end = *begin + 1;
+ while (*end < buffer->size && !isspace(buffer->ptr[*end]))
+ (*end)++;
+
+ return 0;
+}
+
/*
* This function splits the words in buffer->text, stores the list with
* newline separator into out, and saves the offsets of the original words
* in buffer->orig.
*/
-static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out)
+static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out,
+ regex_t *word_regex)
{
int i, j;
+ long alloc = 0;
out->size = 0;
- out->ptr = xmalloc(buffer->text.size);
+ out->ptr = NULL;
/* fake an empty "0th" word */
ALLOC_GROW(buffer->orig, 1, buffer->orig_alloc);
@@ -400,11 +434,8 @@ static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out)
buffer->orig_nr = 1;
for (i = 0; i < buffer->text.size; i++) {
- if (isspace(buffer->text.ptr[i]))
- continue;
- for (j = i + 1; j < buffer->text.size &&
- !isspace(buffer->text.ptr[j]); j++)
- ; /* find the end of the word */
+ if (find_word_boundaries(&buffer->text, word_regex, &i, &j))
+ return;
/* store original boundaries */
ALLOC_GROW(buffer->orig, buffer->orig_nr + 1,
@@ -414,6 +445,7 @@ static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out)
buffer->orig_nr++;
/* store one word */
+ ALLOC_GROW(out->ptr, out->size + j - i + 1, alloc);
memcpy(out->ptr + out->size, buffer->text.ptr + i, j - i);
out->ptr[out->size + j - i] = '\n';
out->size += j - i + 1;
@@ -443,9 +475,10 @@ static void diff_words_show(struct diff_words_data *diff_words)
memset(&xpp, 0, sizeof(xpp));
memset(&xecfg, 0, sizeof(xecfg));
- diff_words_fill(&diff_words->minus, &minus);
- diff_words_fill(&diff_words->plus, &plus);
+ diff_words_fill(&diff_words->minus, &minus, diff_words->word_regex);
+ diff_words_fill(&diff_words->plus, &plus, diff_words->word_regex);
xpp.flags = XDF_NEED_MINIMAL;
+ /* as only the hunk header will be parsed, we need a 0-context */
xecfg.ctxlen = 0;
xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
&xpp, &xecfg, &ecb);
@@ -484,6 +517,7 @@ static void free_diff_words_data(struct emit_callback *ecbdata)
free (ecbdata->diff_words->minus.orig);
free (ecbdata->diff_words->plus.text.ptr);
free (ecbdata->diff_words->plus.orig);
+ free(ecbdata->diff_words->word_regex);
free(ecbdata->diff_words);
ecbdata->diff_words = NULL;
}
@@ -1506,6 +1540,14 @@ static void builtin_diff(const char *name_a,
ecbdata.diff_words =
xcalloc(1, sizeof(struct diff_words_data));
ecbdata.diff_words->file = o->file;
+ if (o->word_regex) {
+ ecbdata.diff_words->word_regex = (regex_t *)
+ xmalloc(sizeof(regex_t));
+ if (regcomp(ecbdata.diff_words->word_regex,
+ o->word_regex, REG_EXTENDED))
+ die ("Invalid regular expression: %s",
+ o->word_regex);
+ }
}
xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
&xpp, &xecfg, &ecb);
@@ -2517,6 +2559,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
DIFF_OPT_CLR(options, COLOR_DIFF);
else if (!strcmp(arg, "--color-words"))
options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS;
+ else if (!prefixcmp(arg, "--color-words=")) {
+ options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS;
+ options->word_regex = arg + 14;
+ }
else if (!strcmp(arg, "--exit-code"))
DIFF_OPT_SET(options, EXIT_WITH_STATUS);
else if (!strcmp(arg, "--quiet"))
diff --git a/diff.h b/diff.h
index 4d5a327..23cd90c 100644
--- a/diff.h
+++ b/diff.h
@@ -98,6 +98,7 @@ struct diff_options {
int stat_width;
int stat_name_width;
+ const char *word_regex;
/* this is set by diffcore for DIFF_FORMAT_PATCH */
int found_changes;
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index b22195f..4873486 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -63,4 +63,61 @@ test_expect_success 'word diff with runs of whitespace' '
'
+cat > expect <<\EOF
+<WHITE>diff --git a/pre b/post<RESET>
+<WHITE>index 330b04f..5ed8eff 100644<RESET>
+<WHITE>--- a/pre<RESET>
+<WHITE>+++ b/post<RESET>
+<BROWN>@@ -1,3 +1,7 @@<RESET>
+h(4),<GREEN>hh<RESET>[44]
+<RESET>
+a = b + c<RESET>
+
+<GREEN>aa = a<RESET>
+
+<GREEN>aeff = aeff * ( aaa<RESET> )
+EOF
+
+test_expect_success 'word diff with a regular expression' '
+
+ word_diff --color-words="[a-z]+"
+
+'
+
+echo 'aaa (aaa)' > pre
+echo 'aaa (aaa) aaa' > post
+
+cat > expect <<\EOF
+<WHITE>diff --git a/pre b/post<RESET>
+<WHITE>index c29453b..be22f37 100644<RESET>
+<WHITE>--- a/pre<RESET>
+<WHITE>+++ b/post<RESET>
+<BROWN>@@ -1 +1 @@<RESET>
+aaa (aaa) <GREEN>aaa<RESET>
+EOF
+
+test_expect_success 'test parsing words for newline' '
+
+ word_diff --color-words="a+"
+
+'
+
+echo '(:' > pre
+echo '(' > post
+
+cat > expect <<\EOF
+<WHITE>diff --git a/pre b/post<RESET>
+<WHITE>index 289cb9d..2d06f37 100644<RESET>
+<WHITE>--- a/pre<RESET>
+<WHITE>+++ b/post<RESET>
+<BROWN>@@ -1 +1 @@<RESET>
+(<RED>:<RESET>
+EOF
+
+test_expect_success 'test when words are only removed at the end' '
+
+ word_diff --color-words=.
+
+'
+
test_done
--
1.6.1.315.g92577
^ permalink raw reply related
* [PATCH v4 5/7] color-words: enable REG_NEWLINE to help user
From: Thomas Rast @ 2009-01-17 16:29 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Johannes Schindelin, Santi Béjar,
Boyd Stephen Smith Jr., Teemu Likonen
In-Reply-To: <1232209788-10408-5-git-send-email-trast@student.ethz.ch>
We silently truncate a match at the newline, which may lead to
unexpected behaviour, e.g., when matching "<[^>]*>" against
<foo
bar>
since then "<foo" becomes a word (and "bar>" doesn't!) even though the
regex said only angle-bracket-delimited things can be words.
To alleviate the problem slightly, use REG_NEWLINE so that negated
classes can't match a newline. Of course newlines can still be
matched explicitly.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
diff.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/diff.c b/diff.c
index 9fb3d0d..00c661f 100644
--- a/diff.c
+++ b/diff.c
@@ -1544,7 +1544,8 @@ static void builtin_diff(const char *name_a,
ecbdata.diff_words->word_regex = (regex_t *)
xmalloc(sizeof(regex_t));
if (regcomp(ecbdata.diff_words->word_regex,
- o->word_regex, REG_EXTENDED))
+ o->word_regex,
+ REG_EXTENDED | REG_NEWLINE))
die ("Invalid regular expression: %s",
o->word_regex);
}
--
1.6.1.315.g92577
^ permalink raw reply related
* [PATCH v4 6/7] color-words: expand docs with precise semantics
From: Thomas Rast @ 2009-01-17 16:29 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Johannes Schindelin, Santi Béjar,
Boyd Stephen Smith Jr., Teemu Likonen
In-Reply-To: <1232209788-10408-6-git-send-email-trast@student.ethz.ch>
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
Documentation/diff-options.txt | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 2c1fa4b..8689a92 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -91,12 +91,17 @@ endif::git-format-patch[]
Turn off colored diff, even when the configuration file
gives the default to color output.
---color-words[=regex]::
- Show colored word diff, i.e. color words which have changed.
+--color-words[=<regex>]::
+ Show colored word diff, i.e., color words which have changed.
+ By default, words are separated by whitespace.
+
-Optionally, you can pass a regular expression that tells Git what the
-words are that you are looking for; The default is to interpret any
-stretch of non-whitespace as a word.
+When a <regex> is specified, every non-overlapping match of the
+<regex> is considered a word. Anything between these matches is
+considered whitespace and ignored(!) for the purposes of finding
+differences. You may want to append `|[^[:space:]]` to your regular
+expression to make sure that it matches all non-whitespace characters.
+A match that contains a newline is silently truncated(!) at the
+newline.
--no-renames::
Turn off rename detection, even when the configuration
--
1.6.1.315.g92577
^ permalink raw reply related
* [PATCH v4 3/7] color-words: change algorithm to allow for 0-character word boundaries
From: Thomas Rast @ 2009-01-17 16:29 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Johannes Schindelin, Santi Béjar,
Boyd Stephen Smith Jr., Teemu Likonen
In-Reply-To: <1232209788-10408-3-git-send-email-trast@student.ethz.ch>
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Up until now, the color-words code assumed that word boundaries are
identical to white space characters.
Therefore, it could get away with a very simple scheme: it copied the
hunks, substituted newlines for each white space character, called
libxdiff with the processed text, and then identified the text to
output by the offsets (which agreed since the original text had the
same length).
This code was ugly, for a number of reasons:
- it was impossible to introduce 0-character word boundaries,
- we had to print everything word by word, and
- the code needed extra special handling of newlines in the removed part.
Fix all of these issues by processing the text such that
- we build word lists, separated by newlines,
- we remember the original offsets for every word, and
- after calling libxdiff on the wordlists, we parse the hunk headers, and
find the corresponding offsets, and then
- we print the removed/added parts in one go.
The pre and post samples in the test were provided by Santi Béjar.
Note that there is some strange special handling of hunk headers where
one line range is 0 due to POSIX: in this case, the start is one too
low. In other words a hunk header '@@ -1,0 +2 @@' actually means that
the line must be added after the _second_ line of the pre text, _not_
the first.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
diff.c | 161 ++++++++++++++++++++++++++++---------------------
t/t4034-diff-words.sh | 66 ++++++++++++++++++++
2 files changed, 159 insertions(+), 68 deletions(-)
create mode 100755 t/t4034-diff-words.sh
diff --git a/diff.c b/diff.c
index c111eef..37c886a 100644
--- a/diff.c
+++ b/diff.c
@@ -319,8 +319,10 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
struct diff_words_buffer {
mmfile_t text;
long alloc;
- long current; /* output pointer */
- int suppressed_newline;
+ struct diff_words_orig {
+ const char *begin, *end;
+ } *orig;
+ int orig_nr, orig_alloc;
};
static void diff_words_append(char *line, unsigned long len,
@@ -335,80 +337,89 @@ static void diff_words_append(char *line, unsigned long len,
struct diff_words_data {
struct diff_words_buffer minus, plus;
+ const char *current_plus;
FILE *file;
};
-static void print_word(FILE *file, struct diff_words_buffer *buffer, int len, int color,
- int suppress_newline)
+static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
{
- const char *ptr;
- int eol = 0;
+ struct diff_words_data *diff_words = priv;
+ int minus_first, minus_len, plus_first, plus_len;
+ const char *minus_begin, *minus_end, *plus_begin, *plus_end;
- if (len == 0)
+ if (line[0] != '@' || parse_hunk_header(line, len,
+ &minus_first, &minus_len, &plus_first, &plus_len))
return;
- ptr = buffer->text.ptr + buffer->current;
- buffer->current += len;
+ /* POSIX requires that first be decremented by one if len == 0... */
+ if (minus_len) {
+ minus_begin = diff_words->minus.orig[minus_first].begin;
+ minus_end =
+ diff_words->minus.orig[minus_first + minus_len - 1].end;
+ } else
+ minus_begin = minus_end =
+ diff_words->minus.orig[minus_first].end;
- if (ptr[len - 1] == '\n') {
- eol = 1;
- len--;
- }
+ if (plus_len) {
+ plus_begin = diff_words->plus.orig[plus_first].begin;
+ plus_end = diff_words->plus.orig[plus_first + plus_len - 1].end;
+ } else
+ plus_begin = plus_end = diff_words->plus.orig[plus_first].end;
- fputs(diff_get_color(1, color), file);
- fwrite(ptr, len, 1, file);
- fputs(diff_get_color(1, DIFF_RESET), file);
+ if (diff_words->current_plus != plus_begin)
+ fwrite(diff_words->current_plus,
+ plus_begin - diff_words->current_plus, 1,
+ diff_words->file);
+ if (minus_begin != minus_end)
+ color_fwrite_lines(diff_words->file,
+ diff_get_color(1, DIFF_FILE_OLD),
+ minus_end - minus_begin, minus_begin);
+ if (plus_begin != plus_end)
+ color_fwrite_lines(diff_words->file,
+ diff_get_color(1, DIFF_FILE_NEW),
+ plus_end - plus_begin, plus_begin);
- if (eol) {
- if (suppress_newline)
- buffer->suppressed_newline = 1;
- else
- putc('\n', file);
- }
-}
-
-static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len)
-{
- struct diff_words_data *diff_words = priv;
-
- if (diff_words->minus.suppressed_newline) {
- if (line[0] != '+')
- putc('\n', diff_words->file);
- diff_words->minus.suppressed_newline = 0;
- }
-
- len--;
- switch (line[0]) {
- case '-':
- print_word(diff_words->file,
- &diff_words->minus, len, DIFF_FILE_OLD, 1);
- break;
- case '+':
- print_word(diff_words->file,
- &diff_words->plus, len, DIFF_FILE_NEW, 0);
- break;
- case ' ':
- print_word(diff_words->file,
- &diff_words->plus, len, DIFF_PLAIN, 0);
- diff_words->minus.current += len;
- break;
- }
+ diff_words->current_plus = plus_end;
}
/*
- * This function splits the words in buffer->text, and stores the list with
- * newline separator into out.
+ * This function splits the words in buffer->text, stores the list with
+ * newline separator into out, and saves the offsets of the original words
+ * in buffer->orig.
*/
static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out)
{
- int i;
- out->size = buffer->text.size;
- out->ptr = xmalloc(out->size);
- memcpy(out->ptr, buffer->text.ptr, out->size);
- for (i = 0; i < out->size; i++)
- if (isspace(out->ptr[i]))
- out->ptr[i] = '\n';
- buffer->current = 0;
+ int i, j;
+
+ out->size = 0;
+ out->ptr = xmalloc(buffer->text.size);
+
+ /* fake an empty "0th" word */
+ ALLOC_GROW(buffer->orig, 1, buffer->orig_alloc);
+ buffer->orig[0].begin = buffer->orig[0].end = buffer->text.ptr;
+ buffer->orig_nr = 1;
+
+ for (i = 0; i < buffer->text.size; i++) {
+ if (isspace(buffer->text.ptr[i]))
+ continue;
+ for (j = i + 1; j < buffer->text.size &&
+ !isspace(buffer->text.ptr[j]); j++)
+ ; /* find the end of the word */
+
+ /* store original boundaries */
+ ALLOC_GROW(buffer->orig, buffer->orig_nr + 1,
+ buffer->orig_alloc);
+ buffer->orig[buffer->orig_nr].begin = buffer->text.ptr + i;
+ buffer->orig[buffer->orig_nr].end = buffer->text.ptr + j;
+ buffer->orig_nr++;
+
+ /* store one word */
+ memcpy(out->ptr + out->size, buffer->text.ptr + i, j - i);
+ out->ptr[out->size + j - i] = '\n';
+ out->size += j - i + 1;
+
+ i = j - 1;
+ }
}
/* this executes the word diff on the accumulated buffers */
@@ -419,22 +430,34 @@ static void diff_words_show(struct diff_words_data *diff_words)
xdemitcb_t ecb;
mmfile_t minus, plus;
+ /* special case: only removal */
+ if (!diff_words->plus.text.size) {
+ color_fwrite_lines(diff_words->file,
+ diff_get_color(1, DIFF_FILE_OLD),
+ diff_words->minus.text.size, diff_words->minus.text.ptr);
+ diff_words->minus.text.size = 0;
+ return;
+ }
+
+ diff_words->current_plus = diff_words->plus.text.ptr;
+
memset(&xpp, 0, sizeof(xpp));
memset(&xecfg, 0, sizeof(xecfg));
diff_words_fill(&diff_words->minus, &minus);
diff_words_fill(&diff_words->plus, &plus);
xpp.flags = XDF_NEED_MINIMAL;
- xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc;
+ xecfg.ctxlen = 0;
xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
&xpp, &xecfg, &ecb);
free(minus.ptr);
free(plus.ptr);
+ if (diff_words->current_plus != diff_words->plus.text.ptr +
+ diff_words->plus.text.size)
+ fwrite(diff_words->current_plus,
+ diff_words->plus.text.ptr + diff_words->plus.text.size
+ - diff_words->current_plus, 1,
+ diff_words->file);
diff_words->minus.text.size = diff_words->plus.text.size = 0;
-
- if (diff_words->minus.suppressed_newline) {
- putc('\n', diff_words->file);
- diff_words->minus.suppressed_newline = 0;
- }
}
typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
@@ -458,7 +481,9 @@ static void free_diff_words_data(struct emit_callback *ecbdata)
diff_words_show(ecbdata->diff_words);
free (ecbdata->diff_words->minus.text.ptr);
+ free (ecbdata->diff_words->minus.orig);
free (ecbdata->diff_words->plus.text.ptr);
+ free (ecbdata->diff_words->plus.orig);
free(ecbdata->diff_words);
ecbdata->diff_words = NULL;
}
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
new file mode 100755
index 0000000..b22195f
--- /dev/null
+++ b/t/t4034-diff-words.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+test_description='word diff colors'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+ git config diff.color.old red
+ git config diff.color.new green
+
+'
+
+decrypt_color () {
+ sed \
+ -e 's/.\[1m/<WHITE>/g' \
+ -e 's/.\[31m/<RED>/g' \
+ -e 's/.\[32m/<GREEN>/g' \
+ -e 's/.\[36m/<BROWN>/g' \
+ -e 's/.\[m/<RESET>/g'
+}
+
+word_diff () {
+ test_must_fail git diff --no-index "$@" pre post > output &&
+ decrypt_color < output > output.decrypted &&
+ test_cmp expect output.decrypted
+}
+
+cat > pre <<\EOF
+h(4)
+
+a = b + c
+EOF
+
+cat > post <<\EOF
+h(4),hh[44]
+
+a = b + c
+
+aa = a
+
+aeff = aeff * ( aaa )
+EOF
+
+cat > expect <<\EOF
+<WHITE>diff --git a/pre b/post<RESET>
+<WHITE>index 330b04f..5ed8eff 100644<RESET>
+<WHITE>--- a/pre<RESET>
+<WHITE>+++ b/post<RESET>
+<BROWN>@@ -1,3 +1,7 @@<RESET>
+<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
+<RESET>
+a = b + c<RESET>
+
+<GREEN>aa = a<RESET>
+
+<GREEN>aeff = aeff * ( aaa )<RESET>
+EOF
+
+test_expect_success 'word diff with runs of whitespace' '
+
+ word_diff --color-words
+
+'
+
+test_done
--
1.6.1.315.g92577
^ permalink raw reply related
* [PATCH v4 7/7] color-words: make regex configurable via attributes
From: Thomas Rast @ 2009-01-17 16:29 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Johannes Schindelin, Santi Béjar,
Boyd Stephen Smith Jr., Teemu Likonen
In-Reply-To: <1232209788-10408-7-git-send-email-trast@student.ethz.ch>
Make the --color-words splitting regular expression configurable via
the diff driver's 'wordregex' attribute. The user can then set the
driver on a file in .gitattributes. If a regex is given on the
command line, it overrides the driver's setting.
We also provide built-in regexes for the languages that already had
funcname patterns, and add an appropriate diff driver entry for C/++.
(The patterns are designed to run UTF-8 sequences into a single chunk
to make sure they remain readable.)
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
Documentation/diff-options.txt | 4 ++
Documentation/gitattributes.txt | 21 ++++++++++
diff.c | 10 +++++
t/t4034-diff-words.sh | 36 ++++++++++++++++++
userdiff.c | 78 +++++++++++++++++++++++++++++++-------
userdiff.h | 1 +
6 files changed, 135 insertions(+), 15 deletions(-)
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 8689a92..1edb82e 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -102,6 +102,10 @@ differences. You may want to append `|[^[:space:]]` to your regular
expression to make sure that it matches all non-whitespace characters.
A match that contains a newline is silently truncated(!) at the
newline.
++
+The regex can also be set via a diff driver, see
+linkgit:gitattributes[1]; giving it explicitly overrides any diff
+driver setting.
--no-renames::
Turn off rename detection, even when the configuration
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 8af22ec..ba3ba12 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -317,6 +317,8 @@ patterns are available:
- `bibtex` suitable for files with BibTeX coded references.
+- `cpp` suitable for source code in the C and C++ languages.
+
- `html` suitable for HTML/XHTML documents.
- `java` suitable for source code in the Java language.
@@ -334,6 +336,25 @@ patterns are available:
- `tex` suitable for source code for LaTeX documents.
+Customizing word diff
+^^^^^^^^^^^^^^^^^^^^^
+
+You can customize the rules that `git diff --color-words` uses to
+split words in a line, by specifying an appropriate regular expression
+in the "diff.*.wordregex" configuration variable. For example, in TeX
+a backslash followed by a sequence of letters forms a command, but
+several such commands can be run together without intervening
+whitespace. To separate them, use a regular expression such as
+
+------------------------
+[diff "tex"]
+ wordregex = "\\\\[a-zA-Z]+|[{}]|\\\\.|[^\\{}[:space:]]+"
+------------------------
+
+A built-in pattern is provided for all languages listed in the
+previous section.
+
+
Performing text diffs of binary files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/diff.c b/diff.c
index 00c661f..9fcde96 100644
--- a/diff.c
+++ b/diff.c
@@ -1380,6 +1380,12 @@ int diff_filespec_is_binary(struct diff_filespec *one)
return one->driver->funcname.pattern ? &one->driver->funcname : NULL;
}
+static const char *userdiff_word_regex(struct diff_filespec *one)
+{
+ diff_filespec_load_driver(one);
+ return one->driver->word_regex;
+}
+
void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b)
{
if (!options->a_prefix)
@@ -1540,6 +1546,10 @@ static void builtin_diff(const char *name_a,
ecbdata.diff_words =
xcalloc(1, sizeof(struct diff_words_data));
ecbdata.diff_words->file = o->file;
+ if (!o->word_regex)
+ o->word_regex = userdiff_word_regex(one);
+ if (!o->word_regex)
+ o->word_regex = userdiff_word_regex(two);
if (o->word_regex) {
ecbdata.diff_words->word_regex = (regex_t *)
xmalloc(sizeof(regex_t));
diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh
index 4873486..744221b 100755
--- a/t/t4034-diff-words.sh
+++ b/t/t4034-diff-words.sh
@@ -84,6 +84,41 @@ test_expect_success 'word diff with a regular expression' '
'
+test_expect_success 'set a diff driver' '
+ git config diff.testdriver.wordregex "[^[:space:]]" &&
+ cat <<EOF > .gitattributes
+pre diff=testdriver
+post diff=testdriver
+EOF
+'
+
+test_expect_success 'option overrides default' '
+
+ word_diff --color-words="[a-z]+"
+
+'
+
+cat > expect <<\EOF
+<WHITE>diff --git a/pre b/post<RESET>
+<WHITE>index 330b04f..5ed8eff 100644<RESET>
+<WHITE>--- a/pre<RESET>
+<WHITE>+++ b/post<RESET>
+<BROWN>@@ -1,3 +1,7 @@<RESET>
+h(4)<GREEN>,hh[44]<RESET>
+<RESET>
+a = b + c<RESET>
+
+<GREEN>aa = a<RESET>
+
+<GREEN>aeff = aeff * ( aaa )<RESET>
+EOF
+
+test_expect_success 'use default supplied by driver' '
+
+ word_diff --color-words
+
+'
+
echo 'aaa (aaa)' > pre
echo 'aaa (aaa) aaa' > post
@@ -100,6 +135,7 @@ test_expect_success 'test parsing words for newline' '
word_diff --color-words="a+"
+
'
echo '(:' > pre
diff --git a/userdiff.c b/userdiff.c
index 3681062..2b55509 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -6,14 +6,20 @@
static int ndrivers;
static int drivers_alloc;
-#define FUNCNAME(name, pattern) \
- { name, NULL, -1, { pattern, REG_EXTENDED } }
+#define PATTERNS(name, pattern, wordregex) \
+ { name, NULL, -1, { pattern, REG_EXTENDED }, wordregex }
static struct userdiff_driver builtin_drivers[] = {
-FUNCNAME("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$"),
-FUNCNAME("java",
+PATTERNS("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$",
+ "[^<>= \t]+|[^[:space:]]|[\x80-\xff]+"),
+PATTERNS("java",
"!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
- "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$"),
-FUNCNAME("objc",
+ "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$",
+ "[a-zA-Z_][a-zA-Z0-9_]*"
+ "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
+ "|[-+*/<>%&^|=!]="
+ "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"
+ "|[^[:space:]]|[\x80-\xff]+"),
+PATTERNS("objc",
/* Negate C statements that can look like functions */
"!^[ \t]*(do|for|if|else|return|switch|while)\n"
/* Objective-C methods */
@@ -21,20 +27,60 @@
/* C functions */
"^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$\n"
/* Objective-C class/protocol definitions */
- "^(@(implementation|interface|protocol)[ \t].*)$"),
-FUNCNAME("pascal",
+ "^(@(implementation|interface|protocol)[ \t].*)$",
+ /* -- */
+ "[a-zA-Z_][a-zA-Z0-9_]*"
+ "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
+ "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"
+ "|[^[:space:]]|[\x80-\xff]+"),
+PATTERNS("pascal",
"^((procedure|function|constructor|destructor|interface|"
"implementation|initialization|finalization)[ \t]*.*)$"
"\n"
- "^(.*=[ \t]*(class|record).*)$"),
-FUNCNAME("php", "^[\t ]*((function|class).*)"),
-FUNCNAME("python", "^[ \t]*((class|def)[ \t].*)$"),
-FUNCNAME("ruby", "^[ \t]*((class|module|def)[ \t].*)$"),
-FUNCNAME("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$"),
-FUNCNAME("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$"),
+ "^(.*=[ \t]*(class|record).*)$",
+ /* -- */
+ "[a-zA-Z_][a-zA-Z0-9_]*"
+ "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
+ "|<>|<=|>=|:=|\\.\\."
+ "|[^[:space:]]|[\x80-\xff]+"),
+PATTERNS("php", "^[\t ]*((function|class).*)",
+ /* -- */
+ "[a-zA-Z_][a-zA-Z0-9_]*"
+ "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
+ "|[-+*/<>%&^|=!.]=|--|\\+\\+|<<=?|>>=?|===|&&|\\|\\||::|->"
+ "|[^[:space:]]|[\x80-\xff]+"),
+PATTERNS("python", "^[ \t]*((class|def)[ \t].*)$",
+ /* -- */
+ "[a-zA-Z_][a-zA-Z0-9_]*"
+ "|[-+0-9.e]+[jJlL]?|0[xX]?[0-9a-fA-F]+[lL]?"
+ "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?"
+ "|[^[:space:]|[\x80-\xff]+"),
+ /* -- */
+PATTERNS("ruby", "^[ \t]*((class|module|def)[ \t].*)$",
+ /* -- */
+ "(@|@@|\\$)?[a-zA-Z_][a-zA-Z0-9_]*"
+ "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+|\\?(\\\\C-)?(\\\\M-)?."
+ "|//=?|[-+*/<>%&^|=!]=|<<=?|>>=?|===|\\.{1,3}|::|[!=]~"
+ "|[^[:space:]|[\x80-\xff]+"),
+PATTERNS("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
+ "[={}\"]|[^={}\" \t]+"),
+PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
+ "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+|[^[:space:]]"),
+PATTERNS("cpp",
+ /* Jump targets or access declarations */
+ "!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:.*$\n"
+ /* C/++ functions/methods at top level */
+ "^([A-Za-z_][A-Za-z_0-9]*([ \t]+[A-Za-z_][A-Za-z_0-9]*([ \t]*::[ \t]*[^[:space:]]+)?){1,}[ \t]*\\([^;]*)$\n"
+ /* compound type at top level */
+ "^((struct|class|enum)[^;]*)$",
+ /* -- */
+ "[a-zA-Z_][a-zA-Z0-9_]*"
+ "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
+ "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"
+ "|[^[:space:]]|[\x80-\xff]+"),
{ "default", NULL, -1, { NULL, 0 } },
};
-#undef FUNCNAME
+#undef PATTERNS
static struct userdiff_driver driver_true = {
"diff=true",
@@ -134,6 +180,8 @@ int userdiff_config(const char *k, const char *v)
return parse_string(&drv->external, k, v);
if ((drv = parse_driver(k, v, "textconv")))
return parse_string(&drv->textconv, k, v);
+ if ((drv = parse_driver(k, v, "wordregex")))
+ return parse_string(&drv->word_regex, k, v);
return 0;
}
diff --git a/userdiff.h b/userdiff.h
index ba29457..c315159 100644
--- a/userdiff.h
+++ b/userdiff.h
@@ -11,6 +11,7 @@ struct userdiff_driver {
const char *external;
int binary;
struct userdiff_funcname funcname;
+ const char *word_regex;
const char *textconv;
};
--
1.6.1.315.g92577
^ permalink raw reply related
* Re: [PATCH/RFC v4 0/5] N-th last checked out branch
From: Johannes Schindelin @ 2009-01-17 16:49 UTC (permalink / raw)
To: Thomas Rast; +Cc: git, Junio C Hamano, Johannes Sixt, Johan Herland
In-Reply-To: <1232208597-29249-1-git-send-email-trast@student.ethz.ch>
Hi,
On Sat, 17 Jan 2009, Thomas Rast wrote:
> I [...] added a fixed up version of your patch on top, since it had some
> context that is not in any version I have.
Thanks.
Yeah, I know, I have too many patches in my fork, but I'm working on it...
:-)
Ciao,
Dscho
^ permalink raw reply
* Re: git-svn fails to fetch repository
From: Jay Soffian @ 2009-01-17 17:33 UTC (permalink / raw)
To: Eric Wong; +Cc: Vladimir Pouzanov, git
In-Reply-To: <20090117104558.GC29598@dcvr.yhbt.net>
On Sat, Jan 17, 2009 at 5:45 AM, Eric Wong <normalperson@yhbt.net> wrote:
> At least you got a working combination working. Does anybody know if
> macports git have any patches/changes to it that could cause this?
I installed the macports git and it worked fine for me. Same versions
of git and subversion. The only difference was that I was on macports
perl 5.8.9 and Vladimir was on macports perl 5.8.8.
If I have time, I'll try it with macports perl 5.8.8 and see if I can
reproduce. I'm pretty curious why the apply_textdelta() callback is
apparently running twice on the same file w/o the intervening close.
:-)
j.
^ permalink raw reply
* Re: [PATCH/RFC v4 3/5] sha1_name: support @{-N} syntax in get_sha1()
From: Johannes Schindelin @ 2009-01-17 17:55 UTC (permalink / raw)
To: Thomas Rast; +Cc: git, Junio C Hamano, Johannes Sixt, Johan Herland
In-Reply-To: <1232208597-29249-4-git-send-email-trast@student.ethz.ch>
Hi,
On Sat, 17 Jan 2009, Thomas Rast wrote:
> diff --git a/t/t1505-rev-parse-last.sh b/t/t1505-rev-parse-last.sh
> new file mode 100755
> index 0000000..1e49dd2
> --- /dev/null
> +++ b/t/t1505-rev-parse-last.sh
> @@ -0,0 +1,71 @@
> +#!/bin/sh
> +
> +test_description='test @{-N} syntax'
> +
> +. ./test-lib.sh
> +
> +
> +make_commit () {
> + echo "$1" > "$1" &&
> + git add "$1" &&
> + git commit -m "$1"
> +}
> +
> +
> +test_expect_success 'setup' '
> +
> + make_commit 1 &&
> + git branch side &&
> + make_commit 2 &&
> + make_commit 3 &&
> + git checkout side &&
> + make_commit 4 &&
> + git merge master &&
> + git checkout master
> +
> +'
> +
> +# 1 -- 2 -- 3 master
> +# \ \
> +# \ \
> +# --- 4 --- 5 side
> +#
> +# and 'side' should be the last branch
> +
> +git log --graph --all --pretty=oneline --decorate
> +
Maybe you want to squash this in, so that the output of "make test" is
not cluttered by the graph?
-- snipsnap --
diff --git a/t/t1505-rev-parse-last.sh b/t/t1505-rev-parse-last.sh
index 1e49dd2..72e8322 100755
--- a/t/t1505-rev-parse-last.sh
+++ b/t/t1505-rev-parse-last.sh
@@ -32,7 +32,11 @@ test_expect_success 'setup' '
#
# and 'side' should be the last branch
-git log --graph --all --pretty=oneline --decorate
+test_expect_success 'show a log (for debugging)' '
+
+ git log --graph --all --pretty=oneline --decorate
+
+'
test_rev_equivalent () {
--
1.6.1.332.g9a59d
^ permalink raw reply related
* [PATCH 6/5] Fix parsing of @{-1}@{1}
From: Johannes Schindelin @ 2009-01-17 18:08 UTC (permalink / raw)
To: Thomas Rast; +Cc: git, Junio C Hamano, Johannes Sixt, Johan Herland
In-Reply-To: <1232208597-29249-6-git-send-email-trast@student.ethz.ch>
To do that, Git no longer looks forward for the '@{' corresponding to the
closing '}' but backward, and dwim_ref() as well as dwim_log() learnt
about the @{-<N>} notation.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
The modifications of dwim_ref() and dwim_log() are probably
more important than the issue I tried to fix...
sha1_name.c | 25 ++++++++++++++++++++++++-
t/t1505-rev-parse-last.sh | 2 +-
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/sha1_name.c b/sha1_name.c
index 306d04b..ee0c456 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -240,8 +240,28 @@ static int ambiguous_path(const char *path, int len)
return slash;
}
+/*
+ * *string and *len will only be substituted, and *string returned (for
+ * later free()ing) if the string passed in is of the form @{-<n>}.
+ */
+static char *substitute_nth_last_branch(const char **string, int *len)
+{
+ struct strbuf buf = STRBUF_INIT;
+ int ret = interpret_nth_last_branch(*string, &buf);
+
+ if (ret == *len) {
+ size_t size;
+ *string = strbuf_detach(&buf, &size);
+ *len = size;
+ return (char *)*string;
+ }
+
+ return NULL;
+}
+
int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
{
+ char *last_branch = substitute_nth_last_branch(&str, &len);
const char **p, *r;
int refs_found = 0;
@@ -261,11 +281,13 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
break;
}
}
+ free(last_branch);
return refs_found;
}
int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
{
+ char *last_branch = substitute_nth_last_branch(&str, &len);
const char **p;
int logs_found = 0;
@@ -296,6 +318,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
if (!warn_ambiguous_refs)
break;
}
+ free(last_branch);
return logs_found;
}
@@ -314,7 +337,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
/* basic@{time or number or -number} format to query ref-log */
reflog_len = at = 0;
if (str[len-1] == '}') {
- for (at = 0; at < len - 1; at++) {
+ for (at = len-2; at >= 0; at--) {
if (str[at] == '@' && str[at+1] == '{') {
reflog_len = (len-1) - (at+2);
len = at;
diff --git a/t/t1505-rev-parse-last.sh b/t/t1505-rev-parse-last.sh
index 72e8322..2d6b31e 100755
--- a/t/t1505-rev-parse-last.sh
+++ b/t/t1505-rev-parse-last.sh
@@ -58,7 +58,7 @@ test_expect_success '@{-1}^2 works' '
test_rev_equivalent side^2 @{-1}^2
'
-test_expect_failure '@{-1}@{1} works' '
+test_expect_success '@{-1}@{1} works' '
test_rev_equivalent side@{1} @{-1}@{1}
'
--
1.6.1.332.g9a59d
^ permalink raw reply related
* Re: [PATCH] git-checkout(1) mention fate of extraneous files
From: jidanni @ 2009-01-17 18:35 UTC (permalink / raw)
To: markus.heidelberg; +Cc: git
In-Reply-To: <200901171357.18005.markus.heidelberg@web.de>
MH> Why do you reformat the whole paragraph?
OK, glad to know that I don't need to!!
^ permalink raw reply
* Re: [PATCH 3/3] http-push: update tests
From: Junio C Hamano @ 2009-01-17 18:54 UTC (permalink / raw)
To: Ray Chuan; +Cc: Johannes Schindelin, git
In-Reply-To: <be6fef0d0901170040r7e11806et87cc5dc3c6f13a2a@mail.gmail.com>
"Ray Chuan" <rctay89@gmail.com> writes:
>>> -test_expect_failure 'push to remote repository' '
>>> +test_expect_success 'push to remote repository' '
>>> cd "$ROOT_PATH"/test_repo_clone &&
>>> : >path2 &&
>>> git add path2 &&
>>> test_tick &&
>>> git commit -m path2 &&
>>> - git push &&
>>> - [ -f "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/refs/heads/master" ]
>>> + git push origin master
>>> '
>>
>> ... this removal? I do not think this is a good change, as it removes
>> a test that is actually pretty important.
>
> i'm sorry for the poor commit message, what i wanted to do was to
> change the tests to expect success rather than failure. no tests were
> removed; only their expected outcomes were modified. currently, the
> pushes fail, so the test 'fails as expected'; now the pushes succeed,
> so they shouldn't be expecting failed pushes (or anything else).
The original seems to want the push to succeed, and also it wants the file
refs/heads/master to be present after the push (presumably because there
should be that ref when the push succeeds). If you fixed "push" that used
to fail to succeed, that is great, and s/failure/success/ is a good thing.
But you are removing something else without explanation. Why do you need
to remove the part of the test that checks if refs/heads/master is present?
Is it looking for a file in a wrong place?
^ permalink raw reply
* Re: [PATCH] interpret_nth_last_branch(): avoid traversing the reflogs twice
From: Junio C Hamano @ 2009-01-17 19:13 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Thomas Rast, git, Johannes Sixt, Johan Herland
In-Reply-To: <alpine.DEB.1.00.0901171602340.3586@pacific.mpi-cbg.de>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> Instead of traversing them twice, we just build a list of branch switches,
> pick the one we're interested in, and free the list again.
Isn't the code keeping them all in core, or am I reading the patch wrong?
If you know that you are interested in the nth-from-the-last switch, and
if you are reading from the beginning, you would need to keep at most n
last switches you have seen in core, wouldn't you?
^ permalink raw reply
* Re: [JGIT PATCH 8/8] Define a basic merge API, and a two-way tree merge strategy
From: Tomi Pakarinen @ 2009-01-17 19:16 UTC (permalink / raw)
To: Shawn O. Pearce; +Cc: Robin Rosenberg, git
In-Reply-To: <20090115210936.GI10179@spearce.org>
testTrivialTwoWay_disjointhistories() failed because merge strategy
didn't handle missing base
version. Am'i right?
Tomi.
>From 1ed694b55d307c640d29eeebfcd108e08681297b Mon Sep 17 00:00:00 2001
From: Tomi Pakarinen <tomi.pakarinen@iki.fi>
Date: Sat, 17 Jan 2009 20:56:04 +0200
Subject: [PATCH] If base version missing, we can merge version from
one of other trees.
Signed-off-by: Tomi Pakarinen <tomi.pakarinen@iki.fi>
---
.../jgit/merge/StrategySimpleTwoWayInCore.java | 28 +++++++++++++++-----
1 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/merge/StrategySimpleTwoWayInCore.java
b/org.spearce.jgit/src/org/spearce/jgit/merge/StrategySimpleTwoWayInCore.java
index 893add9..eb718ab 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/merge/StrategySimpleTwoWayInCore.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/merge/StrategySimpleTwoWayInCore.java
@@ -43,6 +43,7 @@
import org.spearce.jgit.dircache.DirCacheBuilder;
import org.spearce.jgit.dircache.DirCacheEntry;
import org.spearce.jgit.errors.UnmergedPathException;
+import org.spearce.jgit.lib.FileMode;
import org.spearce.jgit.lib.ObjectId;
import org.spearce.jgit.lib.Repository;
import org.spearce.jgit.treewalk.AbstractTreeIterator;
@@ -119,13 +120,26 @@ protected boolean mergeImpl() throws IOException {
}
final int modeB = tw.getRawMode(T_BASE);
- if (modeB == modeO && tw.idEqual(T_BASE, T_OURS))
- add(T_THEIRS, DirCacheEntry.STAGE_0);
- else if (modeB == modeT && tw.idEqual(T_BASE, T_THEIRS))
- add(T_OURS, DirCacheEntry.STAGE_0);
- else {
- conflict();
- hasConflict = true;
+ if (!FileMode.MISSING.equals(modeB)) {
+ if (modeB == modeO && tw.idEqual(T_BASE, T_OURS))
+ add(T_THEIRS, DirCacheEntry.STAGE_0);
+ else if (modeB == modeT && tw.idEqual(T_BASE, T_THEIRS))
+ add(T_OURS, DirCacheEntry.STAGE_0);
+ else {
+ conflict();
+ hasConflict = true;
+ }
+ } else {
+ if (!FileMode.MISSING.equals(modeO)
+ && FileMode.MISSING.equals(modeT))
+ add(T_OURS, DirCacheEntry.STAGE_0);
+ else if (FileMode.MISSING.equals(modeO)
+ && !FileMode.MISSING.equals(modeT))
+ add(T_THEIRS, DirCacheEntry.STAGE_0);
+ else {
+ conflict();
+ hasConflict = true;
+ }
}
}
builder.finish();
--
1.6.0.4
^ permalink raw reply related
* Re: [PATCH] interpret_nth_last_branch(): avoid traversing the reflogs twice
From: Johannes Schindelin @ 2009-01-17 19:29 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Thomas Rast, git, Johannes Sixt, Johan Herland
In-Reply-To: <7vljt97nld.fsf@gitster.siamese.dyndns.org>
Hi,
On Sat, 17 Jan 2009, Junio C Hamano wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>
> > Instead of traversing them twice, we just build a list of branch switches,
> > pick the one we're interested in, and free the list again.
>
> Isn't the code keeping them all in core, or am I reading the patch wrong?
>
> If you know that you are interested in the nth-from-the-last switch, and
> if you are reading from the beginning, you would need to keep at most n
> last switches you have seen in core, wouldn't you?
That is correct. But this is such a highly uncritical code path that I'd
like to keep this simple rather than fast.
Ciao,
Dscho
^ permalink raw reply
* Re: [PATCH 3/3] http-push: update tests
From: Johannes Schindelin @ 2009-01-17 19:37 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Ray Chuan, git
In-Reply-To: <7vsknh7og5.fsf@gitster.siamese.dyndns.org>
Hi,
On Sat, 17 Jan 2009, Junio C Hamano wrote:
> The original seems to want the push to succeed, and also it wants the
> file refs/heads/master to be present after the push (presumably because
> there should be that ref when the push succeeds). If you fixed "push"
> that used to fail to succeed, that is great, and s/failure/success/ is a
> good thing.
>
> But you are removing something else without explanation. Why do you
> need to remove the part of the test that checks if refs/heads/master is
> present? Is it looking for a file in a wrong place?
As I mentioned with two other patches, the push does not succeed, and that
is the reason for the "failure" in test_expect_failure.
It does not succeed for two reasons:
- due to an off-by-path_len bug, xmalloc() tries to allocate ~4GB of
memory, which is a bit much, so http-push die()s with an OOM.
- even with that fix, the push fails because it cannot find any common
refs. It cannot find them because it does not download info/refs as it
is supposed to do, but it looks through refs/, missing the fact that the
refs are packed (which it cannot handle).
Ciao,
Dscho
^ permalink raw reply
* Re: [PATCH/RFC v4 3/5] sha1_name: support @{-N} syntax in get_sha1()
From: Junio C Hamano @ 2009-01-17 19:37 UTC (permalink / raw)
To: Thomas Rast; +Cc: git, Johannes Schindelin, Johannes Sixt, Johan Herland
In-Reply-To: <1232208597-29249-4-git-send-email-trast@student.ethz.ch>
Thomas Rast <trast@student.ethz.ch> writes:
> Let get_sha1() parse the @{-N} syntax, with docs and tests.
>
> Note that while @{-1}^2, @{-2}~5 and such are supported, @{-1}@{1} is
> currently not allowed.
>
> Signed-off-by: Thomas Rast <trast@student.ethz.ch>
> ...
> @@ -324,6 +326,16 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
> return -1;
>
> if (!len && reflog_len) {
> + struct strbuf buf = STRBUF_INIT;
> + int ret;
> + /* try the @{-N} syntax for n-th checkout */
> + ret = interpret_nth_last_branch(str+at, &buf);
> + if (ret > 0) {
> + /* substitute this branch name and restart */
> + return get_sha1_1(buf.buf, buf.len, sha1);
> + } else if (ret == 0) {
> + return -1;
> + }
What are the possible failure cases, and what do we want to tell the
end-user?
- You asked for 3rd but there weren't that many switches yet, and ask
"git rev-parse --verify @{-3}".
Are we Ok with "fatal: Needed a single revision" from rev-parse? Do we
want to show "fatal: @{-3}: not that many branch switches yet"?
What happens to "git checkout @{-3}" in this case? Having checkout say
"fatal: invalid reference: @{-3}" would be fine in this case, I think.
- You try "git checkout @{-3}", you were on "frotz" branch back then, but
the branch does not exist anymore.
I think you will get "fatal: invalid reference: frotz" from checkout,
which should be fine.
There also is a case where nth_last_branch() may find something that is
not a branch (e.g. "git checkout HEAD^"), but I am hoping we can label
that as a bug in nth_last_branch() and fix it later.
^ permalink raw reply
* Re: [PATCH 3/3] http-push: update tests
From: Ray Chuan @ 2009-01-17 19:55 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Johannes Schindelin, git
In-Reply-To: <7vsknh7og5.fsf@gitster.siamese.dyndns.org>
Hi,
On Sat, Jan 17, 2009 at 6:54 PM, Junio C Hamano <gitster@pobox.com> wrote:
> "Ray Chuan" <rctay89@gmail.com> writes:
>
>>>> -test_expect_failure 'push to remote repository' '
>>>> +test_expect_success 'push to remote repository' '
>>>> cd "$ROOT_PATH"/test_repo_clone &&
>>>> : >path2 &&
>>>> git add path2 &&
>>>> test_tick &&
>>>> git commit -m path2 &&
>>>> - git push &&
>>>> - [ -f "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/refs/heads/master" ]
i modified the push arguments as there was no remote ref/branch
specified. With a fixed "git push", that line says:
No refs in common and none specified; doing nothing.
i'd like to take this chance to inquire, what does the -f, plus square
brackets, really mean? i assumed it was to force push to go ahead even
if "a remote ref that is not an ancestor of the local ref used to
overwrite it" check fails.
--
Cheers,
Ray Chuan
^ permalink raw reply
* Re: [PATCH/RFC v4 4/5] checkout: implement "-" abbreviation, add docs and tests
From: Junio C Hamano @ 2009-01-17 19:57 UTC (permalink / raw)
To: Thomas Rast; +Cc: git, Johannes Schindelin, Johannes Sixt, Johan Herland
In-Reply-To: <1232208597-29249-5-git-send-email-trast@student.ethz.ch>
Thomas Rast <trast@student.ethz.ch> writes:
> @@ -133,6 +133,10 @@ the conflicted merge in the specified paths.
> +
> When this parameter names a non-branch (but still a valid commit object),
> your HEAD becomes 'detached'.
> ++
> +As a special case, the "`@\{-N\}`" syntax for the N-th last branch
> +checks out the branch (instead of detaching). You may also specify
> +"`-`" which is synonymous with "`@\{-1\}`".
I mildly disagree with this wording.
The new syntax is supposed to be a new way to name a branch, not a random
non-branch committish that is special cased by "git checkout". I would
further suggest that we should teach "git rev-parse --symbolic-full-name"
and "git rev-parse --symbolic" about the new syntax, so that scripts can
use the syntax to find out the same information.
The "-" thing deserves a mention here in the documentation. That _is_ a
special case that only applies to the "git checkout" command.
> diff --git a/builtin-checkout.c b/builtin-checkout.c
> index dc1de06..b0a101b 100644
> --- a/builtin-checkout.c
> +++ b/builtin-checkout.c
> @@ -679,6 +679,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
> arg = argv[0];
> has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
>
> + if (!strcmp(arg, "-"))
> + arg = "@{-1}";
> +
This is not quite nice as it could be, but it probably is Ok. If the
interpretation of @{-1} errors out, the user won't see an error message
that talks about "-" but instead the user will see "@{-1}".
Also it will look somewhat inconsistent to the end user who does not know
the internals for "-" claim to be a synonym for @{-1} but it really isn't.
For example, "git checkout -^0" does not work as "git checkout @{-1}^0".
To avoid such confusion, we could instead make "git checkout - <ENTER>" a
synonym for "git checkout @{-1} <ENTER>", without claiming to make "-" a
synonym for "@{-1}". In other words, "git checkout -" can become a very
narrow, focused special case that does not allow anything else, such as
pathspecs, "--" separator, nor --force and other options.
^ permalink raw reply
* Re: [PATCH 6/5] Fix parsing of @{-1}@{1}
From: Junio C Hamano @ 2009-01-17 20:02 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Thomas Rast, git, Johannes Sixt, Johan Herland
In-Reply-To: <alpine.DEB.1.00.0901171907530.3586@pacific.mpi-cbg.de>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> To do that, Git no longer looks forward for the '@{' corresponding to the
> closing '}' but backward, and dwim_ref() as well as dwim_log() learnt
> about the @{-<N>} notation.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>
> The modifications of dwim_ref() and dwim_log() are probably
> more important than the issue I tried to fix...
Good, so we can say things like:
git log -g @{-1}
git show-branch -g @{-1}
with this?
By the way, I noticed that without these patch series we show something
when "git rev-parse --verify @{-1}" is asked for. What is it trying to
show?
^ 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