replace: add a --raw mode for --edit
One of the purposes of "git replace --edit" is to help a user repair objects which are malformed or corrupted. Usually we pretty-print trees with "ls-tree", which is much easier to work with than the raw binary data. However, some forms of corruption break the tree-walker, in which case our pretty-printing fails, rendering "--edit" useless for the user. This patch introduces a "--raw" option, which lets you edit the binary data in these instances. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King committed
Jun 24, 2014 at 05:46 UTC
2deda629c2ab7228790fb7561e66515a9bdcf7b6
2 files changed
+29
-10
Documentation/git-replace.txt
+8
@@ -73,6 +73,14 @@ OPTIONS
73
newly created object. See linkgit:git-var[1] for details about
74
how the editor will be chosen.
75
76
+--raw::
77
+ When editing, provide the raw object contents rather than
78
+ pretty-printed ones. Currently this only affects trees, which
79
+ will be shown in their binary form. This is harder to work with,
80
+ but can help when repairing a tree that is so corrupted it
81
+ cannot be pretty-printed. Note that you may need to configure
82
+ your editor to cleanly read and write binary data.
83
+
84
-l <pattern>::
85
--list <pattern>::
86
List replace refs for objects that match the given pattern (or
builtin/replace.c
+21
-10
@@ -188,10 +188,12 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f
188
}
189
190
/*
191
- * Write the contents of the object named by "sha1" to the file "filename",
192
- * pretty-printed for human editing based on its type.
191
+ * Write the contents of the object named by "sha1" to the file "filename".
192
+ * If "raw" is true, then the object's raw contents are printed according to
193
+ * "type". Otherwise, we pretty-print the contents for human editing.
194
*/
194
-static void export_object(const unsigned char *sha1, const char *filename)
195
+static void export_object(const unsigned char *sha1, enum object_type type,
196
+ int raw, const char *filename)
197
{
198
struct child_process cmd = { NULL };
199
int fd;
@@ -202,7 +204,10 @@ static void export_object(const unsigned char *sha1, const char *filename)
204
205
argv_array_push(&cmd.args, "--no-replace-objects");
206
argv_array_push(&cmd.args, "cat-file");
205
- argv_array_push(&cmd.args, "-p");
207
+ if (raw)
208
+ argv_array_push(&cmd.args, typename(type));
209
+ else
210
+ argv_array_push(&cmd.args, "-p");
211
argv_array_push(&cmd.args, sha1_to_hex(sha1));
212
cmd.git_cmd = 1;
213
cmd.out = fd;
@@ -217,7 +222,7 @@ static void export_object(const unsigned char *sha1, const char *filename)
222
* The sha1 of the written object is returned via sha1.
223
*/
224
static void import_object(unsigned char *sha1, enum object_type type,
220
- const char *filename)
225
+ int raw, const char *filename)
226
{
227
int fd;
228
@@ -225,7 +230,7 @@ static void import_object(unsigned char *sha1, enum object_type type,
230
if (fd < 0)
231
die_errno("unable to open %s for reading", filename);
232
228
- if (type == OBJ_TREE) {
233
+ if (!raw && type == OBJ_TREE) {
234
const char *argv[] = { "mktree", NULL };
235
struct child_process cmd = { argv };
236
struct strbuf result = STRBUF_INIT;
@@ -265,7 +270,7 @@ static void import_object(unsigned char *sha1, enum object_type type,
270
*/
271
}
272
268
-static int edit_and_replace(const char *object_ref, int force)
273
+static int edit_and_replace(const char *object_ref, int force, int raw)
274
{
275
char *tmpfile = git_pathdup("REPLACE_EDITOBJ");
276
enum object_type type;
@@ -281,10 +286,10 @@ static int edit_and_replace(const char *object_ref, int force)
286
287
check_ref_valid(old, prev, ref, sizeof(ref), force);
288
284
- export_object(old, tmpfile);
289
+ export_object(old, type, raw, tmpfile);
290
if (launch_editor(tmpfile, NULL, NULL) < 0)
291
die("editing object file failed");
287
- import_object(new, type, tmpfile);
292
+ import_object(new, type, raw, tmpfile);
293
294
free(tmpfile);
295
@@ -297,6 +302,7 @@ static int edit_and_replace(const char *object_ref, int force)
302
int cmd_replace(int argc, const char **argv, const char *prefix)
303
{
304
int force = 0;
305
+ int raw = 0;
306
const char *format = NULL;
307
enum {
308
MODE_UNSPECIFIED = 0,
@@ -310,6 +316,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
316
OPT_CMDMODE('d', "delete", &cmdmode, N_("delete replace refs"), MODE_DELETE),
317
OPT_CMDMODE('e', "edit", &cmdmode, N_("edit existing object"), MODE_EDIT),
318
OPT_BOOL('f', "force", &force, N_("replace the ref if it exists")),
319
+ OPT_BOOL(0, "raw", &raw, N_("do not pretty-print contents for --edit")),
320
OPT_STRING(0, "format", &format, N_("format"), N_("use this format")),
321
OPT_END()
322
};
@@ -329,6 +336,10 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
336
usage_msg_opt("-f only makes sense when writing a replacement",
337
git_replace_usage, options);
338
339
+ if (raw && cmdmode != MODE_EDIT)
340
+ usage_msg_opt("--raw only makes sense with --edit",
341
+ git_replace_usage, options);
342
+
343
switch (cmdmode) {
344
case MODE_DELETE:
345
if (argc < 1)
@@ -346,7 +357,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
357
if (argc != 1)
358
usage_msg_opt("-e needs exactly one argument",
359
git_replace_usage, options);
349
- return edit_and_replace(argv[0], force);
360
+ return edit_and_replace(argv[0], force, raw);
361
362
case MODE_LIST:
363
if (argc > 1)