Commit 54b0c1e0 authored by Christian Couder's avatar Christian Couder Committed by Junio C Hamano

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's avatarChristian Couder <chriscool@tuxfamily.org>
Signed-off-by: default avatarJunio C Hamano <gitster@pobox.com>
parent dae556bd
......@@ -602,6 +602,7 @@ BUILTIN_OBJS += builtin-read-tree.o
BUILTIN_OBJS += builtin-receive-pack.o
BUILTIN_OBJS += builtin-reflog.o
BUILTIN_OBJS += builtin-remote.o
BUILTIN_OBJS += builtin-replace.o
BUILTIN_OBJS += builtin-rerere.o
BUILTIN_OBJS += builtin-reset.o
BUILTIN_OBJS += builtin-rev-list.o
......
/*
* Builtin "git replace"
*
* Copyright (c) 2008 Christian Couder <chriscool@tuxfamily.org>
*
* Based on 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.
*/
#include "cache.h"
#include "builtin.h"
#include "refs.h"
#include "parse-options.h"
static const char * const git_replace_usage[] = {
"git replace -d <object>...",
"git replace -l [<pattern>]",
NULL
};
static int show_reference(const char *refname, const unsigned char *sha1,
int flag, void *cb_data)
{
const char *pattern = cb_data;
if (!fnmatch(pattern, refname, 0))
printf("%s\n", refname);
return 0;
}
static int list_replace_refs(const char *pattern)
{
if (pattern == NULL)
pattern = "*";
for_each_replace_ref(show_reference, (void *) pattern);
return 0;
}
typedef int (*each_replace_name_fn)(const char *name, const char *ref,
const unsigned char *sha1);
static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
{
const char **p;
char ref[PATH_MAX];
int had_error = 0;
unsigned char sha1[20];
for (p = argv; *p; p++) {
if (snprintf(ref, sizeof(ref), "refs/replace/%s", *p)
>= sizeof(ref)) {
error("replace ref name too long: %.*s...", 50, *p);
had_error = 1;
continue;
}
if (!resolve_ref(ref, sha1, 1, NULL)) {
error("replace ref '%s' not found.", *p);
had_error = 1;
continue;
}
if (fn(*p, ref, sha1))
had_error = 1;
}
return had_error;
}
static int delete_replace_ref(const char *name, const char *ref,
const unsigned char *sha1)
{
if (delete_ref(ref, sha1, 0))
return 1;
printf("Deleted replace ref '%s'\n", name);
return 0;
}
int cmd_replace(int argc, const char **argv, const char *prefix)
{
int list = 0, delete = 0;
struct option options[] = {
OPT_BOOLEAN('l', NULL, &list, "list replace refs"),
OPT_BOOLEAN('d', NULL, &delete, "delete replace refs"),
OPT_END()
};
argc = parse_options(argc, argv, options, git_replace_usage, 0);
if (list && delete)
usage_with_options(git_replace_usage, options);
if (delete) {
if (argc < 1)
usage_with_options(git_replace_usage, options);
return for_each_replace_name(argv, delete_replace_ref);
}
/* List refs, even if "list" is not set */
if (argc > 1)
usage_with_options(git_replace_usage, options);
return list_replace_refs(argv[0]);
}
......@@ -112,5 +112,6 @@ extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
extern int cmd_verify_pack(int argc, const char **argv, const char *prefix);
extern int cmd_show_ref(int argc, const char **argv, const char *prefix);
extern int cmd_pack_refs(int argc, const char **argv, const char *prefix);
extern int cmd_replace(int argc, const char **argv, const char *prefix);
#endif
......@@ -340,6 +340,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "receive-pack", cmd_receive_pack },
{ "reflog", cmd_reflog, RUN_SETUP },
{ "remote", cmd_remote, RUN_SETUP },
{ "replace", cmd_replace, RUN_SETUP },
{ "repo-config", cmd_config },
{ "rerere", cmd_rerere, RUN_SETUP },
{ "reset", cmd_reset, RUN_SETUP },
......
......@@ -105,6 +105,18 @@ test_expect_success 'repack, clone and fetch work' '
cd ..
'
test_expect_success '"git replace" listing and deleting' '
test "$HASH2" = "$(git replace -l)" &&
test "$HASH2" = "$(git replace)" &&
aa=${HASH2%??????????????????????????????????????} &&
test "$HASH2" = "$(git replace -l "$aa*")" &&
test_must_fail git replace -d $R &&
test_must_fail git replace -d &&
test_must_fail git replace -l -d $HASH2 &&
git replace -d $HASH2 &&
test -z "$(git replace -l)"
'
#
#
test_done
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment