Skip to content

stash: partial stash specific files #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 28, 2022

Conversation

gitkraken-jacobw
Copy link

Copy-pasted from main libgit2 repo:

There's this concept called partial stashing in Git where users are able to stash desired files without having to stash and also reset the entire workdir. I based my implementation on tiennou's suggestion from libgit2#4725. This introduces options to git_stash_save where developers are able to supply the paths that they want to have stashed from the workdir. I could have gone further and have exposed a git_index* option as tiennou suggested, but I chose not to at this moment. Let me know if I should expose a git_index* option so that users can supply an arbitrary index to be stashed.

I also introduced GIT_STASH_KEEP_ALL, which prevents resetting the index and workdir once a stash has been completed.

Copy link

@AlexaXs AlexaXs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks very good, just maybe it would help with the review if you could add different commits, each one explaining the changes applied. I can think of these two:

  • a commit explaining the fact that code of git_stash_save() has been moved inside the new function git_stash_save_with_opts() and that this function handles two different cases, case when no paths are specified and case with paths for partial stashing.
  • a commit explaining the changes in commit_worktree()

* or error code.
*/
GIT_EXTERN(int) git_stash_save_with_opts(
git_oid *out, git_repository *repo, git_stash_save_options *opts);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • opts should be const: const git_stash_save_options *opts
  • we should keep the format here of other functions: \n and \t for each argument of the function, same way as for example git_stash_apply

src/stash.c Outdated
static int stash_update_index_from_paths(
git_repository *repo,
git_index *index,
git_strarray *paths)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const git_strarray *paths

src/stash.c Outdated
git_oid *w_commit_oid,
git_repository *repo,
const git_signature *stasher,
const char *message,
git_commit *i_commit,
git_commit *b_commit,
git_commit *u_commit)
git_commit *u_commit,
git_tree *tree)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const git_tree *tree

src/stash.c Outdated
static int ensure_there_are_changes_to_stash_paths(
git_repository *repo,
uint32_t flags,
git_strarray *paths)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const git_strarray *paths

src/stash.c Outdated
}

int git_stash_save_with_opts(
git_oid *out, git_repository *repo, git_stash_save_options *opts)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const git_stash_save_options *opts

int error;

GIT_ASSERT_ARG(out);
GIT_ASSERT_ARG(repo);
GIT_ASSERT_ARG(stasher);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to check if opts is NULL, and if so provide a default one. Similar to what normalize_apply_options does at the beginning.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it appears opts.stasher is required, should we instead do something like:

GIT_ASSERT_ARG(opts);
GIT_ASSERT_ARG(opts->stasher); // not sure if this is the best way to validate properties

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems GIT_ASSERT_ARG is used when NULL is not allowed for the argument, and checking for NULL and providing a default value is used when NULL is allowed. So I agree we can use GIT_ASSERT_ARG(opts) inside git_stash_save_with_opts.

The problem is when the user calls git_stash_save, GIT_STASH_SAVE_OPTIONS_INIT initializes stasher with NULL, in which case if we don't allow stasher to be NULL inside git_stash_save_with_opts it won't work.

I think a possible solution could be GIT_ASSERT_ARG(stasher) inside git_stash_save, and GIT_ASSERT_ARG(opts && opts->stasher) inside `git_stash_save_with_opts

* @param version The struct version; pass `GIT_STASH_SAVE_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_stash_save_options_init(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be good to add a test in tests/core/structinit.c similar to this one:

    /* stash apply */
    CHECK_MACRO_FUNC_INIT_EQUAL( \
      git_stash_apply_options, GIT_STASH_APPLY_OPTIONS_VERSION, \
      GIT_STASH_APPLY_OPTIONS_INIT, git_stash_apply_options_init);

src/stash.c Outdated

if ((error = git_repository__ensure_not_bare(repo, "stash save")) < 0)
return error;

if ((error = retrieve_base_commit_and_message(&b_commit, &msg, repo)) < 0)
goto cleanup;

if ((error = ensure_there_are_changes_to_stash(repo, flags)) < 0)
if (opts->paths.count == 0 &&
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably it could clear the code a bit if we added a flag like bool hasPaths assigning it the value of opts->paths.count > 0, and use that flag when testing this condition in the code: if (!hasPaths)...

src/stash.c Outdated
if ((error = commit_worktree(out, repo, stasher, git_buf_cstr(&msg),
i_commit, b_commit, u_commit)) < 0)
goto cleanup;
if (opts->paths.count == 0) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (!hasPaths)...

@@ -593,7 +754,10 @@ int git_stash_save(
git_commit_free(i_commit);
git_commit_free(b_commit);
git_commit_free(u_commit);
git_tree_free(tree);
Copy link

@AlexaXs AlexaXs Jul 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_free() functions are safe with NULL, but since we are mixing code here for cases with paths and without paths, it'd be good to do this here too:

if (hasPaths) {
  git_tree_free(tree);
  git_reference_free(head);
  git_index_free(paths_index);
}

we want to build a partial stash from an index in the future, so some functions have been reworked to allow for this
code has been moved from `git_stash_save` into `git_stash_save_with_opts` in order to handle cases where we want to partially stash using options or stash normally without partially stashed paths specified
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants