Add new "git replace" command
This command can only be used now to list replace refs in "refs/replace/" and to delete them. The option to list replace refs is "-l". The option to delete replace refs is "-d". The behavior should be consistent with how "git tag" and "git branch" are working. The code has been copied from "builtin-tag.c" by Kristian Høgsberg <krh@redhat.com> and Carlos Rica <jasampler@gmail.com> that was itself based on git-tag.sh and mktag.c by Linus Torvalds. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Christian Couder committed
Feb 2, 2009 at 06:12 UTC
54b0c1e041e50cc08b1520b7d557770916d0b7ab
5 files changed
+120
Makefile
+1
@@ -602,6 +602,7 @@ BUILTIN_OBJS += builtin-read-tree.o
602
BUILTIN_OBJS += builtin-receive-pack.o
603
BUILTIN_OBJS += builtin-reflog.o
604
BUILTIN_OBJS += builtin-remote.o
605
+BUILTIN_OBJS += builtin-replace.o
606
BUILTIN_OBJS += builtin-rerere.o
607
BUILTIN_OBJS += builtin-reset.o
608
BUILTIN_OBJS += builtin-rev-list.o
builtin-replace.c
new
+105
@@ -0,0 +1,105 @@
1
+/*
2
+ * Builtin "git replace"
3
+ *
4
+ * Copyright (c) 2008 Christian Couder <chriscool@tuxfamily.org>
5
+ *
6
+ * Based on builtin-tag.c by Kristian Høgsberg <krh@redhat.com>
7
+ * and Carlos Rica <jasampler@gmail.com> that was itself based on
8
+ * git-tag.sh and mktag.c by Linus Torvalds.
9
+ */
10
+
11
+#include "cache.h"
12
+#include "builtin.h"
13
+#include "refs.h"
14
+#include "parse-options.h"
15
+
16
+static const char * const git_replace_usage[] = {
17
+ "git replace -d <object>...",
18
+ "git replace -l [<pattern>]",
19
+ NULL
20
+};
21
+
22
+static int show_reference(const char *refname, const unsigned char *sha1,
23
+ int flag, void *cb_data)
24
+{
25
+ const char *pattern = cb_data;
26
+
27
+ if (!fnmatch(pattern, refname, 0))
28
+ printf("%s\n", refname);
29
+
30
+ return 0;
31
+}
32
+
33
+static int list_replace_refs(const char *pattern)
34
+{
35
+ if (pattern == NULL)
36
+ pattern = "*";
37
+
38
+ for_each_replace_ref(show_reference, (void *) pattern);
39
+
40
+ return 0;
41
+}
42
+
43
+typedef int (*each_replace_name_fn)(const char *name, const char *ref,
44
+ const unsigned char *sha1);
45
+
46
+static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
47
+{
48
+ const char **p;
49
+ char ref[PATH_MAX];
50
+ int had_error = 0;
51
+ unsigned char sha1[20];
52
+
53
+ for (p = argv; *p; p++) {
54
+ if (snprintf(ref, sizeof(ref), "refs/replace/%s", *p)
55
+ >= sizeof(ref)) {
56
+ error("replace ref name too long: %.*s...", 50, *p);
57
+ had_error = 1;
58
+ continue;
59
+ }
60
+ if (!resolve_ref(ref, sha1, 1, NULL)) {
61
+ error("replace ref '%s' not found.", *p);
62
+ had_error = 1;
63
+ continue;
64
+ }
65
+ if (fn(*p, ref, sha1))
66
+ had_error = 1;
67
+ }
68
+ return had_error;
69
+}
70
+
71
+static int delete_replace_ref(const char *name, const char *ref,
72
+ const unsigned char *sha1)
73
+{
74
+ if (delete_ref(ref, sha1, 0))
75
+ return 1;
76
+ printf("Deleted replace ref '%s'\n", name);
77
+ return 0;
78
+}
79
+
80
+int cmd_replace(int argc, const char **argv, const char *prefix)
81
+{
82
+ int list = 0, delete = 0;
83
+ struct option options[] = {
84
+ OPT_BOOLEAN('l', NULL, &list, "list replace refs"),
85
+ OPT_BOOLEAN('d', NULL, &delete, "delete replace refs"),
86
+ OPT_END()
87
+ };
88
+
89
+ argc = parse_options(argc, argv, options, git_replace_usage, 0);
90
+
91
+ if (list && delete)
92
+ usage_with_options(git_replace_usage, options);
93
+
94
+ if (delete) {
95
+ if (argc < 1)
96
+ usage_with_options(git_replace_usage, options);
97
+ return for_each_replace_name(argv, delete_replace_ref);
98
+ }
99
+
100
+ /* List refs, even if "list" is not set */
101
+ if (argc > 1)
102
+ usage_with_options(git_replace_usage, options);
103
+
104
+ return list_replace_refs(argv[0]);
105
+}
builtin.h
+1
@@ -112,5 +112,6 @@ extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
112
extern int cmd_verify_pack(int argc, const char **argv, const char *prefix);
113
extern int cmd_show_ref(int argc, const char **argv, const char *prefix);
114
extern int cmd_pack_refs(int argc, const char **argv, const char *prefix);
115
+extern int cmd_replace(int argc, const char **argv, const char *prefix);
116
117
#endif
git.c
+1
@@ -340,6 +340,7 @@ static void handle_internal_command(int argc, const char **argv)
340
{ "receive-pack", cmd_receive_pack },
341
{ "reflog", cmd_reflog, RUN_SETUP },
342
{ "remote", cmd_remote, RUN_SETUP },
343
+ { "replace", cmd_replace, RUN_SETUP },
344
{ "repo-config", cmd_config },
345
{ "rerere", cmd_rerere, RUN_SETUP },
346
{ "reset", cmd_reset, RUN_SETUP },
t/t6050-replace.sh
+12
@@ -105,6 +105,18 @@ test_expect_success 'repack, clone and fetch work' '
105
cd ..
106
'
107
108
+test_expect_success '"git replace" listing and deleting' '
109
+ test "$HASH2" = "$(git replace -l)" &&
110
+ test "$HASH2" = "$(git replace)" &&
111
+ aa=${HASH2%??????????????????????????????????????} &&
112
+ test "$HASH2" = "$(git replace -l "$aa*")" &&
113
+ test_must_fail git replace -d $R &&
114
+ test_must_fail git replace -d &&
115
+ test_must_fail git replace -l -d $HASH2 &&
116
+ git replace -d $HASH2 &&
117
+ test -z "$(git replace -l)"
118
+'
119
+
120
#
121
#
122
test_done