2 * Builtin "git replace"
4 * Copyright (c) 2008 Christian Couder <chriscool@tuxfamily.org>
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.
14 #include "parse-options.h"
16 static const char * const git_replace_usage
[] = {
17 N_("git replace [-f] <object> <replacement>"),
18 N_("git replace -d <object>..."),
19 N_("git replace [--format=<format>] [-l [<pattern>]]"),
25 REPLACE_FORMAT_MEDIUM
,
31 enum replace_format format
;
34 static int show_reference(const char *refname
, const unsigned char *sha1
,
35 int flag
, void *cb_data
)
37 struct show_data
*data
= cb_data
;
39 if (!fnmatch(data
->pattern
, refname
, 0)) {
40 if (data
->format
== REPLACE_FORMAT_SHORT
)
41 printf("%s\n", refname
);
42 else if (data
->format
== REPLACE_FORMAT_MEDIUM
)
43 printf("%s -> %s\n", refname
, sha1_to_hex(sha1
));
44 else { /* data->format == REPLACE_FORMAT_LONG */
45 unsigned char object
[20];
46 enum object_type obj_type
, repl_type
;
48 if (get_sha1(refname
, object
))
49 return error("Failed to resolve '%s' as a valid ref.", refname
);
51 obj_type
= sha1_object_info(object
, NULL
);
52 repl_type
= sha1_object_info(sha1
, NULL
);
54 printf("%s (%s) -> %s (%s)\n", refname
, typename(obj_type
),
55 sha1_to_hex(sha1
), typename(repl_type
));
62 static int list_replace_refs(const char *pattern
, const char *format
)
64 struct show_data data
;
68 data
.pattern
= pattern
;
70 if (format
== NULL
|| *format
== '\0' || !strcmp(format
, "short"))
71 data
.format
= REPLACE_FORMAT_SHORT
;
72 else if (!strcmp(format
, "medium"))
73 data
.format
= REPLACE_FORMAT_MEDIUM
;
74 else if (!strcmp(format
, "long"))
75 data
.format
= REPLACE_FORMAT_LONG
;
77 die("invalid replace format '%s'\n"
78 "valid formats are 'short', 'medium' and 'long'\n",
81 for_each_replace_ref(show_reference
, (void *) &data
);
86 typedef int (*each_replace_name_fn
)(const char *name
, const char *ref
,
87 const unsigned char *sha1
);
89 static int for_each_replace_name(const char **argv
, each_replace_name_fn fn
)
91 const char **p
, *full_hex
;
94 unsigned char sha1
[20];
96 for (p
= argv
; *p
; p
++) {
97 if (get_sha1(*p
, sha1
)) {
98 error("Failed to resolve '%s' as a valid ref.", *p
);
102 full_hex
= sha1_to_hex(sha1
);
103 snprintf(ref
, sizeof(ref
), "refs/replace/%s", full_hex
);
104 /* read_ref() may reuse the buffer */
105 full_hex
= ref
+ strlen("refs/replace/");
106 if (read_ref(ref
, sha1
)) {
107 error("replace ref '%s' not found.", full_hex
);
111 if (fn(full_hex
, ref
, sha1
))
117 static int delete_replace_ref(const char *name
, const char *ref
,
118 const unsigned char *sha1
)
120 if (delete_ref(ref
, sha1
, 0))
122 printf("Deleted replace ref '%s'\n", name
);
126 static int replace_object(const char *object_ref
, const char *replace_ref
,
129 unsigned char object
[20], prev
[20], repl
[20];
130 enum object_type obj_type
, repl_type
;
132 struct ref_lock
*lock
;
134 if (get_sha1(object_ref
, object
))
135 die("Failed to resolve '%s' as a valid ref.", object_ref
);
136 if (get_sha1(replace_ref
, repl
))
137 die("Failed to resolve '%s' as a valid ref.", replace_ref
);
139 if (snprintf(ref
, sizeof(ref
),
141 sha1_to_hex(object
)) > sizeof(ref
) - 1)
142 die("replace ref name too long: %.*s...", 50, ref
);
143 if (check_refname_format(ref
, 0))
144 die("'%s' is not a valid ref name.", ref
);
146 obj_type
= sha1_object_info(object
, NULL
);
147 repl_type
= sha1_object_info(repl
, NULL
);
148 if (!force
&& obj_type
!= repl_type
)
149 die("Objects must be of the same type.\n"
150 "'%s' points to a replaced object of type '%s'\n"
151 "while '%s' points to a replacement object of type '%s'.",
152 object_ref
, typename(obj_type
),
153 replace_ref
, typename(repl_type
));
155 if (read_ref(ref
, prev
))
158 die("replace ref '%s' already exists", ref
);
160 lock
= lock_any_ref_for_update(ref
, prev
, 0, NULL
);
162 die("%s: cannot lock the ref", ref
);
163 if (write_ref_sha1(lock
, repl
, NULL
) < 0)
164 die("%s: cannot update the ref", ref
);
169 int cmd_replace(int argc
, const char **argv
, const char *prefix
)
171 int list
= 0, delete = 0, force
= 0;
172 const char *format
= NULL
;
173 struct option options
[] = {
174 OPT_BOOL('l', "list", &list
, N_("list replace refs")),
175 OPT_BOOL('d', "delete", &delete, N_("delete replace refs")),
176 OPT_BOOL('f', "force", &force
, N_("replace the ref if it exists")),
177 OPT_STRING(0, "format", &format
, N_("format"), N_("use this format")),
181 read_replace_refs
= 0;
183 argc
= parse_options(argc
, argv
, prefix
, options
, git_replace_usage
, 0);
186 usage_msg_opt("-l and -d cannot be used together",
187 git_replace_usage
, options
);
189 if (format
&& delete)
190 usage_msg_opt("--format and -d cannot be used together",
191 git_replace_usage
, options
);
193 if (force
&& (list
|| delete))
194 usage_msg_opt("-f cannot be used with -d or -l",
195 git_replace_usage
, options
);
200 usage_msg_opt("-d needs at least one argument",
201 git_replace_usage
, options
);
202 return for_each_replace_name(argv
, delete_replace_ref
);
208 usage_msg_opt("bad number of arguments",
209 git_replace_usage
, options
);
211 usage_msg_opt("--format cannot be used when not listing",
212 git_replace_usage
, options
);
213 return replace_object(argv
[0], argv
[1], force
);
216 /* List refs, even if "list" is not set */
218 usage_msg_opt("only one pattern can be given with -l",
219 git_replace_usage
, options
);
221 usage_msg_opt("-f needs some arguments",
222 git_replace_usage
, options
);
224 return list_replace_refs(argv
[0], format
);