{"id":300056,"date":"2020-03-12T21:00:22","date_gmt":"2020-03-12T21:00:22","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=300056"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=300056","title":{"rendered":"\u041c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0441 Gitolite \u043d\u0430 GitLab \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Shell \u0441\u043a\u0440\u0438\u043f\u0442\u0430"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/492122\/\">\n<p><em>\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043d\u0435\u0440\u0435\u0434\u043a\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0442\u0440\u0443\u0434\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e, \u043a\u043e\u0433\u0434\u0430 \u043e\u0431\u044a\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438, \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0435\u043b\u0438\u043a, \u0447\u0442\u043e \u0432\u044b\u0433\u043e\u0434\u043d\u0435\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0435\u0433\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u0418\u043c\u0435\u043d\u043d\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 Gitolite \u043d\u0430 GitLab \u0438 \u043f\u043e\u0431\u0443\u0434\u0438\u043b\u0430 \u043c\u0435\u043d\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e \u043e \u043c\u043e\u0435\u043c \u043e\u043f\u044b\u0442\u0435 \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0432\u043e\u043f\u0440\u043e\u0441\u0435.<\/em><br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/6s\/mh\/kn\/6smhkn4gi8_7ngzatgsoijdvyti.png\"\/><\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<p>\u0414\u043b\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440 \u0441 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 CentOS 7. \u041d\u0430 \u043d\u0435\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043d\u0430\u0431\u043e\u0440 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439: <em>git, ssh-agent, curl, jq, xargs<\/em>.<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043b\u044e\u0447 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a API GitLab. \u0412 \u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u0437\u0430\u0445\u043e\u0434\u0438\u043c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0414\u0430\u043b\u0435\u0435 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u043f\u0443\u043d\u043a\u0442 \u043c\u0435\u043d\u044e <em>\u00abAccess Tokens\u00bb<\/em>. \u0412 \u043e\u0442\u043a\u0440\u044b\u0432\u0448\u0435\u0439\u0441\u044f \u0444\u043e\u0440\u043c\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u0440\u043e\u043a, \u0434\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043a\u043b\u044e\u0447 \u0431\u0443\u0434\u0435\u0442 \u0430\u043a\u0442\u0438\u0432\u0435\u043d. \u041d\u0438\u0436\u0435 \u0441\u0442\u0430\u0432\u0438\u043c \u0433\u0430\u043b\u043e\u0447\u043a\u0443 \u043d\u0430\u043f\u0440\u043e\u0442\u0438\u0432 \u043f\u0443\u043d\u043a\u0442\u0430 api \u0438 \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u043c \u043a\u043d\u043e\u043f\u043a\u0443 <em>\u00abCreate personal access token\u00bb<\/em>. \u042d\u0442\u043e\u0442 \u043a\u043b\u044e\u0447 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 API GitLab.<\/p>\n<p>  <\/p>\n<ol>\n<li>\n<h4 id=\"podgotovka-rabochey-sredy\">\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0440\u0430\u0431\u043e\u0447\u0435\u0439 \u0441\u0440\u0435\u0434\u044b<\/h4>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043c\u044b \u043c\u043e\u0433\u043b\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u043a\u043e\u0434 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 GitLab \u043f\u043e SSH, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0443 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0433\u043e \u0438 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0435\u0439, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430 \u0432 GitLab. \u0414\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430 \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430 GitLab <em>\u00abAdmin area\u00bb<\/em> \u0437\u0430\u0445\u043e\u0434\u0438\u043c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b <em>\u00abDeploy keys\u00bb<\/em> \u0438 \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u043c \u043a\u043d\u043e\u043f\u043a\u0443 <em>\u00abNew deploy key\u00bb<\/em>. \u0412 \u043e\u0442\u043a\u0440\u044b\u0432\u0448\u0435\u0439\u0441\u044f \u0444\u043e\u0440\u043c\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0430\u043c \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447. \u041f\u043e\u0441\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043b\u044e\u0447\u0430, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 GitLab. \u0427\u0442\u043e\u0431\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0435\u0433\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0432 bash:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">curl -k -X GET --header &quot;PRIVATE-TOKEN: &lt;your private token&gt;&quot; &lt;gitlab url&gt;\/api\/v4\/deploy_keys<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435: \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0432\u0432\u043e\u0434\u0438\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044c \u043e\u0442 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0433\u043e SSH \u043a\u043b\u044e\u0447\u0430 \u043f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 git \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0432 ssh-agent. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/em><\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">eval `ssh-agent`<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"bash\">ssh-add ~\/.ssh\/id_rsa<\/code><\/pre>\n<p>  <\/li>\n<li>\n<h4 id=\"sozdanie-repozitoriya-v-gitlab-s-ispolzovaniem-api\">\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0432 GitLab \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c API<\/h4>\n<p>  <\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0432 GitLab, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c POST \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 API GitLab, \u043f\u0435\u0440\u0435\u0434\u0430\u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e Projects API GitLab \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 GitLab.<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\"># $1 - gitlab remote url # $2 - api access token # $3 - remote repository name # $4 - remote repository namespace identifier initRemoteRepository() {     local response=`curl -s -k -X POST --header &quot;Private-Token: $2&quot; --data &quot;name=$3&amp;namespace_id=$4&amp;visibility=private&amp;description=$3&quot; $1\/api\/v4\/projects`     local id=`echo $response | jq -r &quot;.id&quot;`     echo &quot;$id&quot; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f <em>initRemoteRepository<\/em> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f. \u0412 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430.<br \/>  <em>\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435: \u043a\u043b\u044e\u0447 \u2013k \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c, \u0435\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0439 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442 GitLab \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0430\u043c\u043e\u0437\u0430\u0432\u0435\u0440\u0435\u043d\u043d\u044b\u043c.<\/em><\/p>\n<p>  <\/li>\n<li>\n<h4 id=\"predostavlenie-dostupa-na-zapis-i-chtenie-repozitoriya-s-ispolzovaniem-api\">\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u0438 \u0447\u0442\u0435\u043d\u0438\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c API<\/h4>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0434\u0430\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u043f\u0440\u0430\u0432\u043e. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e Deploy Keys API GitLab \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 GitLab.<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\"># $1 - remote url # $2 - api token # $3 - repository identifier # $4 - deploy key identifier setRepositoryWriteAccess() {     local response=`curl -s -k -X PUT --header &quot;PRIVATE-TOKEN: $2&quot; --header &quot;Content-Type: application\/json&quot; --data '{&quot;can_push&quot;: true}' $1\/api\/v4\/projects\/$3\/deploy_keys\/$4`     echo &quot;$response&quot; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f <em>enableRepositoryDeployKey<\/em> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0441 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u043a\u043b\u044e\u0447\u0435\u0439 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0440\u0430\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f.<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\"># $1 - remote url # $2 - api token # $3 - repository identifier # $4 - deploy key identifier enableRepositoryDeployKey() {     local response=`curl -s -k -X POST --header &quot;Private-Token: $2&quot; $1\/api\/v4\/projects\/$3\/deploy_keys\/$4\/enable`     echo &quot;$response&quot; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f <em>setRepositoryWriteAccess<\/em> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439.<\/p>\n<p>  <\/li>\n<li>\n<h4 id=\"migriraciya-repozitoriev-vklyuchaya-vse-vetki\">\u041c\u0438\u0433\u0440\u0438\u0440\u0430\u0446\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432 \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0432\u0441\u0435 \u0432\u0435\u0442\u043a\u0438<\/h4>\n<p>  <\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u0432 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435. \u0421\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0432 GitLab, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u0440\u0438\u0432\u0435\u043b\u0435\u0433\u0438\u0438 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u043f\u0438\u0441\u0438. \u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441 \u0432\u0435\u0442\u043e\u043a \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f. \u0414\u0430\u043b\u0435\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0430 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u0443\u044e \u0432\u0435\u0442\u043a\u0443 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0432 GitLab. <\/p>\n<p>  <\/p>\n<pre><code class=\"bash\"># $1 - branch # $2 \u2013 separator getCanonicalBranchName() {     local branch=&quot;&quot;     IFS=$2 read -r -a array &lt;&lt;&lt; &quot;$1&quot;     length=${#array[@]}     for index in &quot;${!array[@]}&quot;     do         if [ $index -gt 0 ]; then             if [ $index -eq 1 ]; then                 local branch=&quot;${array[index]}&quot;             else                 local branch=&quot;$branch\/${array[index]}&quot;             fi         fi     done     echo &quot;$branch&quot; } PSWD=&quot;$(dirname &quot;$0&quot;)&quot; cd $PSWD while IFS= read -r REPOSITORY do     echo &quot;====================  &lt;$REPOSITORY&gt;  ====================&quot;     GITOLITE_REPO=$GITOLITE$REPOSITORY     echo &quot;Run cloning remote repository $GITOLITE_REPO&quot;     git clone $GITOLITE_REPO     cd $REPOSITORY     GITLAB_REPO=$GITLAB$REPOSITORY.git     echo &quot;Initialize remote gitgab repository $GITLAB_REPO&quot;     PROJECT=$(initRemoteRepository $GITLAB_URL $API_TOKEN $REPOSITORY)     echo &quot;Remote repository initialized identifier $PROJECT&quot;     echo &quot;Add deploy key and enable write access to remote repository $REPOSITORY ($PROJECT)&quot;     response=$(enableRepositoryDeployKey $GITLAB_URL $API_TOKEN $PROJECT $DEPLOY_KEY_ID)     response =$(setRepositoryWriteAccess $GITLAB_URL $API_TOKEN $PROJECT $DEPLOY_KEY_ID)     echo &quot;Add new remote url for repository $GITLAB_REPO&quot;     git remote add gitlab $GITLAB_REPO     # push all branches     IFS_BACK=$IFS     IFS=$'\\n'     branches=$(git branch -r)     for branchName in $branches; do         trimBranchName=`echo $branchName | xargs`         canonicalBranchName=$(getCanonicalBranchName $trimBranchName '\/')         echo &quot;$trimBranchName ($canonicalBranchName) init push&quot;         git checkout -b $canonicalBranchName remotes\/origin\/$canonicalBranchName         git push -f gitlab $canonicalBranchName     done     IFS=$IFS_BACK     cd ..     rm -r -f $REPOSITORY     echo &quot;====================  &lt;$REPOSITORY&gt;  ====================&quot;     echo &quot;&quot; done &lt; &quot;$REPOSITORIES&quot;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0444\u0430\u0439\u043b \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c, \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0432 \u043f\u0440\u0430\u0432\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430. \u041f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0432\u043e\u0434\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0438\u0436\u0435. <\/p>\n<p>  <\/li>\n<\/ol>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u043e\u043b\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u0441\u043a\u0440\u0438\u043f\u0442\u0430<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">REPOSITORIES=&quot;&lt;repositories_file&gt;&quot; GITOLITE=&quot;&lt;gitolite_ssh_url&gt;&quot; GITLAB_URL=&quot;&lt;gitlab_api_url&gt;&quot; GITLAB=&quot;&lt;gitolite_ssh_url&gt;&quot; API_TOKEN=&quot;&lt;api_access_token&gt;&quot; DEPLOY_KEY_ID=&quot;&lt;deploy_key_identifier&gt;&quot; # $1 - gitlab remote url # $2 - api access token # $3 - remote repository name # $4 - remote repository namespace identifier initRemoteRepository() {         local response=`curl -s -k -X POST --header &quot;Private-Token: $2&quot; --data &quot;name=$3&amp;namespace_id=$4&amp;visibility=private&amp;description=$3&quot; $1\/api\/v4\/projects`         local id=`echo $response | jq -r &quot;.id&quot;`         echo &quot;$id&quot; } # $1 - remote url # $2 - api token # $3 - repository identifier # $4 - deploy key identifier setRepositoryWriteAccess() {     local response=`curl -s -k -X PUT --header &quot;PRIVATE-TOKEN: $2&quot; --header &quot;Content-Type: application\/json&quot; --data '{&quot;can_push&quot;: true}' $1\/api\/v4\/projects\/$3\/deploy_keys\/$4`     echo &quot;$response&quot; } # $1 - remote url # $2 - api token # $3 - repository identifier # $4 - deploy key identifier enableRepositoryDeployKey() {     local response=`curl -s -k -X POST --header &quot;Private-Token: $2&quot; $1\/api\/v4\/projects\/$3\/deploy_keys\/$4\/enable`     echo &quot;$response&quot; } # $1 - branch # $2 \u2013 separator getCanonicalBranchName() {     local branch=&quot;&quot;     IFS=$2 read -r -a array &lt;&lt;&lt; &quot;$1&quot;     length=${#array[@]}     for index in &quot;${!array[@]}&quot;     do         if [ $index -gt 0 ]; then             if [ $index -eq 1 ]; then                 local branch=&quot;${array[index]}&quot;             else                 local branch=&quot;$branch\/${array[index]}&quot;             fi         fi     done     echo &quot;$branch&quot; } PSWD=&quot;$(dirname &quot;$0&quot;)&quot; cd $PSWD while IFS= read -r REPOSITORY do     echo &quot;====================  &lt;$REPOSITORY&gt;  ====================&quot;     GITOLITE_REPO=$GITOLITE$REPOSITORY     echo &quot;Run cloning remote repository $GITOLITE_REPO&quot;     git clone $GITOLITE_REPO     cd $REPOSITORY     GITLAB_REPO=$GITLAB$REPOSITORY.git     echo &quot;Initialize remote gitgab repository $GITLAB_REPO&quot;     PROJECT=$(initRemoteRepository $GITLAB_URL $API_TOKEN $REPOSITORY)     echo &quot;Remote repository initialized identifier $PROJECT&quot;     echo &quot;Add deploy key and enable write access to remote repository $REPOSITORY ($PROJECT)&quot;     response=$(enableRepositoryDeployKey $GITLAB_URL $API_TOKEN $PROJECT $DEPLOY_KEY_ID)     response=$(setRepositoryWriteAccess $GITLAB_URL $API_TOKEN $PROJECT $DEPLOY_KEY_ID)     echo &quot;Add new remote url for repository $GITLAB_REPO&quot;     git remote add gitlab $GITLAB_REPO     # push all branches     IFS_BACK=$IFS     IFS=$'\\n'     branches=$(git branch -r)     for branchName in $branches; do         trimBranchName=`echo $branchName | xargs`         canonicalBranchName=$(getCanonicalBranchName $trimBranchName '\/')         echo &quot;$trimBranchName ($canonicalBranchName) init push&quot;         git checkout -b $canonicalBranchName remotes\/origin\/$canonicalBranchName         git push -f gitlab $canonicalBranchName     done     IFS=$IFS_BACK     cd ..     rm -r -f $REPOSITORY     echo &quot;====================  &lt;$REPOSITORY&gt;  ====================&quot;     echo &quot;&quot; done &lt; &quot;$REPOSITORIES&quot;<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0432\u043e\u0434\u0430 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">====================  &lt;project&gt;  ==================== Run cloning remote repository git@skynet-uro.bank.srv:project Cloning into 'project'... remote: Counting objects: 62, done. remote: Compressing objects: 100% (61\/61), done. remote: Total 62 (delta 21), reused 0 (delta 0) Receiving objects: 100% (62\/62), 15.57 KiB | 0 bytes\/s, done. Resolving deltas: 100% (21\/21), done. Current folder path: \/app\/migration\/project Initialize remote gitgab repository git@127.0.0.1:project.git Remote repository initialized identifier 222 Enable deploy key write access to remote repository project (222) Set write access to remote repository project (222) Add new remote url for repository git@127.0.0.1:project.git Push to new remote gitlab repository git@127.0.0.1:project.git Counting objects: 55, done. Delta compression using up to 2 threads. Compressing objects: 100% (38\/38), done. Writing objects: 100% (55\/55), 14.65 KiB | 0 bytes\/s, done. Total 55 (delta 18), reused 50 (delta 16) To git@127.0.0.1:project.git  * [new branch]      master -&gt; master &lt;--- gitlab\/master (master) init push fatal: A branch named 'master' already exists. Everything up-to-date ---&gt; gitlab\/master (master) success pushed &lt;--- origin\/v0.0.0 (v0.0.0) init push Branch v0.0.0 set up to track remote branch v0.0.0 from origin. Switched to a new branch 'v0.0.0' Total 0 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for v0.0.0, visit: remote:   https:\/\/127.0.0.1:8082\/project\/merge_requests\/new?merge_request%5Bsource_branch%5D=v0.0.0 remote: To git@127.0.0.1:project.git  * [new branch]      v0.0.0 -&gt; v0.0.0 ---&gt; origin\/v0.0.0 (v0.0.0) success pushed &lt;--- origin\/v0.0.0-13 (v0.0.0-13) init push Branch v0.0.0-13 set up to track remote branch v0.0.0-13 from origin. Switched to a new branch 'v0.0.0-13' Total 0 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for v0.0.0-13, visit: remote:   https:\/\/127.0.0.1:8082\/project\/merge_requests\/new?merge_request%5Bsource_branch%5D=v0.0.0-13 remote: To git@127.0.0.1:project.git  * [new branch]      v0.0.0-13 -&gt; v0.0.0-13 ---&gt; origin\/v0.0.0-13 (v0.0.0-13) success pushed &lt;--- origin\/v0.0.0-15 (v0.0.0-15) init push Branch v0.0.0-15 set up to track remote branch v0.0.0-15 from origin. Switched to a new branch 'v0.0.0-15' Total 0 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for v0.0.0-15, visit: remote:   https:\/\/127.0.0.1:8082\/project\/merge_requests\/new?merge_request%5Bsource_branch%5D=v0.0.0-15 remote: To git@127.0.0.1:project.git  * [new branch]      v0.0.0-15 -&gt; v0.0.0-15 ---&gt; origin\/v0.0.0-15 (v0.0.0-15) success pushed &lt;--- origin\/v0.0.1 (v0.0.1) init push Branch v0.0.1 set up to track remote branch v0.0.1 from origin. Switched to a new branch 'v0.0.1' Total 0 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for v0.0.1, visit: remote:   https:\/\/127.0.0.1:8082\/project\/merge_requests\/new?merge_request%5Bsource_branch%5D=v0.0.1 remote: To git@127.0.0.1:project.git  * [new branch]      v0.0.1 -&gt; v0.0.1 ---&gt; origin\/v0.0.1 (v0.0.1) success pushed &lt;--- origin\/v0.0.1-11 (v0.0.1-11) init push Branch v0.0.1-11 set up to track remote branch v0.0.1-11 from origin. Switched to a new branch 'v0.0.1-11' Total 0 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for v0.0.1-11, visit: remote:   https:\/\/127.0.0.1:8082\/project\/merge_requests\/new?merge_request%5Bsource_branch%5D=v0.0.1-11 remote: To git@127.0.0.1:project.git  * [new branch]      v0.0.1-11 -&gt; v0.0.1-11 ---&gt; origin\/v0.0.1-11 (v0.0.1-11) success pushed &lt;--- origin\/v0.0.2 (v0.0.2) init push Branch v0.0.2 set up to track remote branch v0.0.2 from origin. Switched to a new branch 'v0.0.2' Total 0 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for v0.0.2, visit: remote:   https:\/\/127.0.0.1:8082\/project\/merge_requests\/new?merge_request%5Bsource_branch%5D=v0.0.2 remote: To git@127.0.0.1:project.git  * [new branch]      v0.0.2 -&gt; v0.0.2 ---&gt; origin\/v0.0.2 (v0.0.2) success pushed &lt;--- origin\/v0.0.3 (v0.0.3) init push Branch v0.0.3 set up to track remote branch v0.0.3 from origin. Switched to a new branch 'v0.0.3' Counting objects: 7, done. Delta compression using up to 2 threads. Compressing objects: 100% (4\/4), done. Writing objects: 100% (4\/4), 592 bytes | 0 bytes\/s, done. Total 4 (delta 3), reused 1 (delta 0) remote: remote: To create a merge request for v0.0.3, visit: remote:   https:\/\/127.0.0.1:8082\/project\/merge_requests\/new?merge_request%5Bsource_branch%5D=v0.0.3 remote: To git@127.0.0.1:project.git  * [new branch]      v0.0.3 -&gt; v0.0.3 ---&gt; origin\/v0.0.3 (v0.0.3) success pushed ====================  &lt;project&gt;  ====================<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/492122\/\"> https:\/\/habr.com\/ru\/post\/492122\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/492122\/\">\n<p><em>\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043d\u0435\u0440\u0435\u0434\u043a\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0442\u0440\u0443\u0434\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e, \u043a\u043e\u0433\u0434\u0430 \u043e\u0431\u044a\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438, \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0435\u043b\u0438\u043a, \u0447\u0442\u043e \u0432\u044b\u0433\u043e\u0434\u043d\u0435\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0435\u0433\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u0418\u043c\u0435\u043d\u043d\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 Gitolite \u043d\u0430 GitLab \u0438 \u043f\u043e\u0431\u0443\u0434\u0438\u043b\u0430 \u043c\u0435\u043d\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e \u043e \u043c\u043e\u0435\u043c \u043e\u043f\u044b\u0442\u0435 \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0432\u043e\u043f\u0440\u043e\u0441\u0435.<\/em><br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/6s\/mh\/kn\/6smhkn4gi8_7ngzatgsoijdvyti.png\"\/><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-300056","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/300056","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=300056"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/300056\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=300056"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=300056"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=300056"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}