commit - 13add98862efe69781a0693d9af2c45d235f1f43
commit + 2822a3526b8c61302ec86e0871e724c07a4b078d
blob - c34b1bcb69fd3e41f6c82be87c06d624f89bf175
blob + 841f4902e5bee78beec97707fdf93aec1087eab9
--- got/got.1
+++ got/got.1
.It Cm he
Short alias for
.Cm histedit .
+.It Cm integrate Ar branch
+Integrate the specified
+.Ar branch
+into the work tree's current branch.
+Files in the work tree are updated to match the contents on the integrated
+.Ar branch ,
+and the reference of the work tree's branch is changed to point at the
+head commit of the integrated
+.Ar branch .
+.Pp
+Both branches can be considered equivalent after integration since they
+will be pointing at the same commit.
+Both branches remain available for future work, if desired.
+In case the integrated
+.Ar branch
+is no longer needed it may be deleted with
+.Cm got branch -d .
+.Pp
+Show the status of each affected file, using the following status codes:
+.Bl -column YXZ description
+.It U Ta file was updated
+.It D Ta file was deleted
+.It A Ta new file was added
+.It \(a~ Ta versioned file is obstructed by a non-regular file
+.It ! Ta a missing versioned file was restored
+.El
+.Pp
+.Cm got integrate
+will refuse to run if certain preconditions are not met.
+Most importantly, the
+.Ar branch
+must have been rebased onto the work tree's current branch with
+.Cm got rebase
+before it can be integrated, in order to linearize commit history and
+resolve merge conflicts.
+If the work tree contains multiple base commits it must first be updated
+to a single base commit with
+.Cm got update .
+If changes have been staged with
+.Cm got stage ,
+these changes must first be committed with
+.Cm got commit
+or unstaged with
+.Cm got unstage .
+If the work tree contains local changes, these changes must first be
+committed with
+.Cm got commit
+or reverted with
+.Cm got revert .
+.It Cm ig
+Short alias for
+.Cm integrate .
.It Cm stage Oo Fl l Oc Oo Fl p Oc Oo Fl F Ar response-script Oc Op Ar path ...
Stage local changes for inclusion in the next commit.
If no
blob - 206285202f7c507b7a0760eda2c197cf1053c16e
blob + c2246a9a4a1eb2d49378c3096a50bcbf472739e2
--- got/got.c
+++ got/got.c
__dead static void usage_backout(void);
__dead static void usage_rebase(void);
__dead static void usage_histedit(void);
+__dead static void usage_integrate(void);
__dead static void usage_stage(void);
__dead static void usage_unstage(void);
__dead static void usage_cat(void);
static const struct got_error* cmd_backout(int, char *[]);
static const struct got_error* cmd_rebase(int, char *[]);
static const struct got_error* cmd_histedit(int, char *[]);
+static const struct got_error* cmd_integrate(int, char *[]);
static const struct got_error* cmd_stage(int, char *[]);
static const struct got_error* cmd_unstage(int, char *[]);
static const struct got_error* cmd_cat(int, char *[]);
{ "backout", cmd_backout, usage_backout, "bo" },
{ "rebase", cmd_rebase, usage_rebase, "rb" },
{ "histedit", cmd_histedit, usage_histedit, "he" },
+ { "integrate", cmd_integrate, usage_integrate,"ig" },
{ "stage", cmd_stage, usage_stage, "sg" },
{ "unstage", cmd_unstage, usage_unstage, "ug" },
{ "cat", cmd_cat, usage_cat, "" },
got_ref_close(tmp_branch);
if (worktree)
got_worktree_close(worktree);
+ if (repo)
+ got_repo_close(repo);
+ return error;
+}
+
+__dead static void
+usage_integrate(void)
+{
+ fprintf(stderr, "usage: %s integrate branch\n", getprogname());
+ exit(1);
+}
+
+static const struct got_error *
+cmd_integrate(int argc, char *argv[])
+{
+ const struct got_error *error = NULL;
+ struct got_repository *repo = NULL;
+ struct got_worktree *worktree = NULL;
+ char *cwd = NULL, *refname = NULL, *base_refname = NULL;
+ const char *branch_arg = NULL;
+ struct got_reference *branch_ref = NULL, *base_branch_ref = NULL;
+ struct got_fileindex *fileindex = NULL;
+ struct got_object_id *commit_id = NULL, *base_commit_id = NULL;
+ int ch, did_something = 0;
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch (ch) {
+ default:
+ usage_integrate();
+ /* NOTREACHED */
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage_integrate();
+ branch_arg = argv[0];
+
+ if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
+ "unveil", NULL) == -1)
+ err(1, "pledge");
+
+ cwd = getcwd(NULL, 0);
+ if (cwd == NULL) {
+ error = got_error_from_errno("getcwd");
+ goto done;
+ }
+
+ error = got_worktree_open(&worktree, cwd);
+ if (error)
+ goto done;
+
+ error = check_rebase_or_histedit_in_progress(worktree);
+ if (error)
+ goto done;
+
+ error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
+ NULL);
+ if (error != NULL)
+ goto done;
+
+ error = apply_unveil(got_repo_get_path(repo), 0,
+ got_worktree_get_root_path(worktree));
+ if (error)
+ goto done;
+
+ if (asprintf(&refname, "refs/heads/%s", branch_arg) == -1) {
+ error = got_error_from_errno("asprintf");
+ goto done;
+ }
+
+ error = got_worktree_integrate_prepare(&fileindex, &branch_ref,
+ &base_branch_ref, worktree, refname, repo);
+ if (error)
+ goto done;
+
+ refname = strdup(got_ref_get_name(branch_ref));
+ if (refname == NULL) {
+ error = got_error_from_errno("strdup");
+ got_worktree_integrate_abort(worktree, fileindex, repo,
+ branch_ref, base_branch_ref);
+ goto done;
+ }
+ base_refname = strdup(got_ref_get_name(base_branch_ref));
+ if (base_refname == NULL) {
+ error = got_error_from_errno("strdup");
+ got_worktree_integrate_abort(worktree, fileindex, repo,
+ branch_ref, base_branch_ref);
+ goto done;
+ }
+
+ error = got_ref_resolve(&commit_id, repo, branch_ref);
+ if (error)
+ goto done;
+
+ error = got_ref_resolve(&base_commit_id, repo, base_branch_ref);
+ if (error)
+ goto done;
+
+ if (got_object_id_cmp(commit_id, base_commit_id) == 0) {
+ error = got_error_msg(GOT_ERR_SAME_BRANCH,
+ "specified branch has already been integrated");
+ got_worktree_integrate_abort(worktree, fileindex, repo,
+ branch_ref, base_branch_ref);
+ goto done;
+ }
+
+ error = check_linear_ancestry(commit_id, base_commit_id, repo);
+ if (error) {
+ if (error->code == GOT_ERR_ANCESTRY)
+ error = got_error(GOT_ERR_REBASE_REQUIRED);
+ got_worktree_integrate_abort(worktree, fileindex, repo,
+ branch_ref, base_branch_ref);
+ goto done;
+ }
+
+ error = got_worktree_integrate_continue(worktree, fileindex, repo,
+ branch_ref, base_branch_ref, update_progress, &did_something,
+ check_cancelled, NULL);
+ if (error)
+ goto done;
+
+ printf("Integrated %s into %s\n", refname, base_refname);
+done:
if (repo)
got_repo_close(repo);
+ if (worktree)
+ got_worktree_close(worktree);
+ free(cwd);
+ free(base_commit_id);
+ free(commit_id);
+ free(refname);
+ free(base_refname);
return error;
}
blob - f8e9822b47d297dd837ffbfe9f018be2143c3b44
blob + f1c654737061914c1e6789930e5d84be5117070c
--- include/got_error.h
+++ include/got_error.h
#define GOT_ERR_COMMIT_NO_EMAIL 108
#define GOT_ERR_TAG_EXISTS 109
#define GOT_ERR_GIT_REPO_FORMAT 110
+#define GOT_ERR_REBASE_REQUIRED 111
static const struct got_error {
int code;
"with Git" },
{ GOT_ERR_TAG_EXISTS,"specified tag already exists" },
{ GOT_ERR_GIT_REPO_FORMAT,"unknown git repository format version" },
+ { GOT_ERR_REBASE_REQUIRED,"specified branch must be rebased first" },
};
/*
blob - 096c4e4ceac795c28e6da4fba2b9be6fd783015b
blob + add6c8aa88f249f82d6451270fc7c7c6952abc9b
--- include/got_worktree.h
+++ include/got_worktree.h
const struct got_error *got_worktree_get_histedit_script_path(char **,
struct got_worktree *);
+/*
+ * Prepare a work tree for integrating a branch.
+ * Return pointers to a fileindex and locked references which must be
+ * passed back to other integrate-related functions.
+ */
+const struct got_error *
+got_worktree_integrate_prepare(struct got_fileindex **,
+ struct got_reference **, struct got_reference **,
+ struct got_worktree *, const char *, struct got_repository *);
/*
+ * Carry out a prepared branch integration operation.
+ * Report affected files via the specified progress callback.
+ */
+const struct got_error *got_worktree_integrate_continue(
+ struct got_worktree *, struct got_fileindex *, struct got_repository *,
+ struct got_reference *, struct got_reference *,
+ got_worktree_checkout_cb, void *, got_cancel_cb, void *);
+
+/* Abort a prepared branch integration operation. */
+const struct got_error *got_worktree_integrate_abort(struct got_worktree *,
+ struct got_fileindex *, struct got_repository *,
+ struct got_reference *, struct got_reference *);
+
+/*
* Stage the specified paths for commit.
* If the patch callback is not NULL, call it to select patch hunks for
* staging. Otherwise, stage the full file content found at each path.
blob - d7dc1224936d7d6588be61fac9a25737e3bc8965
blob + 35d6705944c9ba45ca47f53a0109f5cc466e5957
--- lib/worktree.c
+++ lib/worktree.c
err = delete_ref(commit_ref_name, repo);
done:
free(commit_ref_name);
+ return err;
+}
+
+const struct got_error *
+got_worktree_integrate_prepare(struct got_fileindex **fileindex,
+ struct got_reference **branch_ref, struct got_reference **base_branch_ref,
+ struct got_worktree *worktree, const char *refname,
+ struct got_repository *repo)
+{
+ const struct got_error *err = NULL;
+ char *fileindex_path = NULL;
+ struct check_rebase_ok_arg ok_arg;
+
+ *fileindex = NULL;
+ *branch_ref = NULL;
+ *base_branch_ref = NULL;
+
+ err = lock_worktree(worktree, LOCK_EX);
+ if (err)
+ return err;
+
+ if (strcmp(refname, got_worktree_get_head_ref_name(worktree)) == 0) {
+ err = got_error_msg(GOT_ERR_SAME_BRANCH,
+ "cannot integrate a branch into itself; "
+ "update -b or different branch name required");
+ goto done;
+ }
+
+ err = open_fileindex(fileindex, &fileindex_path, worktree);
+ if (err)
+ goto done;
+
+ /* Preconditions are the same as for rebase. */
+ ok_arg.worktree = worktree;
+ ok_arg.repo = repo;
+ err = got_fileindex_for_each_entry_safe(*fileindex, check_rebase_ok,
+ &ok_arg);
+ if (err)
+ goto done;
+
+ err = got_ref_open(branch_ref, repo, refname, 1);
+ if (err)
+ goto done;
+
+ err = got_ref_open(base_branch_ref, repo,
+ got_worktree_get_head_ref_name(worktree), 1);
+done:
+ if (err) {
+ if (*branch_ref) {
+ got_ref_close(*branch_ref);
+ *branch_ref = NULL;
+ }
+ if (*base_branch_ref) {
+ got_ref_close(*base_branch_ref);
+ *base_branch_ref = NULL;
+ }
+ if (*fileindex) {
+ got_fileindex_free(*fileindex);
+ *fileindex = NULL;
+ }
+ lock_worktree(worktree, LOCK_SH);
+ }
return err;
}
+const struct got_error *
+got_worktree_integrate_continue(struct got_worktree *worktree,
+ struct got_fileindex *fileindex, struct got_repository *repo,
+ struct got_reference *branch_ref, struct got_reference *base_branch_ref,
+ got_worktree_checkout_cb progress_cb, void *progress_arg,
+ got_cancel_cb cancel_cb, void *cancel_arg)
+{
+ const struct got_error *err = NULL, *sync_err, *unlockerr;
+ char *fileindex_path = NULL;
+ struct got_object_id *tree_id = NULL, *commit_id = NULL;
+
+ err = get_fileindex_path(&fileindex_path, worktree);
+ if (err)
+ goto done;
+
+ err = got_ref_resolve(&commit_id, repo, branch_ref);
+ if (err)
+ goto done;
+
+ err = got_object_id_by_path(&tree_id, repo, commit_id,
+ worktree->path_prefix);
+ if (err)
+ goto done;
+
+ err = got_worktree_set_base_commit_id(worktree, repo, commit_id);
+ if (err)
+ goto done;
+
+ err = checkout_files(worktree, fileindex, "", tree_id, NULL, repo,
+ progress_cb, progress_arg, cancel_cb, cancel_arg);
+ if (err)
+ goto sync;
+
+ err = got_ref_change_ref(base_branch_ref, commit_id);
+ if (err)
+ goto sync;
+
+ err = got_ref_write(base_branch_ref, repo);
+sync:
+ sync_err = sync_fileindex(fileindex, fileindex_path);
+ if (sync_err && err == NULL)
+ err = sync_err;
+
+done:
+ unlockerr = got_ref_unlock(branch_ref);
+ if (unlockerr && err == NULL)
+ err = unlockerr;
+ got_ref_close(branch_ref);
+
+ unlockerr = got_ref_unlock(base_branch_ref);
+ if (unlockerr && err == NULL)
+ err = unlockerr;
+ got_ref_close(base_branch_ref);
+
+ got_fileindex_free(fileindex);
+ free(fileindex_path);
+ free(tree_id);
+
+ unlockerr = lock_worktree(worktree, LOCK_SH);
+ if (unlockerr && err == NULL)
+ err = unlockerr;
+ return err;
+}
+
+const struct got_error *
+got_worktree_integrate_abort(struct got_worktree *worktree,
+ struct got_fileindex *fileindex, struct got_repository *repo,
+ struct got_reference *branch_ref, struct got_reference *base_branch_ref)
+{
+ got_ref_close(branch_ref);
+ got_ref_close(base_branch_ref);
+ got_fileindex_free(fileindex);
+ return lock_worktree(worktree, LOCK_SH);
+}
+
struct check_stage_ok_arg {
struct got_object_id *head_commit_id;
struct got_worktree *worktree;
blob - 535e0b8450f2e076c694aaae464ec319797b783f
blob + 65f8a62feba0842c2e9667e380c20958719414c8
--- regress/cmdline/Makefile
+++ regress/cmdline/Makefile
REGRESS_TARGETS=checkout update status log add rm diff blame branch tag \
- ref commit revert cherrypick backout rebase import histedit stage \
- unstage cat
+ ref commit revert cherrypick backout rebase import histedit \
+ integrate stage unstage cat
NOOBJ=Yes
checkout:
histedit:
./histedit.sh
+integrate:
+ ./integrate.sh
+
stage:
./stage.sh
blob - /dev/null
blob + 86d2fa9ed1614f01bad8d546d2b87b57266c3147 (mode 644)
--- /dev/null
+++ regress/cmdline/integrate.sh
+#!/bin/sh
+#
+# Copyright (c) 2019 Stefan Sperling <stsp@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+. ./common.sh
+
+function test_integrate_basic {
+ local testroot=`test_init integrate_basic`
+
+ (cd $testroot/repo && git checkout -q -b newbranch)
+ echo "modified delta on branch" > $testroot/repo/gamma/delta
+ git_commit $testroot/repo -m "committing to delta on newbranch"
+
+ echo "modified alpha on branch" > $testroot/repo/alpha
+ (cd $testroot/repo && git rm -q beta)
+ echo "new file on branch" > $testroot/repo/epsilon/new
+ (cd $testroot/repo && git add epsilon/new)
+ git_commit $testroot/repo -m "committing more changes on newbranch"
+
+ local orig_commit1=`git_show_parent_commit $testroot/repo`
+ local orig_commit2=`git_show_head $testroot/repo`
+
+ (cd $testroot/repo && git checkout -q master)
+ echo "modified zeta on master" > $testroot/repo/epsilon/zeta
+ git_commit $testroot/repo -m "committing to zeta on master"
+ local master_commit=`git_show_head $testroot/repo`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got rebase newbranch > /dev/null)
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got rebase failed unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/repo && git checkout -q newbranch)
+ local new_commit1=`git_show_parent_commit $testroot/repo`
+ local new_commit2=`git_show_head $testroot/repo`
+
+ (cd $testroot/wt && got update -b master > /dev/null)
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got update failed unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got integrate newbranch > $testroot/stdout)
+
+ echo "U alpha" > $testroot/stdout.expected
+ echo "D beta" >> $testroot/stdout.expected
+ echo "A epsilon/new" >> $testroot/stdout.expected
+ echo "U gamma/delta" >> $testroot/stdout.expected
+ echo "Integrated refs/heads/newbranch into refs/heads/master" \
+ >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "modified delta on branch" > $testroot/content.expected
+ cat $testroot/wt/gamma/delta > $testroot/content
+ cmp -s $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/content.expected $testroot/content
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "modified alpha on branch" > $testroot/content.expected
+ cat $testroot/wt/alpha > $testroot/content
+ cmp -s $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/content.expected $testroot/content
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ if [ -e $testroot/wt/beta ]; then
+ echo "removed file beta still exists on disk" >&2
+ test_done "$testroot" "1"
+ return 1
+ fi
+
+ echo "new file on branch" > $testroot/content.expected
+ cat $testroot/wt/epsilon/new > $testroot/content
+ cmp -s $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/content.expected $testroot/content
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got status > $testroot/stdout)
+
+ echo -n > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got log -l3 | grep ^commit > $testroot/stdout)
+ echo "commit $new_commit2 (master, newbranch)" \
+ > $testroot/stdout.expected
+ echo "commit $new_commit1" >> $testroot/stdout.expected
+ echo "commit $master_commit" >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
+function test_integrate_requires_rebase_first {
+ local testroot=`test_init integrate_requires_rebase_first`
+ local init_commit=`git_show_head $testroot/repo`
+
+ (cd $testroot/repo && git checkout -q -b newbranch)
+ echo "modified delta on branch" > $testroot/repo/gamma/delta
+ git_commit $testroot/repo -m "committing to delta on newbranch"
+
+ echo "modified alpha on branch" > $testroot/repo/alpha
+ (cd $testroot/repo && git rm -q beta)
+ echo "new file on branch" > $testroot/repo/epsilon/new
+ (cd $testroot/repo && git add epsilon/new)
+ git_commit $testroot/repo -m "committing more changes on newbranch"
+
+ local orig_commit1=`git_show_parent_commit $testroot/repo`
+ local orig_commit2=`git_show_head $testroot/repo`
+
+ (cd $testroot/repo && git checkout -q master)
+ echo "modified zeta on master" > $testroot/repo/epsilon/zeta
+ git_commit $testroot/repo -m "committing to zeta on master"
+ local master_commit=`git_show_head $testroot/repo`
+
+ (cd $testroot/repo && git checkout -q newbranch)
+ local new_commit1=`git_show_parent_commit $testroot/repo`
+ local new_commit2=`git_show_head $testroot/repo`
+
+ got checkout -b master $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got integrate newbranch \
+ > $testroot/stdout 2> $testroot/stderr)
+ ret="$?"
+ if [ "$ret" == "0" ]; then
+ echo "got integrate succeeded unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo -n > $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "got: specified branch must be rebased first" \
+ > $testroot/stderr.expected
+ cmp -s $testroot/stderr.expected $testroot/stderr
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stderr.expected $testroot/stderr
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/repo && got log -c master | \
+ grep ^commit > $testroot/stdout)
+ echo "commit $master_commit (master)" > $testroot/stdout.expected
+ echo "commit $init_commit" >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/repo && got log -c newbranch | \
+ grep ^commit > $testroot/stdout)
+ echo "commit $new_commit2 (newbranch)" \
+ > $testroot/stdout.expected
+ echo "commit $new_commit1" >> $testroot/stdout.expected
+ echo "commit $init_commit" >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
+function test_integrate_path_prefix {
+ local testroot=`test_init integrate_path_prefix`
+
+ (cd $testroot/repo && git checkout -q -b newbranch)
+ echo "modified delta on branch" > $testroot/repo/gamma/delta
+ git_commit $testroot/repo -m "committing to delta on newbranch"
+
+ echo "modified alpha on branch" > $testroot/repo/alpha
+ (cd $testroot/repo && git rm -q beta)
+ echo "new file on branch" > $testroot/repo/epsilon/new
+ (cd $testroot/repo && git add epsilon/new)
+ git_commit $testroot/repo -m "committing more changes on newbranch"
+
+ local orig_commit1=`git_show_parent_commit $testroot/repo`
+ local orig_commit2=`git_show_head $testroot/repo`
+
+ (cd $testroot/repo && git checkout -q master)
+ echo "modified zeta on master" > $testroot/repo/epsilon/zeta
+ git_commit $testroot/repo -m "committing to zeta on master"
+ local master_commit=`git_show_head $testroot/repo`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got rebase newbranch > /dev/null)
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got rebase failed unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/repo && git checkout -q newbranch)
+ local new_commit1=`git_show_parent_commit $testroot/repo`
+ local new_commit2=`git_show_head $testroot/repo`
+
+ rm -r $testroot/wt
+ got checkout -b master -p epsilon $testroot/repo $testroot/wt \
+ > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got checkout failed unexpectedly"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ (cd $testroot/wt && got integrate newbranch > $testroot/stdout)
+
+ echo "A new" > $testroot/stdout.expected
+ echo "Integrated refs/heads/newbranch into refs/heads/master" \
+ >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
+
+run_test test_integrate_basic
+run_test test_integrate_requires_rebase_first
+run_test test_integrate_path_prefix