From: Stephan Beyer <s-beyer@xxxxxxx> This patch adds the "reset_almost_hard()" function, some related static variables and the related following functions: - parse_and_init_tree_desc() - reset_index_file() - set_verbosity() "reset_almost_hard()" can be used to do a "git reset --hard". It should be faster as it calls "unpack_trees()" directly, and it can optionnaly preserve changes in the work tree if the "allow_dirty" global is set. Preserving changes in the work tree can be usefull if for example you want to get rid of the last commit but keep your current not yet commited work. In this patch the "allow_dirty" global is not used but a following patch will make it possible to set it, and in the end the code should be simpler with a global. The code comes as is from the sequencer GSoC project: git://repo.or.cz/git/sbeyer.git (at commit 5a78908b70ceb5a4ea9fd4b82f07ceba1f019079) Mentored-by: Daniel Barkalow <barkalow@xxxxxxxxxxxx> Mentored-by: Christian Couder <chriscool@xxxxxxxxxxxxx> Signed-off-by: Stephan Beyer <s-beyer@xxxxxxx> Signed-off-by: Christian Couder <chriscool@xxxxxxxxxxxxx> Signed-off-by: Junio C Hamano <gitster@xxxxxxxxx> --- builtin-sequencer--helper.c | 107 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 107 insertions(+), 0 deletions(-) diff --git a/builtin-sequencer--helper.c b/builtin-sequencer--helper.c index 1dda525..a15139c 100644 --- a/builtin-sequencer--helper.c +++ b/builtin-sequencer--helper.c @@ -2,16 +2,108 @@ #include "cache.h" #include "parse-options.h" #include "run-command.h" +#include "refs.h" +#include "diff.h" +#include "unpack-trees.h" #define SEQ_DIR "rebase-merge" #define PATCH_FILE git_path(SEQ_DIR "/patch") +static char *reflog; + +static int allow_dirty = 0, verbosity = 1, advice = 1; + +static unsigned char head_sha1[20]; + static const char * const git_sequencer_helper_usage[] = { "git sequencer--helper --make-patch <commit>", NULL }; +static int parse_and_init_tree_desc(const unsigned char *sha1, + struct tree_desc *desc) +{ + struct tree *tree = parse_tree_indirect(sha1); + if (!tree) + return 1; + init_tree_desc(desc, tree->buffer, tree->size); + return 0; +} + +static int reset_index_file(const unsigned char *sha1, int update, int dirty) +{ + int nr = 1; + int newfd; + struct tree_desc desc[2]; + struct unpack_trees_options opts; + struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); + + memset(&opts, 0, sizeof(opts)); + opts.head_idx = 1; + opts.src_index = &the_index; + opts.dst_index = &the_index; + opts.reset = 1; /* ignore unmerged entries and overwrite wt files */ + opts.merge = 1; + opts.fn = oneway_merge; + if (verbosity > 2) + opts.verbose_update = 1; + if (update) /* update working tree */ + opts.update = 1; + + newfd = hold_locked_index(lock, 1); + + read_cache_unmerged(); + + if (dirty) { + if (get_sha1("HEAD", head_sha1)) + return error("You do not have a valid HEAD."); + if (parse_and_init_tree_desc(head_sha1, desc)) + return error("Failed to find tree of HEAD."); + nr++; + opts.fn = twoway_merge; + } + + if (parse_and_init_tree_desc(sha1, desc + nr - 1)) + return error("Failed to find tree of %s.", sha1_to_hex(sha1)); + if (unpack_trees(nr, desc, &opts)) + return -1; + if (write_cache(newfd, active_cache, active_nr) || + commit_locked_index(lock)) + return error("Could not write new index file."); + + return 0; +} + +/* + * Realize reset --hard behavior. + * If allow_dirty is set and there is a dirty work tree, + * then the changes in the work tree are to be kept. + * + * This should be faster than calling "git reset --hard" because + * this calls "unpack_trees()" directly (instead of forking and + * execing "git read-tree"). + * + * Unmerged entries in the index will be discarded. + * + * If allow_dirty is set and fast forwarding the work tree + * fails because it is dirty, then the work tree will not be + * updated. + * + * No need to read or discard the index before calling this + * function. + */ +static int reset_almost_hard(const unsigned char *sha) +{ + int err = allow_dirty ? + (reset_index_file(sha, 1, 1) || reset_index_file(sha, 0, 0)) : + reset_index_file(sha, 1, 0); + if (err) + return error("Could not reset index."); + + return update_ref(reflog, "HEAD", sha, NULL, 0, MSG_ON_ERR); +} + /* Generate purely informational patch file */ static void make_patch(struct commit *commit) { @@ -78,6 +170,21 @@ static struct commit *get_commit(const char *arg) return lookup_commit_reference(sha1); } +static int set_verbosity(int verbose) +{ + char tmp[] = "0"; + verbosity = verbose; + if (verbosity <= 0) { + verbosity = 0; + advice = 0; + } else if (verbosity > 5) + verbosity = 5; + /* Git does not run on EBCDIC, so we rely on ASCII: */ + tmp[0] += verbosity; + setenv("GIT_MERGE_VERBOSITY", tmp, 1); + return 0; +} + int cmd_sequencer__helper(int argc, const char **argv, const char *prefix) { char *commit = NULL; -- 1.6.4.271.ge010d -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html