[PATCH 1/2] Documentation/git-worktree: fix duplicated 'from'

2015-08-04 Thread Patrick Steinhardt
Signed-off-by: Patrick Steinhardt p...@pks.im
---
 Documentation/git-worktree.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 3387e2f..566ca92 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -124,7 +124,7 @@ thumb is do not make any assumption about whether a path 
belongs to
 $GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
 inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
 
-To prevent a $GIT_DIR/worktrees entry from from being pruned (which
+To prevent a $GIT_DIR/worktrees entry from being pruned (which
 can be useful in some situations, such as when the
 entry's working tree is stored on a portable device), add a file named
 'locked' to the entry's directory. The file contains the reason in
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] Documentation/git-worktree: fix reference to 'locked' file

2015-08-04 Thread Patrick Steinhardt
The documentation of git-worktree refers to the 'locked' file as
'lock'. Fix this to say 'locked' instead.

Signed-off-by: Patrick Steinhardt p...@pks.im
---
 Documentation/git-worktree.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 566ca92..3fedd9e 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -39,7 +39,7 @@ repository so that they do not get automatically pruned.
 
 If a linked working tree is stored on a portable device or network share
 which is not always mounted, you can prevent its administrative files from
-being pruned by creating a file named 'lock' alongside the other
+being pruned by creating a file named 'locked' alongside the other
 administrative files, optionally containing a plain text reason that
 pruning should be suppressed. See section DETAILS for more information.
 
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v9 05/11] ref-filter: support printing N lines from tag annotation

2015-08-04 Thread Karthik Nayak
From: Karthik Nayak karthik@gmail.com

In 'tag.c' we can print N lines from the annotation of the tag using
the '-nnum' option. Copy code from 'tag.c' to 'ref-filter' and
modify 'ref-filter' to support printing of N lines from the annotation
of tags.

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 builtin/for-each-ref.c |  2 +-
 builtin/tag.c  |  4 
 ref-filter.c   | 54 --
 ref-filter.h   |  9 +++--
 4 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 40f343b..e4a4f8a 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -74,7 +74,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char 
*prefix)
if (!maxcount || array.nr  maxcount)
maxcount = array.nr;
for (i = 0; i  maxcount; i++)
-   show_ref_array_item(array.items[i], format, quote_style);
+   show_ref_array_item(array.items[i], format, quote_style, 0);
ref_array_clear(array);
return 0;
 }
diff --git a/builtin/tag.c b/builtin/tag.c
index 471d6b1..0fc7557 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -185,6 +185,10 @@ static enum contains_result contains(struct commit 
*candidate,
return contains_test(candidate, want);
 }
 
