{"thread":{"id":"39729","subject":"[PATCH v3 1/7] refs.c: add err arguments to reflog functions","startedAt":"2015-06-26T00:29:02Z","lastAt":"2015-06-26T22:14:30Z","messageCount":12,"participants":["David Turner","Junio C Hamano"],"isPatch":true,"patchVersion":3,"patchTotal":7},"messages":[{"id":"264920","messageId":"1435278548-3790-1-git-send-email-dturner@twopensource.com","threadId":"39729","inReplyTo":null,"subject":"[PATCH v3 1/7] refs.c: add err arguments to reflog functions","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-26T00:29:02Z","receivedAt":"2015-06-26T00:29:02Z","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@twopensource.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":"264923","messageId":"1435278548-3790-2-git-send-email-dturner@twopensource.com","threadId":"39729","inReplyTo":"1435278548-3790-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v3 2/7] cherry-pick: treat CHERRY_PICK_HEAD and REVERT_HEAD as refs","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-26T00:29:03Z","receivedAt":"2015-06-26T00:29:03Z","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 sequencer.c                      | 37 +++++++++++++++++++------------------\n t/t7509-commit.sh                |  4 ++--\n wt-status.c                      |  6 ++----\n 8 files changed, 32 insertions(+), 33 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/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":"264921","messageId":"1435278548-3790-3-git-send-email-dturner@twopensource.com","threadId":"39729","inReplyTo":"1435278548-3790-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v3 3/7] bisect: treat BISECT_HEAD as a ref","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-26T00:29:04Z","receivedAt":"2015-06-26T00:29:04Z","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 BISECT_HEAD.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n git-bisect.sh | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/git-bisect.sh b/git-bisect.sh\nindex ae3fec2..dddcc89 100755\n--- a/git-bisect.sh\n+++ b/git-bisect.sh\n@@ -35,7 +35,7 @@ _x40=\"$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40\"\n \n bisect_head()\n {\n-\tif test -f \"$GIT_DIR/BISECT_HEAD\"\n+\tif bisect_head_exists\n \tthen\n \t\techo BISECT_HEAD\n \telse\n@@ -209,6 +209,10 @@ check_expected_revs() {\n \tdone\n }\n \n+bisect_head_exists() {\n+    git rev-parse --quiet --verify \"BISECT_HEAD\" >/dev/null\n+}\n+\n bisect_skip() {\n \tall=''\n \tfor arg in \"$@\"\n@@ -310,7 +314,7 @@ bisect_next() {\n \tbisect_next_check good\n \n \t# Perform all bisection computation, display and checkout\n-\tgit bisect--helper --next-all $(test -f \"$GIT_DIR/BISECT_HEAD\" && echo --no-checkout)\n+\tgit bisect--helper --next-all $(bisect_head_exists && echo --no-checkout)\n \tres=$?\n \n \t# Check if we should exit because bisection is finished\n@@ -377,7 +381,7 @@ bisect_reset() {\n \t\tusage ;;\n \tesac\n \n-\tif ! test -f \"$GIT_DIR/BISECT_HEAD\" && ! git checkout \"$branch\" --\n+\tif ! bisect_head_exists && ! git checkout \"$branch\" --\n \tthen\n \t\tdie \"$(eval_gettext \"Could not check out original HEAD '\\$branch'.\n Try 'git bisect reset <commit>'.\")\"\n-- \n2.0.4.314.gdbf7a51-twtrsrc\n"},{"id":"264922","messageId":"1435278548-3790-4-git-send-email-dturner@twopensource.com","threadId":"39729","inReplyTo":"1435278548-3790-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v3 4/7] refs: Break out check for reflog autocreation","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-26T00:29:05Z","receivedAt":"2015-06-26T00:29:05Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"This is just for clarity.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n refs.c | 14 +++++++++-----\n 1 file changed, 9 insertions(+), 5 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex b34a54a..dff91cf 100644\n--- a/refs.c\n+++ b/refs.c\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-- \n2.0.4.314.gdbf7a51-twtrsrc\n"},{"id":"264924","messageId":"1435278548-3790-5-git-send-email-dturner@twopensource.com","threadId":"39729","inReplyTo":"1435278548-3790-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v3 5/7] refs: add safe_create_reflog function","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-26T00:29:06Z","receivedAt":"2015-06-26T00:29:06Z","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             | 19 ++++++++++++++++---\n refs.h             |  2 +-\n 3 files changed, 18 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 93f63d3..55e4fbc 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, 0);\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 dff91cf..7519dac 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -3123,11 +3123,12 @@ 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 /* 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+static int log_ref_setup(const char *refname, struct strbuf *sb_logfile, struct strbuf *err, int force_create)\n {\n \tint logfd, oflags = O_APPEND | O_WRONLY;\n \tchar *logfile;\n@@ -3136,7 +3137,8 @@ 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 && should_autocreate_reflog(refname)) {\n+\tif (log_all_ref_updates &&\n+\t    (force_create || 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@@ -3171,6 +3173,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, int force_create)\n+{\n+\tint ret;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tret = log_ref_setup(refname, &sb, err, force_create);\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@@ -3207,7 +3220,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 = log_ref_setup(refname, sb_log_file, err, 0);\n \n \tif (result)\n \t\treturn result;\ndiff --git a/refs.h b/refs.h\nindex debdefc..3b90e16 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, int force_create);\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":"264926","messageId":"1435278548-3790-6-git-send-email-dturner@twopensource.com","threadId":"39729","inReplyTo":"1435278548-3790-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v3 6/7] git-reflog: add create and exists functions","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-26T00:29:07Z","receivedAt":"2015-06-26T00:29:07Z","isPatch":true,"sender":{"key":"novalis@novalis.org","avatar":"https://avatars.githubusercontent.com/u/77003?v=4"},"body":"These are necessary because alternate ref backends might store reflogs\nsomewhere other than .git/logs.  Code that now directly manipulates\n.git/logs should instead go through git-reflog.\n\nIn a moment, we will use these functions to make git stash work with\nalternate ref backends.\n\nSigned-off-by: David Turner <dturner@twopensource.com>\n---\n builtin/reflog.c       | 79 +++++++++++++++++++++++++++++++++++++++++++++++++-\n t/t1411-reflog-show.sh | 12 ++++++++\n 2 files changed, 90 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/reflog.c b/builtin/reflog.c\nindex c2eb8ff..7fe31fa 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 <ref>\";\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+\tint temp;\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+\ttemp = log_all_ref_updates;\n+\tlog_all_ref_updates = 1;\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, 1)) {\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+\tlog_all_ref_updates = temp;\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\tusage(reflog_exists_usage);\n+\n+\tif (check_refname_format(argv[start], REFNAME_ALLOW_ONELEVEL))\n+\t\tdie(\"invalid ref format: %s\", argv[start]);\n+\treturn !reflog_exists(argv[start]);\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 }\ndiff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh\nindex 6f47c0d..6e1abe7 100755\n--- a/t/t1411-reflog-show.sh\n+++ b/t/t1411-reflog-show.sh\n@@ -166,4 +166,16 @@ test_expect_success 'git log -g -p shows diffs vs. parents' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'reflog exists works' '\n+\tgit reflog exists refs/heads/master &&\n+\t! git reflog exists refs/heads/nonexistent\n+'\n+\n+test_expect_success 'reflog create works' '\n+\tgit update-ref non-refs-dir HEAD &&\n+\t! git reflog exists non-refs-dir &&\n+\tgit reflog create non-refs-dir &&\n+\tgit reflog exists non-refs-dir\n+'\n+\n test_done\n-- \n2.0.4.314.gdbf7a51-twtrsrc\n"},{"id":"264925","messageId":"1435278548-3790-7-git-send-email-dturner@twopensource.com","threadId":"39729","inReplyTo":"1435278548-3790-1-git-send-email-dturner@twopensource.com","subject":"[PATCH v3 7/7] git-stash: use git-reflog instead of creating files","fromName":"David Turner","fromEmail":"dturner@twopensource.com","sentAt":"2015-06-26T00:29:08Z","receivedAt":"2015-06-26T00:29:08Z","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 1 file changed, 2 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\n-- \n2.0.4.314.gdbf7a51-twtrsrc\n"},{"id":"265003","messageId":"xmqqy4j6rvsq.fsf@gitster.dls.corp.google.com","threadId":"39729","inReplyTo":"1435278548-3790-2-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v3 2/7] cherry-pick: treat CHERRY_PICK_HEAD and REVERT_HEAD as refs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-26T21:42:29Z","receivedAt":"2015-06-26T21:42:29Z","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> diff --git a/sequencer.c b/sequencer.c\n> index 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\nI guess this is no longer \"pseudoref\"?\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\nI would have expected that you would use ref_exists() here; you are\nnot reading \"HEAD\" yet writing it into head_sha1[], and not using\nthe value of the ref.\n\nOther than that, looked very sensible.  Thanks.\n"},{"id":"265004","messageId":"xmqqtwturvme.fsf@gitster.dls.corp.google.com","threadId":"39729","inReplyTo":"1435278548-3790-3-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v3 3/7] bisect: treat BISECT_HEAD as a ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-26T21:46:17Z","receivedAt":"2015-06-26T21:46:17Z","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 BISECT_HEAD.\n>\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> ---\n\nInteresting.  From the patch, it seems that the codepath that writes\nBISECT_HEAD were already doing update-ref instead of writing into or\nremoving a file.\n\nThe result of applying this patch looked sane.  Thanks.\n\n>  git-bisect.sh | 10 +++++++---\n>  1 file changed, 7 insertions(+), 3 deletions(-)\n>\n> diff --git a/git-bisect.sh b/git-bisect.sh\n> index ae3fec2..dddcc89 100755\n> --- a/git-bisect.sh\n> +++ b/git-bisect.sh\n> @@ -35,7 +35,7 @@ _x40=\"$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40\"\n>  \n>  bisect_head()\n>  {\n> -\tif test -f \"$GIT_DIR/BISECT_HEAD\"\n> +\tif bisect_head_exists\n>  \tthen\n>  \t\techo BISECT_HEAD\n>  \telse\n> @@ -209,6 +209,10 @@ check_expected_revs() {\n>  \tdone\n>  }\n>  \n> +bisect_head_exists() {\n> +    git rev-parse --quiet --verify \"BISECT_HEAD\" >/dev/null\n> +}\n> +\n>  bisect_skip() {\n>  \tall=''\n>  \tfor arg in \"$@\"\n> @@ -310,7 +314,7 @@ bisect_next() {\n>  \tbisect_next_check good\n>  \n>  \t# Perform all bisection computation, display and checkout\n> -\tgit bisect--helper --next-all $(test -f \"$GIT_DIR/BISECT_HEAD\" && echo --no-checkout)\n> +\tgit bisect--helper --next-all $(bisect_head_exists && echo --no-checkout)\n>  \tres=$?\n>  \n>  \t# Check if we should exit because bisection is finished\n> @@ -377,7 +381,7 @@ bisect_reset() {\n>  \t\tusage ;;\n>  \tesac\n>  \n> -\tif ! test -f \"$GIT_DIR/BISECT_HEAD\" && ! git checkout \"$branch\" --\n> +\tif ! bisect_head_exists && ! git checkout \"$branch\" --\n>  \tthen\n>  \t\tdie \"$(eval_gettext \"Could not check out original HEAD '\\$branch'.\n>  Try 'git bisect reset <commit>'.\")\"\n"},{"id":"265005","messageId":"xmqqpp4iruxh.fsf@gitster.dls.corp.google.com","threadId":"39729","inReplyTo":"1435278548-3790-4-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v3 4/7] refs: Break out check for reflog autocreation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-26T22:01:14Z","receivedAt":"2015-06-26T22:01:14Z","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 is just for clarity.\n>\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> ---\n>  refs.c | 14 +++++++++-----\n>  1 file changed, 9 insertions(+), 5 deletions(-)\n>\n> diff --git a/refs.c b/refs.c\n> index b34a54a..dff91cf 100644\n> --- a/refs.c\n> +++ b/refs.c\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\nThis makes me wonder if \"log_all_ref_updates &&\" part should also be\ninside the helper.  The use of the new helper in 5/7 tells me that\nit is the case, I would say.\n\nBesides, the answer to the question \"should we auto-create reflog?\"\nis \"if we are told to log all, and then the thing is one of these,\nthen we should:\", so it is natural from the name of the new helper\nthat \"log_all_ref_updates &&\" should be in there ;-)\n"},{"id":"265007","messageId":"xmqqlhf6rudx.fsf@gitster.dls.corp.google.com","threadId":"39729","inReplyTo":"1435278548-3790-5-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v3 5/7] refs: add safe_create_reflog function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-26T22:12:58Z","receivedAt":"2015-06-26T22:12:58Z","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\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, 0);\n>  \t\t\t\tlog_all_ref_updates = temp;\n> -\t\t\t\tstrbuf_release(&log_file);\n\nWhat the result of applying this patch does around here is\nincoherent, isn't it?  I do understand and agree that adding the\n\"force-create\" argument to safe_create_reflog() is a good idea, but\nthen I do not think you need to temporarily set log-all-ref-updates\nwhile calling it (and revert it afterwards).  Not having to do that\nis the whole point of \"force-create\", isn't it?\n\n> diff --git a/refs.c b/refs.c\n> index dff91cf..7519dac 100644\n> --- a/refs.c\n> +++ b/refs.c\n> @@ -3123,11 +3123,12 @@ 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\nThis change is *not* part of creating safe-create-reflog.\n\nIt may be part of \"allowing us to use safe_create_reflog() to manage\nstash\", but I'd imagine that a new \"reflog create\" command should\nignore log-all-ref-updates settings (after all, the end user is\nexplicitly telling us to create one by issuing a command), so I\ndoubt it matters if 'stash' is on the auto-create list.\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> +static int log_ref_setup(const char *refname, struct strbuf *sb_logfile, struct strbuf *err, int force_create)\n>  {\n>  \tint logfd, oflags = O_APPEND | O_WRONLY;\n>  \tchar *logfile;\n> @@ -3136,7 +3137,8 @@ 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 && should_autocreate_reflog(refname)) {\n> +\tif (log_all_ref_updates &&\n> +\t    (force_create || should_autocreate_reflog(refname))) {\n\nWith this patch, force_create is used as \"we are throwing you an\nunusual name that do not automatically get a reflog when log-all is\nset, and we are overriding that selection-by-name aspect of auto\ncreation\" but does not defeat log-all settings.  Is that intended?\n\nIf somebody asks safe_create_reflog() to create a reflog and passes\nforce_create, shouldn't we create that reflog regardless of\nlog_all_ref_updates settings?  That is\n\n\tif (force_create || should_autocreate_reflog(refname)) {\n        \t... create it ...\n\nwould be more natural to read here, and you would get that for free\nif 4/7 checked log_all_ref_updates in should_autocreate_reflog().\n"},{"id":"265008","messageId":"xmqqegkyrubd.fsf@gitster.dls.corp.google.com","threadId":"39729","inReplyTo":"1435278548-3790-7-git-send-email-dturner@twopensource.com","subject":"Re: [PATCH v3 7/7] git-stash: use git-reflog instead of creating files","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-26T22:14:30Z","receivedAt":"2015-06-26T22:14:30Z","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 is in support of alternate ref backends which don't necessarily\n> store reflogs as files.\n>\n> Signed-off-by: David Turner <dturner@twopensource.com>\n> ---\n\n6/7 and 7/7 looked sensible; \"git reflog create/exists\" needs a doc\nupdate, though.\n\nThanks.\n"}]}