GITERR_CALLBACK,
GITERR_CHERRYPICK,
GITERR_DESCRIBE,
+ GITERR_REBASE,
} git_error_t;
/**
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * 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_rebase_h__
+#define INCLUDE_git_rebase_h__
+
+#include "common.h"
+#include "types.h"
+#include "oid.h"
+
+/**
+ * @file git2/rebase.h
+ * @brief Git rebase routines
+ * @defgroup git_rebase Git merge routines
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+typedef struct {
+ unsigned int version;
+
+ /**
+ * Provide a quiet rebase experience; unused by libgit2 but provided for
+ * interoperability with other clients.
+ */
+ int quiet;
+} git_rebase_options;
+
+#define GIT_REBASE_OPTIONS_VERSION 1
+#define GIT_REBASE_OPTIONS_INIT {GIT_REBASE_OPTIONS_VERSION}
+
+/**
+ * Initializes a `git_rebase_options` with default values. Equivalent to
+ * creating an instance with GIT_REBASE_OPTIONS_INIT.
+ *
+ * @param opts the `git_rebase_options` instance to initialize.
+ * @param version the version of the struct; you should pass
+ * `GIT_REBASE_OPTIONS_VERSION` here.
+ * @return Zero on success; -1 on failure.
+ */
+GIT_EXTERN(int) git_rebase_init_options(
+ git_rebase_options *opts,
+ unsigned int version);
+
+/**
+ * Sets up a rebase operation to rebase the changes in ours relative to
+ * upstream onto another branch.
+ *
+ * @param repo The repository to perform the rebase
+ * @param branch The terminal commit to rebase
+ * @param upstream The commit to begin rebasing from, or NULL to rebase all
+ * reachable commits
+ * @param onto The branch to rebase onto, or NULL to rebase onto the given
+ * upstream
+ * @param signature The signature of the rebaser
+ * @param opts Options to specify how rebase is performed
+ * @return Zero on success; -1 on failure.
+ */
+GIT_EXTERN(int) git_rebase(
+ git_repository *repo,
+ const git_merge_head *branch,
+ const git_merge_head *upstream,
+ const git_merge_head *onto,
+ const git_signature *signature,
+ const git_rebase_options *opts);
+
+/** @} */
+GIT_END_DECL
+#endif
/* Merge setup / cleanup */
-static int write_orig_head(
- git_repository *repo,
- const git_merge_head *our_head)
-{
- git_filebuf file = GIT_FILEBUF_INIT;
- git_buf file_path = GIT_BUF_INIT;
- int error = 0;
-
- assert(repo && our_head);
-
- if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 &&
- (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 &&
- (error = git_filebuf_printf(&file, "%s\n", our_head->oid_str)) == 0)
- error = git_filebuf_commit(&file);
-
- if (error < 0)
- git_filebuf_cleanup(&file);
-
- git_buf_free(&file_path);
-
- return error;
-}
-
static int write_merge_head(
git_repository *repo,
const git_merge_head *heads[],
assert (repo && our_head && heads);
- if ((error = write_orig_head(repo, our_head)) == 0 &&
+ if ((error = git_repository__set_orig_head(repo, &our_head->oid)) == 0 &&
(error = write_merge_head(repo, heads, heads_len)) == 0 &&
(error = write_merge_mode(repo)) == 0) {
error = write_merge_msg(repo, heads, heads_len);
--- /dev/null
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * 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 "buffer.h"
+#include "repository.h"
+#include "posix.h"
+#include "filebuf.h"
+#include "merge.h"
+#include "array.h"
+
+#include <git2/types.h>
+#include <git2/rebase.h>
+#include <git2/commit.h>
+#include <git2/reset.h>
+#include <git2/revwalk.h>
+
+#define REBASE_APPLY_DIR "rebase-apply"
+#define REBASE_MERGE_DIR "rebase-merge"
+
+#define HEAD_NAME_FILE "head-name"
+#define ORIG_HEAD_FILE "orig-head"
+#define HEAD_FILE "head"
+#define ONTO_FILE "onto"
+#define ONTO_NAME_FILE "onto_name"
+#define QUIET_FILE "quiet"
+
+#define MSGNUM_FILE "msgnum"
+#define END_FILE "end"
+#define CMT_FILE_FMT "cmt.%d"
+
+#define ORIG_DETACHED_HEAD "detached HEAD"
+
+#define REBASE_DIR_MODE 0777
+#define REBASE_FILE_MODE 0666
+
+typedef enum {
+ GIT_REBASE_TYPE_NONE = 0,
+ GIT_REBASE_TYPE_APPLY = 1,
+ GIT_REBASE_TYPE_MERGE = 2,
+} git_rebase_type_t;
+
+static int rebase_state_type(
+ git_rebase_type_t *type_out,
+ char **path_out,
+ git_repository *repo)
+{
+ git_buf path = GIT_BUF_INIT;
+ git_rebase_type_t type = GIT_REBASE_TYPE_NONE;
+
+ if (git_buf_joinpath(&path, repo->path_repository, REBASE_APPLY_DIR) < 0)
+ return -1;
+
+ if (git_path_isdir(git_buf_cstr(&path))) {
+ type = GIT_REBASE_TYPE_APPLY;
+ goto done;
+ }
+
+ git_buf_clear(&path);
+ if (git_buf_joinpath(&path, repo->path_repository, REBASE_MERGE_DIR) < 0)
+ return -1;
+
+ if (git_path_isdir(git_buf_cstr(&path))) {
+ type = GIT_REBASE_TYPE_MERGE;
+ goto done;
+ }
+
+done:
+ *type_out = type;
+
+ if (type != GIT_REBASE_TYPE_NONE && path_out)
+ *path_out = git_buf_detach(&path);
+
+ git_buf_free(&path);
+
+ return 0;
+}
+
+static int rebase_setupfile(git_repository *repo, const char *filename, const char *fmt, ...)
+{
+ git_buf path = GIT_BUF_INIT,
+ contents = GIT_BUF_INIT;
+ va_list ap;
+ int error;
+
+ va_start(ap, fmt);
+ git_buf_vprintf(&contents, fmt, ap);
+ va_end(ap);
+
+ if ((error = git_buf_joinpath(&path, repo->path_repository, REBASE_MERGE_DIR)) == 0 &&
+ (error = git_buf_joinpath(&path, path.ptr, filename)) == 0)
+ error = git_futils_writebuffer(&contents, path.ptr, O_RDWR|O_CREAT, REBASE_FILE_MODE);
+
+ git_buf_free(&path);
+ git_buf_free(&contents);
+
+ return error;
+}
+
+/* TODO: git.git actually uses the literal argv here, this is an attempt
+ * to emulate that.
+ */
+static const char *rebase_onto_name(const git_merge_head *onto)
+{
+ if (onto->ref_name && git__strncmp(onto->ref_name, "refs/heads/", 11) == 0)
+ return onto->ref_name + 11;
+ else if (onto->ref_name)
+ return onto->ref_name;
+ else
+ return onto->oid_str;
+}
+
+static int rebase_setup_merge(
+ git_repository *repo,
+ const git_merge_head *branch,
+ const git_merge_head *upstream,
+ const git_merge_head *onto,
+ const git_rebase_options *opts)
+{
+ git_revwalk *revwalk = NULL;
+ git_commit *commit;
+ git_buf commit_filename = GIT_BUF_INIT;
+ git_oid id;
+ char id_str[GIT_OID_HEXSZ];
+ bool merge;
+ int commit_cnt = 0, error;
+
+ GIT_UNUSED(opts);
+
+ if (!upstream)
+ upstream = onto;
+
+ if ((error = git_revwalk_new(&revwalk, repo)) < 0 ||
+ (error = git_revwalk_push(revwalk, &branch->oid)) < 0 ||
+ (error = git_revwalk_hide(revwalk, &upstream->oid)) < 0)
+ goto done;
+
+ git_revwalk_sorting(revwalk, GIT_SORT_REVERSE | GIT_SORT_TIME);
+
+ while ((error = git_revwalk_next(&id, revwalk)) == 0) {
+ if ((error = git_commit_lookup(&commit, repo, &id)) < 0)
+ goto done;
+
+ merge = (git_commit_parentcount(commit) > 1);
+ git_commit_free(commit);
+
+ if (merge)
+ continue;
+
+ commit_cnt++;
+
+ git_buf_clear(&commit_filename);
+ git_buf_printf(&commit_filename, CMT_FILE_FMT, commit_cnt);
+
+ git_oid_fmt(id_str, &id);
+ if ((error = rebase_setupfile(repo, commit_filename.ptr,
+ "%.*s\n", GIT_OID_HEXSZ, id_str)) < 0)
+ goto done;
+ }
+
+ if (error != GIT_ITEROVER ||
+ (error = rebase_setupfile(repo, END_FILE, "%d\n", commit_cnt)) < 0)
+ goto done;
+
+ error = rebase_setupfile(repo, ONTO_NAME_FILE, "%s\n",
+ rebase_onto_name(onto));
+
+done:
+ git_revwalk_free(revwalk);
+ git_buf_free(&commit_filename);
+
+ return error;
+}
+
+static int rebase_setup(
+ git_repository *repo,
+ const git_merge_head *branch,
+ const git_merge_head *upstream,
+ const git_merge_head *onto,
+ const git_rebase_options *opts)
+{
+ git_buf state_path = GIT_BUF_INIT;
+ const char *orig_head_name;
+ int error;
+
+ if (git_buf_joinpath(&state_path, repo->path_repository, REBASE_MERGE_DIR) < 0)
+ return -1;
+
+ if ((error = p_mkdir(state_path.ptr, REBASE_DIR_MODE)) < 0) {
+ giterr_set(GITERR_OS, "Failed to create rebase directory '%s'",
+ state_path.ptr);
+ goto done;
+ }
+
+ if ((error = git_repository__set_orig_head(repo, &branch->oid)) < 0)
+ goto done;
+
+ orig_head_name = branch->ref_name ? branch->ref_name : ORIG_DETACHED_HEAD;
+
+ if ((error = rebase_setupfile(repo, HEAD_NAME_FILE, "%s\n", orig_head_name)) < 0 ||
+ (error = rebase_setupfile(repo, ONTO_FILE, "%s\n", onto->oid_str)) < 0 ||
+ (error = rebase_setupfile(repo, ORIG_HEAD_FILE, "%s\n", branch->oid_str)) < 0 ||
+ (error = rebase_setupfile(repo, QUIET_FILE, opts->quiet ? "t\n" : "\n")) < 0)
+ goto done;
+
+ error = rebase_setup_merge(repo, branch, upstream, onto, opts);
+
+done:
+ if (error < 0)
+ git_repository__cleanup_files(repo, (const char **)&state_path.ptr, 1);
+
+ git_buf_free(&state_path);
+
+ return error;
+}
+
+int git_rebase_init_options(git_rebase_options *opts, unsigned int version)
+{
+ GIT_INIT_STRUCTURE_FROM_TEMPLATE(
+ opts, version, git_rebase_options, GIT_REBASE_OPTIONS_INIT);
+ return 0;
+}
+
+static void rebase_normalize_options(
+ git_rebase_options *opts,
+ const git_rebase_options *given_opts)
+{
+ if (given_opts)
+ memcpy(&opts, given_opts, sizeof(git_rebase_options));
+}
+
+static int rebase_ensure_not_in_progress(git_repository *repo)
+{
+ int error;
+ git_rebase_type_t type;
+
+ if ((error = rebase_state_type(&type, NULL, repo)) < 0)
+ return error;
+
+ if (type != GIT_REBASE_TYPE_NONE) {
+ giterr_set(GITERR_REBASE, "There is an existing rebase in progress");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int rebase_ensure_not_dirty(git_repository *repo)
+{
+ git_tree *head = NULL;
+ git_index *index = NULL;
+ git_diff *diff = NULL;
+ int error;
+
+ if ((error = git_repository_head_tree(&head, repo)) < 0 ||
+ (error = git_repository_index(&index, repo)) < 0 ||
+ (error = git_diff_tree_to_index(&diff, repo, head, index, NULL)) < 0)
+ goto done;
+
+ if (git_diff_num_deltas(diff) > 0) {
+ giterr_set(GITERR_REBASE, "Uncommitted changes exist in index");
+ error = -1;
+ goto done;
+ }
+
+ git_diff_free(diff);
+ diff = NULL;
+
+ if ((error = git_diff_index_to_workdir(&diff, repo, index, NULL)) < 0)
+ goto done;
+
+ if (git_diff_num_deltas(diff) > 0) {
+ giterr_set(GITERR_REBASE, "Unstaged changes exist in workdir");
+ error = -1;
+ }
+
+done:
+ git_diff_free(diff);
+ git_index_free(index);
+ git_tree_free(head);
+
+ return error;
+}
+
+int git_rebase(
+ git_repository *repo,
+ const git_merge_head *branch,
+ const git_merge_head *upstream,
+ const git_merge_head *onto,
+ const git_signature *signature,
+ const git_rebase_options *given_opts)
+{
+ git_rebase_options opts = GIT_REBASE_OPTIONS_INIT;
+ git_reference *head_ref = NULL;
+ git_buf reflog = GIT_BUF_INIT;
+ git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
+ int error;
+
+ assert(repo && branch && (upstream || onto));
+
+ GITERR_CHECK_VERSION(given_opts, GIT_MERGE_OPTIONS_VERSION, "git_merge_options");
+ rebase_normalize_options(&opts, given_opts);
+
+ if ((error = git_repository__ensure_not_bare(repo, "rebase")) < 0 ||
+ (error = rebase_ensure_not_in_progress(repo)) < 0 ||
+ (error = rebase_ensure_not_dirty(repo)) < 0)
+ goto done;
+
+ if (!onto)
+ onto = upstream;
+
+ if ((error = rebase_setup(repo, branch, upstream, onto, &opts)) < 0)
+ goto done;
+
+ if ((error = git_buf_printf(&reflog,
+ "rebase: checkout %s", rebase_onto_name(onto))) < 0 ||
+ (error = git_reference_create(&head_ref, repo, GIT_HEAD_FILE,
+ &onto->oid, 1, signature, reflog.ptr)) < 0)
+ goto done;
+
+ checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
+ error = git_checkout_head(repo, &checkout_opts);
+
+done:
+ git_reference_free(head_ref);
+ git_buf_free(&reflog);
+ return error;
+}
return error;
}
+int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head)
+{
+ git_filebuf file = GIT_FILEBUF_INIT;
+ git_buf file_path = GIT_BUF_INIT;
+ char orig_head_str[GIT_OID_HEXSZ];
+ int error = 0;
+
+ git_oid_fmt(orig_head_str, orig_head);
+
+ if ((error = git_buf_joinpath(&file_path, repo->path_repository, GIT_ORIG_HEAD_FILE)) == 0 &&
+ (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_FORCE, GIT_MERGE_FILE_MODE)) == 0 &&
+ (error = git_filebuf_printf(&file, "%.*s\n", GIT_OID_HEXSZ, orig_head_str)) == 0)
+ error = git_filebuf_commit(&file);
+
+ if (error < 0)
+ git_filebuf_cleanup(&file);
+
+ git_buf_free(&file_path);
+
+ return error;
+}
+
int git_repository_message(git_buf *out, git_repository *repo)
{
git_buf path = GIT_BUF_INIT;
return GIT_EBAREREPO;
}
+int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head);
+
int git_repository__cleanup_files(git_repository *repo, const char *files[], size_t files_len);
#endif
--- /dev/null
+#include "clar_libgit2.h"
+#include "git2/rebase.h"
+#include "posix.h"
+
+#include <fcntl.h>
+
+static git_repository *repo;
+static git_index *_index;
+static git_signature *signature;
+
+// Fixture setup and teardown
+void test_rebase_setup__initialize(void)
+{
+ repo = cl_git_sandbox_init("rebase");
+ cl_git_pass(git_repository_index(&_index, repo));
+ cl_git_pass(git_signature_now(&signature, "Rebaser", "rebaser@rebaser.rb"));
+}
+
+void test_rebase_setup__cleanup(void)
+{
+ git_signature_free(signature);
+ git_index_free(_index);
+ cl_git_sandbox_cleanup();
+}
+
+/* git checkout beef ; git rebase --merge master
+ * git checkout beef ; git rebase --merge master */
+void test_rebase_setup__blocked_when_in_progress(void)
+{
+ git_reference *branch_ref, *upstream_ref;
+ git_merge_head *branch_head, *upstream_head;
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo));
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
+
+ cl_git_pass(git_merge_head_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_merge_head_from_ref(&upstream_head, repo, upstream_ref));
+
+ cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL));
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo));
+
+ cl_git_fail(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL));
+
+ git_merge_head_free(branch_head);
+ git_merge_head_free(upstream_head);
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+}
+
+/* git checkout beef ; git rebase --merge master */
+void test_rebase_setup__merge(void)
+{
+ git_reference *branch_ref, *upstream_ref;
+ git_merge_head *branch_head, *upstream_head;
+ git_reference *head;
+ git_commit *head_commit;
+ git_oid head_id;
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo));
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
+
+ cl_git_pass(git_merge_head_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_merge_head_from_ref(&upstream_head, repo, upstream_ref));
+
+ cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL));
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo));
+
+ git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00");
+ cl_git_pass(git_repository_head(&head, repo));
+ cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT));
+ cl_assert_equal_oid(&head_id, git_commit_id(head_commit));
+
+ cl_assert_equal_file("b146bd7608eac53d9bf9e1a6963543588b555c64\n", 41, "rebase/.git/ORIG_HEAD");
+
+ cl_assert_equal_file("da9c51a23d02d931a486f45ad18cda05cf5d2b94\n", 41, "rebase/.git/rebase-merge/cmt.1");
+ cl_assert_equal_file("8d1f13f93c4995760ac07d129246ac1ff64c0be9\n", 41, "rebase/.git/rebase-merge/cmt.2");
+ cl_assert_equal_file("3069cc907e6294623e5917ef6de663928c1febfb\n", 41, "rebase/.git/rebase-merge/cmt.3");
+ cl_assert_equal_file("588e5d2f04d49707fe4aab865e1deacaf7ef6787\n", 41, "rebase/.git/rebase-merge/cmt.4");
+ cl_assert_equal_file("b146bd7608eac53d9bf9e1a6963543588b555c64\n", 41, "rebase/.git/rebase-merge/cmt.5");
+ cl_assert_equal_file("5\n", 2, "rebase/.git/rebase-merge/end");
+ cl_assert_equal_file("efad0b11c47cb2f0220cbd6f5b0f93bb99064b00\n", 41, "rebase/.git/rebase-merge/onto");
+ cl_assert_equal_file("master\n", 7, "rebase/.git/rebase-merge/onto_name");
+ cl_assert_equal_file("b146bd7608eac53d9bf9e1a6963543588b555c64\n", 41, "rebase/.git/rebase-merge/orig-head");
+
+ git_commit_free(head_commit);
+ git_reference_free(head);
+ git_merge_head_free(branch_head);
+ git_merge_head_free(upstream_head);
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+}
+
+/* git checkout beef && git rebase --merge --root --onto master */
+void test_rebase_setup__merge_root(void)
+{
+ git_reference *branch_ref, *onto_ref;
+ git_merge_head *branch_head, *onto_head;
+ git_reference *head;
+ git_commit *head_commit;
+ git_oid head_id;
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo));
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef"));
+ cl_git_pass(git_reference_lookup(&onto_ref, repo, "refs/heads/master"));
+
+ cl_git_pass(git_merge_head_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_merge_head_from_ref(&onto_head, repo, onto_ref));
+
+ cl_git_pass(git_rebase(repo, branch_head, NULL, onto_head, signature, NULL));
+
+ git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00");
+ cl_git_pass(git_repository_head(&head, repo));
+ cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT));
+ cl_assert_equal_oid(&head_id, git_commit_id(head_commit));
+
+ cl_assert_equal_file("b146bd7608eac53d9bf9e1a6963543588b555c64\n", 41, "rebase/.git/ORIG_HEAD");
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo));
+
+ cl_assert_equal_file("da9c51a23d02d931a486f45ad18cda05cf5d2b94\n", 41, "rebase/.git/rebase-merge/cmt.1");
+ cl_assert_equal_file("8d1f13f93c4995760ac07d129246ac1ff64c0be9\n", 41, "rebase/.git/rebase-merge/cmt.2");
+ cl_assert_equal_file("3069cc907e6294623e5917ef6de663928c1febfb\n", 41, "rebase/.git/rebase-merge/cmt.3");
+ cl_assert_equal_file("588e5d2f04d49707fe4aab865e1deacaf7ef6787\n", 41, "rebase/.git/rebase-merge/cmt.4");
+ cl_assert_equal_file("b146bd7608eac53d9bf9e1a6963543588b555c64\n", 41, "rebase/.git/rebase-merge/cmt.5");
+ cl_assert_equal_file("5\n", 2, "rebase/.git/rebase-merge/end");
+ cl_assert_equal_file("efad0b11c47cb2f0220cbd6f5b0f93bb99064b00\n", 41, "rebase/.git/rebase-merge/onto");
+ cl_assert_equal_file("master\n", 7, "rebase/.git/rebase-merge/onto_name");
+ cl_assert_equal_file("b146bd7608eac53d9bf9e1a6963543588b555c64\n", 41, "rebase/.git/rebase-merge/orig-head");
+
+ git_commit_free(head_commit);
+ git_reference_free(head);
+ git_merge_head_free(branch_head);
+ git_merge_head_free(onto_head);
+ git_reference_free(branch_ref);
+ git_reference_free(onto_ref);
+}
+
+/* git checkout gravy && git rebase --merge --onto master veal */
+void test_rebase_setup__merge_onto_and_upstream(void)
+{
+ git_reference *branch1_ref, *branch2_ref, *onto_ref;
+ git_merge_head *branch1_head, *branch2_head, *onto_head;
+ git_reference *head;
+ git_commit *head_commit;
+ git_oid head_id;
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo));
+
+ cl_git_pass(git_reference_lookup(&branch1_ref, repo, "refs/heads/gravy"));
+ cl_git_pass(git_reference_lookup(&branch2_ref, repo, "refs/heads/veal"));
+ cl_git_pass(git_reference_lookup(&onto_ref, repo, "refs/heads/master"));
+
+ cl_git_pass(git_merge_head_from_ref(&branch1_head, repo, branch1_ref));
+ cl_git_pass(git_merge_head_from_ref(&branch2_head, repo, branch2_ref));
+ cl_git_pass(git_merge_head_from_ref(&onto_head, repo, onto_ref));
+
+ cl_git_pass(git_rebase(repo, branch1_head, branch2_head, onto_head, signature, NULL));
+
+ git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00");
+ cl_git_pass(git_repository_head(&head, repo));
+ cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT));
+ cl_assert_equal_oid(&head_id, git_commit_id(head_commit));
+
+ cl_assert_equal_file("d616d97082eb7bb2dc6f180a7cca940993b7a56f\n", 41, "rebase/.git/ORIG_HEAD");
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo));
+
+ cl_assert_equal_file("d616d97082eb7bb2dc6f180a7cca940993b7a56f\n", 41, "rebase/.git/rebase-merge/cmt.1");
+ cl_assert_equal_file("1\n", 2, "rebase/.git/rebase-merge/end");
+ cl_assert_equal_file("efad0b11c47cb2f0220cbd6f5b0f93bb99064b00\n", 41, "rebase/.git/rebase-merge/onto");
+ cl_assert_equal_file("master\n", 7, "rebase/.git/rebase-merge/onto_name");
+ cl_assert_equal_file("d616d97082eb7bb2dc6f180a7cca940993b7a56f\n", 41, "rebase/.git/rebase-merge/orig-head");
+
+ git_commit_free(head_commit);
+ git_reference_free(head);
+ git_merge_head_free(branch1_head);
+ git_merge_head_free(branch2_head);
+ git_merge_head_free(onto_head);
+ git_reference_free(branch1_ref);
+ git_reference_free(branch2_ref);
+ git_reference_free(onto_ref);
+}
+
+/* Ensure merge commits are dropped in a rebase */
+/* git checkout veal && git rebase --merge master */
+void test_rebase_setup__branch_with_merges(void)
+{
+ git_reference *branch_ref, *upstream_ref;
+ git_merge_head *branch_head, *upstream_head;
+ git_reference *head;
+ git_commit *head_commit;
+ git_oid head_id;
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo));
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/veal"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
+
+ cl_git_pass(git_merge_head_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_merge_head_from_ref(&upstream_head, repo, upstream_ref));
+
+ cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL));
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo));
+
+ git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00");
+ cl_git_pass(git_repository_head(&head, repo));
+ cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT));
+ cl_assert_equal_oid(&head_id, git_commit_id(head_commit));
+
+ cl_assert_equal_file("f87d14a4a236582a0278a916340a793714256864\n", 41, "rebase/.git/ORIG_HEAD");
+
+ cl_assert_equal_file("4bed71df7017283cac61bbf726197ad6a5a18b84\n", 41, "rebase/.git/rebase-merge/cmt.1");
+ cl_assert_equal_file("2aa3ce842094e08ebac152b3d6d5b0fff39f9c6e\n", 41, "rebase/.git/rebase-merge/cmt.2");
+ cl_assert_equal_file("3e8989b5a16d5258c935d998ef0e6bb139cc4757\n", 41, "rebase/.git/rebase-merge/cmt.3");
+ cl_assert_equal_file("4cacc6f6e740a5bc64faa33e04b8ef0733d8a127\n", 41, "rebase/.git/rebase-merge/cmt.4");
+ cl_assert_equal_file("f87d14a4a236582a0278a916340a793714256864\n", 41, "rebase/.git/rebase-merge/cmt.5");
+ cl_assert_equal_file("5\n", 2, "rebase/.git/rebase-merge/end");
+ cl_assert_equal_file("efad0b11c47cb2f0220cbd6f5b0f93bb99064b00\n", 41, "rebase/.git/rebase-merge/onto");
+ cl_assert_equal_file("master\n", 7, "rebase/.git/rebase-merge/onto_name");
+ cl_assert_equal_file("f87d14a4a236582a0278a916340a793714256864\n", 41, "rebase/.git/rebase-merge/orig-head");
+
+ git_commit_free(head_commit);
+ git_reference_free(head);
+ git_merge_head_free(branch_head);
+ git_merge_head_free(upstream_head);
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+}
+
+/* git checkout barley && git rebase --merge master */
+void test_rebase_setup__orphan_branch(void)
+{
+ git_reference *branch_ref, *upstream_ref;
+ git_merge_head *branch_head, *upstream_head;
+ git_reference *head;
+ git_commit *head_commit;
+ git_oid head_id;
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo));
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/barley"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
+
+ cl_git_pass(git_merge_head_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_merge_head_from_ref(&upstream_head, repo, upstream_ref));
+
+ cl_git_pass(git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL));
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_REBASE_MERGE, git_repository_state(repo));
+
+ git_oid_fromstr(&head_id, "efad0b11c47cb2f0220cbd6f5b0f93bb99064b00");
+ cl_git_pass(git_repository_head(&head, repo));
+ cl_git_pass(git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT));
+ cl_assert_equal_oid(&head_id, git_commit_id(head_commit));
+
+ cl_assert_equal_file("12c084412b952396962eb420716df01022b847cc\n", 41, "rebase/.git/ORIG_HEAD");
+
+ cl_assert_equal_file("aa4c42aecdfc7cd989bbc3209934ea7cda3f4d88\n", 41, "rebase/.git/rebase-merge/cmt.1");
+ cl_assert_equal_file("e4f809f826c1a9fc929874bc0e4644dd2f2a1af4\n", 41, "rebase/.git/rebase-merge/cmt.2");
+ cl_assert_equal_file("9539b2cc291d6a6b1b266df8474d31fdd344dd79\n", 41, "rebase/.git/rebase-merge/cmt.3");
+ cl_assert_equal_file("013cc32d341bab0e6f039f50f153c18986f16c58\n", 41, "rebase/.git/rebase-merge/cmt.4");
+ cl_assert_equal_file("12c084412b952396962eb420716df01022b847cc\n", 41, "rebase/.git/rebase-merge/cmt.5");
+ cl_assert_equal_file("5\n", 2, "rebase/.git/rebase-merge/end");
+ cl_assert_equal_file("efad0b11c47cb2f0220cbd6f5b0f93bb99064b00\n", 41, "rebase/.git/rebase-merge/onto");
+ cl_assert_equal_file("master\n", 7, "rebase/.git/rebase-merge/onto_name");
+ cl_assert_equal_file("12c084412b952396962eb420716df01022b847cc\n", 41, "rebase/.git/rebase-merge/orig-head");
+
+ git_commit_free(head_commit);
+ git_reference_free(head);
+ git_merge_head_free(branch_head);
+ git_merge_head_free(upstream_head);
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+}
+
+static int rebase_is_blocked(void)
+{
+ int error;
+
+ git_reference *branch_ref, *upstream_ref;
+ git_merge_head *branch_head, *upstream_head;
+
+ cl_assert_equal_i(GIT_REPOSITORY_STATE_NONE, git_repository_state(repo));
+
+ cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/beef"));
+ cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
+
+ cl_git_pass(git_merge_head_from_ref(&branch_head, repo, branch_ref));
+ cl_git_pass(git_merge_head_from_ref(&upstream_head, repo, upstream_ref));
+
+ error = git_rebase(repo, branch_head, upstream_head, NULL, signature, NULL);
+
+ git_merge_head_free(branch_head);
+ git_merge_head_free(upstream_head);
+
+ git_reference_free(branch_ref);
+ git_reference_free(upstream_ref);
+
+ return error;
+}
+
+void test_rebase_setup__blocked_for_staged_change(void)
+{
+ cl_git_rewritefile("rebase/newfile.txt", "Stage an add");
+ git_index_add_bypath(_index, "newfile.txt");
+ cl_git_fail(rebase_is_blocked());
+}
+
+void test_rebase_setup__blocked_for_unstaged_change(void)
+{
+ cl_git_rewritefile("rebase/asparagus.txt", "Unstaged change");
+ cl_git_fail(rebase_is_blocked());
+}
+
+void test_rebase_setup__not_blocked_for_untracked_add(void)
+{
+ cl_git_rewritefile("rebase/newfile.txt", "Untracked file");
+ cl_git_pass(rebase_is_blocked());
+}
+
--- /dev/null
+ref: refs/heads/master
--- /dev/null
+[core]
+ repositoryformatversion = 0
+ bare = false
+ logallrefupdates = true
--- /dev/null
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
--- /dev/null
+efad0b11c47cb2f0220cbd6f5b0f93bb99064b00 efad0b11c47cb2f0220cbd6f5b0f93bb99064b00 Edward Thomson <ethomson@edwardthomson.com> 1405623541 -0400 checkout: moving from master to master
--- /dev/null
+x\ 1¥\8eAnC!\fD»æ\14¾@*\7fÀð\91ªªYä\ 6ÙG\ 6\eå/~\88(U¯\1fZå\ 6Ùͼ\91f¦´}ß\ 6X
+o£«B%
+BU«#DGa\91\829øì"R\94H~±.-HæÎ]o\ 3\98}ñ\96µH-±HZSÎÅYLÉyåIØU/ëjøg\[\87\93ür\178_ÛþÝnð¡\93þ©/ý\ f\9eî½´ý\13\16\8f\14ì¼fá\80\1eÑL:Ï\ e}±Æ\1cE¶±ÍùVAú¦r¹+\9b\a\vøT\1d
\ No newline at end of file
--- /dev/null
+x\ 1¥P»N\ 31\10¤öWl\97
+´g¯í³\84"\1aJ:~`½^ç"åÎÈ1Aü=\a\82/ \9b\97F\9a\91¶®ç\ 1nrw£«B\16\91Y9g/U
+¦ä\93ÄJ\93÷ÌÑ\91Mµ\ 4$óÆ]·\ 1$,\12jÐHÈ>K Êì\9c"åY+FçÊÌ\93\8d\7fy»»¢3YL¤8kf\99¼Í®\84â3ÖZ]ªI\82\1a~\1fKëð\>¸\17x]Úzm\e<ê®~£'ý1~Ù\83´õ\b\13¡\ fÖ:"¸GB4»º\8f\eúÏ\1aó¢ý´_Óy\93\ 5\ e§Î·Ï\ 3\9c·Ñà¦|1_\10"fi
\ No newline at end of file
--- /dev/null
+x\ 1¥\8eKjC1\10\ 4³Ö)æ\ 2\ eúÌèI\10B6^z\97\v\8c¤\11\16äYAQ0¾½\15ã\ed×Õ\rMå¾ïm\82¥ø2\87\b¸Â\818³\v\1c)!\96m\93JÄ¡È"\12\8c\89ML¨¾yÈe\826.gg\8bC\938iñU»XIWC.\9b\10\83¯Æg
+\8a\7fç¹\ f8\96+\8f\ 2\9fç¾ÿô\v¼ÉjÿÒ\87<\86'½æ¾¿\83AMÞZô\e\1c4jV»d§üóF\9dziµe\9em) Ì\ e\89Ç\97ÜÔ\1dK\80U\15
\ No newline at end of file
--- /dev/null
+x\ 1¥O9nÃ0\10tÍWì\abp)\89K\ 2F\90&e:\7f`¹\Ú*$\ 6\12\85|?´á\1f¸\9b\ 33\98\91º,s\ 3çÝ©mª\80XXÐ
+c\8a\ 3\ 6ÑÁ#Û¤V\86\1cBÌD¤.F1¿¼éÚ\80\84R \93F
+\ 5s\ fØÉûBÖe'\89Èû\14%ä±\18>Ú½nð\9dÿxËp½×e¯+\´«\ fô¥OãÅÎR\97OÀ±\979ôã\ 4\1fv´Ötµ\8fmúf\8dù©y.³p\9bû\ 4\84V\81÷þ\87oÇnþ\ 1B#Vj
\ No newline at end of file
--- /dev/null
+x\ 1¥\8eMn\ 3!\fF³æ\14¾@#\f\f8RTeÓew¹\80\8d!\99Å\84\88\92V½}hÕ\et÷ýHO/·m[\a¸\85v£\97\ 2Ñg$©H$ÄÈb\85\95\16\8c¨ÙW >\a*jUÌ\9d{¹\r\bR4¡Öd19ò\99sD\91\9a\ÄCb\8d¼ðäQ0ü\18×ÖáM¿¸+\9c¯mûh78\96¹þ¤Sù=þÚ>·í\150Ø%:ç-Â\8b\rÖ\9a¹NÙQþ\891ïM׺f\1eëTp0\1a\:\7f~\9b'fÐUN
\ No newline at end of file
--- /dev/null
+x\ 1¥\8e;n\ 31\fDSë\14¼\80\ 3R\9f] 0\ 27.Óå\ 2\14EÂ[¬eldøúÞ\18¾Aº\997ÀàI_×e\80OóÇØT!\18&Æ\90[ËÅ\12Uö5´¹R¬L\96\ 5ÑP\ 3±¸\eoz\1d\90\e\19\ 5+Ab)i\9e\90\ 5çF¾ø8±\90Ù\14\ 5«\16Ç÷qé\e\9cÛ\83·\ 6?\97¾þö+\1cu§\7f餯áÝ>¥¯_@\11Óä)§\ 2\a\8c\88n§»ìÐ\7fÞ¸ïÞ\16[\84Dz+\ 4\18\1dªª¹'\9d\fTG
\ No newline at end of file
--- /dev/null
+x\ 1¥\8fÛi\ 31\10Eó*¦\81\18iV\1aiÁ\84@H\ai@\8f\19[\10®LÚ\8fbÜ\81ÿî\ 3.çæÞZ\1d\80Þ¾\8c\9d\190YN"e1Æ8K\ 5}HÉ\15!dG\8b^\17\9dH;Iê'î¼\rðÙ' \8eW\1fÄ\14\13²vDâ5\16ÌÉ{¢´æP¬¨x\e×¾Ãgù\8d{\81¯koGßàÌ3ýWï|/\1eî\94{{\ 3cç\18¢F\82WmµV3\9d°\83\9f\9cQ\1f}\93ï\9aGÝ.Ðz©Rs\1cuâ\18\18\1dâ1¿ÅËíP\7fH¾ZÞ
\ No newline at end of file
--- /dev/null
+x\ 1M\90½nÃ0\f\84;ë)î\ 1\8c,\9d\82L-Ð@\83þ\f\1de\9b\8e\85Ò¢*Quüö¥\85\ 6è"\ 1Ç#ï#{\96\1e÷ÇãÝãÃëóÓ'Þ^>Î\açÎU!\11:g"\\ 2s\81Lè}fÚº?ù»ú¬M_½Rî0ÑjMAbÁ`ý5u®\84+\ 6\9f³\98±\fÙ'\1aáãØê!ª`\f\ 3u&\81l\1cÃ\9e¨A·=Mk\8e!µY®,\9eù\84^\ 2#(.\14\957è*\98¥æ²#QD²Ô\101\99\ 4É\98Â\ f!I\8dc£4\8bË~øÚK\91ö\7fÂRU%\1a@\83/l4ÍËdH³_:¬Ag$J\89r#/\9eõän \85eý\ f\ 2\96x¹9)[¾ÑÖtÀ»,^¥Àg²1\8e®\ 31Û\16ðã\18Ôn\ 6;\86ÎÁÎ$æw¿\1e/\8f\8a
\ No newline at end of file
--- /dev/null
+x\ 1¥\8eKj\ 31\f\86»ö)t\81\14ù1¶\ 6Jé&Ëìz\ 1\8d%\13C'.®\9b\?nÈ\rºû\1fðñå¶ïu\80[ÒËèªP\8a\14¦ÕÓ\8a\ 1\99\12"åÀ\9b%\1f¬Cñ\18¢0+\9boîz\19\90rÚ
+-º&*V,e\b, \9d¸¼¥\14ã¶f\92P\fÿ\8esëp\94\ew\81ÏsÛ\7fÚ\ 5Þt®\7féC\1fdz½æ¶¿\83\r\13æ\9cw\1e\ eÓ\ 6Í\§ìÐ\7fbÌ©I-5ó¨SÁÂhpUþ2w_ÎT
--- /dev/null
+x\ 1¥O;\ eÂ0\feÎ)|\ 1P\12\a·\95\10badã\ 2q\1cC\876¨\râú\ 4Ä\rØÞGz\9fT¦i¬àÉoê\923Xï\ 5\99\98Ų²¨\v\1dº!t¤Ü³\ 6»§Á%¶b\1eqÉs\ 5QAñ{O\81\ 6Ô$\1d\86>\8aïI1aPTb´\83ëM|Ö{Yà,¯¸\b\ïeZË\f\87ÜÔ\ f:å¯ñc»T¦#¸O\9dwÔ!lm°Ö4µ\8dùÏ\18s)2ê\98b\1dÛ\ 4\84Z ®íO¼=Wó\ 6>{VT
\ No newline at end of file
--- /dev/null
+x\ 1¥\8f]J\ 41\10\84}Î)ú\ 2JOÒ\99L`\11A¼\81\17èt:»\ 13\91\99,^ß(ÞÀ·ú\81â+éÕ\ 16ÐÃ8TÁ\89s 7L%ø`I¶-Ƽi@·.$ÉÇTRF
+æ\93\ fÝ\al¾8\12\8dÂQ±8\97i¡\95\8bJ\94¤\9eí:g<"\e¾\8f[?à-\7fñ\91áýÖÛÙw¸èL\7fÔ\8bþ\16\7fîIz{\86\85ЯÖbpð\88\84hf:a\87þsƼö½|T\19u¿Bë¹\96*<êÄ!\18\1dø\9cßøz?Í72\11ZÝ
\ No newline at end of file
--- /dev/null
+x\ 1¥\8e;nB1\10ES{\15³\81 Ûø3\96PD\93\92.\e\18\8fÇá\15\ fGÆ\80Ø=\ eb\at÷#\1d\1dnëº\f°\1e?F\17\ 1AdÖ\14\92I\14\9dO\89\ 5Å\14Îh$Û\9cI¶[
+Ϋ?êr\1a\109æ\8a^RÄj\8aAÖ>\84\1aµ-\96s\8c!äÄX\Ut\19ÇÖá»Ü¨\17ø9¶õÜN°\93¹þ§½<\8fWÛp[¿À¸ ³Ö&\r\9fÚiæ:e\87¼\89Q\87V\96º0\8de*\18\18\r~;]ïê\ 1MÿU9
\ No newline at end of file
--- /dev/null
+x\ 1¥\8eK\ e\ 2!\10D]s\8a¾\80\86o\ 3\891n\ºó\ 2Ð4\99YÌ`F\8c×\17\8d7pWõ*©<jË2wÐÎïúÆ\fÙ\933\98\\b\86B*\89³±Å±\8a\81\2%çB(Cvâ\9e6^;\18\89\91(JϨ£EmØEå¹baD\13u U9×,Ò³Om\83Ky¥ÀmjË£päA?éÌßá×\ eÔ\96\13(+\1dj\15¼\84½´R\8aA\87lç?oĵ\95¹Î\94ú<\14,ô\ 6\99¹\8a7è_T\9d
\ No newline at end of file
--- /dev/null
+x\ 1ERKnÛ0\10í\9a§x\a\10²+Z +5U\92\ 2\8d-Dò\ 1(jd\11¢I\86\9f\18¾}\87´Ú®D\883ïËɸ _¿\7fûÒ\ e}ûÞ¾\9c\ 6\fÇSÿ Ä(7Ââr\80\91áL\98²U+E¸\ 52z\19ä9Ç\ 6Q\ 5é :ÁjEæÖàé4âøü\8cã¡Ã¯ÃÓ«à\85´\12\92ó</íÌx·òç\ 2mq\95\89B\ 3µ:_§b\92f\8bu¬g ñµ{c¤ò\15\8b\ e\84«N+$¼&EEÊ$\95³\f»\8btV;\v\95\13²¿\93õ]ßwïh\ f?1´¿ÇG!ç\19éêð\91eHÕήarÚÜu%mê \7fÕ0ñGÖ\89\10Ý\92\9a¢æ |6Uò\85w\82Ëç"+jú¤;oLA²¿â¼â³\7fN©ÁuÕjÅÛi\18ñ£\ 3{\14la+Q\94QïÒ#<Ë׶Î3¦â\85\8dþ\9bª °\ 2\8cÇ~à¤Å¿6vìUÎ\98\887\8cÔ|âJª3®([vVx"ñeLà\ 4´2\ª\f$b^\164Ùdn\98\9de#iç®\9c\8báÇÀ`9qeµ¡\8b6Ûî\96Âg}\ 5Ù?\88?QÂÈ\83
\ No newline at end of file
--- /dev/null
+x\ 1+)JMU0¶`040031QHJ,ÊIÔ+©(ah\ eÞùóÞÿ\9a\82z\r>þÔ\9c\86r\9dS57\ 1jÜ\11À
\ No newline at end of file
--- /dev/null
+x\ 1¥\8d±NÄ0\10D©ý\15««ádç\1c'\91\10\82\ 2 ú\13ýÆÞ\V\8a½\91í\~\9f\80ø\ 3º\99÷¤\19/1r\85¦w\ f5\13\81m|À0è\vÒt¡ntƺ®%×ö\16û\91¬é\ 6k\ 6c\14nu\96\fïaÇ\1cà:K,\92à\99\ eú\93^éWüµ³\97ø\ 2ÆêÖ5¦í5<i«µ:èq^é\9f3ê3qe\ Ó\9d\vKRê\r&ڡȶ\1eÐóJ\ 5¦,\11N×\99à\8bó\8d\13#|ÈVhç\89N\8f\80wä\ 5Ç\85\80\13Ô\99Ôº\8d\v{\b\12\91ÓY}\ 3RYa)
\ No newline at end of file
--- /dev/null
+x\ 1¥\8e½n\ 21\10\84©ý\14û\ 2 óâ;{%\84hR¦K\1fùöG¸8\8c\8cQ^?\ 6å\r¢if¾\91FÃuÛJ\a\p×\9b*$\v¢\vÇäW2#V1\89FC\88Ac\bFqÅ\99Ü=7½uð«\17O\91È\98\13Y>ò\9aÐÏÉ\e[4Ôd\82ÌA\~ökmð!?¹ |]ëö¨78é /wÑwñ\97\ e\·3ø0Í\vââ\13ì§0MnÐq¶ë?gÜg\95b\85s/ãB\80j ¨|ß5»_X$W\87
\ No newline at end of file
--- /dev/null
+x\ 1ERÍNÃ0\fæ\9c§ð\ 3TÜ\10H\9c*\18\f ¶\8am\ f\90¦îj5KBâ0ííq²\ 2§¦©ýý¶·¾\87»\87û\9bv×µ\9fíëa\a»í¡»Uj¯g\84Ñç\bVÇ#B\9f\9d\990\81\1fA§ £>æÔ@2Q\a\ 4bpdÐ^\1ax:ìaûò\ 2ÛÍ
+Þ6Ok%\v<!°\ f2¯Ý x\97rs\ 2rpÖ\8c±\ 13ùP§\12k;§:Ö Ð~½ú\10¤òT#E\843ñ\ 4\1a\ 2¡Á"¥×Æ;\81]DzGÞ\81É\f9\ɺU×>¡Ý<î}ß?*=\fÀg\ f_YG®v\16\r½'{ÕÅdë ~Õ\bñW&FH~䦨٨\90m\95|\92\9dèó±ÈJ\84ßxåM\1cµø+Î+¾ø\97\94\1a8Od&8åÄÐ#\84ÌJ,Ì%\8a2\1a<?\96Ky¯ó\82idaÆ\7fS5\81ß@%\ 2õ×Æ\82=éA eÃj\92\93TR\9dIEÙ\89³Â\93P>\8a\ 2I\80\8c\95RuD\95ò8\92!tl/0x'Fxá®\9c£\95\9fAÀ2Keµ¡\13Ùyq\8bñ»þ\ 59ܪ\1fð\11ÊÃ
\ No newline at end of file
--- /dev/null
+x\ 1M\90AjÃ0\10E»Ö)þ\ 1L6]\85¬Ò\12ÚBh\82í@»\94íq,*kTi\7·ïØ\10èJðçóæi\1aÏ\r\1e·Û\87§}y<|¢:]Î\ecÎ\97\1a§wÔ¯åá\80\97·ã±\ 2÷hlòt+ C"Â÷d\93ä%\9fP*ÐÓ\f\ e\8eCF; ¦X\98êí\ 3Ïû²<Õ\15r\9bl¤\ e6tëÜ\ 5at®¥B#\90âüÂ\fâä¶PeJÁÅ\95eòh½ß¡açá\ 4W
+âo\90\991ð\94ò¢D\ 1Q·º\80^#pBï~\b\91§Ð\96Z1ɶ_Ë(Ðòö\18'\11\ e*°Êg¯6k×\93*\rv,0;\19\10)FJ«y¶^væ.\92=ÏÿEà9\ïMJº_m§¸AÍ£\15ΰ\89\14cè·%ïõ\17°]çDo\ 6=\86\f.#³öÍ\1f\vó\8c\8a
\ No newline at end of file
--- /dev/null
+x\ 1¥\8eAnÃ0\f\ 4{Ö+ø\81\16\14MÙ\12\10\ 4¹ôØ[>@\93\14â\83£ÀQ\90ïÇ-ú\83Üvg\81Åh[×¥\ 3¥é£oî0P"Á±\90¨³²NX*\11ÆH4Y1åÌ©R.á&\9b_;\98\14MQh0$+C\14Îcå$\16³\9a`Ò\9a\8cæÂA\1eýÒ6ø¶§l\ 6çK[ïí
+\aßéo:ùßðß¾´G\88\8ci¤\98\99á\13\191ìt\97íþæMøi¶ÔE¥/»\ 2Ao0»×ð\ 2â\9bS\80
\ No newline at end of file
--- /dev/null
+x\ 1+)JMU0·d040031QHJ,ÊIÔ+©(a¨|Ô6eÕ\83ËlÞl?³\82Øw:/2g\87ªJ)ÊLM\89/HM\ 4+tôýSøêú\1cö5W^¹ÿ;?ñSçú#;\ 1a9$j
\ No newline at end of file
--- /dev/null
+x\ 1ERËnã0\fìY_Á\ f0z+Z '5u\1eè¢Îú\81\9ce\85\8e\85(\96V¢\1aäï\97R\8aöd\89\1aÎp8\1e\eáéåùAv{ÙÊÍÐA×\fûG!zùQú\19Zø#ÛM\roÃçj[wà&PÑ« N)V\10uP\1eÁ\10,F£½U \131f\ 2·pyѳhÖÐokè\9b}W\81Z\8e`Õ\rhÆ\v?ÃU\11\ 6n\9a\9dÏ5\88¤ì9\16\98g¢\ 2sKþ\8aõ®á°ë· a¿«W50ó\9b\5\9fLˤá\84,j\18\9dGHþ.æÑ{\f\850*K¯B¾¿C\7fhàï Û¾Ë\1c\aÙ×m\ 5£3ö.HÆ\96ÓÏ4\ 1á_2Äã¹\89ª\fZ\84O¶\8c|ákpé4ó\10Ñà\17Þu#\ 5Åþ²§â\11Èñ\96*¸ÎFÏpI\91`D`\8fbTú\9cW\91¡ÞÑk.ò½à\99SsÃ\19\7fM]\rÍ\ 5KÎGÞ´øIã\9b{VG¦æ\ e«\f\9f8\92â\8c#J\v;˽\11ù\91'P\81\8c¶Èû\ e(b\9a&£\r.dopäø²Ñ»vÑ\9c¬K\1cÕ\98\88#+\v½\18{þv\8bá«ü\ 5É?\8aÿÐwÇ\83
\ No newline at end of file
--- /dev/null
+x\ 1M\90AjÃ0\10E»Ö)þ\ 1L6]\85¬Ò\12Ú\80Û\ 4Û\81v)ÛãXTѨҨ®o_Ù\10èJðçóæiZË-\1e·Û\87§}U\1e>Q\9f.ç\8dRçK\83Ó;\9a×êpÀ˱,kð\80V\aKs\ 1\19\ 3\11¾\93\ e\12\97|ÒB¡À@\13Ø\19v\11]\12$_¨úø\81ç}U\9d\9a\1a±\vÚS\ fíúun\9c0zÓQ\91#PÆÙ\85éÄȼP%\ 5güÊRõÛ¾,whÙX\18Á\95\9cØ\1921FN!.JäàóVã0ä\b\1c0\98\1f\82çäúÕ2WTÐÝ×2r´¼\ 3nI\84]\16Xå£Í6k×RV\1aõÀdd\84'ï)¬æQ[Ù©»H´<ý\17\81ew½7)äýÙ6ù\r\1a¾iá\b\1d(c\14ývdmþ\ 5tß\eÉ7C>\86\8c&"rî«?v\84\8bê
\ No newline at end of file
--- /dev/null
+x\ 1ERÍnà \fÞ\99§ð\ 3D½M\9bÔS6µ«´i©\9aö\ 1\bq\1a\14\ 2\14L£¾ý\fºSÀ|þ~ìtÆuðúþöR·ûúP\7f\9dZh\9bÓ~%ıþÞÀ¶9\1dà§>|màãôû¹Û´à\ 6\90ÑË Ï)V\10U\90\1eA\13XÐÜ*P\89\183\80³\¶j\14Í\16\8e»\r\1c\9b}[\81´=\18y\ 3\1aqægX$aà¦Ñù\\83HÒL±À<\13\15\98³ù+\ 6\1d\10\16M#Hð\1a\15f+\9dTÎ2-\93\863W¬ft¶\90ü]Ì£÷\18
+a\94\86ÖBö=Ðâà\92d \989\1e\1e:§Í]\90´)§§\e\16¾$MlÏ\rTe\90\15>\99byækpé\9cmE\8dW¼ëF
+\92óåL\85\1fÈñ\94*XFF\98S$è\108£à\bS\1eE\86zGë\ä{Á3§â\86 ÿC\95 d,9\9fí\8bç6\1eÜ£ì\99\9a;\8cÔ|â\95\94d¼¢d9YÖ\89È\8fì\80' \95A\9ew@\11Ó0h¥Ñ\92¹AÏëËAïÚEs0.ñªºD¼²2ÐY\9bé\91\16õü\ 5ɯÄ\1f9ÏÌ\83
\ No newline at end of file
--- /dev/null
+x\ 1¥\8dÁ B1\10D=§\8am@Ù\1f\12ý\ 1\11=Ø\81\rl²\e~À¸\10#b÷F±\ 3o3o`^ÒZK\a\8b~Õ\9b\b\88d\14fñL\14\1c\93Ï6ìØ1GÏ9¦)Ì\981 5ôè\8b68ó\93\1aÃeÑz×\eìeÐO:ÊwøµMÒz\80É¡ßZë¦\19Öè\10Í CÞåÏ\esb.½\f½f\88Ô®ò2o!\vFw
\ No newline at end of file
--- /dev/null
+x\ 1¥\8eÁj\ 31\fD{öWè\a\1a,¯e«\10B.=æÖ\1fÐÚ\12»\87\8dÃÆ!¿_7ô\ f\ 2s\98y\ 3Ã\94¶mk\87@ù£ïª\80\16\ 2Æ\823NC±\12y¶\88\96d\9as.% \e!\aw\93]¯\1d\88Y©\ 6ó±Æ¯ì³i\14\999\91bU)bY-eÎN\1e}i;|קì\15~\96¶ÝÛ\15\8e:è\9f;ë«øO\87Ò¶\13`ô\94\ 22#|úè½\et\9cíúæ\8c»´ºÚZ¤¯ã\ 2Ao0«\9aû\ 5cJT/
\ No newline at end of file
--- /dev/null
+x\ 1¥O;N\ 41\f¥\9eS¸Û
+d;Nf"!´\r%\1d=ÊÇaFb&«\90\15âö\ 4\ 4' {_[/Õ}ß:\18ò7½©\82)yÉÖ¤\82\9cÕ\1a\1f}`\e¬\17B\83b©Ì.\90å2]BÓ£Ct3G\12ʲ$ã|QuI²j4\1c<\8aYæÑ5Îþå\89\13."ÄÑ[6ÞyÇ\1a\85q&\97\v\122ÇEæ\94¦píkmð\98?BËð¼Öý½\1ep¯CýFgý1~Ù]ªû\ 3\90 uÌã!Ü¢ NC\1dãºþóÌô¤íU!¶p¤\15N1´7ý<Ávô
+¹m\9a_.\1a¦/ÚÚdÛ
\ No newline at end of file
--- /dev/null
+x\ 1%P1nÄ0\fëìWð\ 1¹C\81NE§N7¶è¡\ 5:*\89\92\18p¬Ô\92/¸ßWÎm\ 2I\91\94ú$=^^\9f\9f._ï?¿¸~|\7f\9eC¸°\81ã¼\186©yTÈ\84A¨(#1eôÌÓé´\93.\88\86áÀ(\8fHto@̸K-a\13ë°Õ\ 3°\85¡´²\93sá1r6\ 5)&)8¸Å·TêÖa\8f¶<0×\87¿JÙ¢Ý[\87\9d\8cK\87\165IJ²\1f²ÈÀª\18cáÁ¸qÍ\93ì\8c«\15r_\ f\bÍÛ\87"u^@ÐÈ7~X)\97\9b÷2¸ Ýâ G\85,æ¥f¬R¸ùå`BÚ\ 2úÂ4¶3£½Áv\81Q\9fø¤\9bHÖ©¦Öuêa²b SwÞcJ q\ 4\85)fÆ\94èæO\82ùvû\8d×;\87\7fí«\8c\9f
\ No newline at end of file
--- /dev/null
+x\ 1¥NK\ e \10uÍ)æ\ 2\9a)0-M\8cqãÒ\9d\17\18`Ð.Z\f¢ÆÛ\8bÆ\e¸{ÿ¼\90çyª Éj\11\ 1ßùÑJ@\9d\9cD7D\94Ä6ô\94¼q\91b\1fy\10ç\8dVW.²´"³ â¬ÆVC'\9eCGÚ\9b\96$\8f)%3¦1ô¢ø^/¹À!>¹D8]ò|Ë\vl¥©\1f´\97¯ñc\9b\90ç\1dt\16©×\84D°F\8b¨\9aÚÎVùsF\1ds\9cÒ\14¸Ní\82\81\9aá\øñRo\17\1eV<
\ No newline at end of file
--- /dev/null
+x\ 1¥\8e;\ e\ 2!\10\869Å\@3ÀÂ@b\8c\8d¥\9d\17à1\13·X1+Æë\8bÆ\eØý\8fäËWÚ²Ì\1d\8c£M_\99! 5Õ[\14KÆû\9c
+c´l\9d\15Ê\91*IÈ\ 6£CuO+ß:P¡,Áq¤ ºêPÐy/\84¦\9a\92\89\ 6"\96P'QéÙ¯m\85S}¥µÂåÚ\96G»Á\9eÇúIGþ\1e¿¶+m9\80\9e\ 6Ìhò\11¶8!ª±\ eÙÎ\7fbÔ¹ÕYæ\92ú<\144ô\ 6\99YÔ\eõ¯S\95
\ No newline at end of file
--- /dev/null
+x\ 1¥\8eM\8a\ 21\14\84]ç\14ï\ 2\ eùym'0\88\e\97î¼@%yÁ\ 6Û\f1"ÞÞ8Ì\rfWõ\15\14_ªëºt²SØô&Beç
+Ü,ÖO1\e\135æȾ`ò\fÖÁxÃpÈP?hrë\ 4pb\vI¹¤9åàC\8cÉY\1d\82cÁ p\85³÷
+\8f~©\8d\8eù\89\96é|©ë½Þè[\ 6ý¤\83ü\ e\7fí+ÕuO\86õ´³\96YÓV³ÖjÐ!Ûå\9f7êTóR\96\84¾\f\ 5C½RD»ÊK½\ 1ÿXV\18
\ No newline at end of file
--- /dev/null
+x\ 1¥\8e;j\ 31\10\86]ë\14s\81\98\91V\8f\15\18\93&eºôaV3\83UìÊ(
+¹~d\93\e¤û\1fðñ\95¶ïu\80\8bî4º\b\10Z\8a"KF\8d\81×Å/)\b&\97\83c!\11,A²ÓdîÔå\18\80¨vË\84Ù¯\948°õ\1e\83l\14qAѺm«ª'CßãÖ:¼ñ\ fu\86\8f[Û¿Ú\ 1\17\99ë#½ÊóøkçÒö+Ø\89\8aÎ\85äá\ 5=¢\99ë\94\1dòO\8cyo\µ\16\1au*Xh
+Ü«ðç]Èü\ 2x\13V¢
\ No newline at end of file
--- /dev/null
+x\ 1M\90ÍjÃ0\10\84{ÖSÌ\ 3\98\z
+9µ`Ú\82iB~\ e=Êö:\16\95µª´ª\93·ïÚ\10èiav\98ývZÏ-\9e·Û§×\97cS\7fá´¿\1c6Æ\1c.gì?q~?Ö5Þ>\9aæ\ 4\1eÐÚäé^AÆD\84\9fb\93äE\9fPª0Ð\f\ e\8eCFW\ 4%V&»\e:\9b\12«1wÉFêaC¿î]\10Fï:ªT\ 2i\9c_2\838¹/©RRpqÍ2y²Þïвóp\82+\ 5ñwÈÌ\18¹¤¼ Q@Ô«.`P \9c0¸_Bä\12ú\95R-&Ùî{Y\ 5Zæ\80©\88pP\80\15>{¥Y½\9e\14i´S\85ÙÉ\88H1RZɳõ²3\ f\90ìyþ\ f\ 2ÏáúpRÒûJ[â\ 6g\9e¬p\86M¤1\86n\1dy¯_Àö½\13í\fZ\86\8cNkbõ\9b?\8cÂ\8dÊ
\ No newline at end of file
--- /dev/null
+x\ 1¥\8f=nÃ0\f\853ë\14¼@\v\8a¢d\19\b\8a.\1d»å\ 2¬D&\1el\ 5¶\82^¿jÐ\et{?ÀÃ÷J[×¥\ 3%:õ]\15r¤\98\95)I`_\8a\17Á\10¥L\96ªÏ\96Ù´\92|\85ìî²ëÖa\12\8c3¢\ 5F1¤H"Â\1axfoÈXb%ÓÉ&'\8f~k;|ÔoÙ+\nm=Ú\ 6g\1dé¯z×gñç^K[ßÀ3ÆD>Í ^Æ\16º\91\ eØ®ÿ\9cq\9f.¶\14éË@\88Ð\eÈ1þÈõq¸\1fæ©V\13
\ No newline at end of file
--- /dev/null
+x\ 1¥\8eK\8a\ 2A\10D]×)ò\ 2\ eUÙõ\13\ 6qãÒ\9d\17ÈÎ\ f6ØÖÐ\96z}Ûan0»\88\17\10<nó<uÀT6}Q\85\1dÕ4$1&+)E.X¥\96h>\16N1\a\e\91K\90à~hÑ[\a¯\86\8a#\12\8eU²\ 6«b\964cP¯L\18Ƽ\eij£G¿´\ 5\8eò¢Eà|ió½Ýà[WúI\aý\1dþÚ\17·y\ f!ú\94\11\87\9caë£÷n¥«l×\7fÞ¸S\93É&¦>
+\ 3ô\ 6O¥«{\ 3ä\83TÈ
\ No newline at end of file
--- /dev/null
+4b21eb6eeeec7f8fc89a1d334faff9bd5f5f8c34
--- /dev/null
+12c084412b952396962eb420716df01022b847cc
--- /dev/null
+b146bd7608eac53d9bf9e1a6963543588b555c64
--- /dev/null
+7f37fe2d7320360f8a9118b1ed8fba6f38481679
--- /dev/null
+d616d97082eb7bb2dc6f180a7cca940993b7a56f
--- /dev/null
+efad0b11c47cb2f0220cbd6f5b0f93bb99064b00
--- /dev/null
+f87d14a4a236582a0278a916340a793714256864
--- /dev/null
+ASPARAGUS SOUP.
+
+TAKE FOUR LARGE BUNCHES of asparagus, scrape it nicely, cut off one inch
+OF THE TOPS, and lay them in water, chop the stalks and put them on the
+FIRE WITH A PIECE OF BACON, a large onion cut up, and pepper and salt;
+ADD TWO QUARTS OF WATER, boil them till the stalks are quite soft, then
+PULP THEM THROUGH A SIEVE, and strain the water to it, which must be put
+back in the pot; put into it a chicken cut up, with the tops of
+asparagus which had been laid by, boil it until these last articles are
+sufficiently done, thicken with flour, butter and milk, and serve it up.
--- /dev/null
+BEEF SOUP.
+
+Take the hind shin of beef, cut off all the flesh off the leg-bone,
+which must be taken away entirely, or the soup will be greasy. Wash the
+meat clean and lay it in a pot, sprinkle over it one small
+table-spoonful of pounded black pepper, and two of salt; three onions
+the size of a hen's egg, cut small, six small carrots scraped and cut
+up, two small turnips pared and cut into dice; pour on three quarts of
+water, cover the pot close, and keep it gently and steadily boiling five
+hours, which will leave about three pints of clear soup; do not let the
+pot boil over, but take off the scum carefully, as it rises. When it has
+boiled four hours, put in a small bundle of thyme and parsley, and a
+pint of celery cut small, or a tea-spoonful of celery seed pounded.
+These latter ingredients would lose their delicate flavour if boiled too
+much. Just before you take it up, brown it in the following manner: put
+a small table-spoonful of nice brown sugar into an iron skillet, set it
+on the fire and stir it till it melts and looks very dark, pour into it
+a ladle full of the soup, a little at a time; stirring it all the while.
+Strain this browning and mix it well with the soup; take out the bundle
+of thyme and parsley, put the nicest pieces of meat in your tureen, and
+pour on the soup and vegetables; put in some toasted bread cut in dice,
+and serve it up.
--- /dev/null
+SOUP WITH BOUILLI.
+
+Take the nicest part of the thick brisket of beef, about eight pounds,
+put it into a pot with every thing directed for the other soup; make it
+exactly in the same way, only put it on an hour sooner, that you may
+have time to prepare the bouilli; after it has boiled five hours, take
+out the beef, cover up the soup and set it near the fire that it may
+keep hot. Take the skin off the beef, have the yelk of an egg well
+beaten, dip a feather in it and wash the top of your beef, sprinkle over
+it the crumb of stale bread finely grated, put it in a Dutch oven
+previously heated, put the top on with coals enough to brown, but not
+burn the beef; let it stand nearly an hour, and prepare your gravy
+thus:--Take a sufficient quantity of soup and the vegetables boiled in
+it; add to it a table-spoonful of red wine, and two of mushroom catsup,
+thicken with a little bit of butter and a little brown flour; make it
+very hot, pour it in your dish, and put the beef on it. Garnish it with
+green pickle, cut in thin slices, serve up the soup in a tureen with
+bits of toasted bread.
--- /dev/null
+GRAVY SOUP.
+
+Get eight pounds of coarse lean beef--wash it clean and lay it in your
+pot, put in the same ingredients as for the shin soup, with the same
+quantity of water, and follow the process directed for that. Strain the
+soup through a sieve, and serve it up clear, with nothing more than
+toasted bread in it; two table-spoonsful of mushroom catsup will add a
+fine flavour to the soup.
--- /dev/null
+OYSTER SOUP.
+
+Wash and drain two quarts of oysters, put them on with three quarts of
+water, three onions chopped up, two or three slices of lean ham, pepper
+and salt; boil it till reduced one-half, strain it through a sieve,
+return the liquid into the pot, put in one quart of fresh oysters, boil
+it till they are sufficiently done, and thicken the soup with four
+spoonsful of flour, two gills of rich cream, and the yelks of six new
+laid eggs beaten well; boil it a few minutes after the thickening is put
+in. Take care that it does not curdle, and that the flour is not in
+lumps; serve it up with the last oysters that were put in. If the
+flavour of thyme be agreeable, you may put in a little, but take care
+that it does not boil in it long enough to discolour the soup.
--- /dev/null
+VEAL SOUP.
+
+Put into a pot three quarts of water, three onions cut small, one
+spoonful of black pepper pounded, and two of salt, with two or three
+slices of lean ham; let it boil steadily two hours; skim it
+occasionally, then put into it a shin of veal, let it boil two hours
+longer; take out the slices of ham, and skim off the grease if any
+should rise, take a gill of good cream, mix with it two table-spoonsful
+of flour very nicely, and the yelks of two eggs beaten well, strain this
+mixture, and add some chopped parsley; pour some soup on by degrees,
+stir it well, and pour it into the pot, continuing to stir until it has
+boiled two or three minutes to take off the raw taste of the eggs. If
+the cream be not perfectly sweet, and the eggs quite new, the thickening
+will curdle in the soup. For a change you may put a dozen ripe tomatos
+in, first taking off their skins, by letting them stand a few minutes in
+hot water, when they may be easily peeled. When made in this way you
+must thicken it with the flour only. Any part of the veal may be used,
+but the shin or knuckle is the nicest.