+/*
+ * Currently duplicated in ref-filter, will eventually be removed as
+ * we port tag.c to use ref-filter APIs.
+ */
 static void show_tag_lines(const struct object_id *oid, int lines)
 {
int i;
diff --git a/ref-filter.c b/ref-filter.c
index 7c9c51d..1609b01 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1325,7 +1325,51 @@ static void apply_formatting_state(struct 
ref_formatting_state *state, struct st
strbuf_release(state-output);
 }
 
-void show_ref_array_item(struct ref_array_item *info, const char *format, int 
quote_style)
+/*
+ * If 'lines' is greater than 0, print that many lines from the given
+ * object_id 'oid'.
+ */
+static void show_tag_lines(const struct object_id *oid, int lines)
+{
+   int i;
+   unsigned long size;
+   enum object_type type;
+   char *buf, *sp, *eol;
+   size_t len;
+
+   buf = read_sha1_file(oid-hash, type, size);
+   if (!buf)
+   die_errno(unable to read object %s, oid_to_hex(oid));
+   if (type != OBJ_COMMIT  type != OBJ_TAG)
+   goto free_return;
+   if (!size)
+   die(an empty %s object %s?,
+   typename(type), oid_to_hex(oid));
+
+   /* skip header */
+   sp = strstr(buf, \n\n);
+   if (!sp)
+   goto free_return;
+
+   /* only take up to lines lines, and strip the signature from a tag */
+   if (type == OBJ_TAG)
+   size = parse_signature(buf, size);
+   for (i = 0, sp += 2; i  lines  sp  buf + size; i++) {
+   if (i)
+   printf(\n);
+   eol = memchr(sp, '\n', size - (sp - buf));
+   len = eol ? eol - sp : size - (sp - buf);
+   fwrite(sp, len, 1, stdout);
+   if (!eol)
+   break;
+   sp = eol + 1;
+   }
+free_return:
+   free(buf);
+}
+
+void show_ref_array_item(struct ref_array_item *info, const char *format,
+int quote_style, unsigned int lines)
 {
const char *cp, *sp, *ep;
struct strbuf value = STRBUF_INIT;
@@ -1377,8 +1421,14 @@ void show_ref_array_item(struct ref_array_item *info, 
const char *format, int qu
 
for (i = 0; i  final_buf.len; i++)
printf(%c, final_buf.buf[i]);
-   putchar('\n');
strbuf_release(final_buf);
+
+   if (lines  0) {
+   struct object_id oid;
+   hashcpy(oid.hash, info-objectname);
+   show_tag_lines(oid, lines);
+   }
+   putchar('\n');
 }
 
 /*  If no sorting option is given, use refname to sort as default */
diff --git a/ref-filter.h b/ref-filter.h
index 3412dce..2f571ed 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -74,6 +74,7 @@ struct ref_filter {
struct commit *merge_commit;
 
unsigned int with_commit_tag_algo : 1;
+   unsigned int lines;
 };
 
 struct ref_filter_cbdata {
@@ -105,8 +106,12 @@ 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);
-/*  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);
+/*
+ * Print the ref using the given format and quote_style. If 'lines'  0,
+ * print that many lines of the the given ref.
+ */
+void show_ref_array_item(struct ref_array_item *info, 

[PATCH v9 02/11] ref-filter: introduce ref_formatting_state

2015-08-04 Thread Karthik Nayak
Introduce a ref_formatting_state which will eventually hold the values
of modifier atoms. Implement this within ref-filter.

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 ref-filter.c | 64 +---
 ref-filter.h |  5 +
 2 files changed, 49 insertions(+), 20 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 91482c9..2c074a1 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1190,23 +1190,23 @@ void ref_array_sort(struct ref_sorting *sorting, struct 
ref_array *array)
qsort(array-items, array-nr, sizeof(struct ref_array_item *), 
compare_refs);
 }
 
-static void print_value(struct atom_value *v, int quote_style, struct strbuf 
*output)
+static void print_value(struct atom_value *v, struct ref_formatting_state 
*state)
 {
-   switch (quote_style) {
+   switch (state-quote_style) {
case QUOTE_NONE:
-   strbuf_addstr(output, v-s);
+   strbuf_addstr(state-output, v-s);
break;
case QUOTE_SHELL:
-   sq_quote_buf(output, v-s);
+   sq_quote_buf(state-output, v-s);
break;
case QUOTE_PERL:
-   perl_quote_buf(output, v-s);
+   perl_quote_buf(state-output, v-s);
break;
case QUOTE_PYTHON:
-   python_quote_buf(output, v-s);
+   python_quote_buf(state-output, v-s);
break;
case QUOTE_TCL:
-   tcl_quote_buf(output, v-s);
+   tcl_quote_buf(state-output, v-s);
break;
}
 }
@@ -1229,7 +1229,7 @@ static int hex2(const char *cp)
return -1;
 }
 
-static void emit(const char *cp, const char *ep, struct strbuf *output)
+static void emit(const char *cp, const char *ep, struct ref_formatting_state 
*state)
 {
while (*cp  (!ep || cp  ep)) {
if (*cp == '%') {
@@ -1238,35 +1238,58 @@ static void emit(const char *cp, const char *ep, struct 
strbuf *output)
else {
int ch = hex2(cp + 1);
if (0 = ch) {
-   strbuf_addch(output, ch);
+   strbuf_addch(state-output, ch);
cp += 3;
continue;
}
}
}
-   strbuf_addch(output, *cp);
+   strbuf_addch(state-output, *cp);
cp++;
}
 }
 
+static void process_formatting_state(struct atom_value *atomv, struct 
ref_formatting_state *state)
+{
+   /* Based on the atomv values, the formatting state is set */
+}
+
+static void apply_formatting_state(struct ref_formatting_state *state, struct 
strbuf *final)
+{
+   /* More formatting options to be evetually added */
+   strbuf_addbuf(final, state-output);
+   strbuf_release(state-output);
+}
+
 void show_ref_array_item(struct ref_array_item *info, const char *format, int 
quote_style)
 {
const char *cp, *sp, *ep;
-   struct strbuf output = STRBUF_INIT;
+   struct strbuf value = STRBUF_INIT;
+   struct strbuf final_buf = STRBUF_INIT;
+   struct ref_formatting_state state;
int i;
 
+   memset(state, 0, sizeof(state));
+   state.quote_style = quote_style;
+   state.output = value;
+
for (cp = format; *cp  (sp = find_next(cp)); cp = ep + 1) {
-   struct atom_value *atomv;
+   struct atom_value *atomv = NULL;
 
ep = strchr(sp, ')');
-   if (cp  sp)
-   emit(cp, sp, output);
+   if (cp  sp) {
+   emit(cp, sp, state);
+   apply_formatting_state(state, final_buf);
+   }
get_ref_atom_value(info, parse_ref_filter_atom(sp + 2, ep), 
atomv);
-   print_value(atomv, quote_style, output);
+   process_formatting_state(atomv, state);
+   print_value(atomv, state);
+   apply_formatting_state(state, final_buf);
}
if (*cp) {
sp = cp + strlen(cp);
-   emit(cp, sp, output);
+   emit(cp, sp, state);
+   apply_formatting_state(state, final_buf);
}
if (need_color_reset_at_eol) {
struct atom_value resetv;
@@ -1275,12 +1298,13 @@ void show_ref_array_item(struct ref_array_item *info, 
const char *format, int qu
if (color_parse(reset, color)  0)
die(BUG: couldn't parse 'reset' as a color);
resetv.s = color;
-   print_value(resetv, quote_style, output);
+   print_value(resetv, state);
+   

[PATCH v9 10/11] tag.c: implement '--format' option

2015-08-04 Thread Karthik Nayak
From: Karthik Nayak karthik@gmail.com

Implement the '--format' option provided by 'ref-filter'.
This lets the user list tags 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.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 Documentation/git-tag.txt | 15 ++-
 builtin/tag.c | 11 +++
 t/t7004-tag.sh| 16 
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 3ac4a96..75703c5 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -13,7 +13,8 @@ SYNOPSIS
tagname [commit | object]
 'git tag' -d tagname...
 'git tag' [-n[num]] -l [--contains commit] [--points-at object]
-   [--column[=options] | --no-column] [--create-reflog] [--sort=key] 
[pattern...]
+   [--column[=options] | --no-column] [--create-reflog] [--sort=key]
+   [--format=format] [pattern...]
 'git tag' -v tagname...
 
 DESCRIPTION
@@ -158,6 +159,18 @@ This option is only applicable when listing tags without 
annotation lines.
The object that the new tag will refer to, usually a commit.
Defaults to HEAD.
 
+format::
+   A string that interpolates `%(fieldname)` from the object
+   pointed at by a ref being shown.  If `fieldname` is prefixed
+   with an asterisk (`*`) and the ref points at a tag object, the
+   value for the field in the object tag refers is used.  When
+   unspecified, defaults to `%(refname:short)`.  It also
+   interpolates `%%` to `%`, and `%xx` where `xx` are hex digits
+   interpolates to character with hex code `xx`; for example
+   `%00` interpolates to `\0` (NUL), `%09` to `\t` (TAB) and
+   `%0a` to `\n` (LF).  The fields are same as those in `git
+   for-each-ref`.
+
 
 CONFIGURATION
 -
diff --git a/builtin/tag.c b/builtin/tag.c
index 829af6f..13c9579 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -30,10 +30,9 @@ static const char * const git_tag_usage[] = {
 
 static unsigned int colopts;
 
-static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting)
+static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, 
const char *format)
 {
struct ref_array array;
-   char *format;
int i;
 
memset(array, 0, sizeof(array));
@@ -43,7 +42,7 @@ static int list_tags(struct ref_filter *filter, struct 
ref_sorting *sorting)
 
if (filter-lines)
format = %(align:left,16)%(refname:short);
-   else
+   else if (!format)
format = %(refname:short);
 
verify_ref_format(format);
@@ -327,6 +326,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
struct strbuf err = STRBUF_INIT;
struct ref_filter filter;
static struct ref_sorting *sorting = NULL, **sorting_tail = sorting;
+   const char *format = NULL;
struct option options[] = {
OPT_CMDMODE('l', list, cmdmode, N_(list tag names), 'l'),
{ OPTION_INTEGER, 'n', NULL, filter.lines, N_(n),
@@ -359,6 +359,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPTION_CALLBACK, 0, points-at, filter.points_at, 
N_(object),
N_(print only tags of the object), 0, 
parse_opt_object_name
},
+   OPT_STRING(  0 , format, format, N_(format), N_(format to 
use for the output)),
OPT_END()
};
 
@@ -398,8 +399,10 @@ int cmd_tag(int argc, const char **argv, const char 
*prefix)
copts.padding = 2;
run_column_filter(colopts, copts);
}
+   if (format  (filter.lines != -1))
+   die(_(--format and -n are incompatible));
filter.name_patterns = argv;
-   ret = list_tags(filter, sorting);
+   ret = list_tags(filter, sorting, format);
if (column_active(colopts))
stop_column_filter();
return ret;
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 1f066aa..1809011 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -1519,4 +1519,20 @@ EOF
test_cmp expect actual
 '
 
+test_expect_success '--format cannot be used with -n' '
+   test_must_fail git tag -l -n4 --format=%(refname)
+'
+
+test_expect_success '--format should list tags as per format given' '
+   cat expect -\EOF 
+   refname : refs/tags/foo1.10
+   refname : refs/tags/foo1.3
+   refname : refs/tags/foo1.6
+   refname : refs/tags/foo1.6-rc1
+   refname : refs/tags/foo1.6-rc2
+   EOF
+   git tag -l --format=refname : %(refname) foo* actual 
+   test_cmp expect actual
+'
+
 test_done
-- 
2.5.0

--
To 

[PATCH v9 08/11] tag.c: use 'ref-filter' data structures

2015-08-04 Thread Karthik Nayak
From: Karthik Nayak karthik@gmail.com

Make 'tag.c' use 'ref-filter' data structures and make changes to
support the new data structures. This is a part of the process
of porting 'tag.c' to use 'ref-filter' APIs.

This is a temporary step before porting 'tag.c' to use 'ref-filter'
completely. As this is a temporary step, most of the code
introduced here will be removed when 'tag.c' is ported over to use
'ref-filter' APIs

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 builtin/tag.c | 106 +++---
 1 file changed, 57 insertions(+), 49 deletions(-)

diff --git a/builtin/tag.c b/builtin/tag.c
index 0fc7557..e96bae2 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -17,6 +17,7 @@
 #include gpg-interface.h
 #include sha1-array.h
 #include column.h
+#include ref-filter.h
 
 static const char * const git_tag_usage[] = {
N_(git tag [-a | -s | -u key-id] [-f] [-m msg | -F file] 
tagname [head]),
@@ -34,15 +35,6 @@ static const char * const git_tag_usage[] = {
 
 static int tag_sort;
 
-struct tag_filter {
-   const char **patterns;
-   int lines;
-   int sort;
-   struct string_list tags;
-   struct commit_list *with_commit;
-};
-
-static struct sha1_array points_at;
 static unsigned int colopts;
 
 static int match_pattern(const char **patterns, const char *ref)
@@ -61,19 +53,20 @@ static int match_pattern(const char **patterns, const char 
*ref)
  * removed as we port tag.c to use the ref-filter APIs.
  */
 static const unsigned char *match_points_at(const char *refname,
-   const unsigned char *sha1)
+   const unsigned char *sha1,
+   struct sha1_array *points_at)
 {
const unsigned char *tagged_sha1 = NULL;
struct object *obj;
 
-   if (sha1_array_lookup(points_at, sha1) = 0)
+   if (sha1_array_lookup(points_at, sha1) = 0)
return sha1;
obj = parse_object(sha1);
if (!obj)
die(_(malformed object at '%s'), refname);
if (obj-type == OBJ_TAG)
tagged_sha1 = ((struct tag *)obj)-tagged-sha1;
-   if (tagged_sha1  sha1_array_lookup(points_at, tagged_sha1) = 0)
+   if (tagged_sha1  sha1_array_lookup(points_at, tagged_sha1) = 0)
return tagged_sha1;
return NULL;
 }
@@ -228,12 +221,24 @@ free_return:
free(buf);
 }
 
+static void ref_array_append(struct ref_array *array, const char *refname)
+{
+   size_t len = strlen(refname);
+   struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + 
len + 1);
+   memcpy(ref-refname, refname, len);
+   ref-refname[len] = '\0';
+   REALLOC_ARRAY(array-items, array-nr + 1);
+   array-items[array-nr++] = ref;
+}
+
 static int show_reference(const char *refname, const struct object_id *oid,
  int flag, void *cb_data)
 {
-   struct tag_filter *filter = cb_data;
+   struct ref_filter_cbdata *data = cb_data;
+   struct ref_array *array = data-array;
+   struct ref_filter *filter = data-filter;
 
-   if (match_pattern(filter-patterns, refname)) {
+   if (match_pattern(filter-name_patterns, refname)) {
if (filter-with_commit) {
struct commit *commit;
 
@@ -244,12 +249,12 @@ static int show_reference(const char *refname, const 
struct object_id *oid,
return 0;
}
 
-   if (points_at.nr  !match_points_at(refname, oid-hash))
+   if (filter-points_at.nr  !match_points_at(refname, 
oid-hash, filter-points_at))
return 0;
 
if (!filter-lines) {
-   if (filter-sort)
-   string_list_append(filter-tags, refname);
+   if (tag_sort)
+   ref_array_append(array, refname);
else
printf(%s\n, refname);
return 0;
@@ -264,36 +269,36 @@ static int show_reference(const char *refname, const 
struct object_id *oid,
 
 static int sort_by_version(const void *a_, const void *b_)
 {
-   const struct string_list_item *a = a_;
-   const struct string_list_item *b = b_;
-   return versioncmp(a-string, b-string);
+   const struct ref_array_item *a = *((struct ref_array_item **)a_);
+   const struct ref_array_item *b = *((struct ref_array_item **)b_);
+   return versioncmp(a-refname, b-refname);
 }
 
-static int list_tags(const char **patterns, int lines,
-struct commit_list *with_commit, int sort)
+static int list_tags(struct ref_filter *filter, int sort)
 {
-   struct tag_filter filter;
+   struct ref_array array;
+

[PATCH v9 06/11] ref-filter: add support to sort by version

2015-08-04 Thread Karthik Nayak
From: Karthik Nayak karthik@gmail.com

Add support to sort by version using the v:refname and
version:refname option. This is achieved by using the 'versioncmp()'
function as the comparing function for qsort.

This option is included to support sorting by versions in `git tag -l`
which will eventaully be ported to use ref-filter APIs.

Add documentation and tests for the same.

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 Documentation/git-for-each-ref.txt |  3 +++
 ref-filter.c   | 15 ++-
 ref-filter.h   |  3 ++-
 t/t6302-for-each-ref-filter.sh | 36 
 4 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-for-each-ref.txt 
b/Documentation/git-for-each-ref.txt
index d865f98..6b6eb93 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -153,6 +153,9 @@ For sorting purposes, fields with numeric values sort in 
numeric
 order (`objectsize`, `authordate`, `committerdate`, `taggerdate`).
 All other fields are used to sort in their byte-value order.
 
+There is also an option to sort by versions, this can be done by using
+the fieldname `version:refname` or its alias `v:refname`.
+
 In any case, a field name that refers to a field inapplicable to
 the object referred by the ref does not cause an error.  It
 returns an empty string instead.
diff --git a/ref-filter.c b/ref-filter.c
index 1609b01..d244a81 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -11,6 +11,8 @@
 #include ref-filter.h
 #include revision.h
 #include utf8.h
+#include git-compat-util.h
+#include version.h
 
 typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
 
@@ -1181,19 +1183,19 @@ static int cmp_ref_sorting(struct ref_sorting *s, 
struct ref_array_item *a, stru
 
get_ref_atom_value(a, s-atom, va);
get_ref_atom_value(b, s-atom, vb);
-   switch (cmp_type) {
-   case FIELD_STR:
+   if (s-version)
+   cmp = versioncmp(va-s, vb-s);
+   else if (cmp_type == FIELD_STR)
cmp = strcmp(va-s, vb-s);
-   break;
-   default:
+   else {
if (va-ul  vb-ul)
cmp = -1;
else if (va-ul == vb-ul)
cmp = 0;
else
cmp = 1;
-   break;
}
+
return (s-reverse) ? -cmp : cmp;
 }
 
@@ -1460,6 +1462,9 @@ int parse_opt_ref_sorting(const struct option *opt, const 
char *arg, int unset)
s-reverse = 1;
arg++;
}
+   if (skip_prefix(arg, version:, arg) ||
+   skip_prefix(arg, v:, arg))
+   s-version = 1;
len = strlen(arg);
s-atom = parse_ref_filter_atom(arg, arg+len);
return 0;
diff --git a/ref-filter.h b/ref-filter.h
index 2f571ed..449b0d9 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -44,7 +44,8 @@ struct atom_value {
 struct ref_sorting {
struct ref_sorting *next;
int atom; /* index into used_atom array (internal) */
-   unsigned reverse : 1;
+   unsigned reverse : 1,
+   version : 1;
 };
 
 struct ref_array_item {
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index 76041a2..272a7e4 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -129,4 +129,40 @@ test_expect_success 'right alignment' '
test_cmp expect actual
 '
 
+test_expect_success 'setup for version sort' '
+   test_commit foo1.3 
+   test_commit foo1.6 
+   test_commit foo1.10
+'
+
+test_expect_success 'version sort' '
+   git for-each-ref --sort=version:refname --format=%(refname:short) 
refs/tags/ | grep foo actual 
+   cat expect -\EOF 
+   foo1.3
+   foo1.6
+   foo1.10
+   EOF
+   test_cmp expect actual
+'
+
+test_expect_success 'version sort (shortened)' '
+   git for-each-ref --sort=v:refname --format=%(refname:short) 
refs/tags/ | grep foo actual 
+   cat expect -\EOF 
+   foo1.3
+   foo1.6
+   foo1.10
+   EOF
+   test_cmp expect actual
+'
+
+test_expect_success 'reverse version sort' '
+   git for-each-ref --sort=-version:refname --format=%(refname:short) 
refs/tags/ | grep foo actual 
+   cat expect -\EOF 
+   foo1.10
+   foo1.6
+   foo1.3
+   EOF
+   test_cmp expect actual
+'
+
 test_done
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v9 07/11] ref-filter: add option to match literal pattern

2015-08-04 Thread Karthik Nayak
From: Karthik Nayak karthik@gmail.com

Since 'ref-filter' only has an option to match path names add an
option for plain fnmatch pattern-matching.

This is to support the pattern matching options which are used in `git
tag -l` and `git branch -l` where we can match patterns like `git tag
-l foo*` which would match all tags which has a foo* pattern.

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 builtin/for-each-ref.c |  1 +
 ref-filter.c   | 39 ---
 ref-filter.h   |  3 ++-
 3 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index e4a4f8a..3ad6a64 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -68,6 +68,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char 
*prefix)
git_config(git_default_config, NULL);
 
filter.name_patterns = argv;
+   filter.match_as_path = 1;
filter_refs(array, filter, FILTER_REFS_ALL | 
FILTER_REFS_INCLUDE_BROKEN);
ref_array_sort(sorting, array);
 
diff --git a/ref-filter.c b/ref-filter.c
index d244a81..de84dd4 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -956,9 +956,32 @@ static int commit_contains(struct ref_filter *filter, 
struct commit *commit)
 
 /*
  * Return 1 if the refname matches one of the patterns, otherwise 0.
+ * A pattern can be a literal prefix (e.g. a refname refs/heads/master
+ * matches a pattern refs/heads/mas) or a wildcard (e.g. the same ref
+ * matches refs/heads/mas*, too).
+ */
+static int match_pattern(const char **patterns, const char *refname)
+{
+   /*
+* When no '--format' option is given we need to skip the prefix
+* for matching refs of tags and branches.
+*/
+   (void)(skip_prefix(refname, refs/tags/, refname) ||
+  skip_prefix(refname, refs/heads/, refname) ||
+  skip_prefix(refname, refs/remotes/, refname));
+
+   for (; *patterns; patterns++) {
+   if (!wildmatch(*patterns, refname, 0, NULL))
+   return 1;
+   }
+   return 0;
+}
+
+/*
+ * Return 1 if the refname matches one of the patterns, otherwise 0.
  * A pattern can be path prefix (e.g. a refname refs/heads/master
- * matches a pattern refs/heads/) or a wildcard (e.g. the same ref
- * matches refs/heads/m*,too).
+ * matches a pattern refs/heads/ but not refs/heads/m) or a
+ * wildcard (e.g. the same ref matches refs/heads/m*, too).
  */
 static int match_name_as_path(const char **pattern, const char *refname)
 {
@@ -979,6 +1002,16 @@ static int match_name_as_path(const char **pattern, const 
char *refname)
return 0;
 }
 
+/* Return 1 if the refname matches one of the patterns, otherwise 0. */
+static int filter_pattern_match(struct ref_filter *filter, const char *refname)
+{
+   if (!*filter-name_patterns)
+   return 1; /* No pattern always matches */
+   if (filter-match_as_path)
+   return match_name_as_path(filter-name_patterns, refname);
+   return match_pattern(filter-name_patterns, refname);
+}
+
 /*
  * Given a ref (sha1, refname), check if the ref belongs to the array
  * of sha1s. If the given ref is a tag, check if the given tag points
@@ -1047,7 +1080,7 @@ static int ref_filter_handler(const char *refname, const 
struct object_id *oid,
return 0;
}
 
-   if (*filter-name_patterns  
!match_name_as_path(filter-name_patterns, refname))
+   if (!filter_pattern_match(filter, refname))
return 0;
 
if (filter-points_at.nr  !match_points_at(filter-points_at, 
oid-hash, refname))
diff --git a/ref-filter.h b/ref-filter.h
index 449b0d9..5be3e35 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -74,7 +74,8 @@ struct ref_filter {
} merge;
struct commit *merge_commit;
 
-   unsigned int with_commit_tag_algo : 1;
+   unsigned int with_commit_tag_algo : 1,
+   match_as_path : 1;
unsigned int lines;
 };
 
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v9 09/11] tag.c: use 'ref-filter' APIs

2015-08-04 Thread Karthik Nayak
From: Karthik Nayak karthik@gmail.com

Make 'tag.c' use 'ref-filter' APIs for iterating through refs, sorting
and printing of refs. This removes most of the code used in 'tag.c'
replacing it with calls to the 'ref-filter' library.

Make 'tag.c' use the 'filter_refs()' function provided by 'ref-filter'
to filter out tags based on the options set.

For printing tags we use 'show_ref_array_item()' function provided by
'ref-filter'.

We improve the sorting option provided by 'tag.c' by using the sorting
options provided by 'ref-filter'. This causes the test 'invalid sort
parameter on command line' in t7004 to fail, as 'ref-filter' throws an
error for all sorting fields which are incorrect. The test is changed
to reflect the same.

Modify documentation for the same.

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 Documentation/git-tag.txt |  16 ++-
 builtin/tag.c | 342 ++
 t/t7004-tag.sh|   8 +-
 3 files changed, 50 insertions(+), 316 deletions(-)

diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 84f6496..3ac4a96 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -13,7 +13,7 @@ SYNOPSIS
tagname [commit | object]
 'git tag' -d tagname...
 'git tag' [-n[num]] -l [--contains commit] [--points-at object]
-   [--column[=options] | --no-column] [--create-reflog] [pattern...]
+   [--column[=options] | --no-column] [--create-reflog] [--sort=key] 
[pattern...]
 'git tag' -v tagname...
 
 DESCRIPTION
@@ -94,14 +94,16 @@ OPTIONS
using fnmatch(3)).  Multiple patterns may be given; if any of
them matches, the tag is shown.
 
---sort=type::
-   Sort in a specific order. Supported type is refname
-   (lexicographic order), version:refname or v:refname (tag
+--sort=key::
+   Sort based on the key given.  Prefix `-` to sort in
+   descending order of the value. You may use the --sort=key option
+   multiple times, in which case the last key becomes the primary
+   key. Also supports version:refname or v:refname (tag
names are treated as versions). The version:refname sort
order can also be affected by the
-   versionsort.prereleaseSuffix configuration variable. Prepend
-   - to reverse sort order. When this option is not given, the
-   sort order defaults to the value configured for the 'tag.sort'
+   versionsort.prereleaseSuffix configuration variable.
+   The keys supported are the same as those in `git for-each-ref`.
+   Sort order defaults to the value configured for the 'tag.sort'
variable if it exists, or lexicographic order otherwise. See
linkgit:git-config[1].
 
diff --git a/builtin/tag.c b/builtin/tag.c
index e96bae2..829af6f 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -28,278 +28,32 @@ static const char * const git_tag_usage[] = {
NULL
 };
 
-#define STRCMP_SORT 0  /* must be zero */
-#define VERCMP_SORT 1
-#define SORT_MASK   0x7fff
-#define REVERSE_SORT0x8000
-
-static int tag_sort;
-
 static unsigned int colopts;
 
-static int match_pattern(const char **patterns, const char *ref)
-{
-   /* no pattern means match everything */
-   if (!*patterns)
-   return 1;
-   for (; *patterns; patterns++)
-   if (!wildmatch(*patterns, ref, 0, NULL))
-   return 1;
-   return 0;
-}
-
-/*
- * This is currently duplicated in ref-filter.c, and will eventually be
- * removed as we port tag.c to use the ref-filter APIs.
- */
-static const unsigned char *match_points_at(const char *refname,
-   const unsigned char *sha1,
-   struct sha1_array *points_at)
-{
-   const unsigned char *tagged_sha1 = NULL;
-   struct object *obj;
-
-   if (sha1_array_lookup(points_at, sha1) = 0)
-   return sha1;
-   obj = parse_object(sha1);
-   if (!obj)
-   die(_(malformed object at '%s'), refname);
-   if (obj-type == OBJ_TAG)
-   tagged_sha1 = ((struct tag *)obj)-tagged-sha1;
-   if (tagged_sha1  sha1_array_lookup(points_at, tagged_sha1) = 0)
-   return tagged_sha1;
-   return NULL;
-}
-
-static int in_commit_list(const struct commit_list *want, struct commit *c)
-{
-   for (; want; want = want-next)
-   if (!hashcmp(want-item-object.sha1, c-object.sha1))
-   return 1;
-   return 0;
-}
-
-/*
- * The entire code segment for supporting the --contains option has been
- * copied over to ref-filter.{c,h}. This will be deleted evetually when
- * we port tag.c to use ref-filter APIs.
- */
-enum contains_result {
-   CONTAINS_UNKNOWN = -1,
-   CONTAINS_NO = 0,
-   CONTAINS_YES = 1
-};
-
-/*
- * Test whether the 

[PATCH v9 11/11] tag.c: implement '--merged' and '--no-merged' options

2015-08-04 Thread Karthik Nayak
From: Karthik Nayak karthik@gmail.com

Using 'ref-filter' APIs implement the '--merged' and '--no-merged'
options into 'tag.c'. The '--merged' option lets the user to only
list tags merged into the named commit. The '--no-merged' option
lets the user to only list tags not merged into the named commit.
If no object is provided it assumes HEAD as the object.

Add documentation and tests for the same.

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 Documentation/git-tag.txt |  7 ++-
 builtin/tag.c |  6 +-
 t/t7004-tag.sh| 27 +++
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 75703c5..c2785d9 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -14,7 +14,7 @@ SYNOPSIS
 'git tag' -d tagname...
 'git tag' [-n[num]] -l [--contains commit] [--points-at object]
[--column[=options] | --no-column] [--create-reflog] [--sort=key]
-   [--format=format] [pattern...]
+   [--format=format] [--[no-]merged [commit]] [pattern...]
 'git tag' -v tagname...
 
 DESCRIPTION
@@ -171,6 +171,11 @@ This option is only applicable when listing tags without 
annotation lines.
`%0a` to `\n` (LF).  The fields are same as those in `git
for-each-ref`.
 
+--[no-]merged [commit]::
+   Only list tags whose tips are reachable, or not reachable
+   if '--no-merged' is used, from the specified commit ('HEAD'
+   if not specified).
+
 
 CONFIGURATION
 -
diff --git a/builtin/tag.c b/builtin/tag.c
index 13c9579..529b29f 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -23,7 +23,7 @@ static const char * const git_tag_usage[] = {
N_(git tag [-a | -s | -u key-id] [-f] [-m msg | -F file] 
tagname [head]),
N_(git tag -d tagname...),
N_(git tag -l [-n[num]] [--contains commit] [--points-at object]
-   \n\t\t[pattern...]),
+   \n\t\t[--[no-]merged [commit]] [pattern...]),
N_(git tag -v tagname...),
NULL
 };
@@ -353,6 +353,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
OPT_COLUMN(0, column, colopts, N_(show tag list in 
columns)),
OPT_CONTAINS(filter.with_commit, N_(print only tags that 
contain the commit)),
OPT_WITH(filter.with_commit, N_(print only tags that contain 
the commit)),
+   OPT_MERGED(filter, N_(print only tags that are merged)),
+   OPT_NO_MERGED(filter, N_(print only tags that are not 
merged)),
OPT_CALLBACK(0 , sort, sorting_tail, N_(key),
 N_(field name to sort on), 
parse_opt_ref_sorting),
{
@@ -413,6 +415,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
die(_(--contains option is only allowed with -l.));
if (filter.points_at.nr)
die(_(--points-at option is only allowed with -l.));
+   if (filter.merge_commit)
+   die(_(--merged and --no-merged option are only allowed with 
-l));
if (cmdmode == 'd')
return for_each_tag_name(argv, delete_tag);
if (cmdmode == 'v')
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 1809011..5b73539 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -1535,4 +1535,31 @@ test_expect_success '--format should list tags as per 
format given' '
test_cmp expect actual
 '
 
+test_expect_success 'setup --merged test tags' '
+   git tag mergetest-1 HEAD~2 
+   git tag mergetest-2 HEAD~1 
+   git tag mergetest-3 HEAD
+'
+
+test_expect_success '--merged cannot be used in non-list mode' '
+   test_must_fail git tag --merged=mergetest-2 foo
+'
+
+test_expect_success '--merged shows merged tags' '
+   cat expect -\EOF 
+   mergetest-1
+   mergetest-2
+   EOF
+   git tag -l --merged=mergetest-2 mergetest-* actual 
+   test_cmp expect actual
+'
+
+test_expect_success '--no-merged show unmerged tags' '
+   cat expect -\EOF 
+   mergetest-3
+   EOF
+   git tag -l --no-merged=mergetest-2 mergetest-* actual 
+   test_cmp expect actual
+'
+
 test_done
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v9 04/11] ref-filter: add option to filter only tags

2015-08-04 Thread Karthik Nayak
From: Karthik Nayak karthik@gmail.com

Add a functions called 'for_each_tag_ref_fullpath()' to refs.{c,h}
which iterates through each tag ref without trimming the path.

Add an option in 'filter_refs()' to use 'for_each_tag_ref_fullpath()'
and filter refs. This type checking is done by adding a
'FILTER_REFS_TAGS' in 'ref-filter.h'

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 ref-filter.c | 2 ++
 ref-filter.h | 1 +
 refs.c   | 5 +
 refs.h   | 1 +
 4 files changed, 9 insertions(+)

diff --git a/ref-filter.c b/ref-filter.c
index d123299..7c9c51d 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1161,6 +1161,8 @@ int filter_refs(struct ref_array *array, struct 
ref_filter *filter, unsigned int
ret = for_each_rawref(ref_filter_handler, ref_cbdata);
else if (type  FILTER_REFS_ALL)
ret = for_each_ref(ref_filter_handler, ref_cbdata);
+   else if (type  FILTER_REFS_TAGS)
+   ret = for_each_tag_ref_fullpath(ref_filter_handler, 
ref_cbdata);
else if (type)
die(filter_refs: invalid type);
 
diff --git a/ref-filter.h b/ref-filter.h
index 81de1e2..3412dce 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -15,6 +15,7 @@
 
 #define FILTER_REFS_INCLUDE_BROKEN 0x1
 #define FILTER_REFS_ALL 0x2
+#define FILTER_REFS_TAGS 0x4
 
 #define ALIGN_LEFT 0x01
 #define ALIGN_RIGHT 0x02
diff --git a/refs.c b/refs.c
index 2db2975..0103a88 100644
--- a/refs.c
+++ b/refs.c
@@ -2114,6 +2114,11 @@ int for_each_tag_ref(each_ref_fn fn, void *cb_data)
return for_each_ref_in(refs/tags/, fn, cb_data);
 }
 
+int for_each_tag_ref_fullpath(each_ref_fn fn, void *cb_data)
+{
+   return do_for_each_ref(ref_cache, refs/tags/, fn, 0, 0, cb_data);
+}
+
 int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void 
*cb_data)
 {
return for_each_ref_in_submodule(submodule, refs/tags/, fn, cb_data);
diff --git a/refs.h b/refs.h
index 6a3fa6d..0956255 100644
--- a/refs.h
+++ b/refs.h
@@ -174,6 +174,7 @@ extern int head_ref(each_ref_fn fn, void *cb_data);
 extern int for_each_ref(each_ref_fn fn, void *cb_data);
 extern int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);
 extern int for_each_tag_ref(each_ref_fn fn, void *cb_data);
+extern int for_each_tag_ref_fullpath(each_ref_fn fn, void *cb_data);
 extern int for_each_branch_ref(each_ref_fn fn, void *cb_data);
 extern int for_each_remote_ref(each_ref_fn fn, void *cb_data);
 extern int for_each_replace_ref(each_ref_fn fn, void *cb_data);
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v9 03/11] ref-filter: implement an `align` atom

2015-08-04 Thread Karthik Nayak
Implement an `align` atom which will act as a modifier atom and align
any string with or without an %(atom) appearing before a %(end) atom
to the right, left or middle.

It is followed by `:type,paddinglength`, where the `type` is
either left, right or middle and `paddinglength` is the total length
of the padding to be performed. If the atom length is more than the
padding length then no padding is performed. e.g. to pad a succeeding
atom to the middle with a total padding size of 40 we can do a
--format=%(align:middle,40)..

Add documentation and tests for the same.

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 Documentation/git-for-each-ref.txt |  8 
 ref-filter.c   | 84 +++---
 ref-filter.h   | 14 +++
 t/t6302-for-each-ref-filter.sh | 48 ++
 4 files changed, 148 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-for-each-ref.txt 
b/Documentation/git-for-each-ref.txt
index e49d578..d865f98 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -127,6 +127,14 @@ color::
Change output color.  Followed by `:colorname`, where names
are described in `color.branch.*`.
 
+align::
+   Align any string with or without %(atom) before the %(end)
+   atom to the right, left or middle. Followed by
+   `:type,paddinglength`, where the `type` is either left,
+   right or middle and `paddinglength` is the total length of
+   the padding to be performed. If the string length is more than
+   the padding length then no padding is performed.
+
 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 2c074a1..d123299 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -10,6 +10,7 @@
 #include quote.h
 #include ref-filter.h
 #include revision.h
+#include utf8.h
 
 typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
 
@@ -53,6 +54,8 @@ static struct {
{ flag },
{ HEAD },
{ color },
+   { align },
+   { end },
 };
 
 /*
@@ -620,7 +623,7 @@ static void populate_value(struct ref_array_item *ref)
const char *name = used_atom[i];
struct atom_value *v = ref-value[i];
int deref = 0;
-   const char *refname;
+   const char *refname = NULL;
const char *formatp;
struct branch *branch = NULL;
 
@@ -687,6 +690,29 @@ static void populate_value(struct ref_array_item *ref)
else
v-s =  ;
continue;
+   } else if (starts_with(name, align:)) {
+   const char *valp = NULL;
+   struct align *align = xmalloc(sizeof(struct align));
+
+   skip_prefix(name, align:, valp);
+
+   if (skip_prefix(valp, left,, valp))
+   align-align_type = ALIGN_LEFT;
+   else if (skip_prefix(valp, right,, valp))
+   align-align_type = ALIGN_RIGHT;
+   else if (skip_prefix(valp, middle,, valp))
+   align-align_type = ALIGN_MIDDLE;
+   else
+   die(_(align: improper format));
+   if (strtoul_ui(valp, 10, align-align_value))
+   die(_(align: positive value expected));
+   v-align = align;
+   v-modifier_atom = 1;
+   continue;
+   } else if (starts_with(name, end)) {
+   v-end = 1;
+   v-modifier_atom = 1;
+   continue;
} else
continue;
 
@@ -1251,12 +1277,48 @@ static void emit(const char *cp, const char *ep, struct 
ref_formatting_state *st
 
 static void process_formatting_state(struct atom_value *atomv, struct 
ref_formatting_state *state)
 {
-   /* Based on the atomv values, the formatting state is set */
+   if (atomv-align) {
+   state-align = atomv-align;
+   atomv-align = NULL;
+   }
+   if (atomv-end)
+   state-end = 1;
 }
 
 static void apply_formatting_state(struct ref_formatting_state *state, struct 
strbuf *final)
 {
-   /* More formatting options to be evetually added */
+   if (state-align  state-end) {
+   struct strbuf *value = state-output;
+   int len = 0, buf_len = value-len;
+   struct align *align = state-align;
+
+   if (!value-buf)
+   return;
+

[PATCH v9 0/11] Port tag.c over to use ref-filter APIs

2015-08-04 Thread Karthik Nayak
This is part of my GSoC project to unify git tag -l, git branch -l,
git for-each-ref.  This patch series is continued from: Git (next)
https://github.com/git/git/commit/bf5418f49ff0cebc6e5ce04ad1417e1a47c81b61

This series consists of porting tag.c over to using the ref-filter APIs

Version 8 can be found here:
http://thread.gmane.org/gmane.comp.version-control.git/274990

Changes:
* align now excepts strings till a %(end) is met.
* implement the current strbuf within ref_formatting_change
* change the strbuf name from format to final.

Interdiff:

diff --git a/Documentation/git-for-each-ref.txt
b/Documentation/git-for-each-ref.txt
index e89b9b0..6b6eb93 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -128,11 +128,12 @@ color::
are described in `color.branch.*`.

 align::
-   Align succeeding atoms to the right, left or middle. Followed
-   by `:type,paddinglength`, where the `type` is either
-   left, right or middle and `paddinglength` is the total
-   length of the padding to be performed. If the atom length is
-   more than the padding length then no padding is performed.
+   Align any string with or without %(atom) before the %(end)
+   atom to the right, left or middle. Followed by
+   `:type,paddinglength`, where the `type` is either left,
+   right or middle and `paddinglength` is the total length of
+   the padding to be performed. If the string length is more than
+   the padding length then no padding is performed.

 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 afeab37..de84dd4 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -57,6 +57,7 @@ static struct {
{ HEAD },
{ color },
{ align },
+   { end },
 };

 /*
@@ -708,6 +709,11 @@ static void populate_value(struct ref_array_item *ref)
if (strtoul_ui(valp, 10, align-align_value))
die(_(align: positive value expected));
v-align = align;
+   v-modifier_atom = 1;
+   continue;
+   } else if (starts_with(name, end)) {
+   v-end = 1;
+   v-modifier_atom = 1;
continue;
} else
continue;
@@ -1247,24 +1253,23 @@ void ref_array_sort(struct ref_sorting
*sorting, struct ref_array *array)
qsort(array-items, array-nr, sizeof(struct ref_array_item
*), compare_refs);
 }

-static void print_value(struct atom_value *v, struct
ref_formatting_state *state,
-   struct strbuf *output)
+static void print_value(struct atom_value *v, struct
ref_formatting_state *state)
 {
switch (state-quote_style) {
case QUOTE_NONE:
-   strbuf_addstr(output, v-s);
+   strbuf_addstr(state-output, v-s);
break;
case QUOTE_SHELL:
-   sq_quote_buf(output, v-s);
+   sq_quote_buf(state-output, v-s);
break;
case QUOTE_PERL:
-   perl_quote_buf(output, v-s);
+   perl_quote_buf(state-output, v-s);
break;
case QUOTE_PYTHON:
-   python_quote_buf(output, v-s);
+   python_quote_buf(state-output, v-s);
break;
case QUOTE_TCL:
-   tcl_quote_buf(output, v-s);
+   tcl_quote_buf(state-output, v-s);
break;
}
 }
@@ -1287,7 +1292,7 @@ static int hex2(const char *cp)
return -1;
 }

-static void emit(const char *cp, const char *ep, struct strbuf *output)
+static void emit(const char *cp, const char *ep, struct
ref_formatting_state *state)
 {
while (*cp  (!ep || cp  ep)) {
if (*cp == '%') {
@@ -1296,13 +1301,13 @@ static void emit(const char *cp, const char
*ep, struct strbuf *output)
else {
int ch = hex2(cp + 1);
if (0 = ch) {
-   strbuf_addch(output, ch);
+   strbuf_addch(state-output, ch);
cp += 3;
continue;
}
}
}
-   strbuf_addch(output, *cp);
+   strbuf_addch(state-output, *cp);
cp++;
}
 }
@@ -1313,12 +1318,14 @@ static void process_formatting_state(struct
atom_value *atomv, struct ref_format
state-align = atomv-align;
atomv-align = NULL;
}
+   if (atomv-end)
+   state-end = 1;
 }

-static void apply_formatting_state(struct ref_formatting_state
*state, struct strbuf *value,
-   

[PATCH v9 01/11] ref-filter: print output to strbuf for formatting

2015-08-04 Thread Karthik Nayak
Introduce a strbuf `output` which will act as a substitute rather than
printing directly to stdout. This will be used for formatting
eventually.

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 ref-filter.c | 36 ++--
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index 46963a5..91482c9 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1190,30 +1190,25 @@ void ref_array_sort(struct ref_sorting *sorting, struct 
ref_array *array)
qsort(array-items, array-nr, sizeof(struct ref_array_item *), 
compare_refs);
 }
 
-static void print_value(struct atom_value *v, int quote_style)
+static void print_value(struct atom_value *v, int quote_style, struct strbuf 
*output)
 {
-   struct strbuf sb = STRBUF_INIT;
switch (quote_style) {
case QUOTE_NONE:
-   fputs(v-s, stdout);
+   strbuf_addstr(output, v-s);
break;
case QUOTE_SHELL:
-   sq_quote_buf(sb, v-s);
+   sq_quote_buf(output, v-s);
break;
case QUOTE_PERL:
-   perl_quote_buf(sb, v-s);
+   perl_quote_buf(output, v-s);
break;
case QUOTE_PYTHON:
-   python_quote_buf(sb, v-s);
+   python_quote_buf(output, v-s);
break;
case QUOTE_TCL:
-   tcl_quote_buf(sb, v-s);
+   tcl_quote_buf(output, v-s);
break;
}
-   if (quote_style != QUOTE_NONE) {
-   fputs(sb.buf, stdout);
-   strbuf_release(sb);
-   }
 }
 
 static int hex1(char ch)
@@ -1234,7 +1229,7 @@ static int hex2(const char *cp)
return -1;
 }
 
-static void emit(const char *cp, const char *ep)
+static void emit(const char *cp, const char *ep, struct strbuf *output)
 {
while (*cp  (!ep || cp  ep)) {
if (*cp == '%') {
@@ -1243,13 +1238,13 @@ static void emit(const char *cp, const char *ep)
else {
int ch = hex2(cp + 1);
if (0 = ch) {
-   putchar(ch);
+   strbuf_addch(output, ch);
cp += 3;
continue;
}
}
}
-   putchar(*cp);
+   strbuf_addch(output, *cp);
cp++;
}
 }
@@ -1257,19 +1252,21 @@ static void emit(const char *cp, const char *ep)
 void show_ref_array_item(struct ref_array_item *info, const char *format, int 
quote_style)
 {
const char *cp, *sp, *ep;
+   struct strbuf output = STRBUF_INIT;
+   int i;
 
for (cp = format; *cp  (sp = find_next(cp)); cp = ep + 1) {
struct atom_value *atomv;
 
ep = strchr(sp, ')');
if (cp  sp)
-   emit(cp, sp);
+   emit(cp, sp, output);
get_ref_atom_value(info, parse_ref_filter_atom(sp + 2, ep), 
atomv);
-   print_value(atomv, quote_style);
+   print_value(atomv, quote_style, output);
}
if (*cp) {
sp = cp + strlen(cp);
-   emit(cp, sp);
+   emit(cp, sp, output);
}
if (need_color_reset_at_eol) {
struct atom_value resetv;
@@ -1278,9 +1275,12 @@ void show_ref_array_item(struct ref_array_item *info, 
const char *format, int qu
if (color_parse(reset, color)  0)
die(BUG: couldn't parse 'reset' as a color);
resetv.s = color;
-   print_value(resetv, quote_style);
+   print_value(resetv, quote_style, output);
}
+   for (i = 0; i  output.len; i++)
+   printf(%c, output.buf[i]);
putchar('\n');
+   strbuf_release(output);
 }
 
 /*  If no sorting option is given, use refname to sort as default */
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: git svn clone fails

2015-08-04 Thread Jörg Schaible
Hmmm. Is this the proper channel to report issues or should I go somewhere 
else?

Jörg Schaible wrote:

 Hello guys,
 
 we have to turn some projects managed by Subversion into a GIT-based
 solution. However the conversion unfortunately fails with an error:
 
 == % ==
 [...]
 Found branch parent: (refs/remotes/origin/tags/v_2.1.1)
 450fa2c84a8fc087a2a66e5fb3d6d22096671f81
 Following parent with do_switch
 M   changes.xml
 M   pom.xml
 couldn't truncate file at /usr/lib64/perl5/vendor_perl/5.20.2/Git.pm line
 1325.
 $ git --version
 git version 2.5.0
 == % ==
 
 Apart from the line number, the same error occurs also with GIT version
 2.4.6 and 2.3.6 (latest stable version in Gentoo).
 
 The command to create the GIT repository was:
 == % ==
 $ git svn clone http://websvn/svn/essvn/standard/java-commons/lang -s
 --no- metadata --preserve-empty-dirs -A ~/tmp/authors.txt commons-lang
 == % ==
 
 Note, that the command succeeds even for 2.4.6 if we drop the --preserve-
 empty-dirs option - at the cost of some empty directories which are used
 to trigger profiles for Maven; i.e. without those we cannot reproduce
 released versions.
 
 Cheers,
 Jörg


--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 01/45] wrapper: implement xopen()

2015-08-04 Thread Paul Tan
A common usage pattern of open() is to check if it was successful, and
die() if it was not:

int fd = open(path, O_WRONLY | O_CREAT, 0777);
if (fd  0)
die_errno(_(Could not open '%s' for writing.), path);

Implement a wrapper function xopen() that does the above so that we can
save a few lines of code, and make the die() messages consistent.

Helped-by: Torsten Bögershausen tbo...@web.de
Helped-by: Jeff King p...@peff.net
Helped-by: Johannes Schindelin johannes.schinde...@gmx.de
Helped-by: Junio C Hamano gits...@pobox.com
Signed-off-by: Paul Tan pyoka...@gmail.com
---
 git-compat-util.h |  1 +
 wrapper.c | 35 +++
 2 files changed, 36 insertions(+)

diff --git a/git-compat-util.h b/git-compat-util.h
index c6d391f..e168dfd 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -717,6 +717,7 @@ extern void *xrealloc(void *ptr, size_t size);
 extern void *xcalloc(size_t nmemb, size_t size);
 extern void *xmmap(void *start, size_t length, int prot, int flags, int fd, 
off_t offset);
 extern void *xmmap_gently(void *start, size_t length, int prot, int flags, int 
fd, off_t offset);
+extern int xopen(const char *path, int flags, ...);
 extern ssize_t xread(int fd, void *buf, size_t len);
 extern ssize_t xwrite(int fd, const void *buf, size_t len);
 extern ssize_t xpread(int fd, void *buf, size_t len, off_t offset);
diff --git a/wrapper.c b/wrapper.c
index ff49807..0a4502d 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -189,6 +189,41 @@ void *xcalloc(size_t nmemb, size_t size)
 # endif
 #endif
 
+/**
+ * xopen() is the same as open(), but it die()s if the open() fails.
+ */
+int xopen(const char *path, int oflag, ...)
+{
+   mode_t mode = 0;
+   va_list ap;
+
+   /*
+* va_arg() will have undefined behavior if the specified type is not
+* compatible with the argument type. Since integers are promoted to
+* ints, we fetch the next argument as an int, and then cast it to a
+* mode_t to avoid undefined behavior.
+*/
+   va_start(ap, oflag);
+   if (oflag  O_CREAT)
+   mode = va_arg(ap, int);
+   va_end(ap);
+
+   for (;;) {
+   int fd = open(path, oflag, mode);
+   if (fd = 0)
+   return fd;
+   if (errno == EINTR)
+   continue;
+
+   if ((oflag  O_RDWR) == O_RDWR)
+   die_errno(_(could not open '%s' for reading and 
writing), path);
+   else if ((oflag  O_WRONLY) == O_WRONLY)
+   die_errno(_(could not open '%s' for writing), path);
+   else
+   die_errno(_(could not open '%s' for reading), path);
+   }
+}
+
 /*
  * xread() is the same a read(), but it automatically restarts read()
  * operations with a recoverable error (EAGAIN and EINTR). xread()
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 05/45] builtin-am: split out mbox/maildir patches with git-mailsplit

2015-08-04 Thread Paul Tan
git-am.sh supports mbox, stgit and mercurial patches. Re-implement
support for splitting out mbox/maildirs using git-mailsplit, while also
implementing the framework required to support other patch formats in
the future.

Re-implement support for the --patch-format option (since a5a6755
(git-am foreign patch support: introduce patch_format, 2009-05-27)) to
allow the user to choose between the different patch formats.

Helped-by: Junio C Hamano gits...@pobox.com
Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 107 +--
 1 file changed, 104 insertions(+), 3 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index ac172c4..5f3c131 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -8,6 +8,12 @@
 #include exec_cmd.h
 #include parse-options.h
 #include dir.h
+#include run-command.h
+
+enum patch_format {
+   PATCH_FORMAT_UNKNOWN = 0,
+   PATCH_FORMAT_MBOX
+};
 
 struct am_state {
/* state directory path */
@@ -16,6 +22,9 @@ struct am_state {
/* current and last patch numbers, 1-indexed */
int cur;
int last;
+
+   /* number of digits in patch filename */
+   int prec;
 };
 
 /**
@@ -28,6 +37,8 @@ static void am_state_init(struct am_state *state, const char 
*dir)
 
assert(dir);
state-dir = xstrdup(dir);
+
+   state-prec = 4;
 }
 
 /**
@@ -117,13 +128,71 @@ static void am_destroy(const struct am_state *state)
 }
 
 /**
+ * Splits out individual email patches from `paths`, where each path is either
+ * a mbox file or a Maildir. Returns 0 on success, -1 on failure.
+ */
+static int split_mail_mbox(struct am_state *state, const char **paths)
+{
+   struct child_process cp = CHILD_PROCESS_INIT;
+   struct strbuf last = STRBUF_INIT;
+
+   cp.git_cmd = 1;
+   argv_array_push(cp.args, mailsplit);
+   argv_array_pushf(cp.args, -d%d, state-prec);
+   argv_array_pushf(cp.args, -o%s, state-dir);
+   argv_array_push(cp.args, -b);
+   argv_array_push(cp.args, --);
+   argv_array_pushv(cp.args, paths);
+
+   if (capture_command(cp, last, 8))
+   return -1;
+
+   state-cur = 1;
+   state-last = strtol(last.buf, NULL, 10);
+
+   return 0;
+}
+
+/**
+ * Splits a list of files/directories into individual email patches. Each path
+ * in `paths` must be a file/directory that is formatted according to
+ * `patch_format`.
+ *
+ * Once split out, the individual email patches will be stored in the state
+ * directory, with each patch's filename being its index, padded to state-prec
+ * digits.
+ *
+ * state-cur will be set to the index of the first mail, and state-last will
+ * be set to the index of the last mail.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int split_mail(struct am_state *state, enum patch_format patch_format,
+   const char **paths)
+{
+   switch (patch_format) {
+   case PATCH_FORMAT_MBOX:
+   return split_mail_mbox(state, paths);
+   default:
+   die(BUG: invalid patch_format);
+   }
+   return -1;
+}
+
+/**
  * Setup a new am session for applying patches
  */
-static void am_setup(struct am_state *state)
+static void am_setup(struct am_state *state, enum patch_format patch_format,
+   const char **paths)
 {
if (mkdir(state-dir, 0777)  0  errno != EEXIST)
die_errno(_(failed to create directory '%s'), state-dir);
 
+   if (split_mail(state, patch_format, paths)  0) {
+   am_destroy(state);
+   die(_(Failed to split patches.));
+   }
+
/*
 * NOTE: Since the next and last files determine if an am_state
 * session is in progress, they should be written last.
@@ -159,9 +228,25 @@ static void am_run(struct am_state *state)
am_destroy(state);
 }
 
+/**
+ * parse_options() callback that validates and sets opt-value to the
+ * PATCH_FORMAT_* enum value corresponding to `arg`.
+ */
+static int parse_opt_patchformat(const struct option *opt, const char *arg, 
int unset)
+{
+   int *opt_value = opt-value;
+
+   if (!strcmp(arg, mbox))
+   *opt_value = PATCH_FORMAT_MBOX;
+   else
+   return error(_(Invalid value for --patch-format: %s), arg);
+   return 0;
+}
+
 int cmd_am(int argc, const char **argv, const char *prefix)
 {
struct am_state state;
+   int patch_format = PATCH_FORMAT_UNKNOWN;
 
const char * const usage[] = {
N_(git am [options] [(mbox|Maildir)...]),
@@ -169,6 +254,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
};
 
struct option options[] = {
+   OPT_CALLBACK(0, patch-format, patch_format, N_(format),
+   N_(format the patch(es) are in),
+   parse_opt_patchformat),
OPT_END()
};
 
@@ -195,8 +283,21 @@ int cmd_am(int argc, const char **argv, const char 

[PATCH v7 10/45] builtin-am: refuse to apply patches if index is dirty

2015-08-04 Thread Paul Tan
Since d1c5f2a (Add git-am, applymbox replacement., 2005-10-07), git-am
will refuse to apply patches if the index is dirty. Re-implement this
behavior in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 45 +
 1 file changed, 45 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index a2811b6..537ad62 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -14,6 +14,8 @@
 #include cache-tree.h
 #include refs.h
 #include commit.h
+#include diff.h
+#include diffcore.h
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -565,6 +567,43 @@ static void refresh_and_write_cache(void)
 }
 
 /**
+ * Returns 1 if the index differs from HEAD, 0 otherwise. When on an unborn
+ * branch, returns 1 if there are entries in the index, 0 otherwise. If an
+ * strbuf is provided, the space-separated list of files that differ will be
+ * appended to it.
+ */
+static int index_has_changes(struct strbuf *sb)
+{
+   unsigned char head[GIT_SHA1_RAWSZ];
+   int i;
+
+   if (!get_sha1_tree(HEAD, head)) {
+   struct diff_options opt;
+
+   diff_setup(opt);
+   DIFF_OPT_SET(opt, EXIT_WITH_STATUS);
+   if (!sb)
+   DIFF_OPT_SET(opt, QUICK);
+   do_diff_cache(head, opt);
+   diffcore_std(opt);
+   for (i = 0; sb  i  diff_queued_diff.nr; i++) {
+   if (i)
+   strbuf_addch(sb, ' ');
+   strbuf_addstr(sb, diff_queued_diff.queue[i]-two-path);
+   }
+   diff_flush(opt);
+   return DIFF_OPT_TST(opt, HAS_CHANGES) != 0;
+   } else {
+   for (i = 0; sb  i  active_nr; i++) {
+   if (i)
+   strbuf_addch(sb, ' ');
+   strbuf_addstr(sb, active_cache[i]-name);
+   }
+   return !!active_nr;
+   }
+}
+
+/**
  * Parses `mail` using git-mailinfo, extracting its patch and authorship info.
  * state-msg will be set to the patch message. state-author_name,
  * state-author_email and state-author_date will be set to the patch author's
@@ -726,9 +765,15 @@ static void do_commit(const struct am_state *state)
 static void am_run(struct am_state *state)
 {
const char *argv_gc_auto[] = {gc, --auto, NULL};
+   struct strbuf sb = STRBUF_INIT;
 
refresh_and_write_cache();
 
+   if (index_has_changes(sb))
+   die(_(Dirty index: cannot apply patches (dirty: %s)), sb.buf);
+
+   strbuf_release(sb);
+
while (state-cur = state-last) {
const char *mail = am_path(state, msgnum(state));
 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 06/45] builtin-am: auto-detect mbox patches

2015-08-04 Thread Paul Tan
Since 15ced75 (git-am foreign patch support: autodetect some patch
formats, 2009-05-27), git-am.sh is able to autodetect mbox, stgit and
mercurial patches through heuristics.

Re-implement support for autodetecting mbox/maildir files in
builtin/am.c.

RFC 2822 requires that lines are terminated by \r\n. To support this,
implement strbuf_getline_crlf(), which will remove both '\n' and \r\n
from the end of the line.

Helped-by: Junio C Hamano gits...@pobox.com
Helped-by: Eric Sunshine sunsh...@sunshineco.com
Helped-by: Johannes Schindelin johannes.schinde...@gmx.de
Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 109 +++
 1 file changed, 109 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index 5f3c131..c12566a 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -10,6 +10,21 @@
 #include dir.h
 #include run-command.h
 
+/**
+ * Like strbuf_getline(), but treats both '\n' and \r\n as line terminators.
+ */
+static int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)
+{
+   if (strbuf_getwholeline(sb, fp, '\n'))
+   return EOF;
+   if (sb-buf[sb-len - 1] == '\n') {
+   strbuf_setlen(sb, sb-len - 1);
+   if (sb-len  0  sb-buf[sb-len - 1] == '\r')
+   strbuf_setlen(sb, sb-len - 1);
+   }
+   return 0;
+}
+
 enum patch_format {
PATCH_FORMAT_UNKNOWN = 0,
PATCH_FORMAT_MBOX
@@ -128,6 +143,92 @@ static void am_destroy(const struct am_state *state)
 }
 
 /**
+ * Determines if the file looks like a piece of RFC2822 mail by grabbing all
+ * non-indented lines and checking if they look like they begin with valid
+ * header field names.
+ *
+ * Returns 1 if the file looks like a piece of mail, 0 otherwise.
+ */
+static int is_mail(FILE *fp)
+{
+   const char *header_regex = ^[!-9;-~]+:;
+   struct strbuf sb = STRBUF_INIT;
+   regex_t regex;
+   int ret = 1;
+
+   if (fseek(fp, 0L, SEEK_SET))
+   die_errno(_(fseek failed));
+
+   if (regcomp(regex, header_regex, REG_NOSUB | REG_EXTENDED))
+   die(invalid pattern: %s, header_regex);
+
+   while (!strbuf_getline_crlf(sb, fp)) {
+   if (!sb.len)
+   break; /* End of header */
+
+   /* Ignore indented folded lines */
+   if (*sb.buf == '\t' || *sb.buf == ' ')
+   continue;
+
+   /* It's a header if it matches header_regex */
+   if (regexec(regex, sb.buf, 0, NULL, 0)) {
+   ret = 0;
+   goto done;
+   }
+   }
+
+done:
+   regfree(regex);
+   strbuf_release(sb);
+   return ret;
+}
+
+/**
+ * Attempts to detect the patch_format of the patches contained in `paths`,
+ * returning the PATCH_FORMAT_* enum value. Returns PATCH_FORMAT_UNKNOWN if
+ * detection fails.
+ */
+static int detect_patch_format(const char **paths)
+{
+   enum patch_format ret = PATCH_FORMAT_UNKNOWN;
+   struct strbuf l1 = STRBUF_INIT;
+   FILE *fp;
+
+   /*
+* We default to mbox format if input is from stdin and for directories
+*/
+   if (!*paths || !strcmp(*paths, -) || is_directory(*paths))
+   return PATCH_FORMAT_MBOX;
+
+   /*
+* Otherwise, check the first few lines of the first patch, starting
+* from the first non-blank line, to try to detect its format.
+*/
+
+   fp = xfopen(*paths, r);
+
+   while (!strbuf_getline_crlf(l1, fp)) {
+   if (l1.len)
+   break;
+   }
+
+   if (starts_with(l1.buf, From ) || starts_with(l1.buf, From: )) {
+   ret = PATCH_FORMAT_MBOX;
+   goto done;
+   }
+
+   if (l1.len  is_mail(fp)) {
+   ret = PATCH_FORMAT_MBOX;
+   goto done;
+   }
+
+done:
+   fclose(fp);
+   strbuf_release(l1);
+   return ret;
+}
+
+/**
  * Splits out individual email patches from `paths`, where each path is either
  * a mbox file or a Maildir. Returns 0 on success, -1 on failure.
  */
@@ -185,6 +286,14 @@ static int split_mail(struct am_state *state, enum 
patch_format patch_format,
 static void am_setup(struct am_state *state, enum patch_format patch_format,
const char **paths)
 {
+   if (!patch_format)
+   patch_format = detect_patch_format(paths);
+
+   if (!patch_format) {
+   fprintf_ln(stderr, _(Patch format detection failed.));
+   exit(128);
+   }
+
if (mkdir(state-dir, 0777)  0  errno != EEXIST)
die_errno(_(failed to create directory '%s'), state-dir);
 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 02/45] wrapper: implement xfopen()

2015-08-04 Thread Paul Tan
A common usage pattern of fopen() is to check if it succeeded, and die()
if it failed:

FILE *fp = fopen(path, w);
if (!fp)
die_errno(_(could not open '%s' for writing), path);

Implement a wrapper function xfopen() for the above, so that we can save
a few lines of code and make the die() messages consistent.

Helped-by: Jeff King p...@peff.net
Helped-by: Johannes Schindelin johannes.schinde...@gmx.de
Helped-by: Junio C Hamano gits...@pobox.com
Signed-off-by: Paul Tan pyoka...@gmail.com
---
 git-compat-util.h |  1 +
 wrapper.c | 21 +
 2 files changed, 22 insertions(+)

diff --git a/git-compat-util.h b/git-compat-util.h
index e168dfd..392da79 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -722,6 +722,7 @@ extern ssize_t xread(int fd, void *buf, size_t len);
 extern ssize_t xwrite(int fd, const void *buf, size_t len);
 extern ssize_t xpread(int fd, void *buf, size_t len, off_t offset);
 extern int xdup(int fd);
+extern FILE *xfopen(const char *path, const char *mode);
 extern FILE *xfdopen(int fd, const char *mode);
 extern int xmkstemp(char *template);
 extern int xmkstemp_mode(char *template, int mode);
diff --git a/wrapper.c b/wrapper.c
index 0a4502d..e451463 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -346,6 +346,27 @@ int xdup(int fd)
return ret;
 }
 
+/**
+ * xfopen() is the same as fopen(), but it die()s if the fopen() fails.
+ */
+FILE *xfopen(const char *path, const char *mode)
+{
+   for (;;) {
+   FILE *fp = fopen(path, mode);
+   if (fp)
+   return fp;
+   if (errno == EINTR)
+   continue;
+
+   if (*mode  mode[1] == '+')
+   die_errno(_(could not open '%s' for reading and 
writing), path);
+   else if (*mode == 'w' || *mode == 'a')
+   die_errno(_(could not open '%s' for writing), path);
+   else
+   die_errno(_(could not open '%s' for reading), path);
+   }
+}
+
 FILE *xfdopen(int fd, const char *mode)
 {
FILE *stream = fdopen(fd, mode);
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 08/45] builtin-am: apply patch with git-apply

2015-08-04 Thread Paul Tan
Implement applying the patch to the index using git-apply.

If a file is unchanged but stat-dirty, git-apply may erroneously fail to
apply patches, thinking that they conflict with a dirty working tree.

As such, since 2a6f08a (am: refresh the index at start and --resolved,
2011-08-15), git-am will refresh the index before applying patches.
Re-implement this behavior.

Helped-by: Junio C Hamano gits...@pobox.com
Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 72 +++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/builtin/am.c b/builtin/am.c
index 63f0fa4..1f198e4 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -10,6 +10,7 @@
 #include dir.h
 #include run-command.h
 #include quote.h
+#include lockfile.h
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -42,6 +43,14 @@ static int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)
return 0;
 }
 
+/**
+ * Returns the length of the first line of msg.
+ */
+static int linelen(const char *msg)
+{
+   return strchrnul(msg, '\n') - msg;
+}
+
 enum patch_format {
PATCH_FORMAT_UNKNOWN = 0,
PATCH_FORMAT_MBOX
@@ -540,6 +549,19 @@ static const char *msgnum(const struct am_state *state)
 }
 
 /**
+ * Refresh and write index.
+ */
+static void refresh_and_write_cache(void)
+{
+   struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+
+   hold_locked_index(lock_file, 1);
+   refresh_cache(REFRESH_QUIET);
+   if (write_locked_index(the_index, lock_file, COMMIT_LOCK))
+   die(_(unable to write index file));
+}
+
+/**
  * Parses `mail` using git-mailinfo, extracting its patch and authorship info.
  * state-msg will be set to the patch message. state-author_name,
  * state-author_email and state-author_date will be set to the patch author's
@@ -629,10 +651,35 @@ finish:
 }
 
 /**
+ * Applies current patch with git-apply. Returns 0 on success, -1 otherwise.
+ */
+static int run_apply(const struct am_state *state)
+{
+   struct child_process cp = CHILD_PROCESS_INIT;
+
+   cp.git_cmd = 1;
+
+   argv_array_push(cp.args, apply);
+   argv_array_push(cp.args, --index);
+   argv_array_push(cp.args, am_path(state, patch));
+
+   if (run_command(cp))
+   return -1;
+
+   /* Reload index as git-apply will have modified it. */
+   discard_cache();
+   read_cache();
+
+   return 0;
+}
+
+/**
  * Applies all queued mail.
  */
 static void am_run(struct am_state *state)
 {
+   refresh_and_write_cache();
+
while (state-cur = state-last) {
const char *mail = am_path(state, msgnum(state));
 
@@ -645,7 +692,27 @@ static void am_run(struct am_state *state)
write_author_script(state);
write_commit_msg(state);
 
-   /* NEEDSWORK: Patch application not implemented yet */
+   printf_ln(_(Applying: %.*s), linelen(state-msg), state-msg);
+
+   if (run_apply(state)  0) {
+   int advice_amworkdir = 1;
+
+   printf_ln(_(Patch failed at %s %.*s), msgnum(state),
+   linelen(state-msg), state-msg);
+
+   git_config_get_bool(advice.amworkdir, 
advice_amworkdir);
+
+   if (advice_amworkdir)
+   printf_ln(_(The copy of the patch that failed 
is found in: %s),
+   am_path(state, patch));
+
+   exit(128);
+   }
+
+   /*
+* NEEDSWORK: After the patch has been applied to the index
+* with git-apply, we need to make commit as well.
+*/
 
 next:
am_next(state);
@@ -707,6 +774,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 
argc = parse_options(argc, argv, prefix, options, usage, 0);
 
+   if (read_index_preload(the_index, NULL)  0)
+   die(_(failed to read the index));
+
if (am_in_progress(state))
am_load(state);
else {
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 14/45] builtin-am: implement --abort

2015-08-04 Thread Paul Tan
Since 3e5057a (git am --abort, 2008-07-16), git-am supported the --abort
option that will rewind HEAD back to the original commit. Re-implement
this through am_abort().

Since 7b3b7e3 (am --abort: keep unrelated commits since the last failure
and warn, 2010-12-21), to prevent commits made since the last failure
from being lost, git-am will not rewind HEAD back to the original
commit if HEAD moved since the last failure. Re-implement this through
safe_to_abort().

Helped-by: Stefan Beller sbel...@google.com
Signed-off-by: Paul Tan pyoka...@gmail.com
---

Notes:
v7

* Add a free(curr_branch) so we don't leak memory.

 builtin/am.c | 103 +--
 1 file changed, 100 insertions(+), 3 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index 765844b..6c24d07 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -490,6 +490,8 @@ static int split_mail(struct am_state *state, enum 
patch_format patch_format,
 static void am_setup(struct am_state *state, enum patch_format patch_format,
const char **paths)
 {
+   unsigned char curr_head[GIT_SHA1_RAWSZ];
+
if (!patch_format)
patch_format = detect_patch_format(paths);
 
@@ -506,6 +508,14 @@ static void am_setup(struct am_state *state, enum 
patch_format patch_format,
die(_(Failed to split patches.));
}
 
+   if (!get_sha1(HEAD, curr_head)) {
+   write_file(am_path(state, abort-safety), 1, %s, 
sha1_to_hex(curr_head));
+   update_ref(am, ORIG_HEAD, curr_head, NULL, 0, 
UPDATE_REFS_DIE_ON_ERR);
+   } else {
+   write_file(am_path(state, abort-safety), 1, %s, );
+   delete_ref(ORIG_HEAD, NULL, 0);
+   }
+
/*
 * NOTE: Since the next and last files determine if an am_state
 * session is in progress, they should be written last.
@@ -522,6 +532,8 @@ static void am_setup(struct am_state *state, enum 
patch_format patch_format,
  */
 static void am_next(struct am_state *state)
 {
+   unsigned char head[GIT_SHA1_RAWSZ];
+
free(state-author_name);
state-author_name = NULL;
 
@@ -538,6 +550,11 @@ static void am_next(struct am_state *state)
unlink(am_path(state, author-script));
unlink(am_path(state, final-commit));
 
+   if (!get_sha1(HEAD, head))
+   write_file(am_path(state, abort-safety), 1, %s, 
sha1_to_hex(head));
+   else
+   write_file(am_path(state, abort-safety), 1, %s, );
+
state-cur++;
write_file(am_path(state, next), 1, %d, state-cur);
 }
@@ -788,10 +805,14 @@ static void am_run(struct am_state *state, int resume)
const char *argv_gc_auto[] = {gc, --auto, NULL};
struct strbuf sb = STRBUF_INIT;
 
+   unlink(am_path(state, dirtyindex));
+
refresh_and_write_cache();
 
-   if (index_has_changes(sb))
+   if (index_has_changes(sb)) {
+   write_file(am_path(state, dirtyindex), 1, t);
die(_(Dirty index: cannot apply patches (dirty: %s)), sb.buf);
+   }
 
strbuf_release(sb);
 
@@ -980,6 +1001,75 @@ static void am_skip(struct am_state *state)
 }
 
 /**
+ * Returns true if it is safe to reset HEAD to the ORIG_HEAD, false otherwise.
+ *
+ * It is not safe to reset HEAD when:
+ * 1. git-am previously failed because the index was dirty.
+ * 2. HEAD has moved since git-am previously failed.
+ */
+static int safe_to_abort(const struct am_state *state)
+{
+   struct strbuf sb = STRBUF_INIT;
+   unsigned char abort_safety[GIT_SHA1_RAWSZ], head[GIT_SHA1_RAWSZ];
+
+   if (file_exists(am_path(state, dirtyindex)))
+   return 0;
+
+   if (read_state_file(sb, state, abort-safety, 1)  0) {
+   if (get_sha1_hex(sb.buf, abort_safety))
+   die(_(could not parse %s), am_path(state, 
abort_safety));
+   } else
+   hashclr(abort_safety);
+
+   if (get_sha1(HEAD, head))
+   hashclr(head);
+
+   if (!hashcmp(head, abort_safety))
+   return 1;
+
+   error(_(You seem to have moved HEAD since the last 'am' failure.\n
+   Not rewinding to ORIG_HEAD));
+
+   return 0;
+}
+
+/**
+ * Aborts the current am session if it is safe to do so.
+ */
+static void am_abort(struct am_state *state)
+{
+   unsigned char curr_head[GIT_SHA1_RAWSZ], orig_head[GIT_SHA1_RAWSZ];
+   int has_curr_head, has_orig_head;
+   char *curr_branch;
+
+   if (!safe_to_abort(state)) {
+   am_destroy(state);
+   return;
+   }
+
+   curr_branch = resolve_refdup(HEAD, 0, curr_head, NULL);
+   has_curr_head = !is_null_sha1(curr_head);
+   if (!has_curr_head)
+   hashcpy(curr_head, EMPTY_TREE_SHA1_BIN);
+
+   has_orig_head = !get_sha1(ORIG_HEAD, orig_head);
+   if (!has_orig_head)
+   hashcpy(orig_head, EMPTY_TREE_SHA1_BIN);
+
+   

[PATCH v7 13/45] builtin-am: implement --skip

2015-08-04 Thread Paul Tan
Since d1c5f2a (Add git-am, applymbox replacement., 2005-10-07), git-am
supported resuming from a failed patch application by skipping the
current patch. Re-implement this feature by introducing am_skip().

Helped-by: Stefan Beller sbel...@google.com
Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 123 ++-
 1 file changed, 121 insertions(+), 2 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index ec579a6..765844b 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -16,6 +16,8 @@
 #include commit.h
 #include diff.h
 #include diffcore.h
+#include unpack-trees.h
+#include branch.h
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -868,6 +870,116 @@ static void am_resolve(struct am_state *state)
 }
 
 /**
+ * Performs a checkout fast-forward from `head` to `remote`. If `reset` is
+ * true, any unmerged entries will be discarded. Returns 0 on success, -1 on
+ * failure.
+ */
+static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
+{
+   struct lock_file *lock_file;
+   struct unpack_trees_options opts;
+   struct tree_desc t[2];
+
+   if (parse_tree(head) || parse_tree(remote))
+   return -1;
+
+   lock_file = xcalloc(1, sizeof(struct lock_file));
+   hold_locked_index(lock_file, 1);
+
+   refresh_cache(REFRESH_QUIET);
+
+   memset(opts, 0, sizeof(opts));
+   opts.head_idx = 1;
+   opts.src_index = the_index;
+   opts.dst_index = the_index;
+   opts.update = 1;
+   opts.merge = 1;
+   opts.reset = reset;
+   opts.fn = twoway_merge;
+   init_tree_desc(t[0], head-buffer, head-size);
+   init_tree_desc(t[1], remote-buffer, remote-size);
+
+   if (unpack_trees(2, t, opts)) {
+   rollback_lock_file(lock_file);
+   return -1;
+   }
+
+   if (write_locked_index(the_index, lock_file, COMMIT_LOCK))
+   die(_(unable to write new index file));
+
+   return 0;
+}
+
+/**
+ * Clean the index without touching entries that are not modified between
+ * `head` and `remote`.
+ */
+static int clean_index(const unsigned char *head, const unsigned char *remote)
+{
+   struct lock_file *lock_file;
+   struct tree *head_tree, *remote_tree, *index_tree;
+   unsigned char index[GIT_SHA1_RAWSZ];
+   struct pathspec pathspec;
+
+   head_tree = parse_tree_indirect(head);
+   if (!head_tree)
+   return error(_(Could not parse object '%s'.), 
sha1_to_hex(head));
+
+   remote_tree = parse_tree_indirect(remote);
+   if (!remote_tree)
+   return error(_(Could not parse object '%s'.), 
sha1_to_hex(remote));
+
+   read_cache_unmerged();
+
+   if (fast_forward_to(head_tree, head_tree, 1))
+   return -1;
+
+   if (write_cache_as_tree(index, 0, NULL))
+   return -1;
+
+   index_tree = parse_tree_indirect(index);
+   if (!index_tree)
+   return error(_(Could not parse object '%s'.), 
sha1_to_hex(index));
+
+   if (fast_forward_to(index_tree, remote_tree, 0))
+   return -1;
+
+   memset(pathspec, 0, sizeof(pathspec));
+
+   lock_file = xcalloc(1, sizeof(struct lock_file));
+   hold_locked_index(lock_file, 1);
+
+   if (read_tree(remote_tree, 0, pathspec)) {
+   rollback_lock_file(lock_file);
+   return -1;
+   }
+
+   if (write_locked_index(the_index, lock_file, COMMIT_LOCK))
+   die(_(unable to write new index file));
+
+   remove_branch_state();
+
+   return 0;
+}
+
+/**
+ * Resume the current am session by skipping the current patch.
+ */
+static void am_skip(struct am_state *state)
+{
+   unsigned char head[GIT_SHA1_RAWSZ];
+
+   if (get_sha1(HEAD, head))
+   hashcpy(head, EMPTY_TREE_SHA1_BIN);
+
+   if (clean_index(head, head))
+   die(_(failed to clean index));
+
+   am_next(state);
+   am_run(state, 0);
+}
+
+/**
  * parse_options() callback that validates and sets opt-value to the
  * PATCH_FORMAT_* enum value corresponding to `arg`.
  */
@@ -885,7 +997,8 @@ static int parse_opt_patchformat(const struct option *opt, 
const char *arg, int
 enum resume_mode {
RESUME_FALSE = 0,
RESUME_APPLY,
-   RESUME_RESOLVED
+   RESUME_RESOLVED,
+   RESUME_SKIP
 };
 
 int cmd_am(int argc, const char **argv, const char *prefix)
@@ -896,7 +1009,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 
const char * const usage[] = {
N_(git am [options] [(mbox|Maildir)...]),
-   N_(git am [options] --continue),
+   N_(git am [options] (--continue | --skip)),
NULL
};
 
@@ -910,6 +1023,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
OPT_CMDMODE('r', resolved, resume,
N_(synonyms for --continue),
   

[PATCH v7 22/45] builtin-am: bypass git-mailinfo when --rebasing

2015-08-04 Thread Paul Tan
Since 5e835ca (rebase: do not munge commit log message, 2008-04-16),
git am --rebasing no longer gets the commit log message from the patch,
but reads it directly from the commit identified by the From  header
line.

Since 43c2325 (am: use get_author_ident_from_commit instead of mailinfo
when rebasing, 2010-06-16), git am --rebasing also gets the author name,
email and date directly from the commit.

Since 0fbb95d (am: don't call mailinfo if $rebasing, 2012-06-26), git am
--rebasing does not use git-mailinfo to get the patch body, but rather
generates it directly from the commit itself.

The above 3 commits introduced a separate parse_mail() code path in
git-am.sh's --rebasing mode that bypasses git-mailinfo. Re-implement
this code path in builtin/am.c as parse_mail_rebase().

Signed-off-by: Paul Tan pyoka...@gmail.com
---

Notes:
v7

* Since a5481a6 (convert enum date_mode into a struct, 2015-06-25),
  show_ident_date() now takes a date_mode struct. Use the DATE_MODE()
  macro to pass the equivalent date_mode struct to show_ident_date().

 builtin/am.c | 134 ++-
 1 file changed, 133 insertions(+), 1 deletion(-)

diff --git a/builtin/am.c b/builtin/am.c
index 440a653..a02c84e 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -21,6 +21,8 @@
 #include sequencer.h
 #include revision.h
 #include merge-recursive.h
+#include revision.h
+#include log-tree.h
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -788,6 +790,129 @@ finish:
 }
 
 /**
+ * Sets commit_id to the commit hash where the mail was generated from.
+ * Returns 0 on success, -1 on failure.
+ */
+static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail)
+{
+   struct strbuf sb = STRBUF_INIT;
+   FILE *fp = xfopen(mail, r);
+   const char *x;
+
+   if (strbuf_getline(sb, fp, '\n'))
+   return -1;
+
+   if (!skip_prefix(sb.buf, From , x))
+   return -1;
+
+   if (get_sha1_hex(x, commit_id)  0)
+   return -1;
+
+   strbuf_release(sb);
+   fclose(fp);
+   return 0;
+}
+
+/**
+ * Sets state-msg, state-author_name, state-author_email, state-author_date
+ * to the commit's respective info.
+ */
+static void get_commit_info(struct am_state *state, struct commit *commit)
+{
+   const char *buffer, *ident_line, *author_date, *msg;
+   size_t ident_len;
+   struct ident_split ident_split;
+   struct strbuf sb = STRBUF_INIT;
+
+   buffer = logmsg_reencode(commit, NULL, get_commit_output_encoding());
+
+   ident_line = find_commit_header(buffer, author, ident_len);
+
+   if (split_ident_line(ident_split, ident_line, ident_len)  0) {
+   strbuf_add(sb, ident_line, ident_len);
+   die(_(invalid ident line: %s), sb.buf);
+   }
+
+   assert(!state-author_name);
+   if (ident_split.name_begin) {
+   strbuf_add(sb, ident_split.name_begin,
+   ident_split.name_end - ident_split.name_begin);
+   state-author_name = strbuf_detach(sb, NULL);
+   } else
+   state-author_name = xstrdup();
+
+   assert(!state-author_email);
+   if (ident_split.mail_begin) {
+   strbuf_add(sb, ident_split.mail_begin,
+   ident_split.mail_end - ident_split.mail_begin);
+   state-author_email = strbuf_detach(sb, NULL);
+   } else
+   state-author_email = xstrdup();
+
+   author_date = show_ident_date(ident_split, DATE_MODE(NORMAL));
+   strbuf_addstr(sb, author_date);
+   assert(!state-author_date);
+   state-author_date = strbuf_detach(sb, NULL);
+
+   assert(!state-msg);
+   msg = strstr(buffer, \n\n);
+   if (!msg)
+   die(_(unable to parse commit %s), 
sha1_to_hex(commit-object.sha1));
+   state-msg = xstrdup(msg + 2);
+   state-msg_len = strlen(state-msg);
+}
+
+/**
+ * Writes `commit` as a patch to the state directory's patch file.
+ */
+static void write_commit_patch(const struct am_state *state, struct commit 
*commit)
+{
+   struct rev_info rev_info;
+   FILE *fp;
+
+   fp = xfopen(am_path(state, patch), w);
+   init_revisions(rev_info, NULL);
+   rev_info.diff = 1;
+   rev_info.abbrev = 0;
+   rev_info.disable_stdin = 1;
+   rev_info.show_root_diff = 1;
+   rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;
+   rev_info.no_commit_id = 1;
+   DIFF_OPT_SET(rev_info.diffopt, BINARY);
+   DIFF_OPT_SET(rev_info.diffopt, FULL_INDEX);
+   rev_info.diffopt.use_color = 0;
+   rev_info.diffopt.file = fp;
+   rev_info.diffopt.close_file = 1;
+   add_pending_object(rev_info, commit-object, );
+   diff_setup_done(rev_info.diffopt);
+   log_tree_commit(rev_info, commit);
+}
+
+/**
+ * Like parse_mail(), but parses the mail by looking up its commit ID
+ * directly. This is used in --rebasing mode to 

[PATCH v7 36/45] builtin-am: invoke pre-applypatch hook

2015-08-04 Thread Paul Tan
Since d1c5f2a (Add git-am, applymbox replacement., 2005-10-07),
git-am.sg will invoke the pre-applypatch hook after applying the patch
to the index, but before a commit is made. Should the hook exit with a
non-zero status, git am will exit.

Re-implement this in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index f0e3aab..7a7da94 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1334,6 +1334,9 @@ static void do_commit(const struct am_state *state)
const char *reflog_msg, *author;
struct strbuf sb = STRBUF_INIT;
 
+   if (run_hook_le(NULL, pre-applypatch, NULL))
+   exit(1);
+
if (write_cache_as_tree(tree, 0, NULL))
die(_(git write-tree failed to write a tree));
 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 23/45] builtin-am: handle stray state directory

2015-08-04 Thread Paul Tan
Should git-am terminate unexpectedly between the point where the state
directory is created, but the next and last files are not written
yet, a stray state directory will be left behind.

As such, since b141f3c (am: handle stray $dotest directory, 2013-06-15),
git-am.sh explicitly recognizes such a stray directory, and allows the
user to remove it with am --abort.

Re-implement this feature in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 17 +
 1 file changed, 17 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index a02c84e..47dd4c7 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1530,6 +1530,23 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
struct argv_array paths = ARGV_ARRAY_INIT;
int i;
 
+   /*
+* Handle stray state directory in the independent-run case. In
+* the --rebasing case, it is up to the caller to take care of
+* stray directories.
+*/
+   if (file_exists(state.dir)  !state.rebasing) {
+   if (resume == RESUME_ABORT) {
+   am_destroy(state);
+   am_state_release(state);
+   return 0;
+   }
+
+   die(_(Stray %s directory found.\n
+   Use \git am --abort\ to remove it.),
+   state.dir);
+   }
+
if (resume)
die(_(Resolve operation not in progress, we are not 
resuming.));
 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 37/45] builtin-am: invoke post-applypatch hook

2015-08-04 Thread Paul Tan
Since d1c5f2a (Add git-am, applymbox replacement., 2005-10-07),
git-am.sh will invoke the post-applypatch hook after the patch is
applied and a commit is made. The exit code of the hook is ignored.

Re-implement this in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index 7a7da94..c313e58 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1378,6 +1378,8 @@ static void do_commit(const struct am_state *state)
fclose(fp);
}
 
+   run_hook_le(NULL, post-applypatch, NULL);
+
strbuf_release(sb);
 }
 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 34/45] builtin-am: support automatic notes copying

2015-08-04 Thread Paul Tan
Since eb2151b (rebase: support automatic notes copying, 2010-03-12),
git-am.sh supported automatic notes copying in --rebasing mode by
invoking git notes copy once it has finished applying all the patches.

Re-implement this feature in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 60 
 1 file changed, 60 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index dbec9fc..7d7f91d 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -23,6 +23,7 @@
 #include merge-recursive.h
 #include revision.h
 #include log-tree.h
+#include notes-utils.h
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -479,6 +480,64 @@ static int run_post_rewrite_hook(const struct am_state 
*state)
 }
 
 /**
+ * Reads the state directory's rewritten file, and copies notes from the old
+ * commits listed in the file to their rewritten commits.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int copy_notes_for_rebase(const struct am_state *state)
+{
+   struct notes_rewrite_cfg *c;
+   struct strbuf sb = STRBUF_INIT;
+   const char *invalid_line = _(Malformed input line: '%s'.);
+   const char *msg = Notes added by 'git rebase';
+   FILE *fp;
+   int ret = 0;
+
+   assert(state-rebasing);
+
+   c = init_copy_notes_for_rewrite(rebase);
+   if (!c)
+   return 0;
+
+   fp = xfopen(am_path(state, rewritten), r);
+
+   while (!strbuf_getline(sb, fp, '\n')) {
+   unsigned char from_obj[GIT_SHA1_RAWSZ], to_obj[GIT_SHA1_RAWSZ];
+
+   if (sb.len != GIT_SHA1_HEXSZ * 2 + 1) {
+   ret = error(invalid_line, sb.buf);
+   goto finish;
+   }
+
+   if (get_sha1_hex(sb.buf, from_obj)) {
+   ret = error(invalid_line, sb.buf);
+   goto finish;
+   }
+
+   if (sb.buf[GIT_SHA1_HEXSZ] != ' ') {
+   ret = error(invalid_line, sb.buf);
+   goto finish;
+   }
+
+   if (get_sha1_hex(sb.buf + GIT_SHA1_HEXSZ + 1, to_obj)) {
+   ret = error(invalid_line, sb.buf);
+   goto finish;
+   }
+
+   if (copy_note_for_rewrite(c, from_obj, to_obj))
+   ret = error(_(Failed to copy notes from '%s' to '%s'),
+   sha1_to_hex(from_obj), 
sha1_to_hex(to_obj));
+   }
+
+finish:
+   finish_copy_notes_for_rewrite(c, msg);
+   fclose(fp);
+   strbuf_release(sb);
+   return ret;
+}
+
+/**
  * Determines if the file looks like a piece of RFC2822 mail by grabbing all
  * non-indented lines and checking if they look like they begin with valid
  * header field names.
@@ -1405,6 +1464,7 @@ next:
 
if (!is_empty_file(am_path(state, rewritten))) {
assert(state-rebasing);
+   copy_notes_for_rebase(state);
run_post_rewrite_hook(state);
}
 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 30/45] builtin-am: implement --ignore-date

2015-08-04 Thread Paul Tan
Since a79ec62 (git-am: Add --ignore-date option, 2009-01-24), git-am.sh
supported the --ignore-date option, and would use the current timestamp
instead of the one provided in the patch if the option was set.

Re-implement this option in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/builtin/am.c b/builtin/am.c
index f842f69..84d3e05 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -108,6 +108,7 @@ struct am_state {
int scissors; /* enum scissors_type */
struct argv_array git_apply_opts;
const char *resolvemsg;
+   int ignore_date;
int rebasing;
 };
 
@@ -1217,7 +1218,8 @@ static void do_commit(const struct am_state *state)
}
 
author = fmt_ident(state-author_name, state-author_email,
-   state-author_date, IDENT_STRICT);
+   state-ignore_date ? NULL : state-author_date,
+   IDENT_STRICT);
 
if (commit_tree(state-msg, state-msg_len, tree, parents, commit,
author, NULL))
@@ -1661,6 +1663,8 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
OPT_CMDMODE(0, abort, resume,
N_(restore the original branch and abort the patching 
operation.),
RESUME_ABORT),
+   OPT_BOOL(0, ignore-date, state.ignore_date,
+   N_(use current timestamp for author date)),
OPT_HIDDEN_BOOL(0, rebasing, state.rebasing,
N_((internal use for git-rebase))),
OPT_END()
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 21/45] builtin-am: implement --rebasing mode

2015-08-04 Thread Paul Tan
Since 3041c32 (am: --rebasing, 2008-03-04), git-am.sh supported the
--rebasing option, which is used internally by git-rebase to tell git-am
that it is being used for its purpose. It would create the empty file
$state_dir/rebasing to help completion scripts tell if the ongoing
operation is am or rebase.

As of 0fbb95d (am: don't call mailinfo if $rebasing, 2012-06-26),
--rebasing also implies --3way as well.

Since a1549e1 (am: return control to caller, for housekeeping,
2013-05-12), git-am.sh would only clean up the state directory when it
is not --rebasing, instead deferring cleanup to git-rebase.sh.

Re-implement the above in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 30 ++
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index a5d5e8c..440a653 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -89,6 +89,7 @@ struct am_state {
int quiet;
int signoff;
const char *resolvemsg;
+   int rebasing;
 };
 
 /**
@@ -364,6 +365,8 @@ static void am_load(struct am_state *state)
read_state_file(sb, state, sign, 1);
state-signoff = !strcmp(sb.buf, t);
 
+   state-rebasing = !!file_exists(am_path(state, rebasing));
+
strbuf_release(sb);
 }
 
@@ -542,18 +545,29 @@ static void am_setup(struct am_state *state, enum 
patch_format patch_format,
die(_(Failed to split patches.));
}
 
+   if (state-rebasing)
+   state-threeway = 1;
+
write_file(am_path(state, threeway), 1, state-threeway ? t : f);
 
write_file(am_path(state, quiet), 1, state-quiet ? t : f);
 
write_file(am_path(state, sign), 1, state-signoff ? t : f);
 
+   if (state-rebasing)
+   write_file(am_path(state, rebasing), 1, %s, );
+   else
+   write_file(am_path(state, applying), 1, %s, );
+
if (!get_sha1(HEAD, curr_head)) {
write_file(am_path(state, abort-safety), 1, %s, 
sha1_to_hex(curr_head));
-   update_ref(am, ORIG_HEAD, curr_head, NULL, 0, 
UPDATE_REFS_DIE_ON_ERR);
+   if (!state-rebasing)
+   update_ref(am, ORIG_HEAD, curr_head, NULL, 0,
+   UPDATE_REFS_DIE_ON_ERR);
} else {
write_file(am_path(state, abort-safety), 1, %s, );
-   delete_ref(ORIG_HEAD, NULL, 0);
+   if (!state-rebasing)
+   delete_ref(ORIG_HEAD, NULL, 0);
}
 
/*
@@ -1054,8 +1068,14 @@ next:
am_next(state);
}
 
-   am_destroy(state);
-   run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+   /*
+* In rebasing mode, it's up to the caller to take care of
+* housekeeping.
+*/
+   if (!state-rebasing) {
+   am_destroy(state);
+   run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+   }
 }
 
 /**
@@ -1325,6 +1345,8 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
OPT_CMDMODE(0, abort, resume,
N_(restore the original branch and abort the patching 
operation.),
RESUME_ABORT),
+   OPT_HIDDEN_BOOL(0, rebasing, state.rebasing,
+   N_((internal use for git-rebase))),
OPT_END()
};
 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 32/45] builtin-am: implement -S/--gpg-sign, commit.gpgsign

2015-08-04 Thread Paul Tan
Since 3b4e395 (am: add the --gpg-sign option, 2014-02-01), git-am.sh
supported the --gpg-sign option, and would pass it to git-commit-tree,
thus GPG-signing the commit object.

Re-implement this option in builtin/am.c.

git-commit-tree would also sign the commit by default if the
commit.gpgsign setting is true. Since we do not run commit-tree, we
re-implement this behavior by handling the commit.gpgsign setting
ourselves.

Helped-by: Stefan Beller sbel...@google.com
Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/builtin/am.c b/builtin/am.c
index 1561580..18611fa 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -110,6 +110,7 @@ struct am_state {
const char *resolvemsg;
int committer_date_is_author_date;
int ignore_date;
+   const char *sign_commit;
int rebasing;
 };
 
@@ -119,6 +120,8 @@ struct am_state {
  */
 static void am_state_init(struct am_state *state, const char *dir)
 {
+   int gpgsign;
+
memset(state, 0, sizeof(*state));
 
assert(dir);
@@ -133,6 +136,9 @@ static void am_state_init(struct am_state *state, const 
char *dir)
state-scissors = SCISSORS_UNSET;
 
argv_array_init(state-git_apply_opts);
+
+   if (!git_config_get_bool(commit.gpgsign, gpgsign))
+   state-sign_commit = gpgsign ?  : NULL;
 }
 
 /**
@@ -1227,7 +1233,7 @@ static void do_commit(const struct am_state *state)
state-ignore_date ?  : state-author_date, 1);
 
if (commit_tree(state-msg, state-msg_len, tree, parents, commit,
-   author, NULL))
+   author, state-sign_commit))
die(_(failed to write commit object));
 
reflog_msg = getenv(GIT_REFLOG_ACTION);
@@ -1673,6 +1679,9 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
N_(lie about committer date)),
OPT_BOOL(0, ignore-date, state.ignore_date,
N_(use current timestamp for author date)),
+   { OPTION_STRING, 'S', gpg-sign, state.sign_commit, 
N_(key-id),
+ N_(GPG-sign commits),
+ PARSE_OPT_OPTARG, NULL, (intptr_t)  },
OPT_HIDDEN_BOOL(0, rebasing, state.rebasing,
N_((internal use for git-rebase))),
OPT_END()
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 27/45] builtin-am: support --keep-cr, am.keepcr

2015-08-04 Thread Paul Tan
Since ad2c928 (git-am: Add command line parameter `--keep-cr` passing it
to git-mailsplit, 2010-02-27), git-am.sh supported the --keep-cr option
and would pass it to git-mailsplit.

Since e80d4cb (git-am: Add am.keepcr and --no-keep-cr to override it,
2010-02-27), git-am.sh supported the am.keepcr config setting, which
controls whether --keep-cr is on by default.

Re-implement the above in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 29 +++--
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index 8e97839..e34bc51 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -502,7 +502,7 @@ done:
  * Splits out individual email patches from `paths`, where each path is either
  * a mbox file or a Maildir. Returns 0 on success, -1 on failure.
  */
-static int split_mail_mbox(struct am_state *state, const char **paths)
+static int split_mail_mbox(struct am_state *state, const char **paths, int 
keep_cr)
 {
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf last = STRBUF_INIT;
@@ -512,6 +512,8 @@ static int split_mail_mbox(struct am_state *state, const 
char **paths)
argv_array_pushf(cp.args, -d%d, state-prec);
argv_array_pushf(cp.args, -o%s, state-dir);
argv_array_push(cp.args, -b);
+   if (keep_cr)
+   argv_array_push(cp.args, --keep-cr);
argv_array_push(cp.args, --);
argv_array_pushv(cp.args, paths);
 
@@ -536,14 +538,22 @@ static int split_mail_mbox(struct am_state *state, const 
char **paths)
  * state-cur will be set to the index of the first mail, and state-last will
  * be set to the index of the last mail.
  *
+ * Set keep_cr to 0 to convert all lines ending with \r\n to end with \n, 1
+ * to disable this behavior, -1 to use the default configured setting.
+ *
  * Returns 0 on success, -1 on failure.
  */
 static int split_mail(struct am_state *state, enum patch_format patch_format,
-   const char **paths)
+   const char **paths, int keep_cr)
 {
+   if (keep_cr  0) {
+   keep_cr = 0;
+   git_config_get_bool(am.keepcr, keep_cr);
+   }
+
switch (patch_format) {
case PATCH_FORMAT_MBOX:
-   return split_mail_mbox(state, paths);
+   return split_mail_mbox(state, paths, keep_cr);
default:
die(BUG: invalid patch_format);
}
@@ -554,7 +564,7 @@ static int split_mail(struct am_state *state, enum 
patch_format patch_format,
  * Setup a new am session for applying patches
  */
 static void am_setup(struct am_state *state, enum patch_format patch_format,
-   const char **paths)
+   const char **paths, int keep_cr)
 {
unsigned char curr_head[GIT_SHA1_RAWSZ];
const char *str;
@@ -570,7 +580,7 @@ static void am_setup(struct am_state *state, enum 
patch_format patch_format,
if (mkdir(state-dir, 0777)  0  errno != EEXIST)
die_errno(_(failed to create directory '%s'), state-dir);
 
-   if (split_mail(state, patch_format, paths)  0) {
+   if (split_mail(state, patch_format, paths, keep_cr)  0) {
am_destroy(state);
die(_(Failed to split patches.));
}
@@ -1511,6 +1521,7 @@ enum resume_mode {
 int cmd_am(int argc, const char **argv, const char *prefix)
 {
struct am_state state;
+   int keep_cr = -1;
int patch_format = PATCH_FORMAT_UNKNOWN;
enum resume_mode resume = RESUME_FALSE;
 
@@ -1534,6 +1545,12 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
N_(pass -b flag to git-mailinfo), KEEP_NON_PATCH),
OPT_BOOL('m', message-id, state.message_id,
N_(pass -m flag to git-mailinfo)),
+   { OPTION_SET_INT, 0, keep-cr, keep_cr, NULL,
+ N_(pass --keep-cr flag to git-mailsplit for mbox format),
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1},
+   { OPTION_SET_INT, 0, no-keep-cr, keep_cr, NULL,
+ N_(do not pass --keep-cr flag to git-mailsplit independent 
of am.keepcr),
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 0},
OPT_CALLBACK(0, patch-format, patch_format, N_(format),
N_(format the patch(es) are in),
parse_opt_patchformat),
@@ -1631,7 +1648,7 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
argv_array_push(paths, mkpath(%s/%s, prefix, 
argv[i]));
}
 
-   am_setup(state, patch_format, paths.argv);
+   am_setup(state, patch_format, paths.argv, keep_cr);
 
argv_array_clear(paths);
}
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at 

[PATCH v7 07/45] builtin-am: extract patch and commit info with git-mailinfo

2015-08-04 Thread Paul Tan
For the purpose of applying the patch and committing the results,
implement extracting the patch data, commit message and authorship from
an e-mail message using git-mailinfo.

git-mailinfo is run as a separate process, but ideally in the future,
we should be be able to access its functionality directly without
spawning a new process.

Helped-by: Junio C Hamano gits...@pobox.com
Helped-by: Jeff King p...@peff.net
Helped-by: Johannes Schindelin johannes.schinde...@gmx.de
Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 317 +++
 1 file changed, 317 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index c12566a..63f0fa4 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -9,6 +9,23 @@
 #include parse-options.h
 #include dir.h
 #include run-command.h
+#include quote.h
+
+/**
+ * Returns 1 if the file is empty or does not exist, 0 otherwise.
+ */
+static int is_empty_file(const char *filename)
+{
+   struct stat st;
+
+   if (stat(filename, st)  0) {
+   if (errno == ENOENT)
+   return 1;
+   die_errno(_(could not stat %s), filename);
+   }
+
+   return !st.st_size;
+}
 
 /**
  * Like strbuf_getline(), but treats both '\n' and \r\n as line terminators.
@@ -38,6 +55,13 @@ struct am_state {
int cur;
int last;
 
+   /* commit metadata and message */
+   char *author_name;
+   char *author_email;
+   char *author_date;
+   char *msg;
+   size_t msg_len;
+
/* number of digits in patch filename */
int prec;
 };
@@ -62,6 +86,10 @@ static void am_state_init(struct am_state *state, const char 
*dir)
 static void am_state_release(struct am_state *state)
 {
free(state-dir);
+   free(state-author_name);
+   free(state-author_email);
+   free(state-author_date);
+   free(state-msg);
 }
 
 /**
@@ -112,6 +140,161 @@ static int read_state_file(struct strbuf *sb, const 
struct am_state *state,
 }
 
 /**
+ * Reads a KEY=VALUE shell variable assignment from `fp`, returning the VALUE
+ * as a newly-allocated string. VALUE must be a quoted string, and the KEY must
+ * match `key`. Returns NULL on failure.
+ *
+ * This is used by read_author_script() to read the GIT_AUTHOR_* variables from
+ * the author-script.
+ */
+static char *read_shell_var(FILE *fp, const char *key)
+{
+   struct strbuf sb = STRBUF_INIT;
+   const char *str;
+
+   if (strbuf_getline(sb, fp, '\n'))
+   goto fail;
+
+   if (!skip_prefix(sb.buf, key, str))
+   goto fail;
+
+   if (!skip_prefix(str, =, str))
+   goto fail;
+
+   strbuf_remove(sb, 0, str - sb.buf);
+
+   str = sq_dequote(sb.buf);
+   if (!str)
+   goto fail;
+
+   return strbuf_detach(sb, NULL);
+
+fail:
+   strbuf_release(sb);
+   return NULL;
+}
+
+/**
+ * Reads and parses the state directory's author-script file, and sets
+ * state-author_name, state-author_email and state-author_date accordingly.
+ * Returns 0 on success, -1 if the file could not be parsed.
+ *
+ * The author script is of the format:
+ *
+ * GIT_AUTHOR_NAME='$author_name'
+ * GIT_AUTHOR_EMAIL='$author_email'
+ * GIT_AUTHOR_DATE='$author_date'
+ *
+ * where $author_name, $author_email and $author_date are quoted. We are strict
+ * with our parsing, as the file was meant to be eval'd in the old git-am.sh
+ * script, and thus if the file differs from what this function expects, it is
+ * better to bail out than to do something that the user does not expect.
+ */
+static int read_author_script(struct am_state *state)
+{
+   const char *filename = am_path(state, author-script);
+   FILE *fp;
+
+   assert(!state-author_name);
+   assert(!state-author_email);
+   assert(!state-author_date);
+
+   fp = fopen(filename, r);
+   if (!fp) {
+   if (errno == ENOENT)
+   return 0;
+   die_errno(_(could not open '%s' for reading), filename);
+   }
+
+   state-author_name = read_shell_var(fp, GIT_AUTHOR_NAME);
+   if (!state-author_name) {
+   fclose(fp);
+   return -1;
+   }
+
+   state-author_email = read_shell_var(fp, GIT_AUTHOR_EMAIL);
+   if (!state-author_email) {
+   fclose(fp);
+   return -1;
+   }
+
+   state-author_date = read_shell_var(fp, GIT_AUTHOR_DATE);
+   if (!state-author_date) {
+   fclose(fp);
+   return -1;
+   }
+
+   if (fgetc(fp) != EOF) {
+   fclose(fp);
+   return -1;
+   }
+
+   fclose(fp);
+   return 0;
+}
+
+/**
+ * Saves state-author_name, state-author_email and state-author_date in the
+ * state directory's author-script file.
+ */
+static void write_author_script(const struct am_state *state)
+{
+   struct strbuf sb = STRBUF_INIT;
+
+   strbuf_addstr(sb, GIT_AUTHOR_NAME=);

[PATCH v7 28/45] builtin-am: implement --[no-]scissors

2015-08-04 Thread Paul Tan
Since 017678b (am/mailinfo: Disable scissors processing by default,
2009-08-26), git-am supported the --[no-]scissors option, passing it to
git-mailinfo.

Re-implement support for this option in builtin/am.c.

Since the default setting of --scissors in git-mailinfo can be
configured with mailinfo.scissors (and perhaps through other settings in
the future), to be safe we make an explicit distinction between
SCISSORS_UNSET, SCISSORS_TRUE and SCISSORS_FALSE.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 48 
 1 file changed, 48 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index e34bc51..727cfb8 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -74,6 +74,12 @@ enum keep_type {
KEEP_NON_PATCH  /* pass -b flag to git-mailinfo */
 };
 
+enum scissors_type {
+   SCISSORS_UNSET = -1,
+   SCISSORS_FALSE = 0,  /* pass --no-scissors to git-mailinfo */
+   SCISSORS_TRUE/* pass --scissors to git-mailinfo */
+};
+
 struct am_state {
/* state directory path */
char *dir;
@@ -99,6 +105,7 @@ struct am_state {
int utf8;
int keep; /* enum keep_type */
int message_id;
+   int scissors; /* enum scissors_type */
const char *resolvemsg;
int rebasing;
 };
@@ -119,6 +126,8 @@ static void am_state_init(struct am_state *state, const 
char *dir)
state-utf8 = 1;
 
git_config_get_bool(am.messageid, state-message_id);
+
+   state-scissors = SCISSORS_UNSET;
 }
 
 /**
@@ -394,6 +403,14 @@ static void am_load(struct am_state *state)
read_state_file(sb, state, messageid, 1);
state-message_id = !strcmp(sb.buf, t);
 
+   read_state_file(sb, state, scissors, 1);
+   if (!strcmp(sb.buf, t))
+   state-scissors = SCISSORS_TRUE;
+   else if (!strcmp(sb.buf, f))
+   state-scissors = SCISSORS_FALSE;
+   else
+   state-scissors = SCISSORS_UNSET;
+
state-rebasing = !!file_exists(am_path(state, rebasing));
 
strbuf_release(sb);
@@ -614,6 +631,22 @@ static void am_setup(struct am_state *state, enum 
patch_format patch_format,
 
write_file(am_path(state, messageid), 1, state-message_id ? t : 
f);
 
+   switch (state-scissors) {
+   case SCISSORS_UNSET:
+   str = ;
+   break;
+   case SCISSORS_FALSE:
+   str = f;
+   break;
+   case SCISSORS_TRUE:
+   str = t;
+   break;
+   default:
+   die(BUG: invalid value for state-scissors);
+   }
+
+   write_file(am_path(state, scissors), 1, %s, str);
+
if (state-rebasing)
write_file(am_path(state, rebasing), 1, %s, );
else
@@ -798,6 +831,19 @@ static int parse_mail(struct am_state *state, const char 
*mail)
if (state-message_id)
argv_array_push(cp.args, -m);
 
+   switch (state-scissors) {
+   case SCISSORS_UNSET:
+   break;
+   case SCISSORS_FALSE:
+   argv_array_push(cp.args, --no-scissors);
+   break;
+   case SCISSORS_TRUE:
+   argv_array_push(cp.args, --scissors);
+   break;
+   default:
+   die(BUG: invalid value for state-scissors);
+   }
+
argv_array_push(cp.args, am_path(state, msg));
argv_array_push(cp.args, am_path(state, patch));
 
@@ -1551,6 +1597,8 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
{ OPTION_SET_INT, 0, no-keep-cr, keep_cr, NULL,
  N_(do not pass --keep-cr flag to git-mailsplit independent 
of am.keepcr),
  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 0},
+   OPT_BOOL('c', scissors, state.scissors,
+   N_(strip everything before a scissors line)),
OPT_CALLBACK(0, patch-format, patch_format, N_(format),
N_(format the patch(es) are in),
parse_opt_patchformat),
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 38/45] builtin-am: rerere support

2015-08-04 Thread Paul Tan
git-am.sh will call git-rerere at the following events:

* git rerere when a three-way merge fails to record the conflicted
  automerge results. Since 8389b52 (git-rerere: reuse recorded resolve.,
  2006-01-28)

  * Since cb6020b (Teach --[no-]rerere-autoupdate option to merge,
revert and friends, 2009-12-04), git-am.sh supports the
--[no-]rerere-autoupdate option as well, and would pass it to
git-rerere.

* git rerere when --resolved, to record the hand resolution. Since
  f131dd4 (rerere: record (or avoid misrecording) resolved, skipped or
  aborted rebase/am, 2006-12-08)

* git rerere clear when --skip-ing. Since f131dd4 (rerere: record (or
  avoid misrecording) resolved, skipped or aborted rebase/am,
  2006-12-08)

* git rerere clear when --abort-ing. Since 3e5057a (git am --abort,
  2008-07-16)

Re-implement the above in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 25 +
 1 file changed, 25 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index c313e58..33d1f24 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -24,6 +24,7 @@
 #include revision.h
 #include log-tree.h
 #include notes-utils.h
+#include rerere.h
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -114,6 +115,7 @@ struct am_state {
const char *resolvemsg;
int committer_date_is_author_date;
int ignore_date;
+   int allow_rerere_autoupdate;
const char *sign_commit;
int rebasing;
 };
@@ -1312,6 +1314,7 @@ static int fall_back_threeway(const struct am_state 
*state, const char *index_pa
o.verbosity = 0;
 
if (merge_recursive_generic(o, our_tree, his_tree, 1, bases, result)) 
{
+   rerere(state-allow_rerere_autoupdate);
free(his_tree_name);
return error(_(Failed to merge in the changes.));
}
@@ -1531,6 +1534,8 @@ static void am_resolve(struct am_state *state)
die_user_resolve(state);
}
 
+   rerere(0);
+
do_commit(state);
 
am_next(state);
@@ -1631,12 +1636,29 @@ static int clean_index(const unsigned char *head, const 
unsigned char *remote)
 }
 
 /**
+ * Resets rerere's merge resolution metadata.
+ */
+static void am_rerere_clear(void)
+{
+   struct string_list merge_rr = STRING_LIST_INIT_DUP;
+   int fd = setup_rerere(merge_rr, 0);
+
+   if (fd  0)
+   return;
+
+   rerere_clear(merge_rr);
+   string_list_clear(merge_rr, 1);
+}
+
+/**
  * Resume the current am session by skipping the current patch.
  */
 static void am_skip(struct am_state *state)
 {
unsigned char head[GIT_SHA1_RAWSZ];
 
+   am_rerere_clear();
+
if (get_sha1(HEAD, head))
hashcpy(head, EMPTY_TREE_SHA1_BIN);
 
@@ -1694,6 +1716,8 @@ static void am_abort(struct am_state *state)
return;
}
 
+   am_rerere_clear();
+
curr_branch = resolve_refdup(HEAD, 0, curr_head, NULL);
has_curr_head = !is_null_sha1(curr_head);
if (!has_curr_head)
@@ -1823,6 +1847,7 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
N_(lie about committer date)),
OPT_BOOL(0, ignore-date, state.ignore_date,
N_(use current timestamp for author date)),
+   OPT_RERERE_AUTOUPDATE(state.allow_rerere_autoupdate),
{ OPTION_STRING, 'S', gpg-sign, state.sign_commit, 
N_(key-id),
  N_(GPG-sign commits),
  PARSE_OPT_OPTARG, NULL, (intptr_t)  },
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 12/45] builtin-am: don't parse mail when resuming

2015-08-04 Thread Paul Tan
Since 271440e (git-am: make it easier after fixing up an unapplicable
patch., 2005-10-25), when git am is run again after being paused, the
current mail message will not be re-parsed, but instead the contents of
the state directory's patch, msg and author-script files will be used
as-is instead.

Re-implement this in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 34 +-
 1 file changed, 25 insertions(+), 9 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index fd26721..ec579a6 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -776,8 +776,12 @@ static void validate_resume_state(const struct am_state 
*state)
 
 /**
  * Applies all queued mail.
+ *
+ * If `resume` is true, we are resuming. The msg and authorship fields, as
+ * well as the state directory's patch file is used as-is for applying the
+ * patch and committing it.
  */
-static void am_run(struct am_state *state)
+static void am_run(struct am_state *state, int resume)
 {
const char *argv_gc_auto[] = {gc, --auto, NULL};
struct strbuf sb = STRBUF_INIT;
@@ -795,11 +799,16 @@ static void am_run(struct am_state *state)
if (!file_exists(mail))
goto next;
 
-   if (parse_mail(state, mail))
-   goto next; /* mail should be skipped */
+   if (resume) {
+   validate_resume_state(state);
+   resume = 0;
+   } else {
+   if (parse_mail(state, mail))
+   goto next; /* mail should be skipped */
 
-   write_author_script(state);
-   write_commit_msg(state);
+   write_author_script(state);
+   write_commit_msg(state);
+   }
 
printf_ln(_(Applying: %.*s), linelen(state-msg), state-msg);
 
@@ -855,7 +864,7 @@ static void am_resolve(struct am_state *state)
do_commit(state);
 
am_next(state);
-   am_run(state);
+   am_run(state, 0);
 }
 
 /**
@@ -875,6 +884,7 @@ static int parse_opt_patchformat(const struct option *opt, 
const char *arg, int
 
 enum resume_mode {
RESUME_FALSE = 0,
+   RESUME_APPLY,
RESUME_RESOLVED
 };
 
@@ -927,9 +937,12 @@ int cmd_am(int argc, const char **argv, const char *prefix)
if (read_index_preload(the_index, NULL)  0)
die(_(failed to read the index));
 
-   if (am_in_progress(state))
+   if (am_in_progress(state)) {
+   if (resume == RESUME_FALSE)
+   resume = RESUME_APPLY;
+
am_load(state);
-   else {
+   } else {
struct argv_array paths = ARGV_ARRAY_INIT;
int i;
 
@@ -950,7 +963,10 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 
switch (resume) {
case RESUME_FALSE:
-   am_run(state);
+   am_run(state, 0);
+   break;
+   case RESUME_APPLY:
+   am_run(state, 1);
break;
case RESUME_RESOLVED:
am_resolve(state);
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 17/45] builtin-am: exit with user friendly message on failure

2015-08-04 Thread Paul Tan
Since ced9456 (Give the user a hint for how to continue in the case that
git-am fails because it requires user intervention, 2006-05-02), git-am
prints additional information on how the user can re-invoke git-am to
resume patch application after resolving the failure. Re-implement this
through the die_user_resolve() function.

Since cc12005 (Make git rebase interactive help match documentation.,
2006-05-13), git-am supports the --resolvemsg option which is used by
git-rebase to override the message printed out when git-am fails.
Re-implement this option.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 30 ++
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index 0875e69..8b8f2da 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -83,6 +83,7 @@ struct am_state {
 
/* various operating modes and command line options */
int quiet;
+   const char *resolvemsg;
 };
 
 /**
@@ -647,6 +648,25 @@ static int index_has_changes(struct strbuf *sb)
 }
 
 /**
+ * Dies with a user-friendly message on how to proceed after resolving the
+ * problem. This message can be overridden with state-resolvemsg.
+ */
+static void NORETURN die_user_resolve(const struct am_state *state)
+{
+   if (state-resolvemsg) {
+   printf_ln(%s, state-resolvemsg);
+   } else {
+   const char *cmdline = git am;
+
+   printf_ln(_(When you have resolved this problem, run \%s 
--continue\.), cmdline);
+   printf_ln(_(If you prefer to skip this patch, run \%s 
--skip\ instead.), cmdline);
+   printf_ln(_(To restore the original branch and stop patching, 
run \%s --abort\.), cmdline);
+   }
+
+   exit(128);
+}
+
+/**
  * Parses `mail` using git-mailinfo, extracting its patch and authorship info.
  * state-msg will be set to the patch message. state-author_name,
  * state-author_email and state-author_date will be set to the patch author's
@@ -706,7 +726,7 @@ static int parse_mail(struct am_state *state, const char 
*mail)
 
if (is_empty_file(am_path(state, patch))) {
printf_ln(_(Patch is empty. Was it split wrong?));
-   exit(128);
+   die_user_resolve(state);
}
 
strbuf_addstr(msg, \n\n);
@@ -871,7 +891,7 @@ static void am_run(struct am_state *state, int resume)
printf_ln(_(The copy of the patch that failed 
is found in: %s),
am_path(state, patch));
 
-   exit(128);
+   die_user_resolve(state);
}
 
do_commit(state);
@@ -899,13 +919,13 @@ static void am_resolve(struct am_state *state)
printf_ln(_(No changes - did you forget to use 'git add'?\n
If there is nothing left to stage, chances are that 
something else\n
already introduced the same changes; you might want to 
skip this patch.));
-   exit(128);
+   die_user_resolve(state);
}
 
if (unmerged_cache()) {
printf_ln(_(You still have unmerged paths in your index.\n
Did you forget to use 'git add'?));
-   exit(128);
+   die_user_resolve(state);
}
 
do_commit(state);
@@ -1133,6 +1153,8 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
OPT_CALLBACK(0, patch-format, patch_format, N_(format),
N_(format the patch(es) are in),
parse_opt_patchformat),
+   OPT_STRING(0, resolvemsg, state.resolvemsg, NULL,
+   N_(override error message when patch failure occurs)),
OPT_CMDMODE(0, continue, resume,
N_(continue applying patches after resolving a 
conflict),
RESUME_RESOLVED),
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 26/45] builtin-am: implement --[no-]message-id, am.messageid

2015-08-04 Thread Paul Tan
Since a078f73 (git-am: add --message-id/--no-message-id, 2014-11-25),
git-am.sh supported the --[no-]message-id options, and the
am.messageid setting which specifies the default option.

--[no-]message-id tells git-am whether or not the -m option should be
passed to git-mailinfo.

Re-implement this option in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index 68dca2e..8e97839 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -98,6 +98,7 @@ struct am_state {
int signoff;
int utf8;
int keep; /* enum keep_type */
+   int message_id;
const char *resolvemsg;
int rebasing;
 };
@@ -116,6 +117,8 @@ static void am_state_init(struct am_state *state, const 
char *dir)
state-prec = 4;
 
state-utf8 = 1;
+
+   git_config_get_bool(am.messageid, state-message_id);
 }
 
 /**
@@ -388,6 +391,9 @@ static void am_load(struct am_state *state)
else
state-keep = KEEP_FALSE;
 
+   read_state_file(sb, state, messageid, 1);
+   state-message_id = !strcmp(sb.buf, t);
+
state-rebasing = !!file_exists(am_path(state, rebasing));
 
strbuf_release(sb);
@@ -596,6 +602,8 @@ static void am_setup(struct am_state *state, enum 
patch_format patch_format,
 
write_file(am_path(state, keep), 1, %s, str);
 
+   write_file(am_path(state, messageid), 1, state-message_id ? t : 
f);
+
if (state-rebasing)
write_file(am_path(state, rebasing), 1, %s, );
else
@@ -777,6 +785,9 @@ static int parse_mail(struct am_state *state, const char 
*mail)
die(BUG: invalid value for state-keep);
}
 
+   if (state-message_id)
+   argv_array_push(cp.args, -m);
+
argv_array_push(cp.args, am_path(state, msg));
argv_array_push(cp.args, am_path(state, patch));
 
@@ -1521,6 +1532,8 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
N_(pass -k flag to git-mailinfo), KEEP_TRUE),
OPT_SET_INT(0, keep-non-patch, state.keep,
N_(pass -b flag to git-mailinfo), KEEP_NON_PATCH),
+   OPT_BOOL('m', message-id, state.message_id,
+   N_(pass -m flag to git-mailinfo)),
OPT_CALLBACK(0, patch-format, patch_format, N_(format),
N_(format the patch(es) are in),
parse_opt_patchformat),
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 31/45] builtin-am: implement --committer-date-is-author-date

2015-08-04 Thread Paul Tan
Since 3f01ad6 (am: Add --committer-date-is-author-date option,
2009-01-22), git-am.sh implemented the --committer-date-is-author-date
option, which tells git-am to use the timestamp recorded in the email
message as both author and committer date.

Re-implement this option in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index 84d3e05..1561580 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -108,6 +108,7 @@ struct am_state {
int scissors; /* enum scissors_type */
struct argv_array git_apply_opts;
const char *resolvemsg;
+   int committer_date_is_author_date;
int ignore_date;
int rebasing;
 };
@@ -1221,6 +1222,10 @@ static void do_commit(const struct am_state *state)
state-ignore_date ? NULL : state-author_date,
IDENT_STRICT);
 
+   if (state-committer_date_is_author_date)
+   setenv(GIT_COMMITTER_DATE,
+   state-ignore_date ?  : state-author_date, 1);
+
if (commit_tree(state-msg, state-msg_len, tree, parents, commit,
author, NULL))
die(_(failed to write commit object));
@@ -1663,6 +1668,9 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
OPT_CMDMODE(0, abort, resume,
N_(restore the original branch and abort the patching 
operation.),
RESUME_ABORT),
+   OPT_BOOL(0, committer-date-is-author-date,
+   state.committer_date_is_author_date,
+   N_(lie about committer date)),
OPT_BOOL(0, ignore-date, state.ignore_date,
N_(use current timestamp for author date)),
OPT_HIDDEN_BOOL(0, rebasing, state.rebasing,
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 18/45] builtin-am: implement -s/--signoff

2015-08-04 Thread Paul Tan
Since d1c5f2a (Add git-am, applymbox replacement., 2005-10-07), git-am
supported the --signoff option which will append a signoff at the end of
the commit messsage. Re-implement this feature in parse_mail() by
calling append_signoff() if the option is set.

Signed-off-by: Paul Tan pyoka...@gmail.com
---

Notes:
v7

* Having a field named append_signoff takes up a lot of horizontal
  space when referring to it. Shorten the name to just signoff.

 builtin/am.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index 8b8f2da..12952cf 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -18,6 +18,7 @@
 #include diffcore.h
 #include unpack-trees.h
 #include branch.h
+#include sequencer.h
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -83,6 +84,7 @@ struct am_state {
 
/* various operating modes and command line options */
int quiet;
+   int signoff;
const char *resolvemsg;
 };
 
@@ -353,6 +355,9 @@ static void am_load(struct am_state *state)
read_state_file(sb, state, quiet, 1);
state-quiet = !strcmp(sb.buf, t);
 
+   read_state_file(sb, state, sign, 1);
+   state-signoff = !strcmp(sb.buf, t);
+
strbuf_release(sb);
 }
 
