From: Carlos Rica <jasampler@gmail.com>
To: git@vger.kernel.org, Junio C Hamano <gitster@pobox.com>,
Johannes Schindelin <Johannes.Schindelin@gmx.de>
Subject: [PATCH] Make "git reset" a builtin. (incomplete)
Date: Wed, 22 Aug 2007 14:48:16 +0200 [thread overview]
Message-ID: <46CC3090.7080500@gmail.com> (raw)
This is the first version of the program "builtin-reset.c",
intended for replacing the script "git-reset.sh".
The --mixed option with -- paths is not implemented yet.
The tests I made for it are not finished so they are not included,
but it seems to pass the rest of the test suite.
Signed-off-by: Carlos Rica <jasampler@gmail.com>
---
Makefile | 3 +-
builtin-reset.c | 216 +++++++++++++++++++++++++
builtin.h | 1 +
git-reset.sh => contrib/examples/git-reset.sh | 0
git.c | 1 +
5 files changed, 220 insertions(+), 1 deletions(-)
create mode 100644 builtin-reset.c
rename git-reset.sh => contrib/examples/git-reset.sh (100%)
diff --git a/Makefile b/Makefile
index 4eb4637..4f70993 100644
--- a/Makefile
+++ b/Makefile
@@ -206,7 +206,7 @@ SCRIPT_SH = \
git-ls-remote.sh \
git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
git-pull.sh git-rebase.sh git-rebase--interactive.sh \
- git-repack.sh git-request-pull.sh git-reset.sh \
+ git-repack.sh git-request-pull.sh \
git-sh-setup.sh \
git-am.sh \
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
@@ -353,6 +353,7 @@ BUILTIN_OBJS = \
builtin-reflog.o \
builtin-config.o \
builtin-rerere.o \
+ builtin-reset.o \
builtin-rev-list.o \
builtin-rev-parse.o \
builtin-revert.o \
diff --git a/builtin-reset.c b/builtin-reset.c
new file mode 100644
index 0000000..66aac45
--- /dev/null
+++ b/builtin-reset.c
@@ -0,0 +1,216 @@
+/*
+ * "git reset" builtin command
+ *
+ * Copyright (c) 2007 Carlos Rica
+ *
+ * Based on git-reset.sh, which is
+ *
+ * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
+ */
+#include "cache.h"
+#include "tag.h"
+#include "object.h"
+#include "run-command.h"
+#include "refs.h"
+
+static const char builtin_reset_usage[] =
+"git-reset [--mixed | --soft | --hard] [<commit-ish>] [ [--] <paths>...]";
+
+static char *args_to_str(const char **argv)
+{
+ char *buf = NULL;
+ unsigned long len, space = 0, nr = 0;
+
+ for (; *argv; argv++) {
+ len = strlen(*argv);
+ ALLOC_GROW(buf, nr + 1 + len, space);
+ if (nr)
+ buf[nr++] = ' ';
+ memcpy(buf + nr, *argv, len);
+ nr += len;
+ }
+ ALLOC_GROW(buf, nr + 1, space);
+ buf[nr] = '\0';
+
+ return buf;
+}
+
+static inline int is_merge(void)
+{
+ return !access(git_path("MERGE_HEAD"), F_OK);
+}
+
+static int unmerged_files(void)
+{
+ char b;
+ ssize_t len;
+ struct child_process cmd;
+ const char *argv_ls_files[] = {"ls-files", "--unmerged", NULL};
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.argv = argv_ls_files;
+ cmd.git_cmd = 1;
+ cmd.out = -1;
+
+ if (start_command(&cmd))
+ die("Could not run sub-command: git ls-files");
+
+ len = xread(cmd.out, &b, 1);
+ if (len < 0)
+ die("Could not read output from git ls-files: %s",
+ strerror(errno));
+ finish_command(&cmd);
+
+ return len;
+}
+
+static int reset_index_file(const unsigned char *sha1, int is_hard_reset)
+{
+ int i = 0;
+ const char *args[6];
+
+ args[i++] = "read-tree";
+ args[i++] = "-v";
+ args[i++] = "--reset";
+ if (is_hard_reset)
+ args[i++] = "-u";
+ args[i++] = sha1_to_hex(sha1);
+ args[i] = NULL;
+
+ return run_command_v_opt(args, RUN_GIT_CMD);
+}
+
+static int print_line_current_head(void)
+{
+ const char *argv_log[] = {"log", "--max-count=1", "--pretty=oneline",
+ "--abbrev-commit", "HEAD", NULL};
+ printf("HEAD is now at ");
+ unsetenv("GIT_PAGER");
+ return run_command_v_opt(argv_log, RUN_GIT_CMD);
+}
+
+static int update_index_refresh(void)
+{
+ const char *argv_update_index[] = {"update-index", "--refresh", NULL};
+ return run_command_v_opt(argv_update_index, RUN_GIT_CMD);
+}
+
+static int update_ref(const char *action, const char *refname,
+ const unsigned char *sha1, const unsigned char *oldval)
+{
+ static struct ref_lock *lock;
+
+ lock = lock_any_ref_for_update(refname, oldval, 0);
+ if (!lock)
+ return error("Cannot lock the ref: '%s'.", refname);
+ if (write_ref_sha1(lock, sha1, action) < 0)
+ return error("Cannot update the ref: '%s'.", refname);
+ return 0;
+}
+
+enum reset_type { MIXED, SOFT, HARD };
+
+int cmd_reset(int argc, const char **argv, const char *prefix)
+{
+ int i = 1, reset_type = MIXED, update_ref_status = 0;
+ const char *rev = "HEAD";
+ unsigned char sha1[20], *orig = NULL, sha1_orig[20],
+ *old_orig = NULL, sha1_old_orig[20];
+ struct object *obj;
+ char *reflog_action;
+
+ git_config(git_default_config);
+
+ reflog_action = args_to_str(argv);
+ setenv("GIT_REFLOG_ACTION", reflog_action, 0);
+
+ if (i < argc) {
+ if (!strcmp(argv[i], "--mixed")) {
+ reset_type = MIXED;
+ i++;
+ }
+ else if (!strcmp(argv[i], "--soft")) {
+ reset_type = SOFT;
+ i++;
+ }
+ else if (!strcmp(argv[i], "--hard")) {
+ reset_type = HARD;
+ i++;
+ }
+ }
+
+ if (i < argc && argv[i][0] != '-')
+ rev = argv[i++];
+
+ if (get_sha1(rev, sha1))
+ die("Failed to resolve '%s' as a valid ref.", rev);
+
+ obj = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
+ if (!obj)
+ die("Could not parse object '%s'.", rev);
+ memcpy(sha1, obj->sha1, sizeof(sha1));
+
+ if (i < argc && argv[i][0] == '-') {
+ if (strcmp(argv[i], "--"))
+ usage(builtin_reset_usage);
+ else
+ i++;
+ }
+
+ /* git reset --mixed tree [--] paths... can be used to
+ * load chosen paths from the tree into the index without
+ * affecting the working tree nor HEAD. */
+ if (i < argc) {
+ if (reset_type != MIXED)
+ die("Cannot do partial %s reset.", argv[1]);
+ /*
+ git diff-index --cached $rev -- "$@" |
+ sed -e 's/^:\([0-7][0-7]*\) [0-7][0-7]* \([0-9a-f][0-9a-f]*\) [0-9a-f][0-9a-f]* [A-Z] \(.*\)$/\1 \2 \3/' |
+ git update-index --add --remove --index-info || exit
+ */
+ update_index_refresh();
+ return 0;
+ }
+
+ /* Soft reset does not touch the index file nor the working tree
+ * at all, but requires them in a good order. Other resets reset
+ * the index file to the tree object we are switching to. */
+ if (reset_type == SOFT) {
+ if (is_merge() || unmerged_files())
+ die("Cannot do a soft reset in the middle of a merge.");
+ }
+ else if (reset_index_file(sha1, (reset_type == HARD)))
+ die("Could not reset index file to revision '%s'.", rev);
+
+ /* Any resets update HEAD to the head being switched to,
+ * saving the previous head in ORIG_HEAD before. */
+ if (!get_sha1("ORIG_HEAD", sha1_old_orig))
+ old_orig = sha1_old_orig;
+ if (!get_sha1("HEAD", sha1_orig)) {
+ orig = sha1_orig;
+ update_ref("updating ORIG_HEAD", "ORIG_HEAD", orig, old_orig);
+ }
+ else if (old_orig)
+ delete_ref("ORIG_HEAD", old_orig);
+ update_ref_status = update_ref(reflog_action, "HEAD", sha1, orig);
+ free(reflog_action);
+
+ switch (reset_type) {
+ case HARD:
+ if (!update_ref_status)
+ print_line_current_head();
+ break;
+ case SOFT: /* Nothing else to do. */
+ break;
+ case MIXED: /* Report what has not been updated. */
+ update_index_refresh();
+ break;
+ }
+
+ unlink(git_path("MERGE_HEAD"));
+ unlink(git_path("rr-cache/MERGE_RR"));
+ unlink(git_path("MERGE_MSG"));
+ unlink(git_path("SQUASH_MSG"));
+
+ return update_ref_status;
+}
diff --git a/builtin.h b/builtin.h
index bb72000..03ee7bf 100644
--- a/builtin.h
+++ b/builtin.h
@@ -60,6 +60,7 @@ extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
extern int cmd_reflog(int argc, const char **argv, const char *prefix);
extern int cmd_config(int argc, const char **argv, const char *prefix);
extern int cmd_rerere(int argc, const char **argv, const char *prefix);
+extern int cmd_reset(int argc, const char **argv, const char *prefix);
extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
extern int cmd_revert(int argc, const char **argv, const char *prefix);
diff --git a/git-reset.sh b/contrib/examples/git-reset.sh
similarity index 100%
rename from git-reset.sh
rename to contrib/examples/git-reset.sh
diff --git a/git.c b/git.c
index cab0e72..26720f4 100644
--- a/git.c
+++ b/git.c
@@ -359,6 +359,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "reflog", cmd_reflog, RUN_SETUP },
{ "repo-config", cmd_config },
{ "rerere", cmd_rerere, RUN_SETUP },
+ { "reset", cmd_reset, RUN_SETUP },
{ "rev-list", cmd_rev_list, RUN_SETUP },
{ "rev-parse", cmd_rev_parse, RUN_SETUP },
{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
--
1.5.0
next reply other threads:[~2007-08-22 12:48 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-08-22 12:48 Carlos Rica [this message]
2007-08-22 13:00 ` [PATCH] Make "git reset" a builtin. (incomplete) David Kastrup
2007-08-22 13:37 ` Andreas Ericsson
2007-08-22 14:29 ` David Kastrup
2007-08-22 14:49 ` Mike Hommey
2007-08-22 15:02 ` Chris Shoemaker
2007-08-22 15:41 ` David Kastrup
2007-08-22 16:07 ` Nicolas Pitre
2007-08-22 16:51 ` Johannes Schindelin
2007-08-22 17:17 ` David Kastrup
2007-08-22 19:05 ` Linus Torvalds
2007-08-22 19:36 ` David Kastrup
2007-08-22 19:58 ` Linus Torvalds
2007-08-22 22:25 ` David Kastrup
2007-08-22 23:10 ` Linus Torvalds
2007-08-22 23:39 ` David Kastrup
2007-08-23 1:30 ` Linus Torvalds
2007-08-23 0:24 ` Wincent Colaiuta
2007-08-23 1:15 ` Nicolas Pitre
2007-08-23 1:40 ` Jon Smirl
2007-08-23 3:23 ` Linus Torvalds
2007-08-23 4:21 ` Junio C Hamano
2007-08-23 9:15 ` Johannes Schindelin
2007-08-22 21:34 ` Reece Dunn
2007-08-23 9:10 ` Johannes Schindelin
2007-08-23 10:20 ` Theodore Tso
2007-08-23 10:31 ` Johannes Schindelin
2007-08-23 10:55 ` David Tweed
2007-08-23 11:24 ` Theodore Tso
2007-08-23 11:35 ` Johannes Schindelin
2007-08-23 16:30 ` Jon Smirl
2007-08-23 11:25 ` Reece Dunn
2007-08-23 20:26 ` Alex Riesen
2007-08-23 21:14 ` David Kastrup
2007-08-23 21:33 ` Alex Riesen
2007-08-23 22:05 ` David Kastrup
2007-08-22 17:21 ` Nicolas Pitre
2007-08-23 9:55 ` Johannes Schindelin
2007-08-23 15:19 ` Nicolas Pitre
2007-08-22 21:19 ` Reece Dunn
2007-08-23 9:05 ` Johannes Schindelin
2007-08-23 18:40 ` Robin Rosenberg
2007-08-23 2:05 ` Nguyen Thai Ngoc Duy
2007-08-22 13:42 ` Matthieu Moy
2007-08-22 22:28 ` David Kastrup
2007-08-22 14:27 ` Andy Parkins
2007-08-22 14:57 ` Johannes Sixt
2007-08-22 16:20 ` Alex Riesen
2007-08-23 11:14 ` Johannes Schindelin
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=46CC3090.7080500@gmail.com \
--to=jasampler@gmail.com \
--cc=Johannes.Schindelin@gmx.de \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/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).