From 971f1c66742508161c023623aef260d9b777f55c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 10 Jun 2015 17:18:44 -0700 Subject: [PATCH] git storage: re-organize code to make 'origin' remote more widely available I'm going to try to update the remote if the local cache is more recent when we fetch the data, which requires access to the remote over a wider range of code. This re-organizes the code so that we can free the remote later without having to have nasty error handling. We avoid the whole "if an error happened, free the remote and return" by creating helper functions and freeing the remote in the caller, so that all paths end up freeing it naturally. NOTE! We want to try to update the remote when we save the local cache too, so this whole "update remote when opening it" is incomplete. But (a) we do want to do it here as well and (b) this is the easiest place to create the initial "push to remote" code without any new "sync with cloud" interfaces. Signed-off-by: Linus Torvalds Signed-off-by: Dirk Hohndel --- git-access.c | 72 +++++++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/git-access.c b/git-access.c index bf238a191..ded065e01 100644 --- a/git-access.c +++ b/git-access.c @@ -99,7 +99,13 @@ static int reset_to_remote(git_repository *repo, git_reference *local, const git return 0; } -static int try_to_update(git_repository *repo, git_reference *local, git_reference *remote) +static int update_remote(git_repository *repo, git_remote *origin, git_reference *local, git_reference *remote) +{ + report_error("Local cache more recent than remote"); + return 0; +} + +static int try_to_update(git_repository *repo, git_remote *origin, git_reference *local, git_reference *remote) { git_oid base; const git_oid *local_id, *remote_id; @@ -107,6 +113,11 @@ static int try_to_update(git_repository *repo, git_reference *local, git_referen if (!git_reference_cmp(local, remote)) return 0; + // Dirty modified state in the working tree? We're not going + // to update either way + if (git_status_foreach(repo, check_clean, NULL)) + return report_error("local cached copy is dirty, skipping update"); + local_id = git_reference_target(local); remote_id = git_reference_target(remote); @@ -120,11 +131,9 @@ static int try_to_update(git_repository *repo, git_reference *local, git_referen if (git_oid_equal(&base, local_id)) return reset_to_remote(repo, local, remote_id); - /* Is the local repo the more recent one? We're done */ - if (git_oid_equal(&base, remote_id)) { - report_error("Local cache more recent than remote"); - return 0; - } + /* Is the local repo the more recent one? See if we can update upstream */ + if (git_oid_equal(&base, remote_id)) + return update_remote(repo, origin, local, remote); /* Merging a bare repository always needs user action */ if (git_repository_is_bare(repo)) @@ -140,7 +149,8 @@ static int try_to_update(git_repository *repo, git_reference *local, git_referen * But I couldn't find any good examples of this, so for now * you'd need to merge divergent histories manually. But we've * at least verified above that we have a working tree and the - * current branch is checked out, so we *could* try to merge. + * current branch is checked out and clean, so we *could* try + * to merge. */ return report_error("Local and remote have diverged, need to merge"); } @@ -169,12 +179,28 @@ int credential_https_cb(git_cred **out, } #endif +static int check_remote_status(git_repository *repo, git_remote *origin, const char *branch) +{ + git_reference *local_ref, *remote_ref; + + if (git_branch_lookup(&local_ref, repo, branch, GIT_BRANCH_LOCAL)) + return report_error("Git cache branch %s no longer exists", branch); + + if (git_branch_upstream(&remote_ref, local_ref)) { + git_reference_free(local_ref); + return report_error("Git cache branch %s no longer has an upstream branch", branch); + } + + try_to_update(repo, origin, local_ref, remote_ref); + git_reference_free(local_ref); + git_reference_free(remote_ref); +} + static git_repository *update_local_repo(const char *localdir, const char *remote, const char *branch) { int error; git_repository *repo = NULL; git_remote *origin; - git_reference *local_ref, *remote_ref; error = git_repository_open(&repo, localdir); if (error) { @@ -205,31 +231,13 @@ static git_repository *update_local_repo(const char *localdir, const char *remot #else error = git_remote_fetch(origin, NULL, NULL, NULL); #endif + + if (error) + report_error("Unable to fetch remote '%s'", remote); + else + check_remote_status(repo, origin, branch); + git_remote_free(origin); - if (error) { - report_error("Unable to update cache for remote '%s'", remote); - return repo; - } - - // Dirty modified state in the working tree? We're not going - // to tru to update - if (git_status_foreach(repo, check_clean, NULL)) - return repo; - - if (git_branch_lookup(&local_ref, repo, branch, GIT_BRANCH_LOCAL)) { - report_error("Git cache branch %s no longer exists", branch); - return repo; - } - - if (git_branch_upstream(&remote_ref, local_ref)) { - report_error("Git cache branch %s no longer has an upstream branch", branch); - git_reference_free(local_ref); - return repo; - } - - try_to_update(repo, local_ref, remote_ref); - git_reference_free(local_ref); - git_reference_free(remote_ref); return repo; }