@@ -533,6 +538,8 @@ static void am_setup(struct am_state *state, enum 
patch_format patch_format,
 
write_file(am_path(state, quiet), 1, state-quiet ? t : f);
 
+   write_file(am_path(state, sign), 1, state-signoff ? t : f);
+
if (!get_sha1(HEAD, curr_head)) {
write_file(am_path(state, abort-safety), 1, %s, 
sha1_to_hex(curr_head));
update_ref(am, ORIG_HEAD, curr_head, NULL, 0, 
UPDATE_REFS_DIE_ON_ERR);
@@ -734,6 +741,9 @@ static int parse_mail(struct am_state *state, const char 
*mail)
die_errno(_(could not read '%s'), am_path(state, msg));
stripspace(msg, 0);
 
+   if (state-signoff)
+   append_signoff(msg, 0, 0);
+
assert(!state-author_name);
state-author_name = strbuf_detach(author_name, NULL);
 
@@ -1150,6 +1160,8 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
 
struct option options[] = {
OPT__QUIET(state.quiet, N_(be quiet)),
+   OPT_BOOL('s', signoff, state.signoff,
+   N_(add a Signed-off-by line to the commit message)),
OPT_CALLBACK(0, patch-format, patch_format, N_(format),
N_(format the patch(es) are in),
parse_opt_patchformat),
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 15/45] builtin-am: reject patches when there's a session in progress

2015-08-04 Thread Paul Tan
Since d1c5f2a (Add git-am, applymbox replacement., 2005-10-07), git-am
would error out if the user gave it mbox(s) on the command-line, but
there was a session in progress.

Since c95b138 (Fix git-am safety checks, 2006-09-15), git-am would
detect if the user attempted to feed it a mbox via stdin, by checking if
stdin is not a tty and there is no resume command given.

Re-implement the above two safety checks.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index 6c24d07..d4b4b86 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1148,6 +1148,21 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
die(_(failed to read the index));
 
if (am_in_progress(state)) {
+   /*
+* Catch user error to feed us patches when there is a session
+* in progress:
+*
+* 1. mbox path(s) are provided on the command-line.
+* 2. stdin is not a tty: the user is trying to feed us a patch
+*from standard input. This is somewhat unreliable -- stdin
+*could be /dev/null for example and the caller did not
+*intend to feed us a patch but wanted to continue
+*unattended.
+*/
+   if (argc || (resume == RESUME_FALSE  !isatty(0)))
+   die(_(previous rebase directory %s still exists but 
mbox given.),
+   state.dir);
+
if (resume == RESUME_FALSE)
resume = RESUME_APPLY;
 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 35/45] builtin-am: invoke applypatch-msg hook

2015-08-04 Thread Paul Tan
Since d1c5f2a (Add git-am, applymbox replacement., 2005-10-07),
git-am.sh will invoke the applypatch-msg hooks just after extracting the
patch message. If the applypatch-msg hook exits with a non-zero status,
git-am.sh abort before even applying the patch to the index.

Re-implement this in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 24 
 1 file changed, 24 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index 7d7f91d..f0e3aab 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -456,6 +456,27 @@ static void am_destroy(const struct am_state *state)
 }
 
 /**
+ * Runs applypatch-msg hook. Returns its exit code.
+ */
+static int run_applypatch_msg_hook(struct am_state *state)
+{
+   int ret;
+
+   assert(state-msg);
+   ret = run_hook_le(NULL, applypatch-msg, am_path(state, 
final-commit), NULL);
+
+   if (!ret) {
+   free(state-msg);
+   state-msg = NULL;
+   if (read_commit_msg(state)  0)
+   die(_('%s' was deleted by the applypatch-msg hook),
+   am_path(state, final-commit));
+   }
+
+   return ret;
+}
+
+/**
  * Runs post-rewrite hook. Returns it exit code.
  */
 static int run_post_rewrite_hook(const struct am_state *state)
@@ -1420,6 +1441,9 @@ static void am_run(struct am_state *state, int resume)
write_commit_msg(state);
}
 
