pseudorefs: create and use pseudoref update and delete functions
Pseudorefs should not be updated through the ref transaction API, because alternate ref backends still need to store pseudorefs in GIT_DIR (instead of wherever they store refs). Instead, change update_ref and delete_ref to call pseudoref-specific functions. Signed-off-by: David Turner <dturner@twopensource.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
David Turner committed
Jul 31, 2015 at 02:06 UTC
74ec19d4be76c52b872e6f95b39ecbfbe5d9100c
1 file changed
+93
-8
refs.c
+93
-8
@@ -2847,11 +2847,87 @@ enum ref_type ref_type(const char *refname)
2847
return REF_TYPE_NORMAL;
2848
}
2849
2850
+static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,
2851
+ const unsigned char *old_sha1, struct strbuf *err)
2852
+{
2853
+ const char *filename;
2854
+ int fd;
2855
+ static struct lock_file lock;
2856
+ struct strbuf buf = STRBUF_INIT;
2857
+ int ret = -1;
2858
+
2859
+ strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1));
2860
+
2861
+ filename = git_path("%s", pseudoref);
2862
+ fd = hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR);
2863
+ if (fd < 0) {
2864
+ strbuf_addf(err, "Could not open '%s' for writing: %s",
2865
+ filename, strerror(errno));
2866
+ return -1;
2867
+ }
2868
+
2869
+ if (old_sha1) {
2870
+ unsigned char actual_old_sha1[20];
2871
+ read_ref(pseudoref, actual_old_sha1);
2872
+ if (hashcmp(actual_old_sha1, old_sha1)) {
2873
+ strbuf_addf(err, "Unexpected sha1 when writing %s", pseudoref);
2874
+ rollback_lock_file(&lock);
2875
+ goto done;
2876
+ }
2877
+ }
2878
+
2879
+ if (write_in_full(fd, buf.buf, buf.len) != buf.len) {
2880
+ strbuf_addf(err, "Could not write to '%s'", filename);
2881
+ rollback_lock_file(&lock);
2882
+ goto done;
2883
+ }
2884
+
2885
+ commit_lock_file(&lock);
2886
+ ret = 0;
2887
+done:
2888
+ strbuf_release(&buf);
2889
+ return ret;
2890
+}
2891
+
2892
+static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1)
2893
+{
2894
+ static struct lock_file lock;
2895
+ const char *filename;
2896
+
2897
+ filename = git_path("%s", pseudoref);
2898
+
2899
+ if (old_sha1 && !is_null_sha1(old_sha1)) {
2900
+ int fd;
2901
+ unsigned char actual_old_sha1[20];
2902
+
2903
+ fd = hold_lock_file_for_update(&lock, filename,
2904
+ LOCK_DIE_ON_ERROR);
2905
+ if (fd < 0)
2906
+ die_errno(_("Could not open '%s' for writing"), filename);
2907
+ read_ref(pseudoref, actual_old_sha1);
2908
+ if (hashcmp(actual_old_sha1, old_sha1)) {
2909
+ warning("Unexpected sha1 when deleting %s", pseudoref);
2910
+ rollback_lock_file(&lock);
2911
+ return -1;
2912
+ }
2913
+
2914
+ unlink(filename);
2915
+ rollback_lock_file(&lock);
2916
+ } else {
2917
+ unlink(filename);
2918
+ }
2919
+
2920
+ return 0;
2921
+}
2922
+
2923
int delete_ref(const char *refname, const unsigned char *sha1, unsigned int flags)
2924
{
2925
struct ref_transaction *transaction;
2926
struct strbuf err = STRBUF_INIT;
2927
2928
+ if (ref_type(refname) == REF_TYPE_PSEUDOREF)
2929
+ return delete_pseudoref(refname, sha1);
2930
+
2931
transaction = ref_transaction_begin(&err);
2932
if (!transaction ||
2933
ref_transaction_delete(transaction, refname,
@@ -3908,17 +3984,25 @@ int update_ref(const char *msg, const char *refname,
3984
const unsigned char *new_sha1, const unsigned char *old_sha1,
3985
unsigned int flags, enum action_on_err onerr)
3986
{
3911
- struct ref_transaction *t;
3987
+ struct ref_transaction *t = NULL;
3988
struct strbuf err = STRBUF_INIT;
3989
+ int ret = 0;
3990
3914
- t = ref_transaction_begin(&err);
3915
- if (!t ||
3916
- ref_transaction_update(t, refname, new_sha1, old_sha1,
3917
- flags, msg, &err) ||
3918
- ref_transaction_commit(t, &err)) {
3991
+ if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
3992
+ ret = write_pseudoref(refname, new_sha1, old_sha1, &err);
3993
+ } else {
3994
+ t = ref_transaction_begin(&err);
3995
+ if (!t ||
3996
+ ref_transaction_update(t, refname, new_sha1, old_sha1,
3997
+ flags, msg, &err) ||
3998
+ ref_transaction_commit(t, &err)) {
3999
+ ret = 1;
4000
+ ref_transaction_free(t);
4001
+ }
4002
+ }
4003
+ if (ret) {
4004
const char *str = "update_ref failed for ref '%s': %s";
4005
3921
- ref_transaction_free(t);
4006
switch (onerr) {
4007
case UPDATE_REFS_MSG_ON_ERR:
4008
error(str, refname, err.buf);
@@ -3933,7 +4017,8 @@ int update_ref(const char *msg, const char *refname,
4017
return 1;
4018
}
4019
strbuf_release(&err);
3936
- ref_transaction_free(t);
4020
+ if (t)
4021
+ ref_transaction_free(t);
4022
return 0;
4023
}
4024