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

Re: [PATCH v9 07/21] stash: convert apply to builtin

From
Thomas Gummerer <t.gummerer@gmail.com>
Date
Sep 30, 2018, 17:48 UTC
Message-ID
<20180930174848.GE2253@hank.intra.tgummerer.com>
In-Reply-To
<fc0e991d5612f60b254ae07369dfda0939e256dd.1537913094.git.ungureanupaulsebastian@gmail.com>
On 09/26, Paul-Sebastian Ungureanu wrote:
Show 134 quoted lines
> From: Joel Teichroeb <joel@teichroeb.net>
> 
> Add a builtin helper for performing stash commands. Converting
> all at once proved hard to review, so starting with just apply
> lets conversion get started without the other commands being
> finished.
> 
> The helper is being implemented as a drop in replacement for
> stash so that when it is complete it can simply be renamed and
> the shell script deleted.
> 
> Delete the contents of the apply_stash shell function and replace
> it with a call to stash--helper apply until pop is also
> converted.
> 
> Signed-off-by: Joel Teichroeb <joel@teichroeb.net>
> Signed-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com>
> ---
>  .gitignore              |   1 +
>  Makefile                |   1 +
>  builtin.h               |   1 +
>  builtin/stash--helper.c | 452 ++++++++++++++++++++++++++++++++++++++++
>  git-stash.sh            |  78 +------
>  git.c                   |   1 +
>  6 files changed, 463 insertions(+), 71 deletions(-)
>  create mode 100644 builtin/stash--helper.c
> 
> diff --git a/.gitignore b/.gitignore
> index ffceea7d59..b59661cb88 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -157,6 +157,7 @@
>  /git-show-ref
>  /git-stage
>  /git-stash
> +/git-stash--helper
>  /git-status
>  /git-stripspace
>  /git-submodule
> diff --git a/Makefile b/Makefile
> index d03df31c2a..f900c68e69 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1093,6 +1093,7 @@ BUILTIN_OBJS += builtin/shortlog.o
>  BUILTIN_OBJS += builtin/show-branch.o
>  BUILTIN_OBJS += builtin/show-index.o
>  BUILTIN_OBJS += builtin/show-ref.o
> +BUILTIN_OBJS += builtin/stash--helper.o
>  BUILTIN_OBJS += builtin/stripspace.o
>  BUILTIN_OBJS += builtin/submodule--helper.o
>  BUILTIN_OBJS += builtin/symbolic-ref.o
> diff --git a/builtin.h b/builtin.h
> index 99206df4bd..317bc338f7 100644
> --- a/builtin.h
> +++ b/builtin.h
> @@ -223,6 +223,7 @@ extern int cmd_show(int argc, const char **argv, const char *prefix);
>  extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
>  extern int cmd_show_index(int argc, const char **argv, const char *prefix);
>  extern int cmd_status(int argc, const char **argv, const char *prefix);
> +extern int cmd_stash__helper(int argc, const char **argv, const char *prefix);
>  extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
>  extern int cmd_submodule__helper(int argc, const char **argv, const char *prefix);
>  extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
> diff --git a/builtin/stash--helper.c b/builtin/stash--helper.c
> new file mode 100644
> index 0000000000..7819dae332
> --- /dev/null
> +++ b/builtin/stash--helper.c
> @@ -0,0 +1,452 @@
> +#include "builtin.h"
> +#include "config.h"
> +#include "parse-options.h"
> +#include "refs.h"
> +#include "lockfile.h"
> +#include "cache-tree.h"
> +#include "unpack-trees.h"
> +#include "merge-recursive.h"
> +#include "argv-array.h"
> +#include "run-command.h"
> +#include "dir.h"
> +#include "rerere.h"
> +
> +static const char * const git_stash_helper_usage[] = {
> +	N_("git stash--helper apply [--index] [-q|--quiet] [<stash>]"),
> +	NULL
> +};
> +
> +static const char * const git_stash_helper_apply_usage[] = {
> +	N_("git stash--helper apply [--index] [-q|--quiet] [<stash>]"),
> +	NULL
> +};
> +
> +static const char *ref_stash = "refs/stash";
> +static struct strbuf stash_index_path = STRBUF_INIT;
> +
> +/*
> + * w_commit is set to the commit containing the working tree
> + * b_commit is set to the base commit
> + * i_commit is set to the commit containing the index tree
> + * u_commit is set to the commit containing the untracked files tree
> + * w_tree is set to the working tree
> + * b_tree is set to the base tree
> + * i_tree is set to the index tree
> + * u_tree is set to the untracked files tree
> + */
> +
> +struct stash_info {
> +	struct object_id w_commit;
> +	struct object_id b_commit;
> +	struct object_id i_commit;
> +	struct object_id u_commit;
> +	struct object_id w_tree;
> +	struct object_id b_tree;
> +	struct object_id i_tree;
> +	struct object_id u_tree;
> +	struct strbuf revision;
> +	int is_stash_ref;
> +	int has_u;
> +};
> +
> +static void free_stash_info(struct stash_info *info)
> +{
> +	strbuf_release(&info->revision);
> +}
> +
> +static void assert_stash_like(struct stash_info *info, const char *revision)
> +{
> +	if (get_oidf(&info->b_commit, "%s^1", revision) ||
> +	    get_oidf(&info->w_tree, "%s:", revision) ||
> +	    get_oidf(&info->b_tree, "%s^1:", revision) ||
> +	    get_oidf(&info->i_tree, "%s^2:", revision)) {
> +		free_stash_info(info);
> +		error(_("'%s' is not a stash-like commit"), revision);
> +		exit(128);

This seems to just emulate 'die()'. Can we just use that directly? The only reason I could imagine for not doing that would be to keep the same exit code, or the exact same message we had in the shell script. But we're doing neither here. The shell script used to die with exit code 1, while here we're exiting with 128, and the message is now prefixed with 'error: '.

One other thing is that we're free'ing 'info' before printing revision. As revision is basically 'info->revision.buf', and we're freeing that we may end up printing garbage here.

Show 18 quoted lines
> +	}
> +}
> +
> +static int get_stash_info(struct stash_info *info, int argc, const char **argv)
> +{
> +	int ret;
> +	char *end_of_rev;
> +	char *expanded_ref;
> +	const char *revision;
> +	const char *commit = NULL;
> +	struct object_id dummy;
> +	struct strbuf symbolic = STRBUF_INIT;
> +
> +	if (argc > 1) {
> +		int i;
> +		struct strbuf refs_msg = STRBUF_INIT;
> +		for (i = 0; i < argc; i++)
> +			strbuf_addf(&refs_msg, " '%s'", argv[i]);
This should probably use 'strbuf_join_argv()' now. 
Show 480 quoted lines
> +
> +		fprintf_ln(stderr, _("Too many revisions specified:%s"),
> +			   refs_msg.buf);
> +		strbuf_release(&refs_msg);
> +
> +		return -1;
> +	}
> +
> +	if (argc == 1)
> +		commit = argv[0];
> +
> +	strbuf_init(&info->revision, 0);
> +	if (!commit) {
> +		if (!ref_exists(ref_stash)) {
> +			free_stash_info(info);
> +			fprintf_ln(stderr, _("No stash entries found."));
> +			return -1;
> +		}
> +
> +		strbuf_addf(&info->revision, "%s@{0}", ref_stash);
> +	} else if (strspn(commit, "0123456789") == strlen(commit)) {
> +		strbuf_addf(&info->revision, "%s@{%s}", ref_stash, commit);
> +	} else {
> +		strbuf_addstr(&info->revision, commit);
> +	}
> +
> +	revision = info->revision.buf;
> +
> +	if (get_oid(revision, &info->w_commit)) {
> +		error(_("%s is not a valid reference"), revision);
> +		free_stash_info(info);
> +		return -1;
> +	}
> +
> +	assert_stash_like(info, revision);
> +
> +	info->has_u = !get_oidf(&info->u_tree, "%s^3:", revision);
> +
> +	end_of_rev = strchrnul(revision, '@');
> +	strbuf_add(&symbolic, revision, end_of_rev - revision);
> +
> +	ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref);
> +	strbuf_release(&symbolic);
> +	switch (ret) {
> +	case 0: /* Not found, but valid ref */
> +		info->is_stash_ref = 0;
> +		break;
> +	case 1:
> +		info->is_stash_ref = !strcmp(expanded_ref, ref_stash);
> +		break;
> +	default: /* Invalid or ambiguous */
> +		free_stash_info(info);
> +	}
> +
> +	free(expanded_ref);
> +	return !(ret == 0 || ret == 1);
> +}
> +
> +static int reset_tree(struct object_id *i_tree, int update, int reset)
> +{
> +	int nr_trees = 1;
> +	struct unpack_trees_options opts;
> +	struct tree_desc t[MAX_UNPACK_TREES];
> +	struct tree *tree;
> +	struct lock_file lock_file = LOCK_INIT;
> +
> +	read_cache_preload(NULL);
> +	if (refresh_cache(REFRESH_QUIET))
> +		return -1;
> +
> +	hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
> +
> +	memset(&opts, 0, sizeof(opts));
> +
> +	tree = parse_tree_indirect(i_tree);
> +	if (parse_tree(tree))
> +		return -1;
> +
> +	init_tree_desc(t, tree->buffer, tree->size);
> +
> +	opts.head_idx = 1;
> +	opts.src_index = &the_index;
> +	opts.dst_index = &the_index;
> +	opts.merge = 1;
> +	opts.reset = reset;
> +	opts.update = update;
> +	opts.fn = oneway_merge;
> +
> +	if (unpack_trees(nr_trees, t, &opts))
> +		return -1;
> +
> +	if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
> +		return error(_("unable to write new index file"));
> +
> +	return 0;
> +}
> +
> +static int diff_tree_binary(struct strbuf *out, struct object_id *w_commit)
> +{
> +	struct child_process cp = CHILD_PROCESS_INIT;
> +	const char *w_commit_hex = oid_to_hex(w_commit);
> +
> +	/*
> +	 * Diff-tree would not be very hard to replace with a native function,
> +	 * however it should be done together with apply_cached.
> +	 */
> +	cp.git_cmd = 1;
> +	argv_array_pushl(&cp.args, "diff-tree", "--binary", NULL);
> +	argv_array_pushf(&cp.args, "%s^2^..%s^2", w_commit_hex, w_commit_hex);
> +
> +	return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
> +}
> +
> +static int apply_cached(struct strbuf *out)
> +{
> +	struct child_process cp = CHILD_PROCESS_INIT;
> +
> +	/*
> +	 * Apply currently only reads either from stdin or a file, thus
> +	 * apply_all_patches would have to be updated to optionally take a
> +	 * buffer.
> +	 */
> +	cp.git_cmd = 1;
> +	argv_array_pushl(&cp.args, "apply", "--cached", NULL);
> +	return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
> +}
> +
> +static int reset_head(void)
> +{
> +	struct child_process cp = CHILD_PROCESS_INIT;
> +
> +	/*
> +	 * Reset is overall quite simple, however there is no current public
> +	 * API for resetting.
> +	 */
> +	cp.git_cmd = 1;
> +	argv_array_push(&cp.args, "reset");
> +
> +	return run_command(&cp);
> +}
> +
> +static int get_newly_staged(struct strbuf *out, struct object_id *c_tree)
> +{
> +	struct child_process cp = CHILD_PROCESS_INIT;
> +	const char *c_tree_hex = oid_to_hex(c_tree);
> +
> +	/*
> +	 * diff-index is very similar to diff-tree above, and should be
> +	 * converted together with update_index.
> +	 */
> +	cp.git_cmd = 1;
> +	argv_array_pushl(&cp.args, "diff-index", "--cached", "--name-only",
> +			 "--diff-filter=A", NULL);
> +	argv_array_push(&cp.args, c_tree_hex);
> +	return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
> +}
> +
> +static int update_index(struct strbuf *out)
> +{
> +	struct child_process cp = CHILD_PROCESS_INIT;
> +
> +	/*
> +	 * Update-index is very complicated and may need to have a public
> +	 * function exposed in order to remove this forking.
> +	 */
> +	cp.git_cmd = 1;
> +	argv_array_pushl(&cp.args, "update-index", "--add", "--stdin", NULL);
> +	return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
> +}
> +
> +static int restore_untracked(struct object_id *u_tree)
> +{
> +	int res;
> +	struct child_process cp = CHILD_PROCESS_INIT;
> +
> +	/*
> +	 * We need to run restore files from a given index, but without
> +	 * affecting the current index, so we use GIT_INDEX_FILE with
> +	 * run_command to fork processes that will not interfere.
> +	 */
> +	cp.git_cmd = 1;
> +	argv_array_push(&cp.args, "read-tree");
> +	argv_array_push(&cp.args, oid_to_hex(u_tree));
> +	argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
> +			 stash_index_path.buf);
> +	if (run_command(&cp)) {
> +		remove_path(stash_index_path.buf);
> +		return -1;
> +	}
> +
> +	child_process_init(&cp);
> +	cp.git_cmd = 1;
> +	argv_array_pushl(&cp.args, "checkout-index", "--all", NULL);
> +	argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
> +			 stash_index_path.buf);
> +
> +	res = run_command(&cp);
> +	remove_path(stash_index_path.buf);
> +	return res;
> +}
> +
> +static int do_apply_stash(const char *prefix, struct stash_info *info,
> +			  int index, int quiet)
> +{
> +	int ret;
> +	int has_index = index;
> +	struct merge_options o;
> +	struct object_id c_tree;
> +	struct object_id index_tree;
> +	struct commit *result;
> +	const struct object_id *bases[1];
> +
> +	read_cache_preload(NULL);
> +	if (refresh_cache(REFRESH_QUIET))
> +		return -1;
> +
> +	if (write_cache_as_tree(&c_tree, 0, NULL) || reset_tree(&c_tree, 0, 0))
> +		return error(_("cannot apply a stash in the middle of a merge"));
> +
> +	if (index) {
> +		if (!oidcmp(&info->b_tree, &info->i_tree) ||
> +		    !oidcmp(&c_tree, &info->i_tree)) {
> +			has_index = 0;
> +		} else {
> +			struct strbuf out = STRBUF_INIT;
> +
> +			if (diff_tree_binary(&out, &info->w_commit)) {
> +				strbuf_release(&out);
> +				return -1;
> +			}
> +
> +			ret = apply_cached(&out);
> +			strbuf_release(&out);
> +			if (ret)
> +				return -1;
> +
> +			discard_cache();
> +			read_cache();
> +			if (write_cache_as_tree(&index_tree, 0, NULL))
> +				return -1;
> +
> +			reset_head();
> +		}
> +	}
> +
> +	if (info->has_u && restore_untracked(&info->u_tree))
> +		return error(_("could not restore untracked files from stash"));
> +
> +	init_merge_options(&o);
> +
> +	o.branch1 = "Updated upstream";
> +	o.branch2 = "Stashed changes";
> +
> +	if (!oidcmp(&info->b_tree, &c_tree))
> +		o.branch1 = "Version stash was based on";
> +
> +	if (quiet)
> +		o.verbosity = 0;
> +
> +	if (o.verbosity >= 3)
> +		printf_ln(_("Merging %s with %s"), o.branch1, o.branch2);
> +
> +	bases[0] = &info->b_tree;
> +
> +	ret = merge_recursive_generic(&o, &c_tree, &info->w_tree, 1, bases,
> +				      &result);
> +	if (ret) {
> +		rerere(0);
> +
> +		if (index)
> +			fprintf_ln(stderr, _("Index was not unstashed."));
> +
> +		return ret;
> +	}
> +
> +	if (has_index) {
> +		if (reset_tree(&index_tree, 0, 0))
> +			return -1;
> +	} else {
> +		struct strbuf out = STRBUF_INIT;
> +
> +		if (get_newly_staged(&out, &c_tree)) {
> +			strbuf_release(&out);
> +			return -1;
> +		}
> +
> +		if (reset_tree(&c_tree, 0, 1)) {
> +			strbuf_release(&out);
> +			return -1;
> +		}
> +
> +		ret = update_index(&out);
> +		strbuf_release(&out);
> +		if (ret)
> +			return -1;
> +
> +		discard_cache();
> +	}
> +
> +	if (quiet) {
> +		if (refresh_cache(REFRESH_QUIET))
> +			warning("could not refresh index");
> +	} else {
> +		struct child_process cp = CHILD_PROCESS_INIT;
> +
> +		/*
> +		 * Status is quite simple and could be replaced with calls to
> +		 * wt_status in the future, but it adds complexities which may
> +		 * require more tests.
> +		 */
> +		cp.git_cmd = 1;
> +		cp.dir = prefix;
> +		argv_array_push(&cp.args, "status");
> +		run_command(&cp);
> +	}
> +
> +	return 0;
> +}
> +
> +static int apply_stash(int argc, const char **argv, const char *prefix)
> +{
> +	int ret;
> +	int quiet = 0;
> +	int index = 0;
> +	struct stash_info info;
> +	struct option options[] = {
> +		OPT__QUIET(&quiet, N_("be quiet, only report errors")),
> +		OPT_BOOL(0, "index", &index,
> +			 N_("attempt to recreate the index")),
> +		OPT_END()
> +	};
> +
> +	argc = parse_options(argc, argv, prefix, options,
> +			     git_stash_helper_apply_usage, 0);
> +
> +	if (get_stash_info(&info, argc, argv))
> +		return -1;
> +
> +	ret = do_apply_stash(prefix, &info, index, quiet);
> +	free_stash_info(&info);
> +	return ret;
> +}
> +
> +int cmd_stash__helper(int argc, const char **argv, const char *prefix)
> +{
> +	pid_t pid = getpid();
> +	const char *index_file;
> +
> +	struct option options[] = {
> +		OPT_END()
> +	};
> +
> +	git_config(git_default_config, NULL);
> +
> +	argc = parse_options(argc, argv, prefix, options, git_stash_helper_usage,
> +			     PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
> +
> +	index_file = get_index_file();
> +	strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file,
> +		    (uintmax_t)pid);
> +
> +	if (argc < 1)
> +		usage_with_options(git_stash_helper_usage, options);
> +	if (!strcmp(argv[0], "apply"))
> +		return !!apply_stash(argc, argv, prefix);
> +
> +	usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
> +		      git_stash_helper_usage, options);
> +}
> diff --git a/git-stash.sh b/git-stash.sh
> index 94793c1a91..809b1c2d1d 100755
> --- a/git-stash.sh
> +++ b/git-stash.sh
> @@ -566,76 +566,11 @@ assert_stash_ref() {
>  }
>  
>  apply_stash () {
> -
> -	assert_stash_like "$@"
> -
> -	git update-index -q --refresh || die "$(gettext "unable to refresh index")"
> -
> -	# current index state
> -	c_tree=$(git write-tree) ||
> -		die "$(gettext "Cannot apply a stash in the middle of a merge")"
> -
> -	unstashed_index_tree=
> -	if test -n "$INDEX_OPTION" && test "$b_tree" != "$i_tree" &&
> -			test "$c_tree" != "$i_tree"
> -	then
> -		git diff-tree --binary $s^2^..$s^2 | git apply --cached
> -		test $? -ne 0 &&
> -			die "$(gettext "Conflicts in index. Try without --index.")"
> -		unstashed_index_tree=$(git write-tree) ||
> -			die "$(gettext "Could not save index tree")"
> -		git reset
> -	fi
> -
> -	if test -n "$u_tree"
> -	then
> -		GIT_INDEX_FILE="$TMPindex" git read-tree "$u_tree" &&
> -		GIT_INDEX_FILE="$TMPindex" git checkout-index --all &&
> -		rm -f "$TMPindex" ||
> -		die "$(gettext "Could not restore untracked files from stash entry")"
> -	fi
> -
> -	eval "
> -		GITHEAD_$w_tree='Stashed changes' &&
> -		GITHEAD_$c_tree='Updated upstream' &&
> -		GITHEAD_$b_tree='Version stash was based on' &&
> -		export GITHEAD_$w_tree GITHEAD_$c_tree GITHEAD_$b_tree
> -	"
> -
> -	if test -n "$GIT_QUIET"
> -	then
> -		GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY
> -	fi
> -	if git merge-recursive $b_tree -- $c_tree $w_tree
> -	then
> -		# No conflict
> -		if test -n "$unstashed_index_tree"
> -		then
> -			git read-tree "$unstashed_index_tree"
> -		else
> -			a="$TMP-added" &&
> -			git diff-index --cached --name-only --diff-filter=A $c_tree >"$a" &&
> -			git read-tree --reset $c_tree &&
> -			git update-index --add --stdin <"$a" ||
> -				die "$(gettext "Cannot unstage modified files")"
> -			rm -f "$a"
> -		fi
> -		squelch=
> -		if test -n "$GIT_QUIET"
> -		then
> -			squelch='>/dev/null 2>&1'
> -		fi
> -		(cd "$START_DIR" && eval "git status $squelch") || :
> -	else
> -		# Merge conflict; keep the exit status from merge-recursive
> -		status=$?
> -		git rerere
> -		if test -n "$INDEX_OPTION"
> -		then
> -			gettextln "Index was not unstashed." >&2
> -		fi
> -		exit $status
> -	fi
> +	cd "$START_DIR"
> +	git stash--helper apply "$@"
> +	res=$?
> +	cd_to_toplevel
> +	return $res
>  }
>  
>  pop_stash() {
> @@ -713,7 +648,8 @@ push)
>  	;;
>  apply)
>  	shift
> -	apply_stash "$@"
> +	cd "$START_DIR"
> +	git stash--helper apply "$@"
>  	;;
>  clear)
>  	shift
> diff --git a/git.c b/git.c
> index c27c38738b..3c0e762d7d 100644
> --- a/git.c
> +++ b/git.c
> @@ -544,6 +544,7 @@ static struct cmd_struct commands[] = {
>  	{ "show-index", cmd_show_index },
>  	{ "show-ref", cmd_show_ref, RUN_SETUP },
>  	{ "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
> +	{ "stash--helper", cmd_stash__helper, RUN_SETUP | NEED_WORK_TREE },
>  	{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
>  	{ "stripspace", cmd_stripspace },
>  	{ "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX | NO_PARSEOPT },
> -- 
> 2.19.0.rc0.23.g1fb9f40d88
> 
Previous: Paul-Sebastian UngureanuNext: Paul-Sebastian Ungureanu
Message 160 of 181 in “Convert some stash functionality to a builtin”
  1. 0/5 Convert some stash functionality to a builtinJoel Teichroeb, Apr 5, 2018
  2. 1/5 stash: improve option parsing test coverageJoel Teichroeb, Apr 5, 2018
  3. Johannes SchindelinApr 6, 2018
  4. Paul-Sebastian UngureanuApr 6, 2018
  5. Johannes SchindelinApr 9, 2018
  6. 3/5 stash: convert drop and clear to builtinJoel Teichroeb, Apr 5, 2018
  7. Johannes SchindelinApr 6, 2018
  8. 4/5 stash: convert branch to builtinJoel Teichroeb, Apr 5, 2018
  9. Johannes SchindelinApr 6, 2018
  10. 5/5 stash: convert pop to builtinJoel Teichroeb, Apr 5, 2018
  11. Johannes SchindelinApr 6, 2018
  12. 2/5 stash: convert apply to builtinJoel Teichroeb, Apr 5, 2018
  13. Christian CouderApr 5, 2018
  14. Christian CouderApr 5, 2018
  15. Christian CouderApr 5, 2018
  16. Johannes SchindelinApr 5, 2018
  17. Johannes SchindelinApr 6, 2018
  18. Johannes SchindelinApr 6, 2018
  19. Johannes SchindelinApr 6, 2018
  20. Paul-Sebastian UngureanuApr 28, 2018
  21. Johannes SchindelinApr 29, 2018
  22. 0/4 stash: add new tests and introduce a new helper functionPaul-Sebastian Ungureanu, Jun 25, 2018
  23. 1/4 sha1-name.c: added 'get_oidf', which acts like 'get_oid'Paul-Sebastian Ungureanu, Jun 25, 2018
  24. Johannes SchindelinJun 26, 2018
  25. 2/4 stash: improve option parsing test coveragePaul-Sebastian Ungureanu, Jun 25, 2018
  26. 3/4 stash: update test cases conform to coding guidelinesPaul-Sebastian Ungureanu, Jun 25, 2018
  27. Johannes SchindelinJun 26, 2018
  28. 4/4 stash: renamed test cases to be more descriptivePaul-Sebastian Ungureanu, Jun 25, 2018
  29. Johannes SchindelinJun 26, 2018
  30. 2/4 stash: convert drop and clear to builtinPaul-Sebastian Ungureanu, Jun 25, 2018
  31. Johannes SchindelinJun 26, 2018
  32. Paul-Sebastian UngureanuJun 28, 2018
  33. 1/4 stash: convert apply to builtinPaul-Sebastian Ungureanu, Jun 25, 2018
  34. 4/4 stash: convert pop to builtinPaul-Sebastian Ungureanu, Jun 25, 2018
  35. Johannes SchindelinJun 26, 2018
  36. 3/4 stash: convert branch to builtinPaul-Sebastian Ungureanu, Jun 25, 2018
  37. Johannes SchindelinJun 26, 2018
  38. Junio C HamanoJun 27, 2018
  39. Paul-Sebastian UngureanuJun 28, 2018
  40. 1/6 stash: implement the "list" command in the builtinPaul-Sebastian Ungureanu, Jun 25, 2018
  41. 3/6 stash: change `git stash show` usage text and documentationPaul-Sebastian Ungureanu, Jun 25, 2018
  42. 6/6 stash: convert store to builtinPaul-Sebastian Ungureanu, Jun 25, 2018
  43. 2/6 stash: convert show to builtinPaul-Sebastian Ungureanu, Jun 25, 2018
  44. 5/6 stash: update `git stash show` documentationPaul-Sebastian Ungureanu, Jun 25, 2018
  45. 4/6 stash: refactor `show_stash()` to use the diff APIPaul-Sebastian Ungureanu, Jun 25, 2018
  46. Johannes SchindelinJun 26, 2018
  47. Junio C HamanoJun 27, 2018
  48. Paul-Sebastian UngureanuJun 28, 2018
  49. Johannes SchindelinJun 26, 2018
  50. Paul-Sebastian UngureanuJun 28, 2018
  51. [GSoC][PATCH v7 00/26] Convert "git stash" to C builtinPaul-Sebastian Ungureanu, Aug 8, 2018
  52. [GSoC][PATCH v7 01/26] sha1-name.c: added 'get_oidf', which acts like 'get_oid'Paul-Sebastian Ungureanu, Aug 8, 2018
  53. [GSoC][PATCH v7 02/26] stash: improve option parsing test coveragePaul-Sebastian Ungureanu, Aug 8, 2018
  54. [GSoC][PATCH v7 03/26] stash: update test cases conform to coding guidelinesPaul-Sebastian Ungureanu, Aug 8, 2018
  55. [GSoC][PATCH v7 04/26] stash: renamed test cases to be more descriptivePaul-Sebastian Ungureanu, Aug 8, 2018
  56. Thomas GummererAug 15, 2018
  57. [GSoC][PATCH v7 05/26] stash: convert apply to builtinPaul-Sebastian Ungureanu, Aug 8, 2018
  58. Junio C HamanoAug 8, 2018
  59. Paul-Sebastian UngureanuAug 9, 2018
  60. Junio C HamanoAug 9, 2018
  61. Paul-Sebastian UngureanuAug 10, 2018
  62. Duy NguyenAug 18, 2018
  63. [GSoC][PATCH v7 07/26] stash: convert branch to builtinPaul-Sebastian Ungureanu, Aug 8, 2018
  64. [GSoC][PATCH v7 06/26] stash: convert drop and clear to builtinPaul-Sebastian Ungureanu, Aug 8, 2018
  65. [GSoC][PATCH v7 08/26] stash: convert pop to builtinPaul-Sebastian Ungureanu, Aug 8, 2018
  66. [GSoC][PATCH v7 10/26] stash: convert show to builtinPaul-Sebastian Ungureanu, Aug 8, 2018
  67. Thomas GummererAug 15, 2018
  68. Paul Sebastian UngureanuAug 18, 2018
  69. [GSoC][PATCH v7 11/26] stash: change `git stash show` usage text and documentationPaul-Sebastian Ungureanu, Aug 8, 2018
  70. Thomas GummererAug 15, 2018
  71. [GSoC][PATCH v7 12/26] stash: refactor `show_stash()` to use the diff APIPaul-Sebastian Ungureanu, Aug 8, 2018
  72. Thomas GummererAug 15, 2018
  73. Paul Sebastian UngureanuAug 18, 2018
  74. [GSoC][PATCH v7 13/26] stash: update `git stash show` documentationPaul-Sebastian Ungureanu, Aug 8, 2018
  75. Thomas GummererAug 15, 2018
  76. [GSoC][PATCH v7 09/26] stash: implement the "list" command in the builtinPaul-Sebastian Ungureanu, Aug 8, 2018
  77. Thomas GummererAug 15, 2018
  78. Paul Sebastian UngureanuAug 18, 2018
  79. [GSoC][PATCH v7 16/26] stash: replace spawning a "read-tree" processPaul-Sebastian Ungureanu, Aug 8, 2018
  80. Thomas GummererAug 18, 2018
  81. [GSoC][PATCH v7 14/26] stash: convert store to builtinPaul-Sebastian Ungureanu, Aug 8, 2018
  82. Thomas GummererAug 15, 2018
  83. [GSoC][PATCH v7 15/26] stash: convert create to builtinPaul-Sebastian Ungureanu, Aug 8, 2018
  84. Thomas GummererAug 15, 2018
  85. Paul Sebastian UngureanuAug 18, 2018
  86. Thomas GummererAug 18, 2018
  87. [GSoC][PATCH v7 17/26] stash: avoid spawning a "diff-index" processPaul-Sebastian Ungureanu, Aug 8, 2018
  88. Thomas GummererAug 18, 2018
  89. [GSoC][PATCH v7 18/26] stash: convert push to builtinPaul-Sebastian Ungureanu, Aug 8, 2018
  90. Thomas GummererAug 18, 2018
  91. [GSoC][PATCH v7 20/26] stash: add tests for `git stash push -q`Paul-Sebastian Ungureanu, Aug 8, 2018
  92. Thomas GummererAug 18, 2018
  93. [GSoC][PATCH v7 19/26] stash: make push to be quietPaul-Sebastian Ungureanu, Aug 8, 2018
  94. Thomas GummererAug 18, 2018
  95. [GSoC][PATCH v7 21/26] stash: replace spawning `git ls-files` child processPaul-Sebastian Ungureanu, Aug 8, 2018
  96. Thomas GummererAug 18, 2018
  97. [GSoC][PATCH v7 22/26] stash: convert save to builtinPaul-Sebastian Ungureanu, Aug 8, 2018
  98. Thomas GummererAug 18, 2018
  99. [GSoC][PATCH v7 24/26] stash: optimize `get_untracked_files()` and `check_changes()`Paul-Sebastian Ungureanu, Aug 8, 2018
  100. Thomas GummererAug 18, 2018
  101. [GSoC][PATCH v7 25/26] stash: replace all `write-tree` child processes with API callsPaul-Sebastian Ungureanu, Aug 8, 2018
  102. Thomas GummererAug 19, 2018
  103. [GSoC][PATCH v7 23/26] stash: convert `stash--helper.c` into `stash.c`Paul-Sebastian Ungureanu, Aug 8, 2018
  104. Thomas GummererAug 18, 2018
  105. [GSoC][PATCH v7 26/26] stash: replace all "git apply" child processes with API callsPaul-Sebastian Ungureanu, Aug 8, 2018
  106. Thomas GummererAug 19, 2018
  107. Thomas GummererAug 15, 2018
  108. Paul Sebastian UngureanuAug 16, 2018
  109. [GSoC][PATCH v8 00/20] Convert "git stash" to C builtinPaul-Sebastian Ungureanu, Aug 30, 2018
  110. [GSoC][PATCH v8 01/20] sha1-name.c: add `get_oidf()` which acts like `get_oid()`Paul-Sebastian Ungureanu, Aug 30, 2018
  111. [GSoC][PATCH v8 02/20] stash: improve option parsing test coveragePaul-Sebastian Ungureanu, Aug 30, 2018
  112. [GSoC][PATCH v8 03/20] stash: update test cases conform to coding guidelinesPaul-Sebastian Ungureanu, Aug 30, 2018
  113. Junio C HamanoAug 30, 2018
  114. [GSoC][PATCH v8 04/20] stash: rename test cases to be more descriptivePaul-Sebastian Ungureanu, Aug 30, 2018
  115. [GSoC][PATCH v8 05/20] stash: add tests for `git stash show` configPaul-Sebastian Ungureanu, Aug 30, 2018
  116. Junio C HamanoAug 30, 2018
  117. Johannes SchindelinSep 3, 2018
  118. [GSoC][PATCH v8 06/20] stash: convert apply to builtinPaul-Sebastian Ungureanu, Aug 30, 2018
  119. [GSoC][PATCH v8 07/20] stash: convert drop and clear to builtinPaul-Sebastian Ungureanu, Aug 30, 2018
  120. [GSoC][PATCH v8 09/20] stash: convert pop to builtinPaul-Sebastian Ungureanu, Aug 30, 2018
  121. [GSoC][PATCH v8 08/20] stash: convert branch to builtinPaul-Sebastian Ungureanu, Aug 30, 2018
  122. Johannes SchindelinSep 3, 2018
  123. [GSoC][PATCH v8 11/20] stash: convert show to builtinPaul-Sebastian Ungureanu, Aug 30, 2018
  124. [GSoC][PATCH v8 13/20] stash: convert store to builtinPaul-Sebastian Ungureanu, Aug 30, 2018
  125. Johannes SchindelinSep 3, 2018
  126. [GSoC][PATCH v8 14/20] stash: convert create to builtinPaul-Sebastian Ungureanu, Aug 30, 2018
  127. Johannes SchindelinSep 3, 2018
  128. Paul-Sebastian UngureanuSep 25, 2018
  129. Johannes SchindelinNov 9, 2018
  130. [GSoC][PATCH v8 12/20] stash: mention options in `show` synopsis.Paul-Sebastian Ungureanu, Aug 30, 2018
  131. [GSoC][PATCH v8 10/20] stash: convert list to builtinPaul-Sebastian Ungureanu, Aug 30, 2018
  132. [GSoC][PATCH v8 16/20] stash: make push -q quietPaul-Sebastian Ungureanu, Aug 30, 2018
  133. [GSoC][PATCH v8 17/20] stash: convert save to builtinPaul-Sebastian Ungureanu, Aug 30, 2018
  134. Johannes SchindelinSep 3, 2018
  135. Eric SunshineSep 3, 2018
  136. Johannes SchindelinSep 3, 2018
  137. [GSoC][PATCH v8 19/20] stash: optimize `get_untracked_files()` and `check_changes()`Paul-Sebastian Ungureanu, Aug 30, 2018
  138. Johannes SchindelinSep 3, 2018
  139. [GSoC][PATCH v8 18/20] stash: convert `stash--helper.c` into `stash.c`Paul-Sebastian Ungureanu, Aug 30, 2018
  140. Johannes SchindelinSep 3, 2018
  141. Paul-Sebastian UngureanuSep 25, 2018
  142. Johannes SchindelinNov 9, 2018
  143. [GSoC][PATCH v8 20/20] stash: replace all `write-tree` child processes with API callsPaul-Sebastian Ungureanu, Aug 30, 2018
  144. Johannes SchindelinSep 3, 2018
  145. [GSoC][PATCH v8 15/20] stash: convert push to builtinPaul-Sebastian Ungureanu, Aug 30, 2018
  146. Johannes SchindelinSep 3, 2018
  147. Ævar Arnfjörð BjarmasonAug 30, 2018
  148. Junio C HamanoAug 31, 2018
  149. Johannes SchindelinSep 3, 2018
  150. 00/21 Convert "git stash" to C builtinPaul-Sebastian Ungureanu, Sep 25, 2018
  151. 01/21 sha1-name.c: add `get_oidf()` which acts like `get_oid()`Paul-Sebastian Ungureanu, Sep 25, 2018
  152. 02/21 strbuf.c: add `strbuf_join_argv()`Paul-Sebastian Ungureanu, Sep 25, 2018
  153. Thomas GummererSep 30, 2018
  154. 03/21 stash: improve option parsing test coveragePaul-Sebastian Ungureanu, Sep 25, 2018
  155. 04/21 stash: update test cases conform to coding guidelinesPaul-Sebastian Ungureanu, Sep 25, 2018
  156. Thomas GummererSep 30, 2018
  157. 05/21 stash: rename test cases to be more descriptivePaul-Sebastian Ungureanu, Sep 25, 2018
  158. 06/21 stash: add tests for `git stash show` configPaul-Sebastian Ungureanu, Sep 25, 2018
  159. 07/21 stash: convert apply to builtinPaul-Sebastian Ungureanu, Sep 25, 2018
  160. Thomas GummererSep 30, 2018
  161. 08/21 stash: convert drop and clear to builtinPaul-Sebastian Ungureanu, Sep 25, 2018
  162. 10/21 stash: convert pop to builtinPaul-Sebastian Ungureanu, Sep 25, 2018
  163. 11/21 stash: convert list to builtinPaul-Sebastian Ungureanu, Sep 25, 2018
  164. 13/21 stash: mention options in `show` synopsis.Paul-Sebastian Ungureanu, Sep 25, 2018
  165. Thomas GummererOct 2, 2018
  166. 14/21 stash: convert store to builtinPaul-Sebastian Ungureanu, Sep 25, 2018
  167. 15/21 stash: convert create to builtinPaul-Sebastian Ungureanu, Sep 25, 2018
  168. Thomas GummererOct 2, 2018
  169. 16/21 stash: convert push to builtinPaul-Sebastian Ungureanu, Sep 25, 2018
  170. Thomas GummererOct 2, 2018
  171. 17/21 stash: make push -q quietPaul-Sebastian Ungureanu, Sep 25, 2018
  172. 18/21 stash: convert save to builtinPaul-Sebastian Ungureanu, Sep 25, 2018
  173. 19/21 stash: convert `stash--helper.c` into `stash.c`Paul-Sebastian Ungureanu, Sep 25, 2018
  174. Thomas GummererOct 2, 2018
  175. 12/21 stash: convert show to builtinPaul-Sebastian Ungureanu, Sep 25, 2018
  176. 21/21 stash: replace all `write-tree` child processes with API callsPaul-Sebastian Ungureanu, Sep 25, 2018
  177. 20/21 stash: optimize `get_untracked_files()` and `check_changes()`Paul-Sebastian Ungureanu, Sep 25, 2018
  178. 09/21 stash: convert branch to builtinPaul-Sebastian Ungureanu, Sep 25, 2018
  179. Thomas GummererSep 30, 2018
  180. Junio C HamanoSep 26, 2018
  181. Joel TeichroebApr 30, 2018

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.