* [PATCH 1/2] name-rev: allow passing multiple patterns using --refs
From: Jacob Keller @ 2016-12-07 2:32 UTC (permalink / raw)
To: git; +Cc: Jacob Keller
From: Jacob Keller <jacob.keller@gmail.com>
Allow git name-rev to take a string list of patterns instead of only
a single pattern. All patterns are matched inclusively, meaning that
a ref only needs to match one pattern to be included.
Add tests and documentation for this change.
Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
---
Documentation/git-name-rev.txt | 4 +++-
builtin/name-rev.c | 41 +++++++++++++++++++++++++-----------
t/t6007-rev-list-cherry-pick-file.sh | 30 ++++++++++++++++++++++++++
3 files changed, 62 insertions(+), 13 deletions(-)
diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index ca28fb8e2a07..7433627db12d 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -26,7 +26,9 @@ OPTIONS
--refs=<pattern>::
Only use refs whose names match a given shell pattern. The pattern
- can be one of branch name, tag name or fully qualified ref name.
+ can be one of branch name, tag name or fully qualified ref name. If
+ given multiple times, use refs whose names match any of the given shell
+ patterns. Use `--no-refs` to clear any previous ref patterns given.
--all::
List all commits reachable from all refs
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index cd89d48b65e8..000a2a700ed3 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -108,7 +108,7 @@ static const char *name_ref_abbrev(const char *refname, int shorten_unambiguous)
struct name_ref_data {
int tags_only;
int name_only;
- const char *ref_filter;
+ struct string_list ref_filters;
};
static struct tip_table {
@@ -150,16 +150,33 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
if (data->tags_only && !starts_with(path, "refs/tags/"))
return 0;
- if (data->ref_filter) {
- switch (subpath_matches(path, data->ref_filter)) {
- case -1: /* did not match */
- return 0;
- case 0: /* matched fully */
- break;
- default: /* matched subpath */
- can_abbreviate_output = 1;
- break;
+ if (data->ref_filters.nr) {
+ struct string_list_item *item;
+ int matched = 0;
+
+ /* See if any of the patterns match. */
+ for_each_string_list_item(item, &data->ref_filters) {
+ /*
+ * We want to check every pattern even if we already
+ * found a match, just in case one of the later
+ * patterns could abbreviate the output.
+ */
+ switch (subpath_matches(path, item->string)) {
+ case -1: /* did not match */
+ break;
+ case 0: /* matched fully */
+ matched = 1;
+ break;
+ default: /* matched subpath */
+ matched = 1;
+ can_abbreviate_output = 1;
+ break;
+ }
}
+
+ /* If none of the patterns matched, stop now */
+ if (!matched)
+ return 0;
}
add_to_tip_table(oid->hash, path, can_abbreviate_output);
@@ -306,11 +323,11 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
{
struct object_array revs = OBJECT_ARRAY_INIT;
int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
- struct name_ref_data data = { 0, 0, NULL };
+ struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP };
struct option opts[] = {
OPT_BOOL(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
- OPT_STRING(0, "refs", &data.ref_filter, N_("pattern"),
+ OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
N_("only use refs matching <pattern>")),
OPT_GROUP(""),
OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh
index 1408b608eb03..d072ec43b016 100755
--- a/t/t6007-rev-list-cherry-pick-file.sh
+++ b/t/t6007-rev-list-cherry-pick-file.sh
@@ -99,6 +99,36 @@ test_expect_success '--cherry-pick bar does not come up empty (II)' '
test_cmp actual.named expect
'
+test_expect_success 'name-rev multiple --refs combine inclusive' '
+ git rev-list --left-right --cherry-pick F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+$(git rev-list --left-right --right-only --cherry-pick F...E -- bar)
+EOF
+
+test_expect_success 'name-rev --refs excludes non-matched patterns' '
+ git rev-list --left-right --cherry-pick F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/F" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+$(git rev-list --left-right --cherry-pick F...E -- bar)
+EOF
+
+test_expect_success 'name-rev --no-refs clears the refs list' '
+ git rev-list --left-right --cherry-pick F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/F" --refs="*tags/E" --no-refs --refs="*tags/G" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
cat >expect <<EOF
+tags/F
=tags/D
--
2.11.0.rc2.152.g4d04e67
^ permalink raw reply related
* Re: git add -p with new file
From: Duy Nguyen @ 2016-12-07 9:22 UTC (permalink / raw)
To: Ariel; +Cc: Git Mailing List
In-Reply-To: <alpine.DEB.2.11.1612062012540.13185@cherryberry.dsgml.com>
On Wed, Dec 7, 2016 at 8:18 AM, Ariel <asgit@dsgml.com> wrote:
>
> If you do git add -p new_file it says:
>
> No changes.
>
> Which is a rather confusing message. I would expect it to show me the
> content of the file in patch form, in the normal way that -p works, let me
> edit it, etc.
We could improve it a bit, suggesting the user to do git add -N. But
is there a point of using -p on a new file? It will be one big chunk,
you can't split anything. Perhaps maybe you want to use 'e' to edit
what's added?
> (Note: I am aware I can do -N first, but when I specifically enter the name
> of a new file I feel it should figure out what I mean.)
--
Duy
^ permalink raw reply
* 1 files changed
From: joris @ 2016-12-07 9:46 UTC (permalink / raw)
To: git
When committing a change that touches a single file, git reports :
1 files changed, 1069 insertions(+), 1063 deletions(-)
Note the plural for the single file.
Regards,
Joris Wu
Software developer
Brisbane
^ permalink raw reply
* Re: [PATCH 01/17] mv: convert to using pathspec struct interface
From: Duy Nguyen @ 2016-12-07 10:07 UTC (permalink / raw)
To: Brandon Williams; +Cc: Git Mailing List, Stefan Beller, Junio C Hamano
In-Reply-To: <1481061106-117775-2-git-send-email-bmwill@google.com>
On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:
> Convert the 'internal_copy_pathspec()' function to use the pathspec
> struct interface from using the deprecated 'get_pathspec()' interface.
>
> In addition to this, fix a memory leak caused by only duplicating some
> of the pathspec elements. Instead always duplicate all of the the
> pathspec elements as an intermediate step (with modificationed based on
> the passed in flags). This way the intermediate strings can then be
> freed prior to duplicating the result of parse_pathspec (which contains
> each of the elements with the prefix prepended).
>
> Signed-off-by: Brandon Williams <bmwill@google.com>
> ---
> builtin/mv.c | 45 ++++++++++++++++++++++++++++++++-------------
> 1 file changed, 32 insertions(+), 13 deletions(-)
Stefan did something similar last year [1] but I couldn't find why it
did not get merged. Not sure if the reasons are still relevant or
not...
[1] http://public-inbox.org/git/%3C1438885632-26470-1-git-send-email-sbeller@google.com%3E/
> diff --git a/builtin/mv.c b/builtin/mv.c
> index 2f43877..4df4a12 100644
> --- a/builtin/mv.c
> +++ b/builtin/mv.c
> @@ -4,6 +4,7 @@
> * Copyright (C) 2006 Johannes Schindelin
> */
> #include "builtin.h"
> +#include "pathspec.h"
> #include "lockfile.h"
> #include "dir.h"
> #include "cache-tree.h"
> @@ -25,25 +26,43 @@ static const char **internal_copy_pathspec(const char *prefix,
> {
> int i;
> const char **result;
> + struct pathspec ps;
> ALLOC_ARRAY(result, count + 1);
> - COPY_ARRAY(result, pathspec, count);
> - result[count] = NULL;
> +
> + /* Create an intermediate copy of the pathspec based on the flags */
> for (i = 0; i < count; i++) {
> - int length = strlen(result[i]);
> + int length = strlen(pathspec[i]);
> int to_copy = length;
> + char *it;
> while (!(flags & KEEP_TRAILING_SLASH) &&
> - to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))
> + to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))
> to_copy--;
> - if (to_copy != length || flags & DUP_BASENAME) {
> - char *it = xmemdupz(result[i], to_copy);
> - if (flags & DUP_BASENAME) {
> - result[i] = xstrdup(basename(it));
> - free(it);
> - } else
> - result[i] = it;
> - }
> +
> + it = xmemdupz(pathspec[i], to_copy);
> + if (flags & DUP_BASENAME) {
> + result[i] = xstrdup(basename(it));
> + free(it);
> + } else
> + result[i] = it;
> + }
> + result[count] = NULL;
> +
> + parse_pathspec(&ps,
> + PATHSPEC_ALL_MAGIC &
> + ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
> + PATHSPEC_KEEP_ORDER | PATHSPEC_PREFER_CWD,
> + prefix, result);
> + assert(count == ps.nr);
> +
> + /* Copy the pathspec and free the old intermediate strings */
> + for (i = 0; i < count; i++) {
> + const char *match = xstrdup(ps.items[i].match);
> + free((char *) result[i]);
> + result[i] = match;
Sigh.. it looks so weird that we do all the parsing (in a _copy_
pathspec function) then remove struct pathspec and return the plain
string. I guess we can't do anything more until we rework cmd_mv code
to handle pathspec natively.
At the least I think we should rename this function to something else.
But if you have time I really wish we could kill this function. I
haven't stared at cmd_mv() long and hard, but it looks to me that we
combining two separate functionalities in the same function here.
If "mv" takes n arguments, then the first <n-1> arguments may be
pathspec, the last one is always a plain path. The "dest_path =
internal_copy_pathspec..." could be as simple as "dest_path =
prefix_path(argv[argc - 1])". the special treatment for this last
argument [1] can live here. Then, we can do parse_pathspec for the
<n-1> arguments in cmd_mv(). It's still far from perfect, because
cmd_mv can't handle pathspec properly, but it reduces the messy mess
in internal_copy_pathspec a bit, I hope.
[1] c57f628 (mv: let 'git mv file no-such-dir/' error out - 2013-12-03)
> }
> - return get_pathspec(prefix, result);
> +
> + clear_pathspec(&ps);
> + return result;
> }
>
> static const char *add_slash(const char *path)
> --
> 2.8.0.rc3.226.g39d4020
>
--
Duy
^ permalink raw reply
* [PATCH v2] difftool: fix dir-diff index creation when in a subdirectory
From: David Aguilar @ 2016-12-07 10:16 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git ML, Frank Becker, Johannes Schindelin, John Keeping
9ec26e7977 (difftool: fix argument handling in subdirs, 2016-07-18)
corrected how path arguments are handled in a subdirectory, but
it introduced a regression in how entries outside of the
subdirectory are handled by dir-diff.
When preparing the right-side of the diff we only include the
changed paths in the temporary area.
The left side of the diff is constructed from a temporary
index that is built from the same set of changed files, but it
was being constructed from within the subdirectory. This is a
problem because the indexed paths are toplevel-relative, and
thus they were not getting added to the index.
Teach difftool to chdir to the toplevel of the repository before
preparing its temporary indexes. This ensures that all of the
toplevel-relative paths are valid.
Add test cases to more thoroughly exercise this scenario.
Reported-by: Frank Becker <fb@mooflu.com>
Signed-off-by: David Aguilar <davvid@gmail.com>
---
Changes since v1:
- Improved commit message thanks to Johannes Schindelin
("git whatis" was used to describe the referenced commit)
- Add more tests for edge cases that are properly handled
but were not being tested.
git-difftool.perl | 4 ++++
t/t7800-difftool.sh | 44 +++++++++++++++++++++++++++++++++++++++++---
2 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/git-difftool.perl b/git-difftool.perl
index a5790d03a0..959822d5f3 100755
--- a/git-difftool.perl
+++ b/git-difftool.perl
@@ -182,6 +182,10 @@ EOF
}
}
+ # Go to the root of the worktree so that the left index files
+ # are properly setup -- the index is toplevel-relative.
+ chdir($workdir);
+
# Setup temp directories
my $tmpdir = tempdir('git-difftool.XXXXX', CLEANUP => 0, TMPDIR => 1);
my $ldir = "$tmpdir/left";
diff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh
index 70a2de461a..99d4123461 100755
--- a/t/t7800-difftool.sh
+++ b/t/t7800-difftool.sh
@@ -374,6 +374,7 @@ test_expect_success PERL 'setup change in subdirectory' '
echo master >sub/sub &&
git add sub/sub &&
git commit -m "added sub/sub" &&
+ git tag v1 &&
echo test >>file &&
echo test >>sub/sub &&
git add file sub/sub &&
@@ -409,12 +410,49 @@ run_dir_diff_test 'difftool --dir-diff ignores --prompt' '
grep file output
'
-run_dir_diff_test 'difftool --dir-diff from subdirectory' '
+run_dir_diff_test 'difftool --dir-diff branch from subdirectory' '
(
cd sub &&
git difftool --dir-diff $symlinks --extcmd ls branch >output &&
- grep sub output &&
- grep file output
+ # "sub" must only exist in "right"
+ # "file" and "file2" must be listed in both "left" and "right"
+ test "1" = $(grep sub output | wc -l) &&
+ test "2" = $(grep file"$" output | wc -l) &&
+ test "2" = $(grep file2 output | wc -l)
+ )
+'
+
+run_dir_diff_test 'difftool --dir-diff v1 from subdirectory' '
+ (
+ cd sub &&
+ git difftool --dir-diff $symlinks --extcmd ls v1 >output &&
+ # "sub" and "file" exist in both v1 and HEAD.
+ # "file2" is unchanged.
+ test "2" = $(grep sub output | wc -l) &&
+ test "2" = $(grep file output | wc -l) &&
+ test "0" = $(grep file2 output | wc -l)
+ )
+'
+
+run_dir_diff_test 'difftool --dir-diff branch from subdirectory w/ pathspec' '
+ (
+ cd sub &&
+ git difftool --dir-diff $symlinks --extcmd ls branch -- .>output &&
+ # "sub" only exists in "right"
+ # "file" and "file2" must not be listed
+ test "1" = $(grep sub output | wc -l) &&
+ test "0" = $(grep file output | wc -l)
+ )
+'
+
+run_dir_diff_test 'difftool --dir-diff v1 from subdirectory w/ pathspec' '
+ (
+ cd sub &&
+ git difftool --dir-diff $symlinks --extcmd ls v1 -- .>output &&
+ # "sub" exists in v1 and HEAD
+ # "file" is filtered out by the pathspec
+ test "2" = $(grep sub output | wc -l) &&
+ test "0" = $(grep file output | wc -l)
)
'
--
2.11.0.1.g7697df0
^ permalink raw reply related
* Re: [PATCH 02/17] dir: convert create_simplify to use the pathspec struct interface
From: Duy Nguyen @ 2016-12-07 10:17 UTC (permalink / raw)
To: Brandon Williams; +Cc: Git Mailing List, Stefan Beller, Junio C Hamano
In-Reply-To: <1481061106-117775-3-git-send-email-bmwill@google.com>
On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:
> Convert 'create_simplify()' to use the pathspec struct interface from
> using the '_raw' entry in the pathspec.
It would be even better to kill this create_simplify() and let
simplify_away() handle struct pathspec directly.
There is a bug in this code, that might have been found if we
simpify_away() handled pathspec directly: the memcmp() in
simplify_away() will not play well with :(icase) magic. My bad. If
:(icase) is used, the easiest/safe way is simplify nothing. Later on
maybe we can teach simplify_away() to do strncasecmp instead. We could
ignore exclude patterns there too (although not excluding is not a
bug).
--
Duy
^ permalink raw reply
* Re: [PATCH 03/17] dir: convert fill_directory to use the pathspec struct interface
From: Duy Nguyen @ 2016-12-07 10:24 UTC (permalink / raw)
To: Brandon Williams; +Cc: Git Mailing List, Stefan Beller, Junio C Hamano
In-Reply-To: <1481061106-117775-4-git-send-email-bmwill@google.com>
On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:
> Convert 'fill_directory()' to use the pathspec struct interface from
> using the '_raw' entry in the pathspec struct.
>
> Signed-off-by: Brandon Williams <bmwill@google.com>
> ---
> dir.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/dir.c b/dir.c
> index 7df292b..8730a4f 100644
> --- a/dir.c
> +++ b/dir.c
> @@ -188,7 +188,8 @@ int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
> len = common_prefix_len(pathspec);
>
> /* Read the directory and prune it */
> - read_directory(dir, pathspec->nr ? pathspec->_raw[0] : "", len, pathspec);
> + read_directory(dir, pathspec->nr ? pathspec->items[0].match : "",
> + len, pathspec);
Or even better, use common_prefix()'s return value here. I took me a
while to realize this code was not buggy. It is fine to just pick the
first item because the first <len> characters of _all_ pathspec items
must be the same. Something like this
prefix = common_prefix(..)
read_directory(..., prefix, strlen(prefix), pathspec);
expresses it much better. Yeah one extra mem allocation, no big deal
since fill_directory() is not called very often.
> return len;
> }
>
> --
> 2.8.0.rc3.226.g39d4020
>
--
Duy
^ permalink raw reply
* Re: [PATCH 04/17] ls-tree: convert show_recursive to use the pathspec struct interface
From: Duy Nguyen @ 2016-12-07 10:38 UTC (permalink / raw)
To: Brandon Williams; +Cc: Git Mailing List, Stefan Beller, Junio C Hamano
In-Reply-To: <1481061106-117775-5-git-send-email-bmwill@google.com>
On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:
> Convert 'show_recursive()' to use the pathspec struct interface from
> using the '_raw' entry in the pathspec struct.
Slightly off-topic (sorry, but you made me look at this code! :D),
could you update the magic_mask argument of parse_pathspec() in this
file to PATHSPEC_ALL_MAGIC & ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL)?
It makes sure all future magic will be caught as unsupported (and I
think Stefan is adding one, but understandably he did not find this
code).
I think it's in the spirit of renaming _raw to match too. By limiting
magic to fromtop and literal, we are sure match can only be path and
nothing else, which is good because this show_recursive can't handle
anything else either.
>
> Signed-off-by: Brandon Williams <bmwill@google.com>
> ---
> builtin/ls-tree.c | 12 +++++-------
> 1 file changed, 5 insertions(+), 7 deletions(-)
>
> diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
> index 0e30d86..e0f4307 100644
> --- a/builtin/ls-tree.c
> +++ b/builtin/ls-tree.c
> @@ -31,21 +31,18 @@ static const char * const ls_tree_usage[] = {
>
> static int show_recursive(const char *base, int baselen, const char *pathname)
> {
> - const char **s;
> + int i;
>
> if (ls_options & LS_RECURSIVE)
> return 1;
>
> - s = pathspec._raw;
> - if (!s)
> + if (!pathspec.nr)
> return 0;
>
> - for (;;) {
> - const char *spec = *s++;
> + for (i = 0; i < pathspec.nr; i++) {
> + const char *spec = pathspec.items[i].match;
> int len, speclen;
>
> - if (!spec)
> - return 0;
> if (strncmp(base, spec, baselen))
> continue;
> len = strlen(pathname);
> @@ -59,6 +56,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
> continue;
> return 1;
> }
> + return 0;
> }
>
> static int show_tree(const unsigned char *sha1, struct strbuf *base,
> --
> 2.8.0.rc3.226.g39d4020
>
--
Duy
^ permalink raw reply
* Re: [PATCH 09/17] pathspec: always show mnemonic and name in unsupported_magic
From: Duy Nguyen @ 2016-12-07 10:44 UTC (permalink / raw)
To: Brandon Williams; +Cc: Git Mailing List, Stefan Beller, Junio C Hamano
In-Reply-To: <1481061106-117775-10-git-send-email-bmwill@google.com>
On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:
> @@ -413,10 +411,9 @@ void parse_pathspec(struct pathspec *pathspec,
> prefixlen = prefix ? strlen(prefix) : 0;
>
> for (i = 0; i < n; i++) {
> - unsigned short_magic;
> entry = argv[i];
>
> - item[i].magic = prefix_pathspec(item + i, &short_magic,
> + item[i].magic = prefix_pathspec(item + i,
> flags,
> prefix, prefixlen, entry);
The final output looks a bit ...um.. strangely tall, with the first
two lines that have one argument each, then the last line comes with
three arguments. Maybe put 'flags' in the same line as 'item + i'?
> if ((flags & PATHSPEC_LITERAL_PATH) &&
>
--
Duy
^ permalink raw reply
* Re: [PATCH 09/17] pathspec: always show mnemonic and name in unsupported_magic
From: Duy Nguyen @ 2016-12-07 10:47 UTC (permalink / raw)
To: Brandon Williams; +Cc: Git Mailing List, Stefan Beller, Junio C Hamano
In-Reply-To: <1481061106-117775-10-git-send-email-bmwill@google.com>
On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:
> @@ -426,8 +423,7 @@ void parse_pathspec(struct pathspec *pathspec,
> nr_exclude++;
> if (item[i].magic & magic_mask)
> unsupported_magic(entry,
> - item[i].magic & magic_mask,
> - short_magic);
> + item[i].magic & magic_mask);
Same here. Maybe put both arguments in the same line. It looks a bit
better. (sorry for two mails on the same patch, I'm reading the final
output first before going through individual patches that breaks this
function down)
>
> if ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&
> has_symlink_leading_path(item[i].match, item[i].len)) {
--
Duy
^ permalink raw reply
* [ANNOUNCE] DeepGit - free cross-platform Git blame GUI with code move detection
From: Marc Strapetz @ 2016-12-07 10:26 UTC (permalink / raw)
To: git
We have just released the first version of DeepGit, a free
cross-platform tool to investigate the history of source code. It's
based on blame information and comes with a 'fuzzy' line/block move
detection.
http://www.syntevo.com/deepgit/
-Marc
^ permalink raw reply
* Re: [PATCH] git-p4: add p4 shelf support
From: Luke Diamand @ 2016-12-07 11:09 UTC (permalink / raw)
To: Nuno Subtil; +Cc: Git Users, Junio C Hamano, Vinicius Kursancew, Lars Schneider
In-Reply-To: <CALdXDfdXtc+FpePnGmE6_YDQ+8=wUZRqh4Xb65NJXUXaZnmELA@mail.gmail.com>
On 6 December 2016 at 16:12, Nuno Subtil <subtil@gmail.com> wrote:
> Yeah, it looks similar. This change can be ignored if those have already
> been accepted.
Thanks, that's appreciated!
Luke
^ permalink raw reply
* Re: 1 files changed
From: Duy Nguyen @ 2016-12-07 11:16 UTC (permalink / raw)
To: joris; +Cc: Git Mailing List
In-Reply-To: <5cfee62d-0b47-897d-0882-387de68d01fa@gmail.com>
On Wed, Dec 7, 2016 at 4:46 PM, joris <joriswu@gmail.com> wrote:
> When committing a change that touches a single file, git reports :
>
> 1 files changed, 1069 insertions(+), 1063 deletions(-)
>
> Note the plural for the single file.
What version? This should be fixed since v1.7.10, unless some new bug
pops up somewhere.
--
Duy
^ permalink raw reply
* Re: [PATCH v15 12/27] bisect--helper: `get_terms` & `bisect_terms` shell function in C
From: Pranit Bauva @ 2016-12-07 12:06 UTC (permalink / raw)
To: Stephan Beyer; +Cc: Git List
In-Reply-To: <a492fb63-3642-1f97-4668-a927352169f9@gmx.net>
Hey Stephan,
On Wed, Dec 7, 2016 at 4:35 AM, Stephan Beyer <s-beyer@gmx.net> wrote:
> Hey Pranit,
>
> On 12/06/2016 10:14 PM, Pranit Bauva wrote:
>>>> +
>>>> + if (argc == 0) {
>>>> + printf(_("Your current terms are %s for the old state\nand "
>>>> + "%s for the new state.\n"), terms->term_good,
>>>> + terms->term_bad);
>>>
>>> Very minor: It improves the readability if you'd split the string after
>>> the \n and put the "and "in the next line.
>>
>> Ah. This is because of the message. If I do the other way, then it
>> won't match the output in one of the tests in t/t6030 thus, I am
>> keeping it that way in order to avoid modifying the file t/t6030.
>
> I think I was unclear here. I was referring to the coding/layouting
> style, not to the string. I mean like writing:
>
> printf(_("Your current terms are %s for the old state\n"
> "and "%s for the new state.\n"),
> terms->term_good, terms->term_bad);
>
> The string fed to _() is the same, but it is split in a different (imho
> more readable) way: after the "\n", not after the "and ".
Thanks for clearing it out. This seems a sensible change.
>>>> + die(_("invalid argument %s for 'git bisect "
>>>> + "terms'.\nSupported options are: "
>>>> + "--term-good|--term-old and "
>>>> + "--term-bad|--term-new."), argv[i]);
>>>
>>> Hm, "return error(...)" and "die(...)" seems to be quasi-equivalent in
>>> this case. Because I am always looking from a library perspective, I'd
>>> prefer "return error(...)".
>>
>> I should use return error()
>
> When you reroll your patches, please also check if you always put _()
> around your error()s ;) (Hmmm... On the other hand, it might be arguable
> if translations are useful for errors that only occur when people hack
> git-bisect or use the bisect--helper directly... This makes me feel like
> all those errors should be prefixed by some "BUG: " marker since the
> ordinary user only sees them when there is a bug. But I don't feel in
> the position to decide or recommend such a thing, so it's just a thought.)
It is seems a good change, I will do it. Let other's comment on what
they think in the next re-roll.
Regards,
Pranit Bauva
^ permalink raw reply
* Re: [PATCH 16/17] pathspec: small readability changes
From: Duy Nguyen @ 2016-12-07 13:00 UTC (permalink / raw)
To: Brandon Williams; +Cc: Git Mailing List, Stefan Beller, Junio C Hamano
In-Reply-To: <1481061106-117775-17-git-send-email-bmwill@google.com>
On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:
> A few small changes to improve readability. This is done by grouping related
> assignments, adding blank lines, ensuring lines are <80 characters, etc.
>
> Signed-off-by: Brandon Williams <bmwill@google.com>
> ---
> pathspec.c | 15 ++++++++++-----
> 1 file changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/pathspec.c b/pathspec.c
> index 41aa213..8a07b02 100644
> --- a/pathspec.c
> +++ b/pathspec.c
> @@ -334,6 +334,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
> if ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))
> die(_("%s: 'literal' and 'glob' are incompatible"), elt);
>
> + /* Create match string which will be used for pathspec matching */
> if (pathspec_prefix >= 0) {
> match = xstrdup(copyfrom);
> prefixlen = pathspec_prefix;
> @@ -341,11 +342,16 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
> match = xstrdup(copyfrom);
> prefixlen = 0;
> } else {
> - match = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);
> + match = prefix_path_gently(prefix, prefixlen,
> + &prefixlen, copyfrom);
> if (!match)
> die(_("%s: '%s' is outside repository"), elt, copyfrom);
> }
> +
> item->match = match;
> + item->len = strlen(item->match);
> + item->prefix = prefixlen;
> +
> /*
> * Prefix the pathspec (keep all magic) and assign to
> * original. Useful for passing to another command.
> @@ -362,8 +368,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
> } else {
> item->original = xstrdup(elt);
> }
> - item->len = strlen(item->match);
> - item->prefix = prefixlen;
>
> if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)
> strip_submodule_slash_cheap(item);
> @@ -371,13 +375,14 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
> if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)
> strip_submodule_slash_expensive(item);
>
> - if (magic & PATHSPEC_LITERAL)
> + if (magic & PATHSPEC_LITERAL) {
> item->nowildcard_len = item->len;
> - else {
> + } else {
> item->nowildcard_len = simple_length(item->match);
> if (item->nowildcard_len < prefixlen)
> item->nowildcard_len = prefixlen;
> }
> +
> item->flags = 0;
You probably can move this line up with the others too.
And since you have broken this function down so nicely, it made me see
that we could do
item->magic = magic instead of returning "magic" at the end, which is
assigned to item->magic anyway by the caller.
--
Duy
^ permalink raw reply
* Re: [PATCH 11/17] pathspec: factor global magic into its own function
From: Duy Nguyen @ 2016-12-07 12:53 UTC (permalink / raw)
To: Brandon Williams; +Cc: Git Mailing List, Stefan Beller, Junio C Hamano
In-Reply-To: <1481061106-117775-12-git-send-email-bmwill@google.com>
On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:
> Create helper functions to read the global magic environment variables
> in additon to factoring out the global magic gathering logic into its
> own function.
>
> Signed-off-by: Brandon Williams <bmwill@google.com>
> ---
> pathspec.c | 120 +++++++++++++++++++++++++++++++++++++------------------------
> 1 file changed, 74 insertions(+), 46 deletions(-)
>
> diff --git a/pathspec.c b/pathspec.c
> index 5afebd3..08e76f6 100644
> --- a/pathspec.c
> +++ b/pathspec.c
> @@ -87,6 +87,74 @@ static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)
> strbuf_addf(sb, ",prefix:%d)", prefixlen);
> }
>
> +static inline int get_literal_global(void)
> +{
> + static int literal_global = -1;
> +
> + if (literal_global < 0)
> + literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT,
> + 0);
These zeros look so lonely. I know it would exceed 80 columns if we
put it on the previous line. But I think it's ok for occasional
exceptions. Or you could rename noglob_global to noglob.
--
Duy
^ permalink raw reply
* Re: [PATCH v15 23/27] bisect--helper: `bisect_replay` shell function in C
From: Christian Couder @ 2016-12-07 13:15 UTC (permalink / raw)
To: Stephan Beyer; +Cc: Pranit Bauva, Git List, Christian Couder, Lars Schneider
In-Reply-To: <58ab6600-5ac2-9e7d-7cf0-452db40d5f6b@gmx.net>
Hi Stephan,
On Wed, Dec 7, 2016 at 12:40 AM, Stephan Beyer <s-beyer@gmx.net> wrote:
> Hi Pranit and Christian and Lars ;)
>
> On 12/07/2016 12:02 AM, Pranit Bauva wrote:
>> On Tue, Nov 22, 2016 at 6:19 AM, Stephan Beyer <s-beyer@gmx.net> wrote:
>>>
>>> Now that I have a coarse overview of what you did, I have the general
>>> remark that imho the "terms" variable should simply be global instead of
>>> being passed around all the time.
>>
>> In a personal conversation with my mentors, we thought it is the best
>> fit to keep it in a struct and pass it around so that it is easier in
>> libification.
>
> I guess you had that conversation at the beginning of the project and I
> think that at that stage I would have recommended it that way, too.
>
> However, looking at the v15 bisect--helper.c, it looks like it is rather
> a pain to do it that way. I mean, you use the terms like they were
> global variables: you initialize them in cmd_bisect__helper() and then
> you always pass them around; you update them "globally", never using
> restricted scope, never ever use a second instantiation besides the one
> of cmd_bisect__helper(). These are all signs that *in the current code*
> using (static) global variables is the better way (making the code simpler).
>
> The libification argument may be worth considering, though. I am not
> sure if there is really a use-case where you need two different
> instantiations of the terms, *except* if the lib allows bisecting with
> different terms at the same time (in different repos, of course). Is the
> lib "aware" of such use-cases like doing stuff in different repos at the
> same time? If that's the case, not using global variables is the right
> thing to do. In any other case I can imagine, I'd suggest to use global
> variables.
Yeah, I wanted to avoid global variables when there is no very good
reason for them to avoid possible libification work later.
And I don't think passing one parameter around to many functions is a
big burden.
Thanks for your reviews,
Christian.
^ permalink raw reply
* Re: [PATCH 16/17] pathspec: small readability changes
From: Duy Nguyen @ 2016-12-07 13:04 UTC (permalink / raw)
To: Brandon Williams; +Cc: Git Mailing List, Stefan Beller, Junio C Hamano
In-Reply-To: <1481061106-117775-17-git-send-email-bmwill@google.com>
On Wed, Dec 7, 2016 at 4:51 AM, Brandon Williams <bmwill@google.com> wrote:
> A few small changes to improve readability. This is done by grouping related
> assignments, adding blank lines, ensuring lines are <80 characters, etc.
>
> Signed-off-by: Brandon Williams <bmwill@google.com>
> ---
> pathspec.c | 15 ++++++++++-----
> 1 file changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/pathspec.c b/pathspec.c
> index 41aa213..8a07b02 100644
> --- a/pathspec.c
> +++ b/pathspec.c
> @@ -334,6 +334,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
btw, since this function has stopped being "just prefix pathspec" for
a long time, perhaps rename it to parse_pathspec_item, or something.
--
Duy
^ permalink raw reply
* Re: [PATCH] clone,fetch: explain the shallow-clone option a little more clearly
From: Duy Nguyen @ 2016-12-07 14:07 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Alex Henrie, Git Mailing List
In-Reply-To: <xmqqshq029o7.fsf@gitster.mtv.corp.google.com>
On Wed, Dec 7, 2016 at 1:29 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Duy Nguyen <pclouds@gmail.com> writes:
>
>> On Tue, Dec 6, 2016 at 1:28 AM, Junio C Hamano <gitster@pobox.com> wrote:
>>> I however offhand do not think the feature can be used to make the
>>> repository shallower
>>
>> I'm pretty sure it can,...
>
> I wrote my message after a short local testing, but it is very
> possible I botched it and reached a wrong conclusion above.
>
> If we can use the command to make it shallower, then the phrase
> "deepen" would probably be what we need to be fixing in this patch:
>
>> OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("revision"),
>> - N_("deepen history of shallow clone by excluding rev")),
>> + N_("deepen history of shallow clone, excluding rev")),
>
> Perhaps a shorter version of:
>
> Adjust the depth of shallow clone so that commits that are
> decendants of the named rev are made available, while commits
> that are ancestors of the named rev are made beyond reach.
>
> or something like that. Here is my (somewhat botched) attempt:
>
> Adjust shallow clone's history to be cut at the rev
OK mine is "exclude the given tag from local history".
BTW the clone's string could be rephrased better because we know
there's no local history to begin with, if we stick to any verbs that
involves deepening or shortening.
--
Duy
^ permalink raw reply
* Re: BUG: "cherry-pick A..B || git reset --hard OTHER"
From: Christian Couder @ 2016-12-07 14:31 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, SZEDER Gábor
In-Reply-To: <xmqqlgvs28bh.fsf@gitster.mtv.corp.google.com>
On Tue, Dec 6, 2016 at 7:58 PM, Junio C Hamano <gitster@pobox.com> wrote:
> I was burned a few times with this in the past few years, but it did
> not irritate me often enough that I didn't write it down. But I
> think this is serious enough that deserves attention from those who
> were involved.
Yeah, I agree that we should do something about it.
> A short reproduction recipe, using objects from git.git that are
> publicly available and stable, shows how bad it is.
>
> $ git checkout v2.9.3^0
>
> $ git cherry-pick 0582a34f52..a94bb68397
> ... see conflict, decide to give up backporting to
> ... such an old fork point.
> ... the git-prompt gives "|CHERRY-PICKING" correctly.
>
> $ git reset --hard v2.10.2^0
> ... the git-prompt no longer says "|CHERRY-PICKING"
>
> $ edit && git commit -m "prelim work for backporting"
> [detached HEAD cc5a6a9219] prelim work for backporting
>
> $ git cherry-pick 0582a34f52..a94bb68397
> error: a cherry-pick or revert is already in progress
> hint: try "git cherry-pick (--continue | --quit | --abort)"
> fatal: cherry-pick failed
>
> $ git cherry-pick --abort
> ... we come back to v2.9.3^0, losing the new commit!
>
> The above shows two bugs.
>
> (1) The third invocation of "cherry-pick" with "--abort" to get rid
> of the state from the unfinished cherry-pick we did previously
> is necessary, but the command does not notice that we resetted
> to a new branch AND we even did some other work there. This
> loses end-user's work.
>
> "git cherry-pick --abort" should learn from "git am --abort"
> that has an extra safety to deal with the above workflow. The
> state from the unfinished "am" is removed, but the head is not
> rewound to avoid losing end-user's work.
>
> You can try by replacing two instances of
>
> $ git cherry-pick 0582a34f52..a94bb68397
>
> with
>
> $ git format-patch --stdout 0582a34f52..a94bb68397 | git am
>
> in the above sequence, and conclude with "git am--abort" to see
> how much more pleasant and safe "git am --abort" is.
Ok I will try to take a look at that next week.
> (2) The bug in "cherry-pick --abort" is made worse because the
> git-completion script seems to be unaware of $GIT_DIR/sequencer
> and stops saying "|CHERRY-PICKING" after the step to switch to
> a different state with "git reset --hard v2.10.2^0". If the
> prompt showed it after "git reset", the end user would have
> thought twice before starting the "prelim work".
I am not used to hacking the prompt or completion scripts, so I would
appreciate if someone else could do it.
Thanks,
Christian.
^ permalink raw reply
* [PATCH v8 02/19] ref-filter: include reference to 'used_atom' within 'atom_value'
From: Karthik Nayak @ 2016-12-07 15:36 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, jnareb, Karthik Nayak, Karthik Nayak
In-Reply-To: <20161207153627.1468-1-Karthik.188@gmail.com>
From: Karthik Nayak <karthik.188@gmail.com>
Ensure that each 'atom_value' has a reference to its corresponding
'used_atom'. This let's us use values within 'used_atom' in the
'handler' function.
Hence we can get the %(align) atom's parameters directly from the
'used_atom' therefore removing the necessity of passing %(align) atom's
parameters to 'atom_value'.
This also acts as a preparatory patch for the upcoming patch where we
introduce %(if:equals=) and %(if:notequals=).
Signed-off-by: Karthik Nayak <Karthik.188@gmail.com>
---
ref-filter.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/ref-filter.c b/ref-filter.c
index 2fed7fe..5166326 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -230,11 +230,9 @@ struct ref_formatting_state {
struct atom_value {
const char *s;
- union {
- struct align align;
- } u;
void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);
unsigned long ul; /* used for sorting when not FIELD_STR */
+ struct used_atom *atom;
};
/*
@@ -370,7 +368,7 @@ static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_s
push_stack_element(&state->stack);
new = state->stack;
new->at_end = end_align_handler;
- new->at_end_data = &atomv->u.align;
+ new->at_end_data = &atomv->atom->u.align;
}
static void if_then_else_handler(struct ref_formatting_stack **stack)
@@ -1070,6 +1068,7 @@ static void populate_value(struct ref_array_item *ref)
struct branch *branch = NULL;
v->handler = append_atom;
+ v->atom = atom;
if (*name == '*') {
deref = 1;
@@ -1134,7 +1133,6 @@ static void populate_value(struct ref_array_item *ref)
v->s = " ";
continue;
} else if (starts_with(name, "align")) {
- v->u.align = atom->u.align;
v->handler = align_atom_handler;
continue;
} else if (!strcmp(name, "end")) {
--
2.10.2
^ permalink raw reply related
* [PATCH v8 00/19] port branch.c to use ref-filter's printing options
From: Karthik Nayak @ 2016-12-07 15:36 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, jnareb, Karthik Nayak
This is part of unification of the commands 'git tag -l, git branch -l
and git for-each-ref'. This ports over branch.c to use ref-filter's
printing options.
Initially posted here: $(gmane/279226). It was decided that this series
would follow up after refactoring ref-filter parsing mechanism, which
is now merged into master (9606218b32344c5c756f7c29349d3845ef60b80c).
v1 can be found here: $(gmane/288342)
v2 can be found here: $(gmane/288863)
v3 can be found here: $(gmane/290299)
v4 can be found here: $(gmane/291106)
v5b can be found here: $(gmane/292467)
v6 can be found here: http://marc.info/?l=git&m=146330914118766&w=2
v7 can be found here: http://marc.info/?l=git&m=147863593317362&w=2
Changes in this version:
1. use an enum for holding the comparision type in
%(if:[equals/notequals=...]) options.
2. rename the 'strip' option to 'lstrip' and introduce an 'rstrip'
option. Also modify them to take negative values. This drops the
':dri' and ':base' options.
3. Drop unecessary code.
4. Cleanup code and fix spacing.
5. Add more comments wherever required.
6. Add quote_literal_for_format(const char *s) for safer string
insertions in branch.c:build_format().
Thanks to Jacob, Jackub, Junio and Matthieu for their inputs on the
previous version.
Interdiff below.
Karthik Nayak (19):
ref-filter: implement %(if), %(then), and %(else) atoms
ref-filter: include reference to 'used_atom' within 'atom_value'
ref-filter: implement %(if:equals=<string>) and
%(if:notequals=<string>)
ref-filter: modify "%(objectname:short)" to take length
ref-filter: move get_head_description() from branch.c
ref-filter: introduce format_ref_array_item()
ref-filter: make %(upstream:track) prints "[gone]" for invalid
upstreams
ref-filter: add support for %(upstream:track,nobracket)
ref-filter: make "%(symref)" atom work with the ':short' modifier
ref-filter: introduce refname_atom_parser_internal()
ref-filter: introduce refname_atom_parser()
ref-filter: make remote_ref_atom_parser() use
refname_atom_parser_internal()
ref-filter: rename the 'strip' option to 'lstrip'
ref-filter: modify the 'lstrip=<N>' option to work with negative '<N>'
ref-filter: add an 'rstrip=<N>' option to atoms which deal with
refnames
ref-filter: allow porcelain to translate messages in the output
branch, tag: use porcelain output
branch: use ref-filter printing APIs
branch: implement '--format' option
Documentation/git-branch.txt | 7 +-
Documentation/git-for-each-ref.txt | 86 +++++--
builtin/branch.c | 290 +++++++---------------
builtin/tag.c | 6 +-
ref-filter.c | 488 +++++++++++++++++++++++++++++++------
ref-filter.h | 7 +
t/t3203-branch-output.sh | 16 +-
t/t6040-tracking-info.sh | 2 +-
t/t6300-for-each-ref.sh | 88 ++++++-
t/t6302-for-each-ref-filter.sh | 94 +++++++
10 files changed, 784 insertions(+), 300 deletions(-)
Interdiff:
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index f4ad297..c72baeb 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -92,13 +92,14 @@ 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>`
- slash-separated path components from the front of the refname
- (e.g., `%(refname:strip=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. For the base
- directory of the ref (i.e. foo in refs/foo/bar/boz) append
- `:base`. For the entire directory path append `:dir`.
+ abbreviation mode. If `lstrip=<N>` or `rstrip=<N>` option can
+ be appended to strip `<N>` slash-separated path components
+ from or end 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. If a displayed ref has fewer components than
+ `<N>`, the command aborts with an error.
objecttype::
The type of the object (`blob`, `tree`, `commit`, `tag`).
@@ -113,11 +114,10 @@ objectname::
`: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''
- from the displayed ref. Respects `:short`, `:strip`, `:base`
- and `:dir` in the same way as `refname` above. Additionally
+ 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`
@@ -125,14 +125,16 @@ upstream::
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.
+ 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`, `:strip`,
- `:track`, `:trackshort`, `:base` and `:dir` options as
- `upstream` does. Produces an empty string if no `@{push}` ref
- is configured.
+ location for the displayed ref. Respects `:short`, `:lstrip`,
+ `:rstrip`, `: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), ' '
@@ -158,7 +160,7 @@ align::
quoting.
if::
- Used as %(if)...%(then)...(%end) or
+ Used as %(if)...%(then)...%(end) or
%(if)...%(then)...%(else)...%(end). If there is an atom with
value or string literal after the %(if) then everything after
the %(then) is printed, else if the %(else) atom is used, then
@@ -173,8 +175,8 @@ if::
symref::
The ref which the given symbolic ref refers to. If not a
symbolic ref, nothing is printed. Respects the `:short`,
- `:strip`, `:base` and `:dir` options in the same way as
- `refname` above.
+ `: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
@@ -214,12 +216,6 @@ values the `--date` option to linkgit:git-rev-list[1] takes).
Some atoms like %(align) and %(if) always require a matching %(end).
We call them "opening atoms" and sometimes denote them as %($open).
-When a scripting language specific quoting is in effect (i.e. one of
-`--shell`, `--perl`, `--python`, `--tcl` is used), except for opening
-atoms, replacement from every %(atom) is quoted when and only when it
-appears at the top-level (that is, when it appears outside
-%($open)...%(end)).
-
When a scripting language specific quoting is in effect, everything
between a top-level opening atom and its matching %(end) is evaluated
according to the semantics of the opening atom and its result is
diff --git a/builtin/branch.c b/builtin/branch.c
index acadb99..6393c3c 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -306,16 +306,36 @@ static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
return max;
}
+const char *quote_literal_for_format(const char *s)
+{
+ struct strbuf buf = STRBUF_INIT;
+
+ 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;
+ }
+ }
+ return buf.buf;
+}
+
static char *build_format(struct ref_filter *filter, int maxwidth, const char *remote_prefix)
{
struct strbuf fmt = STRBUF_INIT;
struct strbuf local = STRBUF_INIT;
struct strbuf remote = STRBUF_INIT;
- strbuf_addf(&fmt, "%%(if)%%(HEAD)%%(then)* %s%%(else) %%(end)", branch_get_color(BRANCH_COLOR_CURRENT));
+ strbuf_addf(&fmt, "%%(if)%%(HEAD)%%(then)* %s%%(else) %%(end)",
+ branch_get_color(BRANCH_COLOR_CURRENT));
if (filter->verbose) {
- strbuf_addf(&local, "%%(align:%d,left)%%(refname:strip=2)%%(end)", maxwidth);
+ 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) ");
@@ -326,18 +346,19 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
else
strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)");
- strbuf_addf(&remote, "%s%%(align:%d,left)%s%%(refname:strip=2)%%(end)%s%%(if)%%(symref)%%(then) -> %%(symref:short)"
+ 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,
- remote_prefix, branch_get_color(BRANCH_COLOR_RESET));
+ branch_get_color(BRANCH_COLOR_REMOTE), maxwidth, quote_literal_for_format(remote_prefix),
+ branch_get_color(BRANCH_COLOR_RESET));
} else {
- strbuf_addf(&local, "%%(refname:strip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)",
+ 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_addf(&remote, "%s%s%%(refname:strip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)",
- branch_get_color(BRANCH_COLOR_REMOTE), remote_prefix, branch_get_color(BRANCH_COLOR_RESET));
}
- strbuf_addf(&fmt, "%%(if:notequals=remotes)%%(refname:base)%%(then)%s%%(else)%s%%(end)", local.buf, remote.buf);
+ strbuf_addf(&fmt, "%%(if:notequals=refs/remotes)%%(refname:rstrip=-2)%%(then)%s%%(else)%s%%(end)", local.buf, remote.buf);
strbuf_release(&local);
strbuf_release(&remote);
@@ -682,7 +703,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
* create_branch takes care of setting up the tracking
* info and making sure new_upstream is correct
*/
- create_branch(head, branch->name, new_upstream, 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE);
+ create_branch(branch->name, new_upstream, 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE);
} else if (unset_upstream) {
struct branch *branch = branch_get(argv[0]);
struct strbuf buf = STRBUF_INIT;
@@ -728,7 +749,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
strbuf_release(&buf);
branch_existed = ref_exists(branch->refname);
- create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
+ create_branch(argv[0], (argc == 2) ? argv[1] : head,
force, reflog, 0, quiet, track);
/*
diff --git a/ref-filter.c b/ref-filter.c
index 944671a..a68ed7b 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -21,6 +21,7 @@ static struct ref_msg {
const char *behind;
const char *ahead_behind;
} msgs = {
+ /* Untranslated plumbing messages: */
"gone",
"ahead %d",
"behind %d",
@@ -36,6 +37,7 @@ void setup_ref_filter_porcelain_msg(void)
}
typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
+typedef enum { COMPARE_EQUAL, COMPARE_UNEQUAL, COMPARE_NONE } cmp_status;
struct align {
align_type position;
@@ -43,16 +45,16 @@ struct align {
};
struct if_then_else {
- const char *if_equals,
- *not_equals;
+ cmp_status cmp_status;
+ const char *str;
unsigned int then_atom_seen : 1,
else_atom_seen : 1,
condition_satisfied : 1;
};
struct refname_atom {
- enum { R_BASE, R_DIR, R_NORMAL, R_SHORT, R_STRIP } option;
- unsigned int strip;
+ enum { R_NORMAL, R_SHORT, R_LSTRIP, R_RSTRIP } option;
+ int lstrip, rstrip;
};
/*
@@ -81,8 +83,8 @@ static struct used_atom {
unsigned int nlines;
} contents;
struct {
- const char *if_equals,
- *not_equals;
+ cmp_status cmp_status;
+ const char *str;
} if_then_else;
struct {
enum { O_FULL, O_LENGTH, O_SHORT } option;
@@ -109,15 +111,15 @@ 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 (!strcmp(arg, "dir"))
- atom->option = R_DIR;
- else if (!strcmp(arg, "base"))
- atom->option = R_BASE;
- else
+ else if (skip_prefix(arg, "lstrip=", &arg)) {
+ 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);
}
@@ -204,11 +206,6 @@ static void objectname_atom_parser(struct used_atom *atom, const char *arg)
die(_("unrecognized %%(objectname) argument: %s"), arg);
}
-static void symref_atom_parser(struct used_atom *atom, const char *arg)
-{
- return refname_atom_parser_internal(&atom->u.refname, arg, atom->name);
-}
-
static void refname_atom_parser(struct used_atom *atom, const char *arg)
{
return refname_atom_parser_internal(&atom->u.refname, arg, atom->name);
@@ -266,16 +263,19 @@ static void align_atom_parser(struct used_atom *atom, const char *arg)
static void if_atom_parser(struct used_atom *atom, const char *arg)
{
- if (!arg)
+ if (!arg) {
+ atom->u.if_then_else.cmp_status = COMPARE_NONE;
return;
- else if (skip_prefix(arg, "equals=", &atom->u.if_then_else.if_equals))
- ;
- else if (skip_prefix(arg, "notequals=", &atom->u.if_then_else.not_equals))
- ;
- else
+ } else if (skip_prefix(arg, "equals=", &atom->u.if_then_else.str)) {
+ atom->u.if_then_else.cmp_status = COMPARE_EQUAL;
+ } else if (skip_prefix(arg, "notequals=", &atom->u.if_then_else.str)) {
+ atom->u.if_then_else.cmp_status = COMPARE_UNEQUAL;
+ } else {
die(_("unrecognized %%(if) argument: %s"), arg);
+ }
}
+
static struct {
const char *name;
cmp_type cmp_type;
@@ -310,7 +310,7 @@ static struct {
{ "contents", FIELD_STR, contents_atom_parser },
{ "upstream", FIELD_STR, remote_ref_atom_parser },
{ "push", FIELD_STR, remote_ref_atom_parser },
- { "symref", FIELD_STR, symref_atom_parser },
+ { "symref", FIELD_STR, refname_atom_parser },
{ "flag" },
{ "HEAD" },
{ "color", FIELD_STR, color_atom_parser },
@@ -501,12 +501,13 @@ static void if_then_else_handler(struct ref_formatting_stack **stack)
strbuf_reset(&cur->output);
pop_stack_element(&cur);
}
- } else if (!if_then_else->condition_satisfied)
+ } else if (!if_then_else->condition_satisfied) {
/*
* No %(else) atom: just drop the %(then) branch if the
* condition is not satisfied.
*/
strbuf_reset(&cur->output);
+ }
*stack = cur;
free(if_then_else);
@@ -517,8 +518,8 @@ static void if_atom_handler(struct atom_value *atomv, struct ref_formatting_stat
struct ref_formatting_stack *new;
struct if_then_else *if_then_else = xcalloc(sizeof(struct if_then_else), 1);
- if_then_else->if_equals = atomv->atom->u.if_then_else.if_equals;
- if_then_else->not_equals = atomv->atom->u.if_then_else.not_equals;
+ if_then_else->str = atomv->atom->u.if_then_else.str;
+ if_then_else->cmp_status = atomv->atom->u.if_then_else.cmp_status;
push_stack_element(&state->stack);
new = state->stack;
@@ -555,11 +556,11 @@ static void then_atom_handler(struct atom_value *atomv, struct ref_formatting_st
* perform the required comparison. If not, only non-empty
* strings satisfy the 'if' condition.
*/
- if (if_then_else->if_equals) {
- if (!strcmp(if_then_else->if_equals, cur->output.buf))
+ if (if_then_else->cmp_status == COMPARE_EQUAL) {
+ if (!strcmp(if_then_else->str, cur->output.buf))
if_then_else->condition_satisfied = 1;
- } else if (if_then_else->not_equals) {
- if (strcmp(if_then_else->not_equals, cur->output.buf))
+ } else if (if_then_else->cmp_status == COMPARE_UNEQUAL) {
+ if (strcmp(if_then_else->str, cur->output.buf))
if_then_else->condition_satisfied = 1;
} else if (cur->output.len && !is_empty(cur->output.buf))
if_then_else->condition_satisfied = 1;
@@ -1095,21 +1096,68 @@ 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, int len)
{
long remaining = len;
const char *start = 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) {
switch (*start++) {
case '\0':
- die(_("ref '%s' does not have %ud components to :strip"),
+ die(_("ref '%s' does not have %d components to :lstrip"),
refname, len);
case '/':
remaining--;
break;
}
}
+
+ 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--) {
+ char *p = strrchr(start, '/');
+ if (p == NULL)
+ die(_("ref '%s' does not have %d components to :rstrip"),
+ refname, len);
+ else
+ p[0] = '\0';
+ }
return start;
}
@@ -1117,27 +1165,11 @@ 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_BASE) {
- const char *sp, *ep;
-
- if (skip_prefix(refname, "refs/", &sp)) {
- ep = strchr(sp, '/');
- if (!ep)
- return "";
- return xstrndup(sp, ep - sp);
- }
- return "";
- } else if (atom->option == R_DIR) {
- const char *sp, *ep;
-
- sp = refname;
- ep = strrchr(sp, '/');
- if (!ep)
- return "";
- return xstrndup(sp, ep - sp);
- } else
+ 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;
}
@@ -1318,7 +1350,7 @@ static void populate_value(struct ref_array_item *ref)
head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
sha1, NULL);
- if (!strcmp(ref->refname, head))
+ if (head && !strcmp(ref->refname, head))
v->s = "*";
else
v->s = " ";
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index 8ff6568..8d75cef 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -51,20 +51,26 @@ 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:dir refs/heads
-test_atom head refname:base heads
+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:strip=2 origin/master
-test_atom head upstream:dir refs/remotes/origin
-test_atom head upstream:base remotes
+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:strip=1 remotes/myfork/master
-test_atom head push:dir refs/remotes/myfork
-test_atom head push:base remotes
+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)
@@ -147,14 +153,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 'stripping refnames too far gives an error' '
+ test_must_fail git for-each-ref --format="%(refname:lstrip=3)" &&
+ test_must_fail git for-each-ref --format="%(refname:lstrip=-4)"
'
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:rstrip=3)" &&
+ test_must_fail git for-each-ref --format="%(refname:rstrip=-4)"
'
test_expect_success 'Check format specifiers are ignored in naming date atoms' '
@@ -575,6 +581,16 @@ 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 &&
+ sed -e "s/^\* / /" actual >expect &&
+ git checkout --orphan HEAD &&
+ git for-each-ref --format="%(HEAD) %(refname:short)" refs/heads/ >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'Add symbolic ref for the following tests' '
git symbolic-ref refs/heads/sym refs/heads/master
'
@@ -584,7 +600,7 @@ refs/heads/master
EOF
test_expect_success 'Verify usage of %(symref) atom' '
- git for-each-ref --format="%(symref)" refs/heads/sym > actual &&
+ git for-each-ref --format="%(symref)" refs/heads/sym >actual &&
test_cmp expected actual
'
@@ -593,34 +609,29 @@ heads/master
EOF
test_expect_success 'Verify usage of %(symref:short) atom' '
- git for-each-ref --format="%(symref:short)" refs/heads/sym > actual &&
+ git for-each-ref --format="%(symref:short)" refs/heads/sym >actual &&
test_cmp expected actual
'
cat >expected <<EOF
master
+heads/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 &&
+ git for-each-ref --format="%(symref:lstrip=-2)" refs/heads/sym >> actual &&
test_cmp expected actual
'
cat >expected <<EOF
+refs
refs/heads
EOF
-test_expect_success 'Verify usage of %(symref:dir) atom' '
- git for-each-ref --format="%(symref:dir)" refs/heads/sym > actual &&
- test_cmp expected actual
-'
-
-cat >expected <<EOF
-heads
-EOF
-
-test_expect_success 'Verify usage of %(symref:base) atom' '
- git for-each-ref --format="%(symref:base)" refs/heads/sym > actual &&
+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
'
--
2.10.2
^ permalink raw reply related
* [PATCH v8 15/19] ref-filter: add an 'rstrip=<N>' option to atoms which deal with refnames
From: Karthik Nayak @ 2016-12-07 15:36 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, jnareb, Karthik Nayak
In-Reply-To: <20161207153627.1468-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 | 24 ++++++++++++++++++++++
3 files changed, 85 insertions(+), 20 deletions(-)
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index ad9b243..c72baeb 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -92,10 +92,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. If `lstrip=<N>` or `rstrip=<N>` option can
+ be appended to strip `<N>` slash-separated path components
+ from or end 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. If a displayed ref has fewer components than
`<N>`, the command aborts with an error.
@@ -114,22 +116,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.
@@ -171,8 +174,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 deb2b29..9fce5bb 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -32,8 +32,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;
};
/*
@@ -94,6 +94,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);
}
@@ -1105,12 +1109,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--) {
+ char *p = strrchr(start, '/');
+ if (p == NULL)
+ die(_("ref '%s' does not have %d components to :rstrip"),
+ refname, len);
+ 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 26adca8..8d75cef 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)
@@ -150,6 +158,11 @@ test_expect_success 'stripping refnames too far gives an error' '
test_must_fail git for-each-ref --format="%(refname:lstrip=-4)"
'
+test_expect_success 'stripping refnames too far gives an error' '
+ test_must_fail git for-each-ref --format="%(refname:rstrip=3)" &&
+ test_must_fail git for-each-ref --format="%(refname:rstrip=-4)"
+'
+
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 &&
@@ -611,4 +624,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 v8 10/19] ref-filter: introduce refname_atom_parser_internal()
From: Karthik Nayak @ 2016-12-07 15:36 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, jnareb, Karthik Nayak, Karthik Nayak
In-Reply-To: <20161207153627.1468-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 405a0e5..1a18c7d 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -31,6 +31,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().
@@ -63,6 +68,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;
@@ -76,6 +82,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 v8 16/19] ref-filter: allow porcelain to translate messages in the output
From: Karthik Nayak @ 2016-12-07 15:36 UTC (permalink / raw)
To: git; +Cc: jacob.keller, gitster, jnareb, Karthik Nayak
In-Reply-To: <20161207153627.1468-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 9fce5bb..a68ed7b 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -15,6 +15,27 @@
#include "version.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;
@@ -1161,15 +1182,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 0014b92..da17145 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -111,5 +111,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
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