2394
2395
new_update = ref_transaction_add_update(
2396
transaction, referent, new_flags,
2397
- &update->new_oid, &update->old_oid,
2398
- NULL, NULL, update->msg);
2397
+ update->new_target ? NULL : &update->new_oid,
2398
+ update->old_target ? NULL : &update->old_oid,
2399
+ update->new_target, update->old_target, update->msg);
2400
2401
new_update->parent_update = update;
2402
2484
2485
files_assert_main_repository(refs, "lock_ref_for_update");
2486
2486
- if ((update->flags & REF_HAVE_NEW) && is_null_oid(&update->new_oid))
2487
+ if ((update->flags & REF_HAVE_NEW) && ref_update_has_null_new_value(update))
2488
update->flags |= REF_DELETING;
2489
2490
if (head_ref) {
2527
ret = TRANSACTION_GENERIC_ERROR;
2528
goto out;
2529
}
2529
- } else if (check_old_oid(update, &lock->old_oid, err)) {
2530
+ }
2531
+
2532
+ if (update->old_target) {
2533
+ if (ref_update_check_old_target(referent.buf, update, err)) {
2534
+ ret = TRANSACTION_GENERIC_ERROR;
2535
+ goto out;
2536
+ }
2537
+ } else if (check_old_oid(update, &lock->old_oid, err)) {
2538
ret = TRANSACTION_GENERIC_ERROR;
2539
goto out;
2540
}
2555
} else {
2556
struct ref_update *parent_update;
2557
2550
- if (check_old_oid(update, &lock->old_oid, err)) {
2558
+ /*
2559
+ * Even if the ref is a regular ref, if `old_target` is set, we
2560
+ * check the referent value. Ideally `old_target` should only
2561
+ * be set for symrefs, but we're strict about its usage.
2562
+ */
2563
+ if (update->old_target) {
2564
+ if (ref_update_check_old_target(referent.buf, update, err)) {
2565
+ ret = TRANSACTION_GENERIC_ERROR;
2566
+ goto out;
2567
+ }
2568
+ } else if (check_old_oid(update, &lock->old_oid, err)) {
2569
ret = TRANSACTION_GENERIC_ERROR;
2570
goto out;
2571
}
2583
}
2584
}
2585
2568
- if ((update->flags & REF_HAVE_NEW) &&
2569
- !(update->flags & REF_DELETING) &&
2570
- !(update->flags & REF_LOG_ONLY)) {
2586
+ if (update->new_target && !(update->flags & REF_LOG_ONLY)) {
2587
+ if (create_symref_lock(refs, lock, update->refname,
2588
+ update->new_target, err)) {
2589
+ ret = TRANSACTION_GENERIC_ERROR;
2590
+ goto out;
2591
+ }
2592
+
2593
+ if (close_ref_gently(lock)) {
2594
+ strbuf_addf(err, "couldn't close '%s.lock'",
2595
+ update->refname);
2596
+ ret = TRANSACTION_GENERIC_ERROR;
2597
+ goto out;
2598
+ }
2599
+
2600
+ /*
2601
+ * Once we have created the symref lock, the commit
2602
+ * phase of the transaction only needs to commit the lock.
2603
+ */
2604
+ update->flags |= REF_NEEDS_COMMIT;
2605
+ } else if ((update->flags & REF_HAVE_NEW) &&
2606
+ !(update->flags & REF_DELETING) &&
2607
+ !(update->flags & REF_LOG_ONLY)) {
2608
if (!(update->type & REF_ISSYMREF) &&
2609
oideq(&lock->old_oid, &update->new_oid)) {
2610
/*
2867
return ret;
2868
}
2869
2870
+static int parse_and_write_reflog(struct files_ref_store *refs,
2871
+ struct ref_update *update,
2872
+ struct ref_lock *lock,
2873
+ struct strbuf *err)
2874
+{
2875
+ if (update->new_target) {
2876
+ /*
2877
+ * We want to get the resolved OID for the target, to ensure
2878
+ * that the correct value is added to the reflog.
2879
+ */
2880
+ if (!refs_resolve_ref_unsafe(&refs->base, update->new_target,
2881
+ RESOLVE_REF_READING,
2882
+ &update->new_oid, NULL)) {
2883
+ /*
2884
+ * TODO: currently we skip creating reflogs for dangling
2885
+ * symref updates. It would be nice to capture this as
2886
+ * zero oid updates however.
2887
+ */
2888
+ return 0;
2889
+ }
2890
+ }
2891
+
2892
+ if (files_log_ref_write(refs, lock->ref_name, &lock->old_oid,
2893
+ &update->new_oid, update->msg, update->flags, err)) {
2894
+ char *old_msg = strbuf_detach(err, NULL);
2895
+
2896
+ strbuf_addf(err, "cannot update the ref '%s': %s",
2897
+ lock->ref_name, old_msg);
2898
+ free(old_msg);
2899
+ unlock_ref(lock);
2900
+ update->backend_data = NULL;
2901
+ return -1;
2902
+ }
2903
+
2904
+ return 0;
2905
+}
2906
+
2907
static int files_transaction_finish(struct ref_store *ref_store,
2908
struct ref_transaction *transaction,
2909
struct strbuf *err)
2934
2935
if (update->flags & REF_NEEDS_COMMIT ||
2936
update->flags & REF_LOG_ONLY) {
2863
- if (files_log_ref_write(refs,
2864
- lock->ref_name,
2865
- &lock->old_oid,
2866
- &update->new_oid,
2867
- update->msg, update->flags,
2868
- err)) {
2869
- char *old_msg = strbuf_detach(err, NULL);
2870
-
2871
- strbuf_addf(err, "cannot update the ref '%s': %s",
2872
- lock->ref_name, old_msg);
2873
- free(old_msg);
2874
- unlock_ref(lock);
2875
- update->backend_data = NULL;
2937
+ if (parse_and_write_reflog(refs, update, lock, err)) {
2938
ret = TRANSACTION_GENERIC_ERROR;
2939
goto cleanup;
2940
}
2941
}
2942
+
2943
+ /*
2944
+ * We try creating a symlink, if that succeeds we continue to the
2945
+ * next update. If not, we try and create a regular symref.
2946
+ */
2947
+ if (update->new_target && prefer_symlink_refs)
2948
+ if (!create_ref_symlink(lock, update->new_target))
2949
+ continue;
2950
+
2951
if (update->flags & REF_NEEDS_COMMIT) {
2952
clear_loose_ref_cache(refs);
2953
if (commit_ref(lock)) {