mirror of
https://github.com/dolthub/dolt.git
synced 2026-03-09 11:19:01 -05:00
Vinai/dolt merge p2 (#1322)
Adds addition functionality to DOLT_MERGE beyond just ffs
This commit is contained in:
@@ -51,6 +51,21 @@ teardown() {
|
||||
[[ "$output" =~ "$regex" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_ADD all w/ . combined with DOLT_COMMIT -a works" {
|
||||
run dolt sql -q "SELECT DOLT_ADD('.')"
|
||||
run dolt sql -q "SELECT DOLT_COMMIT('-a', '-m', 'Commit1')"
|
||||
|
||||
# Check that everything was added
|
||||
run dolt diff
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "" ]
|
||||
|
||||
run dolt log
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "Commit1" ]] || false
|
||||
[[ "$output" =~ "Bats Tests <bats@email.fake>" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_ADD can take in one table" {
|
||||
run dolt sql -q "SELECT DOLT_ADD('test')"
|
||||
run dolt sql -q "SELECT DOLT_COMMIT('-m', 'Commit1')"
|
||||
@@ -68,7 +83,6 @@ teardown() {
|
||||
[[ "$output" =~ "$regex" ]] || false
|
||||
}
|
||||
|
||||
|
||||
@test "DOLT_ADD can take in multiple tables" {
|
||||
run dolt sql -q "SELECT DOLT_ADD('test', 'test2')"
|
||||
run dolt sql -q "SELECT DOLT_COMMIT('-m', 'Commit1')"
|
||||
|
||||
@@ -158,6 +158,39 @@ SQL
|
||||
[[ ! "$output" =~ "4" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_CHECKOUT between branches operating on the same table works." {
|
||||
run dolt sql << SQL
|
||||
CREATE TABLE one_pk (
|
||||
pk1 BIGINT NOT NULL,
|
||||
c1 BIGINT,
|
||||
c2 BIGINT,
|
||||
PRIMARY KEY (pk1)
|
||||
);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'add tables');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
INSERT INTO one_pk (pk1,c1,c2) VALUES (0,0,0);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'changed master');
|
||||
SELECT DOLT_CHECKOUT('feature-branch');
|
||||
INSERT INTO one_pk (pk1,c1,c2) VALUES (0,1,1);
|
||||
SQL
|
||||
[ $status -eq 0 ]
|
||||
|
||||
run dolt sql -q "SELECT * FROM one_pk" -r csv
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "pk1,c1,c2" ]] || false
|
||||
[[ "$output" =~ "0,1,1" ]] || false
|
||||
[[ ! "$output" =~ "0,0,0" ]] || false
|
||||
|
||||
dolt commit -a -m "changed feature branch"
|
||||
dolt checkout master
|
||||
run dolt sql -q "SELECT * FROM one_pk" -r csv
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "pk1,c1,c2" ]] || false
|
||||
[[ ! "$output" =~ "0,1,1" ]] || false
|
||||
[[ "$output" =~ "0,0,0" ]] || false
|
||||
}
|
||||
|
||||
get_head_commit() {
|
||||
dolt log -n 1 | grep -m 1 commit | cut -c 8-
|
||||
}
|
||||
|
||||
@@ -17,6 +17,13 @@ teardown() {
|
||||
teardown_common
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE with unknown branch name throws an error" {
|
||||
dolt sql -q "SELECT DOLT_COMMIT('-a', '-m', 'Step 1');"
|
||||
|
||||
run dolt sql -q "SELECT DOLT_MERGE('feature-branch');"
|
||||
[ $status -eq 1 ]
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE works with ff" {
|
||||
dolt sql << SQL
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Step 1');
|
||||
@@ -37,9 +44,9 @@ SQL
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "3" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT COUNT(*) FROM test;"
|
||||
run dolt status
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "4" ]] || false
|
||||
[[ "$output" =~ "nothing to commit, working tree clean" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT * FROM test;" -r csv
|
||||
[ $status -eq 0 ]
|
||||
@@ -48,6 +55,10 @@ SQL
|
||||
[[ "$output" =~ "2" ]] || false
|
||||
[[ "$output" =~ "3" ]] || false
|
||||
[[ "$output" =~ "1000" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT COUNT(*) FROM test;" -r csv
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "4" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE correctly returns head and working session variables." {
|
||||
@@ -70,13 +81,371 @@ SQL
|
||||
[[ "$output" =~ $head_hash ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE with unknown branch name name throws an error" {
|
||||
dolt sql -q "SELECT DOLT_COMMIT('-a', '-m', 'Step 1');"
|
||||
@test "DOLT_MERGE correctly merges branches with differing content in same table without conflicts" {
|
||||
dolt sql << SQL
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Step 1');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
INSERT INTO test VALUES (3);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Insert 3');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
INSERT INTO test VALUES (500000);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Insert 500000');
|
||||
SELECT DOLT_MERGE('feature-branch');
|
||||
SQL
|
||||
|
||||
run dolt sql -q "SELECT * FROM test" -r csv
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "pk" ]] || false
|
||||
[[ "$output" =~ "0" ]] || false
|
||||
[[ "$output" =~ "1" ]] || false
|
||||
[[ "$output" =~ "2" ]] || false
|
||||
[[ "$output" =~ "3" ]] || false
|
||||
[[ "$output" =~ "500000" ]] || false
|
||||
|
||||
run dolt log -n 1
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "Insert 500000" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT COUNT(*) FROM dolt_log"
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "3" ]] || false
|
||||
|
||||
run dolt status
|
||||
[[ "$output" =~ "All conflicts fixed but you are still merging" ]] || false
|
||||
[[ "$output" =~ "Changes to be committed:" ]] || false
|
||||
[[ "$output" =~ ([[:space:]]*modified:[[:space:]]*test) ]] || false
|
||||
|
||||
run dolt sql -q "SELECT DOLT_COMMIT('-a', '-m', 'Finish up Merge')";
|
||||
[ $status -eq 0 ]
|
||||
|
||||
run dolt status
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "nothing to commit, working tree clean" ]] || false
|
||||
|
||||
run dolt log -n 1
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "Finish up Merge" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE works with no-ff" {
|
||||
run dolt sql << SQL
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Step 1');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
INSERT INTO test VALUES (3);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'update feature-branch');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
SELECT DOLT_MERGE('feature-branch', '-no-ff', '-m', 'this is a no-ff');
|
||||
SQL
|
||||
[ $status -eq 0 ]
|
||||
|
||||
run dolt log -n 1
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "this is a no-ff" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT COUNT(*) FROM dolt_log"
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "4" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE -no-ff correctly changes head and working session variables." {
|
||||
dolt sql << SQL
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Step 1');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
INSERT INTO test VALUES (3);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'update feature-branch');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
SQL
|
||||
head_variable=@@dolt_repo_$$_head
|
||||
head_hash=$(get_head_commit)
|
||||
working_variable=@@dolt_repo_$$_working
|
||||
working_hash=$(get_working_hash)
|
||||
|
||||
run dolt sql -q "SELECT DOLT_MERGE('feature-branch', '-no-ff', '-m', 'this is a no-ff');"
|
||||
[ $status -eq 0 ]
|
||||
|
||||
run dolt sql -q "SELECT $head_variable"
|
||||
[ $status -eq 0 ]
|
||||
[[ ! "$output" =~ $head_hash ]] || false
|
||||
|
||||
run dolt sql -q "SELECT $working_variable"
|
||||
[ $status -eq 0 ]
|
||||
[[ ! "$output" =~ $working_hash ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE properly detects merge conflicts, returns and error and then aborts." {
|
||||
run dolt sql << SQL
|
||||
CREATE TABLE one_pk (
|
||||
pk1 BIGINT NOT NULL,
|
||||
c1 BIGINT,
|
||||
c2 BIGINT,
|
||||
PRIMARY KEY (pk1)
|
||||
);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'add tables');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
INSERT INTO one_pk (pk1,c1,c2) VALUES (0,0,0);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'changed master');
|
||||
SELECT DOLT_CHECKOUT('feature-branch');
|
||||
INSERT INTO one_pk (pk1,c1,c2) VALUES (0,1,1);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'changed feature branch');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
SELECT DOLT_MERGE('feature-branch');
|
||||
SQL
|
||||
[ $status -eq 1 ]
|
||||
[[ $output =~ "merge has conflicts" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT DOLT_MERGE('--abort');"
|
||||
[ $status -eq 0 ]
|
||||
|
||||
run dolt status
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "nothing to commit, working tree clean" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT * FROM one_pk;" -r csv
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "pk1,c1,c2" ]] || false
|
||||
[[ "$output" =~ "0,0,0" ]] || false
|
||||
[[ ! "$output" =~ "0,1,1" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE properly detects merge conflicts and renders the conflicts in dolt_conflicts." {
|
||||
run dolt sql << SQL
|
||||
CREATE TABLE one_pk (
|
||||
pk1 BIGINT NOT NULL,
|
||||
c1 BIGINT,
|
||||
c2 BIGINT,
|
||||
PRIMARY KEY (pk1)
|
||||
);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'add tables');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
INSERT INTO one_pk (pk1,c1,c2) VALUES (0,0,0);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'changed master');
|
||||
SELECT DOLT_CHECKOUT('feature-branch');
|
||||
INSERT INTO one_pk (pk1,c1,c2) VALUES (0,1,1);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'changed feature branch');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
SELECT DOLT_MERGE('feature-branch');
|
||||
SQL
|
||||
[ $status -eq 1 ]
|
||||
[[ $output =~ "merge has conflicts" ]] || false
|
||||
|
||||
run dolt status
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "On branch master" ]] || false
|
||||
[[ "$output" =~ "You have unmerged tables" ]] || false
|
||||
[[ "$output" =~ ([[:space:]]*both modified:[[:space:]]*one_pk) ]] || false
|
||||
|
||||
run dolt sql -q "SELECT * FROM dolt_conflicts" -r csv
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "table,num_conflicts" ]] || false
|
||||
[[ "$output" =~ "one_pk,1" ]] || false
|
||||
|
||||
# Go through the process of resolving commits
|
||||
run dolt sql << SQL
|
||||
REPLACE INTO one_pk (pk1, c1, c2) SELECT their_pk1, their_c1, their_c2 FROM dolt_conflicts_one_pk WHERE their_pk1 IS NOT NULL;
|
||||
DELETE FROM one_pk WHERE pk1 in (SELECT base_pk1 FROM dolt_conflicts_one_pk WHERE their_pk1 IS NULL);
|
||||
DELETE FROM dolt_conflicts_one_pk;
|
||||
SQL
|
||||
[ $status -eq 0 ]
|
||||
|
||||
run dolt sql -q "SELECT * FROM dolt_conflicts" -r csv
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "table,num_conflicts" ]] || false
|
||||
[[ "$output" =~ "one_pk,0" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT DOLT_COMMIT('-a', '-m', 'Finish Resolving');"
|
||||
[ $status -eq 0 ]
|
||||
|
||||
run dolt sql -q "SELECT * FROM one_pk" -r csv
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "pk1,c1,c2" ]] || false
|
||||
[[ "$output" =~ "0,1,1" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT COUNT(*) from dolt_status;"
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "0" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE with unresolved conflicts throws an error" {
|
||||
run dolt sql << SQL
|
||||
CREATE TABLE one_pk (
|
||||
pk1 BIGINT NOT NULL,
|
||||
c1 BIGINT,
|
||||
c2 BIGINT,
|
||||
PRIMARY KEY (pk1)
|
||||
);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'add tables');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
INSERT INTO one_pk (pk1,c1,c2) VALUES (0,0,0);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'changed master');
|
||||
SELECT DOLT_CHECKOUT('feature-branch');
|
||||
INSERT INTO one_pk (pk1,c1,c2) VALUES (0,1,1);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'changed feature branch');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
SELECT DOLT_MERGE('feature-branch');
|
||||
SQL
|
||||
[ $status -eq 1 ]
|
||||
[[ $output =~ "merge has conflicts" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT DOLT_MERGE('feature-branch');"
|
||||
[ $status -eq 1 ]
|
||||
[[ $output =~ "merge has unresolved conflicts" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE during an active merge throws an error" {
|
||||
run dolt sql << SQL
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Step 1');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
INSERT INTO test VALUES (3);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Insert 3');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
INSERT INTO test VALUES (500000);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Insert 500000');
|
||||
SELECT DOLT_MERGE('feature-branch');
|
||||
SELECT DOLT_MERGE('feature-branch');
|
||||
SQL
|
||||
|
||||
[ $status -eq 1 ]
|
||||
[[ $output =~ "merging is not possible because you have not committed an active merge" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE works with ff and squash" {
|
||||
dolt sql << SQL
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Step 1');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
INSERT INTO test VALUES (3);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'this is a ff');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
SQL
|
||||
run dolt sql -q "SELECT DOLT_MERGE('feature-branch', '--squash');"
|
||||
[ $status -eq 0 ]
|
||||
|
||||
run dolt log -n 1
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "Step 1" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT COUNT(*) FROM dolt_log"
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "2" ]] || false
|
||||
|
||||
run dolt status
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "On branch master" ]] || false
|
||||
[[ "$output" =~ "Changes to be committed:" ]] || false
|
||||
[[ "$output" =~ ([[:space:]]*modified:[[:space:]]*test) ]] || false
|
||||
|
||||
run dolt sql -q "SELECT DOLT_COMMIT('-a', '-m', 'hi');"
|
||||
[ $status -eq 0 ]
|
||||
|
||||
run dolt status
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "nothing to commit, working tree clean" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE with no-ff and squash works." {
|
||||
dolt sql << SQL
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Step 1');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
INSERT INTO test VALUES (3);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Insert 3');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
INSERT INTO test VALUES (500000);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Insert 500000');
|
||||
SELECT DOLT_MERGE('feature-branch', '--squash');
|
||||
SQL
|
||||
|
||||
run dolt status
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "On branch master" ]] || false
|
||||
[[ "$output" =~ "Changes to be committed:" ]] || false
|
||||
[[ "$output" =~ ([[:space:]]*modified:[[:space:]]*test) ]] || false
|
||||
|
||||
run dolt sql -q "SELECT DOLT_COMMIT('-a', '-m', 'Finish up Merge')";
|
||||
[ $status -eq 0 ]
|
||||
|
||||
run dolt status
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "nothing to commit, working tree clean" ]] || false
|
||||
|
||||
run dolt log -n 1
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "Finish up Merge" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE throws errors with working set changes." {
|
||||
run dolt sql << SQL
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Step 1');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
INSERT INTO test VALUES (3);
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'this is a ff');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
CREATE TABLE tbl (
|
||||
pk int primary key
|
||||
);
|
||||
SELECT DOLT_MERGE('feature-branch');
|
||||
SQL
|
||||
[ $status -eq 1 ]
|
||||
[[ "$output" =~ "cannot merge with uncommitted changes" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE with a long series of changing operations works." {
|
||||
dolt sql << SQL
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Step 1');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
INSERT INTO test VALUES (3);
|
||||
INSERT INTO test VALUES (4);
|
||||
INSERT INTO test VALUES (21232);
|
||||
DELETE FROM test WHERE pk=4;
|
||||
UPDATE test SET pk=21 WHERE pk=21232;
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Insert 3');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
INSERT INTO test VALUES (500000);
|
||||
INSERT INTO test VALUES (500001);
|
||||
DELETE FROM test WHERE pk=500001;
|
||||
UPDATE test SET pk=60 WHERE pk=500000;
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Insert 60');
|
||||
SELECT DOLT_MERGE('feature-branch');
|
||||
SQL
|
||||
|
||||
|
||||
run dolt status
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "On branch master" ]] || false
|
||||
[[ "$output" =~ "Changes to be committed:" ]] || false
|
||||
[[ "$output" =~ ([[:space:]]*modified:[[:space:]]*test) ]] || false
|
||||
|
||||
run dolt sql -q "SELECT DOLT_COMMIT('-a', '-m', 'Finish up Merge')";
|
||||
[ $status -eq 0 ]
|
||||
|
||||
run dolt status
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "nothing to commit, working tree clean" ]] || false
|
||||
|
||||
run dolt log -n 1
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "Finish up Merge" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT * FROM test;" -r csv
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "pk" ]] || false
|
||||
[[ "$output" =~ "0" ]] || false
|
||||
[[ "$output" =~ "1" ]] || false
|
||||
[[ "$output" =~ "2" ]] || false
|
||||
[[ "$output" =~ "3" ]] || false
|
||||
[[ "$output" =~ "21" ]] || false
|
||||
[[ "$output" =~ "60" ]] || false
|
||||
|
||||
run dolt sql -q "SELECT COUNT(*) FROM test;" -r csv
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "6" ]] || false
|
||||
}
|
||||
|
||||
get_head_commit() {
|
||||
dolt log -n 1 | grep -m 1 commit | cut -c 8-
|
||||
}
|
||||
|
||||
get_working_hash() {
|
||||
dolt sql -q "select @@dolt_repo_$$_working" | sed -n 4p | sed -e 's/|//' -e 's/|//' -e 's/ //'
|
||||
}
|
||||
|
||||
@@ -438,4 +438,85 @@ SQL
|
||||
|
||||
server_query 1 "SELECT * FROM repo1.r1_one_pk" "pk,c1,c2\n1,1,1\n2,2,2\n3,3,3"
|
||||
server_query 1 "SELECT * FROM repo2.r2_one_pk" "pk,c3,c4\n1,1,1\n2,2,2\n3,3,3"
|
||||
}
|
||||
|
||||
@test "DOLT_ADD, DOLT_COMMIT, DOLT_CHECKOUT, DOLT_MERGE work together in server mode" {
|
||||
skiponwindows "Has dependencies that are missing on the Jenkins Windows installation."
|
||||
|
||||
cd repo1
|
||||
start_sql_server repo1
|
||||
|
||||
|
||||
multi_query 1 "
|
||||
CREATE TABLE test (
|
||||
pk int primary key
|
||||
);
|
||||
INSERT INTO test VALUES (0),(1),(2);
|
||||
SELECT DOLT_ADD('.');
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Step 1');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
"
|
||||
|
||||
server_query 1 "SELECT * FROM test" "pk\n0\n1\n2"
|
||||
run dolt branch
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "* feature-branch" ]] || false
|
||||
|
||||
multi_query 1 "
|
||||
INSERT INTO test VALUES (3);
|
||||
INSERT INTO test VALUES (4);
|
||||
INSERT INTO test VALUES (21232);
|
||||
DELETE FROM test WHERE pk=4;
|
||||
UPDATE test SET pk=21 WHERE pk=21232;
|
||||
"
|
||||
server_query 1 "SELECT * FROM test" "pk\n0\n1\n2\n3\n21"
|
||||
|
||||
multi_query 1 "
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Insert 3');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
"
|
||||
server_query 1 "SELECT * FROM test" "pk\n0\n1\n2"
|
||||
|
||||
multi_query 1 "
|
||||
INSERT INTO test VALUES (500000);
|
||||
INSERT INTO test VALUES (500001);
|
||||
DELETE FROM test WHERE pk=500001;
|
||||
UPDATE test SET pk=60 WHERE pk=500000;
|
||||
SELECT DOLT_ADD('.');
|
||||
SELECT DOLT_COMMIT('-m', 'Insert 60');
|
||||
SELECT DOLT_MERGE('feature-branch');
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'Finish up Merge');
|
||||
"
|
||||
server_query 1 "SELECT * FROM test" "pk\n0\n1\n2\n3\n21\n60"
|
||||
|
||||
run dolt status
|
||||
[ $status -eq 0 ]
|
||||
[[ "$output" =~ "nothing to commit, working tree clean" ]] || false
|
||||
}
|
||||
|
||||
@test "DOLT_MERGE ff works" {
|
||||
skiponwindows "Has dependencies that are missing on the Jenkins Windows installation."
|
||||
|
||||
cd repo1
|
||||
start_sql_server repo1
|
||||
|
||||
|
||||
multi_query 1 "
|
||||
CREATE TABLE test (
|
||||
pk int primary key
|
||||
);
|
||||
INSERT INTO test VALUES (0),(1),(2);
|
||||
SELECT DOLT_ADD('.');
|
||||
SELECT DOLT_COMMIT('-m', 'Step 1');
|
||||
SELECT DOLT_CHECKOUT('-b', 'feature-branch');
|
||||
INSERT INTO test VALUES (3);
|
||||
UPDATE test SET pk=1000 WHERE pk=0;
|
||||
SELECT DOLT_COMMIT('-a', '-m', 'this is a ff');
|
||||
SELECT DOLT_CHECKOUT('master');
|
||||
SELECT DOLT_MERGE('feature-branch');
|
||||
"
|
||||
|
||||
server_query 1 "SELECT * FROM test" "pk\n1\n2\n3\n1000"
|
||||
|
||||
server_query 1 "SELECT COUNT(*) FROM dolt_log" "COUNT(*)\n3"
|
||||
}
|
||||
@@ -82,8 +82,15 @@ const (
|
||||
SoftResetParam = "soft"
|
||||
CheckoutCoBranch = "b"
|
||||
NoFFParam = "no-ff"
|
||||
SquashParam = "squash"
|
||||
AbortParam = "abort"
|
||||
)
|
||||
|
||||
var mergeAbortDetails = `Abort the current conflict resolution process, and try to reconstruct the pre-merge state.
|
||||
|
||||
If there were uncommitted working set changes present when the merge started, {{.EmphasisLeft}}dolt merge --abort{{.EmphasisRight}} will be unable to reconstruct these changes. It is therefore recommended to always commit or stash your changes before running dolt merge.
|
||||
`
|
||||
|
||||
// Creates the argparser shared dolt commit cli and DOLT_COMMIT.
|
||||
func CreateCommitArgParser() *argparser.ArgParser {
|
||||
ap := argparser.NewArgParser()
|
||||
@@ -99,6 +106,9 @@ func CreateCommitArgParser() *argparser.ArgParser {
|
||||
func CreateMergeArgParser() *argparser.ArgParser {
|
||||
ap := argparser.NewArgParser()
|
||||
ap.SupportsFlag(NoFFParam, "", "Create a merge commit even when the merge resolves as a fast-forward.")
|
||||
ap.SupportsFlag(SquashParam, "", "Merges changes to the working set without updating the commit history")
|
||||
ap.SupportsString(CommitMessageArg, "m", "msg", "Use the given {{.LessThan}}msg{{.GreaterThan}} as the commit message.")
|
||||
ap.SupportsFlag(AbortParam, "", mergeAbortDetails)
|
||||
return ap
|
||||
}
|
||||
|
||||
|
||||
@@ -34,12 +34,6 @@ import (
|
||||
"github.com/dolthub/dolt/go/store/hash"
|
||||
)
|
||||
|
||||
const (
|
||||
abortParam = "abort"
|
||||
squashParam = "squash"
|
||||
noFFParam = "no-ff"
|
||||
)
|
||||
|
||||
var mergeDocs = cli.CommandDocumentationContent{
|
||||
ShortDesc: "Join two or more development histories together",
|
||||
LongDesc: `Incorporates changes from the named commits (since the time their histories diverged from the current branch) into the current branch.
|
||||
@@ -56,11 +50,6 @@ The second syntax ({{.LessThan}}dolt merge --abort{{.GreaterThan}}) can only be
|
||||
},
|
||||
}
|
||||
|
||||
var abortDetails = `Abort the current conflict resolution process, and try to reconstruct the pre-merge state.
|
||||
|
||||
If there were uncommitted working set changes present when the merge started, {{.EmphasisLeft}}dolt merge --abort{{.EmphasisRight}} will be unable to reconstruct these changes. It is therefore recommended to always commit or stash your changes before running dolt merge.
|
||||
`
|
||||
|
||||
type MergeCmd struct{}
|
||||
|
||||
// Name is returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
|
||||
@@ -75,19 +64,10 @@ func (cmd MergeCmd) Description() string {
|
||||
|
||||
// CreateMarkdown creates a markdown file containing the helptext for the command at the given path
|
||||
func (cmd MergeCmd) CreateMarkdown(fs filesys.Filesys, path, commandStr string) error {
|
||||
ap := cmd.createArgParser()
|
||||
ap := cli.CreateMergeArgParser()
|
||||
return CreateMarkdown(fs, path, cli.GetCommandDocumentation(commandStr, mergeDocs, ap))
|
||||
}
|
||||
|
||||
func (cmd MergeCmd) createArgParser() *argparser.ArgParser {
|
||||
ap := argparser.NewArgParser()
|
||||
ap.SupportsFlag(abortParam, "", abortDetails)
|
||||
ap.SupportsFlag(squashParam, "", "Merges changes to the working set without updating the commit history")
|
||||
ap.SupportsFlag(noFFParam, "", "Create a merge commit even when the merge resolves as a fast-forward.")
|
||||
ap.SupportsString(cli.CommitMessageArg, "m", "msg", "Use the given {{.LessThan}}msg{{.GreaterThan}} as the commit message.")
|
||||
return ap
|
||||
}
|
||||
|
||||
// EventType returns the type of the event to log
|
||||
func (cmd MergeCmd) EventType() eventsapi.ClientEventType {
|
||||
return eventsapi.ClientEventType_MERGE
|
||||
@@ -95,17 +75,17 @@ func (cmd MergeCmd) EventType() eventsapi.ClientEventType {
|
||||
|
||||
// Exec executes the command
|
||||
func (cmd MergeCmd) Exec(ctx context.Context, commandStr string, args []string, dEnv *env.DoltEnv) int {
|
||||
ap := cmd.createArgParser()
|
||||
ap := cli.CreateMergeArgParser()
|
||||
help, usage := cli.HelpAndUsagePrinters(cli.GetCommandDocumentation(commandStr, mergeDocs, ap))
|
||||
apr := cli.ParseArgs(ap, args, help)
|
||||
|
||||
if apr.ContainsAll(squashParam, noFFParam) {
|
||||
cli.PrintErrf("error: Flags '--%s' and '--%s' cannot be used together.\n", squashParam, noFFParam)
|
||||
if apr.ContainsAll(cli.SquashParam, cli.NoFFParam) {
|
||||
cli.PrintErrf("error: Flags '--%s' and '--%s' cannot be used together.\n", cli.SquashParam, cli.NoFFParam)
|
||||
return 1
|
||||
}
|
||||
|
||||
var verr errhand.VerboseError
|
||||
if apr.Contains(abortParam) {
|
||||
if apr.Contains(cli.AbortParam) {
|
||||
if !dEnv.IsMergeActive() {
|
||||
cli.PrintErrln("fatal: There is no merge to abort")
|
||||
return 1
|
||||
@@ -149,7 +129,7 @@ func (cmd MergeCmd) Exec(ctx context.Context, commandStr string, args []string,
|
||||
}
|
||||
|
||||
func abortMerge(ctx context.Context, doltEnv *env.DoltEnv) errhand.VerboseError {
|
||||
err := actions.CheckoutAllTables(ctx, doltEnv)
|
||||
err := actions.CheckoutAllTables(ctx, doltEnv.DbData())
|
||||
|
||||
if err == nil {
|
||||
err = doltEnv.RepoState.ClearMerge(doltEnv.FS)
|
||||
@@ -194,12 +174,12 @@ func mergeCommitSpec(ctx context.Context, apr *argparser.ArgParseResults, dEnv *
|
||||
|
||||
cli.Println("Updating", h1.String()+".."+h2.String())
|
||||
|
||||
squash := apr.Contains(squashParam)
|
||||
squash := apr.Contains(cli.SquashParam)
|
||||
if squash {
|
||||
cli.Println("Squash commit -- not updating HEAD")
|
||||
}
|
||||
|
||||
tblNames, workingDiffs, err := dEnv.MergeWouldStompChanges(ctx, cm2)
|
||||
tblNames, workingDiffs, err := env.MergeWouldStompChanges(ctx, cm2, dEnv.DbData())
|
||||
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to determine mergability.").AddCause(err).Build()
|
||||
@@ -215,7 +195,7 @@ func mergeCommitSpec(ctx context.Context, apr *argparser.ArgParseResults, dEnv *
|
||||
}
|
||||
|
||||
if ok, err := cm1.CanFastForwardTo(ctx, cm2); ok {
|
||||
if apr.Contains(noFFParam) {
|
||||
if apr.Contains(cli.NoFFParam) {
|
||||
return execNoFFMerge(ctx, apr, dEnv, cm2, verr, workingDiffs)
|
||||
} else {
|
||||
return executeFFMerge(ctx, squash, dEnv, cm2, workingDiffs)
|
||||
|
||||
@@ -57,7 +57,7 @@ func (cmd PullCmd) CreateMarkdown(fs filesys.Filesys, path, commandStr string) e
|
||||
|
||||
func (cmd PullCmd) createArgParser() *argparser.ArgParser {
|
||||
ap := argparser.NewArgParser()
|
||||
ap.SupportsFlag(squashParam, "", "Merges changes to the working set without updating the commit history")
|
||||
ap.SupportsFlag(cli.SquashParam, "", "Merges changes to the working set without updating the commit history")
|
||||
return ap
|
||||
}
|
||||
|
||||
|
||||
@@ -910,7 +910,7 @@ func (s *stats) shouldFlush() bool {
|
||||
return s.unflushedEdits >= maxBatchSize
|
||||
}
|
||||
|
||||
// updateRepoState takes in a context and database and updates repo state if autocommit is on
|
||||
// updateRepoState takes in a context and database and updates repo state.
|
||||
func updateRepoState(ctx *sql.Context, se *sqlEngine) error {
|
||||
err := se.iterDBs(func(_ string, db dsqle.Database) (bool, error) {
|
||||
root, err := db.GetRoot(ctx)
|
||||
@@ -945,7 +945,6 @@ func updateRepoState(ctx *sql.Context, se *sqlEngine) error {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func flushBatchedEdits(ctx *sql.Context, se *sqlEngine) error {
|
||||
err := se.iterDBs(func(_ string, db dsqle.Database) (bool, error) {
|
||||
err := db.Flush(ctx)
|
||||
|
||||
@@ -225,7 +225,7 @@ func (m Merge) Exec(t *testing.T, dEnv *env.DoltEnv) error {
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, h1, h2)
|
||||
|
||||
tblNames, _, err := dEnv.MergeWouldStompChanges(context.Background(), cm2)
|
||||
tblNames, _, err := env.MergeWouldStompChanges(context.Background(), cm2, dEnv.DbData())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/env"
|
||||
)
|
||||
|
||||
func CheckoutAllTables(ctx context.Context, dEnv *env.DoltEnv) error {
|
||||
roots, err := getRoots(ctx, dEnv.DoltDB, dEnv.RepoStateReader(), WorkingRoot, StagedRoot, HeadRoot)
|
||||
func CheckoutAllTables(ctx context.Context, dbData env.DbData) error {
|
||||
roots, err := getRoots(ctx, dbData.Ddb, dbData.Rsr, WorkingRoot, StagedRoot, HeadRoot)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -37,7 +37,7 @@ func CheckoutAllTables(ctx context.Context, dEnv *env.DoltEnv) error {
|
||||
|
||||
docs := doltdocs.SupportedDocs
|
||||
|
||||
return checkoutTablesAndDocs(ctx, dEnv.DbData(), roots, tbls, docs)
|
||||
return checkoutTablesAndDocs(ctx, dbData, roots, tbls, docs)
|
||||
|
||||
}
|
||||
|
||||
|
||||
101
go/libraries/doltcore/env/environment.go
vendored
101
go/libraries/doltcore/env/environment.go
vendored
@@ -430,6 +430,9 @@ func (r *repoStateWriter) SetCWBHeadRef(ctx context.Context, marshalableRef ref.
|
||||
func (r *repoStateWriter) ClearMerge() error {
|
||||
return r.dEnv.RepoState.ClearMerge(r.dEnv.FS)
|
||||
}
|
||||
func (r *repoStateWriter) StartMerge(commitStr string) error {
|
||||
return r.dEnv.RepoState.StartMerge(commitStr, r.dEnv.FS)
|
||||
}
|
||||
|
||||
func (dEnv *DoltEnv) RepoStateWriter() RepoStateWriter {
|
||||
return &repoStateWriter{dEnv}
|
||||
@@ -563,104 +566,6 @@ func (dEnv *DoltEnv) GetTablesWithConflicts(ctx context.Context) ([]string, erro
|
||||
return root.TablesInConflict(ctx)
|
||||
}
|
||||
|
||||
func (dEnv *DoltEnv) MergeWouldStompChanges(ctx context.Context, mergeCommit *doltdb.Commit) ([]string, map[string]hash.Hash, error) {
|
||||
headRoot, err := dEnv.HeadRoot(ctx)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
workingRoot, err := dEnv.WorkingRoot(ctx)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
mergeRoot, err := mergeCommit.GetRootValue()
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
headTableHashes, err := mapTableHashes(ctx, headRoot)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
workingTableHashes, err := mapTableHashes(ctx, workingRoot)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
mergeTableHashes, err := mapTableHashes(ctx, mergeRoot)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
headWorkingDiffs := diffTableHashes(headTableHashes, workingTableHashes)
|
||||
mergeWorkingDiffs := diffTableHashes(headTableHashes, mergeTableHashes)
|
||||
|
||||
stompedTables := make([]string, 0, len(headWorkingDiffs))
|
||||
for tName, _ := range headWorkingDiffs {
|
||||
if _, ok := mergeWorkingDiffs[tName]; ok {
|
||||
// even if the working changes match the merge changes, don't allow (matches git behavior).
|
||||
stompedTables = append(stompedTables, tName)
|
||||
}
|
||||
}
|
||||
|
||||
return stompedTables, headWorkingDiffs, nil
|
||||
}
|
||||
|
||||
func mapTableHashes(ctx context.Context, root *doltdb.RootValue) (map[string]hash.Hash, error) {
|
||||
names, err := root.GetTableNames(ctx)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nameToHash := make(map[string]hash.Hash)
|
||||
for _, name := range names {
|
||||
h, ok, err := root.GetTableHash(ctx, name)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !ok {
|
||||
panic("GetTableNames returned a table that GetTableHash says isn't there.")
|
||||
} else {
|
||||
nameToHash[name] = h
|
||||
}
|
||||
}
|
||||
|
||||
return nameToHash, nil
|
||||
}
|
||||
|
||||
func diffTableHashes(headTableHashes, otherTableHashes map[string]hash.Hash) map[string]hash.Hash {
|
||||
diffs := make(map[string]hash.Hash)
|
||||
for tName, hh := range headTableHashes {
|
||||
if h, ok := otherTableHashes[tName]; ok {
|
||||
if h != hh {
|
||||
// modification
|
||||
diffs[tName] = h
|
||||
}
|
||||
} else {
|
||||
// deletion
|
||||
diffs[tName] = hash.Hash{}
|
||||
}
|
||||
}
|
||||
|
||||
for tName, h := range otherTableHashes {
|
||||
if _, ok := headTableHashes[tName]; !ok {
|
||||
// addition
|
||||
diffs[tName] = h
|
||||
}
|
||||
}
|
||||
|
||||
return diffs
|
||||
}
|
||||
|
||||
func (dEnv *DoltEnv) CredsDir() (string, error) {
|
||||
return getCredsDir(dEnv.hdp)
|
||||
}
|
||||
|
||||
99
go/libraries/doltcore/env/repo_state.go
vendored
99
go/libraries/doltcore/env/repo_state.go
vendored
@@ -42,6 +42,7 @@ type RepoStateWriter interface {
|
||||
SetWorkingHash(context.Context, hash.Hash) error
|
||||
SetCWBHeadRef(context.Context, ref.MarshalableRef) error
|
||||
ClearMerge() error
|
||||
StartMerge(commitStr string) error
|
||||
}
|
||||
|
||||
type DocsReadWriter interface {
|
||||
@@ -287,3 +288,101 @@ func GetRoots(ctx context.Context, ddb *doltdb.DoltDB, rsr RepoStateReader) (wor
|
||||
|
||||
return working, staged, head, nil
|
||||
}
|
||||
|
||||
func MergeWouldStompChanges(ctx context.Context, mergeCommit *doltdb.Commit, dbData DbData) ([]string, map[string]hash.Hash, error) {
|
||||
headRoot, err := HeadRoot(ctx, dbData.Ddb, dbData.Rsr)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
workingRoot, err := WorkingRoot(ctx, dbData.Ddb, dbData.Rsr)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
mergeRoot, err := mergeCommit.GetRootValue()
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
headTableHashes, err := mapTableHashes(ctx, headRoot)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
workingTableHashes, err := mapTableHashes(ctx, workingRoot)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
mergeTableHashes, err := mapTableHashes(ctx, mergeRoot)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
headWorkingDiffs := diffTableHashes(headTableHashes, workingTableHashes)
|
||||
mergeWorkingDiffs := diffTableHashes(headTableHashes, mergeTableHashes)
|
||||
|
||||
stompedTables := make([]string, 0, len(headWorkingDiffs))
|
||||
for tName, _ := range headWorkingDiffs {
|
||||
if _, ok := mergeWorkingDiffs[tName]; ok {
|
||||
// even if the working changes match the merge changes, don't allow (matches git behavior).
|
||||
stompedTables = append(stompedTables, tName)
|
||||
}
|
||||
}
|
||||
|
||||
return stompedTables, headWorkingDiffs, nil
|
||||
}
|
||||
|
||||
func mapTableHashes(ctx context.Context, root *doltdb.RootValue) (map[string]hash.Hash, error) {
|
||||
names, err := root.GetTableNames(ctx)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nameToHash := make(map[string]hash.Hash)
|
||||
for _, name := range names {
|
||||
h, ok, err := root.GetTableHash(ctx, name)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !ok {
|
||||
panic("GetTableNames returned a table that GetTableHash says isn't there.")
|
||||
} else {
|
||||
nameToHash[name] = h
|
||||
}
|
||||
}
|
||||
|
||||
return nameToHash, nil
|
||||
}
|
||||
|
||||
func diffTableHashes(headTableHashes, otherTableHashes map[string]hash.Hash) map[string]hash.Hash {
|
||||
diffs := make(map[string]hash.Hash)
|
||||
for tName, hh := range headTableHashes {
|
||||
if h, ok := otherTableHashes[tName]; ok {
|
||||
if h != hh {
|
||||
// modification
|
||||
diffs[tName] = h
|
||||
}
|
||||
} else {
|
||||
// deletion
|
||||
diffs[tName] = hash.Hash{}
|
||||
}
|
||||
}
|
||||
|
||||
for tName, h := range otherTableHashes {
|
||||
if _, ok := headTableHashes[tName]; !ok {
|
||||
// addition
|
||||
diffs[tName] = h
|
||||
}
|
||||
}
|
||||
|
||||
return diffs
|
||||
}
|
||||
|
||||
@@ -199,14 +199,27 @@ func updateHeadAndWorkingSessionVars(ctx *sql.Context, dbData env.DbData) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hs := headHash.String()
|
||||
|
||||
hasWorkingChanges := hasWorkingSetChanges(dbData.Rsr)
|
||||
hasStagedChanges, err := hasStagedSetChanges(ctx, dbData.Ddb, dbData.Rsr)
|
||||
|
||||
err = setSessionRootExplicit(ctx, headHash.String(), sqle.HeadKeySuffix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
workingHash := dbData.Rsr.WorkingHash().String()
|
||||
|
||||
// This will update the session table editor's root and clear its cache.
|
||||
if !hasStagedChanges && !hasWorkingChanges {
|
||||
return setHeadAndWorkingSessionRoot(ctx, hs)
|
||||
}
|
||||
|
||||
err = setSessionRootExplicit(ctx, hs, sqle.HeadKeySuffix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return setSessionRootExplicit(ctx, workingHash, sqle.WorkingKeySuffix)
|
||||
}
|
||||
|
||||
|
||||
@@ -68,11 +68,6 @@ func (d DoltCommitFunc) Eval(ctx *sql.Context, row sql.Row) (interface{}, error)
|
||||
allFlag := apr.Contains(cli.AllFlag)
|
||||
allowEmpty := apr.Contains(cli.AllowEmptyFlag)
|
||||
|
||||
// Check if there are no changes in the working set but the -a flag is true
|
||||
if allFlag && !hasWorkingSetChanges(rsr) && !allowEmpty {
|
||||
return nil, fmt.Errorf("Cannot commit an empty commit. See the --allow-empty if you want to.")
|
||||
}
|
||||
|
||||
// Check if there are no changes in the staged set but the -a flag is false
|
||||
hasStagedChanges, err := hasStagedSetChanges(ctx, ddb, rsr)
|
||||
if err != nil {
|
||||
@@ -83,6 +78,12 @@ func (d DoltCommitFunc) Eval(ctx *sql.Context, row sql.Row) (interface{}, error)
|
||||
return nil, fmt.Errorf("Cannot commit an empty commit. See the --allow-empty if you want to.")
|
||||
}
|
||||
|
||||
// Check if there are no changes in the working set but the -a flag is true.
|
||||
// The -a flag is fine when a merge is active or there are staged changes as result of a merge or an add.
|
||||
if allFlag && !hasWorkingSetChanges(rsr) && !allowEmpty && !rsr.IsMergeActive() && !hasStagedChanges {
|
||||
return nil, fmt.Errorf("Cannot commit an empty commit. See the --allow-empty if you want to.")
|
||||
}
|
||||
|
||||
if allFlag {
|
||||
err = actions.StageAllTables(ctx, dbData)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,10 @@ import (
|
||||
"github.com/dolthub/dolt/go/cmd/dolt/cli"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/env"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/env/actions"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/merge"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/sqle"
|
||||
"github.com/dolthub/dolt/go/libraries/utils/argparser"
|
||||
)
|
||||
|
||||
const DoltMergeFuncName = "dolt_merge"
|
||||
@@ -57,6 +60,24 @@ func (d DoltMergeFunc) Eval(ctx *sql.Context, row sql.Row) (interface{}, error)
|
||||
|
||||
apr := cli.ParseArgs(ap, args, nil)
|
||||
|
||||
if apr.ContainsAll(cli.SquashParam, cli.NoFFParam) {
|
||||
return 1, fmt.Errorf("error: Flags '--%s' and '--%s' cannot be used together.\n", cli.SquashParam, cli.NoFFParam)
|
||||
}
|
||||
|
||||
if apr.Contains(cli.AbortParam) {
|
||||
if !dbData.Rsr.IsMergeActive() {
|
||||
return 1, fmt.Errorf("fatal: There is no merge to abort")
|
||||
}
|
||||
|
||||
err = abortMerge(ctx, dbData)
|
||||
|
||||
if err != nil {
|
||||
return 1, err
|
||||
}
|
||||
|
||||
return "Merge aborted", nil
|
||||
}
|
||||
|
||||
// The first argument should be the branch name.
|
||||
branchName := apr.Arg(0)
|
||||
|
||||
@@ -70,7 +91,20 @@ func (d DoltMergeFunc) Eval(ctx *sql.Context, row sql.Row) (interface{}, error)
|
||||
return nil, sql.ErrDatabaseNotFound.New(dbName)
|
||||
}
|
||||
|
||||
parent, _, parentRoot, err := getParent(ctx, err, sess, dbName)
|
||||
hasConflicts, err := root.HasConflicts(ctx)
|
||||
if err != nil {
|
||||
return 1, err
|
||||
}
|
||||
|
||||
if hasConflicts {
|
||||
return 1, errors.New("error: merge has unresolved conflicts")
|
||||
}
|
||||
|
||||
if dbData.Rsr.IsMergeActive() {
|
||||
return 1, errors.New("error: merging is not possible because you have not committed an active merge")
|
||||
}
|
||||
|
||||
parent, ph, parentRoot, err := getParent(ctx, err, sess, dbName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -92,36 +126,63 @@ func (d DoltMergeFunc) Eval(ctx *sql.Context, row sql.Row) (interface{}, error)
|
||||
}
|
||||
|
||||
if canFF {
|
||||
err = executeFFMerge(ctx, false, dbData, cm)
|
||||
if apr.Contains(cli.NoFFParam) {
|
||||
err = executeNoFFMerge(ctx, sess, apr, dbData, parent, cm)
|
||||
} else {
|
||||
err = executeFFMerge(ctx, apr.Contains(cli.SquashParam), dbData, cm)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cmh.String(), err
|
||||
} else {
|
||||
return nil, errors.New("DOLT_MERGE only supports fast forwards")
|
||||
}
|
||||
}
|
||||
|
||||
func (d DoltMergeFunc) String() string {
|
||||
childrenStrings := make([]string, len(d.Children()))
|
||||
|
||||
for i, child := range d.Children() {
|
||||
childrenStrings[i] = child.String()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("DOLT_MERGE(%s)", strings.Join(childrenStrings, ","))
|
||||
err = executeMerge(ctx, apr.Contains(cli.SquashParam), parent, cm, dbData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
returnMsg := fmt.Sprintf("Updating %s..%s", cmh.String(), ph.String())
|
||||
|
||||
return returnMsg, nil
|
||||
}
|
||||
|
||||
func (d DoltMergeFunc) Type() sql.Type {
|
||||
return sql.Text
|
||||
func abortMerge(ctx *sql.Context, dbData env.DbData) error {
|
||||
err := actions.CheckoutAllTables(ctx, dbData)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = dbData.Rsw.ClearMerge()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hh, err := dbData.Rsr.CWBHeadHash(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return setHeadAndWorkingSessionRoot(ctx, hh.String())
|
||||
}
|
||||
|
||||
func (d DoltMergeFunc) WithChildren(children ...sql.Expression) (sql.Expression, error) {
|
||||
return NewDoltMergeFunc(children...)
|
||||
}
|
||||
func executeMerge(ctx *sql.Context, squash bool, parent, cm *doltdb.Commit, dbData env.DbData) error {
|
||||
mergeRoot, mergeStats, err := merge.MergeCommits(ctx, parent, cm)
|
||||
|
||||
func NewDoltMergeFunc(args ...sql.Expression) (sql.Expression, error) {
|
||||
return &DoltMergeFunc{expression.NaryExpression{ChildExpressions: args}}, nil
|
||||
if err != nil {
|
||||
switch err {
|
||||
case doltdb.ErrUpToDate:
|
||||
return errors.New("Already up to date.")
|
||||
case merge.ErrFastForward:
|
||||
panic("fast forward merge")
|
||||
default:
|
||||
return errors.New("Bad merge")
|
||||
}
|
||||
}
|
||||
|
||||
return mergeRootToWorking(ctx, squash, dbData, mergeRoot, cm, mergeStats)
|
||||
}
|
||||
|
||||
func executeFFMerge(ctx *sql.Context, squash bool, dbData env.DbData, cm2 *doltdb.Commit) error {
|
||||
@@ -158,3 +219,132 @@ func executeFFMerge(ctx *sql.Context, squash bool, dbData env.DbData, cm2 *doltd
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func executeNoFFMerge(ctx *sql.Context, dSess *sqle.DoltSession, apr *argparser.ArgParseResults, dbData env.DbData, pr, cm2 *doltdb.Commit) error {
|
||||
mergedRoot, err := cm2.GetRootValue()
|
||||
if err != nil {
|
||||
return errors.New("Failed to return root value.")
|
||||
}
|
||||
|
||||
err = mergeRootToWorking(ctx, false, dbData, mergedRoot, cm2, map[string]*merge.MergeStats{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg, msgOk := apr.GetValue(cli.CommitMessageArg)
|
||||
if !msgOk {
|
||||
ph, err := pr.HashOf()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmh, err := cm2.HashOf()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg = fmt.Sprintf("SQL Generated commit merging %s into %s", ph.String(), cmh.String())
|
||||
}
|
||||
|
||||
var name, email string
|
||||
if authorStr, ok := apr.GetValue(cli.AuthorParam); ok {
|
||||
name, email, err = cli.ParseAuthor(authorStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
name = dSess.Username
|
||||
email = dSess.Email
|
||||
}
|
||||
|
||||
// Specify the time if the date parameter is not.
|
||||
t := ctx.QueryTime()
|
||||
if commitTimeStr, ok := apr.GetValue(cli.DateParam); ok {
|
||||
var err error
|
||||
t, err = cli.ParseDate(commitTimeStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
h, err := actions.CommitStaged(ctx, dbData, actions.CommitStagedProps{
|
||||
Message: msg,
|
||||
Date: t,
|
||||
AllowEmpty: apr.Contains(cli.AllowEmptyFlag),
|
||||
CheckForeignKeys: !apr.Contains(cli.ForceFlag),
|
||||
Name: name,
|
||||
Email: email,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return setHeadAndWorkingSessionRoot(ctx, h)
|
||||
}
|
||||
|
||||
func mergeRootToWorking(ctx *sql.Context, squash bool, dbData env.DbData, mergedRoot *doltdb.RootValue, cm2 *doltdb.Commit, mergeStats map[string]*merge.MergeStats) error {
|
||||
h2, err := cm2.HashOf()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
workingRoot := mergedRoot
|
||||
if !squash {
|
||||
err = dbData.Rsw.StartMerge(h2.String())
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
workingHash, err := env.UpdateWorkingRoot(ctx, dbData.Ddb, dbData.Rsw, workingRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasConflicts := checkForConflicts(mergeStats)
|
||||
|
||||
if hasConflicts {
|
||||
return errors.New("merge has conflicts. use the dolt_conflicts table to resolve.")
|
||||
}
|
||||
|
||||
_, err = env.UpdateStagedRoot(ctx, dbData.Ddb, dbData.Rsw, workingRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return setSessionRootExplicit(ctx, workingHash.String(), sqle.WorkingKeySuffix)
|
||||
}
|
||||
|
||||
func checkForConflicts(tblToStats map[string]*merge.MergeStats) bool {
|
||||
for _, stats := range tblToStats {
|
||||
if stats.Operation == merge.TableModified && stats.Conflicts > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (d DoltMergeFunc) String() string {
|
||||
childrenStrings := make([]string, len(d.Children()))
|
||||
|
||||
for i, child := range d.Children() {
|
||||
childrenStrings[i] = child.String()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("DOLT_MERGE(%s)", strings.Join(childrenStrings, ","))
|
||||
}
|
||||
|
||||
func (d DoltMergeFunc) Type() sql.Type {
|
||||
return sql.Text
|
||||
}
|
||||
|
||||
func (d DoltMergeFunc) WithChildren(children ...sql.Expression) (sql.Expression, error) {
|
||||
return NewDoltMergeFunc(children...)
|
||||
}
|
||||
|
||||
func NewDoltMergeFunc(args ...sql.Expression) (sql.Expression, error) {
|
||||
return &DoltMergeFunc{expression.NaryExpression{ChildExpressions: args}}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user