{"thread":{"id":"39712","subject":"[PATCH 0/6] refs backend preamble","startedAt":"2015-06-24T19:16:22Z","lastAt":"2015-06-25T20:31:34Z","messageCount":16,"participants":["David Turner","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"264752","messageId":"1435173388-8346-1-git-send-email-dturner@twopensource.com","threadId":"39712","inReplyTo":null,"subject":"[PATCH 0/6] refs backend preamble","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-24T19:16:22Z","receivedAt":"2015-06-24T19:16:22Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"This set of patches is a preamble to pluggable ref backends.  The\nintent is to use the ref infrastructure for special refs like\nCHERRY_PICK_HEAD where possible, and to use git plumbing commands to\naccess refs and reflogs instead of directly writing files to the .git\ndirectory.\n\nThis series is on top of pu at 9039c98c.\n"},{"id":"264755","messageId":"1435173388-8346-2-git-send-email-dturner@twopensource.com","threadId":"39712","inReplyTo":"1435173388-8346-1-git-send-email-dturner@twopensource.com","subject":"[PATCH 1/6] refs.c: add an err argument to log_ref_setup","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-24T19:16:23Z","receivedAt":"2015-06-24T19:16:23Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Add err argument to log_ref_setup that can explain the reason for a\nfailure. This then eliminates the need to manage errno through this\nfunction since we can just add strerror(errno) to the err string when\nmeaningful. No callers relied on errno from this function for anything\nelse than the error message.\n\nwrite_ref_to_lockfile is a private function that calls\nlog_ref_setup. Update this function to also take an err argument and\nfill it in.  This again eliminates the need to manage errno in this\nfunction.\n\nUpdate of a patch by Ronnie Sahlberg.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\nSigned-off-by: David Turner <dturner@twitter.com>\n---\n builtin/checkout.c |   8 ++--\n refs.c             | 111 ++++++++++++++++++++++++++++-------------------------\n refs.h             |   4 +-\n 3 files changed, 66 insertions(+), 57 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex c018ab3..ac4d10a 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -624,16 +624,18 @@ static void update_refs_for_switch(const struct checkout_opts *opts,\n \t\t\t\tstruct strbuf log_file = STRBUF_INIT;\n \t\t\t\tint ret;\n \t\t\t\tconst char *ref_name;\n+\t\t\t\tstruct strbuf err = STRBUF_INIT;\n \n \t\t\t\tref_name = mkpath(\"refs/heads/%s\", opts->new_orphan_branch);\n \t\t\t\ttemp = log_all_ref_updates;\n \t\t\t\tlog_all_ref_updates = 1;\n-\t\t\t\tret = log_ref_setup(ref_name, &log_file);\n+\t\t\t\tret = log_ref_setup(ref_name, &log_file, &err);\n \t\t\t\tlog_all_ref_updates = temp;\n \t\t\t\tstrbuf_release(&log_file);\n \t\t\t\tif (ret) {\n-\t\t\t\t\tfprintf(stderr, _(\"Can not do reflog for '%s'\\n\"),\n-\t\t\t\t\t    opts->new_orphan_branch);\n+\t\t\t\t\tfprintf(stderr, _(\"Can not do reflog for '%s'. %s\\n\"),\n+\t\t\t\t\topts->new_orphan_branch, err.buf);\n+\t\t\t\t\tstrbuf_release(&err);\n \t\t\t\t\treturn;\n \t\t\t\t}\n \t\t\t}\ndiff --git a/refs.c b/refs.c\nindex fb568d7..b34a54a 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -2975,9 +2975,11 @@ static int rename_ref_available(const char *oldname, const char *newname)\n \treturn ret;\n }\n \n-static int write_ref_to_lockfile(struct ref_lock *lock, const unsigned char *sha1);\n+static int write_ref_to_lockfile(struct ref_lock *lock,\n+\t\t\t\t const unsigned char *sha1, struct strbuf* err);\n static int commit_ref_update(struct ref_lock *lock,\n-\t\t\t     const unsigned char *sha1, const char *logmsg);\n+\t\t\t     const unsigned char *sha1, const char *logmsg,\n+\t\t\t     struct strbuf *err);\n \n int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)\n {\n@@ -3038,9 +3040,10 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n \t}\n \thashcpy(lock->old_oid.hash, orig_sha1);\n \n-\tif (write_ref_to_lockfile(lock, orig_sha1) ||\n-\t    commit_ref_update(lock, orig_sha1, logmsg)) {\n-\t\terror(\"unable to write current sha1 into %s\", newrefname);\n+\tif (write_ref_to_lockfile(lock, orig_sha1, &err) ||\n+\t    commit_ref_update(lock, orig_sha1, logmsg, &err)) {\n+\t\terror(\"unable to write current sha1 into %s: %s\", newrefname, err.buf);\n+\t\tstrbuf_release(&err);\n \t\tgoto rollback;\n \t}\n \n@@ -3056,9 +3059,11 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n \n \tflag = log_all_ref_updates;\n \tlog_all_ref_updates = 0;\n-\tif (write_ref_to_lockfile(lock, orig_sha1) ||\n-\t    commit_ref_update(lock, orig_sha1, NULL))\n-\t\terror(\"unable to write current sha1 into %s\", oldrefname);\n+\tif (write_ref_to_lockfile(lock, orig_sha1, &err) ||\n+\t    commit_ref_update(lock, orig_sha1, NULL, &err)) {\n+\t\terror(\"unable to write current sha1 into %s: %s\", oldrefname, err.buf);\n+\t\tstrbuf_release(&err);\n+\t}\n \tlog_all_ref_updates = flag;\n \n  rollbacklog:\n@@ -3113,8 +3118,8 @@ static int copy_msg(char *buf, const char *msg)\n \treturn cp - buf;\n }\n \n-/* This function must set a meaningful errno on failure */\n-int log_ref_setup(const char *refname, struct strbuf *sb_logfile)\n+/* This function will fill in *err and return -1 on failure */\n+int log_ref_setup(const char *refname, struct strbuf *sb_logfile, struct strbuf *err)\n {\n \tint logfd, oflags = O_APPEND | O_WRONLY;\n \tchar *logfile;\n@@ -3129,9 +3134,8 @@ int log_ref_setup(const char *refname, struct strbuf *sb_logfile)\n \t     starts_with(refname, \"refs/notes/\") ||\n \t     !strcmp(refname, \"HEAD\"))) {\n \t\tif (safe_create_leading_directories(logfile) < 0) {\n-\t\t\tint save_errno = errno;\n-\t\t\terror(\"unable to create directory for %s\", logfile);\n-\t\t\terrno = save_errno;\n+\t\t\tstrbuf_addf(err, \"unable to create directory for %s. \"\n+\t\t\t\t    \"%s\", logfile, strerror(errno));\n \t\t\treturn -1;\n \t\t}\n \t\toflags |= O_CREAT;\n@@ -3144,20 +3148,16 @@ int log_ref_setup(const char *refname, struct strbuf *sb_logfile)\n \n \t\tif (errno == EISDIR) {\n \t\t\tif (remove_empty_directories(logfile)) {\n-\t\t\t\tint save_errno = errno;\n-\t\t\t\terror(\"There are still logs under '%s'\",\n-\t\t\t\t      logfile);\n-\t\t\t\terrno = save_errno;\n+\t\t\t\tstrbuf_addf(err, \"There are still logs under \"\n+\t\t\t\t\t    \"'%s'\", logfile);\n \t\t\t\treturn -1;\n \t\t\t}\n \t\t\tlogfd = open(logfile, oflags, 0666);\n \t\t}\n \n \t\tif (logfd < 0) {\n-\t\t\tint save_errno = errno;\n-\t\t\terror(\"Unable to append to %s: %s\", logfile,\n-\t\t\t      strerror(errno));\n-\t\t\terrno = save_errno;\n+\t\t\tstrbuf_addf(err, \"Unable to append to %s: %s\",\n+\t\t\t\t    logfile, strerror(errno));\n \t\t\treturn -1;\n \t\t}\n \t}\n@@ -3195,7 +3195,7 @@ static int log_ref_write_fd(int fd, const unsigned char *old_sha1,\n \n static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,\n \t\t\t   const unsigned char *new_sha1, const char *msg,\n-\t\t\t   struct strbuf *sb_log_file)\n+\t\t\t   struct strbuf *sb_log_file, struct strbuf *err)\n {\n \tint logfd, result, oflags = O_APPEND | O_WRONLY;\n \tchar *log_file;\n@@ -3203,7 +3203,8 @@ static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,\n \tif (log_all_ref_updates < 0)\n \t\tlog_all_ref_updates = !is_bare_repository();\n \n-\tresult = log_ref_setup(refname, sb_log_file);\n+\tresult = log_ref_setup(refname, sb_log_file, err);\n+\n \tif (result)\n \t\treturn result;\n \tlog_file = sb_log_file->buf;\n@@ -3216,26 +3217,25 @@ static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,\n \tresult = log_ref_write_fd(logfd, old_sha1, new_sha1,\n \t\t\t\t  git_committer_info(0), msg);\n \tif (result) {\n-\t\tint save_errno = errno;\n \t\tclose(logfd);\n-\t\terror(\"Unable to append to %s\", log_file);\n-\t\terrno = save_errno;\n+\t\tstrbuf_addf(err, \"Unable to append to %s. %s\", log_file,\n+\t\t\t    strerror(errno));\n \t\treturn -1;\n \t}\n \tif (close(logfd)) {\n-\t\tint save_errno = errno;\n-\t\terror(\"Unable to append to %s\", log_file);\n-\t\terrno = save_errno;\n+\t\tstrbuf_addf(err, \"Unable to append to %s. %s\", log_file,\n+\t\t\t    strerror(errno));\n \t\treturn -1;\n \t}\n \treturn 0;\n }\n \n static int log_ref_write(const char *refname, const unsigned char *old_sha1,\n-\t\t\t const unsigned char *new_sha1, const char *msg)\n+\t\t\t const unsigned char *new_sha1, const char *msg,\n+\t\t\t struct strbuf *err)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n-\tint ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb);\n+\tint ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb, err);\n \tstrbuf_release(&sb);\n \treturn ret;\n }\n@@ -3247,25 +3247,28 @@ int is_branch(const char *refname)\n \n /*\n  * Write sha1 into the open lockfile, then close the lockfile. On\n- * errors, rollback the lockfile and set errno to reflect the problem.\n+ * errors, rollback the lockfile, fill in *err and\n+ * return -1.\n  */\n static int write_ref_to_lockfile(struct ref_lock *lock,\n-\t\t\t\t const unsigned char *sha1)\n+\t\t\t\t const unsigned char *sha1, struct strbuf *err)\n {\n \tstatic char term = '\\n';\n \tstruct object *o;\n \n \to = parse_object(sha1);\n \tif (!o) {\n-\t\terror(\"Trying to write ref %s with nonexistent object %s\",\n-\t\t\tlock->ref_name, sha1_to_hex(sha1));\n+\t\tstrbuf_addf(err,\n+\t\t\t    \"Trying to write ref %s with nonexistent object %s\",\n+\t\t\t    lock->ref_name, sha1_to_hex(sha1));\n \t\tunlock_ref(lock);\n \t\terrno = EINVAL;\n \t\treturn -1;\n \t}\n \tif (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {\n-\t\terror(\"Trying to write non-commit object %s to branch %s\",\n-\t\t\tsha1_to_hex(sha1), lock->ref_name);\n+\t\tstrbuf_addf(err,\n+\t\t\t    \"Trying to write non-commit object %s to branch %s\",\n+\t\t\t    sha1_to_hex(sha1), lock->ref_name);\n \t\tunlock_ref(lock);\n \t\terrno = EINVAL;\n \t\treturn -1;\n@@ -3273,10 +3276,9 @@ static int write_ref_to_lockfile(struct ref_lock *lock,\n \tif (write_in_full(lock->lk->fd, sha1_to_hex(sha1), 40) != 40 ||\n \t    write_in_full(lock->lk->fd, &term, 1) != 1 ||\n \t    close_ref(lock) < 0) {\n-\t\tint save_errno = errno;\n-\t\terror(\"Couldn't write %s\", lock->lk->filename.buf);\n+\t\tstrbuf_addf(err,\n+\t\t\t    \"Couldn't write %s\", lock->lk->filename.buf);\n \t\tunlock_ref(lock);\n-\t\terrno = save_errno;\n \t\treturn -1;\n \t}\n \treturn 0;\n@@ -3288,12 +3290,15 @@ static int write_ref_to_lockfile(struct ref_lock *lock,\n  * necessary, using the specified lockmsg (which can be NULL).\n  */\n static int commit_ref_update(struct ref_lock *lock,\n-\t\t\t     const unsigned char *sha1, const char *logmsg)\n+\t\t\t     const unsigned char *sha1, const char *logmsg,\n+\t\t\t     struct strbuf *err)\n {\n \tclear_loose_ref_cache(&ref_cache);\n-\tif (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg) < 0 ||\n+\tif (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, err) < 0 ||\n \t    (strcmp(lock->ref_name, lock->orig_ref_name) &&\n-\t     log_ref_write(lock->orig_ref_name, lock->old_oid.hash, sha1, logmsg) < 0)) {\n+\t     log_ref_write(lock->orig_ref_name, lock->old_oid.hash, sha1, logmsg, err) < 0)) {\n+\t\tstrbuf_addf(err, \"Cannot update the ref '%s'.\",\n+\t\t\t    lock->ref_name);\n \t\tunlock_ref(lock);\n \t\treturn -1;\n \t}\n@@ -3317,7 +3322,8 @@ static int commit_ref_update(struct ref_lock *lock,\n \t\t\t\t\t      head_sha1, &head_flag);\n \t\tif (head_ref && (head_flag & REF_ISSYMREF) &&\n \t\t    !strcmp(head_ref, lock->ref_name))\n-\t\t\tlog_ref_write(\"HEAD\", lock->old_oid.hash, sha1, logmsg);\n+\t\t\tlog_ref_write(\"HEAD\", lock->old_oid.hash, sha1, logmsg,\n+\t\t\t\t      err);\n \t}\n \tif (commit_ref(lock)) {\n \t\terror(\"Couldn't set %s\", lock->ref_name);\n@@ -3336,6 +3342,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master,\n \tint fd, len, written;\n \tchar *git_HEAD = git_pathdup(\"%s\", ref_target);\n \tunsigned char old_sha1[20], new_sha1[20];\n+\tstruct strbuf err = STRBUF_INIT;\n \n \tif (logmsg && read_ref(ref_target, old_sha1))\n \t\thashclr(old_sha1);\n@@ -3384,8 +3391,11 @@ int create_symref(const char *ref_target, const char *refs_heads_master,\n #ifndef NO_SYMLINK_HEAD\n \tdone:\n #endif\n-\tif (logmsg && !read_ref(refs_heads_master, new_sha1))\n-\t\tlog_ref_write(ref_target, old_sha1, new_sha1, logmsg);\n+\tif (logmsg && !read_ref(refs_heads_master, new_sha1) &&\n+\t\tlog_ref_write(ref_target, old_sha1, new_sha1, logmsg, &err)) {\n+\t\terror(\"%s\", err.buf);\n+\t\tstrbuf_release(&err);\n+\t}\n \n \tfree(git_HEAD);\n \treturn 0;\n@@ -4021,14 +4031,13 @@ int ref_transaction_commit(struct ref_transaction *transaction,\n \t\t\t\t * value, so we don't need to write it.\n \t\t\t\t */\n \t\t\t} else if (write_ref_to_lockfile(update->lock,\n-\t\t\t\t\t\t\t update->new_sha1)) {\n+\t\t\t\t\t\t\t update->new_sha1,\n+\t\t\t\t\t\t\t err)) {\n \t\t\t\t/*\n \t\t\t\t * The lock was freed upon failure of\n \t\t\t\t * write_ref_to_lockfile():\n \t\t\t\t */\n \t\t\t\tupdate->lock = NULL;\n-\t\t\t\tstrbuf_addf(err, \"cannot update the ref '%s'.\",\n-\t\t\t\t\t    update->refname);\n \t\t\t\tret = TRANSACTION_GENERIC_ERROR;\n \t\t\t\tgoto cleanup;\n \t\t\t} else {\n@@ -4054,11 +4063,9 @@ int ref_transaction_commit(struct ref_transaction *transaction,\n \n \t\tif (update->flags & REF_NEEDS_COMMIT) {\n \t\t\tif (commit_ref_update(update->lock,\n-\t\t\t\t\t      update->new_sha1, update->msg)) {\n+\t\t\t\t\t      update->new_sha1, update->msg, err)) {\n \t\t\t\t/* freed by commit_ref_update(): */\n \t\t\t\tupdate->lock = NULL;\n-\t\t\t\tstrbuf_addf(err, \"Cannot update the ref '%s'.\",\n-\t\t\t\t\t    update->refname);\n \t\t\t\tret = TRANSACTION_GENERIC_ERROR;\n \t\t\t\tgoto cleanup;\n \t\t\t} else {\ndiff --git a/refs.h b/refs.h\nindex e82fca5..debdefc 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -226,9 +226,9 @@ int pack_refs(unsigned int flags);\n #define REF_NODEREF\t0x01\n \n /*\n- * Setup reflog before using. Set errno to something meaningful on failure.\n+ * Setup reflog before using. Fill in err and return -1 on failure.\n  */\n-int log_ref_setup(const char *refname, struct strbuf *logfile);\n+int log_ref_setup(const char *refname, struct strbuf *logfile, struct strbuf *err);\n \n /** Reads log for the value of ref during at_time. **/\n extern int read_ref_at(const char *refname, unsigned int flags,\n-- \n2.0.4.314.gdbf7a51-twtrsrc\n"},{"id":"264754","messageId":"1435173388-8346-3-git-send-email-dturner@twopensource.com","threadId":"39712","inReplyTo":"1435173388-8346-1-git-send-email-dturner@twopensource.com","subject":"[PATCH 2/6] cherry-pick: Use refs infrastructure for CHERRY_PICK_HEAD","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-24T19:16:24Z","receivedAt":"2015-06-24T19:16:24Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Also use refs infrastructure for REVERT_HEAD.  These refs\nneed to go through the refs backend, since some code\nassumes that they can be read as refs.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n branch.c                         |  4 ++--\n builtin/commit.c                 |  7 ++++---\n builtin/merge.c                  |  3 ++-\n contrib/completion/git-prompt.sh |  9 +++++----\n git-gui/lib/commit.tcl           |  2 +-\n refs.c                           | 17 +++++++++--------\n refs.h                           |  5 +++++\n sequencer.c                      | 39 +++++++++++++++++++++------------------\n t/t7509-commit.sh                |  4 ++--\n wt-status.c                      |  6 ++----\n 10 files changed, 53 insertions(+), 43 deletions(-)\n\ndiff --git a/branch.c b/branch.c\nindex b002435..8371a16 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -302,8 +302,8 @@ void create_branch(const char *head,\n \n void remove_branch_state(void)\n {\n-\tunlink(git_path(\"CHERRY_PICK_HEAD\"));\n-\tunlink(git_path(\"REVERT_HEAD\"));\n+\tdelete_ref(\"CHERRY_PICK_HEAD\", NULL, REF_NODEREF | REF_NO_REFLOG);\n+\tdelete_ref(\"REVERT_HEAD\", NULL, REF_NODEREF | REF_NO_REFLOG);\n \tunlink(git_path(\"MERGE_HEAD\"));\n \tunlink(git_path(\"MERGE_RR\"));\n \tunlink(git_path(\"MERGE_MSG\"));\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex b5b1158..0f0b184 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -166,9 +166,10 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)\n \n static void determine_whence(struct wt_status *s)\n {\n+\tunsigned char unused[20];\n \tif (file_exists(git_path(\"MERGE_HEAD\")))\n \t\twhence = FROM_MERGE;\n-\telse if (file_exists(git_path(\"CHERRY_PICK_HEAD\"))) {\n+\telse if (!read_ref(\"CHERRY_PICK_HEAD\", unused)) {\n \t\twhence = FROM_CHERRY_PICK;\n \t\tif (file_exists(git_path(SEQ_DIR)))\n \t\t\tsequencer_in_use = 1;\n@@ -1777,8 +1778,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t}\n \tref_transaction_free(transaction);\n \n-\tunlink(git_path(\"CHERRY_PICK_HEAD\"));\n-\tunlink(git_path(\"REVERT_HEAD\"));\n+\tdelete_ref(\"CHERRY_PICK_HEAD\", NULL, REF_NODEREF | REF_NO_REFLOG);\n+\tdelete_ref(\"REVERT_HEAD\", NULL, REF_NODEREF | REF_NO_REFLOG);\n \tunlink(git_path(\"MERGE_HEAD\"));\n \tunlink(git_path(\"MERGE_MSG\"));\n \tunlink(git_path(\"MERGE_MODE\"));\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 46aacd6..a4abf93 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1144,6 +1144,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \tunsigned char result_tree[20];\n \tunsigned char stash[20];\n \tunsigned char head_sha1[20];\n+\tunsigned char unused[20];\n \tstruct commit *head_commit;\n \tstruct strbuf buf = STRBUF_INIT;\n \tint flag, i, ret = 0, head_subsumed;\n@@ -1206,7 +1207,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\telse\n \t\t\tdie(_(\"You have not concluded your merge (MERGE_HEAD exists).\"));\n \t}\n-\tif (file_exists(git_path(\"CHERRY_PICK_HEAD\"))) {\n+\tif (!read_ref(\"CHERRY_PICK_HEAD\", unused)) {\n \t\tif (advice_resolve_conflict)\n \t\t\tdie(_(\"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\\n\"\n \t\t\t    \"Please, commit your changes before you merge.\"));\ndiff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh\nindex 366f0bc..5e27a34 100644\n--- a/contrib/completion/git-prompt.sh\n+++ b/contrib/completion/git-prompt.sh\n@@ -415,9 +415,9 @@ __git_ps1 ()\n \t\t\tfi\n \t\telif [ -f \"$g/MERGE_HEAD\" ]; then\n \t\t\tr=\"|MERGING\"\n-\t\telif [ -f \"$g/CHERRY_PICK_HEAD\" ]; then\n+\t\telif git rev-parse --quiet --verify \"CHERRY_PICK_HEAD\" >/dev/null; then\n \t\t\tr=\"|CHERRY-PICKING\"\n-\t\telif [ -f \"$g/REVERT_HEAD\" ]; then\n+\t\telif git rev-parse --quiet --verify \"REVERT_HEAD\" >/dev/null; then\n \t\t\tr=\"|REVERTING\"\n \t\telif [ -f \"$g/BISECT_LOG\" ]; then\n \t\t\tr=\"|BISECTING\"\n@@ -429,8 +429,9 @@ __git_ps1 ()\n \t\t\t# symlink symbolic ref\n \t\t\tb=\"$(git symbolic-ref HEAD 2>/dev/null)\"\n \t\telse\n-\t\t\tlocal head=\"\"\n-\t\t\tif ! __git_eread \"$g/HEAD\" head; then\n+\t\t\tlocal head\n+\t\t\thead=\"ref: $(git symbolic-ref HEAD 2>/dev/null)\" || head=$(git rev-parse HEAD)\n+\t\t\tif [ -z \"$head\" ]; then\n \t\t\t\treturn $exit\n \t\t\tfi\n \t\t\t# is it a symbolic ref?\ndiff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl\nindex 864b687..2b08b13 100644\n--- a/git-gui/lib/commit.tcl\n+++ b/git-gui/lib/commit.tcl\n@@ -409,7 +409,7 @@ A rescan will be automatically started now.\n \tcatch {file delete [gitdir MERGE_MSG]}\n \tcatch {file delete [gitdir SQUASH_MSG]}\n \tcatch {file delete [gitdir GITGUI_MSG]}\n-\tcatch {file delete [gitdir CHERRY_PICK_HEAD]}\n+\tcatch {git update-ref -d --no-deref CHERRY_PICK_HEAD}\n \n \t# -- Let rerere do its thing.\n \t#\ndiff --git a/refs.c b/refs.c\nindex b34a54a..c1a563f 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -2979,7 +2979,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,\n \t\t\t\t const unsigned char *sha1, struct strbuf* err);\n static int commit_ref_update(struct ref_lock *lock,\n \t\t\t     const unsigned char *sha1, const char *logmsg,\n-\t\t\t     struct strbuf *err);\n+\t\t\t     struct strbuf *err, int flags);\n \n int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)\n {\n@@ -3041,7 +3041,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n \thashcpy(lock->old_oid.hash, orig_sha1);\n \n \tif (write_ref_to_lockfile(lock, orig_sha1, &err) ||\n-\t    commit_ref_update(lock, orig_sha1, logmsg, &err)) {\n+\t    commit_ref_update(lock, orig_sha1, logmsg, &err, 0)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", newrefname, err.buf);\n \t\tstrbuf_release(&err);\n \t\tgoto rollback;\n@@ -3060,7 +3060,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n \tflag = log_all_ref_updates;\n \tlog_all_ref_updates = 0;\n \tif (write_ref_to_lockfile(lock, orig_sha1, &err) ||\n-\t    commit_ref_update(lock, orig_sha1, NULL, &err)) {\n+\t    commit_ref_update(lock, orig_sha1, NULL, &err, 0)) {\n \t\terror(\"unable to write current sha1 into %s: %s\", oldrefname, err.buf);\n \t\tstrbuf_release(&err);\n \t}\n@@ -3291,12 +3291,13 @@ static int write_ref_to_lockfile(struct ref_lock *lock,\n  */\n static int commit_ref_update(struct ref_lock *lock,\n \t\t\t     const unsigned char *sha1, const char *logmsg,\n-\t\t\t     struct strbuf *err)\n+\t\t\t     struct strbuf *err, int flags)\n {\n \tclear_loose_ref_cache(&ref_cache);\n-\tif (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, err) < 0 ||\n-\t    (strcmp(lock->ref_name, lock->orig_ref_name) &&\n-\t     log_ref_write(lock->orig_ref_name, lock->old_oid.hash, sha1, logmsg, err) < 0)) {\n+\tif (!(flags & REF_NO_REFLOG) &&\n+\t    (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, err) < 0 ||\n+\t     (strcmp(lock->ref_name, lock->orig_ref_name) &&\n+\t      log_ref_write(lock->orig_ref_name, lock->old_oid.hash, sha1, logmsg, err) < 0))) {\n \t\tstrbuf_addf(err, \"Cannot update the ref '%s'.\",\n \t\t\t    lock->ref_name);\n \t\tunlock_ref(lock);\n@@ -4063,7 +4064,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,\n \n \t\tif (update->flags & REF_NEEDS_COMMIT) {\n \t\t\tif (commit_ref_update(update->lock,\n-\t\t\t\t\t      update->new_sha1, update->msg, err)) {\n+\t\t\t\t\t      update->new_sha1, update->msg, err, 0)) {\n \t\t\t\t/* freed by commit_ref_update(): */\n \t\t\t\tupdate->lock = NULL;\n \t\t\t\tret = TRANSACTION_GENERIC_ERROR;\ndiff --git a/refs.h b/refs.h\nindex debdefc..eee99f6 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -153,6 +153,11 @@ struct ref_transaction;\n #define REF_BAD_NAME 0x08\n \n /*\n+ * Used as a flag in ref_update::flags when the reflog should not be updated\n+ */\n+#define REF_NO_REFLOG\t0x40\n+\n+/*\n  * The signature for the callback function for the for_each_*()\n  * functions below.  The memory pointed to by the refname and sha1\n  * arguments is only guaranteed to be valid for the duration of a\ndiff --git a/sequencer.c b/sequencer.c\nindex f8421a8..f66e2be 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -160,19 +160,20 @@ static void free_message(struct commit *commit, struct commit_message *msg)\n \n static void write_cherry_pick_head(struct commit *commit, const char *pseudoref)\n {\n-\tconst char *filename;\n-\tint fd;\n-\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct strbuf err = STRBUF_INIT;\n+\tvoid *transaction;\n \n-\tstrbuf_addf(&buf, \"%s\\n\", sha1_to_hex(commit->object.sha1));\n+\ttransaction = ref_transaction_begin(&err);\n+\tif (!transaction)\n+\t\tdie(_(\"Could not create transaction: %s\"), err.buf);\n \n-\tfilename = git_path(\"%s\", pseudoref);\n-\tfd = open(filename, O_WRONLY | O_CREAT, 0666);\n-\tif (fd < 0)\n-\t\tdie_errno(_(\"Could not open '%s' for writing\"), filename);\n-\tif (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))\n-\t\tdie_errno(_(\"Could not write to '%s'\"), filename);\n-\tstrbuf_release(&buf);\n+\tif (ref_transaction_update(transaction, pseudoref, commit->object.sha1,\n+\t\t\t\t   NULL, REF_NODEREF | REF_NO_REFLOG, NULL,\n+\t\t\t\t   &err))\n+\t\tdie(_(\"Could not write ref %s: %s\"), pseudoref, err.buf);\n+\n+\tif (ref_transaction_commit(transaction, &err))\n+\t\tdie(_(\"Could not commit ref write %s: %s\"), pseudoref, err.buf);\n }\n \n static void print_advice(int show_hint, struct replay_opts *opts)\n@@ -186,7 +187,7 @@ static void print_advice(int show_hint, struct replay_opts *opts)\n \t\t * (typically rebase --interactive) wants to take care\n \t\t * of the commit itself so remove CHERRY_PICK_HEAD\n \t\t */\n-\t\tunlink(git_path(\"CHERRY_PICK_HEAD\"));\n+\t\tdelete_ref(\"CHERRY_PICK_HEAD\", NULL, REF_NODEREF);\n \t\treturn;\n \t}\n \n@@ -878,8 +879,8 @@ static int rollback_single_pick(void)\n {\n \tunsigned char head_sha1[20];\n \n-\tif (!file_exists(git_path(\"CHERRY_PICK_HEAD\")) &&\n-\t    !file_exists(git_path(\"REVERT_HEAD\")))\n+\tif (read_ref(\"CHERRY_PICK_HEAD\", head_sha1) &&\n+\t    read_ref(\"REVERT_HEAD\", head_sha1))\n \t\treturn error(_(\"no cherry-pick or revert in progress\"));\n \tif (read_ref_full(\"HEAD\", 0, head_sha1, NULL))\n \t\treturn error(_(\"cannot resolve HEAD\"));\n@@ -1013,9 +1014,10 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)\n static int continue_single_pick(void)\n {\n \tconst char *argv[] = { \"commit\", NULL };\n+\tunsigned char unused[20];\n \n-\tif (!file_exists(git_path(\"CHERRY_PICK_HEAD\")) &&\n-\t    !file_exists(git_path(\"REVERT_HEAD\")))\n+\tif (read_ref(\"CHERRY_PICK_HEAD\", unused) &&\n+\t    read_ref(\"REVERT_HEAD\", unused))\n \t\treturn error(_(\"no cherry-pick or revert in progress\"));\n \treturn run_command_v_opt(argv, RUN_GIT_CMD);\n }\n@@ -1023,6 +1025,7 @@ static int continue_single_pick(void)\n static int sequencer_continue(struct replay_opts *opts)\n {\n \tstruct commit_list *todo_list = NULL;\n+\tunsigned char unused[20];\n \n \tif (!file_exists(git_path(SEQ_TODO_FILE)))\n \t\treturn continue_single_pick();\n@@ -1030,8 +1033,8 @@ static int sequencer_continue(struct replay_opts *opts)\n \tread_populate_todo(&todo_list, opts);\n \n \t/* Verify that the conflict has been resolved */\n-\tif (file_exists(git_path(\"CHERRY_PICK_HEAD\")) ||\n-\t    file_exists(git_path(\"REVERT_HEAD\"))) {\n+\tif (!read_ref(\"CHERRY_PICK_HEAD\", unused) ||\n+\t    !read_ref(\"REVERT_HEAD\", unused)) {\n \t\tint ret = continue_single_pick();\n \t\tif (ret)\n \t\t\treturn ret;\ndiff --git a/t/t7509-commit.sh b/t/t7509-commit.sh\nindex 9ac7940..f7fd62c 100755\n--- a/t/t7509-commit.sh\n+++ b/t/t7509-commit.sh\n@@ -163,7 +163,7 @@ test_expect_success 'commit respects CHERRY_PICK_HEAD and MERGE_MSG' '\n \ttest_tick &&\n \tgit commit -am \"cherry-pick 1\" --author=\"Cherry <cherry@pick.er>\" &&\n \tgit tag cherry-pick-head &&\n-\tgit rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD &&\n+\tgit update-ref CHERRY_PICK_HEAD $(git rev-parse cherry-pick-head) &&\n \techo \"This is a MERGE_MSG\" >.git/MERGE_MSG &&\n \techo \"cherry-pick 1b\" >>foo &&\n \ttest_tick &&\n@@ -178,7 +178,7 @@ test_expect_success 'commit respects CHERRY_PICK_HEAD and MERGE_MSG' '\n '\n \n test_expect_success '--reset-author with CHERRY_PICK_HEAD' '\n-\tgit rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD &&\n+\tgit update-ref CHERRY_PICK_HEAD $(git rev-parse cherry-pick-head) &&\n \techo \"cherry-pick 2\" >>foo &&\n \ttest_tick &&\n \tgit commit -am \"cherry-pick 2\" --reset-author &&\ndiff --git a/wt-status.c b/wt-status.c\nindex 9c686e6..661c1fb 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1336,8 +1336,7 @@ void wt_status_get_state(struct wt_status_state *state,\n \t\t\tstate->rebase_in_progress = 1;\n \t\tstate->branch = read_and_strip_branch(\"rebase-merge/head-name\");\n \t\tstate->onto = read_and_strip_branch(\"rebase-merge/onto\");\n-\t} else if (!stat(git_path(\"CHERRY_PICK_HEAD\"), &st) &&\n-\t\t\t!get_sha1(\"CHERRY_PICK_HEAD\", sha1)) {\n+\t} else if (!read_ref(\"CHERRY_PICK_HEAD\", sha1)) {\n \t\tstate->cherry_pick_in_progress = 1;\n \t\thashcpy(state->cherry_pick_head_sha1, sha1);\n \t}\n@@ -1345,8 +1344,7 @@ void wt_status_get_state(struct wt_status_state *state,\n \t\tstate->bisect_in_progress = 1;\n \t\tstate->branch = read_and_strip_branch(\"BISECT_START\");\n \t}\n-\tif (!stat(git_path(\"REVERT_HEAD\"), &st) &&\n-\t    !get_sha1(\"REVERT_HEAD\", sha1)) {\n+\tif (!read_ref(\"REVERT_HEAD\", sha1)) {\n \t\tstate->revert_in_progress = 1;\n \t\thashcpy(state->revert_head_sha1, sha1);\n \t}\n-- \n2.0.4.314.gdbf7a51-twtrsrc\n"},{"id":"264756","messageId":"1435173388-8346-4-git-send-email-dturner@twopensource.com","threadId":"39712","inReplyTo":"1435173388-8346-1-git-send-email-dturner@twopensource.com","subject":"[PATCH 3/6] bisect: use refs infrastructure for BISECT_START","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-24T19:16:25Z","receivedAt":"2015-06-24T19:16:25Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"This ref needs to go through the refs backend, since some code assumes\nthat it can be written and read as a ref.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n contrib/completion/git-completion.bash | 2 +-\n git-bisect.sh                          | 4 ++--\n 2 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 93716c4..c4d4d80 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -938,7 +938,7 @@ _git_bisect ()\n \tlocal subcommands=\"start bad good skip reset visualize replay log run\"\n \tlocal subcommand=\"$(__git_find_on_cmdline \"$subcommands\")\"\n \tif [ -z \"$subcommand\" ]; then\n-\t\tif [ -f \"$(__gitdir)\"/BISECT_START ]; then\n+\t\tif [ git rev-parse BISECT_START 2>/dev/null ]; then\n \t\t\t__gitcomp \"$subcommands\"\n \t\telse\n \t\t\t__gitcomp \"replay start\"\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex ae3fec2..8658772 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -166,7 +166,7 @@ bisect_start() {\n \t#\n \techo \"$start_head\" >\"$GIT_DIR/BISECT_START\" && {\n \t\ttest \"z$mode\" != \"z--no-checkout\" ||\n-\t\tgit update-ref --no-deref BISECT_HEAD \"$start_head\"\n+\t\tgit rev-parse \"$start_head\" > \"$GIT_DIR/BISECT_HEAD\"\n \t} &&\n \tgit rev-parse --sq-quote \"$@\" >\"$GIT_DIR/BISECT_NAMES\" &&\n \teval \"$eval true\" &&\n@@ -399,7 +399,7 @@ bisect_clean_state() {\n \trm -f \"$GIT_DIR/BISECT_RUN\" &&\n \t# Cleanup head-name if it got left by an old version of git-bisect\n \trm -f \"$GIT_DIR/head-name\" &&\n-\tgit update-ref -d --no-deref BISECT_HEAD &&\n+\trm -f \"$GIT_DIR/BISECT_HEAD\" &&\n \t# clean up BISECT_START last\n \trm -f \"$GIT_DIR/BISECT_START\"\n }\n-- \n2.0.4.314.gdbf7a51-twtrsrc\n"},{"id":"264753","messageId":"1435173388-8346-5-git-send-email-dturner@twopensource.com","threadId":"39712","inReplyTo":"1435173388-8346-1-git-send-email-dturner@twopensource.com","subject":"[PATCH 4/6] refs: replace log_ref_write with create_reflog","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-24T19:16:26Z","receivedAt":"2015-06-24T19:16:26Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"In a moment, we will use this to add reflog creation commands to\ngit-reflog.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n builtin/checkout.c | 2 +-\n refs.c             | 4 ++--\n refs.h             | 2 +-\n 3 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex ac4d10a..7549ae2 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -629,7 +629,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts,\n \t\t\t\tref_name = mkpath(\"refs/heads/%s\", opts->new_orphan_branch);\n \t\t\t\ttemp = log_all_ref_updates;\n \t\t\t\tlog_all_ref_updates = 1;\n-\t\t\t\tret = log_ref_setup(ref_name, &log_file, &err);\n+\t\t\t\tret = create_reflog(ref_name, &log_file, &err);\n \t\t\t\tlog_all_ref_updates = temp;\n \t\t\t\tstrbuf_release(&log_file);\n \t\t\t\tif (ret) {\ndiff --git a/refs.c b/refs.c\nindex c1a563f..93412ee 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -3119,7 +3119,7 @@ static int copy_msg(char *buf, const char *msg)\n }\n \n /* This function will fill in *err and return -1 on failure */\n-int log_ref_setup(const char *refname, struct strbuf *sb_logfile, struct strbuf *err)\n+int create_reflog(const char *refname, struct strbuf *sb_logfile, struct strbuf *err)\n {\n \tint logfd, oflags = O_APPEND | O_WRONLY;\n \tchar *logfile;\n@@ -3203,7 +3203,7 @@ static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,\n \tif (log_all_ref_updates < 0)\n \t\tlog_all_ref_updates = !is_bare_repository();\n \n-\tresult = log_ref_setup(refname, sb_log_file, err);\n+\tresult = create_reflog(refname, sb_log_file, err);\n \n \tif (result)\n \t\treturn result;\ndiff --git a/refs.h b/refs.h\nindex eee99f6..d4f75a9 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -233,7 +233,7 @@ int pack_refs(unsigned int flags);\n /*\n  * Setup reflog before using. Fill in err and return -1 on failure.\n  */\n-int log_ref_setup(const char *refname, struct strbuf *logfile, struct strbuf *err);\n+int create_reflog(const char *refname, struct strbuf *logfile, struct strbuf *err);\n \n /** Reads log for the value of ref during at_time. **/\n extern int read_ref_at(const char *refname, unsigned int flags,\n-- \n2.0.4.314.gdbf7a51-twtrsrc\n"},{"id":"264757","messageId":"1435173388-8346-6-git-send-email-dturner@twopensource.com","threadId":"39712","inReplyTo":"1435173388-8346-1-git-send-email-dturner@twopensource.com","subject":"[PATCH 5/6] git-reflog: add create and exists functions","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-24T19:16:27Z","receivedAt":"2015-06-24T19:16:27Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"These are necessary because ref backends manage reflogs. In a moment,\nwe will use these functions to make git stash work with alternate\nref backends.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n builtin/reflog.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 80 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex c2eb8ff..3cf7d3d 100644\n--- a/builtin/reflog.c\n+++ b/builtin/reflog.c\n@@ -13,6 +13,10 @@ static const char reflog_expire_usage[] =\n \"git reflog expire [--expire=<time>] [--expire-unreachable=<time>] [--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] [--verbose] [--all] <refs>...\";\n static const char reflog_delete_usage[] =\n \"git reflog delete [--rewrite] [--updateref] [--dry-run | -n] [--verbose] <refs>...\";\n+static const char reflog_create_usage[] =\n+\"git reflog create <refs>...\";\n+static const char reflog_exists_usage[] =\n+\"git reflog exists <refs>...\";\n \n static unsigned long default_reflog_expire;\n static unsigned long default_reflog_expire_unreachable;\n@@ -699,12 +703,81 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)\n \treturn status;\n }\n \n+static int cmd_reflog_create(int argc, const char **argv, const char *prefix)\n+{\n+\tint i, status = 0, start = 0;\n+\tstruct strbuf err = STRBUF_INIT;\n+\tstruct strbuf logfile = STRBUF_INIT;\n+\n+\tfor (i = 1; i < argc; i++) {\n+\t\tconst char *arg = argv[i];\n+\t\tif (!strcmp(arg, \"--\")) {\n+\t\t\ti++;\n+\t\t\tbreak;\n+\t\t}\n+\t\telse if (arg[0] == '-')\n+\t\t\tusage(reflog_create_usage);\n+\t\telse\n+\t\t\tbreak;\n+\t}\n+\n+\tstart = i;\n+\n+\tif (argc - start < 1)\n+\t\treturn error(\"Nothing to create?\");\n+\n+\tfor (i = start ; i < argc; i++) {\n+\t\tif (check_refname_format(argv[i], REFNAME_ALLOW_ONELEVEL))\n+\t\t\tdie(\"invalid ref format: %s\", argv[i]);\n+\t}\n+\tfor (i = start ; i < argc; i++) {\n+\t\tif (create_reflog(argv[i], &logfile, &err)) {\n+\t\t\terror(\"could not create reflog %s: %s\", argv[i],\n+\t\t\t      err.buf);\n+\t\t\tstatus = 1;\n+\t\t\tstrbuf_release(&err);\n+\t\t}\n+\t\tstrbuf_release(&logfile);\n+\t}\n+\treturn status;\n+}\n+\n+static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)\n+{\n+\tint i, status = 0, start = 0;\n+\n+\tfor (i = 1; i < argc; i++) {\n+\t\tconst char *arg = argv[i];\n+\t\tif (!strcmp(arg, \"--\")) {\n+\t\t\ti++;\n+\t\t\tbreak;\n+\t\t}\n+\t\telse if (arg[0] == '-')\n+\t\t\tusage(reflog_exists_usage);\n+\t\telse\n+\t\t\tbreak;\n+\t}\n+\n+\tstart = i;\n+\n+\tif (argc - start < 1)\n+\t\treturn error(\"Nothing to check?\");\n+\n+\tfor (i = start ; i < argc; i++) {\n+\t\tif (check_refname_format(argv[i], REFNAME_ALLOW_ONELEVEL))\n+\t\t\tdie(\"invalid ref format: %s\", argv[i]);\n+\t\tif (!reflog_exists(argv[i]))\n+\t\t\tstatus = 1;\n+\t}\n+\treturn status;\n+}\n+\n /*\n  * main \"reflog\"\n  */\n \n static const char reflog_usage[] =\n-\"git reflog [ show | expire | delete ]\";\n+\"git reflog [ show | expire | delete | create | exists ]\";\n \n int cmd_reflog(int argc, const char **argv, const char *prefix)\n {\n@@ -724,5 +797,11 @@ int cmd_reflog(int argc, const char **argv, const char *prefix)\n \tif (!strcmp(argv[1], \"delete\"))\n \t\treturn cmd_reflog_delete(argc - 1, argv + 1, prefix);\n \n+\tif (!strcmp(argv[1], \"create\"))\n+\t\treturn cmd_reflog_create(argc - 1, argv + 1, prefix);\n+\n+\tif (!strcmp(argv[1], \"exists\"))\n+\t\treturn cmd_reflog_exists(argc - 1, argv + 1, prefix);\n+\n \treturn cmd_log_reflog(argc, argv, prefix);\n }\n-- \n2.0.4.314.gdbf7a51-twtrsrc\n"},{"id":"264758","messageId":"1435173388-8346-7-git-send-email-dturner@twopensource.com","threadId":"39712","inReplyTo":"1435173388-8346-1-git-send-email-dturner@twopensource.com","subject":"[PATCH 6/6] git-stash: use git-reflog instead of creating files","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-24T19:16:28Z","receivedAt":"2015-06-24T19:16:28Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"This is in support of alternate ref backends which don't necessarily\nstore reflogs as files.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n git-stash.sh | 4 ++--\n refs.c       | 1 +\n 2 files changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 8e9e2cd..27155bc 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -184,7 +184,7 @@ store_stash () {\n \tfi\n \n \t# Make sure the reflog for stash is kept.\n-\t: >>\"$(git rev-parse --git-path logs/$ref_stash)\"\n+\tgit reflog create \"$ref_stash\"\n \tgit update-ref -m \"$stash_msg\" $ref_stash $w_commit\n \tret=$?\n \ttest $ret != 0 && test -z $quiet &&\n@@ -262,7 +262,7 @@ save_stash () {\n \t\tsay \"$(gettext \"No local changes to save\")\"\n \t\texit 0\n \tfi\n-\ttest -f \"$(git rev-parse --git-path logs/$ref_stash)\" ||\n+\tgit reflog exists $ref_stash ||\n \t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n \n \tcreate_stash \"$stash_msg\" $untracked\ndiff --git a/refs.c b/refs.c\nindex 93412ee..f3e3da0 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -3132,6 +3132,7 @@ int create_reflog(const char *refname, struct strbuf *sb_logfile, struct strbuf\n \t    (starts_with(refname, \"refs/heads/\") ||\n \t     starts_with(refname, \"refs/remotes/\") ||\n \t     starts_with(refname, \"refs/notes/\") ||\n+\t     !strcmp(refname, \"refs/stash\") ||\n \t     !strcmp(refname, \"HEAD\"))) {\n \t\tif (safe_create_leading_directories(logfile) < 0) {\n \t\t\tstrbuf_addf(err, \"unable to create directory for %s. \"\n-- \n2.0.4.314.gdbf7a51-twtrsrc\n"},{"id":"264847","messageId":"xmqqpp4k0vtu.fsf@gitster.dls.corp.google.com","threadId":"39712","inReplyTo":"1435173388-8346-1-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH 0/6] refs backend preamble","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-25T13:19:25Z","receivedAt":"2015-06-25T13:19:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"David Turner <dturner@twopensource.com> writes:\n\n> This set of patches is a preamble to pluggable ref backends.  The\n> intent is to use the ref infrastructure for special refs like\n> CHERRY_PICK_HEAD where possible, and to use git plumbing commands to\n> access refs and reflogs instead of directly writing files to the .git\n> directory.\n>\n> This series is on top of pu at 9039c98c.\n\nI won't queue this for now but will read and comment.\n\nThanks.\n"},{"id":"264863","messageId":"xmqqzj3nzrv6.fsf@gitster.dls.corp.google.com","threadId":"39712","inReplyTo":"1435173388-8346-2-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH 1/6] refs.c: add an err argument to log_ref_setup","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-25T16:15:41Z","receivedAt":"2015-06-25T16:15:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"David Turner <dturner@twopensource.com> writes:\n\n> Add err argument to log_ref_setup that can explain the reason for a\n> failure. This then eliminates the need to manage errno through this\n> function since we can just add strerror(errno) to the err string when\n> meaningful. No callers relied on errno from this function for anything\n> else than the error message.\n\nI think I saw Michael did something similar to other codepaths in\nthe ref API recently, and going in the same direction is generally a\ngood thing to do for consistency ;-)\n\n> write_ref_to_lockfile is a private function that calls\n> log_ref_setup. Update this function to also take an err argument and\n> fill it in.  This again eliminates the need to manage errno in this\n> function.\n\nThis particular patch is not just about log_ref_setup() and its\nprivate friend write_ref_to_lockfile(), right?  It seems to also\ntouch commit_ref_update(), log_ref_write(), etc.  The overall\n\"theme\" of this change is to teach parts of the ref API that deal\nwith writing reflogs to report errors the same way (i.e. as the\nremainder of the ref API does by using &err), and that may be a\ngood single-line summary of the change (aka \"Subject\").\n\n>  \t\t\t\tif (ret) {\n> -\t\t\t\t\tfprintf(stderr, _(\"Can not do reflog for '%s'\\n\"),\n> -\t\t\t\t\t    opts->new_orphan_branch);\n> +\t\t\t\t\tfprintf(stderr, _(\"Can not do reflog for '%s'. %s\\n\"),\n> +\t\t\t\t\topts->new_orphan_branch, err.buf);\n\nOriginal is underindented but this makes it even worse.  Push\ncontinuation line further to the right (or restructure the code so\nthat it does not have to indent too deeply in the first place).\n\nOther than that, this step looks sensible.\n\nThanks.\n"},{"id":"264864","messageId":"xmqqvbebzqns.fsf@gitster.dls.corp.google.com","threadId":"39712","inReplyTo":"1435173388-8346-3-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH 2/6] cherry-pick: Use refs infrastructure for CHERRY_PICK_HEAD","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-25T16:41:43Z","receivedAt":"2015-06-25T16:41:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"David Turner <dturner@twopensource.com> writes:\n\n> Subject: Re: [PATCH 2/6] cherry-pick: Use refs infrastructure for CHERRY_PICK_HEAD\n> Also use refs infrastructure for REVERT_HEAD.  These refs\n> need to go through the refs backend, since some code\n> assumes that they can be read as refs.\n\n\tcherry-pick: treat CHERRY_PICK_HEAD and REVERT_HEAD as refs\n\n\tInstead of directly writing to and reading from files in\n        $GIT_DIR, use ref API to interact with CHERRY_PICK_HEAD\n\tand REVERT_HEAD.\n\n\n>  void remove_branch_state(void)\n>  {\n> -\tunlink(git_path(\"CHERRY_PICK_HEAD\"));\n> -\tunlink(git_path(\"REVERT_HEAD\"));\n> +\tdelete_ref(\"CHERRY_PICK_HEAD\", NULL, REF_NODEREF | REF_NO_REFLOG);\n> +\tdelete_ref(\"REVERT_HEAD\", NULL, REF_NODEREF | REF_NO_REFLOG);\n\nInteresting.  There is a separate question about NO_REFLOG I'll\ndiscuss in more detail later.  But no-deref puzzled me.  They should\nnot be symbolic, but if somebody by mistake made a symbolic one, we\nwon't accidentally remove another unrelated one through them, so\nthat bit is a good thing to have.\n\n>  static void determine_whence(struct wt_status *s)\n>  {\n> +\tunsigned char unused[20];\n>  \tif (file_exists(git_path(\"MERGE_HEAD\")))\n>  \t\twhence = FROM_MERGE;\n> -\telse if (file_exists(git_path(\"CHERRY_PICK_HEAD\"))) {\n> +\telse if (!read_ref(\"CHERRY_PICK_HEAD\", unused)) {\n\nI would have expected that you would use ref_exists() here.\n\n> diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh\n> index 366f0bc..5e27a34 100644\n> --- a/contrib/completion/git-prompt.sh\n> +++ b/contrib/completion/git-prompt.sh\n> @@ -415,9 +415,9 @@ __git_ps1 ()\n>  \t\t\tfi\n>  \t\telif [ -f \"$g/MERGE_HEAD\" ]; then\n>  \t\t\tr=\"|MERGING\"\n> -\t\telif [ -f \"$g/CHERRY_PICK_HEAD\" ]; then\n> +\t\telif git rev-parse --quiet --verify \"CHERRY_PICK_HEAD\" >/dev/null; then\n>  \t\t\tr=\"|CHERRY-PICKING\"\n> -\t\telif [ -f \"$g/REVERT_HEAD\" ]; then\n> +\t\telif git rev-parse --quiet --verify \"REVERT_HEAD\" >/dev/null; then\n>  \t\t\tr=\"|REVERTING\"\n\nFunctionality-wise this may be OK but at some point we might want to\nhave a native way to produce $r with a single execution of a binary.\n\n> @@ -429,8 +429,9 @@ __git_ps1 ()\n>  \t\t\t# symlink symbolic ref\n>  \t\t\tb=\"$(git symbolic-ref HEAD 2>/dev/null)\"\n>  \t\telse\n> -\t\t\tlocal head=\"\"\n> -\t\t\tif ! __git_eread \"$g/HEAD\" head; then\n> +\t\t\tlocal head\n> +\t\t\thead=\"ref: $(git symbolic-ref HEAD 2>/dev/null)\" || head=$(git rev-parse HEAD)\n> +\t\t\tif [ -z \"$head\" ]; then\n\nThis is questionable; before the pre-context of this hunk is a check\nfor \"HEAD\" inside $GIT_DIR on the filesystem.  Besides, the \"theme\"\nof this patch is about CHERRY_PICK_HEAD and REVERT_HEAD; it does not\njustify to touch things that deal with HEAD in the same patch.\n\n> diff --git a/refs.c b/refs.c\n> index b34a54a..c1a563f 100644\n> --- a/refs.c\n> +++ b/refs.c\n> @@ -2979,7 +2979,7 @@ static int write_ref_to_lockfile(struct ref_lock *lock,\n>  \t\t\t\t const unsigned char *sha1, struct strbuf* err);\n>  static int commit_ref_update(struct ref_lock *lock,\n>  \t\t\t     const unsigned char *sha1, const char *logmsg,\n> -\t\t\t     struct strbuf *err);\n> +\t\t\t     struct strbuf *err, int flags);\n>  \n>  int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)\n>  {\n> @@ -3041,7 +3041,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n>  \thashcpy(lock->old_oid.hash, orig_sha1);\n>  \n>  \tif (write_ref_to_lockfile(lock, orig_sha1, &err) ||\n> -\t    commit_ref_update(lock, orig_sha1, logmsg, &err)) {\n> +\t    commit_ref_update(lock, orig_sha1, logmsg, &err, 0)) {\n>  \t\terror(\"unable to write current sha1 into %s: %s\", newrefname, err.buf);\n>  \t\tstrbuf_release(&err);\n>  \t\tgoto rollback;\n> @@ -3060,7 +3060,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms\n>  \tflag = log_all_ref_updates;\n>  \tlog_all_ref_updates = 0;\n>  \tif (write_ref_to_lockfile(lock, orig_sha1, &err) ||\n> -\t    commit_ref_update(lock, orig_sha1, NULL, &err)) {\n> +\t    commit_ref_update(lock, orig_sha1, NULL, &err, 0)) {\n>  \t\terror(\"unable to write current sha1 into %s: %s\", oldrefname, err.buf);\n>  \t\tstrbuf_release(&err);\n>  \t}\n> @@ -3291,12 +3291,13 @@ static int write_ref_to_lockfile(struct ref_lock *lock,\n>   */\n>  static int commit_ref_update(struct ref_lock *lock,\n>  \t\t\t     const unsigned char *sha1, const char *logmsg,\n> -\t\t\t     struct strbuf *err)\n> +\t\t\t     struct strbuf *err, int flags)\n>  {\n>  \tclear_loose_ref_cache(&ref_cache);\n> -\tif (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, err) < 0 ||\n> -\t    (strcmp(lock->ref_name, lock->orig_ref_name) &&\n> -\t     log_ref_write(lock->orig_ref_name, lock->old_oid.hash, sha1, logmsg, err) < 0)) {\n> +\tif (!(flags & REF_NO_REFLOG) &&\n> +\t    (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, err) < 0 ||\n> +\t     (strcmp(lock->ref_name, lock->orig_ref_name) &&\n> +\t      log_ref_write(lock->orig_ref_name, lock->old_oid.hash, sha1, logmsg, err) < 0))) {\n\nWhat is this change about?  I suspect this should be a separate\npreparatory commit to allow callers to skip reflog update.\n\nBut more importantly, I do not think that it is a good idea in the\nfirst place to allow callers to selectively say \"for this update, do\nnot write a reflog entry\".  If you do three ref-updates on the same\nref in a sequence (e.g. imagine you created a single strand of\npearls consisting of three commits) but passed ref-no-reflog only\nfor the second update, wouldn't that make your reflog entries\ninconsistent?\n\nREF_NO_REFLOG functionality that seletively allows updates to be\nskipped should *NOT* exist, I think.\n\nIn other words, I think \"do updates logged\" should be a property of\neach ref.  If changes to a ref is to be logged, all changes to it\nmust be logged.  If changes to a ref is not to be logged, no changes\nto it must be logged.\n\nThe core.logAllRefUpdates configuration may appear to throw a monkey\nwrench to that if its name is taken literally, as your creation of\nCHECK_HEAD may get logged, which is not what you want.  But we are\nunder no obligation to obey core.logAllRefUpdates when updating\nCHECK_HEAD or REVERT_HEAD.\n\ncore.logAllRefUpdates::\n\tEnable the reflog. Updates to a ref <ref> is logged to the file\n\t\"$GIT_DIR/logs/<ref>\", by appending the new and old\n\tSHA-1, the date/time and the reason of the update, but\n\tonly when the file exists.  If this configuration\n\tvariable is set to true, missing \"$GIT_DIR/logs/<ref>\"\n\tfile is automatically created for branch heads (i.e. under\n\trefs/heads/), remote refs (i.e. under refs/remotes/),\n\tnote refs (i.e. under refs/notes/), and the symbolic ref HEAD.\n\nIt is fairly clear that we promise not to auto-vivify reflogs for\nCHERRY_PICK_HEAD and REVERT_HEAD from this description.\n\nAnd if some users create $GIT_DIR/logs/CHERRY_PICK_HEAD to enable\nreflog for CHERRY_PICK_HEAD, then it is not our business to refuse\nlogging the change just to speed things up a bit.\n"},{"id":"264866","messageId":"xmqqr3ozzq6k.fsf@gitster.dls.corp.google.com","threadId":"39712","inReplyTo":"1435173388-8346-4-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH 3/6] bisect: use refs infrastructure for BISECT_START","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-25T16:52:03Z","receivedAt":"2015-06-25T16:52:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"David Turner <dturner@twopensource.com> writes:\n\n> This ref needs to go through the refs backend, since some code assumes\n> that it can be written and read as a ref.\n\nAnd BISECT_HEAD should no longer be a ref because...?\n\n>\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> ---\n>  contrib/completion/git-completion.bash | 2 +-\n>  git-bisect.sh                          | 4 ++--\n>  2 files changed, 3 insertions(+), 3 deletions(-)\n>\n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index 93716c4..c4d4d80 100644\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -938,7 +938,7 @@ _git_bisect ()\n>  \tlocal subcommands=\"start bad good skip reset visualize replay log run\"\n>  \tlocal subcommand=\"$(__git_find_on_cmdline \"$subcommands\")\"\n>  \tif [ -z \"$subcommand\" ]; then\n> -\t\tif [ -f \"$(__gitdir)\"/BISECT_START ]; then\n> +\t\tif [ git rev-parse BISECT_START 2>/dev/null ]; then\n>  \t\t\t__gitcomp \"$subcommands\"\n>  \t\telse\n>  \t\t\t__gitcomp \"replay start\"\n> diff --git a/git-bisect.sh b/git-bisect.sh\n> index ae3fec2..8658772 100755\n> --- a/git-bisect.sh\n> +++ b/git-bisect.sh\n> @@ -166,7 +166,7 @@ bisect_start() {\n>  \t#\n>  \techo \"$start_head\" >\"$GIT_DIR/BISECT_START\" && {\n>  \t\ttest \"z$mode\" != \"z--no-checkout\" ||\n> -\t\tgit update-ref --no-deref BISECT_HEAD \"$start_head\"\n> +\t\tgit rev-parse \"$start_head\" > \"$GIT_DIR/BISECT_HEAD\"\n>  \t} &&\n>  \tgit rev-parse --sq-quote \"$@\" >\"$GIT_DIR/BISECT_NAMES\" &&\n>  \teval \"$eval true\" &&\n> @@ -399,7 +399,7 @@ bisect_clean_state() {\n>  \trm -f \"$GIT_DIR/BISECT_RUN\" &&\n>  \t# Cleanup head-name if it got left by an old version of git-bisect\n>  \trm -f \"$GIT_DIR/head-name\" &&\n> -\tgit update-ref -d --no-deref BISECT_HEAD &&\n> +\trm -f \"$GIT_DIR/BISECT_HEAD\" &&\n>  \t# clean up BISECT_START last\n>  \trm -f \"$GIT_DIR/BISECT_START\"\n>  }\n"},{"id":"264869","messageId":"xmqqmvznzq2p.fsf@gitster.dls.corp.google.com","threadId":"39712","inReplyTo":"1435173388-8346-5-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH 4/6] refs: replace log_ref_write with create_reflog","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-25T16:54:22Z","receivedAt":"2015-06-25T16:54:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"David Turner <dturner@twopensource.com> writes:\n\n> In a moment, we will use this to add reflog creation commands to\n> git-reflog.\n>\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> ---\n\nThe title is misleading, if this is merely renaming.  I first\nthought with this change the current callers of log_ref_setup()\nwould get a different/updated behaviour from the API by calling\nsomething else, but that is not the case.\n\n>  builtin/checkout.c | 2 +-\n>  refs.c             | 4 ++--\n>  refs.h             | 2 +-\n>  3 files changed, 4 insertions(+), 4 deletions(-)\n>\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index ac4d10a..7549ae2 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -629,7 +629,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts,\n>  \t\t\t\tref_name = mkpath(\"refs/heads/%s\", opts->new_orphan_branch);\n>  \t\t\t\ttemp = log_all_ref_updates;\n>  \t\t\t\tlog_all_ref_updates = 1;\n> -\t\t\t\tret = log_ref_setup(ref_name, &log_file, &err);\n> +\t\t\t\tret = create_reflog(ref_name, &log_file, &err);\n>  \t\t\t\tlog_all_ref_updates = temp;\n>  \t\t\t\tstrbuf_release(&log_file);\n>  \t\t\t\tif (ret) {\n> diff --git a/refs.c b/refs.c\n> index c1a563f..93412ee 100644\n> --- a/refs.c\n> +++ b/refs.c\n> @@ -3119,7 +3119,7 @@ static int copy_msg(char *buf, const char *msg)\n>  }\n>  \n>  /* This function will fill in *err and return -1 on failure */\n> -int log_ref_setup(const char *refname, struct strbuf *sb_logfile, struct strbuf *err)\n> +int create_reflog(const char *refname, struct strbuf *sb_logfile, struct strbuf *err)\n>  {\n>  \tint logfd, oflags = O_APPEND | O_WRONLY;\n>  \tchar *logfile;\n> @@ -3203,7 +3203,7 @@ static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,\n>  \tif (log_all_ref_updates < 0)\n>  \t\tlog_all_ref_updates = !is_bare_repository();\n>  \n> -\tresult = log_ref_setup(refname, sb_log_file, err);\n> +\tresult = create_reflog(refname, sb_log_file, err);\n>  \n>  \tif (result)\n>  \t\treturn result;\n> diff --git a/refs.h b/refs.h\n> index eee99f6..d4f75a9 100644\n> --- a/refs.h\n> +++ b/refs.h\n> @@ -233,7 +233,7 @@ int pack_refs(unsigned int flags);\n>  /*\n>   * Setup reflog before using. Fill in err and return -1 on failure.\n>   */\n> -int log_ref_setup(const char *refname, struct strbuf *logfile, struct strbuf *err);\n> +int create_reflog(const char *refname, struct strbuf *logfile, struct strbuf *err);\n>  \n>  /** Reads log for the value of ref during at_time. **/\n>  extern int read_ref_at(const char *refname, unsigned int flags,\n"},{"id":"264873","messageId":"xmqqioabzoz2.fsf@gitster.dls.corp.google.com","threadId":"39712","inReplyTo":"1435173388-8346-6-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH 5/6] git-reflog: add create and exists functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-25T17:18:09Z","receivedAt":"2015-06-25T17:18:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"David Turner <dturner@twopensource.com> writes:\n\n> These are necessary because ref backends manage reflogs.\n\nBecause?\n\n\tBecause with core.logAllRefUpdates set to false, creating or\n        updating a ref would not log what is done to it, unless a\n        reflog already exists for the ref.  There are cases where\n        we always want to have a reflog for a ref (e.g. refs/stash)\n        regardless of the value of core.logAllRefUpdates, and we\n        need a way to ensure that a reflog for a ref exists.\n        \"reflog create\" is the way to do so.\n\n\tAlso we need to be able to tell if a reflog for a ref\n\texists, and \"reflog exists\" is the way to do so.\n\nNow, going back to 4/6, I think create_reflog() function as an\nexternal API has a few problems.\n\n * Its name does not tell us what should happen when a reflog\n   already exists for the refname the caller asked to \"create\"\n   reflog for.  I understand that this only makes sure it exists and\n   does not destroy existing one.  Its old name, log_ref_setup(),\n   did not have this problem, but now it does.\n\n * Its second parameter that is a strbuf is used only internally\n   from within log_ref_write_1(); all the external callers do not\n   look at it and they are forced to strbuf_init() it before calling\n   the function and to strbuf_release() after the function returns.\n\nOh, also 4/6 incorrectly says that log_ref_write() is renamed to\ncreate_reflog(), but it was log_ref_setup() that was renamed.\n\nI think what 4/6 should have done in order to make the guts of what\nlog_ref_setup() does available as a more useful external API is to\n\n * keep log_ref_setup() as-is, make it static to refs.c, and have\n   the internal caller that cares about the strbuf (i.e. the path\n   to the log file) call that; and\n\n * Add a thin-wrapper for callers that do not care about the path to\n   the log file, e.g.\n\n\tint vivify_reflog(const char *refname, struct strbuf *err)\n\t{\n\t\tint ret;\n\t\tstruct strbuf sb = STRBUF_INIT;\n\n                ret = log_ref_setup(refname, &sb, err);\n                strbuf_release(&sb);\n                return ret;\n\t}\n\nHmm?\n    \n"},{"id":"264878","messageId":"xmqq381fzlei.fsf@gitster.dls.corp.google.com","threadId":"39712","inReplyTo":"xmqqioabzoz2.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 5/6] git-reflog: add create and exists functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-25T18:35:17Z","receivedAt":"2015-06-25T18:35:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Now, going back to 4/6, I think create_reflog() function as an\n> external API has a few problems.\n>\n>  * Its name does not tell us what should happen when a reflog\n>    already exists for the refname the caller asked to \"create\"\n>    reflog for.  I understand that this only makes sure it exists and\n>    does not destroy existing one.  Its old name, log_ref_setup(),\n>    did not have this problem, but now it does.\n> ...\n>  * Add a thin-wrapper for callers that do not care about the path to\n>    the log file, e.g.\n>\n> \tint vivify_reflog(const char *refname, struct strbuf *err)\n> \t{\n\nAs usual, I am aware that I am not good at naming things (but I can\ntell when somebody uses a bad name), and \"vivify\" may be a horrible\nname for that.  A reroll with a better name is very much welcomed.\n\nPerhaps prepare-reflog?  I dunno.\n"},{"id":"264895","messageId":"1435264174.7900.2.camel@twopensource.com","threadId":"39712","inReplyTo":"xmqqr3ozzq6k.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 3/6] bisect: use refs infrastructure for BISECT_START","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-25T20:29:34Z","receivedAt":"2015-06-25T20:29:34Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"On Thu, 2015-06-25 at 09:52 -0700, Junio C Hamano wrote:\n> David Turner <dturner@twopensource.com> writes:\n> \n> > This ref needs to go through the refs backend, since some code assumes\n> > that it can be written and read as a ref.\n> \n> And BISECT_HEAD should no longer be a ref because...?\n\nI can't remember now why I did this.  I guess we'll find out as we work\non the remaining patches.  I'll take it out for now.\n"},{"id":"264896","messageId":"1435264294.7900.3.camel@twopensource.com","threadId":"39712","inReplyTo":"xmqq381fzlei.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH 5/6] git-reflog: add create and exists functions","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-25T20:31:34Z","receivedAt":"2015-06-25T20:31:34Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"On Thu, 2015-06-25 at 11:35 -0700, Junio C Hamano wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n> > Now, going back to 4/6, I think create_reflog() function as an\n> > external API has a few problems.\n> >\n> >  * Its name does not tell us what should happen when a reflog\n> >    already exists for the refname the caller asked to \"create\"\n> >    reflog for.  I understand that this only makes sure it exists and\n> >    does not destroy existing one.  Its old name, log_ref_setup(),\n> >    did not have this problem, but now it does.\n> > ...\n> >  * Add a thin-wrapper for callers that do not care about the path to\n> >    the log file, e.g.\n> >\n> > \tint vivify_reflog(const char *refname, struct strbuf *err)\n> > \t{\n> \n> As usual, I am aware that I am not good at naming things (but I can\n> tell when somebody uses a bad name), and \"vivify\" may be a horrible\n> name for that.  A reroll with a better name is very much welcomed.\n> \n> Perhaps prepare-reflog?  I dunno.\n\nI'll try safe_create_reflog, by analogy to safe_create_leading_dirs.\n"}]}