+   if (run_applypatch_msg_hook(state))
+   exit(1);
+
say(state, stdout, _(Applying: %.*s), linelen(state-msg), 
state-msg);
 
apply_status = run_apply(state, NULL);
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 24/45] builtin-am: implement -u/--utf8

2015-08-04 Thread Paul Tan
Since d1c5f2a (Add git-am, applymbox replacement., 2005-10-07),
git-am.sh supported the -u,--utf8 option. If set, the -u option will be
passed to git-mailinfo to re-code the commit log message and authorship
in the charset specified by i18n.commitencoding. If unset, the -n option
will be passed to git-mailinfo, which disables the re-encoding.

Since d84029b (--utf8 is now default for 'git-am', 2007-01-08), --utf8
is specified by default in git-am.sh.

Re-implement the above in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index 47dd4c7..528b2c9 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -90,6 +90,7 @@ struct am_state {
int threeway;
int quiet;
int signoff;
+   int utf8;
const char *resolvemsg;
int rebasing;
 };
@@ -106,6 +107,8 @@ static void am_state_init(struct am_state *state, const 
char *dir)
state-dir = xstrdup(dir);
 
state-prec = 4;
+
+   state-utf8 = 1;
 }
 
 /**
@@ -367,6 +370,9 @@ static void am_load(struct am_state *state)
read_state_file(sb, state, sign, 1);
state-signoff = !strcmp(sb.buf, t);
 
+   read_state_file(sb, state, utf8, 1);
+   state-utf8 = !strcmp(sb.buf, t);
+
state-rebasing = !!file_exists(am_path(state, rebasing));
 
strbuf_release(sb);
@@ -556,6 +562,8 @@ static void am_setup(struct am_state *state, enum 
patch_format patch_format,
 
write_file(am_path(state, sign), 1, state-signoff ? t : f);
 
+   write_file(am_path(state, utf8), 1, state-utf8 ? t : f);
+
if (state-rebasing)
write_file(am_path(state, rebasing), 1, %s, );
else
@@ -722,6 +730,7 @@ static int parse_mail(struct am_state *state, const char 
*mail)
cp.out = xopen(am_path(state, info), O_WRONLY | O_CREAT, 0777);
 
argv_array_push(cp.args, mailinfo);
+   argv_array_push(cp.args, state-utf8 ? -u : -n);
argv_array_push(cp.args, am_path(state, msg));
argv_array_push(cp.args, am_path(state, patch));
 
@@ -1460,6 +1469,8 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
OPT__QUIET(state.quiet, N_(be quiet)),
OPT_BOOL('s', signoff, state.signoff,
N_(add a Signed-off-by line to the commit message)),
+   OPT_BOOL('u', utf8, state.utf8,
+   N_(recode into utf8 (default))),
OPT_CALLBACK(0, patch-format, patch_format, N_(format),
N_(format the patch(es) are in),
parse_opt_patchformat),
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 45/45] builtin-am: remove redirection to git-am.sh

2015-08-04 Thread Paul Tan
At the beginning of the rewrite of git-am.sh to C, in order to not break
existing test scripts that depended on a functional git-am, a
redirection to git-am.sh was introduced that would activate if the
environment variable _GIT_USE_BUILTIN_AM was not defined.

Now that all of git-am.sh's functionality has been re-implemented in
builtin/am.c, remove this redirection, and retire git-am.sh into
contrib/examples/.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 Makefile|  1 -
 builtin/am.c| 15 ---
 git-am.sh = contrib/examples/git-am.sh |  0
 git.c   |  7 +--
 4 files changed, 1 insertion(+), 22 deletions(-)
 rename git-am.sh = contrib/examples/git-am.sh (100%)

diff --git a/Makefile b/Makefile
index da451f8..e39ca6c 100644
--- a/Makefile
+++ b/Makefile
@@ -467,7 +467,6 @@ TEST_PROGRAMS_NEED_X =
 # interactive shell sessions without exporting it.
 unexport CDPATH
 
-SCRIPT_SH += git-am.sh
 SCRIPT_SH += git-bisect.sh
 SCRIPT_SH += git-difftool--helper.sh
 SCRIPT_SH += git-filter-branch.sh
diff --git a/builtin/am.c b/builtin/am.c
index 1ff74ac..84d57d4 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -2221,21 +2221,6 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
OPT_END()
};
 
-   /*
-* NEEDSWORK: Once all the features of git-am.sh have been
-* re-implemented in builtin/am.c, this preamble can be removed.
-*/
-   if (!getenv(_GIT_USE_BUILTIN_AM)) {
-   const char *path = mkpath(%s/git-am, git_exec_path());
-
-   if (sane_execvp(path, (char **)argv)  0)
-   die_errno(could not exec %s, path);
-   } else {
-   prefix = setup_git_directory();
-   trace_repo_setup(prefix);
-   setup_work_tree();
-   }
-
git_config(git_default_config, NULL);
 
am_state_init(state, git_path(rebase-apply));
diff --git a/git-am.sh b/contrib/examples/git-am.sh
similarity index 100%
rename from git-am.sh
rename to contrib/examples/git-am.sh
diff --git a/git.c b/git.c
index 38d9ad5..5feba41 100644
--- a/git.c
+++ b/git.c
@@ -370,12 +370,7 @@ static int run_builtin(struct cmd_struct *p, int argc, 
const char **argv)
 
 static struct cmd_struct commands[] = {
{ add, cmd_add, RUN_SETUP | NEED_WORK_TREE },
-   /*
-* NEEDSWORK: Once the redirection to git-am.sh in builtin/am.c has
-* been removed, this entry should be changed to
-* RUN_SETUP | NEED_WORK_TREE
-*/
-   { am, cmd_am },
+   { am, cmd_am, RUN_SETUP | NEED_WORK_TREE },
{ annotate, cmd_annotate, RUN_SETUP },
{ apply, cmd_apply, RUN_SETUP_GENTLY },
{ archive, cmd_archive },
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 20/45] builtin-am: implement --3way

2015-08-04 Thread Paul Tan
Since d1c5f2a (Add git-am, applymbox replacement., 2005-10-07),
git-am.sh supported the --3way option, and if set, would attempt to do a
3-way merge if the initial patch application fails.

Since 5d86861 (am -3: list the paths that needed 3-way fallback,
2012-03-28), in a 3-way merge git-am.sh would list the paths that needed
3-way fallback, so that the user can review them more carefully to spot
mismerges.

Re-implement the above in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---

Notes:
v7

* As support for am.threeWay was removed in master, this patch now
  does not implement am.threeWay as well.

 builtin/am.c | 154 +--
 1 file changed, 150 insertions(+), 4 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index 12952cf..a5d5e8c 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -19,6 +19,8 @@
 #include unpack-trees.h
 #include branch.h
 #include sequencer.h
+#include revision.h
+#include merge-recursive.h
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -83,6 +85,7 @@ struct am_state {
int prec;
 
/* various operating modes and command line options */
+   int threeway;
int quiet;
int signoff;
const char *resolvemsg;
@@ -352,6 +355,9 @@ static void am_load(struct am_state *state)
 
read_commit_msg(state);
 
+   read_state_file(sb, state, threeway, 1);
+   state-threeway = !strcmp(sb.buf, t);
+
read_state_file(sb, state, quiet, 1);
state-quiet = !strcmp(sb.buf, t);
 
@@ -536,6 +542,8 @@ static void am_setup(struct am_state *state, enum 
patch_format patch_format,
die(_(Failed to split patches.));
}
 
+   write_file(am_path(state, threeway), 1, state-threeway ? t : f);
+
write_file(am_path(state, quiet), 1, state-quiet ? t : f);
 
write_file(am_path(state, sign), 1, state-signoff ? t : f);
@@ -766,16 +774,34 @@ finish:
 }
 
 /**
- * Applies current patch with git-apply. Returns 0 on success, -1 otherwise.
+ * Applies current patch with git-apply. Returns 0 on success, -1 otherwise. If
+ * `index_file` is not NULL, the patch will be applied to that index.
  */
-static int run_apply(const struct am_state *state)
+static int run_apply(const struct am_state *state, const char *index_file)
 {
struct child_process cp = CHILD_PROCESS_INIT;
 
cp.git_cmd = 1;
 
+   if (index_file)
+   argv_array_pushf(cp.env_array, GIT_INDEX_FILE=%s, 
index_file);
+
+   /*
+* If we are allowed to fall back on 3-way merge, don't give false
+* errors during the initial attempt.
+*/
+   if (state-threeway  !index_file) {
+   cp.no_stdout = 1;
+   cp.no_stderr = 1;
+   }
+
argv_array_push(cp.args, apply);
-   argv_array_push(cp.args, --index);
+
+   if (index_file)
+   argv_array_push(cp.args, --cached);
+   else
+   argv_array_push(cp.args, --index);
+
argv_array_push(cp.args, am_path(state, patch));
 
if (run_command(cp))
@@ -783,8 +809,106 @@ static int run_apply(const struct am_state *state)
 
/* Reload index as git-apply will have modified it. */
discard_cache();
+   read_cache_from(index_file ? index_file : get_index_file());
+
+   return 0;
+}
+
+/**
+ * Builds an index that contains just the blobs needed for a 3way merge.
+ */
+static int build_fake_ancestor(const struct am_state *state, const char 
*index_file)
+{
+   struct child_process cp = CHILD_PROCESS_INIT;
+
+   cp.git_cmd = 1;
+   argv_array_push(cp.args, apply);
+   argv_array_pushf(cp.args, --build-fake-ancestor=%s, index_file);
+   argv_array_push(cp.args, am_path(state, patch));
+
+   if (run_command(cp))
+   return -1;
+
+   return 0;
+}
+
+/**
+ * Attempt a threeway merge, using index_path as the temporary index.
+ */
+static int fall_back_threeway(const struct am_state *state, const char 
*index_path)
+{
+   unsigned char orig_tree[GIT_SHA1_RAWSZ], his_tree[GIT_SHA1_RAWSZ],
+ our_tree[GIT_SHA1_RAWSZ];
+   const unsigned char *bases[1] = {orig_tree};
+   struct merge_options o;
+   struct commit *result;
+   char *his_tree_name;
+
+   if (get_sha1(HEAD, our_tree)  0)
+   hashcpy(our_tree, EMPTY_TREE_SHA1_BIN);
+
+   if (build_fake_ancestor(state, index_path))
+   return error(could not build fake ancestor);
+
+   discard_cache();
+   read_cache_from(index_path);
+
+   if (write_index_as_tree(orig_tree, the_index, index_path, 0, NULL))
+   return error(_(Repository lacks necessary blobs to fall back 
on 3-way merge.));
+
+   say(state, stdout, _(Using index info to reconstruct a base tree...));
+
+   if (!state-quiet) {
+   /*
+* List paths that needed 3-way fallback, so that the user can

[PATCH v7 40/45] builtin-am: support and auto-detect StGit series files

2015-08-04 Thread Paul Tan
Since c574e68 (git-am foreign patch support: StGIT support, 2009-05-27),
git-am.sh is able to read a single StGit series file and, for each StGit
patch listed in the file, convert the StGit patch into a RFC2822 mail
patch suitable for parsing with git-mailinfo, and queue them in the
state directory for applying.

Since 15ced75 (git-am foreign patch support: autodetect some patch
formats, 2009-05-27), git-am.sh is able to auto-detect StGit series
files by checking to see if the file starts with the string:

# This series applies on GIT commit

Re-implement the above in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 59 ++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/builtin/am.c b/builtin/am.c
index d82d07e..3c2ec15 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -80,7 +80,8 @@ static int str_isspace(const char *str)
 enum patch_format {
PATCH_FORMAT_UNKNOWN = 0,
PATCH_FORMAT_MBOX,
-   PATCH_FORMAT_STGIT
+   PATCH_FORMAT_STGIT,
+   PATCH_FORMAT_STGIT_SERIES
 };
 
 enum keep_type {
@@ -650,6 +651,11 @@ static int detect_patch_format(const char **paths)
goto done;
}
 
+   if (starts_with(l1.buf, # This series applies on GIT commit)) {
+   ret = PATCH_FORMAT_STGIT_SERIES;
+   goto done;
+   }
+
strbuf_reset(l2);
strbuf_getline_crlf(l2, fp);
strbuf_reset(l3);
@@ -801,6 +807,53 @@ static int stgit_patch_to_mail(FILE *out, FILE *in, int 
keep_cr)
 }
 
 /**
+ * This function only supports a single StGit series file in `paths`.
+ *
+ * Given an StGit series file, converts the StGit patches in the series into
+ * RFC2822 messages suitable for parsing with git-mailinfo, and queues them in
+ * the state directory.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int split_mail_stgit_series(struct am_state *state, const char **paths,
+   int keep_cr)
+{
+   const char *series_dir;
+   char *series_dir_buf;
+   FILE *fp;
+   struct argv_array patches = ARGV_ARRAY_INIT;
+   struct strbuf sb = STRBUF_INIT;
+   int ret;
+
+   if (!paths[0] || paths[1])
+   return error(_(Only one StGIT patch series can be applied at 
once));
+
+   series_dir_buf = xstrdup(*paths);
+   series_dir = dirname(series_dir_buf);
+
+   fp = fopen(*paths, r);
+   if (!fp)
+   return error(_(could not open '%s' for reading: %s), *paths,
+   strerror(errno));
+
+   while (!strbuf_getline(sb, fp, '\n')) {
+   if (*sb.buf == '#')
+   continue; /* skip comment lines */
+
+   argv_array_push(patches, mkpath(%s/%s, series_dir, sb.buf));
+   }
+
+   fclose(fp);
+   strbuf_release(sb);
+   free(series_dir_buf);
+
+   ret = split_mail_conv(stgit_patch_to_mail, state, patches.argv, 
keep_cr);
+
+   argv_array_clear(patches);
+   return ret;
+}
+
+/**
  * Splits a list of files/directories into individual email patches. Each path
  * in `paths` must be a file/directory that is formatted according to
  * `patch_format`.
@@ -830,6 +883,8 @@ static int split_mail(struct am_state *state, enum 
patch_format patch_format,
return split_mail_mbox(state, paths, keep_cr);
case PATCH_FORMAT_STGIT:
return split_mail_conv(stgit_patch_to_mail, state, paths, 
keep_cr);
+   case PATCH_FORMAT_STGIT_SERIES:
+   return split_mail_stgit_series(state, paths, keep_cr);
default:
die(BUG: invalid patch_format);
}
@@ -1880,6 +1935,8 @@ static int parse_opt_patchformat(const struct option 
*opt, const char *arg, int
*opt_value = PATCH_FORMAT_MBOX;
else if (!strcmp(arg, stgit))
*opt_value = PATCH_FORMAT_STGIT;
+   else if (!strcmp(arg, stgit-series))
+   *opt_value = PATCH_FORMAT_STGIT_SERIES;
else
return error(_(Invalid value for --patch-format: %s), arg);
return 0;
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 43/45] builtin-am: implement legacy -b/--binary option

2015-08-04 Thread Paul Tan
The -b/--binary option was initially implemented in 087b674 (git-am:
--binary; document --resume and --binary., 2005-11-16). The option will
pass the --binary flag to git-apply to allow it to apply binary patches.

However, in 2b6eef9 (Make apply --binary a no-op., 2006-09-06), --binary
was been made a no-op in git-apply. Following that, since cb3a160
(git-am: ignore --binary option, 2008-08-09), the --binary option in
git-am is ignored as well.

In 6c15a1c (am: officially deprecate -b/--binary option, 2012-03-13),
the --binary option was tweaked to its present behavior: when set, the
message:

The -b/--binary option has been a no-op for long time, and it
will be removed. Please do not use it anymore.

will be printed.

Re-implement this in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index 589199f..3c50392 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -2126,6 +2126,7 @@ enum resume_mode {
 int cmd_am(int argc, const char **argv, const char *prefix)
 {
struct am_state state;
+   int binary = -1;
int keep_cr = -1;
int patch_format = PATCH_FORMAT_UNKNOWN;
enum resume_mode resume = RESUME_FALSE;
@@ -2139,6 +2140,8 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
struct option options[] = {
OPT_BOOL('i', interactive, state.interactive,
N_(run interactively)),
+   OPT_HIDDEN_BOOL('b', binary, binary,
+   N_((historical option -- no-op)),
OPT_BOOL('3', 3way, state.threeway,
N_(allow fall back on 3way merging if needed)),
OPT__QUIET(state.quiet, N_(be quiet)),
@@ -2239,6 +2242,10 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
 
argc = parse_options(argc, argv, prefix, options, usage, 0);
 
+   if (binary = 0)
+   fprintf_ln(stderr, _(The -b/--binary option has been a no-op 
for long time, and\n
+   it will be removed. Please do not use it 
anymore.));
+
if (read_index_preload(the_index, NULL)  0)
die(_(failed to read the index));
 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 11/45] builtin-am: implement --resolved/--continue

2015-08-04 Thread Paul Tan
Since 0c15cc9 (git-am: --resolved., 2005-11-16), git-am supported
resuming from a failed patch application. The user will manually apply
the patch, and the run git am --resolved which will then commit the
resulting index. Re-implement this feature by introducing am_resolve().

Since it makes no sense for the user to run am --resolved when there is
no session in progress, we error out in this case.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 72 +++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/builtin/am.c b/builtin/am.c
index 537ad62..fd26721 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -760,6 +760,21 @@ static void do_commit(const struct am_state *state)
 }
 
 /**
+ * Validates the am_state for resuming -- the msg and authorship fields must
+ * be filled up.
+ */
+static void validate_resume_state(const struct am_state *state)
+{
+   if (!state-msg)
+   die(_(cannot resume: %s does not exist.),
+   am_path(state, final-commit));
+
+   if (!state-author_name || !state-author_email || !state-author_date)
+   die(_(cannot resume: %s does not exist.),
+   am_path(state, author-script));
+}
+
+/**
  * Applies all queued mail.
  */
 static void am_run(struct am_state *state)
