@matheusbsbs / matheus-bagliano / commits / 54b0c1e041
Fork 0

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