* [PATCH/RFC 0/6] commit caching
From: Jeff King @ 2013-01-29 9:14 UTC (permalink / raw)
To: git; +Cc: Duy Nguyen, Shawn O. Pearce
This is the cleaned-up version of the commit caching patches I mentioned
here:
http://article.gmane.org/gmane.comp.version-control.git/212329
The basic idea is to generate a cache file that sits alongside a
packfile and contains the timestamp, tree, and parents in a more compact
and easy-to-access format.
The timings from this one are roughly similar to what I posted earlier.
Unlike the earlier version, this one keeps the data for a single commit
together for better cache locality (though I don't think it made a big
difference in my tests, since my cold-cache timing test ends up touching
every commit anyway). The short of it is that for an extra 31M of disk
space (~4%), I get a warm-cache speedup for "git rev-list --all" of
~4.2s to ~0.66s.
The big thing it does not (yet) do is use offsets to reference sha1s, as
Shawn suggested. This would potentially drop the on-disk size from 84
bytes to 16 bytes per commit (or about 6M total for linux.git).
Coupled with using compression level 0 for trees (which do not compress
well at all, and yield only a 2% increase in size when left
uncompressed), my "git rev-list --objects --all" time drops from ~40s to
~25s. Perf reveals that we're spending most of the remaining time in
lookup_object. I've spent a fair bit of time trying to optimize that,
but with no luck; I think it's fairly close to optimal. The problem is
just that we call it a very large number of times, since it is the
mechanism by which we recognize that we have already processed each
sha1.
[1/6]: csum-file: make sha1write const-correct
[2/6]: strbuf: add string-chomping functions
[3/6]: introduce pack metadata cache files
[4/6]: introduce a commit metapack
[5/6]: add git-metapack command
[6/6]: commit: look up commit info in metapack
-Peff
^ permalink raw reply
* [PATCH 1/6] csum-file: make sha1write const-correct
From: Jeff King @ 2013-01-29 9:15 UTC (permalink / raw)
To: git; +Cc: Duy Nguyen, Shawn O. Pearce
In-Reply-To: <20130129091434.GA6975@sigill.intra.peff.net>
We do not modify the buffer we are asked to write; mark it
with const so that callers with const buffers do not get
unnecessary complaints from the compiler.
Signed-off-by: Jeff King <peff@peff.net>
---
csum-file.c | 6 +++---
csum-file.h | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/csum-file.c b/csum-file.c
index 53f5375..465971c 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -11,7 +11,7 @@
#include "progress.h"
#include "csum-file.h"
-static void flush(struct sha1file *f, void *buf, unsigned int count)
+static void flush(struct sha1file *f, const void *buf, unsigned int count)
{
if (0 <= f->check_fd && count) {
unsigned char check_buffer[8192];
@@ -86,13 +86,13 @@ int sha1write(struct sha1file *f, void *buf, unsigned int count)
return fd;
}
-int sha1write(struct sha1file *f, void *buf, unsigned int count)
+int sha1write(struct sha1file *f, const void *buf, unsigned int count)
{
while (count) {
unsigned offset = f->offset;
unsigned left = sizeof(f->buffer) - offset;
unsigned nr = count > left ? left : count;
- void *data;
+ const void *data;
if (f->do_crc)
f->crc32 = crc32(f->crc32, buf, nr);
diff --git a/csum-file.h b/csum-file.h
index 3b540bd..9dedb03 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -34,7 +34,7 @@ extern int sha1close(struct sha1file *, unsigned char *, unsigned int);
extern struct sha1file *sha1fd_check(const char *name);
extern struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp);
extern int sha1close(struct sha1file *, unsigned char *, unsigned int);
-extern int sha1write(struct sha1file *, void *, unsigned int);
+extern int sha1write(struct sha1file *, const void *, unsigned int);
extern void sha1flush(struct sha1file *f);
extern void crc32_begin(struct sha1file *);
extern uint32_t crc32_end(struct sha1file *);
--
1.8.0.2.16.g72e2fc9
^ permalink raw reply related
* [PATCH 2/6] strbuf: add string-chomping functions
From: Jeff King @ 2013-01-29 9:15 UTC (permalink / raw)
To: git; +Cc: Duy Nguyen, Shawn O. Pearce
In-Reply-To: <20130129091434.GA6975@sigill.intra.peff.net>
Sometimes it is handy to cut a trailing string off the end
of a strbuf (e.g., a file extension). These helper functions
make it a one-liner.
Signed-off-by: Jeff King <peff@peff.net>
---
strbuf.c | 11 +++++++++++
strbuf.h | 2 ++
2 files changed, 13 insertions(+)
diff --git a/strbuf.c b/strbuf.c
index 9a373be..8199ced 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -106,6 +106,17 @@ void strbuf_ltrim(struct strbuf *sb)
sb->buf[sb->len] = '\0';
}
+void strbuf_chompmem(struct strbuf *sb, const void *data, size_t len)
+{
+ if (sb->len >= len && !memcmp(data, sb->buf + sb->len - len, len))
+ strbuf_setlen(sb, sb->len - len);
+}
+
+void strbuf_chompstr(struct strbuf *sb, const char *str)
+{
+ strbuf_chompmem(sb, str, strlen(str));
+}
+
struct strbuf **strbuf_split_buf(const char *str, size_t slen,
int terminator, int max)
{
diff --git a/strbuf.h b/strbuf.h
index ecae4e2..3aeb815 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -42,6 +42,8 @@ extern void strbuf_ltrim(struct strbuf *);
extern void strbuf_trim(struct strbuf *);
extern void strbuf_rtrim(struct strbuf *);
extern void strbuf_ltrim(struct strbuf *);
+extern void strbuf_chompmem(struct strbuf *, const void *, size_t);
+extern void strbuf_chompstr(struct strbuf *, const char *);
extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
/*
--
1.8.0.2.16.g72e2fc9
^ permalink raw reply related
* [PATCH 3/6] introduce pack metadata cache files
From: Jeff King @ 2013-01-29 9:15 UTC (permalink / raw)
To: git; +Cc: Duy Nguyen, Shawn O. Pearce
In-Reply-To: <20130129091434.GA6975@sigill.intra.peff.net>
The on-disk packfile format is nicely compact, but it does
not always provide the fastest format for looking up
information. This patch introduces the concept of
"metapacks", optional metadata files which can live
alongside packs and represent their data in different ways.
This can allow space-time tradeoffs in accessing certain
object data.
Such space-time tradeoffs have traditionally gone into the
.idx file (e.g., the fact that we can quickly find an
object's offset in the packfile is due to the index). In
theory, cached data could also go into the .idx file.
However, keeping it in a separate file makes backwards
compatibility much simpler. Older versions of git can simply
ignore the extra files and use the existing methods for
accessing object data. This also makes metapacks optional,
so you can easily tune the space-time tradeoff on a per-repo
basis.
TODO: document on-disk format in Documentation/technical
TODO: document api
Signed-off-by: Jeff King <peff@peff.net>
---
Makefile | 2 +
metapack.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
metapack.h | 42 ++++++++++++++++
3 files changed, 202 insertions(+)
create mode 100644 metapack.c
create mode 100644 metapack.h
diff --git a/Makefile b/Makefile
index 731b6a8..3e4ae1b 100644
--- a/Makefile
+++ b/Makefile
@@ -660,6 +660,7 @@ LIB_H += mergesort.h
LIB_H += merge-blobs.h
LIB_H += merge-recursive.h
LIB_H += mergesort.h
+LIB_H += metapack.h
LIB_H += notes-cache.h
LIB_H += notes-merge.h
LIB_H += notes.h
@@ -778,6 +779,7 @@ LIB_OBJS += mergesort.o
LIB_OBJS += merge-blobs.o
LIB_OBJS += merge-recursive.o
LIB_OBJS += mergesort.o
+LIB_OBJS += metapack.o
LIB_OBJS += name-hash.o
LIB_OBJS += notes.o
LIB_OBJS += notes-cache.o
diff --git a/metapack.c b/metapack.c
new file mode 100644
index 0000000..c859c95
--- /dev/null
+++ b/metapack.c
@@ -0,0 +1,158 @@
+#include "cache.h"
+#include "metapack.h"
+#include "csum-file.h"
+
+static struct sha1file *create_meta_tmp(void)
+{
+ char tmp[PATH_MAX];
+ int fd;
+
+ fd = odb_mkstemp(tmp, sizeof(tmp), "pack/tmp_meta_XXXXXX");
+ return sha1fd(fd, xstrdup(tmp));
+}
+
+static void write_meta_header(struct metapack_writer *mw, const char *id,
+ uint32_t version)
+{
+ version = htonl(version);
+
+ sha1write(mw->out, "META", 4);
+ sha1write(mw->out, "\0\0\0\1", 4);
+ sha1write(mw->out, mw->pack->sha1, 20);
+ sha1write(mw->out, id, 4);
+ sha1write(mw->out, &version, 4);
+}
+
+void metapack_writer_init(struct metapack_writer *mw,
+ const char *pack_idx,
+ const char *name,
+ int version)
+{
+ struct strbuf path = STRBUF_INIT;
+
+ memset(mw, 0, sizeof(*mw));
+
+ mw->pack = add_packed_git(pack_idx, strlen(pack_idx), 1);
+ if (!mw->pack || open_pack_index(mw->pack))
+ die("unable to open packfile '%s'", pack_idx);
+
+ strbuf_addstr(&path, pack_idx);
+ strbuf_chompstr(&path, ".idx");
+ strbuf_addch(&path, '.');
+ strbuf_addstr(&path, name);
+ mw->path = strbuf_detach(&path, NULL);
+
+ mw->out = create_meta_tmp();
+ write_meta_header(mw, name, version);
+}
+
+void metapack_writer_finish(struct metapack_writer *mw)
+{
+ const char *tmp = mw->out->name;
+
+ sha1close(mw->out, NULL, CSUM_FSYNC);
+ if (rename(tmp, mw->path))
+ die_errno("unable to rename temporary metapack file");
+
+ close_pack_index(mw->pack);
+ free(mw->pack);
+ free(mw->path);
+ free((char *)tmp);
+}
+
+void metapack_writer_add(struct metapack_writer *mw, const void *data, int len)
+{
+ sha1write(mw->out, data, len);
+}
+
+void metapack_writer_add_uint32(struct metapack_writer *mw, uint32_t v)
+{
+ v = htonl(v);
+ metapack_writer_add(mw, &v, 4);
+}
+
+void metapack_writer_foreach(struct metapack_writer *mw,
+ metapack_writer_each_fn cb,
+ void *data)
+{
+ const unsigned char *sha1;
+ uint32_t i = 0;
+
+ /*
+ * We'll feed these to the callback in sorted order, since that is the
+ * order that they are stored in the .idx file.
+ */
+ while ((sha1 = nth_packed_object_sha1(mw->pack, i++)))
+ cb(mw, sha1, data);
+}
+
+int metapack_init(struct metapack *m,
+ struct packed_git *pack,
+ const char *name,
+ uint32_t *version)
+{
+ struct strbuf path = STRBUF_INIT;
+ int fd;
+ struct stat st;
+
+ memset(m, 0, sizeof(*m));
+
+ strbuf_addstr(&path, pack->pack_name);
+ strbuf_chompstr(&path, ".pack");
+ strbuf_addch(&path, '.');
+ strbuf_addstr(&path, name);
+
+ fd = open(path.buf, O_RDONLY);
+ strbuf_release(&path);
+ if (fd < 0)
+ return -1;
+ if (fstat(fd, &st) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ m->mapped_len = xsize_t(st.st_size);
+ m->mapped_buf = xmmap(NULL, m->mapped_len, PROT_READ, MAP_PRIVATE, fd, 0);
+ close(fd);
+
+ m->data = m->mapped_buf;
+ m->len = m->mapped_len;
+
+ if (m->len < 8 ||
+ memcmp(m->mapped_buf, "META", 4) ||
+ memcmp(m->mapped_buf + 4, "\0\0\0\1", 4)) {
+ warning("metapack '%s' for '%s' does not have a valid header",
+ name, pack->pack_name);
+ metapack_close(m);
+ return -1;
+ }
+ m->data += 8;
+ m->len -= 8;
+
+ if (m->len < 20 || hashcmp(m->data, pack->sha1)) {
+ warning("metapack '%s' for '%s' does not match pack sha1",
+ name, pack->pack_name);
+ metapack_close(m);
+ return -1;
+ }
+ m->data += 20;
+ m->len -= 20;
+
+ if (m->len < 8 || memcmp(m->data, name, 4)) {
+ warning("metapack '%s' for '%s' does not have expected header id",
+ name, pack->pack_name);
+ metapack_close(m);
+ return -1;
+ }
+ memcpy(version, m->data + 4, 4);
+ *version = ntohl(*version);
+ m->data += 8;
+ m->len -= 8;
+
+ return 0;
+}
+
+void metapack_close(struct metapack *m)
+{
+ munmap(m->mapped_buf, m->mapped_len);
+}
diff --git a/metapack.h b/metapack.h
new file mode 100644
index 0000000..6af17fe
--- /dev/null
+++ b/metapack.h
@@ -0,0 +1,42 @@
+#ifndef METAPACK_H
+#define METAPACK_H
+
+struct packed_git;
+struct sha1file;
+
+struct metapack_writer {
+ char *path;
+ struct packed_git *pack;
+ struct sha1file *out;
+};
+
+void metapack_writer_init(struct metapack_writer *mw,
+ const char *pack_idx,
+ const char *name,
+ int version);
+void metapack_writer_add(struct metapack_writer *mw, const void *data, int len);
+void metapack_writer_add_uint32(struct metapack_writer *mw, uint32_t v);
+void metapack_writer_finish(struct metapack_writer *mw);
+
+typedef void (*metapack_writer_each_fn)(struct metapack_writer *,
+ const unsigned char *sha1,
+ void *data);
+void metapack_writer_foreach(struct metapack_writer *mw,
+ metapack_writer_each_fn cb,
+ void *data);
+
+struct metapack {
+ void *mapped_buf;
+ size_t mapped_len;
+
+ void *data;
+ size_t len;
+};
+
+int metapack_init(struct metapack *m,
+ struct packed_git *pack,
+ const char *name,
+ uint32_t *version);
+void metapack_close(struct metapack *m);
+
+#endif
--
1.8.0.2.16.g72e2fc9
^ permalink raw reply related
* [PATCH 4/6] introduce a commit metapack
From: Jeff King @ 2013-01-29 9:16 UTC (permalink / raw)
To: git; +Cc: Duy Nguyen, Shawn O. Pearce
In-Reply-To: <20130129091434.GA6975@sigill.intra.peff.net>
When we are doing a commit traversal that does not need to
look at the commit messages themselves (e.g., rev-list,
merge-base, etc), we spend a lot of time accessing,
decompressing, and parsing the commit objects just to find
the parent and timestamp information. We can make a
space-time tradeoff by caching that information on disk in a
compact, uncompressed format.
TODO: document on-disk format in Documentation/technical
TODO: document API
Signed-off-by: Jeff King <peff@peff.net>
---
Makefile | 2 +
commit-metapack.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
commit-metapack.h | 12 ++++
3 files changed, 189 insertions(+)
create mode 100644 commit-metapack.c
create mode 100644 commit-metapack.h
diff --git a/Makefile b/Makefile
index 3e4ae1b..6ca5320 100644
--- a/Makefile
+++ b/Makefile
@@ -619,6 +619,7 @@ LIB_H += column.h
LIB_H += cache.h
LIB_H += color.h
LIB_H += column.h
+LIB_H += commit-metapack.h
LIB_H += commit.h
LIB_H += compat/bswap.h
LIB_H += compat/cygwin.h
@@ -730,6 +731,7 @@ LIB_OBJS += combine-diff.o
LIB_OBJS += color.o
LIB_OBJS += column.o
LIB_OBJS += combine-diff.o
+LIB_OBJS += commit-metapack.o
LIB_OBJS += commit.o
LIB_OBJS += compat/obstack.o
LIB_OBJS += compat/terminal.o
diff --git a/commit-metapack.c b/commit-metapack.c
new file mode 100644
index 0000000..2c19f48
--- /dev/null
+++ b/commit-metapack.c
@@ -0,0 +1,175 @@
+#include "cache.h"
+#include "commit-metapack.h"
+#include "metapack.h"
+#include "commit.h"
+#include "sha1-lookup.h"
+
+struct commit_metapack {
+ struct metapack mp;
+ uint32_t nr;
+ unsigned char *index;
+ unsigned char *data;
+ struct commit_metapack *next;
+};
+static struct commit_metapack *commit_metapacks;
+
+static struct commit_metapack *alloc_commit_metapack(struct packed_git *pack)
+{
+ struct commit_metapack *it = xcalloc(1, sizeof(*it));
+ uint32_t version;
+
+ if (metapack_init(&it->mp, pack, "commits", &version) < 0) {
+ free(it);
+ return NULL;
+ }
+ if (version != 1) {
+ /*
+ * This file comes from a more recent git version. Don't bother
+ * warning the user, as we'll just fallback to reading the
+ * commits.
+ */
+ metapack_close(&it->mp);
+ free(it);
+ return NULL;
+ }
+
+ if (it->mp.len < 4) {
+ warning("commit metapack for '%s' is truncated", pack->pack_name);
+ metapack_close(&it->mp);
+ free(it);
+ return NULL;
+ }
+ memcpy(&it->nr, it->mp.data, 4);
+ it->nr = ntohl(it->nr);
+
+ /*
+ * We need 84 bytes for each entry: sha1(20), date(4), tree(20),
+ * parents(40).
+ */
+ if (it->mp.len < (84 * it->nr + 4)) {
+ warning("commit metapack for '%s' is truncated", pack->pack_name);
+ metapack_close(&it->mp);
+ free(it);
+ return NULL;
+ }
+
+ it->index = it->mp.data + 4;
+ it->data = it->index + 20 * it->nr;
+
+ return it;
+}
+
+static void prepare_commit_metapacks(void)
+{
+ static int initialized;
+ struct commit_metapack **tail = &commit_metapacks;
+ struct packed_git *p;
+
+ if (initialized)
+ return;
+
+ prepare_packed_git();
+ for (p = packed_git; p; p = p->next) {
+ struct commit_metapack *it = alloc_commit_metapack(p);
+
+ if (it) {
+ *tail = it;
+ tail = &it->next;
+ }
+ }
+
+ initialized = 1;
+}
+
+int commit_metapack(unsigned char *sha1,
+ uint32_t *timestamp,
+ unsigned char **tree,
+ unsigned char **parent1,
+ unsigned char **parent2)
+{
+ struct commit_metapack *p;
+
+ prepare_commit_metapacks();
+ for (p = commit_metapacks; p; p = p->next) {
+ unsigned char *data;
+ int pos = sha1_entry_pos(p->index, 20, 0, 0, p->nr, p->nr, sha1);
+ if (pos < 0)
+ continue;
+
+ /* timestamp(4) + tree(20) + parents(40) */
+ data = p->data + 64 * pos;
+ *timestamp = *(uint32_t *)data;
+ *timestamp = ntohl(*timestamp);
+ data += 4;
+ *tree = data;
+ data += 20;
+ *parent1 = data;
+ data += 20;
+ *parent2 = data;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+static void get_commits(struct metapack_writer *mw,
+ const unsigned char *sha1,
+ void *data)
+{
+ struct commit_list ***tail = data;
+ enum object_type type = sha1_object_info(sha1, NULL);
+ struct commit *c;
+
+ if (type != OBJ_COMMIT)
+ return;
+
+ c = lookup_commit(sha1);
+ if (!c || parse_commit(c))
+ die("unable to read commit %s", sha1_to_hex(sha1));
+
+ /*
+ * Our fixed-size parent list cannot represent root commits, nor
+ * octopus merges. Just skip those commits, as we can fallback
+ * in those rare cases to reading the actual commit object.
+ */
+ if (!c->parents ||
+ (c->parents && c->parents->next && c->parents->next->next))
+ return;
+
+ *tail = &commit_list_insert(c, *tail)->next;
+}
+
+void commit_metapack_write(const char *idx)
+{
+ struct metapack_writer mw;
+ struct commit_list *commits = NULL, *p;
+ struct commit_list **tail = &commits;
+ uint32_t nr = 0;
+
+ metapack_writer_init(&mw, idx, "commits", 1);
+
+ /* Figure out how many eligible commits we've got in this pack. */
+ metapack_writer_foreach(&mw, get_commits, &tail);
+ for (p = commits; p; p = p->next)
+ nr++;
+ metapack_writer_add_uint32(&mw, nr);
+
+ /* Then write an index of commit sha1s */
+ for (p = commits; p; p = p->next)
+ metapack_writer_add(&mw, p->item->object.sha1, 20);
+
+ /* Followed by the actual date/tree/parents data */
+ for (p = commits; p; p = p->next) {
+ struct commit *c = p->item;
+ metapack_writer_add_uint32(&mw, c->date);
+ metapack_writer_add(&mw, c->tree->object.sha1, 20);
+ metapack_writer_add(&mw, c->parents->item->object.sha1, 20);
+ metapack_writer_add(&mw,
+ c->parents->next ?
+ c->parents->next->item->object.sha1 :
+ null_sha1, 20);
+ }
+
+ metapack_writer_finish(&mw);
+}
diff --git a/commit-metapack.h b/commit-metapack.h
new file mode 100644
index 0000000..4684573
--- /dev/null
+++ b/commit-metapack.h
@@ -0,0 +1,12 @@
+#ifndef METAPACK_COMMIT_H
+#define METAPACK_COMMIT_H
+
+int commit_metapack(unsigned char *sha1,
+ uint32_t *timestamp,
+ unsigned char **tree,
+ unsigned char **parent1,
+ unsigned char **parent2);
+
+void commit_metapack_write(const char *idx_file);
+
+#endif
--
1.8.0.2.16.g72e2fc9
^ permalink raw reply related
* [PATCH 5/6] add git-metapack command
From: Jeff King @ 2013-01-29 9:16 UTC (permalink / raw)
To: git; +Cc: Duy Nguyen, Shawn O. Pearce
In-Reply-To: <20130129091434.GA6975@sigill.intra.peff.net>
This is a plumbing command for generating metapack files.
Right now it understands only the "commits" metapack (and
there is not yet a reader). Eventually we may want to build
this metapack automatically when we generate a new pack.
Let's be conservative for now, though, and let the idea
prove itself in practice before turning it on for everyone.
The commits metapack generated by this command is 84 bytes
per commit; for linux-2.6.git, this is about 31M.
TODO: documentation
Signed-off-by: Jeff King <peff@peff.net>
---
.gitignore | 1 +
Makefile | 1 +
builtin.h | 1 +
builtin/metapack.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
git-repack.sh | 2 +-
git.c | 1 +
6 files changed, 78 insertions(+), 1 deletion(-)
create mode 100644 builtin/metapack.c
diff --git a/.gitignore b/.gitignore
index 6669bf0..3f67a36 100644
--- a/.gitignore
+++ b/.gitignore
@@ -93,6 +93,7 @@
/git-merge-subtree
/git-mergetool
/git-mergetool--lib
+/git-metapack
/git-mktag
/git-mktree
/git-name-rev
diff --git a/Makefile b/Makefile
index 6ca5320..3899699 100644
--- a/Makefile
+++ b/Makefile
@@ -905,6 +905,7 @@ BUILTIN_OBJS += builtin/merge-tree.o
BUILTIN_OBJS += builtin/merge-ours.o
BUILTIN_OBJS += builtin/merge-recursive.o
BUILTIN_OBJS += builtin/merge-tree.o
+BUILTIN_OBJS += builtin/metapack.o
BUILTIN_OBJS += builtin/mktag.o
BUILTIN_OBJS += builtin/mktree.o
BUILTIN_OBJS += builtin/mv.o
diff --git a/builtin.h b/builtin.h
index faef559..30108ab 100644
--- a/builtin.h
+++ b/builtin.h
@@ -97,6 +97,7 @@ extern int cmd_merge_tree(int argc, const char **argv, const char *prefix);
extern int cmd_merge_file(int argc, const char **argv, const char *prefix);
extern int cmd_merge_recursive(int argc, const char **argv, const char *prefix);
extern int cmd_merge_tree(int argc, const char **argv, const char *prefix);
+extern int cmd_metapack(int argc, const char **argv, const char *prefix);
extern int cmd_mktag(int argc, const char **argv, const char *prefix);
extern int cmd_mktree(int argc, const char **argv, const char *prefix);
extern int cmd_mv(int argc, const char **argv, const char *prefix);
diff --git a/builtin/metapack.c b/builtin/metapack.c
new file mode 100644
index 0000000..5fee6cf
--- /dev/null
+++ b/builtin/metapack.c
@@ -0,0 +1,73 @@
+#include "builtin.h"
+#include "parse-options.h"
+#include "commit-metapack.h"
+
+static const char *metapack_usage[] = {
+ N_("git metapack [options] <packindex...>"),
+ NULL
+};
+
+#define METAPACK_COMMITS (1<<0)
+
+static void metapack_one(const char *idx, int type)
+{
+ if (type & METAPACK_COMMITS)
+ commit_metapack_write(idx);
+}
+
+static void metapack_all(int type)
+{
+ struct strbuf path = STRBUF_INIT;
+ size_t dirlen;
+ DIR *dh;
+ struct dirent *de;
+
+ strbuf_addstr(&path, get_object_directory());
+ strbuf_addstr(&path, "/pack");
+ dirlen = path.len;
+
+ dh = opendir(path.buf);
+ if (!dh)
+ die_errno("unable to open pack directory '%s'", path.buf);
+ while ((de = readdir(dh))) {
+ if (!has_extension(de->d_name, ".idx"))
+ continue;
+
+ strbuf_addch(&path, '/');
+ strbuf_addstr(&path, de->d_name);
+ metapack_one(path.buf, type);
+ strbuf_setlen(&path, dirlen);
+ }
+
+ closedir(dh);
+ strbuf_release(&path);
+}
+
+int cmd_metapack(int argc, const char **argv, const char *prefix)
+{
+ int all = 0;
+ int type = 0;
+ struct option opts[] = {
+ OPT_BOOL(0, "all", &all, N_("create metapacks for all packs")),
+ OPT_BIT(0, "commits", &type, N_("create commit metapacks"),
+ METAPACK_COMMITS),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, prefix, opts, metapack_usage, 0);
+
+ if (all && argc)
+ usage_msg_opt(_("pack arguments do not make sense with --all"),
+ metapack_usage, opts);
+ if (!type)
+ usage_msg_opt(_("no metapack type specified"),
+ metapack_usage, opts);
+
+ if (all)
+ metapack_all(type);
+ else
+ for (; *argv; argv++)
+ metapack_one(*argv, type);
+
+ return 0;
+}
diff --git a/git-repack.sh b/git-repack.sh
index 7579331..e6a9773 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -180,7 +180,7 @@ then
do
case " $fullbases " in
*" $e "*) ;;
- *) rm -f "$e.pack" "$e.idx" "$e.keep" ;;
+ *) rm -f "$e.pack" "$e.idx" "$e.keep" "$e.commits";;
esac
done
)
diff --git a/git.c b/git.c
index b10c18b..f6e5552 100644
--- a/git.c
+++ b/git.c
@@ -365,6 +365,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
{ "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
{ "merge-tree", cmd_merge_tree, RUN_SETUP },
+ { "metapack", cmd_metapack, RUN_SETUP },
{ "mktag", cmd_mktag, RUN_SETUP },
{ "mktree", cmd_mktree, RUN_SETUP },
{ "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
--
1.8.0.2.16.g72e2fc9
^ permalink raw reply related
* [PATCH 6/6] commit: look up commit info in metapack
From: Jeff King @ 2013-01-29 9:16 UTC (permalink / raw)
To: git; +Cc: Duy Nguyen, Shawn O. Pearce
In-Reply-To: <20130129091434.GA6975@sigill.intra.peff.net>
Now that we have the plumbing in place to generate and read
commit metapacks, we can hook them up to parse_commit to
fill in the traversal information much more quickly.
We only do so if save_commit_buffer is turned off;
otherwise, the callers will expect to be able to read
commit->buffer after parse_commit returns (and since our
cache obviously does not have that information, we must
leave it NULL). As callers learn to handle a NULL
commit->buffer, we can eventually relax this (while it might
seem like a useless no-op to use the cache if we are going
to load the commit anyway, many callers may first filter
based on the traversal, and end up loading the commit
message for only a subset of the commits).
With this patch (and having run "git metapack --all
--commits"), my best-of-five warm-cache "git rev-list
--count --all" traversal of linux-2.6.git drops from 4.219s
to 0.659s.
Similarly, cold-cache drops from 13.696s to 4.763s due to
the compactness of the cache data (but you are penalized, of
course, if you then want to actually look at the commit
messages, since you have not warmed them into the cache).
Signed-off-by: Jeff King <peff@peff.net>
---
commit.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/commit.c b/commit.c
index e8eb0ae..b326201 100644
--- a/commit.c
+++ b/commit.c
@@ -8,6 +8,7 @@
#include "notes.h"
#include "gpg-interface.h"
#include "mergesort.h"
+#include "commit-metapack.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -306,6 +307,24 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
return 0;
}
+static int parse_commit_metapack(struct commit *item)
+{
+ unsigned char *tree, *p1, *p2;
+ uint32_t ts;
+
+ if (commit_metapack(item->object.sha1, &ts, &tree, &p1, &p2) < 0)
+ return -1;
+
+ item->date = ts;
+ item->tree = lookup_tree(tree);
+ commit_list_insert(lookup_commit(p1), &item->parents);
+ if (!is_null_sha1(p2))
+ commit_list_insert(lookup_commit(p2), &item->parents->next);
+
+ item->object.parsed = 1;
+ return 0;
+}
+
int parse_commit(struct commit *item)
{
enum object_type type;
@@ -317,6 +336,10 @@ int parse_commit(struct commit *item)
return -1;
if (item->object.parsed)
return 0;
+
+ if (!save_commit_buffer && !parse_commit_metapack(item))
+ return 0;
+
buffer = read_sha1_file(item->object.sha1, &type, &size);
if (!buffer)
return error("Could not read %s",
--
1.8.0.2.16.g72e2fc9
^ permalink raw reply related
* Re: [PATCH 2/6] strbuf: add string-chomping functions
From: Michael Haggerty @ 2013-01-29 10:15 UTC (permalink / raw)
To: Jeff King; +Cc: git, Duy Nguyen, Shawn O. Pearce
In-Reply-To: <20130129091540.GB9999@sigill.intra.peff.net>
On 01/29/2013 10:15 AM, Jeff King wrote:
> Sometimes it is handy to cut a trailing string off the end
> of a strbuf (e.g., a file extension). These helper functions
> make it a one-liner.
>
> Signed-off-by: Jeff King <peff@peff.net>
> ---
> strbuf.c | 11 +++++++++++
> strbuf.h | 2 ++
> 2 files changed, 13 insertions(+)
>
> diff --git a/strbuf.c b/strbuf.c
> index 9a373be..8199ced 100644
> --- a/strbuf.c
> +++ b/strbuf.c
> @@ -106,6 +106,17 @@ void strbuf_ltrim(struct strbuf *sb)
> sb->buf[sb->len] = '\0';
> }
>
> +void strbuf_chompmem(struct strbuf *sb, const void *data, size_t len)
> +{
> + if (sb->len >= len && !memcmp(data, sb->buf + sb->len - len, len))
> + strbuf_setlen(sb, sb->len - len);
> +}
> +
> +void strbuf_chompstr(struct strbuf *sb, const char *str)
> +{
> + strbuf_chompmem(sb, str, strlen(str));
> +}
> +
> struct strbuf **strbuf_split_buf(const char *str, size_t slen,
> int terminator, int max)
> {
> diff --git a/strbuf.h b/strbuf.h
> index ecae4e2..3aeb815 100644
> --- a/strbuf.h
> +++ b/strbuf.h
> @@ -42,6 +42,8 @@ extern void strbuf_ltrim(struct strbuf *);
> extern void strbuf_trim(struct strbuf *);
> extern void strbuf_rtrim(struct strbuf *);
> extern void strbuf_ltrim(struct strbuf *);
> +extern void strbuf_chompmem(struct strbuf *, const void *, size_t);
> +extern void strbuf_chompstr(struct strbuf *, const char *);
> extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
>
> /*
>
It might be handy to have these functions return true/false based on
whether the suffix was actually found.
Please document the new functions in
Documentation/technical/api-strbuf.txt. Personally I would also
advocate a "docstring" in the header file, but obviously that preference
is the exception rather than the rule in the git project :-(
Michael
--
Michael Haggerty
mhagger@alum.mit.edu
http://softwareswirl.blogspot.com/
^ permalink raw reply
* Re: [PATCH 4/6] introduce a commit metapack
From: Michael Haggerty @ 2013-01-29 10:24 UTC (permalink / raw)
To: Jeff King; +Cc: git, Duy Nguyen, Shawn O. Pearce
In-Reply-To: <20130129091610.GD9999@sigill.intra.peff.net>
On 01/29/2013 10:16 AM, Jeff King wrote:
> When we are doing a commit traversal that does not need to
> look at the commit messages themselves (e.g., rev-list,
> merge-base, etc), we spend a lot of time accessing,
> decompressing, and parsing the commit objects just to find
> the parent and timestamp information. We can make a
> space-time tradeoff by caching that information on disk in a
> compact, uncompressed format.
>
> TODO: document on-disk format in Documentation/technical
> TODO: document API
Would this be a good place to add the commit generation number that is
so enthusiastically discussed on the mailing list from time to time?
Michael
--
Michael Haggerty
mhagger@alum.mit.edu
http://softwareswirl.blogspot.com/
^ permalink raw reply
* [PATCH] README: fix broken mailing list archive link
From: Ramkumar Ramachandra @ 2013-01-29 10:40 UTC (permalink / raw)
To: Git List
marc.theaimsgroup.com does not exist anymore, so replace it
with a link to the archive on GMane.
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
README | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README b/README
index 49713ea..3aae16a 100644
--- a/README
+++ b/README
@@ -47,8 +47,8 @@ requests, comments and patches to git@vger.kernel.org (read
Documentation/SubmittingPatches for instructions on patch submission).
To subscribe to the list, send an email with just "subscribe git" in
the body to majordomo@vger.kernel.org. The mailing list archives are
-available at http://marc.theaimsgroup.com/?l=git and other archival
-sites.
+available at http://thread.gmane.org/gmane.comp.version-control.git/
+and other archival sites.
The messages titled "A note from the maintainer", "What's in
git.git (stable)" and "What's cooking in git.git (topics)" and
--
1.7.10.4
^ permalink raw reply related
* [PATCH] gitk-git/.gitignore: add rule for gitk-wish
From: Ramkumar Ramachandra @ 2013-01-29 10:52 UTC (permalink / raw)
To: Git List
8f26aa4 (Makefile: remove tracking of TCLTK_PATH, 2012-12-18) removed
"/gitk-git/gitk-wish" from the toplevel .gitignore, with the intent of
moving it to gitk-git/.gitignore in a later patch. This was never
realized.
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
---
Minor patch, so I didn't bother sending it through Paul.
gitk-git/.gitignore | 1 +
1 file changed, 1 insertion(+)
create mode 100644 gitk-git/.gitignore
diff --git a/gitk-git/.gitignore b/gitk-git/.gitignore
new file mode 100644
index 0000000..1dc38be
--- /dev/null
+++ b/gitk-git/.gitignore
@@ -0,0 +1 @@
+/gitk-wish
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH 0/2] optimizing pack access on "read only" fetch repos
From: Duy Nguyen @ 2013-01-29 11:01 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git
In-Reply-To: <7vlibfxhit.fsf@alter.siamese.dyndns.org>
On Sun, Jan 27, 2013 at 1:32 PM, Junio C Hamano <gitster@pobox.com> wrote:
> I also wonder if we would be helped by another "repack" mode that
> coalesces small packs into a single one with minimum overhead, and
> run that often from "gc --auto", so that we do not end up having to
> have 50 packfiles.
>
> When we have 2 or more small and young packs, we could:
>
> - iterate over idx files for these packs to enumerate the objects
> to be packed, replacing read_object_list_from_stdin() step;
>
> - always choose to copy the data we have in these existing packs,
> instead of doing a full prepare_pack(); and
>
> - use the order the objects appear in the original packs, bypassing
> compute_write_order().
Isn't it easier and cheaper to create the "master index", something
like bup does?
--
Duy
^ permalink raw reply
* Re: [PATCH 2/6] strbuf: add string-chomping functions
From: Jeff King @ 2013-01-29 11:10 UTC (permalink / raw)
To: Michael Haggerty; +Cc: git, Duy Nguyen, Shawn O. Pearce
In-Reply-To: <5107A146.4000309@alum.mit.edu>
On Tue, Jan 29, 2013 at 11:15:34AM +0100, Michael Haggerty wrote:
> > +void strbuf_chompmem(struct strbuf *sb, const void *data, size_t len)
> > +{
> > + if (sb->len >= len && !memcmp(data, sb->buf + sb->len - len, len))
> > + strbuf_setlen(sb, sb->len - len);
> > +}
> > +
> > +void strbuf_chompstr(struct strbuf *sb, const char *str)
> > +{
> > + strbuf_chompmem(sb, str, strlen(str));
> > +}
> > +
> It might be handy to have these functions return true/false based on
> whether the suffix was actually found.
Yeah, that sounds reasonable.
> Please document the new functions in
> Documentation/technical/api-strbuf.txt. Personally I would also
> advocate a "docstring" in the header file, but obviously that preference
> is the exception rather than the rule in the git project :-(
Will do. I need to document the metapack functions, too, so I was thinking
about experimenting with some inline documentation systems.
-Peff
^ permalink raw reply
* Re: [PATCH 4/6] introduce a commit metapack
From: Jeff King @ 2013-01-29 11:13 UTC (permalink / raw)
To: Michael Haggerty; +Cc: git, Duy Nguyen, Shawn O. Pearce
In-Reply-To: <5107A36D.2050307@alum.mit.edu>
On Tue, Jan 29, 2013 at 11:24:45AM +0100, Michael Haggerty wrote:
> On 01/29/2013 10:16 AM, Jeff King wrote:
> > When we are doing a commit traversal that does not need to
> > look at the commit messages themselves (e.g., rev-list,
> > merge-base, etc), we spend a lot of time accessing,
> > decompressing, and parsing the commit objects just to find
> > the parent and timestamp information. We can make a
> > space-time tradeoff by caching that information on disk in a
> > compact, uncompressed format.
> >
> > TODO: document on-disk format in Documentation/technical
> > TODO: document API
>
> Would this be a good place to add the commit generation number that is
> so enthusiastically discussed on the mailing list from time to time?
Yes, that is one of my goals. We may even be able to just replace the
timestamp field in the cache with a generation number. When it gets
pretty-printed we pull it out of the commit message again anyway, so in
theory the only use inside "struct commit" is for ordering. But I
haven't looked at all of the use sites yet to be sure nobody is
depending on it being an actual date stamp.
-Peff
^ permalink raw reply
* Re: [PATCH v2 0/4] Auto-generate mergetool lists
From: Joachim Schmitz @ 2013-01-29 11:56 UTC (permalink / raw)
To: git
In-Reply-To: <20130128222147.GD7498@serenity.lan>
John Keeping wrote:
> On Mon, Jan 28, 2013 at 01:50:19PM -0800, Junio C Hamano wrote:
>> What are the situations where a valid user-defined tools is
>> unavailable, by the way?
>
> The same as a built-in tool: the command isn't available.
>
> Currently I'm extracting the command word using:
>
> cmd=$(eval -- "set -- $(git config mergetool.$tool.cmd); echo
> \"$1\"")
Shouldnt this work?
cmd=$((git config "mergetool.$tool.cmd" || git config "difftool.$tool.cmd")
| awk '{print $1}')
> (it's slightly more complicated due to handling difftool.$tool.cmd as
> well, but that's essentially it). Then it just uses the same "type
> $cmd" test as for built-in tools.
>
> I don't know if there's a better way to extract the first word, but
> that's the best I've come up with so far.
>
>
> John
^ permalink raw reply
* Re: [PATCH v2 0/4] Auto-generate mergetool lists
From: John Keeping @ 2013-01-29 12:09 UTC (permalink / raw)
To: Joachim Schmitz; +Cc: git
In-Reply-To: <ke8de9$lk5$1@ger.gmane.org>
On Tue, Jan 29, 2013 at 12:56:58PM +0100, Joachim Schmitz wrote:
> John Keeping wrote:
> > Currently I'm extracting the command word using:
> >
> > cmd=$(eval -- "set -- $(git config mergetool.$tool.cmd); echo
> > \"$1\"")
>
> Shouldnt this work?
> cmd=$((git config "mergetool.$tool.cmd" || git config "difftool.$tool.cmd")
> | awk '{print $1}')
That doesn't handle paths with spaces in, whereas the eval in a subshell
does:
$ cmd='"my command" $BASE $LOCAL $REMOTE'
$ echo "$cmd" | awk '{print $1}'
"my
$ ( eval -- "set -- $cmd; echo \"\$1\"" )
my command
John
^ permalink raw reply
* [PATCH] status: show branch name if possible in in-progress info
From: Nguyễn Thái Ngọc Duy @ 2013-01-29 12:10 UTC (permalink / raw)
To: git; +Cc: Matthieu Moy, Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Seems like a good thing to do.
t/t7512-status-help.sh | 36 +++++++++++++++----------------
wt-status.c | 58 ++++++++++++++++++++++++++++++++++++++++++--------
wt-status.h | 1 +
3 files changed, 68 insertions(+), 27 deletions(-)
diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
index b3f6eb9..096ba6f 100755
--- a/t/t7512-status-help.sh
+++ b/t/t7512-status-help.sh
@@ -76,7 +76,7 @@ test_expect_success 'status when rebase in progress before resolving conflicts'
test_must_fail git rebase HEAD^ --onto HEAD^^ &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently rebasing.
+ # You are currently rebasing '\''rebase_conflicts'\''.
# (fix conflicts and then run "git rebase --continue")
# (use "git rebase --skip" to skip this patch)
# (use "git rebase --abort" to check out the original branch)
@@ -102,7 +102,7 @@ test_expect_success 'status when rebase in progress before rebase --continue' '
git add main.txt &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently rebasing.
+ # You are currently rebasing '\''rebase_conflicts'\''.
# (all conflicts fixed: run "git rebase --continue")
#
# Changes to be committed:
@@ -133,7 +133,7 @@ test_expect_success 'status during rebase -i when conflicts unresolved' '
test_must_fail git rebase -i rebase_i_conflicts &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently rebasing.
+ # You are currently rebasing '\''rebase_i_conflicts_second'\''.
# (fix conflicts and then run "git rebase --continue")
# (use "git rebase --skip" to skip this patch)
# (use "git rebase --abort" to check out the original branch)
@@ -158,7 +158,7 @@ test_expect_success 'status during rebase -i after resolving conflicts' '
git add main.txt &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently rebasing.
+ # You are currently rebasing '\''rebase_i_conflicts_second'\''.
# (all conflicts fixed: run "git rebase --continue")
#
# Changes to be committed:
@@ -185,7 +185,7 @@ test_expect_success 'status when rebasing -i in edit mode' '
git rebase -i HEAD~2 &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing '\''rebase_i_edit'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -210,7 +210,7 @@ test_expect_success 'status when splitting a commit' '
git reset HEAD^ &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently splitting a commit during a rebase.
+ # You are currently splitting a commit while rebasing '\''split_commit'\''.
# (Once your working directory is clean, run "git rebase --continue")
#
# Changes not staged for commit:
@@ -240,7 +240,7 @@ test_expect_success 'status after editing the last commit with --amend during a
git commit --amend -m "foo" &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing '\''amend_last'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -269,7 +269,7 @@ test_expect_success 'status: (continue first edit) second edit' '
git rebase --continue &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing '\''several_edits'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -290,7 +290,7 @@ test_expect_success 'status: (continue first edit) second edit and split' '
git reset HEAD^ &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently splitting a commit during a rebase.
+ # You are currently splitting a commit while rebasing '\''several_edits'\''.
# (Once your working directory is clean, run "git rebase --continue")
#
# Changes not staged for commit:
@@ -316,7 +316,7 @@ test_expect_success 'status: (continue first edit) second edit and amend' '
git commit --amend -m "foo" &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing '\''several_edits'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -337,7 +337,7 @@ test_expect_success 'status: (amend first edit) second edit' '
git rebase --continue &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing '\''several_edits'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -359,7 +359,7 @@ test_expect_success 'status: (amend first edit) second edit and split' '
git reset HEAD^ &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently splitting a commit during a rebase.
+ # You are currently splitting a commit while rebasing '\''several_edits'\''.
# (Once your working directory is clean, run "git rebase --continue")
#
# Changes not staged for commit:
@@ -386,7 +386,7 @@ test_expect_success 'status: (amend first edit) second edit and amend' '
git commit --amend -m "d" &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing '\''several_edits'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -409,7 +409,7 @@ test_expect_success 'status: (split first edit) second edit' '
git rebase --continue &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing '\''several_edits'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -433,7 +433,7 @@ test_expect_success 'status: (split first edit) second edit and split' '
git reset HEAD^ &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently splitting a commit during a rebase.
+ # You are currently splitting a commit while rebasing '\''several_edits'\''.
# (Once your working directory is clean, run "git rebase --continue")
#
# Changes not staged for commit:
@@ -462,7 +462,7 @@ test_expect_success 'status: (split first edit) second edit and amend' '
git commit --amend -m "h" &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing '\''several_edits'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -558,7 +558,7 @@ test_expect_success 'status when bisecting' '
git bisect good one_bisect &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently bisecting.
+ # You are currently bisecting '\''bisect'\''.
# (use "git bisect reset" to get back to the original branch)
#
nothing to commit (use -u to show untracked files)
@@ -580,7 +580,7 @@ test_expect_success 'status when rebase conflicts with statushints disabled' '
test_must_fail git rebase HEAD^ --onto HEAD^^ &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently rebasing.
+ # You are currently rebasing '\''statushints_disabled'\''.
#
# Unmerged paths:
# both modified: main.txt
diff --git a/wt-status.c b/wt-status.c
index d7cfe8f..cc7e2d7 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -872,7 +872,13 @@ static void show_rebase_in_progress(struct wt_status *s,
struct stat st;
if (has_unmerged(s)) {
- status_printf_ln(s, color, _("You are currently rebasing."));
+ if (state->branch)
+ status_printf_ln(s, color,
+ _("You are currently rebasing '%s'."),
+ state->branch);
+ else
+ status_printf_ln(s, color,
+ _("You are currently rebasing."));
if (advice_status_hints) {
status_printf_ln(s, color,
_(" (fix conflicts and then run \"git rebase --continue\")"));
@@ -882,17 +888,35 @@ static void show_rebase_in_progress(struct wt_status *s,
_(" (use \"git rebase --abort\" to check out the original branch)"));
}
} else if (state->rebase_in_progress || !stat(git_path("MERGE_MSG"), &st)) {
- status_printf_ln(s, color, _("You are currently rebasing."));
+ if (state->branch)
+ status_printf_ln(s, color,
+ _("You are currently rebasing '%s'."),
+ state->branch);
+ else
+ status_printf_ln(s, color,
+ _("You are currently rebasing."));
if (advice_status_hints)
status_printf_ln(s, color,
_(" (all conflicts fixed: run \"git rebase --continue\")"));
} else if (split_commit_in_progress(s)) {
- status_printf_ln(s, color, _("You are currently splitting a commit during a rebase."));
+ if (state->branch)
+ status_printf_ln(s, color,
+ _("You are currently splitting a commit while rebasing '%s'."),
+ state->branch);
+ else
+ status_printf_ln(s, color,
+ _("You are currently splitting a commit during a rebase."));
if (advice_status_hints)
status_printf_ln(s, color,
_(" (Once your working directory is clean, run \"git rebase --continue\")"));
} else {
- status_printf_ln(s, color, _("You are currently editing a commit during a rebase."));
+ if (state->branch)
+ status_printf_ln(s, color,
+ _("You are currently editing a commit while rebasing '%s'."),
+ state->branch);
+ else
+ status_printf_ln(s, color,
+ _("You are currently editing a commit during a rebase."));
if (advice_status_hints && !s->amend) {
status_printf_ln(s, color,
_(" (use \"git commit --amend\" to amend the current commit)"));
@@ -923,7 +947,7 @@ static void show_bisect_in_progress(struct wt_status *s,
struct wt_status_state *state,
const char *color)
{
- status_printf_ln(s, color, _("You are currently bisecting."));
+ status_printf_ln(s, color, _("You are currently bisecting '%s'."), state->branch);
if (advice_status_hints)
status_printf_ln(s, color,
_(" (use \"git bisect reset\" to get back to the original branch)"));
@@ -935,6 +959,7 @@ static void wt_status_print_state(struct wt_status *s)
const char *state_color = color(WT_STATUS_HEADER, s);
struct wt_status_state state;
struct stat st;
+ struct strbuf sb = STRBUF_INIT;
memset(&state, 0, sizeof(state));
@@ -947,28 +972,43 @@ static void wt_status_print_state(struct wt_status *s)
state.am_empty_patch = 1;
} else {
state.rebase_in_progress = 1;
+ strbuf_read_file(&sb, git_path("rebase-apply/head-name"), 0);
}
} else if (!stat(git_path("rebase-merge"), &st)) {
if (!stat(git_path("rebase-merge/interactive"), &st))
state.rebase_interactive_in_progress = 1;
else
state.rebase_in_progress = 1;
+ strbuf_read_file(&sb, git_path("rebase-merge/head-name"), 0);
} else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) {
state.cherry_pick_in_progress = 1;
}
- if (!stat(git_path("BISECT_LOG"), &st))
+ if (!stat(git_path("BISECT_LOG"), &st)) {
+ strbuf_read_file(&sb, git_path("BISECT_START"), 0);
state.bisect_in_progress = 1;
+ }
if (state.merge_in_progress)
show_merge_in_progress(s, &state, state_color);
else if (state.am_in_progress)
show_am_in_progress(s, &state, state_color);
- else if (state.rebase_in_progress || state.rebase_interactive_in_progress)
+ else if (state.rebase_in_progress || state.rebase_interactive_in_progress) {
+ while (sb.len && sb.buf[sb.len - 1] == '\n')
+ strbuf_setlen(&sb, sb.len - 1);
+ if (!prefixcmp(sb.buf, "refs/heads/"))
+ state.branch = sb.buf + strlen("refs/heads/");
+ else if (!prefixcmp(sb.buf, "refs/"))
+ state.branch = sb.buf;
show_rebase_in_progress(s, &state, state_color);
- else if (state.cherry_pick_in_progress)
+ } else if (state.cherry_pick_in_progress)
show_cherry_pick_in_progress(s, &state, state_color);
- if (state.bisect_in_progress)
+ if (state.bisect_in_progress) {
+ while (sb.len && sb.buf[sb.len - 1] == '\n')
+ strbuf_setlen(&sb, sb.len - 1);
+ state.branch = sb.buf;
show_bisect_in_progress(s, &state, state_color);
+ }
+ strbuf_release(&sb);
}
void wt_status_print(struct wt_status *s)
diff --git a/wt-status.h b/wt-status.h
index 236b41f..c5eae29 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -79,6 +79,7 @@ struct wt_status_state {
int rebase_interactive_in_progress;
int cherry_pick_in_progress;
int bisect_in_progress;
+ const char *branch;
};
void wt_status_prepare(struct wt_status *s);
--
1.8.1.1.459.g5970e58
^ permalink raw reply related
* [PATCH] branch: show (rebasing) or (bisecting) instead of (no branch) when possible
From: Nguyễn Thái Ngọc Duy @ 2013-01-29 12:12 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
In the spirit of status' in-progress info. I think showing this is
more useful than "(no branch)". I tend to do "git br" more often than
"git st" and this catches my eyes.
builtin/branch.c | 10 +++++++++-
t/t6030-bisect-porcelain.sh | 2 +-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/builtin/branch.c b/builtin/branch.c
index 873f624..b0c5a20 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -557,7 +557,15 @@ static void show_detached(struct ref_list *ref_list)
if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {
struct ref_item item;
- item.name = xstrdup(_("(no branch)"));
+ struct stat st;
+ if ((!stat(git_path("rebase-apply"), &st) &&
+ stat(git_path("rebase-apply/applying"), &st)) ||
+ !stat(git_path("rebase-merge"), &st))
+ item.name = xstrdup(_("(rebasing)"));
+ else if (!stat(git_path("BISECT_LOG"), &st))
+ item.name = xstrdup(_("(bisecting)"));
+ else
+ item.name = xstrdup(_("(no branch)"));
item.width = utf8_strwidth(item.name);
item.kind = REF_LOCAL_BRANCH;
item.dest = NULL;
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 3e0e15f..bc21bc9 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -164,7 +164,7 @@ test_expect_success 'bisect start: existing ".git/BISECT_START" not modified if
cp .git/BISECT_START saved &&
test_must_fail git bisect start $HASH4 foo -- &&
git branch > branch.output &&
- test_i18ngrep "* (no branch)" branch.output > /dev/null &&
+ test_i18ngrep "* (bisecting)" branch.output > /dev/null &&
test_cmp saved .git/BISECT_START
'
test_expect_success 'bisect start: no ".git/BISECT_START" if mistaken rev' '
--
1.8.1.1.459.g5970e58
^ permalink raw reply related
* Re: [RFC] The design of new pathspec features
From: Duy Nguyen @ 2013-01-29 12:17 UTC (permalink / raw)
To: git
In-Reply-To: <20130129043517.GA2878@duynguyen-vnpc.dek-tpc.internal>
On Tue, Jan 29, 2013 at 11:35 AM, Duy Nguyen <pclouds@gmail.com> wrote:
> :(glob) magic
> =============
>
> This magic is for people who want globbing. However, it does _not_ use
> the same matching mechanism the non-magic pathspec does today. It uses
> wildmatch(WM_PATHNAME), which basically means '*' does not match
> slashes and "**" does.
>
> Global option --glob-pathspecs is added to add :(glob) to all
> pathspec. :(literal) magic overrides this global option.
I forgot one thing. The current pathspec behavior, the pattern "[a-z]"
would match a file named "[a-z]" (iow, wildcards are also considered
literal characters). Do we want to keep this behavior in :(glob)? To
me it's a surprise factor and therefore not good. But common sense may
be different.
--
Duy
^ permalink raw reply
* Re: [PATCH] status: show branch name if possible in in-progress info
From: Matthieu Moy @ 2013-01-29 12:31 UTC (permalink / raw)
To: Nguyễn Thái Ngọc Duy; +Cc: git
In-Reply-To: <1359461450-24456-1-git-send-email-pclouds@gmail.com>
I like the idea.
Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:
> diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
> index b3f6eb9..096ba6f 100755
> --- a/t/t7512-status-help.sh
> +++ b/t/t7512-status-help.sh
> @@ -76,7 +76,7 @@ test_expect_success 'status when rebase in progress before resolving conflicts'
> test_must_fail git rebase HEAD^ --onto HEAD^^ &&
> cat >expected <<-\EOF &&
> # Not currently on any branch.
> - # You are currently rebasing.
> + # You are currently rebasing '\''rebase_conflicts'\''.
Perhaps "rebasing *branch* 'rebase_conflicts'"
Or even "rebasing branch 'rebase_conflicts' on <sha1sum>"
?
> @@ -923,7 +947,7 @@ static void show_bisect_in_progress(struct wt_status *s,
> struct wt_status_state *state,
> const char *color)
> {
> - status_printf_ln(s, color, _("You are currently bisecting."));
> + status_printf_ln(s, color, _("You are currently bisecting '%s'."), state->branch);
> if (advice_status_hints)
> status_printf_ln(s, color,
> _(" (use \"git bisect reset\" to get back to the original branch)"));
In the "rebase" case, you test state->branch for null-ness. Don't you
need the same test here? (What happens if you start a bisect from a
detached HEAD state?)
--
Matthieu Moy
http://www-verimag.imag.fr/~moy/
^ permalink raw reply
* Re: [PATCH] status: show branch name if possible in in-progress info
From: Duy Nguyen @ 2013-01-29 12:56 UTC (permalink / raw)
To: Matthieu Moy; +Cc: git
In-Reply-To: <vpqy5fcrwzq.fsf@grenoble-inp.fr>
On Tue, Jan 29, 2013 at 7:31 PM, Matthieu Moy
<Matthieu.Moy@grenoble-inp.fr> wrote:
> I like the idea.
>
> Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:
>
>> diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
>> index b3f6eb9..096ba6f 100755
>> --- a/t/t7512-status-help.sh
>> +++ b/t/t7512-status-help.sh
>> @@ -76,7 +76,7 @@ test_expect_success 'status when rebase in progress before resolving conflicts'
>> test_must_fail git rebase HEAD^ --onto HEAD^^ &&
>> cat >expected <<-\EOF &&
>> # Not currently on any branch.
>> - # You are currently rebasing.
>> + # You are currently rebasing '\''rebase_conflicts'\''.
>
> Perhaps "rebasing *branch* 'rebase_conflicts'"
Looks good. One minor thing, if the ref happens to be
refs/somewhere-not-in-heads, should we still say "rebasing branch
'refs/...'" or just "rebasing 'refs/...'", or something else?
>
> Or even "rebasing branch 'rebase_conflicts' on <sha1sum>"
<sha1sum> being SHA-1 of HEAD? Why would you need it? In short
version, not full SHA-1?
> ?
>
>> @@ -923,7 +947,7 @@ static void show_bisect_in_progress(struct wt_status *s,
>> struct wt_status_state *state,
>> const char *color)
>> {
>> - status_printf_ln(s, color, _("You are currently bisecting."));
>> + status_printf_ln(s, color, _("You are currently bisecting '%s'."), state->branch);
>> if (advice_status_hints)
>> status_printf_ln(s, color,
>> _(" (use \"git bisect reset\" to get back to the original branch)"));
>
> In the "rebase" case, you test state->branch for null-ness. Don't you
> need the same test here? (What happens if you start a bisect from a
> detached HEAD state?)
I did read git-bisect.sh. I did not think it allowed bisecting on
detached HEAD. A simple test just told me otherwise. Will update.
--
Duy
^ permalink raw reply
* Re: [PATCH] status: show branch name if possible in in-progress info
From: Matthieu Moy @ 2013-01-29 13:13 UTC (permalink / raw)
To: Duy Nguyen; +Cc: git
In-Reply-To: <CACsJy8DLdG9O+HaWS8u4n+imdaSZe=GrbYbPOhcMsYMWDq9NZw@mail.gmail.com>
Duy Nguyen <pclouds@gmail.com> writes:
> On Tue, Jan 29, 2013 at 7:31 PM, Matthieu Moy
> <Matthieu.Moy@grenoble-inp.fr> wrote:
>> I like the idea.
>>
>> Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:
>>
>>> diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
>>> index b3f6eb9..096ba6f 100755
>>> --- a/t/t7512-status-help.sh
>>> +++ b/t/t7512-status-help.sh
>>> @@ -76,7 +76,7 @@ test_expect_success 'status when rebase in progress before resolving conflicts'
>>> test_must_fail git rebase HEAD^ --onto HEAD^^ &&
>>> cat >expected <<-\EOF &&
>>> # Not currently on any branch.
>>> - # You are currently rebasing.
>>> + # You are currently rebasing '\''rebase_conflicts'\''.
>>
>> Perhaps "rebasing *branch* 'rebase_conflicts'"
>
> Looks good. One minor thing, if the ref happens to be
> refs/somewhere-not-in-heads, should we still say "rebasing branch
> 'refs/...'" or just "rebasing 'refs/...'", or something else?
I think this should not happen, since HEAD can either point to a branch
or directly to a sha1 in normal conditions. But it doesn't harm to be
defensive, in case ...
>> Or even "rebasing branch 'rebase_conflicts' on <sha1sum>"
>
> <sha1sum> being SHA-1 of HEAD?
Not HEAD, but .git/rebase-merge/onto, i.e. the target of the rebase.
Ideally, I would have loved to see "rebasing master on origin/master",
but I do not think the target ref name is stored during rebase.
> Why would you need it?
The typical use-case is starting a rebase, do something else, come back
the day after and wonder wft. Which branch is being rebased is probably
the most useful, but the target may help too. But I can live
without ;-).
> In short version, not full SHA-1?
If you add it, the short one (long version would make overly long line
with limited use).
--
Matthieu Moy
http://www-verimag.imag.fr/~moy/
^ permalink raw reply
* [PATCH v2] status: show the branch name if possible in in-progress info
From: Nguyễn Thái Ngọc Duy @ 2013-01-29 14:58 UTC (permalink / raw)
To: git; +Cc: Matthieu Moy, Nguyễn Thái Ngọc Duy
In-Reply-To: <1359461450-24456-1-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
- fix bisecting on detached HEAD
- show onto sha-1 for rebase
t/t7512-status-help.sh | 36 ++++++++++----------
wt-status.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++----
wt-status.h | 2 ++
3 files changed, 105 insertions(+), 24 deletions(-)
diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
index b3f6eb9..67ece6b 100755
--- a/t/t7512-status-help.sh
+++ b/t/t7512-status-help.sh
@@ -76,7 +76,7 @@ test_expect_success 'status when rebase in progress before resolving conflicts'
test_must_fail git rebase HEAD^ --onto HEAD^^ &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently rebasing.
+ # You are currently rebasing branch '\''rebase_conflicts'\'' on '\''000106f'\''.
# (fix conflicts and then run "git rebase --continue")
# (use "git rebase --skip" to skip this patch)
# (use "git rebase --abort" to check out the original branch)
@@ -102,7 +102,7 @@ test_expect_success 'status when rebase in progress before rebase --continue' '
git add main.txt &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently rebasing.
+ # You are currently rebasing branch '\''rebase_conflicts'\'' on '\''000106f'\''.
# (all conflicts fixed: run "git rebase --continue")
#
# Changes to be committed:
@@ -133,7 +133,7 @@ test_expect_success 'status during rebase -i when conflicts unresolved' '
test_must_fail git rebase -i rebase_i_conflicts &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently rebasing.
+ # You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''e0164e4'\''.
# (fix conflicts and then run "git rebase --continue")
# (use "git rebase --skip" to skip this patch)
# (use "git rebase --abort" to check out the original branch)
@@ -158,7 +158,7 @@ test_expect_success 'status during rebase -i after resolving conflicts' '
git add main.txt &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently rebasing.
+ # You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''e0164e4'\''.
# (all conflicts fixed: run "git rebase --continue")
#
# Changes to be committed:
@@ -185,7 +185,7 @@ test_expect_success 'status when rebasing -i in edit mode' '
git rebase -i HEAD~2 &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing branch '\''rebase_i_edit'\'' on '\''f90e540'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -210,7 +210,7 @@ test_expect_success 'status when splitting a commit' '
git reset HEAD^ &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently splitting a commit during a rebase.
+ # You are currently splitting a commit while rebasing branch '\''split_commit'\'' on '\''19b175e'\''.
# (Once your working directory is clean, run "git rebase --continue")
#
# Changes not staged for commit:
@@ -240,7 +240,7 @@ test_expect_success 'status after editing the last commit with --amend during a
git commit --amend -m "foo" &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing branch '\''amend_last'\'' on '\''dd030b9'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -269,7 +269,7 @@ test_expect_success 'status: (continue first edit) second edit' '
git rebase --continue &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''eb16a7e'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -290,7 +290,7 @@ test_expect_success 'status: (continue first edit) second edit and split' '
git reset HEAD^ &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently splitting a commit during a rebase.
+ # You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''eb16a7e'\''.
# (Once your working directory is clean, run "git rebase --continue")
#
# Changes not staged for commit:
@@ -316,7 +316,7 @@ test_expect_success 'status: (continue first edit) second edit and amend' '
git commit --amend -m "foo" &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''eb16a7e'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -337,7 +337,7 @@ test_expect_success 'status: (amend first edit) second edit' '
git rebase --continue &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''eb16a7e'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -359,7 +359,7 @@ test_expect_success 'status: (amend first edit) second edit and split' '
git reset HEAD^ &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently splitting a commit during a rebase.
+ # You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''eb16a7e'\''.
# (Once your working directory is clean, run "git rebase --continue")
#
# Changes not staged for commit:
@@ -386,7 +386,7 @@ test_expect_success 'status: (amend first edit) second edit and amend' '
git commit --amend -m "d" &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''eb16a7e'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -409,7 +409,7 @@ test_expect_success 'status: (split first edit) second edit' '
git rebase --continue &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''eb16a7e'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -433,7 +433,7 @@ test_expect_success 'status: (split first edit) second edit and split' '
git reset HEAD^ &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently splitting a commit during a rebase.
+ # You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''eb16a7e'\''.
# (Once your working directory is clean, run "git rebase --continue")
#
# Changes not staged for commit:
@@ -462,7 +462,7 @@ test_expect_success 'status: (split first edit) second edit and amend' '
git commit --amend -m "h" &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently editing a commit during a rebase.
+ # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''eb16a7e'\''.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
@@ -558,7 +558,7 @@ test_expect_success 'status when bisecting' '
git bisect good one_bisect &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently bisecting.
+ # You are currently bisecting branch '\''bisect'\''.
# (use "git bisect reset" to get back to the original branch)
#
nothing to commit (use -u to show untracked files)
@@ -580,7 +580,7 @@ test_expect_success 'status when rebase conflicts with statushints disabled' '
test_must_fail git rebase HEAD^ --onto HEAD^^ &&
cat >expected <<-\EOF &&
# Not currently on any branch.
- # You are currently rebasing.
+ # You are currently rebasing branch '\''statushints_disabled'\'' on '\''1d51a61'\''.
#
# Unmerged paths:
# both modified: main.txt
diff --git a/wt-status.c b/wt-status.c
index d7cfe8f..42fafd0 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -872,7 +872,14 @@ static void show_rebase_in_progress(struct wt_status *s,
struct stat st;
if (has_unmerged(s)) {
- status_printf_ln(s, color, _("You are currently rebasing."));
+ if (state->branch)
+ status_printf_ln(s, color,
+ _("You are currently rebasing branch '%s' on '%s'."),
+ state->branch,
+ state->onto);
+ else
+ status_printf_ln(s, color,
+ _("You are currently rebasing."));
if (advice_status_hints) {
status_printf_ln(s, color,
_(" (fix conflicts and then run \"git rebase --continue\")"));
@@ -882,17 +889,38 @@ static void show_rebase_in_progress(struct wt_status *s,
_(" (use \"git rebase --abort\" to check out the original branch)"));
}
} else if (state->rebase_in_progress || !stat(git_path("MERGE_MSG"), &st)) {
- status_printf_ln(s, color, _("You are currently rebasing."));
+ if (state->branch)
+ status_printf_ln(s, color,
+ _("You are currently rebasing branch '%s' on '%s'."),
+ state->branch,
+ state->onto);
+ else
+ status_printf_ln(s, color,
+ _("You are currently rebasing."));
if (advice_status_hints)
status_printf_ln(s, color,
_(" (all conflicts fixed: run \"git rebase --continue\")"));
} else if (split_commit_in_progress(s)) {
- status_printf_ln(s, color, _("You are currently splitting a commit during a rebase."));
+ if (state->branch)
+ status_printf_ln(s, color,
+ _("You are currently splitting a commit while rebasing branch '%s' on '%s'."),
+ state->branch,
+ state->onto);
+ else
+ status_printf_ln(s, color,
+ _("You are currently splitting a commit during a rebase."));
if (advice_status_hints)
status_printf_ln(s, color,
_(" (Once your working directory is clean, run \"git rebase --continue\")"));
} else {
- status_printf_ln(s, color, _("You are currently editing a commit during a rebase."));
+ if (state->branch)
+ status_printf_ln(s, color,
+ _("You are currently editing a commit while rebasing branch '%s' on '%s'."),
+ state->branch,
+ state->onto);
+ else
+ status_printf_ln(s, color,
+ _("You are currently editing a commit during a rebase."));
if (advice_status_hints && !s->amend) {
status_printf_ln(s, color,
_(" (use \"git commit --amend\" to amend the current commit)"));
@@ -923,16 +951,54 @@ static void show_bisect_in_progress(struct wt_status *s,
struct wt_status_state *state,
const char *color)
{
- status_printf_ln(s, color, _("You are currently bisecting."));
+ if (state->branch)
+ status_printf_ln(s, color,
+ _("You are currently bisecting branch '%s'."),
+ state->branch);
+ else
+ status_printf_ln(s, color,
+ _("You are currently bisecting."));
if (advice_status_hints)
status_printf_ln(s, color,
_(" (use \"git bisect reset\" to get back to the original branch)"));
wt_status_print_trailer(s);
}
+static void read_and_strip_branch(struct strbuf *sb,
+ const char **branch,
+ const char *path)
+{
+ unsigned char sha1[20];
+
+ strbuf_reset(sb);
+ if (strbuf_read_file(sb, git_path("%s", path), 0) <= 0)
+ return;
+
+ while (sb->len && sb->buf[sb->len - 1] == '\n')
+ strbuf_setlen(sb, sb->len - 1);
+ if (!sb->len)
+ return;
+ if (!prefixcmp(sb->buf, "refs/heads/"))
+ *branch = sb->buf + strlen("refs/heads/");
+ else if (!prefixcmp(sb->buf, "refs/"))
+ *branch = sb->buf;
+ else if (!get_sha1_hex(sb->buf, sha1)) {
+ const char *abbrev;
+ abbrev = find_unique_abbrev(sha1, DEFAULT_ABBREV);
+ strbuf_reset(sb);
+ strbuf_addstr(sb, abbrev);
+ *branch = sb->buf;
+ } else if (!strcmp(sb->buf, "detached HEAD")) /* rebase */
+ ;
+ else /* bisect */
+ *branch = sb->buf;
+}
+
static void wt_status_print_state(struct wt_status *s)
{
const char *state_color = color(WT_STATUS_HEADER, s);
+ struct strbuf branch = STRBUF_INIT;
+ struct strbuf onto = STRBUF_INIT;
struct wt_status_state state;
struct stat st;
@@ -947,17 +1013,28 @@ static void wt_status_print_state(struct wt_status *s)
state.am_empty_patch = 1;
} else {
state.rebase_in_progress = 1;
+ read_and_strip_branch(&branch, &state.branch,
+ "rebase-apply/head-name");
+ read_and_strip_branch(&onto, &state.onto,
+ "rebase-apply/onto");
}
} else if (!stat(git_path("rebase-merge"), &st)) {
if (!stat(git_path("rebase-merge/interactive"), &st))
state.rebase_interactive_in_progress = 1;
else
state.rebase_in_progress = 1;
+ read_and_strip_branch(&branch, &state.branch,
+ "rebase-merge/head-name");
+ read_and_strip_branch(&onto, &state.onto,
+ "rebase-merge/onto");
} else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) {
state.cherry_pick_in_progress = 1;
}
- if (!stat(git_path("BISECT_LOG"), &st))
+ if (!stat(git_path("BISECT_LOG"), &st)) {
state.bisect_in_progress = 1;
+ read_and_strip_branch(&branch, &state.branch,
+ "BISECT_START");
+ }
if (state.merge_in_progress)
show_merge_in_progress(s, &state, state_color);
@@ -969,6 +1046,8 @@ static void wt_status_print_state(struct wt_status *s)
show_cherry_pick_in_progress(s, &state, state_color);
if (state.bisect_in_progress)
show_bisect_in_progress(s, &state, state_color);
+ strbuf_release(&branch);
+ strbuf_release(&onto);
}
void wt_status_print(struct wt_status *s)
diff --git a/wt-status.h b/wt-status.h
index 236b41f..81e1dcf 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -79,6 +79,8 @@ struct wt_status_state {
int rebase_interactive_in_progress;
int cherry_pick_in_progress;
int bisect_in_progress;
+ const char *branch;
+ const char *onto;
};
void wt_status_prepare(struct wt_status *s);
--
1.8.1.1.459.g5970e58
^ permalink raw reply related
* Re: Updating shared ref from remote helper, or fetch hook
From: Max Horn @ 2013-01-29 15:00 UTC (permalink / raw)
To: Jed Brown; +Cc: git
In-Reply-To: <87ehh5lw9j.fsf@59A2.org>
Hi Jed, all,
On 28.01.2013, at 06:19, Jed Brown wrote:
> I'm working on an hg remote helper that uses git notes for the sha1
> revision, so that git users can more easily refer to specific commits
> when communicating with hg users.
For the record, I am also working on that very same thing; it is yet another git-remote-hg alternative, based on Felipe's code but with many improvements. You can find it here: <https://github.com/buchuki/gitifyhg>.
Anyway, back to Jed's (and also my) question:
> Since there may be multiple
> concurrent fast-import streams, I write the notes to a private ref
> (refs/notes/hg-REMOTE), to be merged eventually using
>
> git notes --ref hg merge hg-REMOTE*
>
> There will never be conflicts because each hg commit translates to a
> unique git commit, thus even if multiple concurrent remotes process the
> same commit, the corresponding note will match.
>
> Unfortunately, I couldn't find a safe way to get this run after a fetch
> or clone. Of course I can ask the user to arrange to have this command
> run, but it would be a better interface to have it run automatically
> since it is a natural responsibility of the remote helper. Am I missing
> a way to do this or a viable alternative approach?
One idea we (well, Jed :-) had when brain storming about this was that perhaps one could (or even should?) (ab)use the "checkpoint" feature for that.
Basically, when the remote-helper is almost done with everything, issue a "checkpoint" command, to flush out everything we just imported to the HD.
Then once this completed, we can perform the notes merge. The main remaining problem with that is: How would we know when the "checkpoint" actually completed? Any ideas?
Perhaps a way to do that would be to make use of the new "bidi-import" remote helper capability -- if I understand it right, then this effectively connects the fast-import stdout to the stdin of the remote helper. Thus, if one were to follow the "checkpoint" by a "progress" command, then by waiting for that progress command's output to appear back on stdin, the remote helper could determine whether the import succeeded, and perform finalization actions (like merging notes, as in our case).
Does that sound viable? Crazy? Anybody got better a idea?
Cheers,
Max
^ permalink raw reply
* Re: [PATCH 0/2] optimizing pack access on "read only" fetch repos
From: Martin Fick @ 2013-01-29 15:25 UTC (permalink / raw)
To: Jeff King, Junio C Hamano; +Cc: Shawn O. Pearce, git
In-Reply-To: <20130129082939.GB6396@sigill.intra.peff.net>
Jeff King <peff@peff.net> wrote:
>On Sat, Jan 26, 2013 at 10:32:42PM -0800, Junio C Hamano wrote:
>
>> Both makes sense to me.
>>
>> I also wonder if we would be helped by another "repack" mode that
>> coalesces small packs into a single one with minimum overhead, and
>> run that often from "gc --auto", so that we do not end up having to
>> have 50 packfiles.
>>
>> When we have 2 or more small and young packs, we could:
>>
>> - iterate over idx files for these packs to enumerate the objects
>> to be packed, replacing read_object_list_from_stdin() step;
>>
>> - always choose to copy the data we have in these existing packs,
>> instead of doing a full prepare_pack(); and
>>
>> - use the order the objects appear in the original packs, bypassing
>> compute_write_order().
>
>I'm not sure. If I understand you correctly, it would basically just be
>concatenating packs without trying to do delta compression between the
>objects which are ending up in the same pack. So it would save us from
>having to do (up to) 50 binary searches to find an object in a pack,
>but
>would not actually save us much space.
>
>I would be interested to see the timing on how quick it is compared to
>a
>real repack, as the I/O that happens during a repack is non-trivial
>(although if you are leaving aside the big "main" pack, then it is
>probably not bad).
>
>But how do these somewhat mediocre concatenated packs get turned into
>real packs? Pack-objects does not consider deltas between objects in
>the
>same pack. And when would you decide to make a real pack? How do you
>know you have 50 young and small packs, and not 50 mediocre coalesced
>packs?
If we are reconsidering repacking strategies, I would like to propose an approach that might be a more general improvement to repacking which would help in more situations.
You could roll together any packs which are close in size, say within 50% of each other. With this strategy you will end up with files which are spread out by size exponentially. I implementated this strategy on top of the current gc script using keep files, it works fairly well:
https://gerrit-review.googlesource.com/#/c/35215/3/contrib/git-exproll.sh
This saves some time, but mostly it saves I/O when repacking regularly. I suspect that if this strategy were used in core git that further optimizations could be made to also reduce the repack time, but I don't know enough about repacking to know? We run it nightly on our servers, both write and read only mirrors. We us are a ratio of 5 currently to drastically reduce large repack file rollovers,
-Martin
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox