git: correctly detect if there are local changes that should be saved before update: IDEA-76760

The "AD" status (staged addition + unstaged deletion of the same file) is not detected as a local change, thus we add an additional check for `git diff --staged`.

Note: stashing "AD" would stash only the addition, thus after stash-unstash process the file will be created back. However, it seems to be a less serious issue than unability to update.
This commit is contained in:
Kirill Likhodedov
2019-01-29 16:55:07 +03:00
parent d47409c3d0
commit 29332a3d38
3 changed files with 37 additions and 46 deletions
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package git4idea.update;
import com.intellij.openapi.diagnostic.Logger;
@@ -67,7 +53,14 @@ public class GitRebaseUpdater extends GitUpdater {
public boolean isSaveNeeded() {
Collection<Change> localChanges = new LocalChangesUnderRoots(myChangeListManager, myVcsManager)
.getChangesUnderRoots(singletonList(myRoot)).get(myRoot);
return !ContainerUtil.isEmpty(localChanges);
try {
return !ContainerUtil.isEmpty(localChanges) ||
GitUtil.hasLocalChanges(true, myProject, myRoot);
}
catch (VcsException e) {
LOG.info("isSaveNeeded failed to check local changes", e);
return true;
}
}
@NotNull
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
@file:JvmName("GitExecutor")
package git4idea.test
@@ -30,6 +16,7 @@ import git4idea.commands.GitLineHandler
import git4idea.commands.getGitCommandInstance
import git4idea.repo.GitRepository
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import java.io.File
fun gitExecutable() = GitExecutorHolder.PathHolder.GIT_EXECUTABLE
@@ -205,6 +192,12 @@ internal class TestFile internal constructor(val repo: GitRepository, val file:
return this
}
fun delete(): TestFile {
assertTrue(file.exists())
FileUtil.delete(file)
return this
}
fun assertNotExists(): TestFile {
assertFalse(file.exists())
return this
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package git4idea.update
import com.intellij.openapi.progress.EmptyProgressIndicator
@@ -89,6 +75,25 @@ class GitSingleRepoUpdateTest : GitUpdateBaseTest() {
assertFalse("Stash shouldn't be called for clean working tree", stashCalled)
}
// IDEA-76760
fun `test stash is called for rebase in case of AD changes`() {
broRepo.commitAndPush()
var stashCalled = false
git.stashListener = {
stashCalled = true
}
cd(repo)
val file = file("a.txt").create().add().delete().file
updateChangeListManager()
val result = updateWithRebase()
assertSuccessfulUpdate(result)
assertTrue("Stash should be called for clean working tree", stashCalled)
repo.assertStatus(file, 'A')
}
private fun updateWithRebase(): GitUpdateResult {
return GitUpdateProcess(project, EmptyProgressIndicator(), listOf(repo), UpdatedFiles.create(), false, true).update(UpdateMethod.REBASE)
}