Re: [RFC/PATCH] clone: add `--shallow-submodules` flag

2016-03-12 Thread Junio C Hamano
Stefan Beller  writes:

> Why is it interesting for submodules but not for standard repositories?
>
> If I clone a repository without submodules, it is also not recorded
> that I cloned with an explicit depth=1. If you fetch, you may end up with
> a deeper history as git fetch doesn't do a "reshallow" to the configured
> depth.

Very simple.

If you do not have submodule, you would always interact with the
other side directly with "git fetch" or "git pull" and have total
control over when you choose to pass or not to pass extra options to
choose to 1. incrementally extend, 2. deepen, or 3. unshallow.  The
user will always explicitly tell you, and knowing how you got there
would not help you, as there is no need to guess for you.

The user can do the same explicit "cd dir && git fetch" update in
each submodule directory and give appropriate options to choose
among the three, but I have an impression that your recent work is
going in the direction of making commands that are run in the
superproject recurse into submodules that automatically fetches and
updates the history down there, discouraging users from working on
individual submodules.  You lose the flexibility to explicitly
choose among the three for individual submodules, and you may want
to have some smart in your "run from the superproject and recurse"
tools.

A submodule that was initially cloned with depth=1, perhaps because
the user didn't know if the module was interesting to her in the
context of working on the superproject before she had her clone of
the superproject hence she only wanted to see what's there, and a
submodule that was not even fetched initially when the superproject
was cloned and later was "submodule init"ed and fetched with
depth=1, would have the same shallow boundary, but the intent of the
user would clearly be different in the larger picture.  I imagined
that your "run in top-level and recurse to fetch in submodules"
tools would benefit if it has more information to intuit what the
end user meant.
--
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] sequencer.c: fix detection of duplicate s-o-b

2016-03-12 Thread Willy Tarreau
Hi,

after I upgraded my machine, I switched from git 1.7.12.2 to 2.6.4
and experienced an annoying regression when dealing with stable
kernel backports.

I'm using a "dorelease" script which relies on git-cherry-pick's
ability to properly detect duplicate s-o-b to ensure that all merged
commits are properly signed in a release. Today while preparing the
last 2.6.32 release, I did a git log before pushing and found some
commits having two s-o-b lines with myself. I found that these ones
were always those containing some backporting notes between the s-o-b
lines (which we all do in stable branches to indicate what was changed
in the backport process).

