diff options
author | Mohamed Zenadi <zeapo@users.noreply.github.com> | 2019-05-15 11:22:07 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-15 11:22:07 +0200 |
commit | 064a3fad99d5852d50634a98023cb92c4a915606 (patch) | |
tree | d99160440eed728662d588d547e7b05f5ebe749d /app/src/main | |
parent | 127a8b8c8a10d9c93bfc7e91e94b4bcb252eddeb (diff) |
Allow the user to push local master to a new branch in case of conflict (#508)
* detect that we're in a detached head and show the message
* add a new way to clean local repo in case of failed rebase
Diffstat (limited to 'app/src/main')
5 files changed, 109 insertions, 22 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/git/BreakOutOfDetached.kt b/app/src/main/java/com/zeapo/pwdstore/git/BreakOutOfDetached.kt new file mode 100644 index 00000000..31c65704 --- /dev/null +++ b/app/src/main/java/com/zeapo/pwdstore/git/BreakOutOfDetached.kt @@ -0,0 +1,80 @@ +package com.zeapo.pwdstore.git + +import android.app.Activity +import android.app.AlertDialog +import com.zeapo.pwdstore.R +import org.eclipse.jgit.api.Git +import org.eclipse.jgit.api.GitCommand +import org.eclipse.jgit.api.PushCommand +import org.eclipse.jgit.api.RebaseCommand +import java.io.File + +class BreakOutOfDetached(fileDir: File, callingActivity: Activity) : GitOperation(fileDir, callingActivity) { + private lateinit var commands: List<GitCommand<out Any>> + + /** + * Sets the command + * + * @return the current object + */ + fun setCommands(): BreakOutOfDetached { + val git = Git(repository) + val branchName = "conflicting-master-${System.currentTimeMillis()}" + + this.commands = listOf( + // abort the rebase + git.rebase().setOperation(RebaseCommand.Operation.ABORT), + // git checkout -b conflict-branch + git.checkout().setCreateBranch(true).setName(branchName), + // push the changes + git.push().setRemote("origin"), + // switch back to master + git.checkout().setName("master") + ) + return this + } + + override fun execute() { + val git = Git(repository) + if (!git.repository.repositoryState.isRebasing) { + AlertDialog.Builder(callingActivity) + .setTitle(callingActivity.resources.getString(R.string.git_abort_and_push_title)) + .setMessage("The repository is not rebasing, no need to push to another branch") + .setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> + callingActivity.finish() + }.show() + return + } + + if (this.provider != null) { + // set the credentials for push command + this.commands.forEach { cmd -> + if (cmd is PushCommand) { + cmd.setCredentialsProvider(this.provider) + } + } + } + GitAsyncTask(callingActivity, false, true, this) + .execute(*this.commands.toTypedArray()) + } + + override fun onError(errorMessage: String) { + AlertDialog.Builder(callingActivity) + .setTitle(callingActivity.resources.getString(R.string.jgit_error_dialog_title)) + .setMessage("Error occurred when checking out another branch operation $errorMessage") + .setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> + callingActivity.finish() + }.show() + } + + override fun onSuccess() { + AlertDialog.Builder(callingActivity) + .setTitle(callingActivity.resources.getString(R.string.git_abort_and_push_title)) + .setMessage("There was a conflict when trying to rebase. " + + "Your local master branch was pushed to another branch named conflicting-master-....\n" + + "Use this branch to resolve conflict on your computer") + .setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> + callingActivity.finish() + }.show() + } +} diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java b/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java index e945c973..eb9b48ab 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java +++ b/app/src/main/java/com/zeapo/pwdstore/git/GitActivity.java @@ -14,6 +14,7 @@ import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; @@ -48,13 +49,13 @@ public class GitActivity extends AppCompatActivity { public static final int REQUEST_SYNC = 106; public static final int REQUEST_CREATE = 107; public static final int EDIT_GIT_CONFIG = 108; + public static final int BREAK_OUT_OF_DETACHED = 109; private static final String TAG = "GitAct"; private static final String emailPattern = "^[^@]+@[^@]+$"; private Activity activity; private Context context; private String protocol; private String connectionMode; - private File localDir; private String hostname; private SharedPreferences settings; private SshApiSessionFactory.IdentityBuilder identityBuilder; @@ -479,6 +480,7 @@ public class GitActivity extends AppCompatActivity { // init the server information final EditText git_user_name = findViewById(R.id.git_user_name); final EditText git_user_email = findViewById(R.id.git_user_email); + final Button abort = findViewById(R.id.git_abort_rebase); git_user_name.setText(settings.getString("git_config_user_name", "")); git_user_email.setText(settings.getString("git_config_user_email", "")); @@ -492,6 +494,9 @@ public class GitActivity extends AppCompatActivity { Ref ref = repo.getRef("refs/heads/master"); String head = ref.getObjectId().equals(objectId) ? ref.getName() : "DETACHED"; git_commit_hash.setText(String.format("%s (%s)", objectId.abbreviate(8).name(), head)); + + // enable the abort button only if we're rebasing + abort.setEnabled(repo.getRepositoryState().isRebasing()); } catch (Exception e) { // ignore } @@ -532,23 +537,7 @@ public class GitActivity extends AppCompatActivity { } public void abortRebase(View view) { - final Repository repo = PasswordRepository.getRepository(PasswordRepository.getRepositoryDirectory(getApplicationContext())); - if (repo != null) { - new GitOperation(PasswordRepository.getRepositoryDirectory(activity), activity) { - @Override - public void execute() { - Log.d(TAG, "Resetting the repository"); - assert repository != null; - GitAsyncTask tasks = new GitAsyncTask(activity, false, true, this); - tasks.execute(new Git(repo).rebase().setOperation(RebaseCommand.Operation.ABORT)); - } - - @Override - public void onSuccess() { - showGitConfig(); - } - }.execute(); - } + launchGitOperation(BREAK_OUT_OF_DETACHED); } /** @@ -558,7 +547,7 @@ public class GitActivity extends AppCompatActivity { if (PasswordRepository.getRepository(null) == null) { PasswordRepository.initialize(this); } - localDir = PasswordRepository.getRepositoryDirectory(context); + File localDir = PasswordRepository.getRepositoryDirectory(context); if (!saveConfiguration()) return; @@ -649,6 +638,7 @@ public class GitActivity extends AppCompatActivity { */ protected void launchGitOperation(int operation) { GitOperation op; + File localDir = PasswordRepository.getRepositoryDirectory(context); try { @@ -685,6 +675,10 @@ public class GitActivity extends AppCompatActivity { op = new SyncOperation(localDir, activity).setCommands(); break; + case BREAK_OUT_OF_DETACHED: + op = new BreakOutOfDetached(localDir, activity).setCommands(); + break; + case GitOperation.GET_SSH_KEY_FROM_CLONE: op = new CloneOperation(localDir, activity).setCommand(hostname); break; diff --git a/app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.java b/app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.java index 79234a32..52f5b1b7 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.java +++ b/app/src/main/java/com/zeapo/pwdstore/git/GitAsyncTask.java @@ -8,7 +8,10 @@ import com.zeapo.pwdstore.PasswordStore; import com.zeapo.pwdstore.R; import org.eclipse.jgit.api.CommitCommand; import org.eclipse.jgit.api.GitCommand; +import org.eclipse.jgit.api.PullCommand; +import org.eclipse.jgit.api.PullResult; import org.eclipse.jgit.api.PushCommand; +import org.eclipse.jgit.api.RebaseResult; import org.eclipse.jgit.api.StatusCommand; import org.eclipse.jgit.transport.PushResult; import org.eclipse.jgit.transport.RemoteRefUpdate; @@ -50,6 +53,14 @@ public class GitAsyncTask extends AsyncTask<GitCommand, Integer, String> { // the previous status will eventually be used to avoid a commit if (nbChanges == null || nbChanges > 0) command.call(); + } else if (command instanceof PullCommand) { + final PullResult result = ((PullCommand) command).call(); + final RebaseResult rr = result.getRebaseResult(); + + if (rr.getStatus() == RebaseResult.Status.STOPPED) { + return activity.getString(R.string.git_pull_fail_error); + } + } else if (command instanceof PushCommand) { for (final PushResult result : ((PushCommand) command).call()) { // Code imported (modified) from Gerrit PushOp, license Apache v2 diff --git a/app/src/main/java/com/zeapo/pwdstore/git/SyncOperation.java b/app/src/main/java/com/zeapo/pwdstore/git/SyncOperation.java index 4e7f037d..266dd096 100644 --- a/app/src/main/java/com/zeapo/pwdstore/git/SyncOperation.java +++ b/app/src/main/java/com/zeapo/pwdstore/git/SyncOperation.java @@ -58,9 +58,9 @@ public class SyncOperation extends GitOperation { new AlertDialog.Builder(callingActivity). setTitle(callingActivity.getResources().getString(R.string.jgit_error_dialog_title)). setMessage("Error occured during the sync operation, " + + "\nPlease check the FAQ for possible reasons why this error might occur." + callingActivity.getResources().getString(R.string.jgit_error_dialog_text) - + errorMessage - + "\nPlease check the FAQ for possible reasons why this error might occur."). + + errorMessage). setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), (dialogInterface, i) -> callingActivity.finish()).show(); } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 675c5ca9..52f631c1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -238,6 +238,7 @@ <string name="autofill_ins_1_hint">Screenshot of accessibility services</string> <string name="autofill_ins_2_hint">Screenshot of toggle in accessibility services</string> <string name="autofill_ins_3_hint">Screenshot of autofill service in action</string> + <string name="git_pull_fail_error">Pull has failed, you\'re in a detached head. Using "settings > git utils", save your changes to the remote in a new branch and resolve the conflict on your computer.</string> <string name="git_push_nff_error">Push was rejected by remote, run pull before pushing again. You can use Synchronize rather than pull/push as it implements both</string> <string name="git_push_generic_error">Push was rejected by remote, reason:</string> <string name="git_push_other_error">Remote rejected non-fast-forward push. Check receive.denyNonFastForwards variable in config file of destination repository.</string> @@ -246,7 +247,7 @@ <string name="hotp_remember_clear_choice">Clear saved preference for HOTP incrementing</string> <string name="remember_the_passphrase">Remember the passphrase in the app configuration (insecure)</string> <string name="hackish_tools">Hackish tools</string> - <string name="abort_rebase">Abort rebase</string> + <string name="abort_rebase">Abort rebase and push new branch</string> <string name="commit_hash">Commit hash</string> <string name="crypto_password_edit_hint" translatable="false">p@ssw0rd!</string> <string name="crypto_extra_edit_hint">username: something other extra content</string> @@ -258,4 +259,5 @@ <string name="ssh_api_unknown_error">Unknown SSH API Error</string> <string name="sdcard_root_warning_title">SD-Card root selected</string> <string name="sdcard_root_warning_message">You have selected the root of your sdcard for the store. This is extremely dangerous and you will lose your data as its content will, eventually, be deleted</string> + <string name="git_abort_and_push_title">Abort and Push</string> </resources> |