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>]]"),
23 enum repl_fmt
{ SHORT
, MEDIUM
, FULL
};
30 static int show_reference(const char *refname
, const unsigned char *sha1
,
31 int flag
, void *cb_data
)
33 struct show_data
*data
= cb_data
;
35 if (!fnmatch(data
->pattern
, refname
, 0)) {
36 if (data
->fmt
== SHORT
)
37 printf("%s\n", refname
);
38 else if (data
->fmt
== MEDIUM
)
39 printf("%s -> %s\n", refname
, sha1_to_hex(sha1
));
40 else { /* data->fmt == FULL */
41 unsigned char object
[20];
42 enum object_type obj_type
, repl_type
;
44 if (get_sha1(refname
, object
))
45 return error("Failed to resolve '%s' as a valid ref.", refname
);
47 obj_type
= sha1_object_info(object
, NULL
);
48 repl_type
= sha1_object_info(sha1
, NULL
);
50 printf("%s (%s) -> %s (%s)\n", refname
, typename(obj_type
),
51 sha1_to_hex(sha1
), typename(repl_type
));
58 static int list_replace_refs(const char *pattern
, const char *format
)
60 struct show_data data
;
64 data
.pattern
= pattern
;
66 if (format
== NULL
|| *format
== '\0' || !strcmp(format
, "short"))
68 else if (!strcmp(format
, "medium"))
70 else if (!strcmp(format
, "full"))
73 die("invalid replace format '%s'\n"
74 "valid formats are 'short', 'medium' and 'full'\n",
77 for_each_replace_ref(show_reference
, (void *) &data
);
82 typedef int (*each_replace_name_fn
)(const char *name
, const char *ref
,
83 const unsigned char *sha1
);
85 static int for_each_replace_name(const char **argv
, each_replace_name_fn fn
)
87 const char **p
, *full_hex
;
90 unsigned char sha1
[20];
92 for (p
= argv
; *p
; p
++) {
93 if (get_sha1(*p
, sha1
)) {
94 error("Failed to resolve '%s' as a valid ref.", *p
);
98 full_hex
= sha1_to_hex(sha1
);
99 snprintf(ref
, sizeof(ref
), "refs/replace/%s", full_hex
);
100 /* read_ref() may reuse the buffer */
101 full_hex
= ref
+ strlen("refs/replace/");
102 if (read_ref(ref
, sha1
)) {
103 error("replace ref '%s' not found.", full_hex
);
107 if (fn(full_hex
, ref
, sha1
))
113 static int delete_replace_ref(const char *name
, const char *ref
,
114 const unsigned char *sha1
)
116 if (delete_ref(ref
, sha1
, 0))
118 printf("Deleted replace ref '%s'\n", name
);
122 static int replace_object(const char *object_ref
, const char *replace_ref
,
125 unsigned char object
[20], prev
[20], repl
[20];
126 enum object_type obj_type
, repl_type
;
128 struct ref_lock
*lock
;
130 if (get_sha1(object_ref
, object
))
131 die("Failed to resolve '%s' as a valid ref.", object_ref
);
132 if (get_sha1(replace_ref
, repl
))
133 die("Failed to resolve '%s' as a valid ref.", replace_ref
);
135 if (snprintf(ref
, sizeof(ref
),
137 sha1_to_hex(object
)) > sizeof(ref
) - 1)
138 die("replace ref name too long: %.*s...", 50, ref
);
139 if (check_refname_format(ref
, 0))
140 die("'%s' is not a valid ref name.", ref
);
142 obj_type
= sha1_object_info(object
, NULL
);
143 repl_type
= sha1_object_info(repl
, NULL
);
144 if (!force
&& obj_type
!= repl_type
)
145 die("Objects must be of the same type.\n"
146 "'%s' points to a replaced object of type '%s'\n"
147 "while '%s' points to a replacement object of type '%s'.",
148 object_ref
, typename(obj_type
),
149 replace_ref
, typename(repl_type
));
151 if (read_ref(ref
, prev
))
154 die("replace ref '%s' already exists", ref
);
156 lock
= lock_any_ref_for_update(ref
, prev
, 0, NULL
);
158 die("%s: cannot lock the ref", ref
);
159 if (write_ref_sha1(lock
, repl
, NULL
) < 0)
160 die("%s: cannot update the ref", ref
);
165 int cmd_replace(int argc
, const char **argv
, const char *prefix
)
167 int list
= 0, delete = 0, force
= 0;
168 const char *format
= NULL
;
169 struct option options
[] = {
170 OPT_BOOL('l', "list", &list
, N_("list replace refs")),
171 OPT_BOOL('d', "delete", &delete, N_("delete replace refs")),
172 OPT_BOOL('f', "force", &force
, N_("replace the ref if it exists")),
173 OPT_STRING(0, "format", &format
, N_("format"), N_("use this format")),
177 argc
= parse_options(argc
, argv
, prefix
, options
, git_replace_usage
, 0);
180 usage_msg_opt("-l and -d cannot be used together",
181 git_replace_usage
, options
);
183 if (format
&& delete)
184 usage_msg_opt("--format and -d cannot be used together",
185 git_replace_usage
, options
);
187 if (force
&& (list
|| delete))
188 usage_msg_opt("-f cannot be used with -d or -l",
189 git_replace_usage
, options
);
194 usage_msg_opt("-d needs at least one argument",
195 git_replace_usage
, options
);
196 return for_each_replace_name(argv
, delete_replace_ref
);
202 usage_msg_opt("bad number of arguments",
203 git_replace_usage
, options
);
205 usage_msg_opt("--format cannot be used when not listing",
206 git_replace_usage
, options
);
207 return replace_object(argv
[0], argv
[1], force
);
210 /* List refs, even if "list" is not set */
212 usage_msg_opt("only one pattern can be given with -l",
213 git_replace_usage
, options
);
215 usage_msg_opt("-f needs some arguments",
216 git_replace_usage
, options
);
218 return list_replace_refs(argv
[0], format
);