{"thread":{"id":"39728","subject":"[PATCH v2 1/6] refs.c: add err arguments to reflog functions","startedAt":"2015-06-25T20:45:05Z","lastAt":"2015-06-26T00:22:53Z","messageCount":14,"participants":["David Turner","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":6},"messages":[{"id":"264897","messageId":"1435265110-6414-1-git-send-email-dturner@twopensource.com","threadId":"39728","inReplyTo":null,"subject":"[PATCH v2 1/6] refs.c: add err arguments to reflog functions","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-25T20:45:05Z","receivedAt":"2015-06-25T20:45:05Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Add an err argument to log_ref_setup that can explain the reason\nfor a failure. This then eliminates the need to manage errno through\nthis function since we can just add strerror(errno) to the err string\nwhen meaningful. No callers relied on errno from this function for\nanything else than the error message.\n\nAlso add err arguments to private functions write_ref_to_lockfile,\nlog_ref_write_1, commit_ref_update. This again eliminates the need to\nmanage errno in these functions.\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..93f63d3 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\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":"264899","messageId":"1435265110-6414-2-git-send-email-dturner@twopensource.com","threadId":"39728","inReplyTo":"1435265110-6414-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v2 2/6] cherry-pick: treat CHERRY_PICK_HEAD and REVERT_HEAD as refs","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-25T20:45:06Z","receivedAt":"2015-06-25T20:45:06Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Instead of directly writing to and reading from files in\n$GIT_DIR, use ref API to interact with CHERRY_PICK_HEAD\nand REVERT_HEAD.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n branch.c                         |  4 ++--\n builtin/commit.c                 |  6 +++---\n builtin/merge.c                  |  2 +-\n contrib/completion/git-prompt.sh |  4 ++--\n git-gui/lib/commit.tcl           |  2 +-\n refs.c                           | 32 +++++++++++++++++++-------------\n sequencer.c                      | 37 +++++++++++++++++++------------------\n t/t7509-commit.sh                |  4 ++--\n wt-status.c                      |  6 ++----\n 9 files changed, 51 insertions(+), 46 deletions(-)\n\ndiff --git a/branch.c b/branch.c\nindex b002435..ec598aa 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);\n+\tdelete_ref(\"REVERT_HEAD\", NULL, REF_NODEREF);\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..53c7e90 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -168,7 +168,7 @@ static void determine_whence(struct wt_status *s)\n {\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 (ref_exists(\"CHERRY_PICK_HEAD\")) {\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 +1777,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);\n+\tdelete_ref(\"REVERT_HEAD\", NULL, REF_NODEREF);\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..3e2ae2f 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1206,7 +1206,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 (ref_exists(\"CHERRY_PICK_HEAD\")) {\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..e2c5583 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\"\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..de7b5ef 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@@ -3118,6 +3118,14 @@ static int copy_msg(char *buf, const char *msg)\n \treturn cp - buf;\n }\n \n+static int should_autocreate_reflog(const char *refname)\n+{\n+\treturn starts_with(refname, \"refs/heads/\") ||\n+\t\tstarts_with(refname, \"refs/remotes/\") ||\n+\t\tstarts_with(refname, \"refs/notes/\") ||\n+\t\t!strcmp(refname, \"HEAD\");\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 {\n@@ -3128,11 +3136,7 @@ int log_ref_setup(const char *refname, struct strbuf *sb_logfile, struct strbuf\n \tlogfile = sb_logfile->buf;\n \t/* make sure the rest of the function can't change \"logfile\" */\n \tsb_logfile = NULL;\n-\tif (log_all_ref_updates &&\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, \"HEAD\"))) {\n+\tif (log_all_ref_updates && should_autocreate_reflog(refname)) {\n \t\tif (safe_create_leading_directories(logfile) < 0) {\n \t\t\tstrbuf_addf(err, \"unable to create directory for %s. \"\n \t\t\t\t    \"%s\", logfile, strerror(errno));\n@@ -3291,12 +3295,14 @@ 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 ((should_autocreate_reflog(lock->ref_name) ||\n+\t     reflog_exists(lock->ref_name)) &&\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 +4069,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/sequencer.c b/sequencer.c\nindex f8421a8..de904aa 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, 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@@ -1014,8 +1015,8 @@ static int continue_single_pick(void)\n {\n \tconst char *argv[] = { \"commit\", NULL };\n \n-\tif (!file_exists(git_path(\"CHERRY_PICK_HEAD\")) &&\n-\t    !file_exists(git_path(\"REVERT_HEAD\")))\n+\tif (!ref_exists(\"CHERRY_PICK_HEAD\") &&\n+\t    !ref_exists(\"REVERT_HEAD\"))\n \t\treturn error(_(\"no cherry-pick or revert in progress\"));\n \treturn run_command_v_opt(argv, RUN_GIT_CMD);\n }\n@@ -1030,8 +1031,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 (ref_exists(\"CHERRY_PICK_HEAD\") ||\n+\t    ref_exists(\"REVERT_HEAD\")) {\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":"264900","messageId":"1435265110-6414-3-git-send-email-dturner@twopensource.com","threadId":"39728","inReplyTo":"1435265110-6414-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v2 3/6] bisect: use refs infrastructure for BISECT_START","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-25T20:45:07Z","receivedAt":"2015-06-25T20:45:07Z","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":"264898","messageId":"1435265110-6414-4-git-send-email-dturner@twopensource.com","threadId":"39728","inReplyTo":"1435265110-6414-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v2 4/6] refs: add safe_create_reflog function","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-25T20:45:08Z","receivedAt":"2015-06-25T20:45:08Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"Make log_ref_setup private, and add public safe_create_reflog which\ncalls log_ref_setup.\n\nIn a moment, we will use safe_create_reflog to add reflog creation\ncommands to git-reflog.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n builtin/checkout.c |  4 +---\n refs.c             | 11 +++++++++++\n refs.h             |  2 +-\n 3 files changed, 13 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 93f63d3..b793670 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -621,7 +621,6 @@ static void update_refs_for_switch(const struct checkout_opts *opts,\n \t\tif (opts->new_orphan_branch) {\n \t\t\tif (opts->new_branch_log && !log_all_ref_updates) {\n \t\t\t\tint temp;\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@@ -629,9 +628,8 @@ 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 = safe_create_reflog(ref_name, &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'. %s\\n\"),\n \t\t\t\t\t\topts->new_orphan_branch, err.buf);\ndiff --git a/refs.c b/refs.c\nindex de7b5ef..7b02c45 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -3171,6 +3171,17 @@ int log_ref_setup(const char *refname, struct strbuf *sb_logfile, struct strbuf\n \treturn 0;\n }\n \n+\n+int safe_create_reflog(const char *refname, struct strbuf *err)\n+{\n+\tint ret;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tret = log_ref_setup(refname, &sb, err);\n+\tstrbuf_release(&sb);\n+\treturn ret;\n+}\n+\n static int log_ref_write_fd(int fd, const unsigned char *old_sha1,\n \t\t\t    const unsigned char *new_sha1,\n \t\t\t    const char *committer, const char *msg)\ndiff --git a/refs.h b/refs.h\nindex debdefc..2986aac 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -228,7 +228,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 safe_create_reflog(const char *refname, 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":"264902","messageId":"1435265110-6414-5-git-send-email-dturner@twopensource.com","threadId":"39728","inReplyTo":"1435265110-6414-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v2 5/6] git-reflog: add create and exists functions","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-25T20:45:09Z","receivedAt":"2015-06-25T20:45:09Z","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 | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 78 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex c2eb8ff..a64158d 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,79 @@ 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+\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 (safe_create_reflog(argv[i], &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}\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 +795,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":"264901","messageId":"1435265110-6414-6-git-send-email-dturner@twopensource.com","threadId":"39728","inReplyTo":"1435265110-6414-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v2 6/6] git-stash: use git-reflog instead of creating files","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-25T20:45:10Z","receivedAt":"2015-06-25T20:45:10Z","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 7b02c45..e11a32b 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -3123,6 +3123,7 @@ static int should_autocreate_reflog(const char *refname)\n \treturn starts_with(refname, \"refs/heads/\") ||\n \t\tstarts_with(refname, \"refs/remotes/\") ||\n \t\tstarts_with(refname, \"refs/notes/\") ||\n+\t\t!strcmp(refname, \"refs/stash\") ||\n \t\t!strcmp(refname, \"HEAD\");\n }\n \n-- \n2.0.4.314.gdbf7a51-twtrsrc\n"},{"id":"264904","messageId":"xmqq616by0h3.fsf@gitster.dls.corp.google.com","threadId":"39728","inReplyTo":"1435265110-6414-3-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v2 3/6] bisect: use refs infrastructure for BISECT_START","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-25T20:52:40Z","receivedAt":"2015-06-25T20:52:40Z","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 the reason why BISECT_HEAD cannot be treated as a ref, but must\nbe treated as a file under $GIT_DIR, is...?\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":"264905","messageId":"xmqq1tgzy027.fsf@gitster.dls.corp.google.com","threadId":"39728","inReplyTo":"1435265110-6414-5-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v2 5/6] git-reflog: add create and exists functions","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-25T21:01:36Z","receivedAt":"2015-06-25T21:01:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"David Turner <dturner@twopensource.com> writes:\n\nBecause...???\n\n> These are necessary because ref backends manage reflogs.\n\n\"Because ref backends manage reflogs\" may be a good explanation to\nimplement something as part of ref API, but it does not explain why\nthat something needs to be implemented in the first place.\n\n> In a moment,\n> we will use these functions to make git stash work with alternate\n> ref backends.\n>\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> ---\n>  builtin/reflog.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n>  1 file changed, 78 insertions(+), 1 deletion(-)\n>\n> diff --git a/builtin/reflog.c b/builtin/reflog.c\n> index c2eb8ff..a64158d 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\nIt makes sense to take more than one; you may want to prepare more\nthan one, and you would signal error by exiting with a non-zero\nstatus if any of them failed.\n\n> +static const char reflog_exists_usage[] =\n> +\"git reflog exists <refs>...\";\n\nThis is iffy, though.  \"git reflog exists foo bar\" says \"all of them\nexist\" or \"some of them exist\"?  Why is it more useful to implement\n\"all of them exist\"?\n\nPerhaps dropping \"...\" would be simpler to explain and less\nconfusing.\n\n> @@ -699,12 +703,79 @@ 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> +\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\ns/start ;/start;/ (everywhere).\n"},{"id":"264906","messageId":"xmqqwpyrwlgd.fsf@gitster.dls.corp.google.com","threadId":"39728","inReplyTo":"1435265110-6414-4-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v2 4/6] refs: add safe_create_reflog function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-25T21:02:26Z","receivedAt":"2015-06-25T21:02:26Z","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> Make log_ref_setup private, and add public safe_create_reflog which\n> calls log_ref_setup.\n>\n> In a moment, we will use safe_create_reflog to add reflog creation\n> commands to git-reflog.\n>\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> ---\n>  builtin/checkout.c |  4 +---\n>  refs.c             | 11 +++++++++++\n>  refs.h             |  2 +-\n>  3 files changed, 13 insertions(+), 4 deletions(-)\n>\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index 93f63d3..b793670 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -621,7 +621,6 @@ static void update_refs_for_switch(const struct checkout_opts *opts,\n>  \t\tif (opts->new_orphan_branch) {\n>  \t\t\tif (opts->new_branch_log && !log_all_ref_updates) {\n>  \t\t\t\tint temp;\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> @@ -629,9 +628,8 @@ 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 = safe_create_reflog(ref_name, &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'. %s\\n\"),\n>  \t\t\t\t\t\topts->new_orphan_branch, err.buf);\n\nYup, much nicer ;-)\n\n> diff --git a/refs.c b/refs.c\n> index de7b5ef..7b02c45 100644\n> --- a/refs.c\n> +++ b/refs.c\n> @@ -3171,6 +3171,17 @@ int log_ref_setup(const char *refname, struct strbuf *sb_logfile, struct strbuf\n>  \treturn 0;\n>  }\n>  \n> +\n> +int safe_create_reflog(const char *refname, struct strbuf *err)\n> +{\n> +\tint ret;\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\n> +\tret = log_ref_setup(refname, &sb, err);\n> +\tstrbuf_release(&sb);\n> +\treturn ret;\n> +}\n> +\n>  static int log_ref_write_fd(int fd, const unsigned char *old_sha1,\n>  \t\t\t    const unsigned char *new_sha1,\n>  \t\t\t    const char *committer, const char *msg)\n> diff --git a/refs.h b/refs.h\n> index debdefc..2986aac 100644\n> --- a/refs.h\n> +++ b/refs.h\n> @@ -228,7 +228,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 safe_create_reflog(const char *refname, 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":"264908","messageId":"xmqqsi9fwl0i.fsf@gitster.dls.corp.google.com","threadId":"39728","inReplyTo":"1435265110-6414-2-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v2 2/6] cherry-pick: treat CHERRY_PICK_HEAD and REVERT_HEAD as refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-25T21:11:57Z","receivedAt":"2015-06-25T21:11:57Z","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> Instead of directly writing to and reading from files in\n> $GIT_DIR, use ref API to interact with CHERRY_PICK_HEAD\n> and REVERT_HEAD.\n>\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> ---\n\nI may have said this already in the last round, but I cannot shake\noff the feeling that this patch is doing two completely unrelated\nthings at once.\n\nThe change to refs.c that introduced the should_autocreate_reflog()\nhelper (which is a good idea even without any other changes in this\npatch) and then using that to commit_ref_update() does not have\nanything to do with CHERRY_PICK_HEAD/REVERT_HEAD, does it?\n\n * commit_ref_update() gained a new \"flags\" parameter, but it does\n   not seem to be used at all.  Why?\n\n * Why is it a good idea to move the \"does the log exist or should\n   we auto-create?\" check from log_ref_setup() to\n   commit_ref_update()?\n\nThese are not just unexplained, but does not have anything to do\nwith using ref API to write and read CHERRY_PICK_HEAD/REVERT_HEAD.\n\nThey _might_ be a prerequisite, but it is not clear why.  I suspect\nthat you do not have to touch refs.c at all for the purpose of the\n\"theme\" of the patch explained by the \"Subject\" line.\n"},{"id":"264912","messageId":"1435269105.7900.9.camel@twopensource.com","threadId":"39728","inReplyTo":"1435265110-6414-5-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v2 5/6] git-reflog: add create and exists functions","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-25T21:51:45Z","receivedAt":"2015-06-25T21:51:45Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"On Thu, 2015-06-25 at 16:45 -0400, David Turner wrote:\n> +static int cmd_reflog_create(int argc, const char **argv, const char *prefix)\n> +{\n\nWhile revising this patch, I noticed that safe_create_reflog (and this\ncmd_reflog_create) only creates reflogs for refs of the form that git\nitself would autocreate reflogs for.  In other words, it won't create a\nreflog for foo, but will create a reflog for refs/heads/foo (even though\nthat is very likely to already exist).\n\nSo I'll fix that when I re-roll.\n"},{"id":"264914","messageId":"1435271365.7900.16.camel@twopensource.com","threadId":"39728","inReplyTo":"xmqqsi9fwl0i.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH v2 2/6] cherry-pick: treat CHERRY_PICK_HEAD and REVERT_HEAD as refs","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-25T22:29:25Z","receivedAt":"2015-06-25T22:29:25Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"On Thu, 2015-06-25 at 14:11 -0700, Junio C Hamano wrote:\n> David Turner <dturner@twopensource.com> writes:\n> \n> > Instead of directly writing to and reading from files in\n> > $GIT_DIR, use ref API to interact with CHERRY_PICK_HEAD\n> > and REVERT_HEAD.\n> >\n> > Signed-off-by: David Turner <dturner@twopensource.com>\n> > ---\n> \n> I may have said this already in the last round, but I cannot shake\n> off the feeling that this patch is doing two completely unrelated\n> things at once.\n> \n> The change to refs.c that introduced the should_autocreate_reflog()\n> helper (which is a good idea even without any other changes in this\n> patch) \n\nI'll break that out into a separate patch when I reroll.\n\n> and then using that to commit_ref_update() does not have\n> anything to do with CHERRY_PICK_HEAD/REVERT_HEAD, does it?\n\nI had thought that it did, but some testing shows that it does not (or\nat least does not yet).  The original series of patches was assembled\nout of a long process of making the test suite pass with the alternate\nref backend.  I expect that as I rewrite that series, I'll either figure\nout what issues these change solved, or remove them.  In this case, I'll\nsplit the patch.\n\n>  * commit_ref_update() gained a new \"flags\" parameter, but it does\n>    not seem to be used at all.  Why?\n\ncruft, will remove.\n"},{"id":"264916","messageId":"1435274490.7900.19.camel@twopensource.com","threadId":"39728","inReplyTo":"xmqq616by0h3.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH v2 3/6] bisect: use refs infrastructure for BISECT_START","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-25T23:21:30Z","receivedAt":"2015-06-25T23:21:30Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"On Thu, 2015-06-25 at 13: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 the reason why BISECT_HEAD cannot be treated as a ref, but must\n> be treated as a file under $GIT_DIR, is...?\n\nAfter running some tests on the long version of the series, we can and\nshould move it into the backend; will add a patch to the next reroll\n"},{"id":"264918","messageId":"1435278173.7900.27.camel@twopensource.com","threadId":"39728","inReplyTo":"1435274490.7900.19.camel@twopensource.com","subject":"Re: [PATCH v2 3/6] bisect: use refs infrastructure for BISECT_START","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-26T00:22:53Z","receivedAt":"2015-06-26T00:22:53Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"On Thu, 2015-06-25 at 19:21 -0400, David Turner wrote:\n> On Thu, 2015-06-25 at 13: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 the reason why BISECT_HEAD cannot be treated as a ref, but must\n> > be treated as a file under $GIT_DIR, is...?\n> \n> After running some tests on the long version of the series, we can and\n> should move it into the backend; will add a patch to the next reroll\n\nActually, I've looked into this further. BISECT_START isn't a ref\nbecause it contains the ref name that the bisection started from (not a\nsymbolic ref).  BISECT_HEAD is a ref.  Will fix.\n"}]}