git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] Make "git reset" a builtin. (incomplete)

From
CRCarlos Rica <jasampler@gmail.com>
Date
Aug 22, 2007, 12:48 UTC
Message-ID
<46CC3090.7080500@gmail.com>

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: David Kastrup
Message 1 of 49 in “Make "git reset" a builtin. (incomplete)”
  1. Make "git reset" a builtin. (incomplete)Carlos Rica, Aug 22, 2007
  2. David KastrupAug 22, 2007
  3. Andreas EricssonAug 22, 2007
  4. David KastrupAug 22, 2007
  5. Mike HommeyAug 22, 2007
  6. Chris ShoemakerAug 22, 2007
  7. David KastrupAug 22, 2007
  8. Nicolas PitreAug 22, 2007
  9. Johannes SchindelinAug 22, 2007
  10. David KastrupAug 22, 2007
  11. Linus TorvaldsAug 22, 2007
  12. David KastrupAug 22, 2007
  13. Linus TorvaldsAug 22, 2007
  14. David KastrupAug 22, 2007
  15. Linus TorvaldsAug 22, 2007
  16. David KastrupAug 22, 2007
  17. Linus TorvaldsAug 23, 2007
  18. Wincent ColaiutaAug 23, 2007
  19. Nicolas PitreAug 23, 2007
  20. Jon SmirlAug 23, 2007
  21. Linus TorvaldsAug 23, 2007
  22. Junio C HamanoAug 23, 2007
  23. Johannes SchindelinAug 23, 2007
  24. Reece DunnAug 22, 2007
  25. Johannes SchindelinAug 23, 2007
  26. Theodore TsoAug 23, 2007
  27. Johannes SchindelinAug 23, 2007
  28. David TweedAug 23, 2007
  29. Theodore TsoAug 23, 2007
  30. Johannes SchindelinAug 23, 2007
  31. Jon SmirlAug 23, 2007
  32. Reece DunnAug 23, 2007
  33. Alex RiesenAug 23, 2007
  34. David KastrupAug 23, 2007
  35. Alex RiesenAug 23, 2007
  36. David KastrupAug 23, 2007
  37. Nicolas PitreAug 22, 2007
  38. Johannes SchindelinAug 23, 2007
  39. Nicolas PitreAug 23, 2007
  40. Reece DunnAug 22, 2007
  41. Johannes SchindelinAug 23, 2007
  42. Robin RosenbergAug 23, 2007
  43. Nguyen Thai Ngoc DuyAug 23, 2007
  44. Matthieu MoyAug 22, 2007
  45. David KastrupAug 22, 2007
  46. Andy ParkinsAug 22, 2007
  47. Johannes SixtAug 22, 2007
  48. Alex RiesenAug 22, 2007
  49. Johannes SchindelinAug 23, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.