update-ref: add --batch-updates flag for stdin mode
When updating multiple references through stdin, Git's update-ref command normally aborts the entire transaction if any single update fails. This atomic behavior prevents partial updates. Introduce a new batch update system, where the updates the performed together similar but individual updates are allowed to fail. Add a new `--batch-updates` flag that allows the transaction to continue even when individual reference updates fail. This flag can only be used in `--stdin` mode and builds upon the batch update support added to the refs subsystem in the previous commits. When enabled, failed updates are reported in the following format: rejected SP (<old-oid> | <old-target>) SP (<new-oid> | <new-target>) SP <rejection-reason> LF Update the documentation to reflect this change and also tests to cover different scenarios where an update could be rejected. Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Acked-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>main
parent
31726bb90d
commit
221e8fcb7f
|
@ -7,8 +7,10 @@ git-update-ref - Update the object name stored in a ref safely
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[synopsis]
|
||||||
'git update-ref' [-m <reason>] [--no-deref] (-d <ref> [<old-oid>] | [--create-reflog] <ref> <new-oid> [<old-oid>] | --stdin [-z])
|
git update-ref [-m <reason>] [--no-deref] -d <ref> [<old-oid>]
|
||||||
|
git update-ref [-m <reason>] [--no-deref] [--create-reflog] <ref> <new-oid> [<old-oid>]
|
||||||
|
git update-ref [-m <reason>] [--no-deref] --stdin [-z] [--batch-updates]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
@ -57,6 +59,14 @@ performs all modifications together. Specify commands of the form:
|
||||||
With `--create-reflog`, update-ref will create a reflog for each ref
|
With `--create-reflog`, update-ref will create a reflog for each ref
|
||||||
even if one would not ordinarily be created.
|
even if one would not ordinarily be created.
|
||||||
|
|
||||||
|
With `--batch-updates`, update-ref executes the updates in a batch but allows
|
||||||
|
individual updates to fail due to invalid or incorrect user input, applying only
|
||||||
|
the successful updates. However, system-related errors—such as I/O failures or
|
||||||
|
memory issues—will result in a full failure of all batched updates. Any failed
|
||||||
|
updates will be reported in the following format:
|
||||||
|
|
||||||
|
rejected SP (<old-oid> | <old-target>) SP (<new-oid> | <new-target>) SP <rejection-reason> LF
|
||||||
|
|
||||||
Quote fields containing whitespace as if they were strings in C source
|
Quote fields containing whitespace as if they were strings in C source
|
||||||
code; i.e., surrounded by double-quotes and with backslash escapes.
|
code; i.e., surrounded by double-quotes and with backslash escapes.
|
||||||
Use 40 "0" characters or the empty string to specify a zero value. To
|
Use 40 "0" characters or the empty string to specify a zero value. To
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
#include "hex.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "object-name.h"
|
#include "object-name.h"
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
|
@ -13,7 +14,7 @@
|
||||||
static const char * const git_update_ref_usage[] = {
|
static const char * const git_update_ref_usage[] = {
|
||||||
N_("git update-ref [<options>] -d <refname> [<old-oid>]"),
|
N_("git update-ref [<options>] -d <refname> [<old-oid>]"),
|
||||||
N_("git update-ref [<options>] <refname> <new-oid> [<old-oid>]"),
|
N_("git update-ref [<options>] <refname> <new-oid> [<old-oid>]"),
|
||||||
N_("git update-ref [<options>] --stdin [-z]"),
|
N_("git update-ref [<options>] --stdin [-z] [--batch-updates]"),
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -565,6 +566,49 @@ static void parse_cmd_abort(struct ref_transaction *transaction,
|
||||||
report_ok("abort");
|
report_ok("abort");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_rejected_refs(const char *refname,
|
||||||
|
const struct object_id *old_oid,
|
||||||
|
const struct object_id *new_oid,
|
||||||
|
const char *old_target,
|
||||||
|
const char *new_target,
|
||||||
|
enum ref_transaction_error err,
|
||||||
|
void *cb_data UNUSED)
|
||||||
|
{
|
||||||
|
struct strbuf sb = STRBUF_INIT;
|
||||||
|
const char *reason = "";
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
|
case REF_TRANSACTION_ERROR_NAME_CONFLICT:
|
||||||
|
reason = "refname conflict";
|
||||||
|
break;
|
||||||
|
case REF_TRANSACTION_ERROR_CREATE_EXISTS:
|
||||||
|
reason = "reference already exists";
|
||||||
|
break;
|
||||||
|
case REF_TRANSACTION_ERROR_NONEXISTENT_REF:
|
||||||
|
reason = "reference does not exist";
|
||||||
|
break;
|
||||||
|
case REF_TRANSACTION_ERROR_INCORRECT_OLD_VALUE:
|
||||||
|
reason = "incorrect old value provided";
|
||||||
|
break;
|
||||||
|
case REF_TRANSACTION_ERROR_INVALID_NEW_VALUE:
|
||||||
|
reason = "invalid new value provided";
|
||||||
|
break;
|
||||||
|
case REF_TRANSACTION_ERROR_EXPECTED_SYMREF:
|
||||||
|
reason = "expected symref but found regular ref";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
reason = "unkown failure";
|
||||||
|
}
|
||||||
|
|
||||||
|
strbuf_addf(&sb, "rejected %s %s %s %s\n", refname,
|
||||||
|
new_oid ? oid_to_hex(new_oid) : new_target,
|
||||||
|
old_oid ? oid_to_hex(old_oid) : old_target,
|
||||||
|
reason);
|
||||||
|
|
||||||
|
fwrite(sb.buf, sb.len, 1, stdout);
|
||||||
|
strbuf_release(&sb);
|
||||||
|
}
|
||||||
|
|
||||||
static void parse_cmd_commit(struct ref_transaction *transaction,
|
static void parse_cmd_commit(struct ref_transaction *transaction,
|
||||||
const char *next, const char *end UNUSED)
|
const char *next, const char *end UNUSED)
|
||||||
{
|
{
|
||||||
|
@ -573,6 +617,10 @@ static void parse_cmd_commit(struct ref_transaction *transaction,
|
||||||
die("commit: extra input: %s", next);
|
die("commit: extra input: %s", next);
|
||||||
if (ref_transaction_commit(transaction, &error))
|
if (ref_transaction_commit(transaction, &error))
|
||||||
die("commit: %s", error.buf);
|
die("commit: %s", error.buf);
|
||||||
|
|
||||||
|
ref_transaction_for_each_rejected_update(transaction,
|
||||||
|
print_rejected_refs, NULL);
|
||||||
|
|
||||||
report_ok("commit");
|
report_ok("commit");
|
||||||
ref_transaction_free(transaction);
|
ref_transaction_free(transaction);
|
||||||
}
|
}
|
||||||
|
@ -609,7 +657,7 @@ static const struct parse_cmd {
|
||||||
{ "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED },
|
{ "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void update_refs_stdin(void)
|
static void update_refs_stdin(unsigned int flags)
|
||||||
{
|
{
|
||||||
struct strbuf input = STRBUF_INIT, err = STRBUF_INIT;
|
struct strbuf input = STRBUF_INIT, err = STRBUF_INIT;
|
||||||
enum update_refs_state state = UPDATE_REFS_OPEN;
|
enum update_refs_state state = UPDATE_REFS_OPEN;
|
||||||
|
@ -617,7 +665,7 @@ static void update_refs_stdin(void)
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
|
transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
|
||||||
0, &err);
|
flags, &err);
|
||||||
if (!transaction)
|
if (!transaction)
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
|
|
||||||
|
@ -685,7 +733,7 @@ static void update_refs_stdin(void)
|
||||||
*/
|
*/
|
||||||
state = cmd->state;
|
state = cmd->state;
|
||||||
transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
|
transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
|
||||||
0, &err);
|
flags, &err);
|
||||||
if (!transaction)
|
if (!transaction)
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
|
|
||||||
|
@ -701,6 +749,8 @@ static void update_refs_stdin(void)
|
||||||
/* Commit by default if no transaction was requested. */
|
/* Commit by default if no transaction was requested. */
|
||||||
if (ref_transaction_commit(transaction, &err))
|
if (ref_transaction_commit(transaction, &err))
|
||||||
die("%s", err.buf);
|
die("%s", err.buf);
|
||||||
|
ref_transaction_for_each_rejected_update(transaction,
|
||||||
|
print_rejected_refs, NULL);
|
||||||
ref_transaction_free(transaction);
|
ref_transaction_free(transaction);
|
||||||
break;
|
break;
|
||||||
case UPDATE_REFS_STARTED:
|
case UPDATE_REFS_STARTED:
|
||||||
|
@ -727,6 +777,8 @@ int cmd_update_ref(int argc,
|
||||||
struct object_id oid, oldoid;
|
struct object_id oid, oldoid;
|
||||||
int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
|
int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
|
||||||
int create_reflog = 0;
|
int create_reflog = 0;
|
||||||
|
unsigned int flags = 0;
|
||||||
|
|
||||||
struct option options[] = {
|
struct option options[] = {
|
||||||
OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
|
OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
|
||||||
OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
|
OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
|
||||||
|
@ -735,6 +787,8 @@ int cmd_update_ref(int argc,
|
||||||
OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")),
|
OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")),
|
||||||
OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")),
|
OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")),
|
||||||
OPT_BOOL( 0 , "create-reflog", &create_reflog, N_("create a reflog")),
|
OPT_BOOL( 0 , "create-reflog", &create_reflog, N_("create a reflog")),
|
||||||
|
OPT_BIT('0', "batch-updates", &flags, N_("batch reference updates"),
|
||||||
|
REF_TRANSACTION_ALLOW_FAILURE),
|
||||||
OPT_END(),
|
OPT_END(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -756,8 +810,10 @@ int cmd_update_ref(int argc,
|
||||||
usage_with_options(git_update_ref_usage, options);
|
usage_with_options(git_update_ref_usage, options);
|
||||||
if (end_null)
|
if (end_null)
|
||||||
line_termination = '\0';
|
line_termination = '\0';
|
||||||
update_refs_stdin();
|
update_refs_stdin(flags);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (flags & REF_TRANSACTION_ALLOW_FAILURE) {
|
||||||
|
die("--batch-updates can only be used with --stdin");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end_null)
|
if (end_null)
|
||||||
|
|
|
@ -2066,6 +2066,239 @@ do
|
||||||
grep "$(git rev-parse $a) $(git rev-parse $a)" actual
|
grep "$(git rev-parse $a) $(git rev-parse $a)" actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success "stdin $type batch-updates" '
|
||||||
|
git init repo &&
|
||||||
|
test_when_finished "rm -fr repo" &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit commit &&
|
||||||
|
head=$(git rev-parse HEAD) &&
|
||||||
|
|
||||||
|
format_command $type "update refs/heads/ref1" "$head" "$Z" >stdin &&
|
||||||
|
format_command $type "update refs/heads/ref2" "$head" "$Z" >>stdin &&
|
||||||
|
git update-ref $type --stdin --batch-updates <stdin &&
|
||||||
|
echo $head >expect &&
|
||||||
|
git rev-parse refs/heads/ref1 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
git rev-parse refs/heads/ref2 >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success "stdin $type batch-updates with invalid new_oid" '
|
||||||
|
git init repo &&
|
||||||
|
test_when_finished "rm -fr repo" &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit one &&
|
||||||
|
old_head=$(git rev-parse HEAD) &&
|
||||||
|
test_commit two &&
|
||||||
|
head=$(git rev-parse HEAD) &&
|
||||||
|
git update-ref refs/heads/ref1 $head &&
|
||||||
|
git update-ref refs/heads/ref2 $head &&
|
||||||
|
|
||||||
|
format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
|
||||||
|
format_command $type "update refs/heads/ref2" "$(test_oid 001)" "$head" >>stdin &&
|
||||||
|
git update-ref $type --stdin --batch-updates <stdin >stdout &&
|
||||||
|
echo $old_head >expect &&
|
||||||
|
git rev-parse refs/heads/ref1 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
echo $head >expect &&
|
||||||
|
git rev-parse refs/heads/ref2 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_grep -q "invalid new value provided" stdout
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success "stdin $type batch-updates with non-commit new_oid" '
|
||||||
|
git init repo &&
|
||||||
|
test_when_finished "rm -fr repo" &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit one &&
|
||||||
|
old_head=$(git rev-parse HEAD) &&
|
||||||
|
test_commit two &&
|
||||||
|
head=$(git rev-parse HEAD) &&
|
||||||
|
head_tree=$(git rev-parse HEAD^{tree}) &&
|
||||||
|
git update-ref refs/heads/ref1 $head &&
|
||||||
|
git update-ref refs/heads/ref2 $head &&
|
||||||
|
|
||||||
|
format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
|
||||||
|
format_command $type "update refs/heads/ref2" "$head_tree" "$head" >>stdin &&
|
||||||
|
git update-ref $type --stdin --batch-updates <stdin >stdout &&
|
||||||
|
echo $old_head >expect &&
|
||||||
|
git rev-parse refs/heads/ref1 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
echo $head >expect &&
|
||||||
|
git rev-parse refs/heads/ref2 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_grep -q "invalid new value provided" stdout
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success "stdin $type batch-updates with non-existent ref" '
|
||||||
|
git init repo &&
|
||||||
|
test_when_finished "rm -fr repo" &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit one &&
|
||||||
|
old_head=$(git rev-parse HEAD) &&
|
||||||
|
test_commit two &&
|
||||||
|
head=$(git rev-parse HEAD) &&
|
||||||
|
git update-ref refs/heads/ref1 $head &&
|
||||||
|
|
||||||
|
format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
|
||||||
|
format_command $type "update refs/heads/ref2" "$old_head" "$head" >>stdin &&
|
||||||
|
git update-ref $type --stdin --batch-updates <stdin >stdout &&
|
||||||
|
echo $old_head >expect &&
|
||||||
|
git rev-parse refs/heads/ref1 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_must_fail git rev-parse refs/heads/ref2 &&
|
||||||
|
test_grep -q "reference does not exist" stdout
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success "stdin $type batch-updates with dangling symref" '
|
||||||
|
git init repo &&
|
||||||
|
test_when_finished "rm -fr repo" &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit one &&
|
||||||
|
old_head=$(git rev-parse HEAD) &&
|
||||||
|
test_commit two &&
|
||||||
|
head=$(git rev-parse HEAD) &&
|
||||||
|
git update-ref refs/heads/ref1 $head &&
|
||||||
|
git symbolic-ref refs/heads/ref2 refs/heads/nonexistent &&
|
||||||
|
|
||||||
|
format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
|
||||||
|
format_command $type "update refs/heads/ref2" "$old_head" "$head" >>stdin &&
|
||||||
|
git update-ref $type --no-deref --stdin --batch-updates <stdin >stdout &&
|
||||||
|
echo $old_head >expect &&
|
||||||
|
git rev-parse refs/heads/ref1 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
echo $head >expect &&
|
||||||
|
test_must_fail git rev-parse refs/heads/ref2 &&
|
||||||
|
test_grep -q "reference does not exist" stdout
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success "stdin $type batch-updates with regular ref as symref" '
|
||||||
|
git init repo &&
|
||||||
|
test_when_finished "rm -fr repo" &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit one &&
|
||||||
|
old_head=$(git rev-parse HEAD) &&
|
||||||
|
test_commit two &&
|
||||||
|
head=$(git rev-parse HEAD) &&
|
||||||
|
git update-ref refs/heads/ref1 $head &&
|
||||||
|
git update-ref refs/heads/ref2 $head &&
|
||||||
|
|
||||||
|
format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
|
||||||
|
format_command $type "symref-update refs/heads/ref2" "$old_head" "ref" "refs/heads/nonexistent" >>stdin &&
|
||||||
|
git update-ref $type --no-deref --stdin --batch-updates <stdin >stdout &&
|
||||||
|
echo $old_head >expect &&
|
||||||
|
git rev-parse refs/heads/ref1 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
echo $head >expect &&
|
||||||
|
echo $head >expect &&
|
||||||
|
git rev-parse refs/heads/ref2 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_grep -q "expected symref but found regular ref" stdout
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success "stdin $type batch-updates with invalid old_oid" '
|
||||||
|
git init repo &&
|
||||||
|
test_when_finished "rm -fr repo" &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit one &&
|
||||||
|
old_head=$(git rev-parse HEAD) &&
|
||||||
|
test_commit two &&
|
||||||
|
head=$(git rev-parse HEAD) &&
|
||||||
|
git update-ref refs/heads/ref1 $head &&
|
||||||
|
git update-ref refs/heads/ref2 $head &&
|
||||||
|
|
||||||
|
format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
|
||||||
|
format_command $type "update refs/heads/ref2" "$old_head" "$Z" >>stdin &&
|
||||||
|
git update-ref $type --stdin --batch-updates <stdin >stdout &&
|
||||||
|
echo $old_head >expect &&
|
||||||
|
git rev-parse refs/heads/ref1 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
echo $head >expect &&
|
||||||
|
git rev-parse refs/heads/ref2 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_grep -q "reference already exists" stdout
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success "stdin $type batch-updates with incorrect old oid" '
|
||||||
|
git init repo &&
|
||||||
|
test_when_finished "rm -fr repo" &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit one &&
|
||||||
|
old_head=$(git rev-parse HEAD) &&
|
||||||
|
test_commit two &&
|
||||||
|
head=$(git rev-parse HEAD) &&
|
||||||
|
git update-ref refs/heads/ref1 $head &&
|
||||||
|
git update-ref refs/heads/ref2 $head &&
|
||||||
|
|
||||||
|
format_command $type "update refs/heads/ref1" "$old_head" "$head" >stdin &&
|
||||||
|
format_command $type "update refs/heads/ref2" "$head" "$old_head" >>stdin &&
|
||||||
|
git update-ref $type --stdin --batch-updates <stdin >stdout &&
|
||||||
|
echo $old_head >expect &&
|
||||||
|
git rev-parse refs/heads/ref1 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
echo $head >expect &&
|
||||||
|
git rev-parse refs/heads/ref2 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_grep -q "incorrect old value provided" stdout
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success "stdin $type batch-updates refname conflict" '
|
||||||
|
git init repo &&
|
||||||
|
test_when_finished "rm -fr repo" &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit one &&
|
||||||
|
old_head=$(git rev-parse HEAD) &&
|
||||||
|
test_commit two &&
|
||||||
|
head=$(git rev-parse HEAD) &&
|
||||||
|
git update-ref refs/heads/ref/foo $head &&
|
||||||
|
|
||||||
|
format_command $type "update refs/heads/ref/foo" "$old_head" "$head" >stdin &&
|
||||||
|
format_command $type "update refs/heads/ref" "$old_head" "" >>stdin &&
|
||||||
|
git update-ref $type --stdin --batch-updates <stdin >stdout &&
|
||||||
|
echo $old_head >expect &&
|
||||||
|
git rev-parse refs/heads/ref/foo >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_grep -q "refname conflict" stdout
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success "stdin $type batch-updates refname conflict new ref" '
|
||||||
|
git init repo &&
|
||||||
|
test_when_finished "rm -fr repo" &&
|
||||||
|
(
|
||||||
|
cd repo &&
|
||||||
|
test_commit one &&
|
||||||
|
old_head=$(git rev-parse HEAD) &&
|
||||||
|
test_commit two &&
|
||||||
|
head=$(git rev-parse HEAD) &&
|
||||||
|
git update-ref refs/heads/ref/foo $head &&
|
||||||
|
|
||||||
|
format_command $type "update refs/heads/foo" "$old_head" "" >stdin &&
|
||||||
|
format_command $type "update refs/heads/ref" "$old_head" "" >>stdin &&
|
||||||
|
git update-ref $type --stdin --batch-updates <stdin >stdout &&
|
||||||
|
echo $old_head >expect &&
|
||||||
|
git rev-parse refs/heads/foo >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
test_grep -q "refname conflict" stdout
|
||||||
|
)
|
||||||
|
'
|
||||||
done
|
done
|
||||||
|
|
||||||
test_expect_success 'update-ref should also create reflog for HEAD' '
|
test_expect_success 'update-ref should also create reflog for HEAD' '
|
||||||
|
|
Loading…
Reference in New Issue