* [PATCH v9 05/20] ref-filter: move get_head_description() from branch.c
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
Move the implementation of get_head_description() from branch.c to
ref-filter. This gives a description of the HEAD ref if called. This
is used as the refname for the HEAD ref whenever the
FILTER_REFS_DETACHED_HEAD option is used. Make it public because we
need it to calculate the length of the HEAD refs description in
branch.c:calc_maxwidth() when we port branch.c to use ref-filter
APIs.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
builtin/branch.c | 33 ---------------------------------
ref-filter.c | 38 ++++++++++++++++++++++++++++++++++++--
ref-filter.h | 2 ++
3 files changed, 38 insertions(+), 35 deletions(-)
diff --git a/builtin/branch.c b/builtin/branch.c
index 9d30f55..6423ebc 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -364,39 +364,6 @@ static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
strbuf_release(&subject);
}
-static char *get_head_description(void)
-{
- struct strbuf desc = STRBUF_INIT;
- struct wt_status_state state;
- memset(&state, 0, sizeof(state));
- wt_status_get_state(&state, 1);
- if (state.rebase_in_progress ||
- state.rebase_interactive_in_progress)
- strbuf_addf(&desc, _("(no branch, rebasing %s)"),
- state.branch);
- else if (state.bisect_in_progress)
- strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
- state.branch);
- else if (state.detached_from) {
- if (state.detached_at)
- /* TRANSLATORS: make sure this matches
- "HEAD detached at " in wt-status.c */
- strbuf_addf(&desc, _("(HEAD detached at %s)"),
- state.detached_from);
- else
- /* TRANSLATORS: make sure this matches
- "HEAD detached from " in wt-status.c */
- strbuf_addf(&desc, _("(HEAD detached from %s)"),
- state.detached_from);
- }
- else
- strbuf_addstr(&desc, _("(no branch)"));
- free(state.branch);
- free(state.onto);
- free(state.detached_from);
- return strbuf_detach(&desc, NULL);
-}
-
static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,
struct ref_filter *filter, const char *remote_prefix)
{
diff --git a/ref-filter.c b/ref-filter.c
index 385fc04..5511a20 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -14,6 +14,7 @@
#include "git-compat-util.h"
#include "version.h"
#include "trailer.h"
+#include "wt-status.h"
typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
typedef enum { COMPARE_EQUAL, COMPARE_UNEQUAL, COMPARE_NONE } cmp_status;
@@ -1101,6 +1102,37 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
*s = refname;
}
+char *get_head_description(void)
+{
+ struct strbuf desc = STRBUF_INIT;
+ struct wt_status_state state;
+ memset(&state, 0, sizeof(state));
+ wt_status_get_state(&state, 1);
+ if (state.rebase_in_progress ||
+ state.rebase_interactive_in_progress)
+ strbuf_addf(&desc, _("(no branch, rebasing %s)"),
+ state.branch);
+ else if (state.bisect_in_progress)
+ strbuf_addf(&desc, _("(no branch, bisect started on %s)"),
+ state.branch);
+ else if (state.detached_from) {
+ /* TRANSLATORS: make sure these match _("HEAD detached at ")
+ and _("HEAD detached from ") in wt-status.c */
+ if (state.detached_at)
+ strbuf_addf(&desc, _("(HEAD detached at %s)"),
+ state.detached_from);
+ else
+ strbuf_addf(&desc, _("(HEAD detached from %s)"),
+ state.detached_from);
+ }
+ else
+ strbuf_addstr(&desc, _("(no branch)"));
+ free(state.branch);
+ free(state.onto);
+ free(state.detached_from);
+ return strbuf_detach(&desc, NULL);
+}
+
/*
* Parse the object referred by ref, and grab needed value.
*/
@@ -1140,9 +1172,11 @@ static void populate_value(struct ref_array_item *ref)
name++;
}
- if (starts_with(name, "refname"))
+ if (starts_with(name, "refname")) {
refname = ref->refname;
- else if (starts_with(name, "symref"))
+ if (ref->kind & FILTER_REFS_DETACHED_HEAD)
+ refname = get_head_description();
+ } else if (starts_with(name, "symref"))
refname = ref->symref ? ref->symref : "";
else if (starts_with(name, "upstream")) {
const char *branch_name;
diff --git a/ref-filter.h b/ref-filter.h
index fc55fa3..f78323d 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -108,5 +108,7 @@ int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset);
struct ref_sorting *ref_default_sorting(void);
/* Function to parse --merged and --no-merged options */
int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset);
+/* Get the current HEAD's description */
+char *get_head_description(void);
#endif /* REF_FILTER_H */
--
2.10.2
^ permalink raw reply related
* [PATCH v9 04/20] ref-filter: modify "%(objectname:short)" to take length
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
Add support for %(objectname:short=<length>) which would print the
abbreviated unique objectname of given length. When no length is
specified, the length is 'DEFAULT_ABBREV'. The minimum length is
'MINIMUM_ABBREV'. The length may be exceeded to ensure that the
provided object name is unique.
Add tests and documentation for the same.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Helped-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 3 +++
ref-filter.c | 25 +++++++++++++++++++------
t/t6300-for-each-ref.sh | 10 ++++++++++
3 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 39aab09..c2cc03c 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -110,6 +110,9 @@ objectsize::
objectname::
The object name (aka SHA-1).
For a non-ambiguous abbreviation of the object name append `:short`.
+ For an abbreviation of the object name with desired length append
+ `:short=<length>`, where the minimum length is MINIMUM_ABBREV. The
+ length may be exceeded to ensure unique object names.
upstream::
The name of a local ref which can be considered ``upstream''
diff --git a/ref-filter.c b/ref-filter.c
index e002629..385fc04 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -57,7 +57,10 @@ static struct used_atom {
cmp_status cmp_status;
const char *str;
} if_then_else;
- enum { O_FULL, O_SHORT } objectname;
+ struct {
+ enum { O_FULL, O_LENGTH, O_SHORT } option;
+ unsigned int length;
+ } objectname;
} u;
} *used_atom;
static int used_atom_cnt, need_tagged, need_symref;
@@ -129,10 +132,17 @@ static void contents_atom_parser(struct used_atom *atom, const char *arg)
static void objectname_atom_parser(struct used_atom *atom, const char *arg)
{
if (!arg)
- atom->u.objectname = O_FULL;
+ atom->u.objectname.option = O_FULL;
else if (!strcmp(arg, "short"))
- atom->u.objectname = O_SHORT;
- else
+ atom->u.objectname.option = O_SHORT;
+ else if (skip_prefix(arg, "short=", &arg)) {
+ atom->u.objectname.option = O_LENGTH;
+ if (strtoul_ui(arg, 10, &atom->u.objectname.length) ||
+ atom->u.objectname.length == 0)
+ die(_("positive value expected objectname:short=%s"), arg);
+ if (atom->u.objectname.length < MINIMUM_ABBREV)
+ atom->u.objectname.length = MINIMUM_ABBREV;
+ } else
die(_("unrecognized %%(objectname) argument: %s"), arg);
}
@@ -606,12 +616,15 @@ static int grab_objectname(const char *name, const unsigned char *sha1,
struct atom_value *v, struct used_atom *atom)
{
if (starts_with(name, "objectname")) {
- if (atom->u.objectname == O_SHORT) {
+ if (atom->u.objectname.option == O_SHORT) {
v->s = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));
return 1;
- } else if (atom->u.objectname == O_FULL) {
+ } else if (atom->u.objectname.option == O_FULL) {
v->s = xstrdup(sha1_to_hex(sha1));
return 1;
+ } else if (atom->u.objectname.option == O_LENGTH) {
+ v->s = xstrdup(find_unique_abbrev(sha1, atom->u.objectname.length));
+ return 1;
} else
die("BUG: unknown %%(objectname) option");
}
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index aea1dfc..e67c694 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -60,6 +60,8 @@ test_atom head objecttype commit
test_atom head objectsize 171
test_atom head objectname $(git rev-parse refs/heads/master)
test_atom head objectname:short $(git rev-parse --short refs/heads/master)
+test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/master)
+test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/master)
test_atom head tree $(git rev-parse refs/heads/master^{tree})
test_atom head parent ''
test_atom head numparent 0
@@ -99,6 +101,8 @@ test_atom tag objecttype tag
test_atom tag objectsize 154
test_atom tag objectname $(git rev-parse refs/tags/testtag)
test_atom tag objectname:short $(git rev-parse --short refs/tags/testtag)
+test_atom head objectname:short=1 $(git rev-parse --short=1 refs/heads/master)
+test_atom head objectname:short=10 $(git rev-parse --short=10 refs/heads/master)
test_atom tag tree ''
test_atom tag parent ''
test_atom tag numparent ''
@@ -164,6 +168,12 @@ test_expect_success 'Check invalid format specifiers are errors' '
test_must_fail git for-each-ref --format="%(authordate:INVALID)" refs/heads
'
+test_expect_success 'arguments to %(objectname:short=) must be positive integers' '
+ test_must_fail git for-each-ref --format="%(objectname:short=0)" &&
+ test_must_fail git for-each-ref --format="%(objectname:short=-1)" &&
+ test_must_fail git for-each-ref --format="%(objectname:short=foo)"
+'
+
test_date () {
f=$1 &&
committer_date=$2 &&
--
2.10.2
^ permalink raw reply related
* [PATCH v9 06/20] ref-filter: introduce format_ref_array_item()
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
To allow column display, we will need to first render the output in a
string list to allow print_columns() to compute the proper size of
each column before starting the actual output. Introduce the function
format_ref_array_item() that does the formatting of a ref_array_item
to an strbuf.
show_ref_array_item() is kept as a convenience wrapper around it which
obtains the strbuf and prints it the standard output.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
ref-filter.c | 16 ++++++++++++----
ref-filter.h | 3 +++
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/ref-filter.c b/ref-filter.c
index 5511a20..47b521c 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1833,10 +1833,10 @@ static void append_literal(const char *cp, const char *ep, struct ref_formatting
}
}
-void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)
+void format_ref_array_item(struct ref_array_item *info, const char *format,
+ int quote_style, struct strbuf *final_buf)
{
const char *cp, *sp, *ep;
- struct strbuf *final_buf;
struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
state.quote_style = quote_style;
@@ -1866,9 +1866,17 @@ void show_ref_array_item(struct ref_array_item *info, const char *format, int qu
}
if (state.stack->prev)
die(_("format: %%(end) atom missing"));
- final_buf = &state.stack->output;
- fwrite(final_buf->buf, 1, final_buf->len, stdout);
+ strbuf_addbuf(final_buf, &state.stack->output);
pop_stack_element(&state.stack);
+}
+
+void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)
+{
+ struct strbuf final_buf = STRBUF_INIT;
+
+ format_ref_array_item(info, format, quote_style, &final_buf);
+ fwrite(final_buf.buf, 1, final_buf.len, stdout);
+ strbuf_release(&final_buf);
putchar('\n');
}
diff --git a/ref-filter.h b/ref-filter.h
index f78323d..630e7c2 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -100,6 +100,9 @@ int parse_ref_filter_atom(const char *atom, const char *ep);
int verify_ref_format(const char *format);
/* Sort the given ref_array as per the ref_sorting provided */
void ref_array_sort(struct ref_sorting *sort, struct ref_array *array);
+/* Based on the given format and quote_style, fill the strbuf */
+void format_ref_array_item(struct ref_array_item *info, const char *format,
+ int quote_style, struct strbuf *final_buf);
/* Print the ref using the given format and quote_style */
void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style);
/* Callback function for parsing the sort option */
--
2.10.2
^ permalink raw reply related
* [PATCH v9 07/20] ref-filter: make %(upstream:track) prints "[gone]" for invalid upstreams
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
Borrowing from branch.c's implementation print "[gone]" whenever an
unknown upstream ref is encountered instead of just ignoring it.
This makes sure that when branch.c is ported over to using ref-filter
APIs for printing, this feature is not lost.
Make changes to t/t6300-for-each-ref.sh and
Documentation/git-for-each-ref.txt to reflect this change.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Helped-by : Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 3 ++-
ref-filter.c | 4 +++-
t/t6300-for-each-ref.sh | 2 +-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index c2cc03c..24a1679 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -121,7 +121,8 @@ upstream::
"[ahead N, behind M]" and `:trackshort` to show the terse
version: ">" (ahead), "<" (behind), "<>" (ahead and behind),
or "=" (in sync). Has no effect if the ref does not have
- tracking information associated with it.
+ tracking information associated with it. `:track` also prints
+ "[gone]" whenever unknown upstream ref is encountered.
push::
The name of a local ref which represents the `@{push}` location
diff --git a/ref-filter.c b/ref-filter.c
index 47b521c..9989918 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1073,8 +1073,10 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
*s = shorten_unambiguous_ref(refname, warn_ambiguous_refs);
else if (atom->u.remote_ref == RR_TRACK) {
if (stat_tracking_info(branch, &num_ours,
- &num_theirs, NULL))
+ &num_theirs, NULL)) {
+ *s = "[gone]";
return;
+ }
if (!num_ours && !num_theirs)
*s = "";
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index e67c694..a2e3f55 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -382,7 +382,7 @@ test_expect_success 'Check that :track[short] cannot be used with other atoms' '
test_expect_success 'Check that :track[short] works when upstream is invalid' '
cat >expected <<-\EOF &&
-
+ [gone]
EOF
test_when_finished "git config branch.master.merge refs/heads/master" &&
--
2.10.2
^ permalink raw reply related
* [PATCH v9 08/20] ref-filter: add support for %(upstream:track,nobracket)
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
Add support for %(upstream:track,nobracket) which will print the
tracking information without the brackets (i.e. "ahead N, behind M").
This is needed when we port branch.c to use ref-filter's printing APIs.
Add test and documentation for the same.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 10 ++++--
ref-filter.c | 67 +++++++++++++++++++++++++-------------
t/t6300-for-each-ref.sh | 2 ++
3 files changed, 53 insertions(+), 26 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 24a1679..b17273e 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -120,9 +120,13 @@ upstream::
`refname` above. Additionally respects `:track` to show
"[ahead N, behind M]" and `:trackshort` to show the terse
version: ">" (ahead), "<" (behind), "<>" (ahead and behind),
- or "=" (in sync). Has no effect if the ref does not have
- tracking information associated with it. `:track` also prints
- "[gone]" whenever unknown upstream ref is encountered.
+ or "=" (in sync). `:track` also prints "[gone]" whenever
+ unknown upstream ref is encountered. Append `:track,nobracket`
+ to show tracking information without brackets (i.e "ahead N,
+ behind M"). Has no effect if the ref does not have tracking
+ information associated with it. All the options apart from
+ `nobracket` are mutually exclusive, but if used together the
+ last option is selected.
push::
The name of a local ref which represents the `@{push}` location
diff --git a/ref-filter.c b/ref-filter.c
index 9989918..6de0927 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -48,8 +48,10 @@ static struct used_atom {
union {
char color[COLOR_MAXLEN];
struct align align;
- enum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT }
- remote_ref;
+ struct {
+ enum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT } option;
+ unsigned int nobracket : 1;
+ } remote_ref;
struct {
enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB, C_TRAILERS } option;
unsigned int nlines;
@@ -77,16 +79,33 @@ static void color_atom_parser(struct used_atom *atom, const char *color_value)
static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
{
- if (!arg)
- atom->u.remote_ref = RR_NORMAL;
- else if (!strcmp(arg, "short"))
- atom->u.remote_ref = RR_SHORTEN;
- else if (!strcmp(arg, "track"))
- atom->u.remote_ref = RR_TRACK;
- else if (!strcmp(arg, "trackshort"))
- atom->u.remote_ref = RR_TRACKSHORT;
- else
- die(_("unrecognized format: %%(%s)"), atom->name);
+ struct string_list params = STRING_LIST_INIT_DUP;
+ int i;
+
+ if (!arg) {
+ atom->u.remote_ref.option = RR_NORMAL;
+ return;
+ }
+
+ atom->u.remote_ref.nobracket = 0;
+ string_list_split(¶ms, arg, ',', -1);
+
+ for (i = 0; i < params.nr; i++) {
+ const char *s = params.items[i].string;
+
+ if (!strcmp(s, "short"))
+ atom->u.remote_ref.option = RR_SHORTEN;
+ else if (!strcmp(s, "track"))
+ atom->u.remote_ref.option = RR_TRACK;
+ else if (!strcmp(s, "trackshort"))
+ atom->u.remote_ref.option = RR_TRACKSHORT;
+ else if (!strcmp(s, "nobracket"))
+ atom->u.remote_ref.nobracket = 1;
+ else
+ die(_("unrecognized format: %%(%s)"), atom->name);
+ }
+
+ string_list_clear(¶ms, 0);
}
static void body_atom_parser(struct used_atom *atom, const char *arg)
@@ -1069,25 +1088,27 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
struct branch *branch, const char **s)
{
int num_ours, num_theirs;
- if (atom->u.remote_ref == RR_SHORTEN)
+ if (atom->u.remote_ref.option == RR_SHORTEN)
*s = shorten_unambiguous_ref(refname, warn_ambiguous_refs);
- else if (atom->u.remote_ref == RR_TRACK) {
+ else if (atom->u.remote_ref.option == RR_TRACK) {
if (stat_tracking_info(branch, &num_ours,
&num_theirs, NULL)) {
- *s = "[gone]";
- return;
- }
-
- if (!num_ours && !num_theirs)
+ *s = xstrdup("gone");
+ } else if (!num_ours && !num_theirs)
*s = "";
else if (!num_ours)
- *s = xstrfmt("[behind %d]", num_theirs);
+ *s = xstrfmt("behind %d", num_theirs);
else if (!num_theirs)
- *s = xstrfmt("[ahead %d]", num_ours);
+ *s = xstrfmt("ahead %d", num_ours);
else
- *s = xstrfmt("[ahead %d, behind %d]",
+ *s = xstrfmt("ahead %d, behind %d",
num_ours, num_theirs);
- } else if (atom->u.remote_ref == RR_TRACKSHORT) {
+ if (!atom->u.remote_ref.nobracket && *s[0]) {
+ const char *to_free = *s;
+ *s = xstrfmt("[%s]", *s);
+ free((void *)to_free);
+ }
+ } else if (atom->u.remote_ref.option == RR_TRACKSHORT) {
if (stat_tracking_info(branch, &num_ours,
&num_theirs, NULL))
return;
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index a2e3f55..af76dc5 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -372,6 +372,8 @@ test_expect_success 'setup for upstream:track[short]' '
test_atom head upstream:track '[ahead 1]'
test_atom head upstream:trackshort '>'
+test_atom head upstream:track,nobracket 'ahead 1'
+test_atom head upstream:nobracket,track 'ahead 1'
test_atom head push:track '[ahead 1]'
test_atom head push:trackshort '>'
--
2.10.2
^ permalink raw reply related
* [PATCH v9 10/20] ref-filter: introduce refname_atom_parser_internal()
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
Since there are multiple atoms which print refs ('%(refname)',
'%(symref)', '%(push)', '%(upstream)'), it makes sense to have a common
ground for parsing them. This would allow us to share implementations of
the atom modifiers between these atoms.
Introduce refname_atom_parser_internal() to act as a common parsing
function for ref printing atoms. This would eventually be used to
introduce refname_atom_parser() and symref_atom_parser() and also be
internally used in remote_ref_atom_parser().
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
ref-filter.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/ref-filter.c b/ref-filter.c
index e98ef4b..c1ebc40 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -32,6 +32,11 @@ struct if_then_else {
condition_satisfied : 1;
};
+struct refname_atom {
+ enum { R_NORMAL, R_SHORT, R_STRIP } option;
+ unsigned int strip;
+};
+
/*
* An atom is a valid field atom listed below, possibly prefixed with
* a "*" to denote deref_tag().
@@ -64,6 +69,7 @@ static struct used_atom {
enum { O_FULL, O_LENGTH, O_SHORT } option;
unsigned int length;
} objectname;
+ struct refname_atom refname;
} u;
} *used_atom;
static int used_atom_cnt, need_tagged, need_symref;
@@ -77,6 +83,21 @@ static void color_atom_parser(struct used_atom *atom, const char *color_value)
die(_("unrecognized color: %%(color:%s)"), color_value);
}
+static void refname_atom_parser_internal(struct refname_atom *atom,
+ const char *arg, const char *name)
+{
+ if (!arg)
+ atom->option = R_NORMAL;
+ else if (!strcmp(arg, "short"))
+ atom->option = R_SHORT;
+ else if (skip_prefix(arg, "strip=", &arg)) {
+ atom->option = R_STRIP;
+ if (strtoul_ui(arg, 10, &atom->strip) || atom->strip <= 0)
+ die(_("positive value expected refname:strip=%s"), arg);
+ } else
+ die(_("unrecognized %%(%s) argument: %s"), name, arg);
+}
+
static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
{
struct string_list params = STRING_LIST_INIT_DUP;
--
2.10.2
^ permalink raw reply related
* [PATCH v9 09/20] ref-filter: make "%(symref)" atom work with the ':short' modifier
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
The "%(symref)" atom doesn't work when used with the ':short' modifier
because we strictly match only 'symref' for setting the 'need_symref'
indicator. Fix this by comparing with the valid_atom rather than the
used_atom.
Add tests for %(symref) and %(symref:short) while we're here.
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
ref-filter.c | 2 +-
t/t6300-for-each-ref.sh | 24 ++++++++++++++++++++++++
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/ref-filter.c b/ref-filter.c
index 6de0927..e98ef4b 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -352,7 +352,7 @@ int parse_ref_filter_atom(const char *atom, const char *ep)
valid_atom[i].parser(&used_atom[at], arg);
if (*atom == '*')
need_tagged = 1;
- if (!strcmp(used_atom[at].name, "symref"))
+ if (!strcmp(valid_atom[i].name, "symref"))
need_symref = 1;
return at;
}
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index af76dc5..7663a36 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -38,6 +38,7 @@ test_atom() {
case "$1" in
head) ref=refs/heads/master ;;
tag) ref=refs/tags/testtag ;;
+ sym) ref=refs/heads/sym ;;
*) ref=$1 ;;
esac
printf '%s\n' "$3" >expected
@@ -566,6 +567,7 @@ test_expect_success 'Verify sort with multiple keys' '
test_cmp expected actual
'
+
test_expect_success 'do not dereference NULL upon %(HEAD) on unborn branch' '
test_when_finished "git checkout master" &&
git for-each-ref --format="%(HEAD) %(refname:short)" refs/heads/ >actual &&
@@ -600,4 +602,26 @@ test_expect_success 'basic atom: head contents:trailers' '
test_cmp expect actual.clean
'
+test_expect_success 'Add symbolic ref for the following tests' '
+ git symbolic-ref refs/heads/sym refs/heads/master
+'
+
+cat >expected <<EOF
+refs/heads/master
+EOF
+
+test_expect_success 'Verify usage of %(symref) atom' '
+ git for-each-ref --format="%(symref)" refs/heads/sym >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+heads/master
+EOF
+
+test_expect_success 'Verify usage of %(symref:short) atom' '
+ git for-each-ref --format="%(symref:short)" refs/heads/sym >actual &&
+ test_cmp expected actual
+'
+
test_done
--
2.10.2
^ permalink raw reply related
* [PATCH v9 12/20] ref-filter: make remote_ref_atom_parser() use refname_atom_parser_internal()
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
Use the recently introduced refname_atom_parser_internal() within
remote_ref_atom_parser(), this provides a common base for all the ref
printing atoms, allowing %(upstream) and %(push) to also use the
':strip' option.
The atoms '%(push)' and '%(upstream)' will retain the ':track' and
':trackshort' atom modifiers to themselves as they have no meaning in
context to the '%(refname)' and '%(symref)' atoms.
Update the documentation and tests to reflect the same.
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 31 ++++++++++++++++---------------
ref-filter.c | 26 +++++++++++++++-----------
t/t6300-for-each-ref.sh | 2 ++
3 files changed, 33 insertions(+), 26 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 0fa5818..e7cdff6 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -116,23 +116,24 @@ objectname::
upstream::
The name of a local ref which can be considered ``upstream''
- from the displayed ref. Respects `:short` in the same way as
- `refname` above. Additionally respects `:track` to show
- "[ahead N, behind M]" and `:trackshort` to show the terse
- version: ">" (ahead), "<" (behind), "<>" (ahead and behind),
- or "=" (in sync). `:track` also prints "[gone]" whenever
- unknown upstream ref is encountered. Append `:track,nobracket`
- to show tracking information without brackets (i.e "ahead N,
- behind M"). Has no effect if the ref does not have tracking
- information associated with it. All the options apart from
- `nobracket` are mutually exclusive, but if used together the
- last option is selected.
+ from the displayed ref. Respects `:short` and `:strip` in the
+ same way as `refname` above. Additionally respects `:track`
+ to show "[ahead N, behind M]" and `:trackshort` to show the
+ terse version: ">" (ahead), "<" (behind), "<>" (ahead and
+ behind), or "=" (in sync). `:track` also prints "[gone]"
+ whenever unknown upstream ref is encountered. Append
+ `:track,nobracket` to show tracking information without
+ brackets (i.e "ahead N, behind M"). Has no effect if the ref
+ does not have tracking information associated with it. All
+ the options apart from `nobracket` are mutually exclusive, but
+ if used together the last option is selected.
push::
- The name of a local ref which represents the `@{push}` location
- for the displayed ref. Respects `:short`, `:track`, and
- `:trackshort` options as `upstream` does. Produces an empty
- string if no `@{push}` ref is configured.
+ The name of a local ref which represents the `@{push}`
+ location for the displayed ref. Respects `:short`, `:strip`,
+ `:track`, and `:trackshort` options as `upstream`
+ does. Produces an empty string if no `@{push}` ref is
+ configured.
HEAD::
'*' if HEAD matches current ref (the checked out branch), ' '
diff --git a/ref-filter.c b/ref-filter.c
index 7bfd656..9140539 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -54,7 +54,8 @@ static struct used_atom {
char color[COLOR_MAXLEN];
struct align align;
struct {
- enum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT } option;
+ enum { RR_REF, RR_TRACK, RR_TRACKSHORT } option;
+ struct refname_atom refname;
unsigned int nobracket : 1;
} remote_ref;
struct {
@@ -104,7 +105,9 @@ static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
int i;
if (!arg) {
- atom->u.remote_ref.option = RR_NORMAL;
+ atom->u.remote_ref.option = RR_REF;
+ refname_atom_parser_internal(&atom->u.remote_ref.refname,
+ arg, atom->name);
return;
}
@@ -114,16 +117,17 @@ static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
for (i = 0; i < params.nr; i++) {
const char *s = params.items[i].string;
- if (!strcmp(s, "short"))
- atom->u.remote_ref.option = RR_SHORTEN;
- else if (!strcmp(s, "track"))
+ if (!strcmp(s, "track"))
atom->u.remote_ref.option = RR_TRACK;
else if (!strcmp(s, "trackshort"))
atom->u.remote_ref.option = RR_TRACKSHORT;
else if (!strcmp(s, "nobracket"))
atom->u.remote_ref.nobracket = 1;
- else
- die(_("unrecognized format: %%(%s)"), atom->name);
+ else {
+ atom->u.remote_ref.option = RR_REF;
+ refname_atom_parser_internal(&atom->u.remote_ref.refname,
+ arg, atom->name);
+ }
}
string_list_clear(¶ms, 0);
@@ -1119,8 +1123,8 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
struct branch *branch, const char **s)
{
int num_ours, num_theirs;
- if (atom->u.remote_ref.option == RR_SHORTEN)
- *s = shorten_unambiguous_ref(refname, warn_ambiguous_refs);
+ if (atom->u.remote_ref.option == RR_REF)
+ *s = show_ref(&atom->u.remote_ref.refname, refname);
else if (atom->u.remote_ref.option == RR_TRACK) {
if (stat_tracking_info(branch, &num_ours,
&num_theirs, NULL)) {
@@ -1152,8 +1156,8 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
*s = ">";
else
*s = "<>";
- } else /* RR_NORMAL */
- *s = refname;
+ } else
+ die("BUG: unhandled RR_* enum");
}
char *get_head_description(void)
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 18a9e25..c538084 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -55,8 +55,10 @@ test_atom head refname:strip=1 heads/master
test_atom head refname:strip=2 master
test_atom head upstream refs/remotes/origin/master
test_atom head upstream:short origin/master
+test_atom head upstream:strip=2 origin/master
test_atom head push refs/remotes/myfork/master
test_atom head push:short myfork/master
+test_atom head push:strip=1 remotes/myfork/master
test_atom head objecttype commit
test_atom head objectsize 171
test_atom head objectname $(git rev-parse refs/heads/master)
--
2.10.2
^ permalink raw reply related
* [PATCH v9 11/20] ref-filter: introduce refname_atom_parser()
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
Using refname_atom_parser_internal(), introduce refname_atom_parser()
which will parse the %(symref) and %(refname) atoms. Store the parsed
information into the 'used_atom' structure based on the modifiers used
along with the atoms.
Now the '%(symref)' atom supports the ':strip' atom modifier. Update the
Documentation and tests to reflect this.
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 5 +++
ref-filter.c | 73 +++++++++++++++++++++-----------------
t/t6300-for-each-ref.sh | 9 +++++
3 files changed, 54 insertions(+), 33 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index b17273e..0fa5818 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -170,6 +170,11 @@ if::
the value between the %(if:...) and %(then) atoms with the
given string.
+symref::
+ The ref which the given symbolic ref refers to. If not a
+ symbolic ref, nothing is printed. Respects the `:short` and
+ `:strip` options in the same way as `refname` above.
+
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
be used to specify the value in the header field.
diff --git a/ref-filter.c b/ref-filter.c
index c1ebc40..7bfd656 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -187,6 +187,11 @@ static void objectname_atom_parser(struct used_atom *atom, const char *arg)
die(_("unrecognized %%(objectname) argument: %s"), arg);
}
+static void refname_atom_parser(struct used_atom *atom, const char *arg)
+{
+ return refname_atom_parser_internal(&atom->u.refname, arg, atom->name);
+}
+
static align_type parse_align_position(const char *s)
{
if (!strcmp(s, "right"))
@@ -257,7 +262,7 @@ static struct {
cmp_type cmp_type;
void (*parser)(struct used_atom *atom, const char *arg);
} valid_atom[] = {
- { "refname" },
+ { "refname" , FIELD_STR, refname_atom_parser },
{ "objecttype" },
{ "objectsize", FIELD_ULONG },
{ "objectname", FIELD_STR, objectname_atom_parser },
@@ -287,7 +292,7 @@ static struct {
{ "contents", FIELD_STR, contents_atom_parser },
{ "upstream", FIELD_STR, remote_ref_atom_parser },
{ "push", FIELD_STR, remote_ref_atom_parser },
- { "symref" },
+ { "symref", FIELD_STR, refname_atom_parser },
{ "flag" },
{ "HEAD" },
{ "color", FIELD_STR, color_atom_parser },
@@ -1082,21 +1087,16 @@ static inline char *copy_advance(char *dst, const char *src)
return dst;
}
-static const char *strip_ref_components(const char *refname, const char *nr_arg)
+static const char *strip_ref_components(const char *refname, unsigned int len)
{
- char *end;
- long nr = strtol(nr_arg, &end, 10);
- long remaining = nr;
+ long remaining = len;
const char *start = refname;
- if (nr < 1 || *end != '\0')
- die(_(":strip= requires a positive integer argument"));
-
while (remaining) {
switch (*start++) {
case '\0':
- die(_("ref '%s' does not have %ld components to :strip"),
- refname, nr);
+ die(_("ref '%s' does not have %ud components to :strip"),
+ refname, len);
case '/':
remaining--;
break;
@@ -1105,6 +1105,16 @@ static const char *strip_ref_components(const char *refname, const char *nr_arg)
return start;
}
+static const char *show_ref(struct refname_atom *atom, const char *refname)
+{
+ if (atom->option == R_SHORT)
+ return shorten_unambiguous_ref(refname, warn_ambiguous_refs);
+ else if (atom->option == R_STRIP)
+ return strip_ref_components(refname, atom->strip);
+ else
+ return refname;
+}
+
static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
struct branch *branch, const char **s)
{
@@ -1177,6 +1187,21 @@ char *get_head_description(void)
return strbuf_detach(&desc, NULL);
}
+static const char *get_symref(struct used_atom *atom, struct ref_array_item *ref)
+{
+ if (!ref->symref)
+ return "";
+ else
+ return show_ref(&atom->u.refname, ref->symref);
+}
+
+static const char *get_refname(struct used_atom *atom, struct ref_array_item *ref)
+{
+ if (ref->kind & FILTER_REFS_DETACHED_HEAD)
+ return get_head_description();
+ return show_ref(&atom->u.refname, ref->refname);
+}
+
/*
* Parse the object referred by ref, and grab needed value.
*/
@@ -1205,7 +1230,6 @@ static void populate_value(struct ref_array_item *ref)
struct atom_value *v = &ref->value[i];
int deref = 0;
const char *refname;
- const char *formatp;
struct branch *branch = NULL;
v->handler = append_atom;
@@ -1216,12 +1240,10 @@ static void populate_value(struct ref_array_item *ref)
name++;
}
- if (starts_with(name, "refname")) {
- refname = ref->refname;
- if (ref->kind & FILTER_REFS_DETACHED_HEAD)
- refname = get_head_description();
- } else if (starts_with(name, "symref"))
- refname = ref->symref ? ref->symref : "";
+ if (starts_with(name, "refname"))
+ refname = get_refname(atom, ref);
+ else if (starts_with(name, "symref"))
+ refname = get_symref(atom, ref);
else if (starts_with(name, "upstream")) {
const char *branch_name;
/* only local branches may have an upstream */
@@ -1297,21 +1319,6 @@ static void populate_value(struct ref_array_item *ref)
} else
continue;
- formatp = strchr(name, ':');
- if (formatp) {
- const char *arg;
-
- formatp++;
- if (!strcmp(formatp, "short"))
- refname = shorten_unambiguous_ref(refname,
- warn_ambiguous_refs);
- else if (skip_prefix(formatp, "strip=", &arg))
- refname = strip_ref_components(refname, arg);
- else
- die(_("unknown %.*s format %s"),
- (int)(formatp - name), name, formatp);
- }
-
if (!deref)
v->s = refname;
else
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 7663a36..18a9e25 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -624,4 +624,13 @@ test_expect_success 'Verify usage of %(symref:short) atom' '
test_cmp expected actual
'
+cat >expected <<EOF
+master
+EOF
+
+test_expect_success 'Verify usage of %(symref:strip) atom' '
+ git for-each-ref --format="%(symref:strip=2)" refs/heads/sym > actual &&
+ test_cmp expected actual
+'
+
test_done
--
2.10.2
^ permalink raw reply related
* [PATCH v9 13/20] ref-filter: rename the 'strip' option to 'lstrip'
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
In preparation for the upcoming patch, where we introduce the 'rstrip'
option. Rename the 'strip' option to 'lstrip' to remove ambiguity.
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 10 +++++-----
builtin/tag.c | 4 ++--
ref-filter.c | 20 ++++++++++----------
t/t6300-for-each-ref.sh | 22 +++++++++++-----------
4 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index e7cdff6..46b4583 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -95,9 +95,9 @@ refname::
The name of the ref (the part after $GIT_DIR/).
For a non-ambiguous short name of the ref append `:short`.
The option core.warnAmbiguousRefs is used to select the strict
- abbreviation mode. If `strip=<N>` is appended, strips `<N>`
+ abbreviation mode. If `lstrip=<N>` is appended, strips `<N>`
slash-separated path components from the front of the refname
- (e.g., `%(refname:strip=2)` turns `refs/tags/foo` into `foo`.
+ (e.g., `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo`.
`<N>` must be a positive integer. If a displayed ref has fewer
components than `<N>`, the command aborts with an error.
@@ -116,7 +116,7 @@ objectname::
upstream::
The name of a local ref which can be considered ``upstream''
- from the displayed ref. Respects `:short` and `:strip` in the
+ from the displayed ref. Respects `:short` and `:lstrip` in the
same way as `refname` above. Additionally respects `:track`
to show "[ahead N, behind M]" and `:trackshort` to show the
terse version: ">" (ahead), "<" (behind), "<>" (ahead and
@@ -130,7 +130,7 @@ upstream::
push::
The name of a local ref which represents the `@{push}`
- location for the displayed ref. Respects `:short`, `:strip`,
+ location for the displayed ref. Respects `:short`, `:lstrip`,
`:track`, and `:trackshort` options as `upstream`
does. Produces an empty string if no `@{push}` ref is
configured.
@@ -174,7 +174,7 @@ if::
symref::
The ref which the given symbolic ref refers to. If not a
symbolic ref, nothing is printed. Respects the `:short` and
- `:strip` options in the same way as `refname` above.
+ `:lstrip` options in the same way as `refname` above.
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
diff --git a/builtin/tag.c b/builtin/tag.c
index 73df728..b4789ce 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -45,11 +45,11 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con
if (!format) {
if (filter->lines) {
to_free = xstrfmt("%s %%(contents:lines=%d)",
- "%(align:15)%(refname:strip=2)%(end)",
+ "%(align:15)%(refname:lstrip=2)%(end)",
filter->lines);
format = to_free;
} else
- format = "%(refname:strip=2)";
+ format = "%(refname:lstrip=2)";
}
verify_ref_format(format);
diff --git a/ref-filter.c b/ref-filter.c
index 9140539..e0015c6 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -33,8 +33,8 @@ struct if_then_else {
};
struct refname_atom {
- enum { R_NORMAL, R_SHORT, R_STRIP } option;
- unsigned int strip;
+ enum { R_NORMAL, R_SHORT, R_LSTRIP } option;
+ unsigned int lstrip;
};
/*
@@ -91,10 +91,10 @@ static void refname_atom_parser_internal(struct refname_atom *atom,
atom->option = R_NORMAL;
else if (!strcmp(arg, "short"))
atom->option = R_SHORT;
- else if (skip_prefix(arg, "strip=", &arg)) {
- atom->option = R_STRIP;
- if (strtoul_ui(arg, 10, &atom->strip) || atom->strip <= 0)
- die(_("positive value expected refname:strip=%s"), arg);
+ else if (skip_prefix(arg, "lstrip=", &arg)) {
+ atom->option = R_LSTRIP;
+ if (strtoul_ui(arg, 10, &atom->lstrip) || atom->lstrip <= 0)
+ die(_("positive value expected refname:lstrip=%s"), arg);
} else
die(_("unrecognized %%(%s) argument: %s"), name, arg);
}
@@ -1091,7 +1091,7 @@ static inline char *copy_advance(char *dst, const char *src)
return dst;
}
-static const char *strip_ref_components(const char *refname, unsigned int len)
+static const char *lstrip_ref_components(const char *refname, unsigned int len)
{
long remaining = len;
const char *start = refname;
@@ -1099,7 +1099,7 @@ static const char *strip_ref_components(const char *refname, unsigned int len)
while (remaining) {
switch (*start++) {
case '\0':
- die(_("ref '%s' does not have %ud components to :strip"),
+ die(_("ref '%s' does not have %ud components to :lstrip"),
refname, len);
case '/':
remaining--;
@@ -1113,8 +1113,8 @@ static const char *show_ref(struct refname_atom *atom, const char *refname)
{
if (atom->option == R_SHORT)
return shorten_unambiguous_ref(refname, warn_ambiguous_refs);
- else if (atom->option == R_STRIP)
- return strip_ref_components(refname, atom->strip);
+ else if (atom->option == R_LSTRIP)
+ return lstrip_ref_components(refname, atom->lstrip);
else
return refname;
}
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index c538084..5eb013c 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -51,14 +51,14 @@ test_atom() {
test_atom head refname refs/heads/master
test_atom head refname:short master
-test_atom head refname:strip=1 heads/master
-test_atom head refname:strip=2 master
+test_atom head refname:lstrip=1 heads/master
+test_atom head refname:lstrip=2 master
test_atom head upstream refs/remotes/origin/master
test_atom head upstream:short origin/master
-test_atom head upstream:strip=2 origin/master
+test_atom head upstream:lstrip=2 origin/master
test_atom head push refs/remotes/myfork/master
test_atom head push:short myfork/master
-test_atom head push:strip=1 remotes/myfork/master
+test_atom head push:lstrip=1 remotes/myfork/master
test_atom head objecttype commit
test_atom head objectsize 171
test_atom head objectname $(git rev-parse refs/heads/master)
@@ -141,14 +141,14 @@ test_expect_success 'Check invalid atoms names are errors' '
test_must_fail git for-each-ref --format="%(INVALID)" refs/heads
'
-test_expect_success 'arguments to :strip must be positive integers' '
- test_must_fail git for-each-ref --format="%(refname:strip=0)" &&
- test_must_fail git for-each-ref --format="%(refname:strip=-1)" &&
- test_must_fail git for-each-ref --format="%(refname:strip=foo)"
+test_expect_success 'arguments to :lstrip must be positive integers' '
+ test_must_fail git for-each-ref --format="%(refname:lstrip=0)" &&
+ test_must_fail git for-each-ref --format="%(refname:lstrip=-1)" &&
+ test_must_fail git for-each-ref --format="%(refname:lstrip=foo)"
'
test_expect_success 'stripping refnames too far gives an error' '
- test_must_fail git for-each-ref --format="%(refname:strip=3)"
+ test_must_fail git for-each-ref --format="%(refname:lstrip=3)"
'
test_expect_success 'Check format specifiers are ignored in naming date atoms' '
@@ -630,8 +630,8 @@ cat >expected <<EOF
master
EOF
-test_expect_success 'Verify usage of %(symref:strip) atom' '
- git for-each-ref --format="%(symref:strip=2)" refs/heads/sym > actual &&
+test_expect_success 'Verify usage of %(symref:lstrip) atom' '
+ git for-each-ref --format="%(symref:lstrip=2)" refs/heads/sym > actual &&
test_cmp expected actual
'
--
2.10.2
^ permalink raw reply related
* [PATCH v9 14/20] ref-filter: Do not abruptly die when using the 'lstrip=<N>' option
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
Currently when we use the 'lstrip=<N>' option, if 'N' is greater than
the number of components available in the refname, we abruptly end
program execution by calling die().
This behavior is undesired since a single refname with few components
could end program execution. To avoid this, return an empty string
whenever the value 'N' is greater than the number of components
available, instead of calling die().
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 3 +--
ref-filter.c | 3 +--
t/t6300-for-each-ref.sh | 4 ----
3 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 46b4583..82c202a 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -98,8 +98,7 @@ refname::
abbreviation mode. If `lstrip=<N>` is appended, strips `<N>`
slash-separated path components from the front of the refname
(e.g., `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo`.
- `<N>` must be a positive integer. If a displayed ref has fewer
- components than `<N>`, the command aborts with an error.
+ `<N>` must be a positive integer.
objecttype::
The type of the object (`blob`, `tree`, `commit`, `tag`).
diff --git a/ref-filter.c b/ref-filter.c
index e0015c6..76553eb 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1099,8 +1099,7 @@ static const char *lstrip_ref_components(const char *refname, unsigned int len)
while (remaining) {
switch (*start++) {
case '\0':
- die(_("ref '%s' does not have %ud components to :lstrip"),
- refname, len);
+ return "";
case '/':
remaining--;
break;
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 5eb013c..d3d1a97 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -147,10 +147,6 @@ test_expect_success 'arguments to :lstrip must be positive integers' '
test_must_fail git for-each-ref --format="%(refname:lstrip=foo)"
'
-test_expect_success 'stripping refnames too far gives an error' '
- test_must_fail git for-each-ref --format="%(refname:lstrip=3)"
-'
-
test_expect_success 'Check format specifiers are ignored in naming date atoms' '
git for-each-ref --format="%(authordate)" refs/heads &&
git for-each-ref --format="%(authordate:default) %(authordate)" refs/heads &&
--
2.10.2
^ permalink raw reply related
* [PATCH v9 15/20] ref-filter: modify the 'lstrip=<N>' option to work with negative '<N>'
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
Currently the 'lstrip=<N>' option only takes a positive value '<N>'
and strips '<N>' slash-separated path components from the left. Modify
the 'lstrip' option to also take a negative number '<N>' which would
only _leave_ behind 'N' slash-separated path components from the left.
Add documentation and tests for the same.
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 3 ++-
ref-filter.c | 27 ++++++++++++++++++++++-----
t/t6300-for-each-ref.sh | 12 ++++++------
3 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 82c202a..9055ba0 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -98,7 +98,8 @@ refname::
abbreviation mode. If `lstrip=<N>` is appended, strips `<N>`
slash-separated path components from the front of the refname
(e.g., `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo`.
- `<N>` must be a positive integer.
+ if `<N>` is a negative number, then only `<N>` path components
+ are left behind.
objecttype::
The type of the object (`blob`, `tree`, `commit`, `tag`).
diff --git a/ref-filter.c b/ref-filter.c
index 76553eb..1cd92ea 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -34,7 +34,7 @@ struct if_then_else {
struct refname_atom {
enum { R_NORMAL, R_SHORT, R_LSTRIP } option;
- unsigned int lstrip;
+ int lstrip;
};
/*
@@ -93,8 +93,8 @@ static void refname_atom_parser_internal(struct refname_atom *atom,
atom->option = R_SHORT;
else if (skip_prefix(arg, "lstrip=", &arg)) {
atom->option = R_LSTRIP;
- if (strtoul_ui(arg, 10, &atom->lstrip) || atom->lstrip <= 0)
- die(_("positive value expected refname:lstrip=%s"), arg);
+ if (strtol_i(arg, 10, &atom->lstrip))
+ die(_("Integer value expected refname:lstrip=%s"), arg);
} else
die(_("unrecognized %%(%s) argument: %s"), name, arg);
}
@@ -1091,12 +1091,28 @@ static inline char *copy_advance(char *dst, const char *src)
return dst;
}
-static const char *lstrip_ref_components(const char *refname, unsigned int len)
+static const char *lstrip_ref_components(const char *refname, int len)
{
long remaining = len;
const char *start = refname;
- while (remaining) {
+ if (len < 0) {
+ int i;
+ const char *p = refname;
+
+ /* Find total no of '/' separated path-components */
+ for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
+ ;
+ /*
+ * The number of components we need to strip is now
+ * the total minus the components to be left (Plus one
+ * because we count the number of '/', but the number
+ * of components is one more than the no of '/').
+ */
+ remaining = i + len + 1;
+ }
+
+ while (remaining > 0) {
switch (*start++) {
case '\0':
return "";
@@ -1105,6 +1121,7 @@ static const char *lstrip_ref_components(const char *refname, unsigned int len)
break;
}
}
+
return start;
}
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index d3d1a97..203cfaa 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -53,12 +53,16 @@ test_atom head refname refs/heads/master
test_atom head refname:short master
test_atom head refname:lstrip=1 heads/master
test_atom head refname:lstrip=2 master
+test_atom head refname:lstrip=-1 master
+test_atom head refname:lstrip=-2 heads/master
test_atom head upstream refs/remotes/origin/master
test_atom head upstream:short origin/master
test_atom head upstream:lstrip=2 origin/master
+test_atom head upstream:lstrip=-2 origin/master
test_atom head push refs/remotes/myfork/master
test_atom head push:short myfork/master
test_atom head push:lstrip=1 remotes/myfork/master
+test_atom head push:lstrip=-1 master
test_atom head objecttype commit
test_atom head objectsize 171
test_atom head objectname $(git rev-parse refs/heads/master)
@@ -141,12 +145,6 @@ test_expect_success 'Check invalid atoms names are errors' '
test_must_fail git for-each-ref --format="%(INVALID)" refs/heads
'
-test_expect_success 'arguments to :lstrip must be positive integers' '
- test_must_fail git for-each-ref --format="%(refname:lstrip=0)" &&
- test_must_fail git for-each-ref --format="%(refname:lstrip=-1)" &&
- test_must_fail git for-each-ref --format="%(refname:lstrip=foo)"
-'
-
test_expect_success 'Check format specifiers are ignored in naming date atoms' '
git for-each-ref --format="%(authordate)" refs/heads &&
git for-each-ref --format="%(authordate:default) %(authordate)" refs/heads &&
@@ -624,10 +622,12 @@ test_expect_success 'Verify usage of %(symref:short) atom' '
cat >expected <<EOF
master
+heads/master
EOF
test_expect_success 'Verify usage of %(symref:lstrip) atom' '
git for-each-ref --format="%(symref:lstrip=2)" refs/heads/sym > actual &&
+ git for-each-ref --format="%(symref:lstrip=-2)" refs/heads/sym >> actual &&
test_cmp expected actual
'
--
2.10.2
^ permalink raw reply related
* [PATCH v9 16/20] ref-filter: add an 'rstrip=<N>' option to atoms which deal with refnames
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
Complimenting the existing 'lstrip=<N>' option, add an 'rstrip=<N>'
option which strips `<N>` slash-separated path components from the end
of the refname (e.g., `%(refname:rstrip=2)` turns `refs/tags/foo` into
`refs`).
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
Documentation/git-for-each-ref.txt | 40 ++++++++++++++++++++-----------------
ref-filter.c | 41 ++++++++++++++++++++++++++++++++++++--
t/t6300-for-each-ref.sh | 19 ++++++++++++++++++
3 files changed, 80 insertions(+), 20 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 9055ba0..81db67d 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -95,10 +95,12 @@ refname::
The name of the ref (the part after $GIT_DIR/).
For a non-ambiguous short name of the ref append `:short`.
The option core.warnAmbiguousRefs is used to select the strict
- abbreviation mode. If `lstrip=<N>` is appended, strips `<N>`
- slash-separated path components from the front of the refname
- (e.g., `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo`.
- if `<N>` is a negative number, then only `<N>` path components
+ abbreviation mode. The `lstrip=<N>` or `rstrip=<N>` option can
+ be appended to strip `<N>` slash-separated path components
+ from the left or right of the refname respectively (e.g.,
+ `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo` and
+ `%(refname:rstrip=2)` turns `refs/tags/foo` into `refs`). if
+ `<N>` is a negative number, then only `<N>` path components
are left behind.
objecttype::
@@ -116,22 +118,23 @@ objectname::
upstream::
The name of a local ref which can be considered ``upstream''
- from the displayed ref. Respects `:short` and `:lstrip` in the
- same way as `refname` above. Additionally respects `:track`
- to show "[ahead N, behind M]" and `:trackshort` to show the
- terse version: ">" (ahead), "<" (behind), "<>" (ahead and
- behind), or "=" (in sync). `:track` also prints "[gone]"
- whenever unknown upstream ref is encountered. Append
- `:track,nobracket` to show tracking information without
- brackets (i.e "ahead N, behind M"). Has no effect if the ref
- does not have tracking information associated with it. All
- the options apart from `nobracket` are mutually exclusive, but
- if used together the last option is selected.
+ from the displayed ref. Respects `:short`, `:lstrip` and
+ `:rstrip` in the same way as `refname` above. Additionally
+ respects `:track` to show "[ahead N, behind M]" and
+ `:trackshort` to show the terse version: ">" (ahead), "<"
+ (behind), "<>" (ahead and behind), or "=" (in sync). `:track`
+ also prints "[gone]" whenever unknown upstream ref is
+ encountered. Append `:track,nobracket` to show tracking
+ information without brackets (i.e "ahead N, behind M"). Has
+ no effect if the ref does not have tracking information
+ associated with it. All the options apart from `nobracket`
+ are mutually exclusive, but if used together the last option
+ is selected.
push::
The name of a local ref which represents the `@{push}`
location for the displayed ref. Respects `:short`, `:lstrip`,
- `:track`, and `:trackshort` options as `upstream`
+ `:rstrip`, `:track`, and `:trackshort` options as `upstream`
does. Produces an empty string if no `@{push}` ref is
configured.
@@ -173,8 +176,9 @@ if::
symref::
The ref which the given symbolic ref refers to. If not a
- symbolic ref, nothing is printed. Respects the `:short` and
- `:lstrip` options in the same way as `refname` above.
+ symbolic ref, nothing is printed. Respects the `:short`,
+ `:lstrip` and `:rstrip` options in the same way as `refname`
+ above.
In addition to the above, for commit and tag objects, the header
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
diff --git a/ref-filter.c b/ref-filter.c
index 1cd92ea..dd7e751 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -33,8 +33,8 @@ struct if_then_else {
};
struct refname_atom {
- enum { R_NORMAL, R_SHORT, R_LSTRIP } option;
- int lstrip;
+ enum { R_NORMAL, R_SHORT, R_LSTRIP, R_RSTRIP } option;
+ int lstrip, rstrip;
};
/*
@@ -95,6 +95,10 @@ static void refname_atom_parser_internal(struct refname_atom *atom,
atom->option = R_LSTRIP;
if (strtol_i(arg, 10, &atom->lstrip))
die(_("Integer value expected refname:lstrip=%s"), arg);
+ } else if (skip_prefix(arg, "rstrip=", &arg)) {
+ atom->option = R_RSTRIP;
+ if (strtol_i(arg, 10, &atom->rstrip))
+ die(_("Integer value expected refname:rstrip=%s"), arg);
} else
die(_("unrecognized %%(%s) argument: %s"), name, arg);
}
@@ -1125,12 +1129,45 @@ static const char *lstrip_ref_components(const char *refname, int len)
return start;
}
+static const char *rstrip_ref_components(const char *refname, int len)
+{
+ long remaining = len;
+ char *start = xstrdup(refname);
+
+ if (len < 0) {
+ int i;
+ const char *p = refname;
+
+ /* Find total no of '/' separated path-components */
+ for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
+ ;
+ /*
+ * The number of components we need to strip is now
+ * the total minus the components to be left (Plus one
+ * because we count the number of '/', but the number
+ * of components is one more than the no of '/').
+ */
+ remaining = i + len + 1;
+ }
+
+ while (remaining-- > 0) {
+ char *p = strrchr(start, '/');
+ if (p == NULL)
+ return "";
+ else
+ p[0] = '\0';
+ }
+ return start;
+}
+
static const char *show_ref(struct refname_atom *atom, const char *refname)
{
if (atom->option == R_SHORT)
return shorten_unambiguous_ref(refname, warn_ambiguous_refs);
else if (atom->option == R_LSTRIP)
return lstrip_ref_components(refname, atom->lstrip);
+ else if (atom->option == R_RSTRIP)
+ return rstrip_ref_components(refname, atom->rstrip);
else
return refname;
}
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 203cfaa..25a9973 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -55,14 +55,22 @@ test_atom head refname:lstrip=1 heads/master
test_atom head refname:lstrip=2 master
test_atom head refname:lstrip=-1 master
test_atom head refname:lstrip=-2 heads/master
+test_atom head refname:rstrip=1 refs/heads
+test_atom head refname:rstrip=2 refs
+test_atom head refname:rstrip=-1 refs
+test_atom head refname:rstrip=-2 refs/heads
test_atom head upstream refs/remotes/origin/master
test_atom head upstream:short origin/master
test_atom head upstream:lstrip=2 origin/master
test_atom head upstream:lstrip=-2 origin/master
+test_atom head upstream:rstrip=2 refs/remotes
+test_atom head upstream:rstrip=-2 refs/remotes
test_atom head push refs/remotes/myfork/master
test_atom head push:short myfork/master
test_atom head push:lstrip=1 remotes/myfork/master
test_atom head push:lstrip=-1 master
+test_atom head push:rstrip=1 refs/remotes/myfork
+test_atom head push:rstrip=-1 refs
test_atom head objecttype commit
test_atom head objectsize 171
test_atom head objectname $(git rev-parse refs/heads/master)
@@ -631,4 +639,15 @@ test_expect_success 'Verify usage of %(symref:lstrip) atom' '
test_cmp expected actual
'
+cat >expected <<EOF
+refs
+refs/heads
+EOF
+
+test_expect_success 'Verify usage of %(symref:rstrip) atom' '
+ git for-each-ref --format="%(symref:rstrip=2)" refs/heads/sym > actual &&
+ git for-each-ref --format="%(symref:rstrip=-2)" refs/heads/sym >> actual &&
+ test_cmp expected actual
+'
+
test_done
--
2.10.2
^ permalink raw reply related
* [PATCH v9 17/20] ref-filter: allow porcelain to translate messages in the output
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
Introduce setup_ref_filter_porcelain_msg() so that the messages used in
the atom %(upstream:track) can be translated if needed. By default, keep
the messages untranslated, which is the right behavior for plumbing
commands. This is needed as we port branch.c to use ref-filter's
printing API's.
Written-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
ref-filter.c | 29 +++++++++++++++++++++++++----
ref-filter.h | 2 ++
2 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/ref-filter.c b/ref-filter.c
index dd7e751..e478ec6 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -16,6 +16,27 @@
#include "trailer.h"
#include "wt-status.h"
+static struct ref_msg {
+ const char *gone;
+ const char *ahead;
+ const char *behind;
+ const char *ahead_behind;
+} msgs = {
+ /* Untranslated plumbing messages: */
+ "gone",
+ "ahead %d",
+ "behind %d",
+ "ahead %d, behind %d"
+};
+
+void setup_ref_filter_porcelain_msg(void)
+{
+ msgs.gone = _("gone");
+ msgs.ahead = _("ahead %d");
+ msgs.behind = _("behind %d");
+ msgs.ahead_behind = _("ahead %d, behind %d");
+}
+
typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
typedef enum { COMPARE_EQUAL, COMPARE_UNEQUAL, COMPARE_NONE } cmp_status;
@@ -1181,15 +1202,15 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
else if (atom->u.remote_ref.option == RR_TRACK) {
if (stat_tracking_info(branch, &num_ours,
&num_theirs, NULL)) {
- *s = xstrdup("gone");
+ *s = xstrdup(msgs.gone);
} else if (!num_ours && !num_theirs)
*s = "";
else if (!num_ours)
- *s = xstrfmt("behind %d", num_theirs);
+ *s = xstrfmt(msgs.behind, num_theirs);
else if (!num_theirs)
- *s = xstrfmt("ahead %d", num_ours);
+ *s = xstrfmt(msgs.ahead, num_ours);
else
- *s = xstrfmt("ahead %d, behind %d",
+ *s = xstrfmt(msgs.ahead_behind,
num_ours, num_theirs);
if (!atom->u.remote_ref.nobracket && *s[0]) {
const char *to_free = *s;
diff --git a/ref-filter.h b/ref-filter.h
index 630e7c2..44b36ed 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -113,5 +113,7 @@ struct ref_sorting *ref_default_sorting(void);
int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset);
/* Get the current HEAD's description */
char *get_head_description(void);
+/* Set up translated strings in the output. */
+void setup_ref_filter_porcelain_msg(void);
#endif /* REF_FILTER_H */
--
2.10.2
^ permalink raw reply related
* [PATCH v9 18/20] branch, tag: use porcelain output
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
Call ref-filter's setup_ref_filter_porcelain_msg() to enable
translated messages for the %(upstream:tack) atom. Although branch.c
doesn't currently use ref-filter's printing API's, this will ensure
that when it does in the future patches, we do not need to worry about
translation.
Written-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
builtin/branch.c | 2 ++
builtin/tag.c | 2 ++
2 files changed, 4 insertions(+)
diff --git a/builtin/branch.c b/builtin/branch.c
index 6423ebc..34cd61c 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -649,6 +649,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
OPT_END(),
};
+ setup_ref_filter_porcelain_msg();
+
memset(&filter, 0, sizeof(filter));
filter.kind = FILTER_REFS_BRANCHES;
filter.abbrev = -1;
diff --git a/builtin/tag.c b/builtin/tag.c
index b4789ce..8a1a476 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -375,6 +375,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_END()
};
+ setup_ref_filter_porcelain_msg();
+
git_config(git_tag_config, sorting_tail);
memset(&opt, 0, sizeof(opt));
--
2.10.2
^ permalink raw reply related
* [PATCH v9 19/20] branch: use ref-filter printing APIs
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
Port branch.c to use ref-filter APIs for printing. This clears out
most of the code used in branch.c for printing and replaces them with
calls made to the ref-filter library.
Introduce build_format() which gets the format required for printing
of refs. Make amendments to print_ref_list() to reflect these changes.
The strings included in build_format() may not be safely quoted for
inclusion (i.e. it might contain '%' which needs to be escaped with an
additional '%'). Introduce quote_literal_for_format() as a helper
function which takes a string and returns a version of the string that
is safely quoted to be used in the for-each-ref format which is built
in build_format().
Change calc_maxwidth() to also account for the length of HEAD ref, by
calling ref-filter:get_head_discription().
Also change the test in t6040 to reflect the changes.
Before this patch, all cross-prefix symrefs weren't shortened. Since
we're using ref-filter APIs, we shorten all symrefs by default. We also
allow the user to change the format if needed with the introduction of
the '--format' option in the next patch.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Jeff King <peff@peff.net>
Helped-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
builtin/branch.c | 249 ++++++++++++++++-------------------------------
t/t3203-branch-output.sh | 2 +-
t/t6040-tracking-info.sh | 2 +-
3 files changed, 88 insertions(+), 165 deletions(-)
diff --git a/builtin/branch.c b/builtin/branch.c
index 34cd61c..2887545 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -36,12 +36,12 @@ static unsigned char head_sha1[20];
static int branch_use_color = -1;
static char branch_colors[][COLOR_MAXLEN] = {
- GIT_COLOR_RESET,
- GIT_COLOR_NORMAL, /* PLAIN */
- GIT_COLOR_RED, /* REMOTE */
- GIT_COLOR_NORMAL, /* LOCAL */
- GIT_COLOR_GREEN, /* CURRENT */
- GIT_COLOR_BLUE, /* UPSTREAM */
+ "%(color:reset)",
+ "%(color:reset)", /* PLAIN */
+ "%(color:red)", /* REMOTE */
+ "%(color:reset)", /* LOCAL */
+ "%(color:green)", /* CURRENT */
+ "%(color:blue)", /* UPSTREAM */
};
enum color_branch {
BRANCH_COLOR_RESET = 0,
@@ -280,180 +280,88 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
return(ret);
}
-static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
- int show_upstream_ref)
+static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
{
- int ours, theirs;
- char *ref = NULL;
- struct branch *branch = branch_get(branch_name);
- const char *upstream;
- struct strbuf fancy = STRBUF_INIT;
- int upstream_is_gone = 0;
- int added_decoration = 1;
-
- if (stat_tracking_info(branch, &ours, &theirs, &upstream) < 0) {
- if (!upstream)
- return;
- upstream_is_gone = 1;
- }
-
- if (show_upstream_ref) {
- ref = shorten_unambiguous_ref(upstream, 0);
- if (want_color(branch_use_color))
- strbuf_addf(&fancy, "%s%s%s",
- branch_get_color(BRANCH_COLOR_UPSTREAM),
- ref, branch_get_color(BRANCH_COLOR_RESET));
- else
- strbuf_addstr(&fancy, ref);
- }
+ int i, max = 0;
+ for (i = 0; i < refs->nr; i++) {
+ struct ref_array_item *it = refs->items[i];
+ const char *desc = it->refname;
+ int w;
- if (upstream_is_gone) {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s: gone]"), fancy.buf);
- else
- added_decoration = 0;
- } else if (!ours && !theirs) {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s]"), fancy.buf);
- else
- added_decoration = 0;
- } else if (!ours) {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
- else
- strbuf_addf(stat, _("[behind %d]"), theirs);
+ skip_prefix(it->refname, "refs/heads/", &desc);
+ skip_prefix(it->refname, "refs/remotes/", &desc);
+ if (it->kind == FILTER_REFS_DETACHED_HEAD) {
+ char *head_desc = get_head_description();
+ w = utf8_strwidth(head_desc);
+ free(head_desc);
+ } else
+ w = utf8_strwidth(desc);
- } else if (!theirs) {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
- else
- strbuf_addf(stat, _("[ahead %d]"), ours);
- } else {
- if (show_upstream_ref)
- strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
- fancy.buf, ours, theirs);
- else
- strbuf_addf(stat, _("[ahead %d, behind %d]"),
- ours, theirs);
+ if (it->kind == FILTER_REFS_REMOTES)
+ w += remote_bonus;
+ if (w > max)
+ max = w;
}
- strbuf_release(&fancy);
- if (added_decoration)
- strbuf_addch(stat, ' ');
- free(ref);
+ return max;
}
-static void add_verbose_info(struct strbuf *out, struct ref_array_item *item,
- struct ref_filter *filter, const char *refname)
+static const char *quote_literal_for_format(const char *s)
{
- struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
- const char *sub = _(" **** invalid ref ****");
- struct commit *commit = item->commit;
+ static struct strbuf buf = STRBUF_INIT;
- if (!parse_commit(commit)) {
- pp_commit_easy(CMIT_FMT_ONELINE, commit, &subject);
- sub = subject.buf;
+ strbuf_reset(&buf);
+ while (*s) {
+ const char *ep = strchrnul(s, '%');
+ if (s < ep)
+ strbuf_add(&buf, s, ep - s);
+ if (*ep == '%') {
+ strbuf_addstr(&buf, "%%");
+ s = ep + 1;
+ } else {
+ s = ep;
+ }
}
-
- if (item->kind == FILTER_REFS_BRANCHES)
- fill_tracking_info(&stat, refname, filter->verbose > 1);
-
- strbuf_addf(out, " %s %s%s",
- find_unique_abbrev(item->commit->object.oid.hash, filter->abbrev),
- stat.buf, sub);
- strbuf_release(&stat);
- strbuf_release(&subject);
+ return buf.buf;
}
-static void format_and_print_ref_item(struct ref_array_item *item, int maxwidth,
- struct ref_filter *filter, const char *remote_prefix)
+static char *build_format(struct ref_filter *filter, int maxwidth, const char *remote_prefix)
{
- char c;
- int current = 0;
- int color;
- struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
- const char *prefix_to_show = "";
- const char *prefix_to_skip = NULL;
- const char *desc = item->refname;
- char *to_free = NULL;
-
- switch (item->kind) {
- case FILTER_REFS_BRANCHES:
- prefix_to_skip = "refs/heads/";
- skip_prefix(desc, prefix_to_skip, &desc);
- if (!filter->detached && !strcmp(desc, head))
- current = 1;
- else
- color = BRANCH_COLOR_LOCAL;
- break;
- case FILTER_REFS_REMOTES:
- prefix_to_skip = "refs/remotes/";
- skip_prefix(desc, prefix_to_skip, &desc);
- color = BRANCH_COLOR_REMOTE;
- prefix_to_show = remote_prefix;
- break;
- case FILTER_REFS_DETACHED_HEAD:
- desc = to_free = get_head_description();
- current = 1;
- break;
- default:
- color = BRANCH_COLOR_PLAIN;
- break;
- }
+ struct strbuf fmt = STRBUF_INIT;
+ struct strbuf local = STRBUF_INIT;
+ struct strbuf remote = STRBUF_INIT;
- c = ' ';
- if (current) {
- c = '*';
- color = BRANCH_COLOR_CURRENT;
- }
+ strbuf_addf(&fmt, "%%(if)%%(HEAD)%%(then)* %s%%(else) %%(end)",
+ branch_get_color(BRANCH_COLOR_CURRENT));
- strbuf_addf(&name, "%s%s", prefix_to_show, desc);
if (filter->verbose) {
- int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf);
- strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
- maxwidth + utf8_compensation, name.buf,
+ strbuf_addf(&local, "%%(align:%d,left)%%(refname:lstrip=2)%%(end)", maxwidth);
+ strbuf_addf(&local, "%s", branch_get_color(BRANCH_COLOR_RESET));
+ strbuf_addf(&local, " %%(objectname:short=7) ");
+
+ if (filter->verbose > 1)
+ strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
+ "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
+ branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
+ else
+ strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)");
+
+ strbuf_addf(&remote, "%s%%(align:%d,left)%s%%(refname:lstrip=2)%%(end)%s%%(if)%%(symref)%%(then) -> %%(symref:short)"
+ "%%(else) %%(objectname:short=7) %%(contents:subject)%%(end)",
+ branch_get_color(BRANCH_COLOR_REMOTE), maxwidth, quote_literal_for_format(remote_prefix),
branch_get_color(BRANCH_COLOR_RESET));
- } else
- strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
- name.buf, branch_get_color(BRANCH_COLOR_RESET));
-
- if (item->symref) {
- const char *symref = item->symref;
- if (prefix_to_skip)
- skip_prefix(symref, prefix_to_skip, &symref);
- strbuf_addf(&out, " -> %s", symref);
- }
- else if (filter->verbose)
- /* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
- add_verbose_info(&out, item, filter, desc);
- if (column_active(colopts)) {
- assert(!filter->verbose && "--column and --verbose are incompatible");
- string_list_append(&output, out.buf);
} else {
- printf("%s\n", out.buf);
+ strbuf_addf(&local, "%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)",
+ branch_get_color(BRANCH_COLOR_RESET));
+ strbuf_addf(&remote, "%s%s%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)",
+ branch_get_color(BRANCH_COLOR_REMOTE), quote_literal_for_format(remote_prefix),
+ branch_get_color(BRANCH_COLOR_RESET));
}
- strbuf_release(&name);
- strbuf_release(&out);
- free(to_free);
-}
-
-static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
-{
- int i, max = 0;
- for (i = 0; i < refs->nr; i++) {
- struct ref_array_item *it = refs->items[i];
- const char *desc = it->refname;
- int w;
- skip_prefix(it->refname, "refs/heads/", &desc);
- skip_prefix(it->refname, "refs/remotes/", &desc);
- w = utf8_strwidth(desc);
+ strbuf_addf(&fmt, "%%(if:notequals=refs/remotes)%%(refname:rstrip=-2)%%(then)%s%%(else)%s%%(end)", local.buf, remote.buf);
- if (it->kind == FILTER_REFS_REMOTES)
- w += remote_bonus;
- if (w > max)
- max = w;
- }
- return max;
+ strbuf_release(&local);
+ strbuf_release(&remote);
+ return strbuf_detach(&fmt, NULL);
}
static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)
@@ -462,6 +370,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
struct ref_array array;
int maxwidth = 0;
const char *remote_prefix = "";
+ struct strbuf out = STRBUF_INIT;
+ char *format;
/*
* If we are listing more than just remote branches,
@@ -473,18 +383,31 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
memset(&array, 0, sizeof(array));
- verify_ref_format("%(refname)%(symref)");
filter_refs(&array, filter, filter->kind | FILTER_REFS_INCLUDE_BROKEN);
if (filter->verbose)
maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
+ format = build_format(filter, maxwidth, remote_prefix);
+ verify_ref_format(format);
+
ref_array_sort(sorting, &array);
- for (i = 0; i < array.nr; i++)
- format_and_print_ref_item(array.items[i], maxwidth, filter, remote_prefix);
+ for (i = 0; i < array.nr; i++) {
+ format_ref_array_item(array.items[i], format, 0, &out);
+ if (column_active(colopts)) {
+ assert(!filter->verbose && "--column and --verbose are incompatible");
+ /* format to a string_list to let print_columns() do its job */
+ string_list_append(&output, out.buf);
+ } else {
+ fwrite(out.buf, 1, out.len, stdout);
+ putchar('\n');
+ }
+ strbuf_release(&out);
+ }
ref_array_clear(&array);
+ free(format);
}
static void reject_rebase_or_bisect_branch(const char *target)
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 52283df..4521328 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -194,7 +194,7 @@ test_expect_success 'local-branch symrefs shortened properly' '
git symbolic-ref refs/heads/ref-to-remote refs/remotes/origin/branch-one &&
cat >expect <<-\EOF &&
ref-to-branch -> branch-one
- ref-to-remote -> refs/remotes/origin/branch-one
+ ref-to-remote -> origin/branch-one
EOF
git branch >actual.raw &&
grep ref-to <actual.raw >actual &&
diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh
index 3d5c238..97a0765 100755
--- a/t/t6040-tracking-info.sh
+++ b/t/t6040-tracking-info.sh
@@ -44,7 +44,7 @@ b1 [ahead 1, behind 1] d
b2 [ahead 1, behind 1] d
b3 [behind 1] b
b4 [ahead 2] f
-b5 g
+b5 [gone] g
b6 c
EOF
--
2.10.2
^ permalink raw reply related
* [PATCH v9 20/20] branch: implement '--format' option
From: Karthik Nayak @ 2016-12-27 16:23 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, ramsay, Karthik Nayak
In-Reply-To: <20161227162357.28212-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
Implement the '--format' option provided by 'ref-filter'. This lets the
user list branches as per desired format similar to the implementation
in 'git for-each-ref'.
Add tests and documentation for the same.
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
---
Documentation/git-branch.txt | 7 ++++++-
builtin/branch.c | 14 +++++++++-----
t/t3203-branch-output.sh | 14 ++++++++++++++
3 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 5516a47..1fae4ee 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -12,7 +12,7 @@ SYNOPSIS
[--list] [-v [--abbrev=<length> | --no-abbrev]]
[--column[=<options>] | --no-column]
[(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>]
- [--points-at <object>] [<pattern>...]
+ [--points-at <object>] [--format=<format>] [<pattern>...]
'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
'git branch' --unset-upstream [<branchname>]
@@ -250,6 +250,11 @@ start-point is either a local or remote-tracking branch.
--points-at <object>::
Only list branches of the given object.
+--format <format>::
+ A string that interpolates `%(fieldname)` from the object
+ pointed at by a ref being shown. The format is the same as
+ that of linkgit:git-for-each-ref[1].
+
Examples
--------
diff --git a/builtin/branch.c b/builtin/branch.c
index 2887545..4051a18 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -28,6 +28,7 @@ static const char * const builtin_branch_usage[] = {
N_("git branch [<options>] [-r] (-d | -D) <branch-name>..."),
N_("git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"),
N_("git branch [<options>] [-r | -a] [--points-at]"),
+ N_("git branch [<options>] [-r | -a] [--format]"),
NULL
};
@@ -364,14 +365,14 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
return strbuf_detach(&fmt, NULL);
}
-static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting)
+static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)
{
int i;
struct ref_array array;
int maxwidth = 0;
const char *remote_prefix = "";
struct strbuf out = STRBUF_INIT;
- char *format;
+ char *to_free = NULL;
/*
* If we are listing more than just remote branches,
@@ -388,7 +389,8 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
if (filter->verbose)
maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
- format = build_format(filter, maxwidth, remote_prefix);
+ if (!format)
+ format = to_free = build_format(filter, maxwidth, remote_prefix);
verify_ref_format(format);
ref_array_sort(sorting, &array);
@@ -407,7 +409,7 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
}
ref_array_clear(&array);
- free(format);
+ free(to_free);
}
static void reject_rebase_or_bisect_branch(const char *target)
@@ -528,6 +530,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
struct ref_filter filter;
int icase = 0;
static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
+ const char *format = NULL;
struct option options[] = {
OPT_GROUP(N_("Generic options")),
@@ -569,6 +572,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
N_("print only branches of the object"), 0, parse_opt_object_name
},
OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
+ OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")),
OPT_END(),
};
@@ -641,7 +645,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
if (!sorting)
sorting = ref_default_sorting();
sorting->ignore_case = icase;
- print_ref_list(&filter, sorting);
+ print_ref_list(&filter, sorting, format);
print_columns(&output, colopts, NULL);
string_list_clear(&output, 0);
return 0;
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 4521328..5778c0a 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -225,4 +225,18 @@ test_expect_success 'sort branches, ignore case' '
)
'
+test_expect_success 'git branch --format option' '
+ cat >expect <<-\EOF &&
+ Refname is (HEAD detached from fromtag)
+ Refname is refs/heads/ambiguous
+ Refname is refs/heads/branch-one
+ Refname is refs/heads/branch-two
+ Refname is refs/heads/master
+ Refname is refs/heads/ref-to-branch
+ Refname is refs/heads/ref-to-remote
+ EOF
+ git branch --format="Refname is %(refname)" >actual &&
+ test_cmp expect actual
+'
+
test_done
--
2.10.2
^ permalink raw reply related
* Re: What's cooking in git.git (Dec 2016, #05; Mon, 19)
From: Michael Haggerty @ 2016-12-27 17:04 UTC (permalink / raw)
To: Junio C Hamano, git
In-Reply-To: <xmqq37hjmow0.fsf@gitster.mtv.corp.google.com>
On 12/20/2016 01:21 AM, Junio C Hamano wrote:
> Here are the topics that have been cooking. Commits prefixed with
> '-' are only in 'pu' (proposed updates) while commits prefixed with
> '+' are in 'next'. The ones marked with '.' do not appear in any of
> the integration branches, but I am still holding onto them.
>
> The second (rather large) batch of topics have been merged to
> 'master'. Please test and catch possible regressions early.
>
> You can find the changes described here in the integration branches
> of the repositories listed at
>
> http://git-blame.blogspot.com/p/git-public-repositories.html
>
> --------------------------------------------------
> [Graduated to "master"]
>
> [...]
> * jc/lock-report-on-error (2016-12-07) 3 commits
> (merged to 'next' on 2016-12-13 at cb6c07ee92)
> + lockfile: LOCK_REPORT_ON_ERROR
> + hold_locked_index(): align error handling with hold_lockfile_for_update()
> + wt-status: implement opportunisitc index update correctly
>
> Git 2.11 had a minor regression in "merge --ff-only" that competed
> with another process that simultanously attempted to update the
> index. We used to explain what went wrong with an error message,
> but the new code silently failed. The error message has been
> resurrected.
Sorry I didn't notice this earlier, but the `LOCK_REPORT_ON_ERROR`
constant introduced by
3f061bf "lockfile: LOCK_REPORT_ON_ERROR", 2016-12-07
sets that constant to the value 2, which is the same value set for the
existing constant `LOCK_NO_DEREF`. Both constants define bits that can
be set in the `flags` argument of `hold_lock_file_for_update()`, so one
of these values needs to be changed.
Michael
^ permalink raw reply
* Re: What's cooking in git.git (Dec 2016, #05; Mon, 19)
From: Junio C Hamano @ 2016-12-27 17:16 UTC (permalink / raw)
To: Michael Haggerty; +Cc: git
In-Reply-To: <afd95065-d076-b962-8337-b87008b9f894@alum.mit.edu>
Michael Haggerty <mhagger@alum.mit.edu> writes:
> Sorry I didn't notice this earlier, but the `LOCK_REPORT_ON_ERROR`
> constant introduced by
>
> 3f061bf "lockfile: LOCK_REPORT_ON_ERROR", 2016-12-07
>
> sets that constant to the value 2,...
Sorry I didn't notice this earlier, either. Thanks for spotting.
-- >8 --
From: Junio C Hamano <gitster@pobox.com>
Date: Tue, 27 Dec 2016 09:12:09 -0800
Subject: [PATCH] lockfile: move REPORT_ON_ERROR bit elsewhere
There was LOCK_NO_DEREF defined as 2 = 1<<1 with the same value,
which was missed due to a huge comment block. Deconflict by moving
the new one to 4 = 1<<2 for now.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
lockfile.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lockfile.h b/lockfile.h
index 16775a7d79..7b715f9e77 100644
--- a/lockfile.h
+++ b/lockfile.h
@@ -137,7 +137,7 @@ struct lock_file {
* ... this flag can be passed instead to return -1 and give the usual
* error message upon an error.
*/
-#define LOCK_REPORT_ON_ERROR 2
+#define LOCK_REPORT_ON_ERROR 4
/*
* Usually symbolic links in the destination path are resolved. This
--
2.11.0-449-gc01fa73926
^ permalink raw reply related
* Re: git-apply: warn/fail on *changed* end of line (eol) *only*?
From: Junio C Hamano @ 2016-12-27 17:27 UTC (permalink / raw)
To: Igor Djordjevic BugA; +Cc: git
In-Reply-To: <xmqqvau7cqy1.fsf@gitster.mtv.corp.google.com>
Junio C Hamano <gitster@pobox.com> writes:
> Imagine that the project wants LF line endings, i.e. it considers
> that a line with CRLF ending has an unwanted "whitespace" at the
> end. Now, you start from this source file:
>
> 1 <CRLF>
> 3 <CRLF>
> 5 <CRLF>
>
> and a patch like this comes in:
>
> 1 <CRLF>
> -3 <CRLF>
> +three <CRLF>
> 5 <CRLF>
>
> You think that "3 <CRLF>" was replaced by "three <CRLF>", and the
> claim is "the 'previous' contents already had <CRLF> ending, so the
> change is not making things worse".
To see the problem with "check existing lines", it probably is
easier to extend the above example to start from a file with one
more line, like this:
1 <CRLF>
3 <CRLF>
4 <LF>
5 <CRLF>
and extend all the example patches to remove "4 <LF>" line as well,
where they remove "3 <CRLF>", making the first example patch like
so:
1 <CRLF>
-3 <CRLF>
-4 <LF>
+three <CRLF>
5 <CRLF>
Now, if you take "three <CRLF>" to be replacing "3 <CRLF>", then you
may feel that not warning on the CRLF would be the right thing, but
there is no reason (other than the fact you, a human, understand
what 'three' means) to choose "3 <CRLF>" over "4 <LF>" as the
original. If you take "three <CRLF>" to be replacing "4 <LF>", you
would need to warn.
A totally uninteresting special case is when the original is all
<CRLF>, but in that case, as you already said in the original
message, the project wants <CRLF> and you can configure it as such.
Then <CR> in the line-end <CRLF> won't be mistaken as if it is a
whitespace character <CR> at the end of a line terminated with <LF>.
^ permalink raw reply
* Re: Making it possible to do “git push origin” instead of “git push origin <branch>”, without having to one-time prepare each branch for it
From: Stefan Monov @ 2016-12-27 17:47 UTC (permalink / raw)
To: Jacob Keller; +Cc: Git mailing list
In-Reply-To: <CA+P7+xpdKEoNY_cgY4g3bMVZe0p-2bYT4Y-3nYyd0O03iD1nZg@mail.gmail.com>
Thanks guys!
^ permalink raw reply
* [PATCH] worktree: initialize return value for submodule_uses_worktrees
From: Stefan Beller @ 2016-12-27 17:50 UTC (permalink / raw)
To: gitster, larsxschneider; +Cc: git, Stefan Beller
In-Reply-To: <7E1C7387-4F37-423F-803D-3B5690B49D40@gmail.com>
When the worktrees directory is empty, the `ret` will be returned
uninitialized. Fix it by initializing the value.
Signed-off-by: Stefan Beller <sbeller@google.com>
---
This goes on top of 1a248cf (origin/sb/submodule-embed-gitdir);
ideally to be squashed, but as it is in next already, as a separate
patch.
Thanks,
Stefan
worktree.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/worktree.c b/worktree.c
index d4606aa8cd..828fd7a0ad 100644
--- a/worktree.c
+++ b/worktree.c
@@ -387,7 +387,7 @@ int submodule_uses_worktrees(const char *path)
struct strbuf sb = STRBUF_INIT;
DIR *dir;
struct dirent *d;
- int ret;
+ int ret = 0;
struct repository_format format;
submodule_gitdir = git_pathdup_submodule(path, "%s", "");
--
2.11.0.rc2.50.g8bda6b2.dirty
^ permalink raw reply related
* Re: [PATCHv5 3/4] submodule: rename and add flags to ok_to_remove_submodule
From: Stefan Beller @ 2016-12-27 17:55 UTC (permalink / raw)
To: Junio C Hamano
Cc: git@vger.kernel.org, Brandon Williams, David Turner,
brian m. carlson, Johannes Sixt
In-Reply-To: <xmqqr34uchuq.fsf@gitster.mtv.corp.google.com>
On Mon, Dec 26, 2016 at 4:53 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Stefan Beller <sbeller@google.com> writes:
>
>> As only 0 is understood as false, rename the function to invert the
>> meaning, i.e. the return code of 0 signals the removal of the submodule
>> is fine, and other values can be used to return a more precise answer
>> what went wrong.
>
> Makes sense to rename it as that will catch all the callers that
> depend on the old semantics and name.
>
>> - if (start_command(&cp))
>> - die(_("could not run 'git status --porcelain -u --ignore-submodules=none' in submodule %s"), path);
>> + if (start_command(&cp)) {
>> + if (flags & SUBMODULE_REMOVAL_DIE_ON_ERROR)
>> + die(_("could not start 'git status in submodule '%s'"),
>> + path);
>> + ret = -1;
>> + goto out;
>> + }
>
> This new codepath that does not die will not leak anything, as
> a failed start_command() should release its argv[] and env[].
>
>> len = strbuf_read(&buf, cp.out, 1024);
>> if (len > 2)
>> - ok_to_remove = 0;
>> + ret = 1;
>
> Not a new problem but is it obvious why the comparison of "len" is
> against "2"? This may deserve a one-liner comment.
>
> Otherwise looks good to me.
I took the check "len > 2" from the other occurrence in submodule.c.
When thinking about it (and inspecting the man page for
porcelain status), I think just checking != 0 is sufficient.
So in a reroll I'll change that to just
if (len)
...
I'll look at the other occurrences and see if we can reuse code
as well.
Thanks,
Stefan
^ permalink raw reply
* Re: [PATCHv5 1/4] submodule.h: add extern keyword to functions
From: Stefan Beller @ 2016-12-27 17:59 UTC (permalink / raw)
To: Junio C Hamano
Cc: git@vger.kernel.org, Brandon Williams, David Turner,
brian m. carlson, Johannes Sixt
In-Reply-To: <xmqqinq6cgxa.fsf@gitster.mtv.corp.google.com>
On Mon, Dec 26, 2016 at 5:13 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Stefan Beller <sbeller@google.com> writes:
>
>> As the upcoming series will add a lot of functions to the submodule
>> header, let's first make the header consistent to the rest of the project
>> by adding the extern keyword to functions.
>
> This may be the right thing to do in the longer term but a patch
> like this adds a lot of unnecessary work on the integrator when
> there are _other_ topics that are in flight. I'll see how bad the
> conflicts are while merging the topic to 'pu'.
>
> Thanks.
Maybe we can roll this patch on its own,
so in case the latter patches need rerolls we still have this one and can
build on top?
Thanks,
Stefan
^ permalink raw reply
* Re: [PATCHv5 4/4] rm: absorb a submodules git dir before deletion
From: Stefan Beller @ 2016-12-27 18:17 UTC (permalink / raw)
To: Junio C Hamano
Cc: git@vger.kernel.org, Brandon Williams, David Turner,
brian m. carlson, Johannes Sixt
In-Reply-To: <xmqqmvfich2e.fsf@gitster.mtv.corp.google.com>
On Mon, Dec 26, 2016 at 5:10 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Stefan Beller <sbeller@google.com> writes:
>
>> @@ -342,6 +313,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
>> exit(0);
>> }
>>
>> + submodules_absorb_gitdir_if_needed(prefix);
>> +
>> /*
>> * If not forced, the file, the index and the HEAD (if exists)
>> * must match; but the file can already been removed, since
>> @@ -358,9 +331,6 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
>> oidclr(&oid);
>> if (check_local_mod(&oid, index_only))
>> exit(1);
>> - } else if (!index_only) {
>> - if (check_submodules_use_gitfiles())
>> - exit(1);
>> }
>>
>
> Hmph. It may be a bit strange to see an "index-only" remove to
> touch working tree, no? Yet submodules_absorb_gitdir_if_needed() is
> unconditionally called above, which feels somewhat unexpected.
I agree. In a reroll I'll protect the call with
if (!index_only)
submodules_absorb_gitdir_if_needed(prefix);
>
>> @@ -389,32 +359,20 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
>> */
>> if (!index_only) {
>> int removed = 0, gitmodules_modified = 0;
>> for (i = 0; i < list.nr; i++) {
>> const char *path = list.entry[i].name;
>> if (list.entry[i].is_submodule) {
>> + struct strbuf buf = STRBUF_INIT;
>> +
>> + strbuf_addstr(&buf, path);
>> + if (remove_dir_recursively(&buf, 0))
>> + die(_("could not remove '%s'"), path);
>> + strbuf_release(&buf);
>> +
>> + removed = 1;
>> + if (!remove_path_from_gitmodules(path))
>> + gitmodules_modified = 1;
>> + continue;
>> }
>
> I do not see any behaviour change from the original (not quoted
> here), but it is somewhat surprising that "git rm ./submodule" does
> not really check if the submodule has local modifications and files
> that are not even added before remove_dir_recursively() is called.
>
> Or perhaps I am reading the code incorrectly and such a check is
> done elsewhere?
When determining if the entry is a submodule (i.e. setting
the is_submodule bit) we have
list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
if (list.entry[list.nr++].is_submodule &&
!is_staging_gitmodules_ok())
die (_("Please stage ..."));
I think for clarity we could drop the is_submodule bit and only
and directly do
if (S_ISGITLINK(ce->ce_mode) &&
!is_staging_gitmodules_ok())
die (_("Please stage ..."));
and below (the code that you quoted) also just check via
S_ISGITLINK(ce->ce_mode)
Thanks,
Stefan
^ 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