Skip to content

Commit

Permalink
Merge branch 'cr/reset'
Browse files Browse the repository at this point in the history
* cr/reset:
  Simplify cache API
  An additional test for "git-reset -- path"
  Make "git reset" a builtin.
  Move make_cache_entry() from merge-recursive.c into read-cache.c
  Add tests for documented features of "git reset".
  • Loading branch information
Junio C Hamano committed Sep 18, 2007
2 parents 148c630 + 58f6fb5 commit 9346b4e
Show file tree
Hide file tree
Showing 14 changed files with 718 additions and 44 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,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 \
Expand Down Expand Up @@ -358,6 +358,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 \
Expand Down
1 change: 0 additions & 1 deletion builtin-add.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ static void update_callback(struct diff_queue_struct *q,
break;
case DIFF_STATUS_DELETED:
remove_file_from_cache(path);
cache_tree_invalidate_path(active_cache_tree, path);
if (verbose)
printf("remove '%s'\n", path);
break;
Expand Down
2 changes: 0 additions & 2 deletions builtin-apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -2423,7 +2423,6 @@ static void remove_file(struct patch *patch, int rmdir_empty)
if (update_index) {
if (remove_file_from_cache(patch->old_name) < 0)
die("unable to remove %s from index", patch->old_name);
cache_tree_invalidate_path(active_cache_tree, patch->old_name);
}
if (!cached) {
if (S_ISGITLINK(patch->old_mode)) {
Expand Down Expand Up @@ -2578,7 +2577,6 @@ static void create_file(struct patch *patch)
mode = S_IFREG | 0644;
create_one_file(path, mode, buf, size);
add_index_file(path, mode, buf, size);
cache_tree_invalidate_path(active_cache_tree, path);
}

/* phase zero is to remove, phase one is to create */
Expand Down
7 changes: 2 additions & 5 deletions builtin-mv.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,11 +276,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
add_file_to_cache(path, verbose);
}

for (i = 0; i < deleted.nr; i++) {
const char *path = deleted.items[i].path;
remove_file_from_cache(path);
cache_tree_invalidate_path(active_cache_tree, path);
}
for (i = 0; i < deleted.nr; i++)
remove_file_from_cache(deleted.items[i].path);

if (active_cache_changed) {
if (write_cache(newfd, active_cache, active_nr) ||
Expand Down
279 changes: 279 additions & 0 deletions builtin-reset.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
/*
* "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 "commit.h"
#include "run-command.h"
#include "refs.h"
#include "diff.h"
#include "diffcore.h"
#include "tree.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 void print_new_head_line(struct commit *commit)
{
const char *hex, *dots = "...", *body;

hex = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
if (!hex) {
hex = sha1_to_hex(commit->object.sha1);
dots = "";
}
printf("HEAD is now at %s%s", hex, dots);
body = strstr(commit->buffer, "\n\n");
if (body) {
const char *eol;
size_t len;
body += 2;
eol = strchr(body, '\n');
len = eol ? eol - body : strlen(body);
printf(" %.*s\n", (int) len, body);
}
else
printf("\n");
}

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 void update_index_from_diff(struct diff_queue_struct *q,
struct diff_options *opt, void *data)
{
int i;

/* do_diff_cache() mangled the index */
discard_cache();
read_cache();

for (i = 0; i < q->nr; i++) {
struct diff_filespec *one = q->queue[i]->one;
if (one->mode) {
struct cache_entry *ce;
ce = make_cache_entry(one->mode, one->sha1, one->path,
0, 0);
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD |
ADD_CACHE_OK_TO_REPLACE);
} else
remove_file_from_cache(one->path);
}
}

static int read_from_tree(const char *prefix, const char **argv,
unsigned char *tree_sha1)
{
struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
int index_fd;
struct diff_options opt;

memset(&opt, 0, sizeof(opt));
diff_tree_setup_paths(get_pathspec(prefix, (const char **)argv), &opt);
opt.output_format = DIFF_FORMAT_CALLBACK;
opt.format_callback = update_index_from_diff;

index_fd = hold_locked_index(lock, 1);
read_cache();
if (do_diff_cache(tree_sha1, &opt))
return 1;
diffcore_std(&opt);
diff_flush(&opt);
return write_cache(index_fd, active_cache, active_nr) ||
close(index_fd) ||
commit_locked_index(lock);
}

static void prepend_reflog_action(const char *action, char *buf, size_t size)
{
const char *sep = ": ";
const char *rla = getenv("GIT_REFLOG_ACTION");
if (!rla)
rla = sep = "";
if (snprintf(buf, size, "%s%s%s", rla, sep, action) >= size)
warning("Reflog action message too long: %.*s...", 50, buf);
}

enum reset_type { MIXED, SOFT, HARD, NONE };
static char *reset_type_names[] = { "mixed", "soft", "hard", NULL };

int cmd_reset(int argc, const char **argv, const char *prefix)
{
int i = 1, reset_type = NONE, 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 commit *commit;
char *reflog_action, msg[1024];

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);

commit = lookup_commit_reference(sha1);
if (!commit)
die("Could not parse object '%s'.", rev);
hashcpy(sha1, commit->object.sha1);

if (i < argc && !strcmp(argv[i], "--"))
i++;
else if (i < argc && argv[i][0] == '-')
usage(builtin_reset_usage);

/* git reset 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)
warning("--mixed option is deprecated with paths.");
else if (reset_type != NONE)
die("Cannot do %s reset with paths.",
reset_type_names[reset_type]);
if (read_from_tree(prefix, argv + i, sha1))
return 1;
return update_index_refresh() ? 1 : 0;
}
if (reset_type == NONE)
reset_type = MIXED; /* by default */

/* 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;
prepend_reflog_action("updating ORIG_HEAD", msg, sizeof(msg));
update_ref(msg, "ORIG_HEAD", orig, old_orig, 0, MSG_ON_ERR);
}
else if (old_orig)
delete_ref("ORIG_HEAD", old_orig);
prepend_reflog_action("updating HEAD", msg, sizeof(msg));
update_ref_status = update_ref(msg, "HEAD", sha1, orig, 0, MSG_ON_ERR);

switch (reset_type) {
case HARD:
if (!update_ref_status)
print_new_head_line(commit);
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"));

free(reflog_action);

return update_ref_status;
}
1 change: 0 additions & 1 deletion builtin-rm.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ int cmd_rm(int argc, const char **argv, const char *prefix)

if (remove_file_from_cache(path))
die("git-rm: unable to remove %s", path);
cache_tree_invalidate_path(active_cache_tree, path);
}

if (show_only)
Expand Down
9 changes: 0 additions & 9 deletions builtin-update-index.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,6 @@ static int process_path(const char *path)
int len;
struct stat st;

/* We probably want to do this in remove_file_from_cache() and
* add_cache_entry() instead...
*/
cache_tree_invalidate_path(active_cache_tree, path);

/*
* First things first: get the stat information, to decide
* what to do about the pathname!
Expand Down Expand Up @@ -239,7 +234,6 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
return error("%s: cannot add to the index - missing --add option?",
path);
report("add '%s'", path);
cache_tree_invalidate_path(active_cache_tree, path);
return 0;
}

Expand Down Expand Up @@ -284,7 +278,6 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
die("Unable to mark file %s", path);
goto free_return;
}
cache_tree_invalidate_path(active_cache_tree, path);

if (force_remove) {
if (remove_file_from_cache(p))
Expand Down Expand Up @@ -367,7 +360,6 @@ static void read_index_info(int line_termination)
free(path_name);
continue;
}
cache_tree_invalidate_path(active_cache_tree, path_name);

if (!mode) {
/* mode == 0 means there is no such path -- remove */
Expand Down Expand Up @@ -474,7 +466,6 @@ static int unresolve_one(const char *path)
goto free_return;
}

cache_tree_invalidate_path(active_cache_tree, path);
remove_file_from_cache(path);
if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) {
error("%s: cannot add our version to the index.", path);
Expand Down
1 change: 1 addition & 0 deletions builtin.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 9346b4e

Please sign in to comment.