I didn't feel brave enough to individually deal with each offending
patch by hand so instead I bisected the git changes and found that the
behaviour changed with commit bab4d10 ("sequencer.c: teach append_signoff
how to detect duplicate s-o-b").

The reason is that function has_conforming_footer() immediately stops
after the first non-conforming line without checking if there are
conforming lines after. But if someone added signed-off-by anywhere
after a non-conforming block, it should always be considered as part
of the footer. Thus I adjusted the logic to check till the end of the
footer and report the presence of valid rfc2822 or cherry-picked lines
after the last non-conformant one and now it correctly handles all types
of commits I had to deal with (ie: only adds s-o-b when it doesn't match
the last one and doesn't add an empty line after a conformant one). For
example, this footer :

Signed-off-by: Mike Galbraith 
[bwh: Backported to 3.2:
 - Adjust numbering in the comment
 - Adjust filename]
Signed-off-by: Ben Hutchings 
Cc: Byungchul Park 
Cc: Peter Zijlstra 
Cc: Willy Tarreau 

Used to be turned into this :

Signed-off-by: Mike Galbraith 
[bwh: Backported to 3.2:
 - Adjust numbering in the comment
 - Adjust filename]
Signed-off-by: Ben Hutchings 
Cc: Byungchul Park 
Cc: Peter Zijlstra 
Cc: Willy Tarreau 

Signed-off-by: Willy Tarreau 

And is now properly converted to :

Signed-off-by: Mike Galbraith 
[bwh: Backported to 3.2:
 - Adjust numbering in the comment
 - Adjust filename]
Signed-off-by: Ben Hutchings 
Cc: Byungchul Park 
Cc: Peter Zijlstra 
Cc: Willy Tarreau 
Signed-off-by: Willy Tarreau 

Also, cherry-picking the last commit above again would produce this
before :

Signed-off-by: Mike Galbraith 
[bwh: Backported to 3.2:
 - Adjust numbering in the comment
 - Adjust filename]
Signed-off-by: Ben Hutchings 
Cc: Byungchul Park 
Cc: Peter Zijlstra 
Cc: Willy Tarreau 
Signed-off-by: Willy Tarreau 

Signed-off-by: Willy Tarreau 

And it now is properly left untouched since the last s-o-b line
is properly matched.

I'm appending the patch, please include it upstream.

Thanks!
Willy


>From be9624a0df4c649d452f898925953a81dc9163fc Mon Sep 17 00:00:00 2001
From: Willy Tarreau 
Date: Sat, 12 Mar 2016 13:35:35 +0100
Subject: sequencer.c: fix detection of duplicate s-o-b

Commit bab4d10 ("sequencer.c: teach append_signoff how to detect
duplicate s-o-b") changed the method used to detect duplicate s-o-b,
but it introduced a regression for a case where some non-compliant
information are present in the footer. In maintenance branches, it's
very common to add some elements after the signed-off and to add your
s-o-b after. This is used a lot in the stable kernel series, for
example this commit backported from 3.2 to 2.6.32 :

ALSA: usb-audio: avoid freeing umidi object twice

commit 07d86ca93db7e5cdf4743564d98292042ec21af7 upstream.

The 'umidi' object will be free'd on the error path by snd_usbmidi_free()
when tearing down the rawmidi interface. So we shouldn't try to free it
in snd_usbmidi_create() after having registered the rawmidi interface.

Found by KASAN.

Signed-off-by: Andrey Konovalov 
Acked-by: Clemens Ladisch 
Signed-off-by: Takashi Iwai 
Signed-off-by: Ben Hutchings 
[wt: file is sound/midi/usbmidi.c in 2.6.32]
Signed-off-by: Willy Tarreau 

Prior to the commit above, a cherry-pick -s would not append an extra s-o-b.
After this commit, a new line and a second s-o-b are added, making the footer
look like this :

Signed-off-by: Andrey Konovalov 
Acked-by: 

Graph sloc tool for git repos

2016-03-12 Thread Kai Hendry
Hi there,

I penned a script to plot SLOC of a git project using GNUplot & I
thought the fastest way to count code fluctuations was via `git show
--numstat`.

However that requires some awk counting of the lines:
https://github.com/kaihendry/graphsloc/blob/5f31e388e9b655e1801f13885f4311d221663a19/collect-stats.sh#L32

Is there a better way I missed? I think there is bug since my graph was
a factor of 10 out whilst graphing Linux:
https://twitter.com/kaihendry/status/706627679924174848

(Though the shape looks right)

Good news it's generating graphs for smaller projects just fine:
http://s.natalian.org/2016-03-12/dwm-3465bed.csv.svg

Anyway, would love to get your feedback on
https://github.com/kaihendry/graphsloc

Kind regards from Petaling Jaya,
--
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/RFC/GSoC 16/17] editor: implement git_sequence_editor() and launch_sequence_editor()

2016-03-12 Thread Paul Tan
Signed-off-by: Paul Tan 
---
 cache.h  |  1 +
 editor.c | 27 +--
 strbuf.h |  1 +
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/cache.h b/cache.h
index aa5e97c..d7a6fc6 100644
--- a/cache.h
+++ b/cache.h
@@ -1222,6 +1222,7 @@ extern const char *fmt_name(const char *name, const char 
*email);
 extern const char *ident_default_name(void);
 extern const char *ident_default_email(void);
 extern const char *git_editor(void);
+extern const char *git_sequence_editor(void);
 extern const char *git_pager(int stdout_is_tty);
 extern int git_ident_config(const char *, const char *, void *);
 
diff --git a/editor.c b/editor.c
index 01c644c..4c5874b 100644
--- a/editor.c
+++ b/editor.c
@@ -29,10 +29,22 @@ const char *git_editor(void)
return editor;
 }
 
-int launch_editor(const char *path, struct strbuf *buffer, const char *const 
*env)
+const char *git_sequence_editor(void)
 {
-   const char *editor = git_editor();
+   const char *sequence_editor = getenv("GIT_SEQUENCE_EDITOR");
+
+   if (sequence_editor && *sequence_editor)
+   return sequence_editor;
 
+   git_config_get_string_const("sequence.editor", _editor);
+   if (sequence_editor && *sequence_editor)
+   return sequence_editor;
+
+   return git_editor();
+}
+
+static int launch_specific_editor(const char *editor, const char *path, struct 
strbuf *buffer, const char *const *env)
+{
if (!editor)
return error("Terminal is dumb, but EDITOR unset");
 
@@ -65,5 +77,16 @@ int launch_editor(const char *path, struct strbuf *buffer, 
const char *const *en
if (strbuf_read_file(buffer, path, 0) < 0)
return error("could not read file '%s': %s",
path, strerror(errno));
+
return 0;
 }
+
+int launch_editor(const char *path, struct strbuf *buffer, const char *const 
*env)
+{
+   return launch_specific_editor(git_editor(), path, buffer, env);
+}
+
+int launch_sequence_editor(const char *path, struct strbuf *buffer, const char 
*const *env)
+{
+   return launch_specific_editor(git_sequence_editor(), path, buffer, env);
+}
diff --git a/strbuf.h b/strbuf.h
index f72fd14..aebdcd7 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -524,6 +524,7 @@ extern void strbuf_add_unique_abbrev(struct strbuf *sb,
  * file's contents are not read into the buffer upon completion.
  */
 extern int launch_editor(const char *path, struct strbuf *buffer, const char 
*const *env);
+extern int launch_sequence_editor(const char *path, struct strbuf *buffer, 
const char *const *env);
 
 extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char 
*buf, size_t size);
 
-- 
2.7.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/RFC/GSoC 13/17] rebase-todo: introduce rebase_todo_list

2016-03-12 Thread Paul Tan
Implement rebase_todo_list, which is a resizable array of
rebase_todo_items.

Signed-off-by: Paul Tan 
---
 rebase-todo.c | 107 ++
 rebase-todo.h |  27 +++
 2 files changed, 134 insertions(+)

diff --git a/rebase-todo.c b/rebase-todo.c
index ac6b222..4f14638 100644
--- a/rebase-todo.c
+++ b/rebase-todo.c
@@ -142,3 +142,110 @@ void strbuf_add_rebase_todo_item(struct strbuf *sb,
 
strbuf_addch(sb, '\n');
 }
+
+void rebase_todo_list_init(struct rebase_todo_list *list)
+{
+   list->items = NULL;
+   list->nr = 0;
+   list->alloc = 0;
+}
+
+void rebase_todo_list_clear(struct rebase_todo_list *list)
+{
+   unsigned int i;
+
+   for (i = 0; i < list->nr; i++)
+   rebase_todo_item_release(>items[i]);
+   free(list->items);
+   rebase_todo_list_init(list);
+}
+
+void rebase_todo_list_swap(struct rebase_todo_list *dst,
+  struct rebase_todo_list *src)
+{
+   struct rebase_todo_list tmp = *dst;
+
+   *dst = *src;
+   *src = tmp;
+}
+
+unsigned int rebase_todo_list_count(const struct rebase_todo_list *list)
+{
+   unsigned int i, count = 0;
+
+   for (i = 0; i < list->nr; i++)
+   if (list->items[i].action != REBASE_TODO_NONE)
+   count++;
+   return count;
+}
+
+struct rebase_todo_item *rebase_todo_list_push(struct rebase_todo_list *list, 
const struct rebase_todo_item *src_item)
+{
+   struct rebase_todo_item *item = rebase_todo_list_push_empty(list);
+
+   rebase_todo_item_copy(item, src_item);
+   return item;
+}
+
+struct rebase_todo_item *rebase_todo_list_push_empty(struct rebase_todo_list 
*list)
+{
+   struct rebase_todo_item *item;
+
+   ALLOC_GROW(list->items, list->nr + 1, list->alloc);
+   item = >items[list->nr++];
+   rebase_todo_item_init(item);
+   return item;
+}
+
+struct rebase_todo_item *rebase_todo_list_push_noop(struct rebase_todo_list 
*list)
+{
+   struct rebase_todo_item *item = rebase_todo_list_push_empty(list);
+
+   item->action = REBASE_TODO_NOOP;
+   return item;
+}
+
+int rebase_todo_list_load(struct rebase_todo_list *list, const char *path, int 
abbrev)
+{
+   struct strbuf sb = STRBUF_INIT;
+   FILE *fp;
+
+   fp = fopen(path, "r");
+   if (!fp)
+   return error(_("could not open %s for reading"), path);
+
+   while (strbuf_getline(, fp) != EOF) {
+   struct rebase_todo_item *item = 
rebase_todo_list_push_empty(list);
+   if (rebase_todo_item_parse(item, sb.buf, abbrev) < 0) {
+   rebase_todo_item_release(item);
+   list->nr--;
+   strbuf_release();
+   fclose(fp);
+   return -1;
+   }
+   }
+   strbuf_release();
+   fclose(fp);
+   return 0;
+}
+
+void rebase_todo_list_save(const struct rebase_todo_list *list, const char 
*filename, unsigned int offset, int abbrev)
+{
+   char *tmpfile = mkpathdup("%s.new", filename);
+   struct strbuf sb = STRBUF_INIT;
+   int fd;
+
+   for (; offset < list->nr; offset++)
+   strbuf_add_rebase_todo_item(, >items[offset], abbrev);
+
+   fd = xopen(tmpfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+   if (write_in_full(fd, sb.buf, sb.len) != sb.len)
+   die_errno(_("could not write to %s"), tmpfile);
+   close(fd);
+   strbuf_release();
+
+   if (rename(tmpfile, filename))
+   die_errno(_("rename failed"));
+
+   free(tmpfile);
+}
diff --git a/rebase-todo.h b/rebase-todo.h
index 2eedbb0..f602fd2 100644
--- a/rebase-todo.h
+++ b/rebase-todo.h
@@ -25,4 +25,31 @@ int rebase_todo_item_parse(struct rebase_todo_item *, const 
char *line, int abbr
 
 void strbuf_add_rebase_todo_item(struct strbuf *, const struct 
rebase_todo_item *, int abbrev);
 
+struct rebase_todo_list {
+   struct rebase_todo_item *items;
+   unsigned int nr, alloc;
+};
+
+#define REBASE_TODO_LIST_INIT { NULL, 0, 0 }
+
+void rebase_todo_list_init(struct rebase_todo_list *);
+
+void rebase_todo_list_clear(struct rebase_todo_list *);
+
+void rebase_todo_list_swap(struct rebase_todo_list *dst, struct 
rebase_todo_list *src);
+
+unsigned int rebase_todo_list_count(const struct rebase_todo_list *);
+
+struct rebase_todo_item *rebase_todo_list_push(struct rebase_todo_list *,
+  const struct rebase_todo_item *);
+
+struct rebase_todo_item *rebase_todo_list_push_empty(struct rebase_todo_list 
*);
+
+struct rebase_todo_item *rebase_todo_list_push_noop(struct rebase_todo_list *);
+
+int rebase_todo_list_load(struct rebase_todo_list *, const char *path, int 
abbrev);
+
+void rebase_todo_list_save(const struct rebase_todo_list *, const char *path,
+  unsigned int offset, int abbrev);
+
 #endif /* REBASE_TODO_H */
-- 

[PATCH/RFC/GSoC 08/17] rebase-common: let refresh_and_write_cache() take a flags argument

2016-03-12 Thread Paul Tan
refresh_and_write_cache() is a handy function for refreshing the index
and writing the resulting index back to the filesystem. However, it
always calls refresh_cache() with REFRESH_QUIET. Allow callers to modify
the behavior of refresh_cache() by allowing callers to pass a flags
argument to refresh_cache().

Signed-off-by: Paul Tan 
---
 builtin/am.c| 2 +-
 rebase-common.c | 4 ++--
 rebase-common.h | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index 504b604..5185719 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1815,7 +1815,7 @@ static void am_run(struct am_state *state, int resume)
 
unlink(am_path(state, "dirtyindex"));
 
-   refresh_and_write_cache();
+   refresh_and_write_cache(REFRESH_QUIET);
 
if (index_has_changes()) {
write_state_bool(state, "dirtyindex", 1);
diff --git a/rebase-common.c b/rebase-common.c
index b07e1f1..97b0687 100644
--- a/rebase-common.c
+++ b/rebase-common.c
@@ -5,12 +5,12 @@
 #include "refs.h"
 #include "lockfile.h"
 
-void refresh_and_write_cache(void)
+void refresh_and_write_cache(unsigned int flags)
 {
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
 
hold_locked_index(lock_file, 1);
-   refresh_cache(REFRESH_QUIET);
+   refresh_cache(flags);
if (write_locked_index(_index, lock_file, COMMIT_LOCK))
die(_("unable to write index file"));
 }
diff --git a/rebase-common.h b/rebase-common.h
index 8620e8c..4586f03 100644
--- a/rebase-common.h
+++ b/rebase-common.h
@@ -4,7 +4,7 @@
 /**
  * Refresh and write index.
  */
-void refresh_and_write_cache(void);
+void refresh_and_write_cache(unsigned int);
 
 /* common rebase backend options */
 struct rebase_options {
-- 
2.7.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/RFC/GSoC 12/17] rebase-todo: introduce rebase_todo_item

2016-03-12 Thread Paul Tan
In an interactive rebase, commands are read and executed from a todo
list (.git/rebase-merge/git-rebase-todo) to perform the rebase.

In the upcoming re-implementation of git-rebase -i in C, it is useful to
be able to parse each command into a data structure which can then be
operated on. Implement rebase_todo_item for this.

Signed-off-by: Paul Tan 
---
 Makefile  |   1 +
 rebase-todo.c | 144 ++
 rebase-todo.h |  28 
 3 files changed, 173 insertions(+)
 create mode 100644 rebase-todo.c
 create mode 100644 rebase-todo.h

diff --git a/Makefile b/Makefile
index d43e068..8b928e4 100644
--- a/Makefile
+++ b/Makefile
@@ -782,6 +782,7 @@ LIB_OBJS += read-cache.o
 LIB_OBJS += rebase-am.o
 LIB_OBJS += rebase-common.o
 LIB_OBJS += rebase-merge.o
+LIB_OBJS += rebase-todo.o
 LIB_OBJS += reflog-walk.o
 LIB_OBJS += refs.o
 LIB_OBJS += refs/files-backend.o
diff --git a/rebase-todo.c b/rebase-todo.c
new file mode 100644
index 000..ac6b222
--- /dev/null
+++ b/rebase-todo.c
@@ -0,0 +1,144 @@
+#include "cache.h"
+#include "rebase-todo.h"
+
+/*
+ * Used as the default `rest` value, so that users can always assume `rest` is
+ * non NULL and `rest` is NUL terminated even for a freshly initialized
+ * rebase_todo_item.
+ */
+static char rebase_todo_item_slopbuf[1];
+
+void rebase_todo_item_init(struct rebase_todo_item *item)
+{
+   item->action = REBASE_TODO_NONE;
+   oidclr(>oid);
+   item->rest = rebase_todo_item_slopbuf;
+}
+
+void rebase_todo_item_release(struct rebase_todo_item *item)
+{
+   if (item->rest != rebase_todo_item_slopbuf)
+   free(item->rest);
+   rebase_todo_item_init(item);
+}
+
+void rebase_todo_item_copy(struct rebase_todo_item *dst, const struct 
rebase_todo_item *src)
+{
+   if (dst->rest != rebase_todo_item_slopbuf)
+   free(dst->rest);
+   *dst = *src;
+   dst->rest = xstrdup(src->rest);
+}
+
+static const char *next_word(struct strbuf *sb, const char *str)
+{
+   const char *end;
+
+   while (*str && isspace(*str))
+   str++;
+
+   end = str;
+   while (*end && !isspace(*end))
+   end++;
+
+   strbuf_reset(sb);
+   strbuf_add(sb, str, end - str);
+   return end;
+}
+
+int rebase_todo_item_parse(struct rebase_todo_item *item, const char *line, 
int abbrev)
+{
+   struct strbuf word = STRBUF_INIT;
+   const char *str = line;
+   int has_oid = 1, ret = 0;
+
+   while (*str && isspace(*str))
+   str++;
+
+   if (!*str || *str == comment_line_char) {
+   item->action = REBASE_TODO_NONE;
+   oidclr(>oid);
+   if (item->rest != rebase_todo_item_slopbuf)
+   free(item->rest);
+   item->rest = *str ? xstrdup(str) : rebase_todo_item_slopbuf;
+   return 0;
+   }
+
+   str = next_word(, str);
+   if (!strcmp(word.buf, "noop")) {
+   item->action = REBASE_TODO_NOOP;
+   has_oid = 0;
+   } else if (!strcmp(word.buf, "pick") || !strcmp(word.buf, "p")) {
+   item->action = REBASE_TODO_PICK;
+   } else {
+   ret = error(_("Unknown command: %s"), word.buf);
+   goto finish;
+   }
+
+   if (has_oid) {
+   str = next_word(, str);
+   if (abbrev) {
+   /* accept abbreviated object ids */
+   if (get_oid_commit(word.buf, >oid)) {
+   ret = error(_("Not a commit: %s"), word.buf);
+   goto finish;
+   }
+   } else {
+   if (word.len != GIT_SHA1_HEXSZ || get_oid_hex(word.buf, 
>oid)) {
+   ret = error(_("Invalid line: %s"), line);
+   goto finish;
+   }
+   }
+   } else {
+   oidclr(>oid);
+   }
+
+   if (*str && isspace(*str))
+   str++;
+   if (*str) {
+   if (item->rest != rebase_todo_item_slopbuf)
+   free(item->rest);
+   item->rest = xstrdup(str);
+   }
+
+finish:
+   strbuf_release();
+   return ret;
+}
+
+void strbuf_add_rebase_todo_item(struct strbuf *sb,
+const struct rebase_todo_item *item, int 
abbrev)
+{
+   int has_oid = 1;
+
+   switch (item->action) {
+   case REBASE_TODO_NONE:
+   has_oid = 0;
+   break;
+   case REBASE_TODO_NOOP:
+   strbuf_addstr(sb, "noop");
+   has_oid = 0;
+   break;
+   case REBASE_TODO_PICK:
+   strbuf_addstr(sb, "pick");
+   break;
+   default:
+   die("BUG: invalid rebase_todo_item action %d", item->action);
+   }
+
+   if (has_oid) {
+   strbuf_addch(sb, ' ');
+   

[PATCH/RFC/GSoC 10/17] rebase-common: implement cache_has_uncommitted_changes()

2016-03-12 Thread Paul Tan
In the upcoming git-rebase-to-C rewrite, it is a common opertation to
check if the index has uncommitted changes, so that rebase can complain
that the index is dirty, or commit the uncommitted changes in the index.

builtin/pull.c already implements the function we want. Move it to
rebase-common.c so that it can be shared between all rebase backends and
git-pull.

Signed-off-by: Paul Tan 
---
 builtin/pull.c  | 22 +-
 rebase-common.c | 17 +
 rebase-common.h |  5 +
 3 files changed, 23 insertions(+), 21 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index 9e65dc9..6be4213 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -307,26 +307,6 @@ static enum rebase_type config_get_rebase(void)
 }
 
 /**
- * Returns 1 if there are uncommitted changes, 0 otherwise.
- */
-static int has_uncommitted_changes(const char *prefix)
-{
-   struct rev_info rev_info;
-   int result;
-
-   if (is_cache_unborn())
-   return 0;
-
-   init_revisions(_info, prefix);
-   DIFF_OPT_SET(_info.diffopt, IGNORE_SUBMODULES);
-   DIFF_OPT_SET(_info.diffopt, QUICK);
-   add_head_to_pending(_info);
-   diff_setup_done(_info.diffopt);
-   result = run_diff_index(_info, 1);
-   return diff_result_code(_info.diffopt, result);
-}
-
-/**
  * If the work tree has unstaged or uncommitted changes, dies with the
  * appropriate message.
  */
@@ -345,7 +325,7 @@ static void die_on_unclean_work_tree(const char *prefix)
do_die = 1;
}
 
-   if (has_uncommitted_changes(prefix)) {
+   if (cache_has_uncommitted_changes()) {
if (do_die)
error(_("Additionally, your index contains uncommitted 
changes."));
else
diff --git a/rebase-common.c b/rebase-common.c
index 61be8f1..94783a9 100644
--- a/rebase-common.c
+++ b/rebase-common.c
@@ -29,6 +29,23 @@ int cache_has_unstaged_changes(void)
return diff_result_code(_info.diffopt, result);
 }
 
+int cache_has_uncommitted_changes(void)
+{
+   struct rev_info rev_info;
+   int result;
+
+   if (is_cache_unborn())
+   return 0;
+
+   init_revisions(_info, NULL);
+   DIFF_OPT_SET(_info.diffopt, IGNORE_SUBMODULES);
+   DIFF_OPT_SET(_info.diffopt, QUICK);
+   add_head_to_pending(_info);
+   diff_setup_done(_info.diffopt);
+   result = run_diff_index(_info, 1);
+   return diff_result_code(_info.diffopt, result);
+}
+
 void rebase_options_init(struct rebase_options *opts)
 {
oidclr(>onto);
diff --git a/rebase-common.h b/rebase-common.h
index 9d14e25..97d9a5b 100644
--- a/rebase-common.h
+++ b/rebase-common.h
@@ -11,6 +11,11 @@ void refresh_and_write_cache(unsigned int);
  */
 int cache_has_unstaged_changes(void);
 
+/**
+ * Returns 1 if there are uncommitted changes, 0 otherwise.
+ */
+int cache_has_uncommitted_changes(void);
+
 /* common rebase backend options */
 struct rebase_options {
struct object_id onto;
-- 
2.7.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/RFC/GSoC 14/17] status: use rebase_todo_list

2016-03-12 Thread Paul Tan
Since 84e6fb9 (status: give more information during rebase -i,
2015-07-06), git status during an interactive rebase will show the list
of commands that are done and yet to be done. It implemented its own
hand-rolled parser in order to achieve this.

Now that we are able to fully parse interactive rebase's todo lists with
rebase_todo_list_parse(), use it in wt-status.c to reduce the amount of
code needed to implement this feature.

Signed-off-by: Paul Tan 
---

This patch is just an illustration, and is not quite right as it does not strip
comments and blank lines like the original did.

 wt-status.c | 100 +++-
 1 file changed, 25 insertions(+), 75 deletions(-)

diff --git a/wt-status.c b/wt-status.c
index ab4f80d..96b82ef 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -15,6 +15,7 @@
 #include "column.h"
 #include "strbuf.h"
 #include "utf8.h"
+#include "rebase-todo.h"
 
 static const char cut_line[] =
 " >8 \n";
@@ -1026,94 +1027,39 @@ static int split_commit_in_progress(struct wt_status *s)
return split_in_progress;
 }
 
-/*
- * Turn
- * "pick d6a2f0303e897ec257dd0e0a39a5ccb709bc2047 some message"
- * into
- * "pick d6a2f03 some message"
- *
- * The function assumes that the line does not contain useless spaces
- * before or after the command.
- */
-static void abbrev_sha1_in_line(struct strbuf *line)
-{
-   struct strbuf **split;
-   int i;
-
-   if (starts_with(line->buf, "exec ") ||
-   starts_with(line->buf, "x "))
-   return;
-
-   split = strbuf_split_max(line, ' ', 3);
-   if (split[0] && split[1]) {
-   unsigned char sha1[20];
-   const char *abbrev;
-
-   /*
-* strbuf_split_max left a space. Trim it and re-add
-* it after abbreviation.
-*/
-   strbuf_trim(split[1]);
-   if (!get_sha1(split[1]->buf, sha1)) {
-   abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
-   strbuf_reset(split[1]);
-   strbuf_addf(split[1], "%s ", abbrev);
-   strbuf_reset(line);
-   for (i = 0; split[i]; i++)
-   strbuf_addf(line, "%s", split[i]->buf);
-   }
-   }
-   for (i = 0; split[i]; i++)
-   strbuf_release(split[i]);
-
-}
-
-static void read_rebase_todolist(const char *fname, struct string_list *lines)
-{
-   struct strbuf line = STRBUF_INIT;
-   FILE *f = fopen(git_path("%s", fname), "r");
-
-   if (!f)
-   die_errno("Could not open file %s for reading",
- git_path("%s", fname));
-   while (!strbuf_getline_lf(, f)) {
-   if (line.len && line.buf[0] == comment_line_char)
-   continue;
-   strbuf_trim();
-   if (!line.len)
-   continue;
-   abbrev_sha1_in_line();
-   string_list_append(lines, line.buf);
-   }
-}
-
 static void show_rebase_information(struct wt_status *s,
struct wt_status_state *state,
const char *color)
 {
if (state->rebase_interactive_in_progress) {
-   int i;
-   int nr_lines_to_show = 2;
+   unsigned int i;
+   unsigned int nr_lines_to_show = 2;
+   struct strbuf sb = STRBUF_INIT;
 
-   struct string_list have_done = STRING_LIST_INIT_DUP;
-   struct string_list yet_to_do = STRING_LIST_INIT_DUP;
+   struct rebase_todo_list have_done = REBASE_TODO_LIST_INIT;
+   struct rebase_todo_list yet_to_do = REBASE_TODO_LIST_INIT;
 
-   read_rebase_todolist("rebase-merge/done", _done);
-   read_rebase_todolist("rebase-merge/git-rebase-todo", 
_to_do);
+   if (rebase_todo_list_load(_done, 
git_path("rebase-merge/done"), 1) < 0)
+   return;
+   if (rebase_todo_list_load(_to_do, 
git_path("rebase-merge/git-rebase-todo"), 1) < 0)
+   return;
 
if (have_done.nr == 0)
status_printf_ln(s, color, _("No commands done."));
else {
status_printf_ln(s, color,
-   Q_("Last command done (%d command done):",
-   "Last commands done (%d commands 
done):",
+   Q_("Last command done (%u command done):",
+   "Last commands done (%u commands 
done):",
have_done.nr),
have_done.nr);
for (i = (have_done.nr > nr_lines_to_show)
? have_done.nr 

[PATCH/RFC/GSoC 06/17] rebase-am: introduce am backend for builtin rebase

2016-03-12 Thread Paul Tan
Since 7f59dbb (Rewrite rebase to use git-format-patch piped to git-am.,
2005-11-14), git-rebase will by default use "git am" to rebase commits.
This is done by first checking out to the new base commit, generating a
series of patches with the commits to replay, and then applying them
with git-am. Finally, if orig_head is a branch, it is updated to point
to the tip of the new rebased commit history.

Implement a skeletal version of this method of rebasing commits by
introducing a new rebase-am backend for our builtin-rebase. This
skeletal version can only call git-format-patch and git-am to perform a
rebase, and is unable to resume from a failed rebase. Subsequent
patches will re-implement all the missing features.

The symmetric difference between upstream...orig_head is used because in
a later patch, we will add an additional exclusion revision in order to
handle fork points correctly.  See b6266dc (rebase--am: use
--cherry-pick instead of --ignore-if-in-upstream, 2014-07-15).

The initial steps of checking out the new base commit, and the final
cleanup steps of updating refs are common between the am backend and
merge backend. As such, we implement the common setup and teardown
sequence in the shared functions rebase_common_setup() and
rebase_common_finish(), so we can share code with the merge backend when
it is implemented in a later patch.

Signed-off-by: Paul Tan 
---
 Makefile |   1 +
 builtin/rebase.c |  25 +
 rebase-am.c  | 110 +++
 rebase-am.h  |  22 +++
 rebase-common.c  |  81 
 rebase-common.h  |   6 +++
 6 files changed, 245 insertions(+)
 create mode 100644 rebase-am.c
 create mode 100644 rebase-am.h

diff --git a/Makefile b/Makefile
index b29c672..a2618ea 100644
--- a/Makefile
+++ b/Makefile
@@ -779,6 +779,7 @@ LIB_OBJS += prompt.o
 LIB_OBJS += quote.o
 LIB_OBJS += reachable.o
 LIB_OBJS += read-cache.o
+LIB_OBJS += rebase-am.o
 LIB_OBJS += rebase-common.o
 LIB_OBJS += reflog-walk.o
 LIB_OBJS += refs.o
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 40176ca..ec63d3b 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -8,6 +8,22 @@
 #include "remote.h"
 #include "branch.h"
 #include "refs.h"
+#include "rebase-am.h"
+
+enum rebase_type {
+   REBASE_TYPE_NONE = 0,
+   REBASE_TYPE_AM
+};
+
+static const char *rebase_dir(enum rebase_type type)
+{
+   switch (type) {
+   case REBASE_TYPE_AM:
+   return git_path_rebase_am_dir();
+   default:
+   die("BUG: invalid rebase_type %d", type);
+   }
+}
 
 /**
  * Used by get_curr_branch_upstream_name() as a for_each_remote() callback to
@@ -208,6 +224,15 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
die(_("Failed to resolve '%s' as a valid revision."), 
"HEAD");
}
 
+   /* Run the appropriate rebase backend */
+   {
+   struct rebase_am state;
+   rebase_am_init(, rebase_dir(REBASE_TYPE_AM));
+   rebase_options_swap(, _opts);
+   rebase_am_run();
+   rebase_am_release();
+   }
+
rebase_options_release(_opts);
return 0;
 }
diff --git a/rebase-am.c b/rebase-am.c
new file mode 100644
index 000..53e8798
--- /dev/null
+++ b/rebase-am.c
@@ -0,0 +1,110 @@
+#include "cache.h"
+#include "rebase-am.h"
+#include "run-command.h"
+
+GIT_PATH_FUNC(git_path_rebase_am_dir, "rebase-apply");
+
+void rebase_am_init(struct rebase_am *state, const char *dir)
+{
+   if (!dir)
+   dir = git_path_rebase_am_dir();
+   rebase_options_init(>opts);
+   state->dir = xstrdup(dir);
+}
+
+void rebase_am_release(struct rebase_am *state)
+{
+   rebase_options_release(>opts);
+   free(state->dir);
+}
+
+int rebase_am_in_progress(const struct rebase_am *state)
+{
+   const char *dir = state ? state->dir : git_path_rebase_am_dir();
+   struct stat st;
+
+   return !lstat(dir, ) && S_ISDIR(st.st_mode);
+}
+
+int rebase_am_load(struct rebase_am *state)
+{
+   if (rebase_options_load(>opts, state->dir) < 0)
+   return -1;
+
+   return 0;
+}
+
+static int run_format_patch(const char *patches, const struct object_id *left,
+   const struct object_id *right)
+{
+   struct child_process cp = CHILD_PROCESS_INIT;
+   int ret;
+
+   cp.git_cmd = 1;
+   cp.out = xopen(patches, O_WRONLY | O_CREAT, 0777);
+   argv_array_push(, "format-patch");
+   argv_array_push(, "-k");
+   argv_array_push(, "--stdout");
+   argv_array_push(, "--full-index");
+   argv_array_push(, "--cherry-pick");
+   argv_array_push(, "--right-only");
+   argv_array_push(, "--src-prefix=a/");
+   argv_array_push(, "--dst-prefix=b/");
+   argv_array_push(, "--no-renames");
+   argv_array_push(, "--no-cover-letter");
+   argv_array_pushf(, "%s...%s", 

[PATCH/RFC/GSoC 09/17] rebase-common: implement cache_has_unstaged_changes()

2016-03-12 Thread Paul Tan
In the upcoming git-rebase-to-C rewrite, it is a common operation to
check if the worktree has unstaged changes, so that it can complain that
the worktree is dirty.

builtin/pull.c already implements this function. Move it to
rebase-common.c so that it can be shared between all rebase backends and
git-pull.

Signed-off-by: Paul Tan 
---
 builtin/pull.c  | 19 ++-
 rebase-common.c | 14 ++
 rebase-common.h |  5 +
 3 files changed, 21 insertions(+), 17 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index 10eff03..9e65dc9 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -17,6 +17,7 @@
 #include "revision.h"
 #include "tempfile.h"
 #include "lockfile.h"
+#include "rebase-common.h"
 
 enum rebase_type {
REBASE_INVALID = -1,
@@ -306,22 +307,6 @@ static enum rebase_type config_get_rebase(void)
 }
 
 /**
- * Returns 1 if there are unstaged changes, 0 otherwise.
- */
-static int has_unstaged_changes(const char *prefix)
-{
-   struct rev_info rev_info;
-   int result;
-
-   init_revisions(_info, prefix);
-   DIFF_OPT_SET(_info.diffopt, IGNORE_SUBMODULES);
-   DIFF_OPT_SET(_info.diffopt, QUICK);
-   diff_setup_done(_info.diffopt);
-   result = run_diff_files(_info, 0);
-   return diff_result_code(_info.diffopt, result);
-}
-
-/**
  * Returns 1 if there are uncommitted changes, 0 otherwise.
  */
 static int has_uncommitted_changes(const char *prefix)
@@ -355,7 +340,7 @@ static void die_on_unclean_work_tree(const char *prefix)
update_index_if_able(_index, lock_file);
rollback_lock_file(lock_file);
 
-   if (has_unstaged_changes(prefix)) {
+   if (cache_has_unstaged_changes()) {
error(_("Cannot pull with rebase: You have unstaged changes."));
do_die = 1;
}
diff --git a/rebase-common.c b/rebase-common.c
index 97b0687..61be8f1 100644
--- a/rebase-common.c
+++ b/rebase-common.c
@@ -4,6 +4,7 @@
 #include "run-command.h"
 #include "refs.h"
 #include "lockfile.h"
+#include "revision.h"
 
 void refresh_and_write_cache(unsigned int flags)
 {
@@ -15,6 +16,19 @@ void refresh_and_write_cache(unsigned int flags)
die(_("unable to write index file"));
 }
 
+int cache_has_unstaged_changes(void)
+{
+   struct rev_info rev_info;
+   int result;
+
+   init_revisions(_info, NULL);
+   DIFF_OPT_SET(_info.diffopt, IGNORE_SUBMODULES);
+   DIFF_OPT_SET(_info.diffopt, QUICK);
+   diff_setup_done(_info.diffopt);
+   result = run_diff_files(_info, 0);
+   return diff_result_code(_info.diffopt, result);
+}
+
 void rebase_options_init(struct rebase_options *opts)
 {
oidclr(>onto);
diff --git a/rebase-common.h b/rebase-common.h
index 4586f03..9d14e25 100644
--- a/rebase-common.h
+++ b/rebase-common.h
@@ -6,6 +6,11 @@
  */
 void refresh_and_write_cache(unsigned int);
 
+/**
+ * Returns 1 if there are unstaged changes, 0 otherwise.
+ */
+int cache_has_unstaged_changes(void);
+
 /* common rebase backend options */
 struct rebase_options {
struct object_id onto;
-- 
2.7.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/RFC/GSoC 11/17] rebase-merge: introduce merge backend for builtin rebase

2016-03-12 Thread Paul Tan
Since 58634db (rebase: Allow merge strategies to be used when rebasing,
2006-06-21), git-rebase supported rebasing with a merge strategy when
the -m switch is used.

Re-implement a skeletal version of the above method of rebasing in a new
rebase-merge backend for our builtin-rebase. This skeletal version is
only able to re-apply commits using the merge-recursive strategy, and is
unable to resume from a conflict. Subsequent patches will re-implement
all the missing features.

Signed-off-by: Paul Tan 
---
 Makefile |   1 +
 builtin/rebase.c |  17 +++-
 rebase-merge.c   | 256 +++
 rebase-merge.h   |  28 ++
 4 files changed, 300 insertions(+), 2 deletions(-)
 create mode 100644 rebase-merge.c
 create mode 100644 rebase-merge.h

diff --git a/Makefile b/Makefile
index a2618ea..d43e068 100644
--- a/Makefile
+++ b/Makefile
@@ -781,6 +781,7 @@ LIB_OBJS += reachable.o
 LIB_OBJS += read-cache.o
 LIB_OBJS += rebase-am.o
 LIB_OBJS += rebase-common.o
+LIB_OBJS += rebase-merge.o
 LIB_OBJS += reflog-walk.o
 LIB_OBJS += refs.o
 LIB_OBJS += refs/files-backend.o
diff --git a/builtin/rebase.c b/builtin/rebase.c
index ec63d3b..6d42115 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -9,10 +9,12 @@
 #include "branch.h"
 #include "refs.h"
 #include "rebase-am.h"
+#include "rebase-merge.h"
 
 enum rebase_type {
REBASE_TYPE_NONE = 0,
-   REBASE_TYPE_AM
+   REBASE_TYPE_AM,
+   REBASE_TYPE_MERGE
 };
 
 static const char *rebase_dir(enum rebase_type type)
@@ -20,6 +22,8 @@ static const char *rebase_dir(enum rebase_type type)
switch (type) {
case REBASE_TYPE_AM:
return git_path_rebase_am_dir();
+   case REBASE_TYPE_MERGE:
+   return git_path_rebase_merge_dir();
default:
die("BUG: invalid rebase_type %d", type);
}
@@ -137,6 +141,7 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
struct rebase_options rebase_opts;
const char *onto_name = NULL;
const char *branch_name;
+   int do_merge = 0;
 
const char * const usage[] = {
N_("git rebase [options] [--onto ] [] 
[]"),
@@ -146,6 +151,8 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
OPT_GROUP(N_("Available options are")),
OPT_STRING(0, "onto", _name, NULL,
N_("rebase onto given branch instead of upstream")),
+   OPT_BOOL('m', "merge", _merge,
+   N_("use merging strategies to rebase")),
OPT_END()
};
 
@@ -225,7 +232,13 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
}
 
/* Run the appropriate rebase backend */
-   {
+   if (do_merge) {
+   struct rebase_merge state;
+   rebase_merge_init(, rebase_dir(REBASE_TYPE_MERGE));
+   rebase_options_swap(, _opts);
+   rebase_merge_run();
+   rebase_merge_release();
+   } else {
struct rebase_am state;
rebase_am_init(, rebase_dir(REBASE_TYPE_AM));
rebase_options_swap(, _opts);
diff --git a/rebase-merge.c b/rebase-merge.c
new file mode 100644
index 000..dc96faf
--- /dev/null
+++ b/rebase-merge.c
@@ -0,0 +1,256 @@
+#include "cache.h"
+#include "rebase-merge.h"
+#include "run-command.h"
+#include "dir.h"
+#include "revision.h"
+
+GIT_PATH_FUNC(git_path_rebase_merge_dir, "rebase-merge");
+
+void rebase_merge_init(struct rebase_merge *state, const char *dir)
+{
+   if (!dir)
+   dir = git_path_rebase_merge_dir();
+   rebase_options_init(>opts);
+   state->dir = xstrdup(dir);
+   state->msgnum = 0;
+   state->end = 0;
+   state->prec = 4;
+}
+
+void rebase_merge_release(struct rebase_merge *state)
+{
+   rebase_options_release(>opts);
+   free(state->dir);
+}
+
+int rebase_merge_in_progress(const struct rebase_merge *state)
+{
+   const char *dir = state ? state->dir : git_path_rebase_merge_dir();
+   struct stat st;
+
+   if (lstat(dir, ) || !S_ISDIR(st.st_mode))
+   return 0;
+
+   if (file_exists(mkpath("%s/interactive", dir)))
+   return 0;
+
+   return 1;
+}
+
+static const char *state_path(const struct rebase_merge *state, const char 
*filename)
+{
+   return mkpath("%s/%s", state->dir, filename);
+}
+
+static int read_state_file(const struct rebase_merge *state, const char 
*filename, struct strbuf *sb)
+{
+   const char *path = state_path(state, filename);
+   if (strbuf_read_file(sb, path, 0) < 0)
+   return error(_("could not read file %s"), path);
+   strbuf_trim(sb);
+   return 0;
+}
+
+static int read_state_ui(const struct rebase_merge *state, const char 
*filename, unsigned int *ui)
+{
+   struct strbuf sb = STRBUF_INIT;
+   if (read_state_file(state, filename, ) < 0) {
+  

[PATCH/RFC/GSoC 07/17] rebase-common: implement refresh_and_write_cache()

2016-03-12 Thread Paul Tan
In the upcoming git-rebase to C rewrite, it is a common operation to
refresh the index and write the resulting index.

builtin/am.c already implements refresh_and_write_cache(), which is what
we want. Move it to rebase-common.c, so that it can be shared with all
the rebase backends, including git-am.

Signed-off-by: Paul Tan 
---
 builtin/am.c| 14 +-
 rebase-common.c | 11 +++
 rebase-common.h |  5 +
 3 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/builtin/am.c b/builtin/am.c
index d003939..504b604 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -28,6 +28,7 @@
 #include "rerere.h"
 #include "prompt.h"
 #include "mailinfo.h"
+#include "rebase-common.h"
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -1125,19 +1126,6 @@ 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(_index, lock_file, COMMIT_LOCK))
-   die(_("unable to write index file"));
-}
-
-/**
  * 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
diff --git a/rebase-common.c b/rebase-common.c
index 8169fb6..b07e1f1 100644
--- a/rebase-common.c
+++ b/rebase-common.c
@@ -3,6 +3,17 @@
 #include "dir.h"
 #include "run-command.h"
 #include "refs.h"
+#include "lockfile.h"
+
+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(_index, lock_file, COMMIT_LOCK))
+   die(_("unable to write index file"));
+}
 
 void rebase_options_init(struct rebase_options *opts)
 {
diff --git a/rebase-common.h b/rebase-common.h
index 067ad0b..8620e8c 100644
--- a/rebase-common.h
+++ b/rebase-common.h
@@ -1,6 +1,11 @@
 #ifndef REBASE_COMMON_H
 #define REBASE_COMMON_H
 
+/**
+ * Refresh and write index.
+ */
+void refresh_and_write_cache(void);
+
 /* common rebase backend options */
 struct rebase_options {
struct object_id onto;
-- 
2.7.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/RFC/GSoC 17/17] rebase-interactive: introduce interactive backend for builtin rebase

2016-03-12 Thread Paul Tan
Since 1b1dce4 (Teach rebase an interactive mode, 2007-06-25), git-rebase
supports an interactive mode when passed the -i switch.

In interactive mode, git-rebase allows users to edit the list of patches
(using the user's GIT_SEQUENCE_EDITOR), so that the user can reorder,
edit and delete patches.

Re-implement a skeletal version of the above feature by introducing a
rebase-interactive backend for our builtin-rebase. This skeletal
implementation is only able to pick and re-order commits.

Signed-off-by: Paul Tan 
---
 Makefile |   1 +
 builtin/rebase.c |  17 ++-
 rebase-interactive.c | 375 +++
 rebase-interactive.h |  33 +
 4 files changed, 424 insertions(+), 2 deletions(-)
 create mode 100644 rebase-interactive.c
 create mode 100644 rebase-interactive.h

diff --git a/Makefile b/Makefile
index 8b928e4..3bd3127 100644
--- a/Makefile
+++ b/Makefile
@@ -781,6 +781,7 @@ LIB_OBJS += reachable.o
 LIB_OBJS += read-cache.o
 LIB_OBJS += rebase-am.o
 LIB_OBJS += rebase-common.o
+LIB_OBJS += rebase-interactive.o
 LIB_OBJS += rebase-merge.o
 LIB_OBJS += rebase-todo.o
 LIB_OBJS += reflog-walk.o
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 6d42115..d811a44 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -10,11 +10,13 @@
 #include "refs.h"
 #include "rebase-am.h"
 #include "rebase-merge.h"
+#include "rebase-interactive.h"
 
 enum rebase_type {
REBASE_TYPE_NONE = 0,
REBASE_TYPE_AM,
-   REBASE_TYPE_MERGE
+   REBASE_TYPE_MERGE,
+   REBASE_TYPE_INTERACTIVE
 };
 
 static const char *rebase_dir(enum rebase_type type)
@@ -24,6 +26,8 @@ static const char *rebase_dir(enum rebase_type type)
return git_path_rebase_am_dir();
case REBASE_TYPE_MERGE:
return git_path_rebase_merge_dir();
+   case REBASE_TYPE_INTERACTIVE:
+   return git_path_rebase_interactive_dir();
default:
die("BUG: invalid rebase_type %d", type);
}
@@ -142,6 +146,7 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
const char *onto_name = NULL;
const char *branch_name;
int do_merge = 0;
+   int interactive = 0;
 
const char * const usage[] = {
N_("git rebase [options] [--onto ] [] 
[]"),
@@ -153,6 +158,8 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
N_("rebase onto given branch instead of upstream")),
OPT_BOOL('m', "merge", _merge,
N_("use merging strategies to rebase")),
+   OPT_BOOL('i', "interactive", ,
+   N_("let the user edit the list of commits to rebase")),
OPT_END()
};
 
@@ -232,7 +239,13 @@ int cmd_rebase(int argc, const char **argv, const char 
*prefix)
}
 
/* Run the appropriate rebase backend */
-   if (do_merge) {
+   if (interactive) {
+   struct rebase_interactive state;
+   rebase_interactive_init(, 
rebase_dir(REBASE_TYPE_INTERACTIVE));
+   rebase_options_swap(, _opts);
+   rebase_interactive_run();
+   rebase_interactive_release();
+   } else if (do_merge) {
struct rebase_merge state;
rebase_merge_init(, rebase_dir(REBASE_TYPE_MERGE));
rebase_options_swap(, _opts);
diff --git a/rebase-interactive.c b/rebase-interactive.c
new file mode 100644
index 000..342a6fe
--- /dev/null
+++ b/rebase-interactive.c
@@ -0,0 +1,375 @@
+#include "cache.h"
+#include "rebase-interactive.h"
+#include "argv-array.h"
+#include "revision.h"
+#include "dir.h"
+#include "run-command.h"
+
+static int is_empty_commit(struct commit *commit)
+{
+   if (commit->parents)
+   return !oidcmp(>object.oid, 
>parents->item->object.oid);
+   else
+   return !hashcmp(commit->object.oid.hash, EMPTY_TREE_SHA1_BIN);
+}
+
+GIT_PATH_FUNC(git_path_rebase_interactive_dir, "rebase-merge")
+
+void rebase_interactive_init(struct rebase_interactive *state, const char *dir)
+{
+   rebase_options_init(>opts);
+   if (!dir)
+   dir = git_path_rebase_interactive_dir();
+   state->dir = xstrdup(dir);
+
+   state->todo_file = mkpathdup("%s/git-rebase-todo", state->dir);
+   rebase_todo_list_init(>todo);
+   state->todo_offset = 0;
+   state->todo_count = 0;
+
+   state->done_file = mkpathdup("%s/done", state->dir);
+   state->done_count = 0;
+
+   state->instruction_format = NULL;
+   git_config_get_value("rebase.instructionFormat", 
>instruction_format);
+}
+
+void rebase_interactive_release(struct rebase_interactive *state)
+{
+   rebase_options_release(>opts);
+   free(state->dir);
+
+   free(state->todo_file);
+   rebase_todo_list_clear(>todo);
+
+   free(state->done_file);
+}
+
+int rebase_interactive_in_progress(const struct 

[PATCH/RFC/GSoC 15/17] wrapper: implement append_file()

2016-03-12 Thread Paul Tan
Signed-off-by: Paul Tan 
---
 cache.h   |  1 +
 wrapper.c | 23 +++
 2 files changed, 24 insertions(+)

diff --git a/cache.h b/cache.h
index 55d443e..aa5e97c 100644
--- a/cache.h
+++ b/cache.h
@@ -1700,6 +1700,7 @@ static inline ssize_t write_str_in_full(int fd, const 
char *str)
 
 extern int write_file(const char *path, const char *fmt, ...);
 extern int write_file_gently(const char *path, const char *fmt, ...);
+extern void append_file(const char *path, const char *fmt, ...);
 
 /* pager.c */
 extern void setup_pager(void);
diff --git a/wrapper.c b/wrapper.c
index 9afc1a0..cd77e94 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -709,6 +709,29 @@ int write_file_gently(const char *path, const char *fmt, 
...)
return status;
 }
 
+void append_file(const char *path, const char *fmt, ...)
+{
+   struct strbuf sb = STRBUF_INIT;
+   int fd = open(path, O_WRONLY | O_CREAT | O_APPEND, 0666);
+   va_list params;
+   if (fd < 0)
+   die_errno(_("could not open %s for appending"), path);
+   va_start(params, fmt);
+   strbuf_vaddf(, fmt, params);
+   va_end(params);
+   strbuf_complete_line();
+   if (write_in_full(fd, sb.buf, sb.len) != sb.len) {
+   int err = errno;
+   close(fd);
+   strbuf_release();
+   errno = err;
+   die_errno(_("could not write to %s"), path);
+   }
+   strbuf_release();
+   if (close(fd))
+   die_errno(_("could not close %s"), path);
+}
+
 void sleep_millisec(int millisec)
 {
poll(NULL, 0, millisec);
-- 
2.7.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/RFC/GSoC 05/17] rebase-options: implement rebase_options_load() and rebase_options_save()

2016-03-12 Thread Paul Tan
These functions can be used for loading and saving common rebase options
into a state directory.

Signed-off-by: Paul Tan 
---
 rebase-common.c | 69 +
 rebase-common.h |  4 
 2 files changed, 73 insertions(+)

diff --git a/rebase-common.c b/rebase-common.c
index 5a49ac4..1835f08 100644
--- a/rebase-common.c
+++ b/rebase-common.c
@@ -26,3 +26,72 @@ void rebase_options_swap(struct rebase_options *dst, struct 
rebase_options *src)
*dst = *src;
*src = tmp;
 }
+
+static int state_file_exists(const char *dir, const char *file)
+{
+   return file_exists(mkpath("%s/%s", dir, file));
+}
+
+static int read_state_file(struct strbuf *sb, const char *dir, const char 
*file)
+{
+   const char *path = mkpath("%s/%s", dir, file);
+   strbuf_reset(sb);
+   if (strbuf_read_file(sb, path, 0) >= 0)
+   return sb->len;
+   else
+   return error(_("could not read '%s'"), path);
+}
+
+int rebase_options_load(struct rebase_options *opts, const char *dir)
+{
+   struct strbuf sb = STRBUF_INIT;
+   const char *filename;
+
+   /* opts->orig_refname */
+   if (read_state_file(, dir, "head-name") < 0)
+   return -1;
+   strbuf_trim();
+   if (starts_with(sb.buf, "refs/heads/"))
+   opts->orig_refname = strbuf_detach(, NULL);
+   else if (!strcmp(sb.buf, "detached HEAD"))
+   opts->orig_refname = NULL;
+   else
+   return error(_("could not parse %s"), mkpath("%s/%s", dir, 
"head-name"));
+
+   /* opts->onto */
+   if (read_state_file(, dir, "onto") < 0)
+   return -1;
+   strbuf_trim();
+   if (get_oid_hex(sb.buf, >onto) < 0)
+   return error(_("could not parse %s"), mkpath("%s/%s", dir, 
"onto"));
+
+   /*
+* We always write to orig-head, but interactive rebase used to write
+* to head. Fall back to reading from head to cover for the case that
+* the user upgraded git with an ongoing interactive rebase.
+*/
+   filename = state_file_exists(dir, "orig-head") ? "orig-head" : "head";
+   if (read_state_file(, dir, filename) < 0)
+   return -1;
+   strbuf_trim();
+   if (get_oid_hex(sb.buf, >orig_head) < 0)
+   return error(_("could not parse %s"), mkpath("%s/%s", dir, 
filename));
+
+   strbuf_release();
+   return 0;
+}
+
+static int write_state_text(const char *dir, const char *file, const char 
*string)
+{
+   return write_file(mkpath("%s/%s", dir, file), "%s", string);
+}
+
+void rebase_options_save(const struct rebase_options *opts, const char *dir)
+{
+   const char *head_name = opts->orig_refname;
+   if (!head_name)
+   head_name = "detached HEAD";
+   write_state_text(dir, "head-name", head_name);
+   write_state_text(dir, "onto", oid_to_hex(>onto));
+   write_state_text(dir, "orig-head", oid_to_hex(>orig_head));
+}
diff --git a/rebase-common.h b/rebase-common.h
index db5146a..051c056 100644
--- a/rebase-common.h
+++ b/rebase-common.h
@@ -20,4 +20,8 @@ void rebase_options_release(struct rebase_options *);
 
 void rebase_options_swap(struct rebase_options *dst, struct rebase_options 
*src);
 
+int rebase_options_load(struct rebase_options *, const char *dir);
+
+void rebase_options_save(const struct rebase_options *, const char *dir);
+
 #endif /* REBASE_COMMON_H */
-- 
2.7.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/RFC/GSoC 03/17] builtin-rebase: implement skeletal builtin rebase

2016-03-12 Thread Paul Tan
Signed-off-by: Paul Tan 
---
 Makefile |  5 +
 builtin.h|  1 +
 builtin/rebase.c | 31 +++
 git.c|  1 +
 4 files changed, 34 insertions(+), 4 deletions(-)
 create mode 100644 builtin/rebase.c

diff --git a/Makefile b/Makefile
index 24bef8d..ad98714 100644
--- a/Makefile
+++ b/Makefile
@@ -496,7 +496,6 @@ SCRIPT_SH += git-merge-one-file.sh
 SCRIPT_SH += git-merge-resolve.sh
 SCRIPT_SH += git-mergetool.sh
 SCRIPT_SH += git-quiltimport.sh
-SCRIPT_SH += git-rebase.sh
 SCRIPT_SH += git-remote-testgit.sh
 SCRIPT_SH += git-request-pull.sh
 SCRIPT_SH += git-stash.sh
@@ -505,9 +504,6 @@ SCRIPT_SH += git-web--browse.sh
 
 SCRIPT_LIB += git-mergetool--lib
 SCRIPT_LIB += git-parse-remote
-SCRIPT_LIB += git-rebase--am
-SCRIPT_LIB += git-rebase--interactive
-SCRIPT_LIB += git-rebase--merge
 SCRIPT_LIB += git-sh-setup
 SCRIPT_LIB += git-sh-i18n
 
@@ -909,6 +905,7 @@ BUILTIN_OBJS += builtin/prune.o
 BUILTIN_OBJS += builtin/pull.o
 BUILTIN_OBJS += builtin/push.o
 BUILTIN_OBJS += builtin/read-tree.o
+BUILTIN_OBJS += builtin/rebase.o
 BUILTIN_OBJS += builtin/receive-pack.o
 BUILTIN_OBJS += builtin/reflog.o
 BUILTIN_OBJS += builtin/remote.o
diff --git a/builtin.h b/builtin.h
index 6b95006..a184a58 100644
--- a/builtin.h
+++ b/builtin.h
@@ -102,6 +102,7 @@ extern int cmd_prune_packed(int argc, const char **argv, 
const char *prefix);
 extern int cmd_pull(int argc, const char **argv, const char *prefix);
 extern int cmd_push(int argc, const char **argv, const char *prefix);
 extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
+extern int cmd_rebase(int argc, const char **argv, const char *prefix);
 extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);
 extern int cmd_reflog(int argc, const char **argv, const char *prefix);
 extern int cmd_remote(int argc, const char **argv, const char *prefix);
diff --git a/builtin/rebase.c b/builtin/rebase.c
new file mode 100644
index 000..04cc1bd
--- /dev/null
+++ b/builtin/rebase.c
@@ -0,0 +1,31 @@
+/*
+ * Builtin "git rebase"
+ */
+#include "cache.h"
+#include "builtin.h"
+#include "parse-options.h"
+
+static int git_rebase_config(const char *k, const char *v, void *cb)
+{
+   return git_default_config(k, v, NULL);
+}
+
+int cmd_rebase(int argc, const char **argv, const char *prefix)
+{
+   const char * const usage[] = {
+   N_("git rebase [options]"),
+   NULL
+   };
+   struct option options[] = {
+   OPT_END()
+   };
+
+   git_config(git_rebase_config, NULL);
+
+   argc = parse_options(argc, argv, prefix, options, usage, 0);
+
+   if (read_cache_preload(NULL) < 0)
+   die(_("failed to read the index"));
+
+   return 0;
+}
diff --git a/git.c b/git.c
index 6cc0c07..f9b7033 100644
--- a/git.c
+++ b/git.c
@@ -452,6 +452,7 @@ static struct cmd_struct commands[] = {
{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
{ "push", cmd_push, RUN_SETUP },
{ "read-tree", cmd_read_tree, RUN_SETUP },
+   { "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
{ "receive-pack", cmd_receive_pack },
{ "reflog", cmd_reflog, RUN_SETUP },
{ "remote", cmd_remote, RUN_SETUP },
-- 
2.7.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/RFC/GSoC 02/17] sha1_name: implement get_oid() and friends

2016-03-12 Thread Paul Tan
5f7817c (define a structure for object IDs, 2015-03-13) introduced the
object_id struct to replace the used of unsigned char[] arrays to hold
object IDs. This gives us the benefit of compile-time checking for
misuse.

To fully take advantage of compile-time type-checking, introduce the
get_oid_*() functions which wrap the corresponding get_sha1_*()
functions.

Signed-off-by: Paul Tan 
---
 cache.h |  6 ++
 sha1_name.c | 30 ++
 2 files changed, 36 insertions(+)

diff --git a/cache.h b/cache.h
index b829410..55d443e 100644
--- a/cache.h
+++ b/cache.h
@@ -1116,11 +1116,17 @@ struct object_context {
 #define GET_SHA1_ONLY_TO_DIE04000
 
 extern int get_sha1(const char *str, unsigned char *sha1);
+extern int get_oid(const char *str, struct object_id *oid);
 extern int get_sha1_commit(const char *str, unsigned char *sha1);
+extern int get_oid_commit(const char *str, struct object_id *oid);
 extern int get_sha1_committish(const char *str, unsigned char *sha1);
+extern int get_oid_committish(const char *str, struct object_id *oid);
 extern int get_sha1_tree(const char *str, unsigned char *sha1);
+extern int get_oid_tree(const char *str, struct object_id *oid);
 extern int get_sha1_treeish(const char *str, unsigned char *sha1);
+extern int get_oid_treeish(const char *str, struct object_id *oid);
 extern int get_sha1_blob(const char *str, unsigned char *sha1);
+extern int get_oid_blob(const char *str, struct object_id *oid);
 extern void maybe_die_on_misspelt_object_name(const char *name, const char 
*prefix);
 extern int get_sha1_with_context(const char *str, unsigned flags, unsigned 
char *sha1, struct object_context *orc);
 
diff --git a/sha1_name.c b/sha1_name.c
index 3acf221..307dfad 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -1214,6 +1214,11 @@ int get_sha1(const char *name, unsigned char *sha1)
return get_sha1_with_context(name, 0, sha1, );
 }
 
+int get_oid(const char *name, struct object_id *oid)
+{
+   return get_sha1(name, oid->hash);
+}
+
 /*
  * Many callers know that the user meant to name a commit-ish by
  * syntactical positions where the object name appears.  Calling this
@@ -1231,6 +1236,11 @@ int get_sha1_committish(const char *name, unsigned char 
*sha1)
 sha1, );
 }
 
+int get_oid_committish(const char *name, struct object_id *oid)
+{
+   return get_sha1_committish(name, oid->hash);
+}
+
 int get_sha1_treeish(const char *name, unsigned char *sha1)
 {
struct object_context unused;
@@ -1238,6 +1248,11 @@ int get_sha1_treeish(const char *name, unsigned char 
*sha1)
 sha1, );
 }
 
+int get_oid_treeish(const char *name, struct object_id *oid)
+{
+   return get_sha1_treeish(name, oid->hash);
+}
+
 int get_sha1_commit(const char *name, unsigned char *sha1)
 {
struct object_context unused;
@@ -1245,6 +1260,11 @@ int get_sha1_commit(const char *name, unsigned char 
*sha1)
 sha1, );
 }
 
+int get_oid_commit(const char *name, struct object_id *oid)
+{
+   return get_sha1_commit(name, oid->hash);
+}
+
 int get_sha1_tree(const char *name, unsigned char *sha1)
 {
struct object_context unused;
@@ -1252,6 +1272,11 @@ int get_sha1_tree(const char *name, unsigned char *sha1)
 sha1, );
 }
 
+int get_oid_tree(const char *name, struct object_id *oid)
+{
+   return get_sha1_tree(name, oid->hash);
+}
+
 int get_sha1_blob(const char *name, unsigned char *sha1)
 {
struct object_context unused;
@@ -1259,6 +1284,11 @@ int get_sha1_blob(const char *name, unsigned char *sha1)
 sha1, );
 }
 
+int get_oid_blob(const char *name, struct object_id *oid)
+{
+   return get_sha1_blob(name, oid->hash);
+}
+
 /* Must be called only when object_name:filename doesn't exist. */
 static void diagnose_invalid_sha1_path(const char *prefix,
   const char *filename,
-- 
2.7.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/RFC/GSoC 00/17] A barebones git-rebase in C

2016-03-12 Thread Paul Tan
Hi all,

Last year I rewrote git-am from shell script to C. This succeeded in speeding
up a non-interactive git-rebase by 6-7x[1], which is really handly when rebasing
multiple topic branches.

[1] http://thread.gmane.org/gmane.comp.version-control.git/271967

However, it turns out that when working on a topic branch, I frequently use
interactive rebase instead to edit and squash commits. Unfortunately, as
git-rebase--interactive.sh is still a shell script, it is a bit slower (e.g.
taking a few seconds longer compared to non-interactive rebase when rebasing
big topic branches).

The situation is much worse on Windows, as from the invocation of git rebase -i,
it takes a few seconds before the editor even pops up, and the actual
rebase proceeds at a snails pace, taking around 3 minutes for a 50-patch
series, which is a huge deal-breaker since my workflow depends on frequent
commits and squashes.

As such, this year I would like to apply for GSoC to work on a rewrite of
git-rebase to C. It is slightly hefty, as there are three backends (am, merge
and interactive), along with the git-rebase.sh script.

To get a gauge of how much code is needed for the rewrite, I explored rewriting
the scripts into C, and then extracted some bits out and polished them a bit to
make a barebones git-rebase in C, creating this patch series:

[01/17] perf: introduce performance tests for git-rebase

A simple performance test for the three rebase backends so we can compare this
C version and the shell version below.

[02/17] sha1_name: implement get_oid() and friends
[03/17] builtin-rebase: implement skeletal builtin rebase
[04/17] builtin-rebase: parse rebase arguments into a common rebase_options 
struct
[05/17] rebase-options: implement rebase_options_load() and 
rebase_options_save()

The three rebase backends (am, merge, interactive) have vastly different
capabilities, so I did not try to shoehorn them into the same interface.
However, they do share a few common options and functionality, so I introduced
the common rebase-common.c library and rebase_options struct.

In the above patches we implement the essential arguments for a rebase: the
upstream, branch_name and --onto .

[06/17] rebase-am: introduce am backend for builtin rebase

This patch implements a barebones rebase-am backend.

[07/17] rebase-common: implement refresh_and_write_cache()
[08/17] rebase-common: let refresh_and_write_cache() take a flags argument
[09/17] rebase-common: implement cache_has_unstaged_changes()
[10/17] rebase-common: implement cache_has_uncommitted_changes()
[11/17] rebase-merge: introduce merge backend for builtin rebase

These patches implement a barebones rebase-merge backend.

[12/17] rebase-todo: introduce rebase_todo_item
[13/17] rebase-todo: introduce rebase_todo_list
[14/17] status: use rebase_todo_list
[15/17] wrapper: implement append_file()
[16/17] editor: implement git_sequence_editor() and launch_sequence_editor()
[17/17] rebase-interactive: introduce interactive backend for builtin rebase

And these patches implement a barebones rebase-interactive backend.

With these patches the performance numbers when rebasing 50 commits on the
git.git repository are, on Linux,

Before patch series:

Test   this tree
--
3400.2: rebase --onto master^  1.10(0.84+0.06)
3402.2: rebase -m --onto master^   2.38(1.38+0.13)
3404.2: rebase -i --onto master^   3.11(1.37+0.27)

After patch series:

Test   this tree
--
3400.2: rebase --onto master^  0.74(0.51+0.08)
3402.2: rebase -m --onto master^   1.72(1.26+0.17)
3404.2: rebase -i --onto master^   1.74(1.20+0.18)

And on Windows,

Before patch series:

Test   this tree

3400.2: rebase --onto master^  10.90(0.06+0.47)
3402.2: rebase -m --onto master^   86.87(0.04+0.47)
3404.2: rebase -i --onto master^   191.65(0.09+0.44)

After patch series:

Test   this tree
---
3400.2: rebase --onto master^  6.45(0.13+0.40)
3402.2: rebase -m --onto master^   12.32(0.13+0.40)
3404.2: rebase -i --onto master^   14.16(0.15+0.40)

(Thanks to the git-am rewrite, non-interactive rebase on Windows is already
relatively fast ;-) )

So, we have around a 1.4x-1.8x speedup for Linux users, and a 1.7x-13x speedup
for Windows users. The annoying long delay before the interactive editor is
launched on Windows is gotten rid of, which I'm very happy about :-)

On the code side, we do get some nice things with a rewrite to C. For example,
we get the rebase-todo library for parsing and writing git-rebase-todo files,
which means that wt-status.c and rebase-interactive.c can share the same
parsing code. Although not in this patch series, rebase-interactive.c can also
now share the same author-script parsing and writing 

[PATCH/RFC/GSoC 01/17] perf: introduce performance tests for git-rebase

2016-03-12 Thread Paul Tan
To determine the speedup (or slowdown) of the upcoming git-rebase
rewrite to C, add a simple performance test for each of the 3 git-rebase
backends (am, merge and interactive).

Signed-off-by: Paul Tan 
---
 t/perf/p3400-rebase.sh | 25 +
 t/perf/p3402-rebase-merge.sh   | 25 +
 t/perf/p3404-rebase-interactive.sh | 26 ++
 3 files changed, 76 insertions(+)
 create mode 100755 t/perf/p3400-rebase.sh
 create mode 100755 t/perf/p3402-rebase-merge.sh
 create mode 100755 t/perf/p3404-rebase-interactive.sh

diff --git a/t/perf/p3400-rebase.sh b/t/perf/p3400-rebase.sh
new file mode 100755
index 000..f172a64
--- /dev/null
+++ b/t/perf/p3400-rebase.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+test_description="Tests rebase performance with am backend"
+
+. ./perf-lib.sh
+
+test_perf_default_repo
+test_checkout_worktree
+
+# Setup a topic branch with 50 commits
+test_expect_success 'setup topic branch' '
+   git checkout -b perf-topic-branch master &&
+   for i in $(test_seq 50); do
+   test_commit perf-$i file
+   done &&
+   git tag perf-topic-branch-initial
+'
+
+test_perf 'rebase --onto master^' '
+   git checkout perf-topic-branch &&
+   git reset --hard perf-topic-branch-initial &&
+   git rebase --onto master^ master
+'
+
+test_done
diff --git a/t/perf/p3402-rebase-merge.sh b/t/perf/p3402-rebase-merge.sh
new file mode 100755
index 000..b71ce12
--- /dev/null
+++ b/t/perf/p3402-rebase-merge.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+test_description="Tests rebase performance with merge backend"
+
+. ./perf-lib.sh
+
+test_perf_default_repo
+test_checkout_worktree
+
+# Setup a topic branch with 50 commits
+test_expect_success 'setup topic branch' '
+   git checkout -b perf-topic-branch master &&
+   for i in $(test_seq 50); do
+   test_commit perf-$i file
+   done &&
+   git tag perf-topic-branch-initial
+'
+
+test_perf 'rebase -m --onto master^' '
+   git checkout perf-topic-branch &&
+   git reset --hard perf-topic-branch-initial &&
+   git rebase -m --onto master^ master
+'
+
+test_done
diff --git a/t/perf/p3404-rebase-interactive.sh 
b/t/perf/p3404-rebase-interactive.sh
new file mode 100755
index 000..aaca105
--- /dev/null
+++ b/t/perf/p3404-rebase-interactive.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+test_description="Tests interactive rebase performance"
+
+. ./perf-lib.sh
+. "$TEST_DIRECTORY"/lib-rebase.sh
+
+test_perf_default_repo
+test_checkout_worktree
+
+# Setup a topic branch with 50 commits
+test_expect_success 'setup topic branch' '
+   git checkout -b perf-topic-branch master &&
+   for i in $(test_seq 50); do
+   test_commit perf-$i file
+   done &&
+   git tag perf-topic-branch-initial
+'
+
+test_perf 'rebase -i --onto master^' '
+   git checkout perf-topic-branch &&
+   git reset --hard perf-topic-branch-initial &&
+   GIT_SEQUENCE_EDITOR=: git rebase -i --onto master^ master
+'
+
+test_done
-- 
2.7.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: [ANNOUNCE] Git v2.8.0-rc2

2016-03-12 Thread Max Horn

> On 11 Mar 2016, at 00:04, Junio C Hamano  wrote:
> 
> A release candidate Git v2.8.0-rc2 is now available for testing
> at the usual places.  It is comprised of 459 non-merge commits
> since v2.7.0, contributed by 60 people, 19 of which are new faces.
> 
[...]

> Updates since v2.7
> --
> 
> UI, Workflows & Features
> 
> * It turns out "git clone" over rsync transport has been broken when
>   the source repository has packed references for a long time, and
>   nobody noticed nor complained about it.
> 
> * "branch --delete" has "branch -d" but "push --delete" does not.

This states a problem, but not whether (and how) it was resolved?

[...]

> * Across the transition at around Git version 2.0, the user used to
>   get a pretty loud warning when running "git push" without setting
>   push.default configuration variable.  We no longer warn, given that
>   the transition is over long time ago.

That last sentence sounds weird... perhaps "the transition was completed a long 
time ago" ? Or "the transition ended a long time ago" ?

> 
> * README has been renamed to README.md and its contents got tweaked
>   slightly to make it easier on the eyes.
> 
> 
> Performance, Internal Implementation, Development Support etc.
> 
> * Add a framework to spawn a group of processes in parallel, and use
>   it to run "git fetch --recurse-submodules" in parallel.
> 
> * A slight update to the Makefile to mark "phoney" targets
>   as such correctly.

phoney -> phony ? (it seems in british english you can write "phoney", but 
according to a quickly Google search this is rarely used in relation to 
Makefiles; no surprise, given that the corresponding syntax element is ".PHONY" 
and you are not allowed to spell it differently ;-)

[...]

> 
> * Some calls to strcpy(3) triggers a false warning from static
>   analysers that are less intelligent than humans, and reducing the
>   number of these false hits helps us notice real issues.  A few
>   calls to strcpy(3) in test-path-utils that are already safe has
>   been rewritten to avoid false wanings.
> 
> * Some calls to strcpy(3) triggers a false warning from static
>   analysers that are less intelligent than humans, and reducing the
>   number of these false hits helps us notice real issues.  A few
>   calls to strcpy(3) in "git rerere" that are already safe has been
>   rewritten to avoid false wanings.

The above two messages are very similar, only the end differs a bit. Perhaps
merge them into one? I.e.. "A few calls to strcpy(3) in test-path-utils and 
"git rerere" that [...]"

Also: wanings -> warnings

[...]

> 
> * Asking gitweb for a nonexistent commit left a warning in the server
>   log.
> 
>   Somebody may want to follow this up with an additional test, perhaps?
>   IIRC, we do test that no Perl warnings are given to the server log,
>   so this should have been caught if our test coverage were good.

That last paragraph seems odd for a changelog?

[...]

> * The underlying machinery used by "ls-files -o" and other commands
>   have been taught not to create empty submodule ref cache for a

have -> has (the machinery is singular)





Cheers,
Max--
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