mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-07 12:45:00 +00:00
commit
8a1479a55a
@ -52,5 +52,6 @@
|
||||
#include "git2/reset.h"
|
||||
#include "git2/message.h"
|
||||
#include "git2/pack.h"
|
||||
#include "git2/stash.h"
|
||||
|
||||
#endif
|
||||
|
@ -59,6 +59,7 @@ typedef enum {
|
||||
GITERR_SSL,
|
||||
GITERR_SUBMODULE,
|
||||
GITERR_THREAD,
|
||||
GITERR_STASH,
|
||||
} git_error_t;
|
||||
|
||||
/**
|
||||
|
@ -347,6 +347,14 @@ GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry);
|
||||
*/
|
||||
GIT_EXTERN(int) git_index_read_tree(git_index *index, git_tree *tree);
|
||||
|
||||
/**
|
||||
* Get the repository this index relates to
|
||||
*
|
||||
* @param index The index
|
||||
* @return A pointer to the repository
|
||||
*/
|
||||
GIT_EXTERN(git_repository *) git_index_owner(const git_index *index);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
||||
|
@ -97,9 +97,9 @@ GIT_EXTERN(const git_reflog_entry *) git_reflog_entry_byindex(git_reflog *reflog
|
||||
/**
|
||||
* Remove an entry from the reflog by its index
|
||||
*
|
||||
* To ensure there's no gap in the log history, set the `rewrite_previosu_entry` to 1.
|
||||
* When deleting entry `n`, member old_oid of entry `n-1` (if any) will be updated with
|
||||
* the value of memeber new_oid of entry `n+1`.
|
||||
* To ensure there's no gap in the log history, set `rewrite_previous_entry`
|
||||
* param value to 1. When deleting entry `n`, member old_oid of entry `n-1`
|
||||
* (if any) will be updated with the value of member new_oid of entry `n+1`.
|
||||
*
|
||||
* @param reflog a previously loaded reflog.
|
||||
*
|
||||
|
122
include/git2/stash.h
Normal file
122
include/git2/stash.h
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2012 the libgit2 contributors
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
#ifndef INCLUDE_git_stash_h__
|
||||
#define INCLUDE_git_stash_h__
|
||||
|
||||
#include "common.h"
|
||||
#include "types.h"
|
||||
|
||||
/**
|
||||
* @file git2/stash.h
|
||||
* @brief Git stash management routines
|
||||
* @ingroup Git
|
||||
* @{
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
enum {
|
||||
GIT_STASH_DEFAULT = 0,
|
||||
|
||||
/* All changes already added to the index
|
||||
* are left intact in the working directory
|
||||
*/
|
||||
GIT_STASH_KEEP_INDEX = (1 << 0),
|
||||
|
||||
/* All untracked files are also stashed and then
|
||||
* cleaned up from the working directory
|
||||
*/
|
||||
GIT_STASH_INCLUDE_UNTRACKED = (1 << 1),
|
||||
|
||||
/* All ignored files are also stashed and then
|
||||
* cleaned up from the working directory
|
||||
*/
|
||||
GIT_STASH_INCLUDE_IGNORED = (1 << 2),
|
||||
};
|
||||
|
||||
/**
|
||||
* Save the local modifications to a new stash.
|
||||
*
|
||||
* @param out Object id of the commit containing the stashed state.
|
||||
* This commit is also the target of the direct reference refs/stash.
|
||||
*
|
||||
* @param repo The owning repository.
|
||||
*
|
||||
* @param stasher The identity of the person performing the stashing.
|
||||
*
|
||||
* @param message Optional description along with the stashed state.
|
||||
*
|
||||
* @param flags Flags to control the stashing process.
|
||||
*
|
||||
* @return 0 on success, GIT_ENOTFOUND where there's nothing to stash,
|
||||
* or error code.
|
||||
*/
|
||||
|
||||
GIT_EXTERN(int) git_stash_save(
|
||||
git_oid *out,
|
||||
git_repository *repo,
|
||||
git_signature *stasher,
|
||||
const char *message,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* When iterating over all the stashed states, callback that will be
|
||||
* issued per entry.
|
||||
*
|
||||
* @param index The position within the stash list. 0 points to the
|
||||
* most recent stashed state.
|
||||
*
|
||||
* @param message The stash message.
|
||||
*
|
||||
* @param stash_oid The commit oid of the stashed state.
|
||||
*
|
||||
* @param payload Extra parameter to callback function.
|
||||
*
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
*/
|
||||
typedef int (*stash_cb)(
|
||||
size_t index,
|
||||
const char* message,
|
||||
const git_oid *stash_oid,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Loop over all the stashed states and issue a callback for each one.
|
||||
*
|
||||
* If the callback returns a non-zero value, this will stop looping.
|
||||
*
|
||||
* @param repo Repository where to find the stash.
|
||||
*
|
||||
* @param callabck Callback to invoke per found stashed state. The most recent
|
||||
* stash state will be enumerated first.
|
||||
*
|
||||
* @param payload Extra parameter to callback function.
|
||||
*
|
||||
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_stash_foreach(
|
||||
git_repository *repo,
|
||||
stash_cb callback,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Remove a single stashed state from the stash list.
|
||||
*
|
||||
* @param repo The owning repository.
|
||||
*
|
||||
* @param index The position within the stash list. 0 points to the
|
||||
* most recent stashed state.
|
||||
*
|
||||
* @return 0 on success, or error code
|
||||
*/
|
||||
|
||||
GIT_EXTERN(int) git_stash_drop(
|
||||
git_repository *repo,
|
||||
size_t index);
|
||||
|
||||
/** @} */
|
||||
GIT_END_DECL
|
||||
#endif
|
@ -1071,3 +1071,8 @@ int git_index_read_tree(git_index *index, git_tree *tree)
|
||||
|
||||
return git_tree_walk(tree, read_tree_cb, GIT_TREEWALK_POST, index);
|
||||
}
|
||||
|
||||
git_repository *git_index_owner(const git_index *index)
|
||||
{
|
||||
return INDEX_OWNER(index);
|
||||
}
|
||||
|
22
src/reflog.c
22
src/reflog.c
@ -166,6 +166,9 @@ void git_reflog_free(git_reflog *reflog)
|
||||
unsigned int i;
|
||||
git_reflog_entry *entry;
|
||||
|
||||
if (reflog == NULL)
|
||||
return;
|
||||
|
||||
for (i=0; i < reflog->entries.length; i++) {
|
||||
entry = git_vector_get(&reflog->entries, i);
|
||||
|
||||
@ -185,7 +188,10 @@ static int retrieve_reflog_path(git_buf *path, git_reference *ref)
|
||||
|
||||
static int create_new_reflog_file(const char *filepath)
|
||||
{
|
||||
int fd;
|
||||
int fd, error;
|
||||
|
||||
if ((error = git_futils_mkpath2file(filepath, GIT_REFLOG_DIR_MODE)) < 0)
|
||||
return error;
|
||||
|
||||
if ((fd = p_open(filepath,
|
||||
O_WRONLY | O_CREAT | O_TRUNC,
|
||||
@ -463,26 +469,26 @@ int git_reflog_drop(
|
||||
if (!rewrite_previous_entry)
|
||||
return 0;
|
||||
|
||||
/* No need to rewrite anything when removing the first entry */
|
||||
if (idx == 0)
|
||||
/* No need to rewrite anything when removing the most recent entry */
|
||||
if (idx == entrycount - 1)
|
||||
return 0;
|
||||
|
||||
/* There are no more entries in the log */
|
||||
if (entrycount == 1)
|
||||
return 0;
|
||||
|
||||
entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx - 1);
|
||||
entry = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx);
|
||||
|
||||
/* If the last entry has just been removed... */
|
||||
if (idx == entrycount - 1) {
|
||||
/* ...clear the oid_old member of the "new" last entry */
|
||||
/* If the oldest entry has just been removed... */
|
||||
if (idx == 0) {
|
||||
/* ...clear the oid_old member of the "new" oldest entry */
|
||||
if (git_oid_fromstr(&entry->oid_old, GIT_OID_HEX_ZERO) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
previous = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx);
|
||||
previous = (git_reflog_entry *)git_reflog_entry_byindex(reflog, idx - 1);
|
||||
git_oid_cpy(&entry->oid_old, &previous->oid_cur);
|
||||
|
||||
return 0;
|
||||
|
@ -35,6 +35,9 @@
|
||||
#define GIT_CHERRY_PICK_HEAD_FILE "CHERRY_PICK_HEAD"
|
||||
#define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master"
|
||||
|
||||
#define GIT_STASH_FILE "stash"
|
||||
#define GIT_REFS_STASH_FILE GIT_REFS_DIR GIT_STASH_FILE
|
||||
|
||||
#define GIT_REFNAME_MAX 1024
|
||||
|
||||
struct git_reference {
|
||||
|
659
src/stash.c
Normal file
659
src/stash.c
Normal file
@ -0,0 +1,659 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2012 the libgit2 contributors
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "repository.h"
|
||||
#include "commit.h"
|
||||
#include "tree.h"
|
||||
#include "reflog.h"
|
||||
#include "git2/diff.h"
|
||||
#include "git2/stash.h"
|
||||
#include "git2/status.h"
|
||||
#include "git2/checkout.h"
|
||||
|
||||
static int create_error(int error, const char *msg)
|
||||
{
|
||||
giterr_set(GITERR_STASH, "Cannot stash changes - %s", msg);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int ensure_non_bare_repository(git_repository *repo)
|
||||
{
|
||||
if (!git_repository_is_bare(repo))
|
||||
return 0;
|
||||
|
||||
return create_error(GIT_EBAREREPO,
|
||||
"Stash related operations require a working directory.");
|
||||
}
|
||||
|
||||
static int retrieve_head(git_reference **out, git_repository *repo)
|
||||
{
|
||||
int error = git_repository_head(out, repo);
|
||||
|
||||
if (error == GIT_EORPHANEDHEAD)
|
||||
return create_error(error, "You do not have the initial commit yet.");
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int append_abbreviated_oid(git_buf *out, const git_oid *b_commit)
|
||||
{
|
||||
char *formatted_oid;
|
||||
|
||||
formatted_oid = git_oid_allocfmt(b_commit);
|
||||
GITERR_CHECK_ALLOC(formatted_oid);
|
||||
|
||||
git_buf_put(out, formatted_oid, 7);
|
||||
git__free(formatted_oid);
|
||||
|
||||
return git_buf_oom(out) ? -1 : 0;
|
||||
}
|
||||
|
||||
static int append_commit_description(git_buf *out, git_commit* commit)
|
||||
{
|
||||
const char *message;
|
||||
int pos = 0, len;
|
||||
|
||||
if (append_abbreviated_oid(out, git_commit_id(commit)) < 0)
|
||||
return -1;
|
||||
|
||||
message = git_commit_message(commit);
|
||||
len = strlen(message);
|
||||
|
||||
/* TODO: Replace with proper commit short message
|
||||
* when git_commit_message_short() is implemented.
|
||||
*/
|
||||
while (pos < len && message[pos] != '\n')
|
||||
pos++;
|
||||
|
||||
git_buf_putc(out, ' ');
|
||||
git_buf_put(out, message, pos);
|
||||
git_buf_putc(out, '\n');
|
||||
|
||||
return git_buf_oom(out) ? -1 : 0;
|
||||
}
|
||||
|
||||
static int retrieve_base_commit_and_message(
|
||||
git_commit **b_commit,
|
||||
git_buf *stash_message,
|
||||
git_repository *repo)
|
||||
{
|
||||
git_reference *head = NULL;
|
||||
int error;
|
||||
|
||||
if ((error = retrieve_head(&head, repo)) < 0)
|
||||
return error;
|
||||
|
||||
error = -1;
|
||||
|
||||
if (strcmp("HEAD", git_reference_name(head)) == 0)
|
||||
git_buf_puts(stash_message, "(no branch): ");
|
||||
else
|
||||
git_buf_printf(
|
||||
stash_message,
|
||||
"%s: ",
|
||||
git_reference_name(head) + strlen(GIT_REFS_HEADS_DIR));
|
||||
|
||||
if (git_commit_lookup(b_commit, repo, git_reference_oid(head)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (append_commit_description(stash_message, *b_commit) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = 0;
|
||||
|
||||
cleanup:
|
||||
git_reference_free(head);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int build_tree_from_index(git_tree **out, git_index *index)
|
||||
{
|
||||
git_oid i_tree_oid;
|
||||
|
||||
if (git_tree_create_fromindex(&i_tree_oid, index) < 0)
|
||||
return -1;
|
||||
|
||||
return git_tree_lookup(out, git_index_owner(index), &i_tree_oid);
|
||||
}
|
||||
|
||||
static int commit_index(
|
||||
git_commit **i_commit,
|
||||
git_index *index,
|
||||
git_signature *stasher,
|
||||
const char *message,
|
||||
const git_commit *parent)
|
||||
{
|
||||
git_tree *i_tree = NULL;
|
||||
git_oid i_commit_oid;
|
||||
git_buf msg = GIT_BUF_INIT;
|
||||
int error = -1;
|
||||
|
||||
if (build_tree_from_index(&i_tree, index) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_buf_printf(&msg, "index on %s\n", message) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_commit_create(
|
||||
&i_commit_oid,
|
||||
git_index_owner(index),
|
||||
NULL,
|
||||
stasher,
|
||||
stasher,
|
||||
NULL,
|
||||
git_buf_cstr(&msg),
|
||||
i_tree,
|
||||
1,
|
||||
&parent) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = git_commit_lookup(i_commit, git_index_owner(index), &i_commit_oid);
|
||||
|
||||
cleanup:
|
||||
git_tree_free(i_tree);
|
||||
git_buf_free(&msg);
|
||||
return error;
|
||||
}
|
||||
|
||||
struct cb_data {
|
||||
git_index *index;
|
||||
|
||||
bool include_changed;
|
||||
bool include_untracked;
|
||||
bool include_ignored;
|
||||
};
|
||||
|
||||
static int update_index_cb(
|
||||
void *cb_data,
|
||||
const git_diff_delta *delta,
|
||||
float progress)
|
||||
{
|
||||
int pos;
|
||||
struct cb_data *data = (struct cb_data *)cb_data;
|
||||
|
||||
GIT_UNUSED(progress);
|
||||
|
||||
switch (delta->status) {
|
||||
case GIT_DELTA_IGNORED:
|
||||
if (!data->include_ignored)
|
||||
break;
|
||||
|
||||
return git_index_add(data->index, delta->new_file.path, 0);
|
||||
|
||||
case GIT_DELTA_UNTRACKED:
|
||||
if (!data->include_untracked)
|
||||
break;
|
||||
|
||||
return git_index_add(data->index, delta->new_file.path, 0);
|
||||
|
||||
case GIT_DELTA_ADDED:
|
||||
/* Fall through */
|
||||
case GIT_DELTA_MODIFIED:
|
||||
if (!data->include_changed)
|
||||
break;
|
||||
|
||||
return git_index_add(data->index, delta->new_file.path, 0);
|
||||
|
||||
case GIT_DELTA_DELETED:
|
||||
if (!data->include_changed)
|
||||
break;
|
||||
|
||||
if ((pos = git_index_find(data->index, delta->new_file.path)) < 0)
|
||||
return -1;
|
||||
|
||||
if (git_index_remove(data->index, pos) < 0)
|
||||
return -1;
|
||||
|
||||
default:
|
||||
/* Unimplemented */
|
||||
giterr_set(
|
||||
GITERR_INVALID,
|
||||
"Cannot update index. Unimplemented status kind (%d)",
|
||||
delta->status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int build_untracked_tree(
|
||||
git_tree **tree_out,
|
||||
git_index *index,
|
||||
git_commit *i_commit,
|
||||
uint32_t flags)
|
||||
{
|
||||
git_tree *i_tree = NULL;
|
||||
git_diff_list *diff = NULL;
|
||||
git_diff_options opts = {0};
|
||||
struct cb_data data = {0};
|
||||
int error = -1;
|
||||
|
||||
git_index_clear(index);
|
||||
|
||||
data.index = index;
|
||||
|
||||
if (flags & GIT_STASH_INCLUDE_UNTRACKED) {
|
||||
opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_RECURSE_UNTRACKED_DIRS;
|
||||
data.include_untracked = true;
|
||||
}
|
||||
|
||||
if (flags & GIT_STASH_INCLUDE_IGNORED) {
|
||||
opts.flags |= GIT_DIFF_INCLUDE_IGNORED;
|
||||
data.include_ignored = true;
|
||||
}
|
||||
|
||||
if (git_commit_tree(&i_tree, i_commit) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_diff_workdir_to_tree(git_index_owner(index), &opts, i_tree, &diff) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_diff_foreach(diff, &data, update_index_cb, NULL, NULL) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (build_tree_from_index(tree_out, index) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = 0;
|
||||
|
||||
cleanup:
|
||||
git_diff_list_free(diff);
|
||||
git_tree_free(i_tree);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int commit_untracked(
|
||||
git_commit **u_commit,
|
||||
git_index *index,
|
||||
git_signature *stasher,
|
||||
const char *message,
|
||||
git_commit *i_commit,
|
||||
uint32_t flags)
|
||||
{
|
||||
git_tree *u_tree = NULL;
|
||||
git_oid u_commit_oid;
|
||||
git_buf msg = GIT_BUF_INIT;
|
||||
int error = -1;
|
||||
|
||||
if (build_untracked_tree(&u_tree, index, i_commit, flags) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_buf_printf(&msg, "untracked files on %s\n", message) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_commit_create(
|
||||
&u_commit_oid,
|
||||
git_index_owner(index),
|
||||
NULL,
|
||||
stasher,
|
||||
stasher,
|
||||
NULL,
|
||||
git_buf_cstr(&msg),
|
||||
u_tree,
|
||||
0,
|
||||
NULL) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = git_commit_lookup(u_commit, git_index_owner(index), &u_commit_oid);
|
||||
|
||||
cleanup:
|
||||
git_tree_free(u_tree);
|
||||
git_buf_free(&msg);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int build_workdir_tree(
|
||||
git_tree **tree_out,
|
||||
git_index *index,
|
||||
git_commit *b_commit)
|
||||
{
|
||||
git_tree *b_tree = NULL;
|
||||
git_diff_list *diff = NULL, *diff2 = NULL;
|
||||
git_diff_options opts = {0};
|
||||
struct cb_data data = {0};
|
||||
int error = -1;
|
||||
|
||||
if (git_commit_tree(&b_tree, b_commit) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_diff_index_to_tree(git_index_owner(index), &opts, b_tree, &diff) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_diff_workdir_to_index(git_index_owner(index), &opts, &diff2) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_diff_merge(diff, diff2) < 0)
|
||||
goto cleanup;
|
||||
|
||||
data.index = index;
|
||||
data.include_changed = true;
|
||||
|
||||
if (git_diff_foreach(diff, &data, update_index_cb, NULL, NULL) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (build_tree_from_index(tree_out, index) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = 0;
|
||||
|
||||
cleanup:
|
||||
git_diff_list_free(diff);
|
||||
git_diff_list_free(diff2);
|
||||
git_tree_free(b_tree);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int commit_worktree(
|
||||
git_oid *w_commit_oid,
|
||||
git_index *index,
|
||||
git_signature *stasher,
|
||||
const char *message,
|
||||
git_commit *i_commit,
|
||||
git_commit *b_commit,
|
||||
git_commit *u_commit)
|
||||
{
|
||||
git_tree *w_tree = NULL, *i_tree = NULL;
|
||||
int error = -1;
|
||||
|
||||
const git_commit *parents[] = { NULL, NULL, NULL };
|
||||
|
||||
parents[0] = b_commit;
|
||||
parents[1] = i_commit;
|
||||
parents[2] = u_commit;
|
||||
|
||||
if (git_commit_tree(&i_tree, i_commit) < 0)
|
||||
return -1;
|
||||
|
||||
if (git_index_read_tree(index, i_tree) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (build_workdir_tree(&w_tree, index, b_commit) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_commit_create(
|
||||
w_commit_oid,
|
||||
git_index_owner(index),
|
||||
NULL,
|
||||
stasher,
|
||||
stasher,
|
||||
NULL,
|
||||
message,
|
||||
w_tree,
|
||||
u_commit ? 3 : 2, parents) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = 0;
|
||||
|
||||
cleanup:
|
||||
git_tree_free(i_tree);
|
||||
git_tree_free(w_tree);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int prepare_worktree_commit_message(
|
||||
git_buf* msg,
|
||||
const char *user_message)
|
||||
{
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
int error = -1;
|
||||
|
||||
git_buf_set(&buf, git_buf_cstr(msg), git_buf_len(msg));
|
||||
git_buf_clear(msg);
|
||||
|
||||
if (!user_message)
|
||||
git_buf_printf(msg, "WIP on %s", git_buf_cstr(&buf));
|
||||
else {
|
||||
const char *colon;
|
||||
|
||||
if ((colon = strchr(git_buf_cstr(&buf), ':')) == NULL)
|
||||
goto cleanup;
|
||||
|
||||
git_buf_puts(msg, "On ");
|
||||
git_buf_put(msg, git_buf_cstr(&buf), colon - buf.ptr);
|
||||
git_buf_printf(msg, ": %s\n", user_message);
|
||||
}
|
||||
|
||||
error = git_buf_oom(msg) || git_buf_oom(&buf) ? -1 : 0;
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&buf);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int update_reflog(
|
||||
git_oid *w_commit_oid,
|
||||
git_repository *repo,
|
||||
git_signature *stasher,
|
||||
const char *message)
|
||||
{
|
||||
git_reference *stash = NULL;
|
||||
git_reflog *reflog = NULL;
|
||||
int error;
|
||||
|
||||
if ((error = git_reference_create_oid(&stash, repo, GIT_REFS_STASH_FILE, w_commit_oid, 1)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((error = git_reflog_read(&reflog, stash)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((error = git_reflog_append(reflog, w_commit_oid, stasher, message)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((error = git_reflog_write(reflog)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = 0;
|
||||
|
||||
cleanup:
|
||||
git_reference_free(stash);
|
||||
git_reflog_free(reflog);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int is_dirty_cb(const char *path, unsigned int status, void *payload)
|
||||
{
|
||||
GIT_UNUSED(path);
|
||||
GIT_UNUSED(status);
|
||||
GIT_UNUSED(payload);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ensure_there_are_changes_to_stash(
|
||||
git_repository *repo,
|
||||
bool include_untracked_files,
|
||||
bool include_ignored_files)
|
||||
{
|
||||
int error;
|
||||
git_status_options opts;
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
|
||||
if (include_untracked_files)
|
||||
opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
|
||||
GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
|
||||
|
||||
if (include_ignored_files)
|
||||
opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED;
|
||||
|
||||
error = git_status_foreach_ext(repo, &opts, is_dirty_cb, NULL);
|
||||
|
||||
if (error == GIT_EUSER)
|
||||
return 0;
|
||||
|
||||
if (!error)
|
||||
return create_error(GIT_ENOTFOUND, "There is nothing to stash.");
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int reset_index_and_workdir(
|
||||
git_repository *repo,
|
||||
git_commit *commit,
|
||||
bool remove_untracked)
|
||||
{
|
||||
git_checkout_opts opts;
|
||||
|
||||
memset(&opts, 0, sizeof(git_checkout_opts));
|
||||
|
||||
opts.checkout_strategy =
|
||||
GIT_CHECKOUT_CREATE_MISSING | GIT_CHECKOUT_OVERWRITE_MODIFIED;
|
||||
|
||||
if (remove_untracked)
|
||||
opts.checkout_strategy |= GIT_CHECKOUT_REMOVE_UNTRACKED;
|
||||
|
||||
return git_checkout_tree(repo, (git_object *)commit, &opts);
|
||||
}
|
||||
|
||||
int git_stash_save(
|
||||
git_oid *out,
|
||||
git_repository *repo,
|
||||
git_signature *stasher,
|
||||
const char *message,
|
||||
uint32_t flags)
|
||||
{
|
||||
git_index *index = NULL;
|
||||
git_commit *b_commit = NULL, *i_commit = NULL, *u_commit = NULL;
|
||||
git_buf msg = GIT_BUF_INIT;
|
||||
int error;
|
||||
|
||||
assert(out && repo && stasher);
|
||||
|
||||
if ((error = ensure_non_bare_repository(repo)) < 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 & GIT_STASH_INCLUDE_UNTRACKED) == GIT_STASH_INCLUDE_UNTRACKED,
|
||||
(flags & GIT_STASH_INCLUDE_IGNORED) == GIT_STASH_INCLUDE_IGNORED)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = -1;
|
||||
|
||||
if (git_repository_index(&index, repo) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (commit_index(&i_commit, index, stasher, git_buf_cstr(&msg), b_commit) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((flags & GIT_STASH_INCLUDE_UNTRACKED || flags & GIT_STASH_INCLUDE_IGNORED)
|
||||
&& commit_untracked(&u_commit, index, stasher, git_buf_cstr(&msg), i_commit, flags) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (prepare_worktree_commit_message(&msg, message) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (commit_worktree(out, index, stasher, git_buf_cstr(&msg), i_commit, b_commit, u_commit) < 0)
|
||||
goto cleanup;
|
||||
|
||||
git_buf_rtrim(&msg);
|
||||
if (update_reflog(out, repo, stasher, git_buf_cstr(&msg)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (reset_index_and_workdir(
|
||||
repo,
|
||||
((flags & GIT_STASH_KEEP_INDEX) == GIT_STASH_KEEP_INDEX) ?
|
||||
i_commit : b_commit,
|
||||
(flags & GIT_STASH_INCLUDE_UNTRACKED) == GIT_STASH_INCLUDE_UNTRACKED) < 0)
|
||||
goto cleanup;
|
||||
|
||||
error = 0;
|
||||
|
||||
cleanup:
|
||||
git_buf_free(&msg);
|
||||
git_commit_free(i_commit);
|
||||
git_commit_free(b_commit);
|
||||
git_commit_free(u_commit);
|
||||
git_index_free(index);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_stash_foreach(
|
||||
git_repository *repo,
|
||||
stash_cb callback,
|
||||
void *payload)
|
||||
{
|
||||
git_reference *stash;
|
||||
git_reflog *reflog = NULL;
|
||||
int error;
|
||||
size_t i, max;
|
||||
const git_reflog_entry *entry;
|
||||
|
||||
error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE);
|
||||
if (error == GIT_ENOTFOUND)
|
||||
return 0;
|
||||
|
||||
if (error < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((error = git_reflog_read(&reflog, stash)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
max = git_reflog_entrycount(reflog);
|
||||
for (i = 0; i < max; i++) {
|
||||
entry = git_reflog_entry_byindex(reflog, max - i - 1);
|
||||
|
||||
if (callback(i,
|
||||
git_reflog_entry_msg(entry),
|
||||
git_reflog_entry_oidnew(entry),
|
||||
payload)) {
|
||||
error = GIT_EUSER;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
error = 0;
|
||||
|
||||
cleanup:
|
||||
git_reference_free(stash);
|
||||
git_reflog_free(reflog);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_stash_drop(
|
||||
git_repository *repo,
|
||||
size_t index)
|
||||
{
|
||||
git_reference *stash;
|
||||
git_reflog *reflog = NULL;
|
||||
size_t max;
|
||||
int error;
|
||||
|
||||
if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0)
|
||||
return error;
|
||||
|
||||
if ((error = git_reflog_read(&reflog, stash)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
max = git_reflog_entrycount(reflog);
|
||||
|
||||
if (index > max - 1) {
|
||||
error = GIT_ENOTFOUND;
|
||||
giterr_set(GITERR_STASH, "No stashed state at position %" PRIuZ, index);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((error = git_reflog_drop(reflog, max - index - 1, true)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if ((error = git_reflog_write(reflog)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (max == 1) {
|
||||
error = git_reference_delete(stash);
|
||||
stash = NULL;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
git_reference_free(stash);
|
||||
git_reflog_free(reflog);
|
||||
return error;
|
||||
}
|
@ -128,68 +128,3 @@ void test_object_commit_commitstagedfile__generate_predictable_object_ids(void)
|
||||
git_tree_free(tree);
|
||||
git_index_free(index);
|
||||
}
|
||||
|
||||
void test_object_commit_commitstagedfile__message_prettify(void)
|
||||
{
|
||||
char buffer[100];
|
||||
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer), "", 0) == 1);
|
||||
cl_assert_equal_s(buffer, "");
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer), "", 1) == 1);
|
||||
cl_assert_equal_s(buffer, "");
|
||||
|
||||
cl_assert_equal_i(7, git_message_prettify(buffer, sizeof(buffer), "Short", 0));
|
||||
cl_assert_equal_s("Short\n", buffer);
|
||||
cl_assert_equal_i(7, git_message_prettify(buffer, sizeof(buffer), "Short", 1));
|
||||
cl_assert_equal_s("Short\n", buffer);
|
||||
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer), "This is longer\nAnd multiline\n# with some comments still in\n", 0) > 0);
|
||||
cl_assert_equal_s(buffer, "This is longer\nAnd multiline\n# with some comments still in\n");
|
||||
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer), "This is longer\nAnd multiline\n# with some comments still in\n", 1) > 0);
|
||||
cl_assert_equal_s(buffer, "This is longer\nAnd multiline\n");
|
||||
|
||||
/* try out overflow */
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "12345678",
|
||||
0) > 0);
|
||||
cl_assert_equal_s(buffer,
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "12345678\n");
|
||||
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "12345678\n",
|
||||
0) > 0);
|
||||
cl_assert_equal_s(buffer,
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "12345678\n");
|
||||
|
||||
cl_git_fail(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "123456789",
|
||||
0));
|
||||
cl_git_fail(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "123456789\n",
|
||||
0));
|
||||
cl_git_fail(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890",
|
||||
0));
|
||||
cl_git_fail(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890""x",
|
||||
0));
|
||||
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890\n"
|
||||
"# 1234567890" "1234567890" "1234567890" "1234567890" "1234567890\n"
|
||||
"1234567890",
|
||||
1) > 0);
|
||||
|
||||
cl_assert(git_message_prettify(NULL, 0, "", 0) == 1);
|
||||
cl_assert(git_message_prettify(NULL, 0, "Short test", 0) == 12);
|
||||
cl_assert(git_message_prettify(NULL, 0, "Test\n# with\nComments", 1) == 15);
|
||||
}
|
||||
|
@ -169,3 +169,68 @@ void test_object_message__keep_comments(void)
|
||||
assert_message_prettifying("# comment\n" ttt "\n", "# comment\n" ttt "\n", 0);
|
||||
assert_message_prettifying(ttt "\n" "# comment\n" ttt "\n", ttt "\n" "# comment\n" ttt "\n", 0);
|
||||
}
|
||||
|
||||
void test_object_message__message_prettify(void)
|
||||
{
|
||||
char buffer[100];
|
||||
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer), "", 0) == 1);
|
||||
cl_assert_equal_s(buffer, "");
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer), "", 1) == 1);
|
||||
cl_assert_equal_s(buffer, "");
|
||||
|
||||
cl_assert_equal_i(7, git_message_prettify(buffer, sizeof(buffer), "Short", 0));
|
||||
cl_assert_equal_s("Short\n", buffer);
|
||||
cl_assert_equal_i(7, git_message_prettify(buffer, sizeof(buffer), "Short", 1));
|
||||
cl_assert_equal_s("Short\n", buffer);
|
||||
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer), "This is longer\nAnd multiline\n# with some comments still in\n", 0) > 0);
|
||||
cl_assert_equal_s(buffer, "This is longer\nAnd multiline\n# with some comments still in\n");
|
||||
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer), "This is longer\nAnd multiline\n# with some comments still in\n", 1) > 0);
|
||||
cl_assert_equal_s(buffer, "This is longer\nAnd multiline\n");
|
||||
|
||||
/* try out overflow */
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "12345678",
|
||||
0) > 0);
|
||||
cl_assert_equal_s(buffer,
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "12345678\n");
|
||||
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "12345678\n",
|
||||
0) > 0);
|
||||
cl_assert_equal_s(buffer,
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "12345678\n");
|
||||
|
||||
cl_git_fail(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "123456789",
|
||||
0));
|
||||
cl_git_fail(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "123456789\n",
|
||||
0));
|
||||
cl_git_fail(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890",
|
||||
0));
|
||||
cl_git_fail(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890"
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890""x",
|
||||
0));
|
||||
|
||||
cl_assert(git_message_prettify(buffer, sizeof(buffer),
|
||||
"1234567890" "1234567890" "1234567890" "1234567890" "1234567890\n"
|
||||
"# 1234567890" "1234567890" "1234567890" "1234567890" "1234567890\n"
|
||||
"1234567890",
|
||||
1) > 0);
|
||||
|
||||
cl_assert(git_message_prettify(NULL, 0, "", 0) == 1);
|
||||
cl_assert(git_message_prettify(NULL, 0, "Short test", 0) == 12);
|
||||
cl_assert(git_message_prettify(NULL, 0, "Test\n# with\nComments", 1) == 15);
|
||||
}
|
||||
|
@ -43,57 +43,48 @@ void test_refs_reflog_drop__can_drop_an_entry(void)
|
||||
|
||||
void test_refs_reflog_drop__can_drop_an_entry_and_rewrite_the_log_history(void)
|
||||
{
|
||||
const git_reflog_entry *before_previous, *before_next;
|
||||
const git_reflog_entry *after_next;
|
||||
git_oid before_next_old_oid;
|
||||
const git_reflog_entry *before_current;
|
||||
const git_reflog_entry *after_current;
|
||||
git_oid before_current_old_oid, before_current_cur_oid;
|
||||
|
||||
cl_assert(entrycount > 4);
|
||||
|
||||
before_previous = git_reflog_entry_byindex(g_reflog, 3);
|
||||
before_next = git_reflog_entry_byindex(g_reflog, 1);
|
||||
git_oid_cpy(&before_next_old_oid, &before_next->oid_old);
|
||||
before_current = git_reflog_entry_byindex(g_reflog, 2);
|
||||
git_oid_cpy(&before_current_old_oid, &before_current->oid_old);
|
||||
git_oid_cpy(&before_current_cur_oid, &before_current->oid_cur);
|
||||
|
||||
cl_git_pass(git_reflog_drop(g_reflog, 2, 1));
|
||||
cl_assert_equal_i(entrycount - 1, git_reflog_entrycount(g_reflog));
|
||||
|
||||
after_next = git_reflog_entry_byindex(g_reflog, 1);
|
||||
after_current = git_reflog_entry_byindex(g_reflog, 2);
|
||||
|
||||
cl_assert_equal_i(0, git_oid_cmp(&before_next->oid_cur, &after_next->oid_cur));
|
||||
cl_assert(git_oid_cmp(&before_next_old_oid, &after_next->oid_old) != 0);
|
||||
cl_assert_equal_i(0, git_oid_cmp(&before_previous->oid_cur, &after_next->oid_old));
|
||||
cl_assert_equal_i(0, git_oid_cmp(&before_current_old_oid, &after_current->oid_old));
|
||||
cl_assert(0 != git_oid_cmp(&before_current_cur_oid, &after_current->oid_cur));
|
||||
}
|
||||
|
||||
void test_refs_reflog_drop__can_drop_the_first_entry(void)
|
||||
void test_refs_reflog_drop__can_drop_the_oldest_entry(void)
|
||||
{
|
||||
const git_reflog_entry *entry;
|
||||
|
||||
cl_assert(entrycount > 2);
|
||||
|
||||
cl_git_pass(git_reflog_drop(g_reflog, 0, 0));
|
||||
cl_assert_equal_i(entrycount - 1, git_reflog_entrycount(g_reflog));
|
||||
}
|
||||
|
||||
void test_refs_reflog_drop__can_drop_the_last_entry(void)
|
||||
{
|
||||
const git_reflog_entry *entry;
|
||||
|
||||
cl_assert(entrycount > 2);
|
||||
|
||||
cl_git_pass(git_reflog_drop(g_reflog, entrycount - 1, 0));
|
||||
cl_assert_equal_i(entrycount - 1, git_reflog_entrycount(g_reflog));
|
||||
|
||||
entry = git_reflog_entry_byindex(g_reflog, entrycount - 2);
|
||||
entry = git_reflog_entry_byindex(g_reflog, 0);
|
||||
cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) != 0);
|
||||
}
|
||||
|
||||
void test_refs_reflog_drop__can_drop_the_last_entry_and_rewrite_the_log_history(void)
|
||||
void test_refs_reflog_drop__can_drop_the_oldest_entry_and_rewrite_the_log_history(void)
|
||||
{
|
||||
const git_reflog_entry *entry;
|
||||
|
||||
cl_assert(entrycount > 2);
|
||||
|
||||
cl_git_pass(git_reflog_drop(g_reflog, entrycount - 1, 1));
|
||||
cl_git_pass(git_reflog_drop(g_reflog, 0, 1));
|
||||
cl_assert_equal_i(entrycount - 1, git_reflog_entrycount(g_reflog));
|
||||
|
||||
entry = git_reflog_entry_byindex(g_reflog, entrycount - 2);
|
||||
entry = git_reflog_entry_byindex(g_reflog, 0);
|
||||
cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) == 0);
|
||||
}
|
||||
|
||||
|
126
tests-clar/stash/drop.c
Normal file
126
tests-clar/stash/drop.c
Normal file
@ -0,0 +1,126 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "fileops.h"
|
||||
#include "stash_helpers.h"
|
||||
|
||||
static git_repository *repo;
|
||||
static git_signature *signature;
|
||||
|
||||
void test_stash_drop__initialize(void)
|
||||
{
|
||||
cl_git_pass(git_repository_init(&repo, "stash", 0));
|
||||
cl_git_pass(git_signature_new(&signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */
|
||||
}
|
||||
|
||||
void test_stash_drop__cleanup(void)
|
||||
{
|
||||
git_signature_free(signature);
|
||||
git_repository_free(repo);
|
||||
cl_git_pass(git_futils_rmdir_r("stash", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
|
||||
}
|
||||
|
||||
void test_stash_drop__cannot_drop_from_an_empty_stash(void)
|
||||
{
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_stash_drop(repo, 0));
|
||||
}
|
||||
|
||||
static void push_three_states(void)
|
||||
{
|
||||
git_oid oid;
|
||||
git_index *index;
|
||||
|
||||
cl_git_mkfile("stash/zero.txt", "content\n");
|
||||
cl_git_pass(git_repository_index(&index, repo));
|
||||
cl_git_pass(git_index_add(index, "zero.txt", 0));
|
||||
commit_staged_files(&oid, index, signature);
|
||||
|
||||
cl_git_mkfile("stash/one.txt", "content\n");
|
||||
cl_git_pass(git_stash_save(&oid, repo, signature, "First", GIT_STASH_INCLUDE_UNTRACKED));
|
||||
|
||||
cl_git_mkfile("stash/two.txt", "content\n");
|
||||
cl_git_pass(git_stash_save(&oid, repo, signature, "Second", GIT_STASH_INCLUDE_UNTRACKED));
|
||||
|
||||
cl_git_mkfile("stash/three.txt", "content\n");
|
||||
cl_git_pass(git_stash_save(&oid, repo, signature, "Third", GIT_STASH_INCLUDE_UNTRACKED));
|
||||
|
||||
git_index_free(index);
|
||||
}
|
||||
|
||||
void test_stash_drop__cannot_drop_a_non_existing_stashed_state(void)
|
||||
{
|
||||
push_three_states();
|
||||
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_stash_drop(repo, 666));
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_stash_drop(repo, 42));
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_stash_drop(repo, 3));
|
||||
}
|
||||
|
||||
void test_stash_drop__can_purge_the_stash_from_the_top(void)
|
||||
{
|
||||
push_three_states();
|
||||
|
||||
cl_git_pass(git_stash_drop(repo, 0));
|
||||
cl_git_pass(git_stash_drop(repo, 0));
|
||||
cl_git_pass(git_stash_drop(repo, 0));
|
||||
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_stash_drop(repo, 0));
|
||||
}
|
||||
|
||||
void test_stash_drop__can_purge_the_stash_from_the_bottom(void)
|
||||
{
|
||||
push_three_states();
|
||||
|
||||
cl_git_pass(git_stash_drop(repo, 2));
|
||||
cl_git_pass(git_stash_drop(repo, 1));
|
||||
cl_git_pass(git_stash_drop(repo, 0));
|
||||
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_stash_drop(repo, 0));
|
||||
}
|
||||
|
||||
void test_stash_drop__dropping_an_entry_rewrites_reflog_history(void)
|
||||
{
|
||||
git_reference *stash;
|
||||
git_reflog *reflog;
|
||||
const git_reflog_entry *entry;
|
||||
git_oid oid;
|
||||
size_t count;
|
||||
|
||||
push_three_states();
|
||||
|
||||
cl_git_pass(git_reference_lookup(&stash, repo, "refs/stash"));
|
||||
|
||||
cl_git_pass(git_reflog_read(&reflog, stash));
|
||||
entry = git_reflog_entry_byindex(reflog, 1);
|
||||
|
||||
git_oid_cpy(&oid, git_reflog_entry_oidold(entry));
|
||||
count = git_reflog_entrycount(reflog);
|
||||
|
||||
git_reflog_free(reflog);
|
||||
|
||||
cl_git_pass(git_stash_drop(repo, 1));
|
||||
|
||||
cl_git_pass(git_reflog_read(&reflog, stash));
|
||||
entry = git_reflog_entry_byindex(reflog, 1);
|
||||
|
||||
cl_assert_equal_i(0, git_oid_cmp(&oid, git_reflog_entry_oidold(entry)));
|
||||
cl_assert_equal_i(count - 1, git_reflog_entrycount(reflog));
|
||||
|
||||
git_reflog_free(reflog);
|
||||
|
||||
git_reference_free(stash);
|
||||
}
|
||||
|
||||
void test_stash_drop__dropping_the_last_entry_removes_the_stash(void)
|
||||
{
|
||||
git_reference *stash;
|
||||
|
||||
push_three_states();
|
||||
|
||||
cl_git_pass(git_reference_lookup(&stash, repo, "refs/stash"));
|
||||
git_reference_free(stash);
|
||||
|
||||
cl_git_pass(git_stash_drop(repo, 0));
|
||||
cl_git_pass(git_stash_drop(repo, 0));
|
||||
cl_git_pass(git_stash_drop(repo, 0));
|
||||
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&stash, repo, "refs/stash"));
|
||||
}
|
119
tests-clar/stash/foreach.c
Normal file
119
tests-clar/stash/foreach.c
Normal file
@ -0,0 +1,119 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "fileops.h"
|
||||
#include "stash_helpers.h"
|
||||
|
||||
struct callback_data
|
||||
{
|
||||
char **oids;
|
||||
int invokes;
|
||||
};
|
||||
|
||||
static git_repository *repo;
|
||||
static git_signature *signature;
|
||||
static git_oid stash_tip_oid;
|
||||
struct callback_data data;
|
||||
|
||||
#define REPO_NAME "stash"
|
||||
|
||||
void test_stash_foreach__initialize(void)
|
||||
{
|
||||
cl_git_pass(git_signature_new(
|
||||
&signature,
|
||||
"nulltoken",
|
||||
"emeric.fermas@gmail.com",
|
||||
1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */
|
||||
|
||||
memset(&data, 0, sizeof(struct callback_data));
|
||||
}
|
||||
|
||||
void test_stash_foreach__cleanup(void)
|
||||
{
|
||||
git_signature_free(signature);
|
||||
git_repository_free(repo);
|
||||
cl_git_pass(git_futils_rmdir_r(REPO_NAME, NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
|
||||
}
|
||||
|
||||
static int callback_cb(
|
||||
size_t index,
|
||||
const char* message,
|
||||
const git_oid *stash_oid,
|
||||
void *payload)
|
||||
{
|
||||
int i = 0;
|
||||
bool found = false;
|
||||
struct callback_data *data = (struct callback_data *)payload;
|
||||
|
||||
cl_assert_equal_i(0, git_oid_streq(stash_oid, data->oids[data->invokes++]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_stash_foreach__enumerating_a_empty_repository_doesnt_fail(void)
|
||||
{
|
||||
char *oids[] = { NULL };
|
||||
|
||||
data.oids = oids;
|
||||
|
||||
cl_git_pass(git_repository_init(&repo, REPO_NAME, 0));
|
||||
|
||||
cl_git_pass(git_stash_foreach(repo, callback_cb, &data));
|
||||
|
||||
cl_assert_equal_i(0, data.invokes);
|
||||
}
|
||||
|
||||
void test_stash_foreach__can_enumerate_a_repository(void)
|
||||
{
|
||||
char *oids_default[] = {
|
||||
"1d91c842a7cdfc25872b3a763e5c31add8816c25", NULL };
|
||||
|
||||
char *oids_untracked[] = {
|
||||
"7f89a8b15c878809c5c54d1ff8f8c9674154017b",
|
||||
"1d91c842a7cdfc25872b3a763e5c31add8816c25", NULL };
|
||||
|
||||
char *oids_ignored[] = {
|
||||
"c95599a8fef20a7e57582c6727b1a0d02e0a5828",
|
||||
"7f89a8b15c878809c5c54d1ff8f8c9674154017b",
|
||||
"1d91c842a7cdfc25872b3a763e5c31add8816c25", NULL };
|
||||
|
||||
cl_git_pass(git_repository_init(&repo, REPO_NAME, 0));
|
||||
|
||||
setup_stash(repo, signature);
|
||||
|
||||
cl_git_pass(git_stash_save(
|
||||
&stash_tip_oid,
|
||||
repo,
|
||||
signature,
|
||||
NULL,
|
||||
GIT_STASH_DEFAULT));
|
||||
|
||||
data.oids = oids_default;
|
||||
|
||||
cl_git_pass(git_stash_foreach(repo, callback_cb, &data));
|
||||
cl_assert_equal_i(1, data.invokes);
|
||||
|
||||
data.oids = oids_untracked;
|
||||
data.invokes = 0;
|
||||
|
||||
cl_git_pass(git_stash_save(
|
||||
&stash_tip_oid,
|
||||
repo,
|
||||
signature,
|
||||
NULL,
|
||||
GIT_STASH_INCLUDE_UNTRACKED));
|
||||
|
||||
cl_git_pass(git_stash_foreach(repo, callback_cb, &data));
|
||||
cl_assert_equal_i(2, data.invokes);
|
||||
|
||||
data.oids = oids_ignored;
|
||||
data.invokes = 0;
|
||||
|
||||
cl_git_pass(git_stash_save(
|
||||
&stash_tip_oid,
|
||||
repo,
|
||||
signature,
|
||||
NULL,
|
||||
GIT_STASH_INCLUDE_IGNORED));
|
||||
|
||||
cl_git_pass(git_stash_foreach(repo, callback_cb, &data));
|
||||
cl_assert_equal_i(3, data.invokes);
|
||||
}
|
370
tests-clar/stash/save.c
Normal file
370
tests-clar/stash/save.c
Normal file
@ -0,0 +1,370 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "fileops.h"
|
||||
#include "stash_helpers.h"
|
||||
|
||||
static git_repository *repo;
|
||||
static git_signature *signature;
|
||||
static git_oid stash_tip_oid;
|
||||
|
||||
/*
|
||||
* Friendly reminder, in order to ease the reading of the following tests:
|
||||
*
|
||||
* "stash" points to the worktree commit
|
||||
* "stash^1" points to the base commit (HEAD when the stash was created)
|
||||
* "stash^2" points to the index commit
|
||||
* "stash^3" points to the untracked commit
|
||||
*/
|
||||
|
||||
void test_stash_save__initialize(void)
|
||||
{
|
||||
cl_git_pass(git_repository_init(&repo, "stash", 0));
|
||||
cl_git_pass(git_signature_new(&signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */
|
||||
|
||||
setup_stash(repo, signature);
|
||||
}
|
||||
|
||||
void test_stash_save__cleanup(void)
|
||||
{
|
||||
git_signature_free(signature);
|
||||
git_repository_free(repo);
|
||||
cl_git_pass(git_futils_rmdir_r("stash", NULL, GIT_DIRREMOVAL_FILES_AND_DIRS));
|
||||
}
|
||||
|
||||
static void assert_object_oid(const char* revision, const char* expected_oid, git_otype type)
|
||||
{
|
||||
git_object *object;
|
||||
int result;
|
||||
|
||||
result = git_revparse_single(&object, repo, revision);
|
||||
|
||||
if (!expected_oid) {
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, result);
|
||||
return;
|
||||
} else
|
||||
cl_assert_equal_i(0, result);
|
||||
|
||||
cl_assert_equal_i(type, git_object_type(object));
|
||||
cl_git_pass(git_oid_streq(git_object_id(object), expected_oid));
|
||||
|
||||
git_object_free(object);
|
||||
}
|
||||
|
||||
static void assert_blob_oid(const char* revision, const char* expected_oid)
|
||||
{
|
||||
assert_object_oid(revision, expected_oid, GIT_OBJ_BLOB);
|
||||
}
|
||||
|
||||
void test_stash_save__does_not_keep_index_by_default(void)
|
||||
{
|
||||
/*
|
||||
$ git stash
|
||||
|
||||
$ git show refs/stash:what
|
||||
see you later
|
||||
|
||||
$ git show refs/stash:how
|
||||
not so small and
|
||||
|
||||
$ git show refs/stash:who
|
||||
funky world
|
||||
|
||||
$ git show refs/stash:when
|
||||
fatal: Path 'when' exists on disk, but not in 'stash'.
|
||||
|
||||
$ git show refs/stash^2:what
|
||||
goodbye
|
||||
|
||||
$ git show refs/stash^2:how
|
||||
not so small and
|
||||
|
||||
$ git show refs/stash^2:who
|
||||
world
|
||||
|
||||
$ git show refs/stash^2:when
|
||||
fatal: Path 'when' exists on disk, but not in 'stash^2'.
|
||||
|
||||
$ git status --short
|
||||
?? when
|
||||
|
||||
*/
|
||||
unsigned int status;
|
||||
|
||||
cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT));
|
||||
cl_git_pass(git_status_file(&status, repo, "when"));
|
||||
|
||||
assert_blob_oid("refs/stash:what", "bc99dc98b3eba0e9157e94769cd4d49cb49de449"); /* see you later */
|
||||
assert_blob_oid("refs/stash:how", "e6d64adb2c7f3eb8feb493b556cc8070dca379a3"); /* not so small and */
|
||||
assert_blob_oid("refs/stash:who", "a0400d4954659306a976567af43125a0b1aa8595"); /* funky world */
|
||||
assert_blob_oid("refs/stash:when", NULL);
|
||||
assert_blob_oid("refs/stash:just.ignore", NULL);
|
||||
|
||||
assert_blob_oid("refs/stash^2:what", "dd7e1c6f0fefe118f0b63d9f10908c460aa317a6"); /* goodbye */
|
||||
assert_blob_oid("refs/stash^2:how", "e6d64adb2c7f3eb8feb493b556cc8070dca379a3"); /* not so small and */
|
||||
assert_blob_oid("refs/stash^2:who", "cc628ccd10742baea8241c5924df992b5c019f71"); /* world */
|
||||
assert_blob_oid("refs/stash^2:when", NULL);
|
||||
assert_blob_oid("refs/stash^2:just.ignore", NULL);
|
||||
|
||||
assert_blob_oid("refs/stash^3", NULL);
|
||||
|
||||
cl_assert_equal_i(GIT_STATUS_WT_NEW, status);
|
||||
}
|
||||
|
||||
static void assert_status(
|
||||
const char *path,
|
||||
int status_flags)
|
||||
{
|
||||
unsigned int status;
|
||||
int error;
|
||||
|
||||
error = git_status_file(&status, repo, path);
|
||||
|
||||
if (status_flags < 0) {
|
||||
cl_assert_equal_i(status_flags, error);
|
||||
return;
|
||||
}
|
||||
|
||||
cl_assert_equal_i(0, error);
|
||||
cl_assert_equal_i((unsigned int)status_flags, status);
|
||||
}
|
||||
|
||||
void test_stash_save__can_keep_index(void)
|
||||
{
|
||||
cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_KEEP_INDEX));
|
||||
|
||||
assert_status("what", GIT_STATUS_INDEX_MODIFIED);
|
||||
assert_status("how", GIT_STATUS_INDEX_MODIFIED);
|
||||
assert_status("who", GIT_STATUS_CURRENT);
|
||||
assert_status("when", GIT_STATUS_WT_NEW);
|
||||
assert_status("just.ignore", GIT_STATUS_IGNORED);
|
||||
}
|
||||
|
||||
static void assert_commit_message_contains(const char *revision, const char *fragment)
|
||||
{
|
||||
git_commit *commit;
|
||||
|
||||
cl_git_pass(git_revparse_single(((git_object **)&commit), repo, revision));
|
||||
|
||||
cl_assert(strstr(git_commit_message(commit), fragment) != NULL);
|
||||
|
||||
git_commit_free(commit);
|
||||
}
|
||||
|
||||
void test_stash_save__can_include_untracked_files(void)
|
||||
{
|
||||
cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED));
|
||||
|
||||
assert_commit_message_contains("refs/stash^3", "untracked files on master: ");
|
||||
|
||||
assert_blob_oid("refs/stash^3:what", NULL);
|
||||
assert_blob_oid("refs/stash^3:how", NULL);
|
||||
assert_blob_oid("refs/stash^3:who", NULL);
|
||||
assert_blob_oid("refs/stash^3:when", "b6ed15e81e2593d7bb6265eb4a991d29dc3e628b");
|
||||
assert_blob_oid("refs/stash^3:just.ignore", NULL);
|
||||
}
|
||||
|
||||
void test_stash_save__can_include_untracked_and_ignored_files(void)
|
||||
{
|
||||
cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED | GIT_STASH_INCLUDE_IGNORED));
|
||||
|
||||
assert_commit_message_contains("refs/stash^3", "untracked files on master: ");
|
||||
|
||||
assert_blob_oid("refs/stash^3:what", NULL);
|
||||
assert_blob_oid("refs/stash^3:how", NULL);
|
||||
assert_blob_oid("refs/stash^3:who", NULL);
|
||||
assert_blob_oid("refs/stash^3:when", "b6ed15e81e2593d7bb6265eb4a991d29dc3e628b");
|
||||
assert_blob_oid("refs/stash^3:just.ignore", "78925fb1236b98b37a35e9723033e627f97aa88b");
|
||||
}
|
||||
|
||||
#define MESSAGE "Look Ma! I'm on TV!"
|
||||
void test_stash_save__can_accept_a_message(void)
|
||||
{
|
||||
cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, MESSAGE, GIT_STASH_DEFAULT));
|
||||
|
||||
assert_commit_message_contains("refs/stash^2", "index on master: ");
|
||||
assert_commit_message_contains("refs/stash", "On master: " MESSAGE);
|
||||
}
|
||||
|
||||
void test_stash_save__cannot_stash_against_an_unborn_branch(void)
|
||||
{
|
||||
git_reference *head;
|
||||
|
||||
cl_git_pass(git_reference_lookup(&head, repo, "HEAD"));
|
||||
cl_git_pass(git_reference_set_target(head, "refs/heads/unborn"));
|
||||
|
||||
cl_assert_equal_i(GIT_EORPHANEDHEAD,
|
||||
git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT));
|
||||
|
||||
git_reference_free(head);
|
||||
}
|
||||
|
||||
void test_stash_save__cannot_stash_against_a_bare_repository(void)
|
||||
{
|
||||
git_repository *local;
|
||||
|
||||
cl_git_pass(git_repository_init(&local, "sorry-it-is-a-non-bare-only-party", 1));
|
||||
|
||||
cl_assert_equal_i(GIT_EBAREREPO,
|
||||
git_stash_save(&stash_tip_oid, local, signature, NULL, GIT_STASH_DEFAULT));
|
||||
|
||||
git_repository_free(local);
|
||||
}
|
||||
|
||||
void test_stash_save__can_stash_against_a_detached_head(void)
|
||||
{
|
||||
git_repository_detach_head(repo);
|
||||
|
||||
cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT));
|
||||
|
||||
assert_commit_message_contains("refs/stash^2", "index on (no branch): ");
|
||||
assert_commit_message_contains("refs/stash", "WIP on (no branch): ");
|
||||
}
|
||||
|
||||
void test_stash_save__stashing_updates_the_reflog(void)
|
||||
{
|
||||
char *sha;
|
||||
|
||||
assert_object_oid("refs/stash@{0}", NULL, GIT_OBJ_COMMIT);
|
||||
|
||||
cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT));
|
||||
|
||||
sha = git_oid_allocfmt(&stash_tip_oid);
|
||||
|
||||
assert_object_oid("refs/stash@{0}", sha, GIT_OBJ_COMMIT);
|
||||
assert_object_oid("refs/stash@{1}", NULL, GIT_OBJ_COMMIT);
|
||||
|
||||
git__free(sha);
|
||||
}
|
||||
|
||||
void test_stash_save__cannot_stash_when_there_are_no_local_change(void)
|
||||
{
|
||||
git_index *index;
|
||||
git_oid commit_oid, stash_tip_oid;
|
||||
|
||||
cl_git_pass(git_repository_index(&index, repo));
|
||||
|
||||
/*
|
||||
* 'what' and 'who' are being committed.
|
||||
* 'when' remain untracked.
|
||||
*/
|
||||
git_index_add(index, "what", 0);
|
||||
git_index_add(index, "who", 0);
|
||||
cl_git_pass(git_index_write(index));
|
||||
commit_staged_files(&commit_oid, index, signature);
|
||||
git_index_free(index);
|
||||
|
||||
cl_assert_equal_i(GIT_ENOTFOUND,
|
||||
git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT));
|
||||
|
||||
p_unlink("stash/when");
|
||||
cl_assert_equal_i(GIT_ENOTFOUND,
|
||||
git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED));
|
||||
}
|
||||
|
||||
void test_stash_save__can_stage_normal_then_stage_untracked(void)
|
||||
{
|
||||
/*
|
||||
* $ git ls-tree stash@{1}^0
|
||||
* 100644 blob ac4d88de61733173d9959e4b77c69b9f17a00980 .gitignore
|
||||
* 100644 blob e6d64adb2c7f3eb8feb493b556cc8070dca379a3 how
|
||||
* 100644 blob bc99dc98b3eba0e9157e94769cd4d49cb49de449 what
|
||||
* 100644 blob a0400d4954659306a976567af43125a0b1aa8595 who
|
||||
*
|
||||
* $ git ls-tree stash@{1}^1
|
||||
* 100644 blob ac4d88de61733173d9959e4b77c69b9f17a00980 .gitignore
|
||||
* 100644 blob ac790413e2d7a26c3767e78c57bb28716686eebc how
|
||||
* 100644 blob ce013625030ba8dba906f756967f9e9ca394464a what
|
||||
* 100644 blob cc628ccd10742baea8241c5924df992b5c019f71 who
|
||||
*
|
||||
* $ git ls-tree stash@{1}^2
|
||||
* 100644 blob ac4d88de61733173d9959e4b77c69b9f17a00980 .gitignore
|
||||
* 100644 blob e6d64adb2c7f3eb8feb493b556cc8070dca379a3 how
|
||||
* 100644 blob dd7e1c6f0fefe118f0b63d9f10908c460aa317a6 what
|
||||
* 100644 blob cc628ccd10742baea8241c5924df992b5c019f71 who
|
||||
*
|
||||
* $ git ls-tree stash@{1}^3
|
||||
* fatal: Not a valid object name stash@{1}^3
|
||||
*
|
||||
* $ git ls-tree stash@{0}^0
|
||||
* 100644 blob ac4d88de61733173d9959e4b77c69b9f17a00980 .gitignore
|
||||
* 100644 blob ac790413e2d7a26c3767e78c57bb28716686eebc how
|
||||
* 100644 blob ce013625030ba8dba906f756967f9e9ca394464a what
|
||||
* 100644 blob cc628ccd10742baea8241c5924df992b5c019f71 who
|
||||
*
|
||||
* $ git ls-tree stash@{0}^1
|
||||
* 100644 blob ac4d88de61733173d9959e4b77c69b9f17a00980 .gitignore
|
||||
* 100644 blob ac790413e2d7a26c3767e78c57bb28716686eebc how
|
||||
* 100644 blob ce013625030ba8dba906f756967f9e9ca394464a what
|
||||
* 100644 blob cc628ccd10742baea8241c5924df992b5c019f71 who
|
||||
*
|
||||
* $ git ls-tree stash@{0}^2
|
||||
* 100644 blob ac4d88de61733173d9959e4b77c69b9f17a00980 .gitignore
|
||||
* 100644 blob ac790413e2d7a26c3767e78c57bb28716686eebc how
|
||||
* 100644 blob ce013625030ba8dba906f756967f9e9ca394464a what
|
||||
* 100644 blob cc628ccd10742baea8241c5924df992b5c019f71 who
|
||||
*
|
||||
* $ git ls-tree stash@{0}^3
|
||||
* 100644 blob b6ed15e81e2593d7bb6265eb4a991d29dc3e628b when
|
||||
*/
|
||||
|
||||
assert_status("what", GIT_STATUS_WT_MODIFIED | GIT_STATUS_INDEX_MODIFIED);
|
||||
assert_status("how", GIT_STATUS_INDEX_MODIFIED);
|
||||
assert_status("who", GIT_STATUS_WT_MODIFIED);
|
||||
assert_status("when", GIT_STATUS_WT_NEW);
|
||||
assert_status("just.ignore", GIT_STATUS_IGNORED);
|
||||
|
||||
cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_DEFAULT));
|
||||
assert_status("what", GIT_STATUS_CURRENT);
|
||||
assert_status("how", GIT_STATUS_CURRENT);
|
||||
assert_status("who", GIT_STATUS_CURRENT);
|
||||
assert_status("when", GIT_STATUS_WT_NEW);
|
||||
assert_status("just.ignore", GIT_STATUS_IGNORED);
|
||||
|
||||
cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED));
|
||||
assert_status("what", GIT_STATUS_CURRENT);
|
||||
assert_status("how", GIT_STATUS_CURRENT);
|
||||
assert_status("who", GIT_STATUS_CURRENT);
|
||||
assert_status("when", GIT_ENOTFOUND);
|
||||
assert_status("just.ignore", GIT_STATUS_IGNORED);
|
||||
|
||||
|
||||
assert_blob_oid("stash@{1}^0:what", "bc99dc98b3eba0e9157e94769cd4d49cb49de449"); /* see you later */
|
||||
assert_blob_oid("stash@{1}^0:how", "e6d64adb2c7f3eb8feb493b556cc8070dca379a3"); /* not so small and */
|
||||
assert_blob_oid("stash@{1}^0:who", "a0400d4954659306a976567af43125a0b1aa8595"); /* funky world */
|
||||
assert_blob_oid("stash@{1}^0:when", NULL);
|
||||
|
||||
assert_blob_oid("stash@{1}^2:what", "dd7e1c6f0fefe118f0b63d9f10908c460aa317a6"); /* goodbye */
|
||||
assert_blob_oid("stash@{1}^2:how", "e6d64adb2c7f3eb8feb493b556cc8070dca379a3"); /* not so small and */
|
||||
assert_blob_oid("stash@{1}^2:who", "cc628ccd10742baea8241c5924df992b5c019f71"); /* world */
|
||||
assert_blob_oid("stash@{1}^2:when", NULL);
|
||||
|
||||
assert_object_oid("stash@{1}^3", NULL, GIT_OBJ_COMMIT);
|
||||
|
||||
assert_blob_oid("stash@{0}^0:what", "ce013625030ba8dba906f756967f9e9ca394464a"); /* hello */
|
||||
assert_blob_oid("stash@{0}^0:how", "ac790413e2d7a26c3767e78c57bb28716686eebc"); /* small */
|
||||
assert_blob_oid("stash@{0}^0:who", "cc628ccd10742baea8241c5924df992b5c019f71"); /* world */
|
||||
assert_blob_oid("stash@{0}^0:when", NULL);
|
||||
|
||||
assert_blob_oid("stash@{0}^2:what", "ce013625030ba8dba906f756967f9e9ca394464a"); /* hello */
|
||||
assert_blob_oid("stash@{0}^2:how", "ac790413e2d7a26c3767e78c57bb28716686eebc"); /* small */
|
||||
assert_blob_oid("stash@{0}^2:who", "cc628ccd10742baea8241c5924df992b5c019f71"); /* world */
|
||||
assert_blob_oid("stash@{0}^2:when", NULL);
|
||||
|
||||
assert_blob_oid("stash@{0}^3:when", "b6ed15e81e2593d7bb6265eb4a991d29dc3e628b"); /* now */
|
||||
}
|
||||
|
||||
#define EMPTY_TREE "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
|
||||
|
||||
void test_stash_save__including_untracked_without_any_untracked_file_creates_an_empty_tree(void)
|
||||
{
|
||||
p_unlink("stash/when");
|
||||
|
||||
assert_status("what", GIT_STATUS_WT_MODIFIED | GIT_STATUS_INDEX_MODIFIED);
|
||||
assert_status("how", GIT_STATUS_INDEX_MODIFIED);
|
||||
assert_status("who", GIT_STATUS_WT_MODIFIED);
|
||||
assert_status("when", GIT_ENOTFOUND);
|
||||
assert_status("just.ignore", GIT_STATUS_IGNORED);
|
||||
|
||||
cl_git_pass(git_stash_save(&stash_tip_oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED));
|
||||
|
||||
assert_object_oid("stash^3^{tree}", EMPTY_TREE, GIT_OBJ_TREE);
|
||||
}
|
66
tests-clar/stash/stash_helpers.c
Normal file
66
tests-clar/stash/stash_helpers.c
Normal file
@ -0,0 +1,66 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "fileops.h"
|
||||
|
||||
void commit_staged_files(
|
||||
git_oid *commit_oid,
|
||||
git_index *index,
|
||||
git_signature *signature)
|
||||
{
|
||||
git_tree *tree;
|
||||
git_oid tree_oid;
|
||||
git_repository *repo;
|
||||
|
||||
repo = git_index_owner(index);
|
||||
|
||||
cl_git_pass(git_tree_create_fromindex(&tree_oid, index));
|
||||
|
||||
cl_git_pass(git_tree_lookup(&tree, repo, &tree_oid));
|
||||
cl_git_pass(git_commit_create_v(
|
||||
commit_oid,
|
||||
repo,
|
||||
"HEAD",
|
||||
signature,
|
||||
signature,
|
||||
NULL,
|
||||
"Initial commit",
|
||||
tree,
|
||||
0));
|
||||
|
||||
git_tree_free(tree);
|
||||
}
|
||||
|
||||
void setup_stash(git_repository *repo, git_signature *signature)
|
||||
{
|
||||
git_oid commit_oid;
|
||||
git_index *index;
|
||||
|
||||
cl_git_pass(git_repository_index(&index, repo));
|
||||
|
||||
cl_git_mkfile("stash/what", "hello\n"); /* ce013625030ba8dba906f756967f9e9ca394464a */
|
||||
cl_git_mkfile("stash/how", "small\n"); /* ac790413e2d7a26c3767e78c57bb28716686eebc */
|
||||
cl_git_mkfile("stash/who", "world\n"); /* cc628ccd10742baea8241c5924df992b5c019f71 */
|
||||
cl_git_mkfile("stash/when", "now\n"); /* b6ed15e81e2593d7bb6265eb4a991d29dc3e628b */
|
||||
cl_git_mkfile("stash/just.ignore", "me\n"); /* 78925fb1236b98b37a35e9723033e627f97aa88b */
|
||||
|
||||
cl_git_mkfile("stash/.gitignore", "*.ignore\n");
|
||||
|
||||
cl_git_pass(git_index_add(index, "what", 0));
|
||||
cl_git_pass(git_index_add(index, "how", 0));
|
||||
cl_git_pass(git_index_add(index, "who", 0));
|
||||
cl_git_pass(git_index_add(index, ".gitignore", 0));
|
||||
cl_git_pass(git_index_write(index));
|
||||
|
||||
commit_staged_files(&commit_oid, index, signature);
|
||||
|
||||
cl_git_rewritefile("stash/what", "goodbye\n"); /* dd7e1c6f0fefe118f0b63d9f10908c460aa317a6 */
|
||||
cl_git_rewritefile("stash/how", "not so small and\n"); /* e6d64adb2c7f3eb8feb493b556cc8070dca379a3 */
|
||||
cl_git_rewritefile("stash/who", "funky world\n"); /* a0400d4954659306a976567af43125a0b1aa8595 */
|
||||
|
||||
cl_git_pass(git_index_add(index, "what", 0));
|
||||
cl_git_pass(git_index_add(index, "how", 0));
|
||||
cl_git_pass(git_index_write(index));
|
||||
|
||||
cl_git_rewritefile("stash/what", "see you later\n"); /* bc99dc98b3eba0e9157e94769cd4d49cb49de449 */
|
||||
|
||||
git_index_free(index);
|
||||
}
|
8
tests-clar/stash/stash_helpers.h
Normal file
8
tests-clar/stash/stash_helpers.h
Normal file
@ -0,0 +1,8 @@
|
||||
void setup_stash(
|
||||
git_repository *repo,
|
||||
git_signature *signature);
|
||||
|
||||
void commit_staged_files(
|
||||
git_oid *commit_oid,
|
||||
git_index *index,
|
||||
git_signature *signature);
|
Loading…
Reference in New Issue
Block a user