mirror of
https://github.com/git/git.git
synced 2025-12-12 20:36:24 +01:00
Merge branch 'kn/fix-fetch-backfill-tag-with-batched-ref-updates' into jch
"git fetch" that involves fetching tags, when a tag being fetched needs to overwrite existing one, failed to fetch other tags, which has been corrected. * kn/fix-fetch-backfill-tag-with-batched-ref-updates: fetch: fix failed batched updates skipping operations fetch: fix non-conflicting tags not being committed fetch: extract out reference committing logic
This commit is contained in:
@@ -1681,6 +1681,36 @@ static void ref_transaction_rejection_handler(const char *refname,
|
||||
*data->retcode = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Commit the reference transaction. If it isn't an atomic transaction, handle
|
||||
* rejected updates as part of using batched updates.
|
||||
*/
|
||||
static int commit_ref_transaction(struct ref_transaction **transaction,
|
||||
bool is_atomic, const char *remote_name,
|
||||
struct strbuf *err)
|
||||
{
|
||||
int retcode = ref_transaction_commit(*transaction, err);
|
||||
if (retcode)
|
||||
goto out;
|
||||
|
||||
if (!is_atomic) {
|
||||
struct ref_rejection_data data = {
|
||||
.conflict_msg_shown = 0,
|
||||
.remote_name = remote_name,
|
||||
.retcode = &retcode,
|
||||
};
|
||||
|
||||
ref_transaction_for_each_rejected_update(*transaction,
|
||||
ref_transaction_rejection_handler,
|
||||
&data);
|
||||
}
|
||||
|
||||
out:
|
||||
ref_transaction_free(*transaction);
|
||||
*transaction = NULL;
|
||||
return retcode;
|
||||
}
|
||||
|
||||
static int do_fetch(struct transport *transport,
|
||||
struct refspec *rs,
|
||||
const struct fetch_config *config)
|
||||
@@ -1853,33 +1883,14 @@ static int do_fetch(struct transport *transport,
|
||||
if (retcode)
|
||||
goto cleanup;
|
||||
|
||||
retcode = ref_transaction_commit(transaction, &err);
|
||||
if (retcode) {
|
||||
/*
|
||||
* Explicitly handle transaction cleanup to avoid
|
||||
* aborting an already closed transaction.
|
||||
*/
|
||||
ref_transaction_free(transaction);
|
||||
transaction = NULL;
|
||||
retcode = commit_ref_transaction(&transaction, atomic_fetch,
|
||||
transport->remote->name, &err);
|
||||
/*
|
||||
* With '--atomic', bail out if the transaction fails. Without '--atomic',
|
||||
* continue to fetch head and perform other post-fetch operations.
|
||||
*/
|
||||
if (retcode && atomic_fetch)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!atomic_fetch) {
|
||||
struct ref_rejection_data data = {
|
||||
.retcode = &retcode,
|
||||
.conflict_msg_shown = 0,
|
||||
.remote_name = transport->remote->name,
|
||||
};
|
||||
|
||||
ref_transaction_for_each_rejected_update(transaction,
|
||||
ref_transaction_rejection_handler,
|
||||
&data);
|
||||
if (retcode) {
|
||||
ref_transaction_free(transaction);
|
||||
transaction = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
commit_fetch_head(&fetch_head);
|
||||
|
||||
@@ -1945,6 +1956,14 @@ static int do_fetch(struct transport *transport,
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/*
|
||||
* When using batched updates, we want to commit the non-rejected
|
||||
* updates and also handle the rejections.
|
||||
*/
|
||||
if (retcode && !atomic_fetch && transaction)
|
||||
commit_ref_transaction(&transaction, false,
|
||||
transport->remote->name, &err);
|
||||
|
||||
if (retcode) {
|
||||
if (err.len) {
|
||||
error("%s", err.buf);
|
||||
|
||||
150
t/t5510-fetch.sh
150
t/t5510-fetch.sh
@@ -1552,6 +1552,7 @@ test_expect_success CASE_INSENSITIVE_FS,REFFILES 'D/F conflict on case insensiti
|
||||
'
|
||||
|
||||
test_expect_success REFFILES 'D/F conflict on case sensitive filesystem with lock' '
|
||||
test_when_finished rm -rf base repo &&
|
||||
(
|
||||
git init --ref-format=reftable base &&
|
||||
cd base &&
|
||||
@@ -1577,6 +1578,155 @@ test_expect_success REFFILES 'D/F conflict on case sensitive filesystem with loc
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'fetch --tags fetches existing tags' '
|
||||
test_when_finished rm -rf base repo &&
|
||||
|
||||
git init base &&
|
||||
git -C base commit --allow-empty -m "empty-commit" &&
|
||||
|
||||
git clone --bare base repo &&
|
||||
|
||||
git -C base tag tag-1 &&
|
||||
git -C repo for-each-ref >out &&
|
||||
test_grep ! "tag-1" out &&
|
||||
git -C repo fetch --tags &&
|
||||
git -C repo for-each-ref >out &&
|
||||
test_grep "tag-1" out
|
||||
'
|
||||
|
||||
test_expect_success 'fetch --tags fetches non-conflicting tags' '
|
||||
test_when_finished rm -rf base repo &&
|
||||
|
||||
git init base &&
|
||||
git -C base commit --allow-empty -m "empty-commit" &&
|
||||
git -C base tag tag-1 &&
|
||||
|
||||
git clone --bare base repo &&
|
||||
|
||||
git -C base tag tag-2 &&
|
||||
git -C repo for-each-ref >out &&
|
||||
test_grep ! "tag-2" out &&
|
||||
|
||||
git -C base commit --allow-empty -m "second empty-commit" &&
|
||||
git -C base tag -f tag-1 &&
|
||||
|
||||
test_must_fail git -C repo fetch --tags 2>out &&
|
||||
test_grep "tag-1 (would clobber existing tag)" out &&
|
||||
git -C repo for-each-ref >out &&
|
||||
test_grep "tag-2" out
|
||||
'
|
||||
|
||||
test_expect_success "backfill tags when providing a refspec" '
|
||||
test_when_finished rm -rf source target &&
|
||||
|
||||
git init source &&
|
||||
git -C source commit --allow-empty --message common &&
|
||||
git clone file://"$(pwd)"/source target &&
|
||||
(
|
||||
cd source &&
|
||||
test_commit history &&
|
||||
test_commit fetch-me
|
||||
) &&
|
||||
|
||||
# The "history" tag is backfilled even though we requested
|
||||
# to only fetch HEAD
|
||||
git -C target fetch origin HEAD:branch &&
|
||||
git -C target tag -l >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
fetch-me
|
||||
history
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success REFFILES "FETCH_HEAD is updated even if ref updates fail" '
|
||||
test_when_finished rm -rf base repo &&
|
||||
|
||||
git init base &&
|
||||
(
|
||||
cd base &&
|
||||
test_commit "updated" &&
|
||||
|
||||
git update-ref refs/heads/foo @ &&
|
||||
git update-ref refs/heads/branch @
|
||||
) &&
|
||||
|
||||
git init --bare repo &&
|
||||
(
|
||||
cd repo &&
|
||||
rm -f FETCH_HEAD &&
|
||||
git remote add origin ../base &&
|
||||
>refs/heads/foo.lock &&
|
||||
test_must_fail git fetch -f origin "refs/heads/*:refs/heads/*" 2>err &&
|
||||
test_grep "error: fetching ref refs/heads/foo failed: reference already exists" err &&
|
||||
test_grep "branch ${SQ}branch${SQ} of ../base" FETCH_HEAD &&
|
||||
test_grep "branch ${SQ}foo${SQ} of ../base" FETCH_HEAD
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success "upstream tracking info is added with --set-upstream" '
|
||||
test_when_finished rm -rf base repo &&
|
||||
|
||||
git init --initial-branch=main base &&
|
||||
test_commit -C base "updated" &&
|
||||
|
||||
git init --bare --initial-branch=main repo &&
|
||||
(
|
||||
cd repo &&
|
||||
git remote add origin ../base &&
|
||||
git fetch origin --set-upstream main &&
|
||||
git config get branch.main.remote >actual &&
|
||||
echo "origin" >expect &&
|
||||
test_cmp expect actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success REFFILES "upstream tracking info is added even with conflicts" '
|
||||
test_when_finished rm -rf base repo &&
|
||||
|
||||
git init --initial-branch=main base &&
|
||||
test_commit -C base "updated" &&
|
||||
|
||||
git init --bare --initial-branch=main repo &&
|
||||
(
|
||||
cd repo &&
|
||||
git remote add origin ../base &&
|
||||
test_must_fail git config get branch.main.remote &&
|
||||
|
||||
mkdir -p refs/remotes/origin &&
|
||||
>refs/remotes/origin/main.lock &&
|
||||
test_must_fail git fetch origin --set-upstream main &&
|
||||
git config get branch.main.remote >actual &&
|
||||
echo "origin" >expect &&
|
||||
test_cmp expect actual
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success REFFILES "HEAD is updated even with conflicts" '
|
||||
test_when_finished rm -rf base repo &&
|
||||
|
||||
git init base &&
|
||||
(
|
||||
cd base &&
|
||||
test_commit "updated" &&
|
||||
|
||||
git update-ref refs/heads/foo @ &&
|
||||
git update-ref refs/heads/branch @
|
||||
) &&
|
||||
|
||||
git init --bare repo &&
|
||||
(
|
||||
cd repo &&
|
||||
git remote add origin ../base &&
|
||||
|
||||
test_path_is_missing refs/remotes/origin/HEAD &&
|
||||
mkdir -p refs/remotes/origin &&
|
||||
>refs/remotes/origin/branch.lock &&
|
||||
test_must_fail git fetch origin &&
|
||||
test -f refs/remotes/origin/HEAD
|
||||
)
|
||||
'
|
||||
|
||||
. "$TEST_DIRECTORY"/lib-httpd.sh
|
||||
start_httpd
|
||||
|
||||
|
||||
Reference in New Issue
Block a user