-
Notifications
You must be signed in to change notification settings - Fork 5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
git: prune any deleted refs before fetching #9504
git: prune any deleted refs before fetching #9504
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, great catch of an edge case! I wonder if a unit test would be possible here. Maybe using a file://
repo as "remote"?
Considering this seems to be a fairly far-edge case, I also wonder if the "happy path" should skip the prune and then only run if there's an error on fetch. |
Codecov Report
@@ Coverage Diff @@
## master #9504 +/- ##
==========================================
+ Coverage 45.84% 45.86% +0.02%
==========================================
Files 221 221
Lines 26300 26309 +9
==========================================
+ Hits 12057 12067 +10
+ Misses 12589 12586 -3
- Partials 1654 1656 +2
Continue to review full report at Codecov.
|
@crenshaw-dev Thanks for the quick response 🙂
Should be doable. I'll see what can be done.
Good idea, I'll change the implementation to do this. Maybe even read the contents of the error and determine if a prune would be worthwhile. |
I like that. A second unit test could check to make sure the git error string checking works (so if we upgrade git, we remember to update the string if it changes). |
@KevinSnyderCodes thanks for the changes! Can you sign your commits to get DCO to pass? |
This commit modifies `nativeGitClient.Fetch()` to call `git remote prune origin` before fetching refs. In some cases, an old branch may exist that conflicts with the name of a new branch. The old branch will have been deleted from `origin` but still exist locally in the `argocd-repo-server`. Example: an old branch `feature/foo` conflicts with a new branch `feature/foo/bar` In these cases, syncing an application results in the error: ``` rpc error: code = Internal desc = Failed to fetch default: `git fetch origin --tags --force` failed exit status 1: error: cannot lock ref 'refs/remotes/origin/feature/foo/bar': 'refs/remotes/origin/feature/foo' exists; cannot create 'refs/remotes/origin/feature/foo/bar' From https://github.com/org/repo ! [new branch] feature/foo/bar -> origin/feature/foo/bar (unable to update local ref) error: some local refs could not be updated; try running 'git remote prune origin' to remove any old, conflicting branches ``` Adding `git remote prune origin` before fetching, as recommended by the error message, should fix this issue. The current workaround is to restart the `argocd-repo-server` which should flush the local repository folder. This works when Argo CD is installed using the Helm chart. Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com>
* fix: added extra protection to syncing app with replace Signed-off-by: ciiay <yicai@redhat.com> * Code clean up Signed-off-by: ciiay <yicai@redhat.com> * Updated logic for isAppOfAppsPattern Signed-off-by: ciiay <yicai@redhat.com> * Updated text strings as per comment Signed-off-by: ciiay <yicai@redhat.com> * Fixed lint issue Signed-off-by: ciiay <yicai@redhat.com> Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com>
* chore: Simplified GetRepoHTTPClient function Signed-off-by: ls0f <lovedboy.tk@qq.com> * simplified code and improve unit test coverage Signed-off-by: ls0f <lovedboy.tk@qq.com> Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com>
…d unit tests Confirmed that `Test_nativeGitClient_Fetch_Prune` fails without the bug fix, succeeds with it. Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com>
…roj#9434) * fix: avoid k8s API call before authorization in k8s endpoint Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * check for bad project Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * lint Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * more logging Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * handle 404, return 500 instead of 400 for other errors Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * use user input Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * refactor validation Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fix tests Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fixes, tests Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com>
Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com>
b6bd269
to
f46225c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm - thanks again @KevinSnyderCodes!
Thanks for this, I think I've actually run into this edge case repeatedly with a large monorepo with the only solution be to just restart the repo-servers. Though my error message surfaced is slightly different from this one.
(Full message edited a bit to remove real branch/repo names) |
Your error log doesn't contain this string which the check relies on. Will it still run I am getting the same error log so I hope this fixes it correctly. Also, would this PR be part of the next release? |
@kadamanas93 I can cherry-pick this onto 2.4 (or earlier if anyone needs it). I don't think this PR will fix your problem, since your error string is different. Can you outline the steps to create a situation which produces your error message? I'd want to write a unit test along with the fix to make sure we don't accidentally regress from fixing your issue. |
I really don't know how it's different than what OP described except the error message is different. I do have some extra log lines for my error message though:
|
My guess was the difference was the old branch was in the namespace/path of the new name and then the old branch was removed upstream. |
That seems possible. @kadamanas93 if you can write out the |
I am not sure if I managed to replicate the exact error I have but based on @sidewinder12s hypothesis, here is how I produced the error. I cloned a repo in two separate directories: # clone repos
mkdir clone_1 clone_2
cd clone_1 && git clone git@github.com:kadamanas93/repo.git
cd ../clone_2 && git clone git@github.com:kadamanas93/repo.git
# create branch
cd clone_1/repo
git checkout -b foo
git push -u origin foo
# branch foo should be in repo clone 2
cd ../../clone_2/repo
git fetch
# delete the branch locally and remotely
cd ../../clone_1/repo
git branch -d foo
git push -d origin foo
# create new branch with conflicts
git checkout -b foo/bar
git push -u origin foo/bar
cd ../../clone_2/repo
git fetch origin --tags --force
error: cannot lock ref 'refs/remotes/origin/foo/bar': 'refs/remotes/origin/foo' exists; cannot create 'refs/remotes/origin/foo/bar'
From github.com:kadamanas93/repo
! [new branch] foo/bar -> origin/foo/bar (unable to update local ref) |
@kadamanas93 unfortunately I think that's the exact same process as what's tested in this PR. Which makes me wonder why the error message is different. :-/ |
@crenshaw-dev What are your thoughts on always running The main downside I can think of is adding an unnecessary operation and latency to the Maybe we can put the behavior behind some global flag, if that's a pattern Argo CD likes to use. |
@KevinSnyderCodes fair... I think I'd be alright with an always-prune option behind a flag. I think I'd much, much prefer to have a test case and logic specifically tailored to the issue though. Argo CD is already very config-heavy, and I prefer to avoid more cognitive load. |
I also wonder if running prune on every fetch may introduce a performance regression with monorepos/large git repositories. I am not exactly sure how to reproduce since I hadn't created the breaking branches on our monorepo, but if I run into it again I can try and collect more info. Would performing a prune always during hard refreshes be another option? Or on some cadence? |
Yeah, I feel like it's probably a fairly light operation, but I'm just not sure.
I like the hard-refresh option. Cadence gets tricky, but theoretically would work. I think I'd want an API endpoint so users could schedule their own Cron to do the prune. |
Yeah, the only other thing I wasn't sure if you only exposed this through a hard refresh was how did that behave if you have multiple app server/repo-server replicas defined. Would you need to hit an app on each broken repo-server?
That and/or just have the repo-server prune on a cron as well with the api endpoint available. I'd generally thought that hard refresh would hard refresh everything on an app, but found that there were lots of little things that wouldn't get refreshed, so might want to force the prune during that as well anyways. |
* git: prune any deleted refers before fetching This commit modifies `nativeGitClient.Fetch()` to call `git remote prune origin` before fetching refs. In some cases, an old branch may exist that conflicts with the name of a new branch. The old branch will have been deleted from `origin` but still exist locally in the `argocd-repo-server`. Example: an old branch `feature/foo` conflicts with a new branch `feature/foo/bar` In these cases, syncing an application results in the error: ``` rpc error: code = Internal desc = Failed to fetch default: `git fetch origin --tags --force` failed exit status 1: error: cannot lock ref 'refs/remotes/origin/feature/foo/bar': 'refs/remotes/origin/feature/foo' exists; cannot create 'refs/remotes/origin/feature/foo/bar' From https://github.com/org/repo ! [new branch] feature/foo/bar -> origin/feature/foo/bar (unable to update local ref) error: some local refs could not be updated; try running 'git remote prune origin' to remove any old, conflicting branches ``` Adding `git remote prune origin` before fetching, as recommended by the error message, should fix this issue. The current workaround is to restart the `argocd-repo-server` which should flush the local repository folder. This works when Argo CD is installed using the Helm chart. Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com> * fix: added extra protection to syncing app with replace (#9187) * fix: added extra protection to syncing app with replace Signed-off-by: ciiay <yicai@redhat.com> * Code clean up Signed-off-by: ciiay <yicai@redhat.com> * Updated logic for isAppOfAppsPattern Signed-off-by: ciiay <yicai@redhat.com> * Updated text strings as per comment Signed-off-by: ciiay <yicai@redhat.com> * Fixed lint issue Signed-off-by: ciiay <yicai@redhat.com> Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com> * chore: Simplified GetRepoHTTPClient function (#9396) * chore: Simplified GetRepoHTTPClient function Signed-off-by: ls0f <lovedboy.tk@qq.com> * simplified code and improve unit test coverage Signed-off-by: ls0f <lovedboy.tk@qq.com> Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com> * Only prune if fetch error message indicates that it is worthwhile, add unit tests Confirmed that `Test_nativeGitClient_Fetch_Prune` fails without the bug fix, succeeds with it. Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com> * fix: avoid k8s call before authorization for terminal endpoint (#9434) * fix: avoid k8s API call before authorization in k8s endpoint Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * check for bad project Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * lint Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * more logging Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * handle 404, return 500 instead of 400 for other errors Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * use user input Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * refactor validation Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fix tests Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> * fixes, tests Signed-off-by: Michael Crenshaw <michael@crenshaw.dev> Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com> * Match against "try running 'git remote prune origin'" Signed-off-by: Kevin Snyder <kevin.snyder.codes@gmail.com> Co-authored-by: Yi Cai <yicai@redhat.com> Co-authored-by: ls0f <lovedboy.tk@qq.com> Co-authored-by: Michael Crenshaw <michael@crenshaw.dev> Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
That's fair, you'd have to hit each repo-server. |
Cherry-picked onto release-2.4 for 2.4.4. |
This PR modifies
nativeGitClient.Fetch()
to callgit remote prune origin
before fetching refs.In some cases, an old branch may exist that conflicts with the name of a new branch. The old branch will have been deleted from
origin
but still exist locally in theargocd-repo-server
.Example: an old branch
feature/foo
conflicts with a new branchfeature/foo/bar
In these cases, syncing an application results in the error:
Adding
git remote prune origin
before fetching, as recommended by the error message, should fix this issue.The current workaround is to restart the
argocd-repo-server
which should flush the local repository folder. This works when Argo CD is installed using the Helm chart.Note on DCO:
If the DCO action in the integration test fails, one or more of your commits are not signed off. Please click on the Details link next to the DCO action for instructions on how to resolve this.
Checklist: