diff options
author | John Cai <jcai@gitlab.com> | 2020-04-27 19:15:16 +0300 |
---|---|---|
committer | John Cai <jcai@gitlab.com> | 2020-04-27 19:15:16 +0300 |
commit | 738599c95a53b970efaf694fdf921163fded42b5 (patch) | |
tree | bdd5548d30f11a8f37fc1225c16d4ce24e652ffe | |
parent | ca7faa446b4db4713ad128698d4130aa4de8a26e (diff) | |
parent | a16627f7b2bad16f72d58ad36ddb8686505360c0 (diff) |
Merge branch 'sh-fix-rebase' into 'master'
Fix rebase when diff contains only deleted files
Closes gitlab#209817
See merge request gitlab-org/gitaly!2109
-rw-r--r-- | changelogs/unreleased/sh-fix-rebase.yml | 5 | ||||
-rw-r--r-- | internal/service/operations/rebase_test.go | 64 | ||||
-rw-r--r-- | ruby/lib/gitlab/git/repository.rb | 20 |
3 files changed, 88 insertions, 1 deletions
diff --git a/changelogs/unreleased/sh-fix-rebase.yml b/changelogs/unreleased/sh-fix-rebase.yml new file mode 100644 index 000000000..54a81afc2 --- /dev/null +++ b/changelogs/unreleased/sh-fix-rebase.yml @@ -0,0 +1,5 @@ +--- +title: Fix rebase when diff contains only deleted files +merge_request: 2109 +author: +type: fixed diff --git a/internal/service/operations/rebase_test.go b/internal/service/operations/rebase_test.go index da254dced..222c723fd 100644 --- a/internal/service/operations/rebase_test.go +++ b/internal/service/operations/rebase_test.go @@ -404,6 +404,70 @@ func getBranchSha(t *testing.T, repoPath string, branchName string) string { return strings.TrimSpace(branchSha) } +func TestRebaseRequestWithDeletedFile(t *testing.T) { + ctxOuter, cancel := testhelper.Context() + defer cancel() + + server, serverSocketPath := runFullServerWithHooks(t) + defer server.Stop() + + client, conn := operations.NewOperationClient(t, serverSocketPath) + defer conn.Close() + + testRepo, testRepoPath, cleanupFn := testhelper.NewTestRepoWithWorktree(t) + defer cleanupFn() + + testRepoCopy, _, cleanup := testhelper.NewTestRepo(t) + defer cleanup() + + cleanupSrv := operations.SetupAndStartGitlabServer(t, rebaseUser.GlId, testRepo.GlRepository) + defer cleanupSrv() + + md := testhelper.GitalyServersMetadata(t, serverSocketPath) + ctx := metadata.NewOutgoingContext(ctxOuter, md) + + branch := "rebase-delete-test" + + testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "config", "user.name", string(rebaseUser.Name)) + testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "config", "user.email", string(rebaseUser.Email)) + testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "checkout", "-b", branch, "master~1") + testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "rm", "README") + testhelper.MustRunCommand(t, nil, "git", "-C", testRepoPath, "commit", "-a", "-m", "delete file") + + branchSha := getBranchSha(t, testRepoPath, branch) + + rebaseStream, err := client.UserRebaseConfirmable(ctx) + require.NoError(t, err) + + headerRequest := buildHeaderRequest(testRepo, rebaseUser, "1", branch, branchSha, testRepoCopy, "master") + require.NoError(t, rebaseStream.Send(headerRequest), "send header") + + firstResponse, err := rebaseStream.Recv() + require.NoError(t, err, "receive first response") + + _, err = gitlog.GetCommit(ctx, testRepo, firstResponse.GetRebaseSha()) + require.NoError(t, err, "look up git commit before rebase is applied") + + applyRequest := buildApplyRequest(true) + require.NoError(t, rebaseStream.Send(applyRequest), "apply rebase") + + secondResponse, err := rebaseStream.Recv() + require.NoError(t, err, "receive second response") + + err = testhelper.ReceiveEOFWithTimeout(func() error { + _, err = rebaseStream.Recv() + return err + }) + require.NoError(t, err, "consume EOF") + + newBranchSha := getBranchSha(t, testRepoPath, branch) + + require.NotEqual(t, newBranchSha, branchSha) + require.Equal(t, newBranchSha, firstResponse.GetRebaseSha()) + + require.True(t, secondResponse.GetRebaseApplied(), "the second rebase is applied") +} + // This error is used as a sentinel value var errRecvTimeout = errors.New("timeout waiting for response") diff --git a/ruby/lib/gitlab/git/repository.rb b/ruby/lib/gitlab/git/repository.rb index 80b4c24ef..942880482 100644 --- a/ruby/lib/gitlab/git/repository.rb +++ b/ruby/lib/gitlab/git/repository.rb @@ -736,6 +736,14 @@ module Gitlab private + def sparse_checkout_empty?(output) + output.include?("error: Sparse checkout leaves no entry on working directory") + end + + def disable_sparse_checkout + run_git!(%w[config core.sparseCheckout false], include_stderr: true) + end + def create_merge_commit(user, our_commit, their_commit, message) raise 'Invalid merge target' unless our_commit raise 'Invalid merge source' unless their_commit @@ -884,7 +892,17 @@ module Gitlab configure_sparse_checkout(worktree_git_path, sparse_checkout_files) # After sparse checkout configuration, checkout `branch` in worktree - run_git!(%W[checkout --detach #{branch}], chdir: worktree.path, env: env, include_stderr: true) + output, cmd_status = run_git(%W[checkout --detach #{branch}], chdir: worktree.path, env: env, include_stderr: true) + + # If sparse checkout fails, fall back to a regular checkout. + if cmd_status.nonzero? + if sparse_checkout_empty?(output) + disable_sparse_checkout + run_git!(%W[checkout --detach #{branch}], chdir: worktree.path, env: env, include_stderr: true) + else + raise GitError, output + end + end else # Create worktree and checkout `branch` in it run_git!(base_args + [worktree.path, branch], env: env, include_stderr: true) |