<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: K8sCat</title>
    <description>The latest articles on DEV Community by K8sCat (@k8scat).</description>
    <link>https://dev.to/k8scat</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F574340%2Fadd69fa7-e696-40dd-8ffc-232ab76042d0.jpeg</url>
      <title>DEV Community: K8sCat</title>
      <link>https://dev.to/k8scat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/k8scat"/>
    <language>en</language>
    <item>
      <title>Backup your repos via GitHub Actions</title>
      <dc:creator>K8sCat</dc:creator>
      <pubDate>Sun, 27 Jun 2021 17:45:08 +0000</pubDate>
      <link>https://dev.to/k8scat/backup-your-repo-via-github-actions-124c</link>
      <guid>https://dev.to/k8scat/backup-your-repo-via-github-actions-124c</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2ihz5zyv6qbafnw9ds8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2ihz5zyv6qbafnw9ds8.png" alt="GitHub Actions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anything may be lost unless you have a backup for them.&lt;/p&gt;

&lt;p&gt;This article tell you how to backup your git repositories via GitHub Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our target
&lt;/h2&gt;

&lt;p&gt;In this article, our final target is to backup git repositories under the user-a to another user named user-b .&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation
&lt;/h2&gt;

&lt;p&gt;Before all, we need to create a new git repository used to run the backup workflow, and there will be some files in it and you can use the command tree to have a check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── .github
│   └── workflows
│       └── mirror.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normally, we wouldn’t to expose our secrets directly, so we need to create some secrets in the GitHub repository settings which will be used to clone, create and push git repo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GH_TOKEN_A is the user-a ‘s GitHub AccessToken&lt;/li&gt;
&lt;li&gt;GH_TOKEN_B is the user-b ‘s GitHub AccessToken&lt;/li&gt;
&lt;li&gt;SLACK_WEBHOOK is used to notify us while the workflow started or ended&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mirror Workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  List user-a ‘s repos
&lt;/h3&gt;

&lt;p&gt;We’ll use the command-line tool gh to list user-a ‘s github repositories:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GH_TOKEN_A&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; gh_token_a
gh auth login &lt;span class="nt"&gt;--with-token&lt;/span&gt; &amp;lt; gh_token_a
gh repo list user-a &lt;span class="nt"&gt;-L&lt;/span&gt; 1000 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; a_repos
&lt;span class="nb"&gt;cat &lt;/span&gt;a_repos
&lt;span class="nb"&gt;cat &lt;/span&gt;a_repos | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create repo with the same name
&lt;/h3&gt;

&lt;p&gt;Before push the git repo, we need to make the repo existed under the user user-b , like list repos above, we also use gh to create a git repo with the same name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh repo create user-b/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--private&lt;/span&gt; &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Clone repo
&lt;/h3&gt;

&lt;p&gt;While we make sure that the repo with the same name is already existed under the user user-b , we can clone the git repo from the user user-a first.&lt;/p&gt;

&lt;p&gt;Unlike normal git clone, we should use the flag --bare to &lt;br&gt;
clone the repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--bare&lt;/span&gt; https://&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GH_TOKEN_A&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;@github.com/user-a/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.git &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Push repo
&lt;/h3&gt;

&lt;p&gt;Finally, we can push the cloned repo to user-b ‘s repo which has the same name.&lt;/p&gt;

&lt;p&gt;And we will use two flags to push them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--all&lt;/code&gt; means push all branches&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--mirror&lt;/code&gt; means push all refs, contains all branches and tags
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;mirror_repo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GH_TOKEN_B&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@github.com/user-b/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.git"&lt;/span&gt;
git push &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;mirror_repo&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
&lt;/span&gt;git push &lt;span class="nt"&gt;--mirror&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;mirror_repo&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Full workflow script
&lt;/h2&gt;

&lt;p&gt;This is the full workflow script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;name: Mirror repos

on:
  schedule:
    - cron: &lt;span class="s2"&gt;"0 18 * * 0-4"&lt;/span&gt; &lt;span class="c"&gt;# 设置定时任务，周一到周五的凌晨2点进行备份&lt;/span&gt;
  workflow_dispatch: &lt;span class="c"&gt;# 手动触发构建&lt;/span&gt;

&lt;span class="nb"&gt;jobs&lt;/span&gt;:
  mirror:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: GitHub CLI version
        run: gh &lt;span class="nt"&gt;--version&lt;/span&gt;

      - name: List repos
        &lt;span class="nb"&gt;env&lt;/span&gt;:
          GH_TOKEN_A: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.GH_TOKEN_A &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
        run: |
          &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GH_TOKEN_A&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; gh_token_a
          gh auth login &lt;span class="nt"&gt;--with-token&lt;/span&gt; &amp;lt; gh_token_a
          gh repo list user-a &lt;span class="nt"&gt;-L&lt;/span&gt; 1000 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; a_repos
          &lt;span class="nb"&gt;cat &lt;/span&gt;a_repos
          &lt;span class="nb"&gt;cat &lt;/span&gt;a_repos | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;

      - name: Mirror repos
        &lt;span class="nb"&gt;env&lt;/span&gt;:
          GH_TOKEN_A: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.GH_TOKEN_A &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          GH_TOKEN_B: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.GH_TOKEN_B &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          IGNORE_REPOS: &lt;span class="s2"&gt;"/repo_a/repo_b/"&lt;/span&gt;
          ONLY_BRANCH_REPOS: &lt;span class="s2"&gt;"/repo_c/repo_d/"&lt;/span&gt;
        run: |
          &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GH_TOKEN_B&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; gh_token_b
          gh auth login &lt;span class="nt"&gt;--with-token&lt;/span&gt; &amp;lt; gh_token_b

          &lt;span class="nb"&gt;mkdir &lt;/span&gt;repos
          &lt;span class="nb"&gt;cd &lt;/span&gt;repos
          &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt;
          &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GITHUB_WORKSPACE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/a_repos | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;repo&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
            &lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $1}'&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt;/ &lt;span class="s1"&gt;'{print $2}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IGNORE_REPOS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ &lt;span class="s2"&gt;"/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true

            &lt;/span&gt;gh repo create user-b/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--private&lt;/span&gt; &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
            rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

            git clone &lt;span class="nt"&gt;--bare&lt;/span&gt; https://&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GH_TOKEN_A&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;@github.com/user-a/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.git &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

            &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
            &lt;span class="nv"&gt;mirror_repo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GH_TOKEN_B&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@github.com/user-b/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.git"&lt;/span&gt;
            git push &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;mirror_repo&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
            &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ONLY_BRANCH_REPOS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ &lt;span class="s2"&gt;"/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
            &lt;/span&gt;git push &lt;span class="nt"&gt;--mirror&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;mirror_repo&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
            cd&lt;/span&gt; -
          &lt;span class="k"&gt;done&lt;/span&gt;

      - name: Slack Notification
        uses: rtCamp/action-slack-notify@v2
        &lt;span class="nb"&gt;env&lt;/span&gt;:
          SLACK_WEBHOOK: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.SLACK_WEBHOOK &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>github</category>
      <category>backup</category>
      <category>mirror</category>
    </item>
  </channel>
</rss>
