From: Greg Hewgill <greg@hewgill.com>
To: git@vger.kernel.org
Subject: Re: Proposal for git stash rename
Date: Sun, 20 Jun 2010 11:11:12 +0000 [thread overview]
Message-ID: <20100620111112.GH24805@occam.hewgill.net> (raw)
In-Reply-To: <AANLkTimjEksHI4nlefqmNzdNiseVyMQcw312g2AHFQDZ@mail.gmail.com>
On Sun, Jun 20, 2010 at 10:54:43AM +0000, ??var Arnfj??r?? Bjarmason wrote:
> It's good to post a WIP PATCH even if it needs cleanup, just as a
> point for further discussion.
Thanks, point taken. WIP patch follows.
This patch implements a "git stash rename" using a new
"git reflog update" command that updates the message associated
with a reflog entry.
---
builtin/reflog.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
git-stash.sh | 5 ++
t/t3903-stash.sh | 10 ++++
3 files changed, 164 insertions(+), 0 deletions(-)
diff --git a/builtin/reflog.c b/builtin/reflog.c
index ebf610e..35eae1f 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -7,6 +7,7 @@
#include "diff.h"
#include "revision.h"
#include "reachable.h"
+#include "strbuf.h"
/*
* reflog expire
@@ -16,6 +17,8 @@ static const char reflog_expire_usage[] =
"git reflog expire [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
static const char reflog_delete_usage[] =
"git reflog delete [--verbose] [--dry-run] [--rewrite] [--updateref] <refs>...";
+static const char reflog_update_usage[] =
+"git reflog update [--verbose] [--dry-run] [--rewrite] <ref> <newdescr>";
static unsigned long default_reflog_expire;
static unsigned long default_reflog_expire_unreachable;
@@ -30,6 +33,7 @@ struct cmd_reflog_expire_cb {
unsigned long expire_total;
unsigned long expire_unreachable;
int recno;
+ struct strbuf newmsg;
};
struct expire_reflog_cb {
@@ -335,6 +339,30 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
return 0;
}
+static int update_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
+ const char *email, unsigned long timestamp, int tz,
+ const char *message, void *cb_data)
+{
+ struct expire_reflog_cb *cb = cb_data;
+
+ if (cb->cmd->rewrite)
+ osha1 = cb->last_kept_sha1;
+
+ if (cb->cmd->recno && --(cb->cmd->recno) == 0)
+ message = cb->cmd->newmsg.buf;
+
+ if (cb->newlog) {
+ char sign = (tz < 0) ? '-' : '+';
+ int zone = (tz < 0) ? (-tz) : tz;
+ fprintf(cb->newlog, "%s %s %s %lu %c%04d\t%s",
+ sha1_to_hex(osha1), sha1_to_hex(nsha1),
+ email, timestamp, sign, zone,
+ message);
+ hashcpy(cb->last_kept_sha1, nsha1);
+ }
+ return 0;
+}
+
static int push_tip_to_list(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
{
struct commit_list **list = cb_data;
@@ -448,6 +476,65 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
return status;
}
+static int update_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
+{
+ struct cmd_reflog_expire_cb *cmd = cb_data;
+ struct expire_reflog_cb cb;
+ struct ref_lock *lock;
+ char *log_file, *newlog_path = NULL;
+ int status = 0;
+
+ memset(&cb, 0, sizeof(cb));
+
+ /*
+ * we take the lock for the ref itself to prevent it from
+ * getting updated.
+ */
+ lock = lock_any_ref_for_update(ref, sha1, 0);
+ if (!lock)
+ return error("cannot lock ref '%s'", ref);
+ log_file = git_pathdup("logs/%s", ref);
+ if (!file_exists(log_file))
+ goto finish;
+ if (!cmd->dry_run) {
+ newlog_path = git_pathdup("logs/%s.lock", ref);
+ cb.newlog = fopen(newlog_path, "w");
+ }
+
+ cb.cmd = cmd;
+
+ for_each_reflog_ent(ref, update_reflog_ent, &cb);
+
+ finish:
+ if (cb.newlog) {
+ if (fclose(cb.newlog)) {
+ status |= error("%s: %s", strerror(errno),
+ newlog_path);
+ unlink(newlog_path);
+ } else if (cmd->updateref &&
+ (write_in_full(lock->lock_fd,
+ sha1_to_hex(cb.last_kept_sha1), 40) != 40 ||
+ write_str_in_full(lock->lock_fd, "\n") != 1 ||
+ close_ref(lock) < 0)) {
+ status |= error("Couldn't write %s",
+ lock->lk->filename);
+ unlink(newlog_path);
+ } else if (rename(newlog_path, log_file)) {
+ status |= error("cannot rename %s to %s",
+ newlog_path, log_file);
+ unlink(newlog_path);
+ } else if (cmd->updateref && commit_ref(lock)) {
+ status |= error("Couldn't set %s", lock->ref_name);
+ } else {
+ adjust_shared_perm(log_file);
+ }
+ }
+ free(newlog_path);
+ free(log_file);
+ unlock_ref(lock);
+ return status;
+}
+
static int collect_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
{
struct collected_reflog *e;
@@ -752,6 +839,65 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
return status;
}
+static int cmd_reflog_update(int argc, const char **argv, const char *prefix)
+{
+ struct cmd_reflog_expire_cb cb;
+ int i, status = 0;
+
+ memset(&cb, 0, sizeof(cb));
+
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+ if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
+ cb.dry_run = 1;
+ else if (!strcmp(arg, "--rewrite"))
+ cb.rewrite = 1;
+ else if (!strcmp(arg, "--verbose"))
+ cb.verbose = 1;
+ else if (!strcmp(arg, "--")) {
+ i++;
+ break;
+ }
+ else if (arg[0] == '-')
+ usage(reflog_update_usage);
+ else
+ break;
+ }
+
+ if (argc - i < 2)
+ usage(reflog_update_usage);
+
+ strbuf_init(&cb.newmsg, strlen(argv[i+1])+1);
+ strbuf_addstr(&cb.newmsg, argv[i+1]);
+ strbuf_addstr(&cb.newmsg, "\n");
+
+ const char *spec = strstr(argv[i], "@{");
+ unsigned char sha1[20];
+ char *ep, *ref;
+ int recno;
+
+ if (!spec) {
+ return error("Not a reflog: %s", argv[i]);
+ }
+
+ if (!dwim_log(argv[i], spec - argv[i], sha1, &ref)) {
+ return error("no reflog for '%s'", argv[i]);
+ }
+
+ recno = strtoul(spec + 2, &ep, 10);
+ if (*ep == '}') {
+ cb.recno = -recno;
+ for_each_reflog_ent(ref, count_reflog_ent, &cb);
+ } else {
+ return error("specific ref please");
+ }
+
+ status |= update_reflog(ref, sha1, 0, &cb);
+ free(ref);
+
+ return status;
+}
+
/*
* main "reflog"
*/
@@ -777,6 +923,9 @@ int cmd_reflog(int argc, const char **argv, const char *prefix)
if (!strcmp(argv[1], "delete"))
return cmd_reflog_delete(argc - 1, argv + 1, prefix);
+ if (!strcmp(argv[1], "update"))
+ return cmd_reflog_update(argc - 1, argv + 1, prefix);
+
/* Not a recognized reflog command..*/
usage(reflog_usage);
}
diff --git a/git-stash.sh b/git-stash.sh
index 1d95447..aa80897 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -8,6 +8,7 @@ USAGE="list [<options>]
or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]
or: $dashless branch <branchname> [<stash>]
or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet] [<message>]]
+ or: $dashless rename <stash> <message>
or: $dashless clear"
SUBDIRECTORY_OK=Yes
@@ -431,6 +432,10 @@ branch)
shift
apply_to_branch "$@"
;;
+rename)
+ shift
+ git reflog update $1 "$2"
+ ;;
*)
case $# in
0)
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 8fe14cc..c0de00c 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -378,4 +378,14 @@ test_expect_failure 'stash file to directory' '
test foo = "$(cat file/file)"
'
+test_expect_success 'update stash message' '
+ git reset --hard &&
+ git checkout master &&
+ echo foo >file &&
+ git stash save "first message" &&
+ git stash list | grep "^stash@{0}: On master: first message$" &&
+ git stash rename stash@{0} "second message" &&
+ git stash list | grep "^stash@{0}: second message$"
+'
+
test_done
--
1.6.6
next prev parent reply other threads:[~2010-06-20 11:11 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-06-20 9:31 Proposal for git stash rename Greg Hewgill
2010-06-20 10:54 ` Ævar Arnfjörð Bjarmason
2010-06-20 11:11 ` Greg Hewgill [this message]
2013-01-04 18:25 ` Micheil Smith
2013-01-04 21:40 ` Junio C Hamano
2013-01-09 8:38 ` Michael Haggerty
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100620111112.GH24805@occam.hewgill.net \
--to=greg@hewgill.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).