@@ -814,6 +829,36 @@ next:
 }
 
 /**
+ * Resume the current am session after patch application failure. The user did
+ * all the hard work, and we do not have to do any patch application. Just
+ * trust and commit what the user has in the index and working tree.
+ */
+static void am_resolve(struct am_state *state)
+{
+   validate_resume_state(state);
+
+   printf_ln(_(Applying: %.*s), linelen(state-msg), state-msg);
+
+   if (!index_has_changes(NULL)) {
+   printf_ln(_(No changes - did you forget to use 'git add'?\n
+   If there is nothing left to stage, chances are that 
something else\n
+   already introduced the same changes; you might want to 
skip this patch.));
+   exit(128);
+   }
+
+   if (unmerged_cache()) {
+   printf_ln(_(You still have unmerged paths in your index.\n
+   Did you forget to use 'git add'?));
+   exit(128);
+   }
+
+   do_commit(state);
+
+   am_next(state);
+   am_run(state);
+}
+
+/**
  * parse_options() callback that validates and sets opt-value to the
  * PATCH_FORMAT_* enum value corresponding to `arg`.
  */
@@ -828,13 +873,20 @@ static int parse_opt_patchformat(const struct option 
*opt, const char *arg, int
return 0;
 }
 
+enum resume_mode {
+   RESUME_FALSE = 0,
+   RESUME_RESOLVED
+};
+
 int cmd_am(int argc, const char **argv, const char *prefix)
 {
struct am_state state;
int patch_format = PATCH_FORMAT_UNKNOWN;
+   enum resume_mode resume = RESUME_FALSE;
 
const char * const usage[] = {
N_(git am [options] [(mbox|Maildir)...]),
+   N_(git am [options] --continue),
NULL
};
 
@@ -842,6 +894,12 @@ int cmd_am(int argc, const char **argv, const char *prefix)
OPT_CALLBACK(0, patch-format, patch_format, N_(format),
N_(format the patch(es) are in),
parse_opt_patchformat),
+   OPT_CMDMODE(0, continue, resume,
+   N_(continue applying patches after resolving a 
conflict),
+   RESUME_RESOLVED),
+   OPT_CMDMODE('r', resolved, resume,
+   N_(synonyms for --continue),
+   RESUME_RESOLVED),
OPT_END()
};
 
@@ -875,6 +933,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
struct argv_array paths = ARGV_ARRAY_INIT;
int i;
 
+   if (resume)
+   die(_(Resolve operation not in progress, we are not 
resuming.));
+
for (i = 0; i  argc; i++) {
if (is_absolute_path(argv[i]) || !prefix)
argv_array_push(paths, argv[i]);
@@ -887,7 +948,16 @@ int cmd_am(int argc, const char **argv, const char *prefix)
argv_array_clear(paths);
}
 
-   am_run(state);
+   switch (resume) {
+   case RESUME_FALSE:
+   am_run(state);
+   break;
+   case RESUME_RESOLVED:
+   am_resolve(state);
+   break;
+   default:
+   die(BUG: invalid resume value);
+   }
 
am_state_release(state);
 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 09/45] builtin-am: implement committing applied patch

2015-08-04 Thread Paul Tan
Implement do_commit(), which commits the index which contains the
results of applying the patch, along with the extracted commit message
and authorship information.

Since 29b6754 (am: remove rebase-apply directory before gc, 2010-02-22),
git gc --auto is also invoked to pack the loose objects that are created
from making the commits.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 55 +++
 1 file changed, 51 insertions(+), 4 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index 1f198e4..a2811b6 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -11,6 +11,9 @@
 #include run-command.h
 #include quote.h
 #include lockfile.h
+#include cache-tree.h
+#include refs.h
+#include commit.h
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -674,10 +677,56 @@ static int run_apply(const struct am_state *state)
 }
 
 /**
+ * Commits the current index with state-msg as the commit message and
+ * state-author_name, state-author_email and state-author_date as the author
+ * information.
+ */
+static void do_commit(const struct am_state *state)
+{
+   unsigned char tree[GIT_SHA1_RAWSZ], parent[GIT_SHA1_RAWSZ],
+ commit[GIT_SHA1_RAWSZ];
+   unsigned char *ptr;
+   struct commit_list *parents = NULL;
+   const char *reflog_msg, *author;
+   struct strbuf sb = STRBUF_INIT;
+
+   if (write_cache_as_tree(tree, 0, NULL))
+   die(_(git write-tree failed to write a tree));
+
+   if (!get_sha1_commit(HEAD, parent)) {
+   ptr = parent;
+   commit_list_insert(lookup_commit(parent), parents);
+   } else {
+   ptr = NULL;
+   fprintf_ln(stderr, _(applying to an empty history));
+   }
+
+   author = fmt_ident(state-author_name, state-author_email,
+   state-author_date, IDENT_STRICT);
+
+   if (commit_tree(state-msg, state-msg_len, tree, parents, commit,
+   author, NULL))
+   die(_(failed to write commit object));
+
+   reflog_msg = getenv(GIT_REFLOG_ACTION);
+   if (!reflog_msg)
+   reflog_msg = am;
+
+   strbuf_addf(sb, %s: %.*s, reflog_msg, linelen(state-msg),
+   state-msg);
+
+   update_ref(sb.buf, HEAD, commit, ptr, 0, UPDATE_REFS_DIE_ON_ERR);
+
+   strbuf_release(sb);
+}
+
+/**
  * Applies all queued mail.
  */
 static void am_run(struct am_state *state)
 {
+   const char *argv_gc_auto[] = {gc, --auto, NULL};
+
refresh_and_write_cache();
 
while (state-cur = state-last) {
@@ -709,16 +758,14 @@ static void am_run(struct am_state *state)
exit(128);
}
 
-   /*
-* NEEDSWORK: After the patch has been applied to the index
-* with git-apply, we need to make commit as well.
-*/
+   do_commit(state);
 
 next:
am_next(state);
}
 
am_destroy(state);
+   run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
 }
 
 /**
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 44/45] builtin-am: check for valid committer ident

2015-08-04 Thread Paul Tan
When commit_tree() is called, if the user does not have an explicit
committer ident configured, it will attempt to construct a default
committer ident based on the user's and system's info (e.g. gecos field,
hostname etc.) However, if a default committer ident is unable to be
constructed, commit_tree() will die(), but at this point of git-am's
execution, there will already be changes made to the index and work
tree.

This can be confusing to new users, and as such since d64e6b0 (Keep
Porcelainish from failing by broken ident after making changes.,
2006-02-18) git-am.sh will check to see if the committer ident has been
configured, or a default one can be constructed, before even starting to
apply patches.

Re-implement this in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index 3c50392..1ff74ac 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -2246,6 +2246,9 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
fprintf_ln(stderr, _(The -b/--binary option has been a no-op 
for long time, and\n
it will be removed. Please do not use it 
anymore.));
 
+   /* Ensure a valid committer ident can be constructed */
+   git_committer_info(IDENT_STRICT);
+
if (read_index_preload(the_index, NULL)  0)
die(_(failed to read the index));
 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 29/45] builtin-am: pass git-apply's options to git-apply

2015-08-04 Thread Paul Tan
git-am.sh recognizes some of git-apply's options, and would pass them to
git-apply:

* --whitespace, since 8c31cb8 (git-am: --whitespace=x option.,
  2006-02-28)

* -C, since 67dad68 (add -C[NUM] to git-am, 2007-02-08)

* -p, since 2092a1f (Teach git-am to pass -p option down to git-apply,
  2007-02-11)

* --directory, since b47dfe9 (git-am: add --directory=dir option,
  2009-01-11)

* --reject, since b80da42 (git-am: implement --reject option passed to
  git-apply, 2009-01-23)

* --ignore-space-change, --ignore-whitespace, since 86c91f9 (git apply:
  option to ignore whitespace differences, 2009-08-04)

* --exclude, since 77e9e49 (am: pass exclude down to apply, 2011-08-03)

* --include, since 58725ef (am: support --include option, 2012-03-28)

* --reject, since b80da42 (git-am: implement --reject option passed to
  git-apply, 2009-01-23)

Re-implement support for these options in builtin/am.c.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 45 +
 1 file changed, 45 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index 727cfb8..f842f69 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -106,6 +106,7 @@ struct am_state {
int keep; /* enum keep_type */
int message_id;
int scissors; /* enum scissors_type */
+   struct argv_array git_apply_opts;
const char *resolvemsg;
int rebasing;
 };
@@ -128,6 +129,8 @@ static void am_state_init(struct am_state *state, const 
char *dir)
git_config_get_bool(am.messageid, state-message_id);
 
