mirror of
https://github.com/android-password-store/Android-Password-Store.git
synced 2025-09-07 16:09:38 +02:00
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
This commit is contained in:
parent
127a8b8c8a
commit
064a3fad99
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
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_SYNC = 106;
|
||||||
public static final int REQUEST_CREATE = 107;
|
public static final int REQUEST_CREATE = 107;
|
||||||
public static final int EDIT_GIT_CONFIG = 108;
|
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 TAG = "GitAct";
|
||||||
private static final String emailPattern = "^[^@]+@[^@]+$";
|
private static final String emailPattern = "^[^@]+@[^@]+$";
|
||||||
private Activity activity;
|
private Activity activity;
|
||||||
private Context context;
|
private Context context;
|
||||||
private String protocol;
|
private String protocol;
|
||||||
private String connectionMode;
|
private String connectionMode;
|
||||||
private File localDir;
|
|
||||||
private String hostname;
|
private String hostname;
|
||||||
private SharedPreferences settings;
|
private SharedPreferences settings;
|
||||||
private SshApiSessionFactory.IdentityBuilder identityBuilder;
|
private SshApiSessionFactory.IdentityBuilder identityBuilder;
|
||||||
|
@ -479,6 +480,7 @@ public class GitActivity extends AppCompatActivity {
|
||||||
// init the server information
|
// init the server information
|
||||||
final EditText git_user_name = findViewById(R.id.git_user_name);
|
final EditText git_user_name = findViewById(R.id.git_user_name);
|
||||||
final EditText git_user_email = findViewById(R.id.git_user_email);
|
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_name.setText(settings.getString("git_config_user_name", ""));
|
||||||
git_user_email.setText(settings.getString("git_config_user_email", ""));
|
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");
|
Ref ref = repo.getRef("refs/heads/master");
|
||||||
String head = ref.getObjectId().equals(objectId) ? ref.getName() : "DETACHED";
|
String head = ref.getObjectId().equals(objectId) ? ref.getName() : "DETACHED";
|
||||||
git_commit_hash.setText(String.format("%s (%s)", objectId.abbreviate(8).name(), head));
|
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) {
|
} catch (Exception e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
@ -532,23 +537,7 @@ public class GitActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void abortRebase(View view) {
|
public void abortRebase(View view) {
|
||||||
final Repository repo = PasswordRepository.getRepository(PasswordRepository.getRepositoryDirectory(getApplicationContext()));
|
launchGitOperation(BREAK_OUT_OF_DETACHED);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -558,7 +547,7 @@ public class GitActivity extends AppCompatActivity {
|
||||||
if (PasswordRepository.getRepository(null) == null) {
|
if (PasswordRepository.getRepository(null) == null) {
|
||||||
PasswordRepository.initialize(this);
|
PasswordRepository.initialize(this);
|
||||||
}
|
}
|
||||||
localDir = PasswordRepository.getRepositoryDirectory(context);
|
File localDir = PasswordRepository.getRepositoryDirectory(context);
|
||||||
|
|
||||||
if (!saveConfiguration())
|
if (!saveConfiguration())
|
||||||
return;
|
return;
|
||||||
|
@ -649,6 +638,7 @@ public class GitActivity extends AppCompatActivity {
|
||||||
*/
|
*/
|
||||||
protected void launchGitOperation(int operation) {
|
protected void launchGitOperation(int operation) {
|
||||||
GitOperation op;
|
GitOperation op;
|
||||||
|
File localDir = PasswordRepository.getRepositoryDirectory(context);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
@ -685,6 +675,10 @@ public class GitActivity extends AppCompatActivity {
|
||||||
op = new SyncOperation(localDir, activity).setCommands();
|
op = new SyncOperation(localDir, activity).setCommands();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BREAK_OUT_OF_DETACHED:
|
||||||
|
op = new BreakOutOfDetached(localDir, activity).setCommands();
|
||||||
|
break;
|
||||||
|
|
||||||
case GitOperation.GET_SSH_KEY_FROM_CLONE:
|
case GitOperation.GET_SSH_KEY_FROM_CLONE:
|
||||||
op = new CloneOperation(localDir, activity).setCommand(hostname);
|
op = new CloneOperation(localDir, activity).setCommand(hostname);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -8,7 +8,10 @@ import com.zeapo.pwdstore.PasswordStore;
|
||||||
import com.zeapo.pwdstore.R;
|
import com.zeapo.pwdstore.R;
|
||||||
import org.eclipse.jgit.api.CommitCommand;
|
import org.eclipse.jgit.api.CommitCommand;
|
||||||
import org.eclipse.jgit.api.GitCommand;
|
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.PushCommand;
|
||||||
|
import org.eclipse.jgit.api.RebaseResult;
|
||||||
import org.eclipse.jgit.api.StatusCommand;
|
import org.eclipse.jgit.api.StatusCommand;
|
||||||
import org.eclipse.jgit.transport.PushResult;
|
import org.eclipse.jgit.transport.PushResult;
|
||||||
import org.eclipse.jgit.transport.RemoteRefUpdate;
|
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
|
// the previous status will eventually be used to avoid a commit
|
||||||
if (nbChanges == null || nbChanges > 0)
|
if (nbChanges == null || nbChanges > 0)
|
||||||
command.call();
|
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) {
|
} else if (command instanceof PushCommand) {
|
||||||
for (final PushResult result : ((PushCommand) command).call()) {
|
for (final PushResult result : ((PushCommand) command).call()) {
|
||||||
// Code imported (modified) from Gerrit PushOp, license Apache v2
|
// Code imported (modified) from Gerrit PushOp, license Apache v2
|
||||||
|
|
|
@ -58,9 +58,9 @@ public class SyncOperation extends GitOperation {
|
||||||
new AlertDialog.Builder(callingActivity).
|
new AlertDialog.Builder(callingActivity).
|
||||||
setTitle(callingActivity.getResources().getString(R.string.jgit_error_dialog_title)).
|
setTitle(callingActivity.getResources().getString(R.string.jgit_error_dialog_title)).
|
||||||
setMessage("Error occured during the sync operation, "
|
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)
|
+ callingActivity.getResources().getString(R.string.jgit_error_dialog_text)
|
||||||
+ errorMessage
|
+ errorMessage).
|
||||||
+ "\nPlease check the FAQ for possible reasons why this error might occur.").
|
|
||||||
setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), (dialogInterface, i) -> callingActivity.finish()).show();
|
setPositiveButton(callingActivity.getResources().getString(R.string.dialog_ok), (dialogInterface, i) -> callingActivity.finish()).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,6 +238,7 @@
|
||||||
<string name="autofill_ins_1_hint">Screenshot of accessibility services</string>
|
<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_2_hint">Screenshot of toggle in accessibility services</string>
|
||||||
<string name="autofill_ins_3_hint">Screenshot of autofill service in action</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_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_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>
|
<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="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="remember_the_passphrase">Remember the passphrase in the app configuration (insecure)</string>
|
||||||
<string name="hackish_tools">Hackish tools</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="commit_hash">Commit hash</string>
|
||||||
<string name="crypto_password_edit_hint" translatable="false">p@ssw0rd!</string>
|
<string name="crypto_password_edit_hint" translatable="false">p@ssw0rd!</string>
|
||||||
<string name="crypto_extra_edit_hint">username: something other extra content</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="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_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="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>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue