From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 12/16] subtree: rewriting outgoing commits
Date: Sat, 31 Jul 2010 23:18:21 +0700 [thread overview]
Message-ID: <1280593105-22015-13-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1280593105-22015-1-git-send-email-pclouds@gmail.com>
Which is exactly the opposite of rewriting incoming commits.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
subtree.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
subtree.h | 1 +
2 files changed, 174 insertions(+), 0 deletions(-)
diff --git a/subtree.c b/subtree.c
index 8c075be..739ff5f 100644
--- a/subtree.c
+++ b/subtree.c
@@ -359,3 +359,176 @@ void subtree_import()
if (revs.pending.nr)
free(revs.pending.objects);
}
+
+/*
+ * The opposite of narrow_tree(). Put the subtree back to the original tree.
+ */
+static int widen_tree(const unsigned char *sha1,
+ unsigned char *newsha1,
+ const unsigned char *subtree_sha1,
+ const char *prefix)
+{
+ struct tree_desc desc;
+ struct name_entry entry;
+ struct strbuf buffer;
+ const char *slash;
+ int subtree_len;
+ enum object_type type;
+ unsigned long size;
+ char *tree;
+
+ slash = strchr(prefix, '/');
+ subtree_len = slash ? slash - prefix : strlen(prefix);
+
+ tree = read_sha1_file(sha1, &type, &size);
+ if (type != OBJ_TREE)
+ die("%s is not a tree", sha1_to_hex(sha1));
+
+ init_tree_desc(&desc, tree, size);
+ strbuf_init(&buffer, 8192);
+ while (tree_entry(&desc, &entry)) {
+ strbuf_addf(&buffer, "%o %.*s%c", entry.mode, strlen(entry.path), entry.path, '\0');
+
+ if (S_ISDIR(entry.mode) &&
+ subtree_len == strlen(entry.path) &&
+ !strncmp(entry.path, prefix, subtree_len)) {
+ unsigned char newtree_sha1[20];
+
+ if (slash && slash[1]) /* trailing slash does not count */
+ widen_tree(entry.sha1, newtree_sha1, subtree_sha1,
+ prefix+subtree_len+1);
+ else
+ /* replace the tree */
+ memcpy(newtree_sha1, subtree_sha1, 20);
+
+ strbuf_add(&buffer, newtree_sha1, 20);
+ }
+ else
+ strbuf_add(&buffer, entry.sha1, 20);
+ }
+ free(tree);
+
+ if (write_sha1_file(buffer.buf, buffer.len, tree_type, newsha1)) {
+ error("Could not write replaced tree for %s", sha1_to_hex(sha1));
+ strbuf_release(&buffer);
+ return 1;
+ }
+ strbuf_release(&buffer);
+ return 0;
+}
+
+static int find_subtree(const unsigned char *sha1, unsigned char *newsha1, const char *prefix)
+{
+ struct tree_desc desc;
+ struct name_entry entry;
+ const char *slash;
+ enum object_type type;
+ unsigned long size;
+ int subtree_len;
+ char *tree;
+
+ slash = strchr(prefix, '/');
+ subtree_len = slash ? slash - prefix : strlen(prefix);
+
+ tree = read_sha1_file(sha1, &type, &size);
+ if (type != OBJ_TREE)
+ die("%s is not a tree", sha1_to_hex(sha1));
+
+ init_tree_desc(&desc, tree, size);
+ while (tree_entry(&desc, &entry)) {
+ if (!S_ISDIR(entry.mode))
+ continue;
+
+ if (subtree_len == strlen(entry.path) &&
+ !strncmp(entry.path, prefix, subtree_len)) {
+
+ if (slash && slash[1]) { /* trailing slash does not count */
+ if (find_subtree(entry.sha1, newsha1, prefix+subtree_len+1))
+ return 1;
+ }
+ else
+ memcpy(newsha1, entry.sha1, 20);
+ free(tree);
+ return 0;
+ }
+ }
+ free(tree);
+
+ return 1;
+}
+
+/* The opposite of shadow_commit() */
+static int expose_commit(const unsigned char *sha1, unsigned char *newsha1,
+ const unsigned char *basesha1,
+ const char *prefix, FILE *fp)
+{
+ unsigned char treesha1[20], subtree_sha1[20];
+ enum object_type type;
+ unsigned long size, base_size;
+ void *base_buffer, *buffer;
+ int saved_read_replace_refs = read_replace_refs;
+
+ /* Get subtree from the new commit, sha1 */
+ read_replace_refs = 0;
+ buffer = read_sha1_file(sha1, &type, &size);
+ read_replace_refs = saved_read_replace_refs;
+ get_sha1_hex(buffer+5, treesha1);
+
+ if (!buffer || type != OBJ_COMMIT ||
+ find_subtree(treesha1, subtree_sha1, prefix)) {
+ free(buffer);
+ error("Failed to find subtree tree in base commit %s", sha1_to_hex(sha1));
+ return 1;
+ }
+
+ /* Get the old base tree from basesha1 */
+ read_replace_refs = 0;
+ base_buffer = read_sha1_file(basesha1, &type, &base_size);
+ read_replace_refs = saved_read_replace_refs;
+ get_sha1_hex(base_buffer+5, treesha1);
+
+ if (!buffer || type != OBJ_COMMIT ||
+ widen_tree(treesha1, newsha1, subtree_sha1, prefix)) {
+ free(buffer);
+ error("Failed to widen tree for commit %s", sha1_to_hex(sha1));
+ return 1;
+ }
+ free(base_buffer);
+
+ /* replace new tree in */
+ memcpy((char*)buffer+5, sha1_to_hex(newsha1), 40);
+
+ if (write_sha1_file(buffer, size, commit_type, newsha1)) {
+ free(buffer);
+ error("Could not write replaced commit for %s", sha1_to_hex(sha1));
+ return 1;
+ }
+
+ if (fp) {
+ char buf[82];
+ memcpy(buf, sha1_to_hex(newsha1), 40);
+ buf[40] = ' ';
+ memcpy(buf+41, sha1_to_hex(sha1), 40);
+ buf[81] = '\n';
+ fwrite(buf, 82, 1, fp);
+ }
+ free(buffer);
+
+ return 0;
+}
+
+int subtree_export(unsigned char *sha1, unsigned char *basesha1, unsigned char *newsha1)
+{
+ FILE *fp;
+
+ fp = fopen(git_path("subtree"), "a+");
+ if (expose_commit(sha1, newsha1, basesha1, core_subtree, fp))
+ die("Failed to rewrite commit %s", sha1_to_hex(sha1));
+ fclose(fp);
+
+ if (subtree_commit)
+ free(subtree_commit);
+ prepare_subtree_commit();
+
+ return 0;
+}
diff --git a/subtree.h b/subtree.h
index 3512e2a..081838f 100644
--- a/subtree.h
+++ b/subtree.h
@@ -1,3 +1,4 @@
void prepare_subtree_commit();
const unsigned char *subtree_lookup_object(const unsigned char *sha1);
void subtree_import();
+int subtree_export(unsigned char *sha1, unsigned char *basesha1, unsigned char *newsha1);
--
1.7.1.rc1.69.g24c2f7
next prev parent reply other threads:[~2010-08-01 2:39 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-07-31 16:18 [PATCH 00/16] Subtree clone proof of concept Nguyễn Thái Ngọc Duy
2010-07-31 16:18 ` [PATCH 01/16] Add core.subtree Nguyễn Thái Ngọc Duy
2010-07-31 16:18 ` [PATCH 02/16] list-objects: limit traversing within the given subtree if core.subtree is set Nguyễn Thái Ngọc Duy
2010-08-01 11:30 ` Ævar Arnfjörð Bjarmason
2010-08-01 23:11 ` Nguyen Thai Ngoc Duy
2010-08-02 4:21 ` Elijah Newren
2010-08-02 6:51 ` Nguyen Thai Ngoc Duy
2010-07-31 16:18 ` [PATCH 03/16] parse_object: keep sha1 even when parsing replaced one Nguyễn Thái Ngọc Duy
2010-07-31 16:18 ` [PATCH 04/16] Allow to invalidate a commit in in-memory object store Nguyễn Thái Ngọc Duy
2010-07-31 16:18 ` [PATCH 05/16] Hook up replace-object to allow bulk commit replacement Nguyễn Thái Ngọc Duy
2010-08-02 19:58 ` Junio C Hamano
2010-08-02 22:42 ` Nguyen Thai Ngoc Duy
2010-07-31 16:18 ` [PATCH 06/16] upload-pack: use a separate variable to control whether internal rev-list is used Nguyễn Thái Ngọc Duy
2010-08-02 4:25 ` Elijah Newren
2010-07-31 16:18 ` [PATCH 07/16] upload-pack: support subtree pack Nguyễn Thái Ngọc Duy
2010-08-02 4:27 ` Elijah Newren
2010-07-31 16:18 ` [PATCH 08/16] fetch-pack: support --subtree Nguyễn Thái Ngọc Duy
2010-07-31 16:18 ` [PATCH 09/16] subtree: rewrite incoming commits Nguyễn Thái Ngọc Duy
2010-08-02 4:37 ` Elijah Newren
2010-07-31 16:18 ` [PATCH 10/16] clone: support subtree clone with parameter --subtree Nguyễn Thái Ngọc Duy
2010-07-31 16:18 ` [PATCH 11/16] pack-objects: add --subtree (for pushing) Nguyễn Thái Ngọc Duy
2010-07-31 16:18 ` Nguyễn Thái Ngọc Duy [this message]
2010-08-02 4:40 ` [PATCH 12/16] subtree: rewriting outgoing commits Elijah Newren
2010-07-31 16:18 ` [PATCH 13/16] Update commit_tree() interface to take base tree too Nguyễn Thái Ngọc Duy
2010-07-31 16:18 ` [PATCH 14/16] commit_tree(): rewriting/replacing new commits Nguyễn Thái Ngọc Duy
2010-07-31 16:18 ` [PATCH 15/16] commit: rewrite outgoing commits Nguyễn Thái Ngọc Duy
2010-07-31 16:18 ` [PATCH 16/16] do not use thin packs and subtree together (just a bad feeling about this) Nguyễn Thái Ngọc Duy
2010-08-01 4:14 ` [PATCH 00/16] Subtree clone proof of concept Sverre Rabbelier
2010-08-01 6:58 ` Nguyen Thai Ngoc Duy
2010-08-01 20:05 ` Sverre Rabbelier
2010-08-02 5:18 ` Elijah Newren
2010-08-02 7:10 ` Nguyen Thai Ngoc Duy
2010-08-02 22:55 ` Nguyen Thai Ngoc Duy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1280593105-22015-13-git-send-email-pclouds@gmail.com \
--to=pclouds@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.