state-scissors = SCISSORS_UNSET;
+
+   argv_array_init(state-git_apply_opts);
 }
 
 /**
@@ -140,6 +143,7 @@ static void am_state_release(struct am_state *state)
free(state-author_email);
free(state-author_date);
free(state-msg);
+   argv_array_clear(state-git_apply_opts);
 }
 
 /**
@@ -411,6 +415,11 @@ static void am_load(struct am_state *state)
else
state-scissors = SCISSORS_UNSET;
 
+   read_state_file(sb, state, apply-opt, 1);
+   argv_array_clear(state-git_apply_opts);
+   if (sq_dequote_to_argv_array(sb.buf, state-git_apply_opts)  0)
+   die(_(could not parse %s), am_path(state, apply-opt));
+
state-rebasing = !!file_exists(am_path(state, rebasing));
 
strbuf_release(sb);
@@ -585,6 +594,7 @@ static void am_setup(struct am_state *state, enum 
patch_format patch_format,
 {
unsigned char curr_head[GIT_SHA1_RAWSZ];
const char *str;
+   struct strbuf sb = STRBUF_INIT;
 
if (!patch_format)
patch_format = detect_patch_format(paths);
@@ -647,6 +657,9 @@ static void am_setup(struct am_state *state, enum 
patch_format patch_format,
 
write_file(am_path(state, scissors), 1, %s, str);
 
+   sq_quote_argv(sb, state-git_apply_opts.argv, 0);
+   write_file(am_path(state, apply-opt), 1, %s, sb.buf);
+
if (state-rebasing)
write_file(am_path(state, rebasing), 1, %s, );
else
@@ -671,6 +684,8 @@ static void am_setup(struct am_state *state, enum 
patch_format patch_format,
write_file(am_path(state, next), 1, %d, state-cur);
 
write_file(am_path(state, last), 1, %d, state-last);
+
+   strbuf_release(sb);
 }
 
 /**
@@ -1058,6 +1073,8 @@ static int run_apply(const struct am_state *state, const 
char *index_file)
 
argv_array_push(cp.args, apply);
 
+   argv_array_pushv(cp.args, state-git_apply_opts.argv);
+
if (index_file)
argv_array_push(cp.args, --cached);
else
@@ -1084,6 +1101,7 @@ static int build_fake_ancestor(const struct am_state 
*state, const char *index_f
 
cp.git_cmd = 1;
argv_array_push(cp.args, apply);
+   argv_array_pushv(cp.args, state-git_apply_opts.argv);
argv_array_pushf(cp.args, --build-fake-ancestor=%s, index_file);
argv_array_push(cp.args, am_path(state, patch));
 
@@ -1599,9 +1617,36 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
  PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 0},
OPT_BOOL('c', scissors, state.scissors,
N_(strip everything before a scissors line)),
+   OPT_PASSTHRU_ARGV(0, whitespace, state.git_apply_opts, 
N_(action),
+   N_(pass it through git-apply),
+   0),
+   OPT_PASSTHRU_ARGV(0, ignore-space-change, 
state.git_apply_opts, NULL,
+   N_(pass it through git-apply),
+   PARSE_OPT_NOARG),
+   OPT_PASSTHRU_ARGV(0, ignore-whitespace, 
state.git_apply_opts, NULL,
+   N_(pass it through git-apply),
+   PARSE_OPT_NOARG),
+   OPT_PASSTHRU_ARGV(0, directory, state.git_apply_opts, 
N_(root),
+   N_(pass it through git-apply),
+   0),
+   OPT_PASSTHRU_ARGV(0, exclude, 

[PATCH v7 42/45] builtin-am: implement -i/--interactive

2015-08-04 Thread Paul Tan
Since d1c5f2a (Add git-am, applymbox replacement., 2005-10-07),
git-am.sh supported the --interactive mode. After parsing the patch mail
and extracting the patch, commit message and authorship info, an
interactive session will begin that allows the user to choose between:

* applying the patch

* applying the patch and all subsequent patches (by disabling
  interactive mode in subsequent patches)

* skipping the patch

* editing the commit message

Since f89ad67 (Add [v]iew patch in git-am interactive., 2005-10-25),
git-am.sh --interactive also supported viewing the patch to be applied.

When --resolved-ing in --interactive mode, we need to take care to
update the patch with the contents of the index, such that the correct
patch will be displayed when the patch is viewed in interactive mode.

Re-implement the above in builtin/am.c

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 105 ++-
 1 file changed, 104 insertions(+), 1 deletion(-)

diff --git a/builtin/am.c b/builtin/am.c
index 98c10a0..589199f 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -25,6 +25,7 @@
 #include log-tree.h
 #include notes-utils.h
 #include rerere.h
+#include prompt.h
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -119,6 +120,7 @@ struct am_state {
int prec;
 
/* various operating modes and command line options */
+   int interactive;
int threeway;
int quiet;
int signoff;
@@ -1171,7 +1173,7 @@ static void NORETURN die_user_resolve(const struct 
am_state *state)
if (state-resolvemsg) {
printf_ln(%s, state-resolvemsg);
} else {
-   const char *cmdline = git am;
+   const char *cmdline = state-interactive ? git am -i : git 
am;
 
printf_ln(_(When you have resolved this problem, run \%s 
--continue\.), cmdline);
printf_ln(_(If you prefer to skip this patch, run \%s 
--skip\ instead.), cmdline);
@@ -1404,6 +1406,36 @@ static void write_commit_patch(const struct am_state 
*state, struct commit *comm
 }
 
 /**
+ * Writes the diff of the index against HEAD as a patch to the state
+ * directory's patch file.
+ */
+static void write_index_patch(const struct am_state *state)
+{
+   struct tree *tree;
+   unsigned char head[GIT_SHA1_RAWSZ];
+   struct rev_info rev_info;
+   FILE *fp;
+
+   if (!get_sha1_tree(HEAD, head))
+   tree = lookup_tree(head);
+   else
+   tree = lookup_tree(EMPTY_TREE_SHA1_BIN);
+
+   fp = xfopen(am_path(state, patch), w);
+   init_revisions(rev_info, NULL);
+   rev_info.diff = 1;
+   rev_info.disable_stdin = 1;
+   rev_info.no_commit_id = 1;
+   rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;
+   rev_info.diffopt.use_color = 0;
+   rev_info.diffopt.file = fp;
+   rev_info.diffopt.close_file = 1;
+   add_pending_object(rev_info, tree-object, );
+   diff_setup_done(rev_info.diffopt);
+   run_diff_index(rev_info, 1);
+}
+
+/**
  * Like parse_mail(), but parses the mail by looking up its commit ID
  * directly. This is used in --rebasing mode to bypass git-mailinfo's munging
  * of patches.
@@ -1655,6 +1687,65 @@ static void validate_resume_state(const struct am_state 
*state)
 }
 
 /**
+ * Interactively prompt the user on whether the current patch should be
+ * applied.
+ *
+ * Returns 0 if the user chooses to apply the patch, 1 if the user chooses to
+ * skip it.
+ */
+static int do_interactive(struct am_state *state)
+{
+   assert(state-msg);
+
+   if (!isatty(0))
+   die(_(cannot be interactive without stdin connected to a 
terminal.));
+
+   for (;;) {
+   const char *reply;
+
+   puts(_(Commit Body is:));
+   puts(--);
+   printf(%s, state-msg);
+   puts(--);
+
+   /*
+* TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
+* in your translation. The program will only accept English
+* input at this point.
+*/
+   reply = git_prompt(_(Apply? [y]es/[n]o/[e]dit/[v]iew 
patch/[a]ccept all: ), PROMPT_ECHO);
+
+   if (!reply) {
+   continue;
+   } else if (*reply == 'y' || *reply == 'Y') {
+   return 0;
+   } else if (*reply == 'a' || *reply == 'A') {
+   state-interactive = 0;
+   return 0;
+   } else if (*reply == 'n' || *reply == 'N') {
+   return 1;
+   } else if (*reply == 'e' || *reply == 'E') {
+   struct strbuf msg = STRBUF_INIT;
+
+   if (!launch_editor(am_path(state, final-commit), 
msg, NULL)) {
+   free(state-msg);
+   

[PATCH v7 41/45] builtin-am: support and auto-detect mercurial patches

2015-08-04 Thread Paul Tan
Since 0cfd112 (am: preliminary support for hg patches, 2011-08-29),
git-am.sh could convert mercurial patches to an RFC2822 mail patch
suitable for parsing with git-mailinfo, and queue them in the state
directory for application.

Since 15ced75 (git-am foreign patch support: autodetect some patch
formats, 2009-05-27), git-am.sh was able to auto-detect mercurial
patches by checking if the file begins with the line:

# HG changeset patch

Re-implement the above in builtin/am.c.

Helped-by: Stefan Beller sbel...@google.com
Signed-off-by: Paul Tan pyoka...@gmail.com
---

Notes:
v7

* Since a5481a6 (convert enum date_mode into a struct, 2015-06-25),
  show_date() now takes a date_mode struct. Use the DATE_MODE() macro to
  pass the equivalent date_mode struct to show_date().

 builtin/am.c | 74 +++-
 1 file changed, 73 insertions(+), 1 deletion(-)

diff --git a/builtin/am.c b/builtin/am.c
index 3c2ec15..98c10a0 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -81,7 +81,8 @@ enum patch_format {
PATCH_FORMAT_UNKNOWN = 0,
PATCH_FORMAT_MBOX,
PATCH_FORMAT_STGIT,
-   PATCH_FORMAT_STGIT_SERIES
+   PATCH_FORMAT_STGIT_SERIES,
+   PATCH_FORMAT_HG
 };
 
 enum keep_type {
@@ -656,6 +657,11 @@ static int detect_patch_format(const char **paths)
goto done;
}
 
+   if (!strcmp(l1.buf, # HG changeset patch)) {
+   ret = PATCH_FORMAT_HG;
+   goto done;
+   }
+
strbuf_reset(l2);
strbuf_getline_crlf(l2, fp);
strbuf_reset(l3);
@@ -854,6 +860,68 @@ static int split_mail_stgit_series(struct am_state *state, 
const char **paths,
 }
 
 /**
+ * A split_patches_conv() callback that converts a mercurial patch to a RFC2822
+ * message suitable for parsing with git-mailinfo.
+ */
+static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)
+{
+   struct strbuf sb = STRBUF_INIT;
+
+   while (!strbuf_getline(sb, in, '\n')) {
+   const char *str;
+
+   if (skip_prefix(sb.buf, # User , str))
+   fprintf(out, From: %s\n, str);
+   else if (skip_prefix(sb.buf, # Date , str)) {
+   unsigned long timestamp;
+   long tz, tz2;
+   char *end;
+
+   errno = 0;
+   timestamp = strtoul(str, end, 10);
+   if (errno)
+   return error(_(invalid timestamp));
+
+   if (!skip_prefix(end,  , str))
+   return error(_(invalid Date line));
+
+   errno = 0;
+   tz = strtol(str, end, 10);
+   if (errno)
+   return error(_(invalid timezone offset));
+
+   if (*end)
+   return error(_(invalid Date line));
+
+   /*
+* mercurial's timezone is in seconds west of UTC,
+* however git's timezone is in hours + minutes east of
+* UTC. Convert it.
+*/
+   tz2 = labs(tz) / 3600 * 100 + labs(tz) % 3600 / 60;
+   if (tz  0)
+   tz2 = -tz2;
+
+   fprintf(out, Date: %s\n, show_date(timestamp, tz2, 
DATE_MODE(RFC2822)));
+   } else if (starts_with(sb.buf, # )) {
+   continue;
+   } else {
+   fprintf(out, \n%s\n, sb.buf);
+   break;
+   }
+   }
+
+   strbuf_reset(sb);
+   while (strbuf_fread(sb, 8192, in)  0) {
+   fwrite(sb.buf, 1, sb.len, out);
+   strbuf_reset(sb);
+   }
+
+   strbuf_release(sb);
+   return 0;
+}
+
+/**
  * Splits a list of files/directories into individual email patches. Each path
  * in `paths` must be a file/directory that is formatted according to
  * `patch_format`.
@@ -885,6 +953,8 @@ static int split_mail(struct am_state *state, enum 
patch_format patch_format,
return split_mail_conv(stgit_patch_to_mail, state, paths, 
keep_cr);
case PATCH_FORMAT_STGIT_SERIES:
return split_mail_stgit_series(state, paths, keep_cr);
+   case PATCH_FORMAT_HG:
+   return split_mail_conv(hg_patch_to_mail, state, paths, keep_cr);
default:
die(BUG: invalid patch_format);
}
@@ -1937,6 +2007,8 @@ static int parse_opt_patchformat(const struct option 
*opt, const char *arg, int
*opt_value = PATCH_FORMAT_STGIT;
else if (!strcmp(arg, stgit-series))
*opt_value = PATCH_FORMAT_STGIT_SERIES;
+   else if (!strcmp(arg, hg))
+   *opt_value = PATCH_FORMAT_HG;
else
return error(_(Invalid value for 

[PATCH v7 03/45] builtin-am: implement skeletal builtin am

2015-08-04 Thread Paul Tan
For the purpose of rewriting git-am.sh into a C builtin, implement a
skeletal builtin/am.c that redirects to $GIT_EXEC_PATH/git-am if the
environment variable _GIT_USE_BUILTIN_AM is not defined. Since in the
Makefile git-am.sh takes precedence over builtin/am.c,
$GIT_EXEC_PATH/git-am will contain the shell script git-am.sh, and thus
this allows us to fall back on the functional git-am.sh when running the
test suite for tests that depend on a working git-am implementation.

Since git-am.sh cannot handle any environment modifications by
setup_git_directory(), am is declared with no setup flags in git.c. On
the other hand, to re-implement git-am.sh in builtin/am.c, we need to
run all the git dir and work tree setup logic that git.c typically does
for us. As such, we work around this temporarily by copying the logic in
git.c's run_builtin(), which is roughly:

prefix = setup_git_directory();
trace_repo_setup(prefix);
setup_work_tree();

This redirection should be removed when all the features of git-am.sh
have been re-implemented in builtin/am.c.

Helped-by: Junio C Hamano gits...@pobox.com
Signed-off-by: Paul Tan pyoka...@gmail.com
---
 Makefile |  1 +
 builtin.h|  1 +
 builtin/am.c | 29 +
 git.c|  6 ++
 4 files changed, 37 insertions(+)
 create mode 100644 builtin/am.c

diff --git a/Makefile b/Makefile
index 7efedbe..da451f8 100644
--- a/Makefile
+++ b/Makefile
@@ -813,6 +813,7 @@ LIB_OBJS += xdiff-interface.o
 LIB_OBJS += zlib.o
 
 BUILTIN_OBJS += builtin/add.o
+BUILTIN_OBJS += builtin/am.o
 BUILTIN_OBJS += builtin/annotate.o
 BUILTIN_OBJS += builtin/apply.o
 BUILTIN_OBJS += builtin/archive.o
diff --git a/builtin.h b/builtin.h
index 839483d..79aaf0a 100644
--- a/builtin.h
+++ b/builtin.h
@@ -30,6 +30,7 @@ extern int textconv_object(const char *path, unsigned mode, 
const unsigned char
 extern int is_builtin(const char *s);
 
 extern int cmd_add(int argc, const char **argv, const char *prefix);
+extern int cmd_am(int argc, const char **argv, const char *prefix);
 extern int cmd_annotate(int argc, const char **argv, const char *prefix);
 extern int cmd_apply(int argc, const char **argv, const char *prefix);
 extern int cmd_archive(int argc, const char **argv, const char *prefix);
diff --git a/builtin/am.c b/builtin/am.c
new file mode 100644
index 000..fd32caf
--- /dev/null
+++ b/builtin/am.c
@@ -0,0 +1,29 @@
+/*
+ * Builtin git am
+ *
+ * Based on git-am.sh by Junio C Hamano.
+ */
+#include cache.h
+#include builtin.h
+#include exec_cmd.h
+
+int cmd_am(int argc, const char **argv, const char *prefix)
+{
+
+   /*
+* NEEDSWORK: Once all the features of git-am.sh have been
+* re-implemented in builtin/am.c, this preamble can be removed.
+*/
+   if (!getenv(_GIT_USE_BUILTIN_AM)) {
+   const char *path = mkpath(%s/git-am, git_exec_path());
+
+   if (sane_execvp(path, (char **)argv)  0)
+   die_errno(could not exec %s, path);
+   } else {
+   prefix = setup_git_directory();
+   trace_repo_setup(prefix);
+   setup_work_tree();
+   }
+
+   return 0;
+}
diff --git a/git.c b/git.c
index 55c327c..38d9ad5 100644
--- a/git.c
+++ b/git.c
@@ -370,6 +370,12 @@ static int run_builtin(struct cmd_struct *p, int argc, 
const char **argv)
 
 static struct cmd_struct commands[] = {
{ add, cmd_add, RUN_SETUP | NEED_WORK_TREE },
+   /*
+* NEEDSWORK: Once the redirection to git-am.sh in builtin/am.c has
+* been removed, this entry should be changed to
+* RUN_SETUP | NEED_WORK_TREE
+*/
+   { am, cmd_am },
{ annotate, cmd_annotate, RUN_SETUP },
{ apply, cmd_apply, RUN_SETUP_GENTLY },
{ archive, cmd_archive },
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 04/45] builtin-am: implement patch queue mechanism

2015-08-04 Thread Paul Tan
git-am applies a series of patches. If the process terminates
abnormally, we want to be able to resume applying the series of patches.
This requires the session state to be saved in a persistent location.

Implement the mechanism of a patch queue, represented by 2 integers --
the index of the current patch we are applying and the index of the last
patch, as well as its lifecycle through the following functions:

* am_setup(), which will set up the state directory
  $GIT_DIR/rebase-apply. As such, even if the process exits abnormally,
  the last-known state will still persist.

* am_load(), which is called if there is an am session in
  progress, to load the last known state from the state directory so we
  can resume applying patches.

* am_run(), which will do the actual patch application. After applying a
  patch, it calls am_next() to increment the current patch index. The
  logic for applying and committing a patch is not implemented yet.

* am_destroy(), which is finally called when we successfully applied all
  the patches in the queue, to clean up by removing the state directory
  and its contents.

Helped-by: Junio C Hamano gits...@pobox.com
Helped-by: Stefan Beller sbel...@google.com
Helped-by: Johannes Schindelin johannes.schinde...@gmx.de
Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c | 177 +++
 1 file changed, 177 insertions(+)

diff --git a/builtin/am.c b/builtin/am.c
index fd32caf..ac172c4 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -6,9 +6,171 @@
 #include cache.h
 #include builtin.h
 #include exec_cmd.h
+#include parse-options.h
+#include dir.h
+
+struct am_state {
+   /* state directory path */
+   char *dir;
+
+   /* current and last patch numbers, 1-indexed */
+   int cur;
+   int last;
+};
+
+/**
+ * Initializes am_state with the default values. The state directory is set to
+ * dir.
+ */
+static void am_state_init(struct am_state *state, const char *dir)
+{
+   memset(state, 0, sizeof(*state));
+
+   assert(dir);
+   state-dir = xstrdup(dir);
+}
+
+/**
+ * Releases memory allocated by an am_state.
+ */
+static void am_state_release(struct am_state *state)
+{
+   free(state-dir);
+}
+
+/**
+ * Returns path relative to the am_state directory.
+ */
+static inline const char *am_path(const struct am_state *state, const char 
*path)
+{
+   return mkpath(%s/%s, state-dir, path);
+}
+
+/**
+ * Returns 1 if there is an am session in progress, 0 otherwise.
+ */
+static int am_in_progress(const struct am_state *state)
+{
+   struct stat st;
+
+   if (lstat(state-dir, st)  0 || !S_ISDIR(st.st_mode))
+   return 0;
+   if (lstat(am_path(state, last), st) || !S_ISREG(st.st_mode))
+   return 0;
+   if (lstat(am_path(state, next), st) || !S_ISREG(st.st_mode))
+   return 0;
+   return 1;
+}
+
+/**
+ * Reads the contents of `file` in the `state` directory into `sb`. Returns the
+ * number of bytes read on success, -1 if the file does not exist. If `trim` is
+ * set, trailing whitespace will be removed.
+ */
+static int read_state_file(struct strbuf *sb, const struct am_state *state,
+   const char *file, int trim)
+{
+   strbuf_reset(sb);
+
+   if (strbuf_read_file(sb, am_path(state, file), 0) = 0) {
+   if (trim)
+   strbuf_trim(sb);
+
+   return sb-len;
+   }
+
+   if (errno == ENOENT)
+   return -1;
+
+   die_errno(_(could not read '%s'), am_path(state, file));
+}
+
+/**
+ * Loads state from disk.
+ */
+static void am_load(struct am_state *state)
+{
+   struct strbuf sb = STRBUF_INIT;
+
+   if (read_state_file(sb, state, next, 1)  0)
+   die(BUG: state file 'next' does not exist);
+   state-cur = strtol(sb.buf, NULL, 10);
+
+   if (read_state_file(sb, state, last, 1)  0)
+   die(BUG: state file 'last' does not exist);
+   state-last = strtol(sb.buf, NULL, 10);
+
+   strbuf_release(sb);
+}
+
+/**
+ * Removes the am_state directory, forcefully terminating the current am
+ * session.
+ */
+static void am_destroy(const struct am_state *state)
+{
+   struct strbuf sb = STRBUF_INIT;
+
+   strbuf_addstr(sb, state-dir);
+   remove_dir_recursively(sb, 0);
+   strbuf_release(sb);
+}
+
+/**
+ * Setup a new am session for applying patches
+ */
+static void am_setup(struct am_state *state)
+{
+   if (mkdir(state-dir, 0777)  0  errno != EEXIST)
+   die_errno(_(failed to create directory '%s'), state-dir);
+
+   /*
+* NOTE: Since the next and last files determine if an am_state
+* session is in progress, they should be written last.
+*/
+
+   write_file(am_path(state, next), 1, %d, state-cur);
+
+   write_file(am_path(state, last), 1, %d, state-last);
+}
+
+/**
+ * Increments the patch pointer, and cleans am_state for the application of 

[PATCH v7 00/45] Make git-am a builtin

2015-08-04 Thread Paul Tan
This is a re-roll of [v6]. The changes are as follows:

* removed am.threeWay config to match master

* renamed am_state's append_signoff field to the shorter signoff to
  preserve horizontal space.

* Fix memory leak in am_abort() (Noticed by Stefan, thanks!)

* Rebase onto master, and adjust to the changes introduced by
  a5481a6 (convert enum date_mode into a struct, 2015-06-25).

Interdiff below.

Previous versions:

[WIP v1] http://thread.gmane.org/gmane.comp.version-control.git/270048
[WIP v2] http://thread.gmane.org/gmane.comp.version-control.git/271381
[WIP v3] http://thread.gmane.org/gmane.comp.version-control.git/271967
[v4] http://thread.gmane.org/gmane.comp.version-control.git/272876
[v5] http://thread.gmane.org/gmane.comp.version-control.git/273520
[v6] http://thread.gmane.org/gmane.comp.version-control.git/274225

git-am is a commonly used command for applying a series of patches from a
mailbox to the current branch. Currently, it is implemented by the shell script
git-am.sh. However, compared to C, shell scripts have certain deficiencies:
they need to spawn a lot of processes, introduce a lot of dependencies and
cannot take advantage of git's internal caches.

This patch series rewrites git-am.sh into C builtin/am.c, and is part of my
GSoC project to rewrite git-pull and git-am into C builtins[1].

[1] https://gist.github.com/pyokagan/1b7b0d1f4dab6ba3cef1


Paul Tan (45):
  wrapper: implement xopen()
  wrapper: implement xfopen()
  builtin-am: implement skeletal builtin am
  builtin-am: implement patch queue mechanism
  builtin-am: split out mbox/maildir patches with git-mailsplit
  builtin-am: auto-detect mbox patches
  builtin-am: extract patch and commit info with git-mailinfo
  builtin-am: apply patch with git-apply
  builtin-am: implement committing applied patch
  builtin-am: refuse to apply patches if index is dirty
  builtin-am: implement --resolved/--continue
  builtin-am: don't parse mail when resuming
  builtin-am: implement --skip
  builtin-am: implement --abort
  builtin-am: reject patches when there's a session in progress
  builtin-am: implement -q/--quiet
  builtin-am: exit with user friendly message on failure
  builtin-am: implement -s/--signoff
  cache-tree: introduce write_index_as_tree()
  builtin-am: implement --3way
  builtin-am: implement --rebasing mode
  builtin-am: bypass git-mailinfo when --rebasing
  builtin-am: handle stray state directory
  builtin-am: implement -u/--utf8
  builtin-am: implement -k/--keep, --keep-non-patch
  builtin-am: implement --[no-]message-id, am.messageid
  builtin-am: support --keep-cr, am.keepcr
  builtin-am: implement --[no-]scissors
  builtin-am: pass git-apply's options to git-apply
  builtin-am: implement --ignore-date
  builtin-am: implement --committer-date-is-author-date
  builtin-am: implement -S/--gpg-sign, commit.gpgsign
  builtin-am: invoke post-rewrite hook
  builtin-am: support automatic notes copying
  builtin-am: invoke applypatch-msg hook
  builtin-am: invoke pre-applypatch hook
  builtin-am: invoke post-applypatch hook
  builtin-am: rerere support
  builtin-am: support and auto-detect StGit patches
  builtin-am: support and auto-detect StGit series files
  builtin-am: support and auto-detect mercurial patches
  builtin-am: implement -i/--interactive
  builtin-am: implement legacy -b/--binary option
  builtin-am: check for valid committer ident
  builtin-am: remove redirection to git-am.sh

 Makefile|2 +-
 builtin.h   |1 +
 builtin/am.c| 2319 +++
 cache-tree.c|   29 +-
 cache-tree.h|1 +
 git-am.sh = contrib/examples/git-am.sh |0
 git-compat-util.h   |2 +
 git.c   |1 +
 wrapper.c   |   56 +
 9 files changed, 2398 insertions(+), 13 deletions(-)
 create mode 100644 builtin/am.c
 rename git-am.sh = contrib/examples/git-am.sh (100%)

diff --git a/builtin/am.c b/builtin/am.c
index 1116304..84d57d4 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -123,7 +123,7 @@ struct am_state {
int interactive;
int threeway;
int quiet;
-   int append_signoff;
+   int signoff;
int utf8;
int keep; /* enum keep_type */
int message_id;
@@ -152,8 +152,6 @@ static void am_state_init(struct am_state *state, const 
char *dir)
 
state-prec = 4;
 
-   git_config_get_bool(am.threeway, state-threeway);
-
state-utf8 = 1;
 
git_config_get_bool(am.messageid, state-message_id);
@@ -429,7 +427,7 @@ static void am_load(struct am_state *state)
state-quiet = !strcmp(sb.buf, t);
 
read_state_file(sb, state, sign, 1);
-   state-append_signoff = !strcmp(sb.buf, t);
+   state-signoff = !strcmp(sb.buf, t);
 
read_state_file(sb, state, utf8, 1);
state-utf8 = !strcmp(sb.buf, 

[PATCH v2 0/3] am: let command-line options override saved options

2015-08-04 Thread Paul Tan
Let command-line options override saved options in git-am when resuming

This is a re-roll of [v1]. Previous versions:

[v1] http://thread.gmane.org/gmane.comp.version-control.git/274789

When resuming, git-am mistakenly ignores command-line options.

For instance, when a patch fails to apply with git am patch, subsequently
running git am --3way would not cause git-am to fall back on attempting a
threeway merge.  This occurs because by default the --3way option is saved as
false, and the saved am options are loaded after the command-line options are
parsed, thus overwriting the command-line options when resuming.

[PATCH 1/3] tweaks test-terminal.perl to redirect the stdin of the child
process to a pty. This is to support the tests in [PATCH 2/3].

[PATCH 2/3] fixes builtin/am.c, enabling command-line options to override saved
options. However, even with this patch, the following command-line options have
no effect when resuming:

* --signoff overriding --no-signoff

* --no-keep overriding --keep

* --message-id overriding --no-message-id

* --scissors overriding --no-scissors

This is because they are only taken into account during the mail-parsing stage,
which is skipped over when resuming.

[PATCH 3/3] adds support for the --signoff option when resuming by recognizing
that we can (re-)append the signoff when the user explicitly specifies the
--signoff option.

Since the --keep, --message-id and --scissors options are handled by
git-mailinfo, it is tricky to implement support for them without introducing
lots of code complexity, and thus this patch series does not attempt to.

Furthermore, it is hard to imagine a use case for e.g. --scissors overriding
--no-scissors, and hence it might be preferable to wait until someone comes
with a solid use case, instead of implementing potentially undesirable behavior
and having to support it.


Paul Tan (3):
  test_terminal: redirect child process' stdin to a pty
  am: let command-line options override saved options
  am: let --signoff override --no-signoff

 builtin/am.c   |  42 ---
 t/t4153-am-resume-override-opts.sh | 102 +
 t/test-terminal.perl   |  25 +++--
 3 files changed, 158 insertions(+), 11 deletions(-)
 create mode 100755 t/t4153-am-resume-override-opts.sh

-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 1/3] test_terminal: redirect child process' stdin to a pty

2015-08-04 Thread Paul Tan
When resuming, git-am detects if we are trying to feed it patches or not
by checking if stdin is a TTY.

However, the test library redirects stdin to /dev/null. This makes it
difficult, for instance, to test the behavior of git am -3 when
resuming, as git-am will think we are trying to feed it patches and
error out.

Support this use case by extending test-terminal.perl to create a
pseudo-tty for the child process' standard input as well.

Note that due to the way the code is structured, the child's stdin
pseudo-tty will be closed when we finish reading from our stdin. This
means that in the common case, where our stdin is attached to /dev/null,
the child's stdin pseudo-tty will be closed immediately. Some operations
like isatty(), which git-am uses, require the file descriptor to be
open, and hence if the success of the command depends on such functions,
test_terminal's stdin should be redirected to a source with large amount
of data to ensure that the child's stdin is not closed, e.g.

test_terminal git am --3way /dev/zero

Cc: Jonathan Nieder jrnie...@gmail.com
Cc: Jeff King p...@peff.net
Signed-off-by: Paul Tan pyoka...@gmail.com
---
 t/test-terminal.perl | 25 -
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/t/test-terminal.perl b/t/test-terminal.perl
index 1fb373f..f6fc9ae 100755
--- a/t/test-terminal.perl
+++ b/t/test-terminal.perl
@@ -5,15 +5,17 @@ use warnings;
 use IO::Pty;
 use File::Copy;
 
-# Run @$argv in the background with stdio redirected to $out and $err.
+# Run @$argv in the background with stdio redirected to $in, $out and $err.
 sub start_child {
-   my ($argv, $out, $err) = @_;
+   my ($argv, $in, $out, $err) = @_;
my $pid = fork;
if (not defined $pid) {
die fork failed: $!
} elsif ($pid == 0) {
+   open STDIN, , $in;
open STDOUT, , $out;
open STDERR, , $err;
+   close $in;
close $out;
exec(@$argv) or die cannot exec '$argv-[0]': $!
}
@@ -50,14 +52,23 @@ sub xsendfile {
 }
 
 sub copy_stdio {
-   my ($out, $err) = @_;
+   my ($in, $out, $err) = @_;
my $pid = fork;
+   if (!$pid) {
+   close($out);
+   close($err);
+   xsendfile($in, \*STDIN);
+   exit 0;
+   }
+   $pid = fork;
defined $pid or die fork failed: $!;
if (!$pid) {
+   close($in);
close($out);
xsendfile(\*STDERR, $err);
exit 0;
}
+   close($in);
close($err);
xsendfile(\*STDOUT, $out);
finish_child($pid) == 0
@@ -67,14 +78,18 @@ sub copy_stdio {
 if ($#ARGV  1) {
die usage: test-terminal program args;
 }
+my $master_in = new IO::Pty;
 my $master_out = new IO::Pty;
 my $master_err = new IO::Pty;
+$master_in-set_raw();
 $master_out-set_raw();
 $master_err-set_raw();
+$master_in-slave-set_raw();
 $master_out-slave-set_raw();
 $master_err-slave-set_raw();
-my $pid = start_child(\@ARGV, $master_out-slave, $master_err-slave);
+my $pid = start_child(\@ARGV, $master_in-slave, $master_out-slave, 
$master_err-slave);
+close $master_in-slave;
 close $master_out-slave;
 close $master_err-slave;
-copy_stdio($master_out, $master_err);
+copy_stdio($master_in, $master_out, $master_err);
 exit(finish_child($pid));
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 2/3] am: let command-line options override saved options

2015-08-04 Thread Paul Tan
When resuming, git-am mistakenly ignores command-line options.

For instance, when a patch fails to apply with git am patch,
subsequently running git am --3way would not cause git-am to fall
back on attempting a threeway merge.  This occurs because by default
the --3way option is saved as false, and the saved am options are
loaded after the command-line options are parsed, thus overwriting
the command-line options when resuming.

Fix this by moving the am_load() function call before parse_options(),
so that command-line options will override the saved am options.

The purpose of supporting this use case is to enable users to wiggle
that one conflicting patch. As such, it is expected that the
command-line options do not affect subsequent applied patches. Implement
this by calling am_load() once we apply the conflicting patch
successfully.

Noticed-by: Junio C Hamano gits...@pobox.com
Helped-by: Junio C Hamano gits...@pobox.com
Helped-by: Jeff King p...@peff.net
Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c   | 16 ++--
 t/t4153-am-resume-override-opts.sh | 82 ++
 2 files changed, 94 insertions(+), 4 deletions(-)
 create mode 100755 t/t4153-am-resume-override-opts.sh

diff --git a/builtin/am.c b/builtin/am.c
index 84d57d4..0961304 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1777,7 +1777,6 @@ static void am_run(struct am_state *state, int resume)
 
if (resume) {
validate_resume_state(state);
-   resume = 0;
} else {
int skip;
 
@@ -1839,6 +1838,10 @@ static void am_run(struct am_state *state, int resume)
 
 next:
am_next(state);
+
+   if (resume)
+   am_load(state);
+   resume = 0;
}
 
if (!is_empty_file(am_path(state, rewritten))) {
@@ -1893,6 +1896,7 @@ static void am_resolve(struct am_state *state)
 
 next:
am_next(state);
+   am_load(state);
am_run(state, 0);
 }
 
@@ -2020,6 +2024,7 @@ static void am_skip(struct am_state *state)
die(_(failed to clean index));
 
am_next(state);
+   am_load(state);
am_run(state, 0);
 }
 
@@ -2130,6 +2135,7 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
int keep_cr = -1;
int patch_format = PATCH_FORMAT_UNKNOWN;
enum resume_mode resume = RESUME_FALSE;
+   int in_progress;
 
const char * const usage[] = {
N_(git am [options] [(mbox|Maildir)...]),
@@ -2225,6 +2231,10 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
 
am_state_init(state, git_path(rebase-apply));
 
+   in_progress = am_in_progress(state);
+   if (in_progress)
+   am_load(state);
+
argc = parse_options(argc, argv, prefix, options, usage, 0);
 
if (binary = 0)
@@ -2237,7 +2247,7 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
if (read_index_preload(the_index, NULL)  0)
die(_(failed to read the index));
 
-   if (am_in_progress(state)) {
+   if (in_progress) {
/*
 * Catch user error to feed us patches when there is a session
 * in progress:
@@ -2255,8 +2265,6 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
 
if (resume == RESUME_FALSE)
resume = RESUME_APPLY;
-
-   am_load(state);
} else {
struct argv_array paths = ARGV_ARRAY_INIT;
int i;
diff --git a/t/t4153-am-resume-override-opts.sh 
b/t/t4153-am-resume-override-opts.sh
new file mode 100755
index 000..39fac79
--- /dev/null
+++ b/t/t4153-am-resume-override-opts.sh
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+test_description='git-am command-line options override saved options'
+
+. ./test-lib.sh
+. $TEST_DIRECTORY/lib-terminal.sh
+
+format_patch () {
+   git format-patch --stdout -1 $1 $1.eml
+}
+
+test_expect_success 'setup' '
+   test_commit initial file 
+   test_commit first file 
+
+   git checkout initial 
+   git mv file file2 
+   test_tick 
+   git commit -m renamed-file 
+   git tag renamed-file 
+
+   git checkout -b side initial 
+   test_commit side1 file 
+   test_commit side2 file 
+
+   format_patch side1 
+   format_patch side2
+'
+
+test_expect_success TTY '--3way overrides --no-3way' '
+   rm -fr .git/rebase-apply 
+   git reset --hard 
+   git checkout renamed-file 
+
+   # Applying side1 will fail as the file has been renamed.
+   test_must_fail git am --no-3way side[12].eml 
+   test_path_is_dir .git/rebase-apply 
+   test_cmp_rev renamed-file HEAD 
+   test -z $(git ls-files -u) 
+
+   # Applying side1 with am --3way will succeed due to the threeway-merge.
+   # Applying side2 will fail as --3way does not apply to it.
+   

[PATCH v2 3/3] am: let --signoff override --no-signoff

2015-08-04 Thread Paul Tan
After resolving a conflicting patch, a user may wish to sign off the
patch to declare that the patch has been modified. As such, the user
will expect that running git am --signoff --continue will append the
signoff to the commit message.

However, the --signoff option is only taken into account during the
mail-parsing stage. If the --signoff option is set, then the signoff
will be appended to the commit message. Since the mail-parsing stage
comes before the patch application stage, the --signoff option, if
provided on the command-line when resuming, will have no effect at all.

We cannot move the append_signoff() call to the patch application stage
as the applypatch-msg hook and interactive mode, which run before patch
application, may expect the signoff to be there.

Fix this by taking note if the user explictly set the --signoff option
on the command-line, and append the signoff to the commit message when
resuming if so.

Signed-off-by: Paul Tan pyoka...@gmail.com
---
 builtin/am.c   | 28 +---
 t/t4153-am-resume-override-opts.sh | 20 
 2 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index 0961304..8c95aec 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -98,6 +98,12 @@ enum scissors_type {
SCISSORS_TRUE/* pass --scissors to git-mailinfo */
 };
 
+enum signoff_type {
+   SIGNOFF_FALSE = 0,
+   SIGNOFF_TRUE = 1,
+   SIGNOFF_EXPLICIT /* --signoff was set on the command-line */
+};
+
 struct am_state {
/* state directory path */
char *dir;
@@ -123,7 +129,7 @@ struct am_state {
int interactive;
int threeway;
int quiet;
-   int signoff;
+   int signoff; /* enum signoff_type */
int utf8;
int keep; /* enum keep_type */
int message_id;
@@ -1184,6 +1190,18 @@ static void NORETURN die_user_resolve(const struct 
am_state *state)
 }
 
 /**
+ * Appends signoff to the msg field of the am_state.
+ */
+static void am_append_signoff(struct am_state *state)
+{
+   struct strbuf sb = STRBUF_INIT;
+
+   strbuf_attach(sb, state-msg, state-msg_len, state-msg_len);
+   append_signoff(sb, 0, 0);
+   state-msg = strbuf_detach(sb, state-msg_len);
+}
+
+/**
  * Parses `mail` using git-mailinfo, extracting its patch and authorship info.
  * state-msg will be set to the patch message. state-author_name,
  * state-author_email and state-author_date will be set to the patch author's
@@ -2151,8 +2169,9 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
OPT_BOOL('3', 3way, state.threeway,
N_(allow fall back on 3way merging if needed)),
OPT__QUIET(state.quiet, N_(be quiet)),
-   OPT_BOOL('s', signoff, state.signoff,
-   N_(add a Signed-off-by line to the commit message)),
+   OPT_SET_INT('s', signoff, state.signoff,
+   N_(add a Signed-off-by line to the commit message),
+   SIGNOFF_EXPLICIT),
OPT_BOOL('u', utf8, state.utf8,
N_(recode into utf8 (default))),
OPT_SET_INT('k', keep, state.keep,
@@ -2265,6 +2284,9 @@ int cmd_am(int argc, const char **argv, const char 
*prefix)
 
if (resume == RESUME_FALSE)
resume = RESUME_APPLY;
+
+   if (state.signoff == SIGNOFF_EXPLICIT)
+   am_append_signoff(state);
} else {
struct argv_array paths = ARGV_ARRAY_INIT;
int i;
diff --git a/t/t4153-am-resume-override-opts.sh 
b/t/t4153-am-resume-override-opts.sh
index 39fac79..7c013d8 100755
--- a/t/t4153-am-resume-override-opts.sh
+++ b/t/t4153-am-resume-override-opts.sh
@@ -64,6 +64,26 @@ test_expect_success '--no-quiet overrides --quiet' '
test_i18ncmp expected out
 '
 
+test_expect_success '--signoff overrides --no-signoff' '
+   rm -fr .git/rebase-apply 
+   git reset --hard 
+   git checkout first 
+
+   test_must_fail git am --no-signoff side[12].eml 
+   test_path_is_dir .git/rebase-apply 
+   echo side1 file 
+   git add file 
+   git am --signoff --continue 
+
+   # Applied side1 will be signed off
+   echo Signed-off-by: $GIT_COMMITTER_NAME $GIT_COMMITTER_EMAIL 
expected 
+   git cat-file commit HEAD^ | grep Signed-off-by: actual 
+   test_cmp expected actual 
+
+   # Applied side2 will not be signed off
+   test $(git cat-file commit HEAD | grep -c Signed-off-by:) -eq 0
+'
+
 test_expect_success TTY '--reject overrides --no-reject' '
rm -fr .git/rebase-apply 
git reset --hard 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 0/3] am: let command-line options override saved options

2015-08-04 Thread Paul Tan
Let command-line options override saved options in git-am when resuming

This is a re-roll of [v1]. Previous versions:

[v1] http://thread.gmane.org/gmane.comp.version-control.git/274789

When resuming, git-am mistakenly ignores command-line options.

For instance, when a patch fails to apply with git am patch, subsequently
running git am --3way would not cause git-am to fall back on attempting a
threeway merge.  This occurs because by default the --3way option is saved as
false, and the saved am options are loaded after the command-line options are
parsed, thus overwriting the command-line options when resuming.

[PATCH 1/3] tweaks test-terminal.perl to redirect the stdin of the child
process to a pty. This is to support the tests in [PATCH 2/3].

[PATCH 2/3] fixes builtin/am.c, enabling command-line options to override saved
options. However, even with this patch, the following command-line options have
no effect when resuming:

* --signoff overriding --no-signoff

* --no-keep overriding --keep

* --message-id overriding --no-message-id

* --scissors overriding --no-scissors

This is because they are only taken into account during the mail-parsing stage,
which is skipped over when resuming.

[PATCH 3/3] adds support for the --signoff option when resuming by recognizing
that we can (re-)append the signoff when the user explicitly specifies the
--signoff option.

Since the --keep, --message-id and --scissors options are handled by
git-mailinfo, it is tricky to implement support for them without introducing
lots of code complexity, and thus this patch series does not attempt to.

Furthermore, it is hard to imagine a use case for e.g. --scissors overriding
--no-scissors, and hence it might be preferable to wait until someone comes
with a solid use case, instead of implementing potentially undesirable behavior
and having to support it.


Paul Tan (3):
  test_terminal: redirect child process' stdin to a pty
  am: let command-line options override saved options
  am: let --signoff override --no-signoff

 builtin/am.c   |  42 ---
 t/t4153-am-resume-override-opts.sh | 102 +
 t/test-terminal.perl   |  25 +++--
 3 files changed, 158 insertions(+), 11 deletions(-)
 create mode 100755 t/t4153-am-resume-override-opts.sh

-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] git-am: add am.threeWay config variable

2015-08-04 Thread Paul Tan
From: Remi Lespinet remi.lespi...@ensimag.grenoble-inp.fr

Add the am.threeWay configuration variable to use the -3 or --3way
option of git am by default. When am.threeway is set and not desired
for a specific git am command, the --no-3way option can be used to
override it.

Signed-off-by: Remi Lespinet remi.lespi...@ensimag.grenoble-inp.fr
Signed-off-by: Paul Tan pyoka...@gmail.com
---
I tweaked Remi's patch so it is implemented on top of builtin/am.c. Hopefully
there will be no regressions this time ;)

 Documentation/config.txt |  8 
 Documentation/git-am.txt |  7 +--
 builtin/am.c |  2 ++
 t/t4150-am.sh| 19 +++
 4 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 315f271..fb3fc57 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -769,6 +769,14 @@ am.keepcr::
by giving '--no-keep-cr' from the command line.
See linkgit:git-am[1], linkgit:git-mailsplit[1].
 
+am.threeWay::
+   By default, `git am` will fail if the patch does not apply cleanly. When
+   set to true, this setting tells `git am` to fall back on 3-way merge if
+   the patch records the identity of blobs it is supposed to apply to and
+   we have those blobs available locally (equivalent to giving the `--3way`
+   option from the command line). Defaults to `false`.
+   See linkgit:git-am[1].
+
 apply.ignoreWhitespace::
When set to 'change', tells 'git apply' to ignore changes in
whitespace, in the same way as the '--ignore-space-change'
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 0d8ba48..dbea6e7 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -10,7 +10,7 @@ SYNOPSIS
 
 [verse]
 'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8]
-[--3way] [--interactive] [--committer-date-is-author-date]
+[--[no-]3way] [--interactive] [--committer-date-is-author-date]
 [--ignore-date] [--ignore-space-change | --ignore-whitespace]
 [--whitespace=option] [-Cn] [-pn] [--directory=dir]
 [--exclude=path] [--include=path] [--reject] [-q | --quiet]
@@ -90,10 +90,13 @@ default.   You can use `--no-utf8` to override this.
 
 -3::
 --3way::
+--no-3way::
When the patch does not apply cleanly, fall back on
3-way merge if the patch records the identity of blobs
it is supposed to apply to and we have those blobs
-   available locally.
+   available locally. `--no-3way` can be used to override
+   am.threeWay configuration variable. For more information,
+   see am.threeWay in linkgit:git-config[1].
 
 --ignore-space-change::
 --ignore-whitespace::
diff --git a/builtin/am.c b/builtin/am.c
index 84d57d4..1399c8d 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -152,6 +152,8 @@ static void am_state_init(struct am_state *state, const 
char *dir)
 
state-prec = 4;
 
+   git_config_get_bool(am.threeway, state-threeway);
+
state-utf8 = 1;
 
git_config_get_bool(am.messageid, state-message_id);
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index e9b6f81..dd627c4 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -551,6 +551,25 @@ test_expect_success 'am -3 -p0 can read --no-prefix patch' 
'
git diff --exit-code lorem
 '
 
+test_expect_success 'am with config am.threeWay falls back to 3-way merge' '
+   rm -fr .git/rebase-apply 
+   git reset --hard 
+   git checkout -b lorem4 base3way 
+   test_config am.threeWay 1 
+   git am lorem-move.patch 
+   test_path_is_missing .git/rebase-apply 
+   git diff --exit-code lorem
+'
+
+test_expect_success 'am with config am.threeWay overridden by --no-3way' '
+   rm -fr .git/rebase-apply 
+   git reset --hard 
+   git checkout -b lorem5 base3way 
+   test_config am.threeWay 1 
+   test_must_fail git am --no-3way lorem-move.patch 
+   test_path_is_dir .git/rebase-apply
+'
+
 test_expect_success 'am can rename a file' '
grep ^rename from rename.patch 
rm -fr .git/rebase-apply 
-- 
2.5.0.280.gd88bd6e

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [git-p4] import with labels fails when commit is not transferred

2015-08-04 Thread Luke Diamand

On 04/07/15 04:27, Luke Diamand wrote:

Sorry for not replying earlier, and thanks for taking the time to
investigate this!

It's a pretty subtle corner case: I think a test case would be useful.
I'm going to try to put something together, unless you beat me to it!

(I think t9811-git-p4-label-import.sh is the one that needs extending).


I've been looking into this a bit more, and I think that you don't need 
a try/except - it's enough just to add ignore_error=True to the call 
to read_lines.


It also looks like this is a general problem of importing a label where 
the revision doesn't exist in git. For example, if you create a p4 
label, then clone at the revision after that, you will get the problem.


I've got a test case and a modified git-p4.py, but I haven't yet got to 
the point where I'm convinced it works. I think the fix is pretty much 
what you've shown (replacing try-except with ignore_error) but I'd like 
my test case to be a bit more convincing.


Thanks!
Luke



On 30/06/15 09:45, Holl, Marcus wrote:

Hi,

I have an issue with the git p4 tooling regarding import of labels.

My git version is 2.4.5

I try to transform a perforce repository. My command line is:
git p4 clone --verbose --detect-branches --import-local
--import-labels --destination DESTINATION //depot@all


The relevant parts in the gitconfig is:
[git-p4]
 branchUser = USERNAME


For that user there is a branch mapping defined with a lot of entries
like:
//depot/trunk/... //depot/branches/ipro-status-8-2--branch/...
//depot/trunk/... //depot/branches/9-0-preview/...
//depot/trunk/... //depot/branches/release-8-0-0-branch/...
//depot/trunk/... //depot/branches/release-8-1-0-branch/...
//depot/trunk/... //depot/branches/release-8-2-0-branch/...
//depot/trunk/... //depot/branches/release-8-3-0-branch/...
//depot/trunk/... //depot/branches/release-8-4-branch/...
//depot/trunk/... //depot/branches/release-8-5-branch/...
...


The import fails with the log output that can be found at the bottom
of this mail.

git log -all -grep \[git-p4:.*change\ =\ 69035\] reports nothing.
The commit is not contained in the git repository.

p4 describe for changelist 69035 returns a reasonable result. This
change contains one file located at a path in the perforce folder
structure that comes without corresponding entry in the perforce
branch mapping.

According to the given branch mapping it looks reasonable to me that
the change is omitted in the git repository. But in my opinion the
import should not fail in such a case.

A reasonable behavior would be to blacklist the label (add it to
git-p4.ignoredP4Labels) and to continue with the next label.

Attached is a proposal for a fix that needs to be carefully reviews
since I'm not that experienced with python.

Other proposals for resolving this issue are highly appreciated.

Thanks a lot and best regards,
Marcus Holl


Log output:

Reading pipe: ['git', 'rev-list', '--max-count=1', '--reverse',
':/\\[git-p4:.*change = 69035\\]']
fatal: ambiguous argument ':/\[git-p4:.*change = 69035\]': unknown
revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git command [revision...] -- [file...]'
ied with change: 69078, original Date: 2010-04-22T09:07:24.00Z\n',
'Update': '2013/11/02 07:40:31', 'Label': 'release-8-1-0-976',
'Access': '2015/06/26 14:50:15', 'Owner': 'svn_p4_converter',
'Options': 'unlocked noautoreload'}
p4 label release-8-1-0-976 mapped to git commit
82a11809928b86a7bde03cf486428de52ab3380f
writing tag release-9-0-0-179 for commit
fb8370cd04806686c567ad720d065436f2334b4a
labelDetails= {'code': 'stat', 'Description': 'Created or modified
with change: 96984, original Date: 2011-12-22T16:01:25.681427Z\n',
'Update': '2013/11/02 15:15:50', 'Label': 'release-9-0-0-179',
'Access': '2015/06/26 14:50:16', 'Owner': 'build', 'Options':
'unlocked noautoreload'}
p4 label release-9-0-0-179 mapped to git commit
fb8370cd04806686c567ad720d065436f2334b4a
Traceback (most recent call last):
   File /usr/lib/git/git-p4, line 3297, in module
 main()
   File /usr/lib/git/git-p4, line 3291, in main
 if not cmd.run(args):
   File /usr/lib/git/git-p4, line 3165, in run
 if not P4Sync.run(self, depotPaths):
   File /usr/lib/git/git-p4, line 3045, in run
 self.importP4Labels(self.gitStream, missingP4Labels)
   File /usr/lib/git/git-p4, line 2421, in importP4Labels
 --reverse, :/\[git-p4:.*change = %d\] % changelist])
   File /usr/lib/git/git-p4, line 138, in read_pipe
 die('Command failed: %s' % str(c))
   File /usr/lib/git/git-p4, line 106, in die
 raise Exception(msg)
Exception: Command failed: ['git', 'rev-list', '--max-count=1',
'--reverse', ':/\\[git-p4:.*change = 69035\\]']





--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v4] clone: simplify string handling in guess_dir_name()

2015-08-04 Thread Sebastian Schuberth
On Tue, Aug 4, 2015 at 6:34 AM, Lukas Fleischer lfleisc...@lfos.de wrote:

 I am currently on vacation and cannot bisect or debug this but I am
 pretty confident that this patch changes the behaviour of directory name
 guessing. With Git 2.4.6, cloning http://foo.bar/foo.git/ results in a
 directory named foo and with Git 2.5.0, the resulting directory is
 called foo.git.

 Note how the end variable is decreased when the repository name ends
 with a slash but that isn't taken into account when simply using
 strip_suffix() later...

 Is this intended?

I did not intend this change in behavior, and I can confirm that
reverting my patch restores the original behavior. Thanks for bringing
this to my attention, I'll work on a patch.

-- 
Sebastian Schuberth
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 4/6] clone: do not use port number as dir name

2015-08-04 Thread Patrick Steinhardt
If the URI contains a port number and the URI's path component is
empty we fail to guess a sensible directory name. E.g. cloning a
repository 'ssh://example.com:/' we guess a directory name
'' where we would want the hostname only, e.g. 'example.com'.

Fix this by stripping trailing port numbers.

Signed-off-by: Patrick Steinhardt p...@pks.im
---
 builtin/clone.c | 17 +
 1 file changed, 17 insertions(+)

diff --git a/builtin/clone.c b/builtin/clone.c
index 794a933..a163797 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -181,6 +181,23 @@ static char *guess_dir_name(const char *repo, int 
is_bundle, int is_bare)
}
 
/*
+* Strip trailing port number if we've got only a
+* hostname (that is, there is no dir separator but a
+* colon). This check is required such that we do not
+* strip URI's like '/foo/bar:.git', which should
+* result in a dir '' being guessed due to backwards
+* compatibility.
+*/
+   if (memchr(start, '/', end - start) == NULL
+memchr(start, ':', end - start) != NULL) {
+   ptr = end;
+   while (start  ptr  isdigit(ptr[-1])  ptr[-1] != ':')
+   ptr--;
+   if (start  ptr  ptr[-1] == ':')
+   end = ptr - 1;
+   }
+
+   /*
 * Find last component. To remain backwards compatible we
 * also regard colons as path separators, such that
 * cloning a repository 'foo:bar.git' would result in a
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 1/6] tests: fix broken chains in t1509-root-worktree

2015-08-04 Thread Patrick Steinhardt
Signed-off-by: Patrick Steinhardt p...@pks.im
---
 t/t1509-root-worktree.sh | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-worktree.sh
index b6977d4..0c80129 100755
--- a/t/t1509-root-worktree.sh
+++ b/t/t1509-root-worktree.sh
@@ -125,7 +125,7 @@ fi
 ONE_SHA1=d00491fd7e5bb6fa28c517a0bb32b8b506539d4d
 
 test_expect_success 'setup' '
-   rm -rf /foo
+   rm -rf /foo 
mkdir /foo 
mkdir /foo/bar 
echo 1  /foo/foome 
@@ -218,7 +218,7 @@ unset GIT_WORK_TREE
 
 test_expect_success 'go to /' 'cd /'
 test_expect_success 'setup' '
-   rm -rf /.git
+   rm -rf /.git 
echo Initialized empty Git repository in /.git/  expected 
git init  result 
test_cmp expected result
@@ -241,8 +241,8 @@ say auto bare gitdir
 
 # DESTROY!
 test_expect_success 'setup' '
-   rm -rf /refs /objects /info /hooks
-   rm /*
+   rm -rf /refs /objects /info /hooks 
+   rm /* 
cd / 
echo Initialized empty Git repository in /  expected 
git init --bare  result 
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 2/6] tests: fix cleanup after tests in t1509-root-worktree

2015-08-04 Thread Patrick Steinhardt
During cleanup we do a simple 'rm /*' to remove leftover files
from previous tests. As 'rm' errors out when there is anything it
cannot delete and there are directories present at '/' it will
throw an error, causing the '' chain to fail.

Fix this by explicitly removing the files.

Signed-off-by: Patrick Steinhardt p...@pks.im
---
 t/t1509-root-worktree.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-worktree.sh
index 0c80129..553a3f6 100755
--- a/t/t1509-root-worktree.sh
+++ b/t/t1509-root-worktree.sh
@@ -242,7 +242,7 @@ say auto bare gitdir
 # DESTROY!
 test_expect_success 'setup' '
rm -rf /refs /objects /info /hooks 
-   rm /* 
+   rm -f /expected /ls.expected /me /result 
cd / 
echo Initialized empty Git repository in /  expected 
git init --bare  result 
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 0/6] fix repo name when cloning a server's root

2015-08-04 Thread Patrick Steinhardt
This is the third version of this patch series. It aims to
improve guessing directory names such that we do not include
authentication data and port numbers in them.

This version drops the patches exposing 'parse_connect_url()' and
instead does the stripping of authentification data and port
inside the URI in 'guess_dir_name()'.

Actually I'm not that happy with the patch as it currently stands
as it requires a lot of complexity to correctly strip the URI
such that we do not mishandle several corner cases. At least I
didn't find any shorter way of doing what I want without breaking
backwards compatibility. I'll try to explain why the more complex
ways of handling the URI are required:

 - The naive way of just adding '@' as path separator would break
   cloning repositories like '/foo/b...@baz.git' (which would
   currently become 'bar@baz' but would become 'baz' only).

 - Skipping the scheme initially is required because without it we
   wouldn't be able to scan until the next dir separator in the
   host part when stripping authentication information.

 - First checking for '/' in the current stripped URI when we
   want to remove the port is required because we do not want to
   strip port numbers when cloning from something like
   '/foo/bar:.git' (which would currently become '' but
   would then be stripped of the ':' part and instead become
   'bar'). Still, this breaks on cloning a bare repository in the
   current dir (e.g. cloning 'bar:.git', which should become
   '' because it is not a port number but would become
   'bar').

As you can see, there is a lot of complexity in there and I'm not
convinced this is better than just exposing
'parse_connect_url()', which already handles everything for us.
Maybe I'm just being blind for the obvious solution here, though.

Patrick Steinhardt (6):
  tests: fix broken  chains in t1509-root-worktree
  tests: fix cleanup after tests in t1509-root-worktree
  clone: do not include authentication data in guessed dir
  clone: do not use port number as dir name
  clone: abort if no dir name could be guessed
  clone: add tests for cloning with empty path

 builtin/clone.c  | 67 
 t/t1509-root-worktree.sh | 51 +---
 2 files changed, 103 insertions(+), 15 deletions(-)

-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3 6/6] clone: add tests for cloning with empty path

2015-08-04 Thread Patrick Steinhardt
Test behavior of `git clone` when working with an empty path
component. This may be the case when cloning a file system's root
directory or from a remote server's root.

Signed-off-by: Patrick Steinhardt p...@pks.im
---
 t/t1509-root-worktree.sh | 43 +++
 1 file changed, 43 insertions(+)

diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-worktree.sh
index 553a3f6..d521ca3 100755
--- a/t/t1509-root-worktree.sh
+++ b/t/t1509-root-worktree.sh
@@ -237,6 +237,49 @@ test_foobar_foobar
 
 test_expect_success 'cleanup' 'rm -rf /.git'
 
+say clone .git at root without reponame
+
+test_expect_success 'go to /' 'cd /'
+test_expect_success 'setup' '
+   echo Initialized empty Git repository in /.git/  expected 
+   git init  result 
+   test_cmp expected result
+'
+
+test_clone_expect_dir() {
+   URL=$1
+   DIR=$2
+   cat -EOF expected 
+   Cloning into '$DIR'...
+   warning: You appear to have cloned an empty repository.
+   EOF
+   git clone $URL result 21 
+   rm -rf $DIR 
+   test_cmp expected result
+}
+
+test_expect_success 'go to /clones' 'mkdir /clones  cd /clones'
+test_expect_success 'simple clone of /' '
+   cat -EOF expected 
+   fatal: No directory name could be guessed.
+   Please specify a directory on the command line
+   EOF
+   test_expect_code 128 git clone / result 21 
+   test_cmp expected result'
+
+test_expect_success 'clone with file://host/' '
+   test_clone_expect_dir file://127.0.0.1/ 127.0.0.1'
+test_expect_success 'clone with file://user@host/' '
+   test_clone_expect_dir file://user@127.0.0.1/ 127.0.0.1'
+test_expect_success 'clone with file://user:password@host/' '
+   test_clone_expect_dir file://user:password@127.0.0.1/ 127.0.0.1'
+test_expect_success 'clone with file://host:port/' '
+   test_clone_expect_dir file://127.0.0.1:/ 127.0.0.1'
+test_expect_success 'clone with file://user:password@host:port' '
+   test_clone_expect_dir file://user:password@127.0.0.1:/ 127.0.0.1'
+
+test_expect_success 'cleanup' 'rm -rf /.git /clones'
+
 say auto bare gitdir
 
 # DESTROY!
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3] remote: add get-url subcommand

2015-08-04 Thread Ben Boeckel
Expanding `insteadOf` is a part of ls-remote --url and there is no way
to expand `pushInsteadOf` as well. Add a get-url subcommand to be able
to query both as well as a way to get all configured urls.

Signed-off-by: Ben Boeckel maths...@gmail.com
---
 Documentation/git-remote.txt | 10 
 builtin/remote.c | 54 
 2 files changed, 64 insertions(+)

diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 4c6d6de..3c9bf45 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -15,6 +15,7 @@ SYNOPSIS
 'git remote remove' name
 'git remote set-head' name (-a | --auto | -d | --delete | branch)
 'git remote set-branches' [--add] name branch...
+'git remote get-url' [--push] [--all] name
 'git remote set-url' [--push] name newurl [oldurl]
 'git remote set-url --add' [--push] name newurl
 'git remote set-url --delete' [--push] name url
@@ -131,6 +132,15 @@ The named branches will be interpreted as if specified 
with the
 With `--add`, instead of replacing the list of currently tracked
 branches, adds to that list.
 
+'get-url'::
+
+Retrieves the URLs for a remote. Configurations for `insteadOf` and
+`pushInsteadOf` are expanded here. By default, only the first URL is listed.
++
+With '--push', push URLs are queried rather than fetch URLs.
++
+With '--all', all URLs for the remote will be listed.
+
 'set-url'::
 
 Changes URLs for the remote. Sets first URL for remote name that matches
diff --git a/builtin/remote.c b/builtin/remote.c
index f4a6ec9..904869a 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -18,6 +18,7 @@ static const char * const builtin_remote_usage[] = {
N_(git remote prune [-n | --dry-run] name),
N_(git remote [-v | --verbose] update [-p | --prune] [(group | 
remote)...]),
N_(git remote set-branches [--add] name branch...),
+   N_(git remote get-url [--push] [--all] name),
N_(git remote set-url [--push] name newurl [oldurl]),
N_(git remote set-url --add name newurl),
N_(git remote set-url --delete name url),
@@ -65,6 +66,11 @@ static const char * const builtin_remote_update_usage[] = {
NULL
 };
 
+static const char * const builtin_remote_geturl_usage[] = {
+   N_(git remote get-url [--push] [--all] name),
+   NULL
+};
+
 static const char * const builtin_remote_seturl_usage[] = {
N_(git remote set-url [--push] name newurl [oldurl]),
N_(git remote set-url --add name newurl),
@@ -1497,6 +1503,52 @@ static int set_branches(int argc, const char **argv)
return set_remote_branches(argv[0], argv + 1, add_mode);
 }
 
+static int get_url(int argc, const char **argv)
+{
+   int i, push_mode = 0, all_mode = 0;
+   const char *remotename = NULL;
+   struct remote *remote;
+   const char **url;
+   int url_nr;
+   struct option options[] = {
+   OPT_BOOL('\0', push, push_mode,
+N_(query push URLs rather than fetch URLs)),
+   OPT_BOOL('\0', all, all_mode,
+N_(return all URLs)),
+   OPT_END()
+   };
+   argc = parse_options(argc, argv, NULL, options, 
builtin_remote_geturl_usage, 0);
+
+   if (argc != 1)
+   usage_with_options(builtin_remote_geturl_usage, options);
+
+   remotename = argv[0];
+
+   if (!remote_is_configured(remotename))
+   die(_(No such remote '%s'), remotename);
+   remote = remote_get(remotename);
+
+   if (push_mode) {
+   url = remote-pushurl;
+   url_nr = remote-pushurl_nr;
+   } else {
+   url = remote-url;
+   url_nr = remote-url_nr;
+   }
+
+   if (!url_nr)
+   die(_(no URLs configured for remote '%s'), remotename);
+
+   if (all_mode) {
+   for (i = 0; i  url_nr; i++)
+   printf_ln(%s, url[i]);
+   } else {
+   printf_ln(%s, *url);
+   }
+
+   return 0;
+}
+
 static int set_url(int argc, const char **argv)
 {
int i, push_mode = 0, add_mode = 0, delete_mode = 0;
@@ -1606,6 +1658,8 @@ int cmd_remote(int argc, const char **argv, const char 
*prefix)
result = set_head(argc, argv);
else if (!strcmp(argv[0], set-branches))
result = set_branches(argc, argv);
+   else if (!strcmp(argv[0], get-url))
+   result = get_url(argc, argv);
else if (!strcmp(argv[0], set-url))
result = set_url(argc, argv);
else if (!strcmp(argv[0], show))
-- 
2.1.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


допоможіть сайту нашої школи http://154school.kiev.ua/ - будь ласка, відкрийте його для перегляду однієї-двох сторінок,

2015-08-04 Thread admin
Доброго дня, 
будь ласка, просимо переглянути наш шкільний сайт,
якщо це не важко для вас,
http://154school.kiev.ua/ - будь ласка, відкрийте його для перегляду 
однієї-двох сторінок,
і на будь-якій сторінці один раз натисніть на рекламний банер, який вам 
найбільш цікавий,
це Ваша допомога, щоб ми могли заплатити за хостинг нашого шкільного сайту,
дякуємо,
системний адміністратор
ad...@154school.kiev.ua
http://154school.kiev.ua/

hello, 
our school site require you view,
please, if it's not hard for you, 
http://154school.kiev.ua/ - please open it for viewing our site - one or two 
pages,
and on any page, 
click once on the advertising banner that most interesting for you,
it is your help to pay for hosting our school site,
thank you
system Administrator
ad...@154school.kiev.ua
http://154school.kiev.ua/

 
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] git_open_noatime: return with errno=0 on success

2015-08-04 Thread Clemens Buchacher
In read_sha1_file_extended we die if read_object fails with a fatal
error. We detect a fatal error if errno is non-zero and is not
ENOENT. If the object could not be read because it does not exist,
this is not considered a fatal error and we want to return NULL.

Somewhere down the line, read_object calls git_open_noatime to open
a pack index file, for example. We first try open with O_NOATIME.
If O_NOATIME fails with EPERM, we retry without O_NOATIME. When the
second open succeeds, errno is however still set to EPERM from the
first attempt. When we finally determine that the object does not
exist, read_object returns NULL and read_sha1_file_extended dies
with a fatal error:

fatal: failed to read object sha1: Operation not permitted

Fix this by resetting errno to zero before we call open again.

Cc: Linus Torvalds torva...@linux-foundation.org
Signed-off-by: Clemens Buchacher clemens.buchac...@intel.com
---

This is a re-submission without changes except for a typo fix in the
comments (thanks Eric). The original submission received no other
comments, but I think it is a clear improvement and I hope it was just
missed the first time.

Best regards,
Clemens

 sha1_file.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sha1_file.c b/sha1_file.c
index 77cd81d..62b7ad6 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1453,6 +1453,7 @@ int git_open_noatime(const char *name)
static int sha1_file_open_flag = O_NOATIME;
 
for (;;) {
+   errno = 0;
int fd = open(name, O_RDONLY | sha1_file_open_flag);
if (fd = 0)
return fd;
-- 
1.9.4

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 07/10] branch.c: use 'ref-filter' data structures

2015-08-04 Thread Karthik Nayak
Make 'branch.c' use 'ref-filter' data structures and make changes to
support the new data structures. This is a part of the process of
porting 'branch.c' to use 'ref-filter' APIs.

This is a temporary step before porting 'branch.c' to use 'ref-filter'
completely. As this is a temporary step, most of the code introduced
here will be removed when 'branch.c' is ported over to use
'ref-filter' APIs

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 builtin/branch.c | 295 ++-
 ref-filter.h |   7 +-
 2 files changed, 122 insertions(+), 180 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 1ac7fbc..edc3d7d 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -19,6 +19,7 @@
 #include column.h
 #include utf8.h
 #include wt-status.h
+#include ref-filter.h
 
 static const char * const builtin_branch_usage[] = {
N_(git branch [options] [-r | -a] [--merged | --no-merged]),
@@ -28,10 +29,6 @@ static const char * const builtin_branch_usage[] = {
NULL
 };
 
-#define REF_LOCAL_BRANCH0x01
-#define REF_REMOTE_BRANCH   0x02
-#define REF_DETACHED_HEAD   0x04
-
 static const char *head;
 static unsigned char head_sha1[20];
 
@@ -53,13 +50,6 @@ enum color_branch {
BRANCH_COLOR_UPSTREAM = 5
 };
 
-static enum merge_filter {
-   NO_FILTER = 0,
-   SHOW_NOT_MERGED,
-   SHOW_MERGED
-} merge_filter;
-static unsigned char merge_filter_ref[20];
-
 static struct string_list output = STRING_LIST_INIT_DUP;
 static unsigned int colopts;
 
@@ -280,22 +270,6 @@ static int delete_branches(int argc, const char **argv, 
int force, int kinds,
return(ret);
 }
 
-struct ref_item {
-   char *name;
-   char *dest;
-   unsigned int kind;
-   struct commit *commit;
-   int ignore;
-};
-
-struct ref_list {
-   struct rev_info revs;
-   int index, alloc, verbose, abbrev;
-   struct ref_item *list;
-   struct commit_list *with_commit;
-   int kinds;
-};
-
 static char *resolve_symref(const char *src, const char *prefix)
 {
unsigned char sha1[20];
@@ -310,11 +284,6 @@ static char *resolve_symref(const char *src, const char 
*prefix)
return xstrdup(dst);
 }
 
-struct append_ref_cb {
-   struct ref_list *ref_list;
-   const char **pattern;
-};
-
 static int match_patterns(const char **pattern, const char *refname)
 {
if (!*pattern)
@@ -327,11 +296,29 @@ static int match_patterns(const char **pattern, const 
char *refname)
return 0;
 }
 
+/*
+ * Allocate memory for a new ref_array_item and insert that into the
+ * given ref_array. Doesn't take the objectname unlike
+ * new_ref_array_item(). This is a temporary function which will be
+ * removed when we port branch.c to use ref-filter APIs.
+ */
+static struct ref_array_item *ref_array_append(struct ref_array *array, const 
char *refname)
+{
+   size_t len = strlen(refname);
+   struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + 
len + 1);
+   memcpy(ref-refname, refname, len);
+   ref-refname[len] = '\0';
+   REALLOC_ARRAY(array-items, array-nr + 1);
+   array-items[array-nr++] = ref;
+   return ref;
+}
+
 static int append_ref(const char *refname, const struct object_id *oid, int 
flags, void *cb_data)
 {
-   struct append_ref_cb *cb = (struct append_ref_cb *)(cb_data);
-   struct ref_list *ref_list = cb-ref_list;
-   struct ref_item *newitem;
+   struct ref_filter_cbdata *cb = (struct ref_filter_cbdata *)(cb_data);
+   struct ref_filter *filter = cb-filter;
+   struct ref_array *array = cb-array;
+   struct ref_array_item *item;
struct commit *commit;
int kind, i;
const char *prefix, *orig_refname = refname;
@@ -360,59 +347,46 @@ static int append_ref(const char *refname, const struct 
object_id *oid, int flag
}
 
/* Don't add types the caller doesn't want */
-   if ((kind  ref_list-kinds) == 0)
+   if ((kind  filter-branch_kind) == 0)
return 0;
 
-   if (!match_patterns(cb-pattern, refname))
+   if (!match_patterns(filter-name_patterns, refname))
return 0;
 
commit = NULL;
-   if (ref_list-verbose || ref_list-with_commit || merge_filter != 
NO_FILTER) {
+   if (filter-verbose || filter-with_commit || filter-merge != 
REF_FILTER_MERGED_NONE) {
commit = lookup_commit_reference_gently(oid-hash, 1);
if (!commit)
return 0;
 
/* Filter with with_commit if specified */
-   if (!is_descendant_of(commit, ref_list-with_commit))
+   if (!is_descendant_of(commit, filter-with_commit))
return 0;
 
-   if (merge_filter != NO_FILTER)
-   add_pending_object(ref_list-revs,
+

[PATCH 03/10] branch: bump get_head_description() to the top

2015-08-04 Thread Karthik Nayak
This is a preperatory patch for 'roll show_detached HEAD into regular
ref_list'. This patch moves get_head_descrition() to the top so that
it can be used in print_ref_item().

Based-on-patch-by: Jeff King p...@peff.net
Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 builtin/branch.c | 62 
 1 file changed, 31 insertions(+), 31 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index b058b74..65f6d0d 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -497,6 +497,37 @@ static void add_verbose_info(struct strbuf *out, struct 
ref_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) {
+   /* 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);
+}
+
 static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
   int abbrev, int current, const char *remote_prefix)
 {
@@ -569,37 +600,6 @@ static int calc_maxwidth(struct ref_list *refs, int 
remote_bonus)
return max;
 }
 
-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) {
-   /* 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);
-}
-
 static void show_detached(struct ref_list *ref_list, int maxwidth)
 {
struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 
1);
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 05/10] branch: move 'current' check down to the presentation layer

2015-08-04 Thread Karthik Nayak
We check if given ref is the current branch in print_ref_list(). Move
this check to print_ref_item() where it is checked right before
printing.

Based-on-patch-by: Jeff King p...@peff.net
Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 builtin/branch.c | 22 +++---
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 81815c9..c5f2944 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -534,9 +534,10 @@ static char *get_head_description(void)
 }
 
 static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
-  int abbrev, int current, const char *remote_prefix)
+  int abbrev, int detached, const char *remote_prefix)
 {
char c;
+   int current = 0;
int color;
struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
const char *prefix = ;
@@ -547,15 +548,18 @@ static void print_ref_item(struct ref_item *item, int 
maxwidth, int verbose,
 
switch (item-kind) {
case REF_LOCAL_BRANCH:
-   color = BRANCH_COLOR_LOCAL;
+   if (!detached  !strcmp(item-name, head))
+   current = 1;
+   else
+   color = BRANCH_COLOR_LOCAL;
break;
case REF_REMOTE_BRANCH:
color = BRANCH_COLOR_REMOTE;
prefix = remote_prefix;
break;
case REF_DETACHED_HEAD:
-   color = BRANCH_COLOR_CURRENT;
desc = get_head_description();
+   current = 1;
break;
default:
color = BRANCH_COLOR_PLAIN;
@@ -684,21 +688,17 @@ static int print_ref_list(int kinds, int detached, int 
verbose, int abbrev, stru
index = ref_list.index;
 
/* Print detached HEAD before sorting and printing the rest */
-   if (detached  (ref_list.list[index - 1].kind == REF_DETACHED_HEAD) 
-   !strcmp(ref_list.list[index - 1].name, head)) {
+   if (detached) {
print_ref_item(ref_list.list[index - 1], maxwidth, verbose, 
abbrev,
-  1, remote_prefix);
+  detached, remote_prefix);
index -= 1;
}
 
qsort(ref_list.list, index, sizeof(struct ref_item), ref_cmp);
 
-   for (i = 0; i  index; i++) {
-   int current = !detached  (ref_list.list[i].kind == 
REF_LOCAL_BRANCH) 
-   !strcmp(ref_list.list[i].name, head);
+   for (i = 0; i  index; i++)
print_ref_item(ref_list.list[i], maxwidth, verbose,
-  abbrev, current, remote_prefix);
-   }
+  abbrev, detached, remote_prefix);
 
free_ref_list(ref_list);
 
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 06/10] branch: drop non-commit error reporting

2015-08-04 Thread Karthik Nayak
Remove the error reporting variable to make the code easier to port
over to using ref-filter APIs.

Based-on-patch-by: Jeff King p...@peff.net
Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 builtin/branch.c | 18 --
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index c5f2944..1ac7fbc 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -313,7 +313,6 @@ static char *resolve_symref(const char *src, const char 
*prefix)
 struct append_ref_cb {
struct ref_list *ref_list;
const char **pattern;
-   int ret;
 };
 
 static int match_patterns(const char **pattern, const char *refname)
@@ -370,10 +369,8 @@ static int append_ref(const char *refname, const struct 
object_id *oid, int flag
commit = NULL;
if (ref_list-verbose || ref_list-with_commit || merge_filter != 
NO_FILTER) {
commit = lookup_commit_reference_gently(oid-hash, 1);
-   if (!commit) {
-   cb-ret = error(_(branch '%s' does not point at a 
commit), refname);
+   if (!commit)
return 0;
-   }
 
/* Filter with with_commit if specified */
if (!is_descendant_of(commit, ref_list-with_commit))
@@ -616,7 +613,7 @@ static int calc_maxwidth(struct ref_list *refs, int 
remote_bonus)
return max;
 }
 
-static int print_ref_list(int kinds, int detached, int verbose, int abbrev, 
struct commit_list *with_commit, const char **pattern)
+static void print_ref_list(int kinds, int detached, int verbose, int abbrev, 
struct commit_list *with_commit, const char **pattern)
 {
int i, index;
struct append_ref_cb cb;
@@ -641,7 +638,6 @@ static int print_ref_list(int kinds, int detached, int 
verbose, int abbrev, stru
init_revisions(ref_list.revs, NULL);
cb.ref_list = ref_list;
cb.pattern = pattern;
-   cb.ret = 0;
/*
 * First we obtain all regular branch refs and then if the
 * HEAD is detached then we insert that ref to the end of the
@@ -701,11 +697,6 @@ static int print_ref_list(int kinds, int detached, int 
verbose, int abbrev, stru
   abbrev, detached, remote_prefix);
 
free_ref_list(ref_list);
-
-   if (cb.ret)
-   error(_(some refs could not be read));
-
-   return cb.ret;
 }
 
 static void rename_branch(const char *oldname, const char *newname, int force)
@@ -921,15 +912,14 @@ int cmd_branch(int argc, const char **argv, const char 
*prefix)
die(_(branch name required));
return delete_branches(argc, argv, delete  1, kinds, quiet);
} else if (list) {
-   int ret;
/*  git branch --local also shows HEAD when it is detached */
if (kinds  REF_LOCAL_BRANCH)
kinds |= REF_DETACHED_HEAD;
-   ret = print_ref_list(kinds, detached, verbose, abbrev,
+   print_ref_list(kinds, detached, verbose, abbrev,
 with_commit, argv);
print_columns(output, colopts, NULL);
string_list_clear(output, 0);
-   return ret;
+   return 0;
}
else if (edit_description) {
const char *branch_name;
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/10] Port branch.c to ref-filter.

2015-08-04 Thread Karthik Nayak
This is part of my GSoC project to unify git tag -l, git branch -l,
git for-each-ref.  This patch series is continued from: Git (next)
https://github.com/git/git/commit/bf5418f49ff0cebc6e5ce04ad1417e1a47c81b61

This series consists of porting branch.c over to using the ref-filter
APIs. This does not involve the usage of show_ref_array_item() as it
has its own changes to be made, and on suggestion of my mentors I have
decided to split the porting of branch.c to this and eventually
implementation of the --format option.

The RFC version can be found here :
article.gmane.org/gmane.comp.version-control.git/274737

This is a follow up to the port of tag.c to use ref-filter APIs.
(currently in the 9th iteration)

Changes :
* Change the order of ref_kind[] structure in filter_branch_kind.
* Commit message changes.
* Comments added if required.
* Small code changes.

No interdiff as this was a split version and might as well be treated
as the start of the patch series.

-- 
Regards,
Karthik Nayak
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 04/10] branch: roll show_detached HEAD into regular ref_list

2015-08-04 Thread Karthik Nayak
Remove show_detached() and make detached HEAD to be rolled into
regular ref_list by adding REF_DETACHED_HEAD as a kind of branch and
supporting the same in append_ref(). This eliminates the need for an
extra function and helps in easier porting of branch.c to use
ref-filter APIs.

Before show_detached() used to check if the HEAD branch satisfies the
'--contains' option, now that is taken care by append_ref().

Based-on-patch-by: Jeff King p...@peff.net
Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 builtin/branch.c | 68 +---
 1 file changed, 40 insertions(+), 28 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 65f6d0d..81815c9 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -30,6 +30,7 @@ static const char * const builtin_branch_usage[] = {
 
 #define REF_LOCAL_BRANCH0x01
 #define REF_REMOTE_BRANCH   0x02
+#define REF_DETACHED_HEAD   0x04
 
 static const char *head;
 static unsigned char head_sha1[20];
@@ -352,8 +353,12 @@ static int append_ref(const char *refname, const struct 
object_id *oid, int flag
break;
}
}
-   if (ARRAY_SIZE(ref_kind) = i)
-   return 0;
+   if (ARRAY_SIZE(ref_kind) = i) {
+   if (!strcmp(refname, HEAD))
+   kind = REF_DETACHED_HEAD;
+   else
+   return 0;
+   }
 
/* Don't add types the caller doesn't want */
if ((kind  ref_list-kinds) == 0)
@@ -535,6 +540,7 @@ static void print_ref_item(struct ref_item *item, int 
maxwidth, int verbose,
int color;
struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
const char *prefix = ;
+   const char *desc = item-name;
 
if (item-ignore)
return;
@@ -547,6 +553,10 @@ static void print_ref_item(struct ref_item *item, int 
maxwidth, int verbose,
color = BRANCH_COLOR_REMOTE;
prefix = remote_prefix;
break;
+   case REF_DETACHED_HEAD:
+   color = BRANCH_COLOR_CURRENT;
+   desc = get_head_description();
+   break;
default:
color = BRANCH_COLOR_PLAIN;
break;
@@ -558,7 +568,7 @@ static void print_ref_item(struct ref_item *item, int 
maxwidth, int verbose,
color = BRANCH_COLOR_CURRENT;
}
 
-   strbuf_addf(name, %s%s, prefix, item-name);
+   strbuf_addf(name, %s%s, prefix, desc);
if (verbose) {
int utf8_compensation = strlen(name.buf) - 
utf8_strwidth(name.buf);
strbuf_addf(out, %c %s%-*s%s, c, branch_get_color(color),
@@ -581,6 +591,8 @@ static void print_ref_item(struct ref_item *item, int 
maxwidth, int verbose,
}
strbuf_release(name);
strbuf_release(out);
+   if (item-kind == REF_DETACHED_HEAD)
+   free((void *)desc);
 }
 
 static int calc_maxwidth(struct ref_list *refs, int remote_bonus)
@@ -600,25 +612,9 @@ static int calc_maxwidth(struct ref_list *refs, int 
remote_bonus)
return max;
 }
 
-static void show_detached(struct ref_list *ref_list, int maxwidth)
-{
-   struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 
1);
-
-   if (head_commit  is_descendant_of(head_commit, 
ref_list-with_commit)) {
-   struct ref_item item;
-   item.name = get_head_description();
-   item.kind = REF_LOCAL_BRANCH;
-   item.dest = NULL;
-   item.commit = head_commit;
-   item.ignore = 0;
-   print_ref_item(item, maxwidth, ref_list-verbose, 
ref_list-abbrev, 1, );
-   free(item.name);
-   }
-}
-
 static int print_ref_list(int kinds, int detached, int verbose, int abbrev, 
struct commit_list *with_commit, const char **pattern)
 {
-   int i;
+   int i, index;
struct append_ref_cb cb;
struct ref_list ref_list;
int maxwidth = 0;
@@ -642,7 +638,14 @@ static int print_ref_list(int kinds, int detached, int 
verbose, int abbrev, stru
cb.ref_list = ref_list;
cb.pattern = pattern;
cb.ret = 0;
+   /*
+* First we obtain all regular branch refs and then if the
+* HEAD is detached then we insert that ref to the end of the
+* ref_fist so that it can be printed first.
+*/
for_each_rawref(append_ref, cb);
+   if (detached)
+   head_ref(append_ref, cb);
/*
 * The following implementation is currently duplicated in ref-filter. 
It
 * will eventually be removed when we port branch.c to use ref-filter 
APIs.
@@ -678,15 +681,20 @@ static int print_ref_list(int kinds, int detached, int 
verbose, int abbrev, stru
if (verbose)
maxwidth = calc_maxwidth(ref_list, 

[PATCH 09/10] branch: add '--points-at' option

2015-08-04 Thread Karthik Nayak
Add the '--points-at' option provided by 'ref-filter'. The option lets
the user to list only branches which points at the given object.

Add documentation and tests for the same.

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 Documentation/git-branch.txt | 6 +-
 builtin/branch.c | 7 ++-
 t/t3203-branch-output.sh | 9 +
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 897cd81..211cfc3 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -11,7 +11,8 @@ SYNOPSIS
 'git branch' [--color[=when] | --no-color] [-r | -a]
[--list] [-v [--abbrev=length | --no-abbrev]]
[--column[=options] | --no-column]
-   [(--merged | --no-merged | --contains) [commit]] [--sort=key] 
[pattern...]
+   [(--merged | --no-merged | --contains) [commit]] [--sort=key]
+   [--points-at object] [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]
@@ -237,6 +238,9 @@ start-point is either a local or remote-tracking branch.
for-each-ref`. Sort order defaults to sorting based on branch
type.
 
+--points-at object::
+   Only list branches of the given object.
+
 Examples
 
 
diff --git a/builtin/branch.c b/builtin/branch.c
index 34ccf0c..5dad1da 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -26,6 +26,7 @@ static const char * const builtin_branch_usage[] = {
N_(git branch [options] [-l] [-f] branch-name [start-point]),
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]),
NULL
 };
 
@@ -654,6 +655,10 @@ int cmd_branch(int argc, const char **argv, const char 
*prefix)
OPT_COLUMN(0, column, colopts, N_(list branches in 
columns)),
OPT_CALLBACK(0 , sort, sorting_tail, N_(key),
 N_(field name to sort on), 
parse_opt_ref_sorting),
+   {
+   OPTION_CALLBACK, 0, points-at, filter.points_at, 
N_(object),
+   N_(print only branches of the object), 0, 
parse_opt_object_name
+   },
OPT_END(),
};
 
@@ -682,7 +687,7 @@ int cmd_branch(int argc, const char **argv, const char 
*prefix)
if (!delete  !rename  !edit_description  !new_upstream  
!unset_upstream  argc == 0)
list = 1;
 
-   if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE)
+   if (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || 
filter.points_at.nr)
list = 1;
 
if (!!delete + !!rename + !!new_upstream +
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 38c68bd..1deb7cb 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -154,4 +154,13 @@ EOF
test_i18ncmp expect actual
 '
 
+test_expect_success 'git branch --points-at option' '
+   cat expect EOF 
+  master
+  branch-one
+EOF
+   git branch --points-at=branch-one actual 
+   test_cmp expect actual
+'
+
 test_done
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 08/10] branch.c: use 'ref-filter' APIs

2015-08-04 Thread Karthik Nayak
Make 'branch.c' use 'ref-filter' APIs for iterating through refs
sorting. This removes most of the code used in 'branch.c' replacing it
with calls to the 'ref-filter' library.

Make 'branch.c' use the 'filter_refs()' function provided by 'ref-filter'
to filter out tags based on the options set.

We provide a sorting option provided for 'branch.c' by using the sorting
options provided by 'ref-filter'.

Also remove the 'ignore' variable from ref_array_item as it was
previously used for the '--merged' option and now that is handled by
ref-filter.

The test t1430 'git branch shows badly named ref' fails as this checks
the ability of branch.c to list broken refs, which is now displayed as
a warning while using ref-filter APIs.

Modify documentation and add tests for the same.

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 Documentation/git-branch.txt |   9 +-
 builtin/branch.c | 219 ---
 ref-filter.c |   8 +-
 ref-filter.h |   1 -
 t/t1430-bad-ref-name.sh  |  10 +-
 t/t3203-branch-output.sh |  11 +++
 6 files changed, 68 insertions(+), 190 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index a67138a..897cd81 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -11,7 +11,7 @@ SYNOPSIS
 'git branch' [--color[=when] | --no-color] [-r | -a]
[--list] [-v [--abbrev=length | --no-abbrev]]
[--column[=options] | --no-column]
-   [(--merged | --no-merged | --contains) [commit]] [pattern...]
+   [(--merged | --no-merged | --contains) [commit]] [--sort=key] 
[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]
@@ -229,6 +229,13 @@ start-point is either a local or remote-tracking branch.
The new name for an existing branch. The same restrictions as for
branchname apply.
 
+--sort=key::
+   Sort based on the key given. Prefix `-` to sort in descending
+   order of the value. You may use the --sort=key option
+   multiple times, in which case the last key becomes the primary
+   key. The keys supported are the same as those in `git
+   for-each-ref`. Sort order defaults to sorting based on branch
+   type.
 
 Examples
 
diff --git a/builtin/branch.c b/builtin/branch.c
index edc3d7d..34ccf0c 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -270,125 +270,6 @@ static int delete_branches(int argc, const char **argv, 
int force, int kinds,
return(ret);
 }
 
-static char *resolve_symref(const char *src, const char *prefix)
-{
-   unsigned char sha1[20];
-   int flag;
-   const char *dst;
-
-   dst = resolve_ref_unsafe(src, 0, sha1, flag);
-   if (!(dst  (flag  REF_ISSYMREF)))
-   return NULL;
-   if (prefix)
-   skip_prefix(dst, prefix, dst);
-   return xstrdup(dst);
-}
-
-static int match_patterns(const char **pattern, const char *refname)
-{
-   if (!*pattern)
-   return 1; /* no pattern always matches */
-   while (*pattern) {
-   if (!wildmatch(*pattern, refname, 0, NULL))
-   return 1;
-   pattern++;
-   }
-   return 0;
-}
-
-/*
- * Allocate memory for a new ref_array_item and insert that into the
- * given ref_array. Doesn't take the objectname unlike
- * new_ref_array_item(). This is a temporary function which will be
- * removed when we port branch.c to use ref-filter APIs.
- */
-static struct ref_array_item *ref_array_append(struct ref_array *array, const 
char *refname)
-{
-   size_t len = strlen(refname);
-   struct ref_array_item *ref = xcalloc(1, sizeof(struct ref_array_item) + 
len + 1);
-   memcpy(ref-refname, refname, len);
-   ref-refname[len] = '\0';
-   REALLOC_ARRAY(array-items, array-nr + 1);
-   array-items[array-nr++] = ref;
-   return ref;
-}
-
-static int append_ref(const char *refname, const struct object_id *oid, int 
flags, void *cb_data)
-{
-   struct ref_filter_cbdata *cb = (struct ref_filter_cbdata *)(cb_data);
-   struct ref_filter *filter = cb-filter;
-   struct ref_array *array = cb-array;
-   struct ref_array_item *item;
-   struct commit *commit;
-   int kind, i;
-   const char *prefix, *orig_refname = refname;
-
-   static struct {
-   int kind;
-   const char *prefix;
-   } ref_kind[] = {
-   { REF_LOCAL_BRANCH, refs/heads/ },
-   { REF_REMOTE_BRANCH, refs/remotes/ },
-   };
-
-   /* Detect kind */
-   for (i = 0; i  ARRAY_SIZE(ref_kind); i++) {
-   prefix = ref_kind[i].prefix;
-   if 

[PATCH 02/10] branch: refactor width computation

2015-08-04 Thread Karthik Nayak
From: Karthik Nayak karthik@gmail.com

Remove unnecessary variables from ref_list and ref_item which were
used for width computation. This is to make ref_item similar to
ref-filter's ref_array_item. This will ensure a smooth port of
branch.c to use ref-filter APIs in further patches.

Previously the maxwidth was computed when inserting the refs into the
ref_list. Now, we obtain the entire ref_list and then compute
maxwidth.

Based-on-patch-by: Jeff King p...@peff.net
Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 builtin/branch.c | 61 +---
 1 file changed, 32 insertions(+), 29 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 4fc8beb..b058b74 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -282,14 +282,14 @@ static int delete_branches(int argc, const char **argv, 
int force, int kinds,
 struct ref_item {
char *name;
char *dest;
-   unsigned int kind, width;
+   unsigned int kind;
struct commit *commit;
int ignore;
 };
 
 struct ref_list {
struct rev_info revs;
-   int index, alloc, maxwidth, verbose, abbrev;
+   int index, alloc, verbose, abbrev;
struct ref_item *list;
struct commit_list *with_commit;
int kinds;
@@ -386,15 +386,8 @@ static int append_ref(const char *refname, const struct 
object_id *oid, int flag
newitem-name = xstrdup(refname);
newitem-kind = kind;
newitem-commit = commit;
-   newitem-width = utf8_strwidth(refname);
newitem-dest = resolve_symref(orig_refname, prefix);
newitem-ignore = 0;
-   /* adjust for remotes/ */
-   if (newitem-kind == REF_REMOTE_BRANCH 
-   ref_list-kinds != REF_REMOTE_BRANCH)
-   newitem-width += 8;
-   if (newitem-width  ref_list-maxwidth)
-   ref_list-maxwidth = newitem-width;
 
return 0;
 }
@@ -505,11 +498,12 @@ static void add_verbose_info(struct strbuf *out, struct 
ref_item *item,
 }
 
 static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
-  int abbrev, int current, char *prefix)
+  int abbrev, int current, const char *remote_prefix)
 {
char c;
int color;
struct strbuf out = STRBUF_INIT, name = STRBUF_INIT;
+   const char *prefix = ;
 
if (item-ignore)
return;
@@ -520,6 +514,7 @@ static void print_ref_item(struct ref_item *item, int 
maxwidth, int verbose,
break;
case REF_REMOTE_BRANCH:
color = BRANCH_COLOR_REMOTE;
+   prefix = remote_prefix;
break;
default:
color = BRANCH_COLOR_PLAIN;
@@ -557,16 +552,21 @@ static void print_ref_item(struct ref_item *item, int 
maxwidth, int verbose,
strbuf_release(out);
 }
 
-static int calc_maxwidth(struct ref_list *refs)
+static int calc_maxwidth(struct ref_list *refs, int remote_bonus)
 {
-   int i, w = 0;
+   int i, max = 0;
for (i = 0; i  refs-index; i++) {
+   struct ref_item *it = refs-list[i];
+   int w = utf8_strwidth(it-name);
+
if (refs-list[i].ignore)
continue;
-   if (refs-list[i].width  w)
-   w = refs-list[i].width;
+   if (it-kind == REF_REMOTE_BRANCH)
+   w += remote_bonus;
+   if (w  max)
+   max = w;
}
-   return w;
+   return max;
 }
 
 static char *get_head_description(void)
@@ -600,21 +600,18 @@ static char *get_head_description(void)
return strbuf_detach(desc, NULL);
 }
 
-static void show_detached(struct ref_list *ref_list)
+static void show_detached(struct ref_list *ref_list, int maxwidth)
 {
struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 
1);
 
if (head_commit  is_descendant_of(head_commit, 
ref_list-with_commit)) {
struct ref_item item;
item.name = get_head_description();
-   item.width = utf8_strwidth(item.name);
item.kind = REF_LOCAL_BRANCH;
item.dest = NULL;
item.commit = head_commit;
item.ignore = 0;
-   if (item.width  ref_list-maxwidth)
-   ref_list-maxwidth = item.width;
-   print_ref_item(item, ref_list-maxwidth, ref_list-verbose, 
ref_list-abbrev, 1, );
+   print_ref_item(item, maxwidth, ref_list-verbose, 
ref_list-abbrev, 1, );
free(item.name);
}
 }
@@ -624,6 +621,16 @@ static int print_ref_list(int kinds, int detached, int 
verbose, int abbrev, stru
int i;
struct append_ref_cb cb;
struct ref_list ref_list;
+   int maxwidth = 0;
+   const char 

Re: [PATCH 0/10] Port branch.c to ref-filter.

2015-08-04 Thread Karthik Nayak
There are nine patches in the series. Have put 0/10 by mistake.

-- 
Regards,
Karthik Nayak
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 01/10] ref-filter: add option to filter only branches

2015-08-04 Thread Karthik Nayak
From: Karthik Nayak karthik@gmail.com

Add an option in 'filter_refs()' to use 'for_each_branch_ref()'
and filter refs. This type checking is done by adding a
'FILTER_REFS_BRANCHES' in 'ref-filter.h'.

Add an option in 'ref_filter_handler()' to filter different
types of branches by calling 'filter_branch_kind()' which
checks for the type of branch needed.

Mentored-by: Christian Couder christian.cou...@gmail.com
Mentored-by: Matthieu Moy matthieu@grenoble-inp.fr
Signed-off-by: Karthik Nayak karthik@gmail.com
---
 ref-filter.c | 47 +++
 ref-filter.h | 10 --
 2 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/ref-filter.c b/ref-filter.c
index de84dd4..c573109 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1044,6 +1044,46 @@ static const unsigned char *match_points_at(struct 
sha1_array *points_at,
return NULL;
 }
 
+/*
+ * Checks if a given refname is a branch and returns the kind of
+ * branch it is. If not a branch, 0 is returned.
+ */
+static int filter_branch_kind(struct ref_filter *filter, const char *refname)
+{
+   int kind, i;
+
+   static struct {
+   const char *prefix;
+   int kind;
+   } ref_kind[] = {
+   { refs/heads/ , REF_LOCAL_BRANCH },
+   { refs/remotes/ , REF_REMOTE_BRANCH },
+   };
+
+   /*  If no kind is specified, no need to filter */
+   if (!filter-branch_kind)
+   return REF_NO_BRANCH_FILTERING;
+
+   for (i = 0; i  ARRAY_SIZE(ref_kind); i++) {
+   if (starts_with(refname, ref_kind[i].prefix)) {
+   kind = ref_kind[i].kind;
+   break;
+   }
+   }
+
+   if (ARRAY_SIZE(ref_kind) = i) {
+   if (!strcmp(refname, HEAD))
+   kind = REF_DETACHED_HEAD;
+   else
+   return 0;
+   }
+
+   if ((filter-branch_kind  kind) == 0)
+   return 0;
+
+   return kind;
+}
+
 /* Allocate space for a new ref_array_item and copy the objectname and flag to 
it */
 static struct ref_array_item *new_ref_array_item(const char *refname,
 const unsigned char 
*objectname,
@@ -1069,6 +1109,7 @@ static int ref_filter_handler(const char *refname, const 
struct object_id *oid,
struct ref_filter *filter = ref_cbdata-filter;
struct ref_array_item *ref;
struct commit *commit = NULL;
+   unsigned int kind;
 
if (flag  REF_BAD_NAME) {
warning(ignoring ref with broken name %s, refname);
@@ -1080,6 +1121,9 @@ static int ref_filter_handler(const char *refname, const 
struct object_id *oid,
return 0;
}
 
+   if (!(kind = filter_branch_kind(filter, refname)))
+   return 0;
+
if (!filter_pattern_match(filter, refname))
return 0;
 
@@ -1108,6 +1152,7 @@ static int ref_filter_handler(const char *refname, const 
struct object_id *oid,
 */
ref = new_ref_array_item(refname, oid-hash, flag);
ref-commit = commit;
+   ref-kind = kind;
 
REALLOC_ARRAY(ref_cbdata-array-items, ref_cbdata-array-nr + 1);
ref_cbdata-array-items[ref_cbdata-array-nr++] = ref;
@@ -1198,6 +1243,8 @@ int filter_refs(struct ref_array *array, struct 
ref_filter *filter, unsigned int
ret = for_each_ref(ref_filter_handler, ref_cbdata);
else if (type  FILTER_REFS_TAGS)
ret = for_each_tag_ref_fullpath(ref_filter_handler, 
ref_cbdata);
+   else if (type  FILTER_REFS_BRANCHES)
+   ret = for_each_rawref(ref_filter_handler, ref_cbdata);
else if (type)
die(filter_refs: invalid type);
 
diff --git a/ref-filter.h b/ref-filter.h
index 5be3e35..b5a13e8 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -16,6 +16,12 @@
 #define FILTER_REFS_INCLUDE_BROKEN 0x1
 #define FILTER_REFS_ALL 0x2
 #define FILTER_REFS_TAGS 0x4
+#define FILTER_REFS_BRANCHES 0x8
+
+#define REF_DETACHED_HEAD   0x01
+#define REF_LOCAL_BRANCH0x02
+#define REF_REMOTE_BRANCH   0x04
+#define REF_NO_BRANCH_FILTERING 0x08
 
 #define ALIGN_LEFT 0x01
 #define ALIGN_RIGHT 0x02
@@ -50,7 +56,7 @@ struct ref_sorting {
 
 struct ref_array_item {
unsigned char objectname[20];
-   int flag;
+   int flag, kind;
const char *symref;
struct commit *commit;
struct atom_value *value;
@@ -76,7 +82,7 @@ struct ref_filter {
 
unsigned int with_commit_tag_algo : 1,
match_as_path : 1;
-   unsigned int lines;
+   unsigned int lines, branch_kind;
 };
 
 struct ref_filter_cbdata {
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] git-p4: fix faulty paths for case insensitive systems

2015-08-04 Thread Lars Schneider
Thank you for your reply. Your t8919 test case looks exactly like the right 
thing. Unfortuantly I don’t have Internet access for the next two weeks. 
Afterwards I will provide a proper test cases for the patch.

You are correct about the speed. All these initial “p4 dirs” calls make the 
clone pretty slow. However, for us it is a one time history migration and 
therefore speed is not an issue. I also understand your “core.ignorecase” 
comment. Let’s assume the path correction works as expected, how and when would 
you trigger it? Would you only rely on the “server ignoring case” flag?

Cheers,
Lars

On 05 Aug 2015, at 00:06, Luke Diamand l...@diamand.org wrote:

 On 02/08/15 16:15, larsxschnei...@gmail.com wrote:
 From: Lars Schneider larsxschnei...@gmail.com
 
 Hi,
 
 I want to propose this patch as it helped us to migrate a big source code 
 base
 successfully from P4 to Git. I am sorry that I don't provide a test case, 
 yet.
 
 Case sensitivity is a pretty tricky area with p4 - it's very brave of you to 
 have a go at fixing it!
 
 I would like to get advise on the patch and on the best strategy to provide a
 test. Do you only run git-p4 integration tests in t/t98??-git-p4-*.sh? If 
 yes,
 which version of start_p4d should I use?
 
 Only the t98* tests relate to git-p4 so if you just copy one of those it 
 should do the right thing.
 
 t9819-git-p4-case-folding.sh already has a few failing tests for this 
 problem. I wrote it a while back just to illustrate the problem, so it might 
 be of use to you, or you might need to start again.
 
 Won't your change make importing much slower for people with this problem?
 
 Also, I'm not sure you can use core.ignorecase to trigger this: the problem 
 will arise if the *server* is ignoring case as well (which I think you can 
 detect by querying the server).
 
 I'm not trying to be negative - but this problem does have some annoying 
 pitfalls! Let me know if you think I can help though.
 
 Regards!
 Luke
 

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: fetching from an hg remote fails with bare git repositories

2015-08-04 Thread Taylor Braun-Jones
On Tue, Aug 4, 2015 at 2:56 PM, Stefan Beller sbel...@google.com wrote:
 On Tue, Aug 4, 2015 at 10:45 AM, Taylor Braun-Jones
 tay...@braun-jones.org wrote:
 Fetching from an hg remote fails with bare git repositories. Non-bare
 repositories work fine.

 Steps to reproduce:

 mkdir /tmp/hgrepo
 cd /tmp/hgrepo
 hg init
 echo foo  foo.txt
 hg add foo.txt
 hg commit -m add foo.txt foo.txt
 git clone hg::/tmp/hgrepo/ /tmp/gitrepo
 cd /tmp/gitrepo/
 git fetch # WORKS
 git clone --bare hg::/tmp/hgrepo/ /tmp/gitrepo.git
 cd /tmp/gitrepo.git/
 git fetch # FAILS

 The error message from the last line is:

 fatal: bad object 
 error: hg::/tmp/hgrepo/ did not send all necessary objects

 Taylor

 Which version of git did you test this with? Does it also happen on
 the latest version?

Sorry - forgot that detail. This is using git 2.1.4 from Ubuntu 15.04
x86_64. I haven't tried the latest version of git yet.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2 0/3] am: let command-line options override saved options

2015-08-04 Thread Junio C Hamano
Paul Tan pyoka...@gmail.com writes:

 Let command-line options override saved options in git-am when resuming

 This is a re-roll of [v1]. Previous versions:

 [v1] http://thread.gmane.org/gmane.comp.version-control.git/274789

 When resuming, git-am mistakenly ignores command-line options.

 For instance, when a patch fails to apply with git am patch, subsequently
 running git am --3way would not cause git-am to fall back on attempting a
 threeway merge.  This occurs because by default the --3way option is saved as
 false, and the saved am options are loaded after the command-line options 
 are
 parsed, thus overwriting the command-line options when resuming.

 [PATCH 1/3] tweaks test-terminal.perl to redirect the stdin of the child
 process to a pty. This is to support the tests in [PATCH 2/3].

 [PATCH 2/3] fixes builtin/am.c, enabling command-line options to override 
 saved
 options. However, even with this patch, the following command-line options 
 have
 no effect when resuming:

 * --signoff overriding --no-signoff

 * --no-keep overriding --keep

 * --message-id overriding --no-message-id

 * --scissors overriding --no-scissors

 This is because they are only taken into account during the mail-parsing 
 stage,
 which is skipped over when resuming.

It is more like which has already happened, so I would tend to
think that these are the right things to ignore.  Otherwise, a
pretty common sequence would not work well ...

$ git am mbox
... conflicted ...
$ edit .git/rebase-apply/patch
$ git am

... if the resuming invocation re-split the message by running
mailinfo again, the edit by the user will be lost.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v4] clone: simplify string handling in guess_dir_name()

2015-08-04 Thread Jeff King
On Tue, Aug 04, 2015 at 09:31:18AM +0200, Sebastian Schuberth wrote:

 On Tue, Aug 4, 2015 at 6:34 AM, Lukas Fleischer lfleisc...@lfos.de wrote:
 
  I am currently on vacation and cannot bisect or debug this but I am
  pretty confident that this patch changes the behaviour of directory name
  guessing. With Git 2.4.6, cloning http://foo.bar/foo.git/ results in a
  directory named foo and with Git 2.5.0, the resulting directory is
  called foo.git.
 
  Note how the end variable is decreased when the repository name ends
  with a slash but that isn't taken into account when simply using
  strip_suffix() later...
 
  Is this intended?
 
 I did not intend this change in behavior, and I can confirm that
 reverting my patch restores the original behavior. Thanks for bringing
 this to my attention, I'll work on a patch.

I think this regression is in v2.4.8, as well. We should be able to use
a running len instead of the end pointer in the earlier part, and
then use strip_suffix_mem later (to strip from our already-reduced
length, rather than the full NUL-terminated string). Like this:

diff --git a/builtin/clone.c b/builtin/clone.c
index 303a3a7..4b61e4c 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -146,20 +146,19 @@ static char *get_repo_path(const char *repo, int 
*is_bundle)
 
 static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
 {
-   const char *end = repo + strlen(repo), *start;
-   size_t len;
+   const char *start;
+   size_t len = strlen(repo);
char *dir;
 
/*
 * Strip trailing spaces, slashes and /.git
 */
-   while (repo  end  (is_dir_sep(end[-1]) || isspace(end[-1])))
-   end--;
-   if (end - repo  5  is_dir_sep(end[-5]) 
-   !strncmp(end - 4, .git, 4)) {
-   end -= 5;
-   while (repo  end  is_dir_sep(end[-1]))
-   end--;
+   while (len  0  (is_dir_sep(repo[len-1]) || isspace(repo[len-1])))
+   len--;
+   if (len  5  is_dir_sep(repo[len-5]) 
+   strip_suffix_mem(repo, len, .git)) {
+   while (len  0  is_dir_sep(repo[len-1]))
+   len--;
}
 
/*
@@ -167,14 +166,14 @@ static char *guess_dir_name(const char *repo, int 
is_bundle, int is_bare)
 * the form  remote.example.com:foo.git, i.e. no slash
 * in the directory part.
 */
-   start = end;
+   start = repo + len;
while (repo  start  !is_dir_sep(start[-1])  start[-1] != ':')
start--;
 
/*
 * Strip .{bundle,git}.
 */
-   strip_suffix(start, is_bundle ? .bundle : .git , len);
+   strip_suffix_mem(start, len, is_bundle ? .bundle : .git);
 
if (is_bare)
dir = xstrfmt(%.*s.git, (int)len, start);
@@ -187,6 +186,7 @@ static char *guess_dir_name(const char *repo, int 
is_bundle, int is_bare)
if (*dir) {
char *out = dir;
int prev_space = 1 /* strip leading whitespace */;
+   const char *end;
for (end = dir; *end; ++end) {
char ch = *end;
if ((unsigned char)ch  '\x20')

Sadly we cannot just `strip_suffix_mem(repo, len, /.git))` in the
earlier code, as we have to account for multiple directory separators. I
believe the above code does the right thing, though. I haven't looked at
how badly it interacts with the other guess_dir_name work from Patrick
Steinhardt that has been going on, though.

-Peff
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: fetching from an hg remote fails with bare git repositories

2015-08-04 Thread Mike Hommey
On Tue, Aug 04, 2015 at 05:27:13PM -0400, Taylor Braun-Jones wrote:
 On Tue, Aug 4, 2015 at 2:56 PM, Stefan Beller sbel...@google.com wrote:
  On Tue, Aug 4, 2015 at 10:45 AM, Taylor Braun-Jones
  tay...@braun-jones.org wrote:
  Fetching from an hg remote fails with bare git repositories. Non-bare
  repositories work fine.
 
  Steps to reproduce:
 
  mkdir /tmp/hgrepo
  cd /tmp/hgrepo
  hg init
  echo foo  foo.txt
  hg add foo.txt
  hg commit -m add foo.txt foo.txt
  git clone hg::/tmp/hgrepo/ /tmp/gitrepo
  cd /tmp/gitrepo/
  git fetch # WORKS
  git clone --bare hg::/tmp/hgrepo/ /tmp/gitrepo.git
  cd /tmp/gitrepo.git/
  git fetch # FAILS
 
  The error message from the last line is:
 
  fatal: bad object 
  error: hg::/tmp/hgrepo/ did not send all necessary objects
 
  Taylor
 
  Which version of git did you test this with? Does it also happen on
  the latest version?
 
 Sorry - forgot that detail. This is using git 2.1.4 from Ubuntu 15.04
 x86_64. I haven't tried the latest version of git yet.

Another missing detail is what you're using for mercurial support in
git. I would guess https://github.com/felipec/git-remote-hg. Shameless
plug, you may want to give a try to
https://github.com/glandium/git-cinnabar.

Anyways, your error looks like what I fixed in 33cae54, which git
describe tells me made it to git 2.3.2.

Mike
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 2/4] submodule: implement `module_name` as a builtin helper

2015-08-04 Thread Stefan Beller
The series consists of 2 patches only actually. The next patches have
not been sent as they are heavy WIP.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v6 2/2] path: implement common_dir handling in git_path_submodule()

2015-08-04 Thread Max Kirillov
When submodule is a linked worktree, git diff --submodule and other
calls which directly access the submodule's object database do not correctly
calculate its path. Fix it by changing the git_path_submodule() behavior,
to use either common or per-worktree directory.

Do it similarly as for parent repository, but ignore the GIT_COMMON_DIR
environment variable, because it would mean common directory for the parent
repository and does not make sense for submodule.

Also add test for functionality which uses this call.

Signed-off-by: Max Kirillov m...@max630.net
---
 cache.h  |  1 +
 path.c   | 24 
 setup.c  | 17 -
 t/t7410-submodule-checkout-to.sh | 10 ++
 4 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/cache.h b/cache.h
index 4f55466..b87ec75 100644
--- a/cache.h
+++ b/cache.h
@@ -442,6 +442,7 @@ extern char *get_object_directory(void);
 extern char *get_index_file(void);
 extern char *get_graft_file(void);
 extern int set_git_dir(const char *path);
+extern int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
 extern int get_common_dir(struct strbuf *sb, const char *gitdir);
 extern const char *get_git_namespace(void);
 extern const char *strip_namespace(const char *namespaced_ref);
diff --git a/path.c b/path.c
index 10f4cbf..b0cf444 100644
--- a/path.c
+++ b/path.c
@@ -98,7 +98,7 @@ static const char *common_list[] = {
NULL
 };
 
-static void update_common_dir(struct strbuf *buf, int git_dir_len)
+static void update_common_dir(struct strbuf *buf, int git_dir_len, const char 
*common_dir)
 {
char *base = buf-buf + git_dir_len;
const char **p;
@@ -115,12 +115,17 @@ static void update_common_dir(struct strbuf *buf, int 
git_dir_len)
path++;
is_dir = 1;
}
+
+   if (!common_dir) {
+   common_dir = get_git_common_dir();
+   }
+
if (is_dir  dir_prefix(base, path)) {
-   replace_dir(buf, git_dir_len, get_git_common_dir());
+   replace_dir(buf, git_dir_len, common_dir);
return;
}
if (!is_dir  !strcmp(base, path)) {
-   replace_dir(buf, git_dir_len, get_git_common_dir());
+   replace_dir(buf, git_dir_len, common_dir);
return;
}
}
@@ -160,7 +165,7 @@ static void adjust_git_path(struct strbuf *buf, int 
git_dir_len)
else if (git_db_env  dir_prefix(base, objects))
replace_dir(buf, git_dir_len + 7, get_object_directory());
else if (git_common_dir_env)
-   update_common_dir(buf, git_dir_len);
+   update_common_dir(buf, git_dir_len, NULL);
 }
 
 static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)
@@ -228,6 +233,8 @@ const char *git_path_submodule(const char *path, const char 
*fmt, ...)
 {
struct strbuf *buf = get_pathname();
const char *git_dir;
+   struct strbuf git_submodule_common_dir = STRBUF_INIT;
+   struct strbuf git_submodule_dir = STRBUF_INIT;
va_list args;
 
strbuf_addstr(buf, path);
@@ -241,11 +248,20 @@ const char *git_path_submodule(const char *path, const 
char *fmt, ...)
strbuf_addstr(buf, git_dir);
}
strbuf_addch(buf, '/');
+   strbuf_addstr(git_submodule_dir, buf-buf);
 
va_start(args, fmt);
strbuf_vaddf(buf, fmt, args);
va_end(args);
+
+   if (get_common_dir_noenv(git_submodule_common_dir, 
git_submodule_dir.buf)) {
+   update_common_dir(buf, git_submodule_dir.len, 
git_submodule_common_dir.buf);
+   }
+
strbuf_cleanup_path(buf);
+
+   strbuf_release(git_submodule_dir);
+   strbuf_release(git_submodule_common_dir);
return buf-buf;
 }
 
diff --git a/setup.c b/setup.c
index 82c0cc2..39ea06b 100644
--- a/setup.c
+++ b/setup.c
@@ -229,14 +229,21 @@ void verify_non_filename(const char *prefix, const char 
*arg)
 
 int get_common_dir(struct strbuf *sb, const char *gitdir)
 {
+   const char *git_env_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
+   if (git_env_common_dir) {
+   strbuf_addstr(sb, git_env_common_dir);
+   return 1;
+   } else {
+   return get_common_dir_noenv(sb, gitdir);
+   }
+}
+
+int get_common_dir_noenv(struct strbuf *sb, const char *gitdir)
+{
struct strbuf data = STRBUF_INIT;
struct strbuf path = STRBUF_INIT;
-   const char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
int ret = 0;
-   if (git_common_dir) {
-   strbuf_addstr(sb, git_common_dir);
-   return 1;
-   }
+
strbuf_addf(path, %s/commondir, gitdir);
if (file_exists(path.buf)) {
if 

[PATCH v6 1/2] submodule refactor: use git_path_submodule() in add_submodule_odb()

2015-08-04 Thread Max Kirillov
Functions which directly operate submodule's object database do not handle the
case when the submodule is linked worktree (which are introduced in
c7b3a3d2fe). Instead of fixing the path calculation use already existing
git_path_submodule() function, with intention to modify only that function
whenever we need to change real location of submodule's repository content.

Signed-off-by: Max Kirillov m...@max630.net
---
 submodule.c | 28 ++--
 1 file changed, 10 insertions(+), 18 deletions(-)

diff --git a/submodule.c b/submodule.c
index 15e90d1..70d18ec 100644
--- a/submodule.c
+++ b/submodule.c
@@ -122,43 +122,35 @@ void stage_updated_gitmodules(void)
 
 static int add_submodule_odb(const char *path)
 {
-   struct strbuf objects_directory = STRBUF_INIT;
struct alternate_object_database *alt_odb;
+   const char *objects_directory;
int ret = 0;
-   const char *git_dir;
 
-   strbuf_addf(objects_directory, %s/.git, path);
-   git_dir = read_gitfile(objects_directory.buf);
-   if (git_dir) {
-   strbuf_reset(objects_directory);
-   strbuf_addstr(objects_directory, git_dir);
-   }
-   strbuf_addstr(objects_directory, /objects/);
-   if (!is_directory(objects_directory.buf)) {
+   objects_directory = git_path_submodule(path, objects/);
+   if (!is_directory(objects_directory)) {
ret = -1;
goto done;
}
+
/* avoid adding it twice */
for (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb-next)
-   if (alt_odb-name - alt_odb-base == objects_directory.len 
-   !strncmp(alt_odb-base, objects_directory.buf,
-   objects_directory.len))
+   if (alt_odb-name - alt_odb-base == strlen(objects_directory) 

+   !strcmp(alt_odb-base, objects_directory))
goto done;
 
-   alt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));
+   alt_odb = xmalloc(strlen(objects_directory) + 42 + sizeof(*alt_odb));
alt_odb-next = alt_odb_list;
-   strcpy(alt_odb-base, objects_directory.buf);
-   alt_odb-name = alt_odb-base + objects_directory.len;
+   strcpy(alt_odb-base, objects_directory);
+   alt_odb-name = alt_odb-base + strlen(objects_directory);
alt_odb-name[2] = '/';
alt_odb-name[40] = '\0';
alt_odb-name[41] = '\0';
alt_odb_list = alt_odb;
 
/* add possible alternates from the submodule */
-   read_info_alternates(objects_directory.buf, 0);
+   read_info_alternates(objects_directory, 0);
prepare_alt_odb();
 done:
-   strbuf_release(objects_directory);
return ret;
 }
 
-- 
2.3.4.2801.g3d0809b

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v6 0/2] path: implement common_dir handling in git_path_submodule()

2015-08-04 Thread Max Kirillov
Fixed the pointer declaration spacing issue and updated commit messages.

The 1/2 refactoring still might leave some cases behind. I could grep only 
function
connect_work_tree_and_git_dir() which, as far as I can see, involved in moving 
repositories.
Have not touched it because correct moving parts of multiple-worktree
repositories probably is a bigger task than just fix config file location.

Max Kirillov (2):
  submodule refactor: use git_path_submodule() in add_submodule_odb()
  path: implement common_dir handling in git_path_submodule()

 cache.h  |  1 +
 path.c   | 24 
 setup.c  | 17 -
 submodule.c  | 28 ++--
 t/t7410-submodule-checkout-to.sh | 10 ++
 5 files changed, 53 insertions(+), 27 deletions(-)

-- 
2.3.4.2801.g3d0809b

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 2/2] path: implement common_dir handling in git_path_submodule()

2015-08-04 Thread Max Kirillov
When submodule is a linked worktree, git diff --submodule and other
calls which directly access the submodule's object database do not correctly
calculate its path. Fix it by changing the git_path_submodule() behavior,
to use either common or per-worktree directory.

Do it similarly as for parent repository, but ignore the GIT_COMMON_DIR
environment variable, because it would mean common directory for the parent
repository and does not make sense for submodule.

Also add test for functionality which uses this call.

Signed-off-by: Max Kirillov m...@max630.net
---
 cache.h  |  1 +
 path.c   | 24 
 setup.c  | 17 -
 t/t7410-submodule-checkout-to.sh | 10 ++
 4 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/cache.h b/cache.h
index 4f55466..b87ec75 100644
--- a/cache.h
+++ b/cache.h
@@ -442,6 +442,7 @@ extern char *get_object_directory(void);
 extern char *get_index_file(void);
 extern char *get_graft_file(void);
 extern int set_git_dir(const char *path);
+extern int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
 extern int get_common_dir(struct strbuf *sb, const char *gitdir);
 extern const char *get_git_namespace(void);
 extern const char *strip_namespace(const char *namespaced_ref);
diff --git a/path.c b/path.c
index 10f4cbf..b0cf444 100644
--- a/path.c
+++ b/path.c
@@ -98,7 +98,7 @@ static const char *common_list[] = {
NULL
 };
 
-static void update_common_dir(struct strbuf *buf, int git_dir_len)
+static void update_common_dir(struct strbuf *buf, int git_dir_len, const char 
*common_dir)
 {
char *base = buf-buf + git_dir_len;
const char **p;
@@ -115,12 +115,17 @@ static void update_common_dir(struct strbuf *buf, int 
git_dir_len)
path++;
is_dir = 1;
}
+
+   if (!common_dir) {
+   common_dir = get_git_common_dir();
+   }
+
if (is_dir  dir_prefix(base, path)) {
-   replace_dir(buf, git_dir_len, get_git_common_dir());
+   replace_dir(buf, git_dir_len, common_dir);
return;
}
if (!is_dir  !strcmp(base, path)) {
-   replace_dir(buf, git_dir_len, get_git_common_dir());
+   replace_dir(buf, git_dir_len, common_dir);
return;
}
}
@@ -160,7 +165,7 @@ static void adjust_git_path(struct strbuf *buf, int 
git_dir_len)
else if (git_db_env  dir_prefix(base, objects))
replace_dir(buf, git_dir_len + 7, get_object_directory());
else if (git_common_dir_env)
-   update_common_dir(buf, git_dir_len);
+   update_common_dir(buf, git_dir_len, NULL);
 }
 
 static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)
@@ -228,6 +233,8 @@ const char *git_path_submodule(const char *path, const char 
*fmt, ...)
 {
struct strbuf *buf = get_pathname();
const char *git_dir;
+   struct strbuf git_submodule_common_dir = STRBUF_INIT;
+   struct strbuf git_submodule_dir = STRBUF_INIT;
va_list args;
 
strbuf_addstr(buf, path);
@@ -241,11 +248,20 @@ const char *git_path_submodule(const char *path, const 
char *fmt, ...)
strbuf_addstr(buf, git_dir);
}
strbuf_addch(buf, '/');
+   strbuf_addstr(git_submodule_dir, buf-buf);
 
va_start(args, fmt);
strbuf_vaddf(buf, fmt, args);
va_end(args);
+
+   if (get_common_dir_noenv(git_submodule_common_dir, 
git_submodule_dir.buf)) {
+   update_common_dir(buf, git_submodule_dir.len, 
git_submodule_common_dir.buf);
+   }
+
strbuf_cleanup_path(buf);
+
+   strbuf_release(git_submodule_dir);
+   strbuf_release(git_submodule_common_dir);
return buf-buf;
 }
 
diff --git a/setup.c b/setup.c
index 82c0cc2..39ea06b 100644
--- a/setup.c
+++ b/setup.c
@@ -229,14 +229,21 @@ void verify_non_filename(const char *prefix, const char 
*arg)
 
 int get_common_dir(struct strbuf *sb, const char *gitdir)
 {
+   const char *git_env_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
+   if (git_env_common_dir) {
+   strbuf_addstr(sb, git_env_common_dir);
+   return 1;
+   } else {
+   return get_common_dir_noenv(sb, gitdir);
+   }
+}
+
+int get_common_dir_noenv(struct strbuf *sb, const char *gitdir)
+{
struct strbuf data = STRBUF_INIT;
struct strbuf path = STRBUF_INIT;
-   const char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
int ret = 0;
-   if (git_common_dir) {
-   strbuf_addstr(sb, git_common_dir);
-   return 1;
-   }
+
strbuf_addf(path, %s/commondir, gitdir);
if (file_exists(path.buf)) {
if 

Re: [PATCH] git-p4: fix faulty paths for case insensitive systems

2015-08-04 Thread Luke Diamand

On 02/08/15 16:15, larsxschnei...@gmail.com wrote:

From: Lars Schneider larsxschnei...@gmail.com

Hi,

I want to propose this patch as it helped us to migrate a big source code base
successfully from P4 to Git. I am sorry that I don't provide a test case, yet.


Case sensitivity is a pretty tricky area with p4 - it's very brave of 
you to have a go at fixing it!



I would like to get advise on the patch and on the best strategy to provide a
test. Do you only run git-p4 integration tests in t/t98??-git-p4-*.sh? If yes,
which version of start_p4d should I use?


Only the t98* tests relate to git-p4 so if you just copy one of those it 
should do the right thing.


t9819-git-p4-case-folding.sh already has a few failing tests for this 
problem. I wrote it a while back just to illustrate the problem, so it 
might be of use to you, or you might need to start again.


Won't your change make importing much slower for people with this problem?

Also, I'm not sure you can use core.ignorecase to trigger this: the 
problem will arise if the *server* is ignoring case as well (which I 
think you can detect by querying the server).


I'm not trying to be negative - but this problem does have some annoying 
pitfalls! Let me know if you think I can help though.


Regards!
Luke

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 1/2] submodule refactor: use git_path_submodule() in add_submodule_odb()

2015-08-04 Thread Max Kirillov
Functions which directly operate submodule's object database do not handle the
case when the submodule is linked worktree (which are introduced in
c7b3a3d2fe). Instead of fixing the path calculation use already existing
git_path_submodule() function without changing overall behavior. Then it will
be possible to modify only that function whenever we need to change real
location of submodule's repository content.

Signed-off-by: Max Kirillov m...@max630.net
---
 submodule.c | 28 ++--
 1 file changed, 10 insertions(+), 18 deletions(-)

diff --git a/submodule.c b/submodule.c
index 15e90d1..70d18ec 100644
--- a/submodule.c
+++ b/submodule.c
@@ -122,43 +122,35 @@ void stage_updated_gitmodules(void)
 
 static int add_submodule_odb(const char *path)
 {
-   struct strbuf objects_directory = STRBUF_INIT;
struct alternate_object_database *alt_odb;
+   const char *objects_directory;
int ret = 0;
-   const char *git_dir;
 
-   strbuf_addf(objects_directory, %s/.git, path);
-   git_dir = read_gitfile(objects_directory.buf);
-   if (git_dir) {
-   strbuf_reset(objects_directory);
-   strbuf_addstr(objects_directory, git_dir);
-   }
-   strbuf_addstr(objects_directory, /objects/);
-   if (!is_directory(objects_directory.buf)) {
+   objects_directory = git_path_submodule(path, objects/);
+   if (!is_directory(objects_directory)) {
ret = -1;
goto done;
}
+
/* avoid adding it twice */
for (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb-next)
-   if (alt_odb-name - alt_odb-base == objects_directory.len 
-   !strncmp(alt_odb-base, objects_directory.buf,
-   objects_directory.len))
+   if (alt_odb-name - alt_odb-base == strlen(objects_directory) 

+   !strcmp(alt_odb-base, objects_directory))
goto done;
 
-   alt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));
+   alt_odb = xmalloc(strlen(objects_directory) + 42 + sizeof(*alt_odb));
alt_odb-next = alt_odb_list;
-   strcpy(alt_odb-base, objects_directory.buf);
-   alt_odb-name = alt_odb-base + objects_directory.len;
+   strcpy(alt_odb-base, objects_directory);
+   alt_odb-name = alt_odb-base + strlen(objects_directory);
alt_odb-name[2] = '/';
alt_odb-name[40] = '\0';
alt_odb-name[41] = '\0';
alt_odb_list = alt_odb;
 
/* add possible alternates from the submodule */
-   read_info_alternates(objects_directory.buf, 0);
+   read_info_alternates(objects_directory, 0);
prepare_alt_odb();
 done:
-   strbuf_release(objects_directory);
return ret;
 }
 
-- 
2.3.4.2801.g3d0809b

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v7 0/2] path: implement common_dir handling in git_path_submodule()

2015-08-04 Thread Max Kirillov
Emphasized that 1/2 does not change behavior.

Max Kirillov (2):
  submodule refactor: use git_path_submodule() in add_submodule_odb()
  path: implement common_dir handling in git_path_submodule()

 cache.h  |  1 +
 path.c   | 24 
 setup.c  | 17 -
 submodule.c  | 28 ++--
 t/t7410-submodule-checkout-to.sh | 10 ++
 5 files changed, 53 insertions(+), 27 deletions(-)

-- 
2.3.4.2801.g3d0809b

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


fetching from an hg remote fails with bare git repositories

2015-08-04 Thread Taylor Braun-Jones
Fetching from an hg remote fails with bare git repositories. Non-bare
repositories work fine.

Steps to reproduce:

mkdir /tmp/hgrepo
cd /tmp/hgrepo
hg init
echo foo  foo.txt
hg add foo.txt
hg commit -m add foo.txt foo.txt
git clone hg::/tmp/hgrepo/ /tmp/gitrepo
cd /tmp/gitrepo/
git fetch # WORKS
git clone --bare hg::/tmp/hgrepo/ /tmp/gitrepo.git
cd /tmp/gitrepo.git/
git fetch # FAILS

The error message from the last line is:

fatal: bad object 
error: hg::/tmp/hgrepo/ did not send all necessary objects

Taylor
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 2/2] Documentation/git-worktree: fix reference to 'locked' file

2015-08-04 Thread Eric Sunshine
On Tue, Aug 4, 2015 at 8:27 AM, Patrick Steinhardt p...@pks.im wrote:
 The documentation of git-worktree refers to the 'locked' file as
 'lock'. Fix this to say 'locked' instead.

Thanks for the patch. This is already fixed in 'next' by 2e73ab6
(Documentation/git-worktree: fix incorrect reference to file locked,
2015-07-20)

 Signed-off-by: Patrick Steinhardt p...@pks.im
 ---
 diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
 index 566ca92..3fedd9e 100644
 --- a/Documentation/git-worktree.txt
 +++ b/Documentation/git-worktree.txt
 @@ -39,7 +39,7 @@ repository so that they do not get automatically pruned.

  If a linked working tree is stored on a portable device or network share
  which is not always mounted, you can prevent its administrative files from
 -being pruned by creating a file named 'lock' alongside the other
 +being pruned by creating a file named 'locked' alongside the other
  administrative files, optionally containing a plain text reason that
  pruning should be suppressed. See section DETAILS for more information.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 1/2] Documentation/git-worktree: fix duplicated 'from'

2015-08-04 Thread Eric Sunshine
On Tue, Aug 4, 2015 at 8:27 AM, Patrick Steinhardt p...@pks.im wrote:
 Signed-off-by: Patrick Steinhardt p...@pks.im
 ---
 diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
 index 3387e2f..566ca92 100644
 --- a/Documentation/git-worktree.txt
 +++ b/Documentation/git-worktree.txt
 @@ -124,7 +124,7 @@ thumb is do not make any assumption about whether a path 
 belongs to
  $GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
  inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.

 -To prevent a $GIT_DIR/worktrees entry from from being pruned (which
 +To prevent a $GIT_DIR/worktrees entry from being pruned (which

Thanks. I vaguely recall spotting this repetition when preparing to
move this chunk of text from git-checkout.txt to git-worktree.txt[1],
and planned on fixing it in a follow-on patch (such as [2,3,4,5]), but
forgot about it. For what it's worth (though certainly not necessary
for such an obviously correct path):

Acked-by: Eric Sunshine sunsh...@sunshineco.com

[1]: 93a3649 (Documentation: move linked worktree description from
checkout to worktree, 2015-07-06)
[2]: 6d3824c (Documentation/git-worktree: add BUGS section, 2015-07-06)
[3]: af189b4 (Documentation/git-worktree: split technical info from
general description, 2015-07-06)
[4]: a8ba5dd (Documentation/git-worktree: add high-level 'lock'
overview, 2015-07-06)
[5]: 9645459 (Documentation/git-worktree: add EXAMPLES section, 2015-07-06)

  can be useful in some situations, such as when the
  entry's working tree is stored on a portable device), add a file named
  'locked' to the entry's directory. The file contains the reason in
 --
 2.5.0
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v3 6/6] clone: add tests for cloning with empty path

2015-08-04 Thread Eric Sunshine
On Tue, Aug 4, 2015 at 7:29 AM, Patrick Steinhardt p...@pks.im wrote:
 Test behavior of `git clone` when working with an empty path
 component. This may be the case when cloning a file system's root
 directory or from a remote server's root.

A few minor, mostly style-related, comments below...

 Signed-off-by: Patrick Steinhardt p...@pks.im
 ---
 diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-worktree.sh
 index 553a3f6..d521ca3 100755
 --- a/t/t1509-root-worktree.sh
 +++ b/t/t1509-root-worktree.sh
 @@ -237,6 +237,49 @@ test_foobar_foobar

  test_expect_success 'cleanup' 'rm -rf /.git'

 +say clone .git at root without reponame
 +
 +test_expect_success 'go to /' 'cd /'
 +test_expect_success 'setup' '
 +   echo Initialized empty Git repository in /.git/  expected 
 +   git init  result 
 +   test_cmp expected result
 +'
 +
 +test_clone_expect_dir() {
 +   URL=$1
 +   DIR=$2

It would be nice for the -chain to be intact for these two lines, as
well, since you never know where someone may insert code in the
future. If code is inserted above or between these lines, and the code
fails, its failure will go unnoticed due to the broken -chain.

 +   cat -EOF expected 

In this codebase, it's customary to say:

cat expected -EOF 

 +   Cloning into '$DIR'...
 +   warning: You appear to have cloned an empty repository.
 +   EOF

In this codebase, it's customary to place the content and EOF at the
same indentation level as the opening 'cat EOF'.

 +   git clone $URL result 21 
 +   rm -rf $DIR 
 +   test_cmp expected result
 +}
 +
 +test_expect_success 'go to /clones' 'mkdir /clones  cd /clones'
 +test_expect_success 'simple clone of /' '
 +   cat -EOF expected 

Since you don't expect any variable interpolation in this case, you
can telegraph that intent more clearly via:

cat expected -\EOF 

 +   fatal: No directory name could be guessed.
 +   Please specify a directory on the command line
 +   EOF
 +   test_expect_code 128 git clone / result 21 
 +   test_cmp expected result'
 +
 +test_expect_success 'clone with file://host/' '
 +   test_clone_expect_dir file://127.0.0.1/ 127.0.0.1'
 +test_expect_success 'clone with file://user@host/' '
 +   test_clone_expect_dir file://user@127.0.0.1/ 127.0.0.1'
 +test_expect_success 'clone with file://user:password@host/' '
 +   test_clone_expect_dir file://user:password@127.0.0.1/ 127.0.0.1'
 +test_expect_success 'clone with file://host:port/' '
 +   test_clone_expect_dir file://127.0.0.1:/ 127.0.0.1'
 +test_expect_success 'clone with file://user:password@host:port' '
 +   test_clone_expect_dir file://user:password@127.0.0.1:/ 127.0.0.1'
 +
 +test_expect_success 'cleanup' 'rm -rf /.git /clones'
 +
  say auto bare gitdir

  # DESTROY!
 --
 2.5.0
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


  1   2   >