8
n8n 中文网amn8n.com

将工作流备份到 Gitea 上的 git 仓库

高级

这是一个Other领域的自动化工作流,包含 20 个节点。主要使用 If, N8n, Set, Code, HttpRequest 等节点。 备份工作流到 Gitea 上的 git 仓库

前置要求
  • 可能需要目标 API 的认证凭证

分类

工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "Ef2uEM6H19K2DGUO",
  "meta": {
    "templateId": "2532",
    "templateCredsSetupCompleted": true
  },
  "name": "将工作流备份到 Gitea 上的 git 仓库",
  "tags": [
    {
      "id": "UWNX4AzSneYNvTQI",
      "name": "Gitea",
      "createdAt": "2025-01-28T23:10:06.823Z",
      "updatedAt": "2025-01-28T23:10:06.823Z"
    },
    {
      "id": "4b7Bs9T0Cagsg5tT",
      "name": "Git",
      "createdAt": "2025-01-28T23:10:26.545Z",
      "updatedAt": "2025-01-28T23:10:26.545Z"
    },
    {
      "id": "HiN3ehC2KkAp5kVs",
      "name": "Backup",
      "createdAt": "2025-01-28T23:10:38.878Z",
      "updatedAt": "2025-01-28T23:10:38.878Z"
    }
  ],
  "nodes": [
    {
      "id": "639582ef-f13e-4844-bd10-647718079121",
      "name": "全局变量",
      "type": "n8n-nodes-base.set",
      "position": [
        600,
        240
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "repo.url",
              "value": "https://git.vdm.dev"
            },
            {
              "name": "repo.name",
              "value": "workflows"
            },
            {
              "name": "repo.owner",
              "value": "n8n"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "9df89713-220e-43b9-b234-b8f5612629cf",
      "name": "n8n",
      "type": "n8n-nodes-base.n8n",
      "position": [
        840,
        240
      ],
      "parameters": {
        "filters": {},
        "requestOptions": {}
      },
      "credentials": {
        "n8nApi": {
          "id": "ZjfxOLTTHX2CzbKa",
          "name": "Main N8N Account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4b2d375c-a339-404c-babd-555bd2fc4091",
      "name": "定时触发器",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        380,
        240
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 45
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ea026e96-0db1-41fd-b003-2f2bf4662696",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2620,
        300
      ],
      "parameters": {
        "height": 80,
        "content": "工作流更改已提交到仓库"
      },
      "typeVersion": 1
    },
    {
      "id": "9c402daa-6d03-485d-b8a0-58f1b65d396d",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2260,
        180
      ],
      "parameters": {
        "height": 80,
        "content": "检查工作流中是否有任何更改"
      },
      "typeVersion": 1
    },
    {
      "id": "1d9216d9-bf8d-4945-8a58-22fb1ffc9be8",
      "name": "便签 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1800,
        580
      ],
      "parameters": {
        "height": 80,
        "content": "为工作流创建新文件"
      },
      "typeVersion": 1
    },
    {
      "id": "60a3953b-d9f1-4afd-b299-e314116b96c6",
      "name": "便签 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1300,
        200
      ],
      "parameters": {
        "height": 80,
        "content": "检查文件是否存在于仓库中"
      },
      "typeVersion": 1
    },
    {
      "id": "f2340ad0-71a1-4c74-8d90-bcb974b8b305",
      "name": "便签 5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        780,
        180
      ],
      "parameters": {
        "height": 80,
        "content": "获取所有工作流"
      },
      "typeVersion": 1
    },
    {
      "id": "617bea19-341a-4e9d-b6fd-6b417e58d756",
      "name": "便签6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        500,
        180
      ],
      "parameters": {
        "height": 80,
        "content": "设置变量"
      },
      "typeVersion": 1
    },
    {
      "id": "72f806d7-e30a-470b-9ba2-37fdc35de3c8",
      "name": "设置数据更新节点",
      "type": "n8n-nodes-base.set",
      "position": [
        1920,
        240
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "0a6b769a-c66d-4784-92c7-a70caa28e1ba",
              "name": "item",
              "type": "object",
              "value": "={{ $node[\"ForEach\"].json }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "bca5e2c4-7aa3-48df-9e5f-b31977970c28",
      "name": "设置数据创建节点",
      "type": "n8n-nodes-base.set",
      "position": [
        1220,
        640
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "0a6b769a-c66d-4784-92c7-a70caa28e1ba",
              "name": "item",
              "type": "object",
              "value": "={{ $node[\"ForEach\"].json }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "bf74b1ea-e066-462b-9c3d-ed4a44a09a33",
      "name": "Base64 编码更新",
      "type": "n8n-nodes-base.code",
      "position": [
        2140,
        240
      ],
      "parameters": {
        "language": "python",
        "pythonCode": "import json\nimport base64\nfrom js import Object\n\n# Assuming _input.all() returns a JavaScript object\njs_object = _input.all()\n\n# Convert the JsProxy object to a Python dictionary\ndef js_to_py(js_obj):\n    if isinstance(js_obj, (str, int, float, bool)) or js_obj is None:\n        # Base types are already Python-compatible\n        return js_obj\n    elif isinstance(js_obj, list):\n        # Convert lists recursively\n        return [js_to_py(item) for item in js_obj]\n    elif hasattr(js_obj, \"__iter__\") and not isinstance(js_obj, str):\n        # Handle JsProxy objects (JavaScript objects or arrays)\n        if hasattr(js_obj, \"keys\"):\n            # If it has keys, treat it as a dictionary\n            return {key: js_to_py(js_obj[key]) for key in Object.keys(js_obj)}\n        else:\n            # Otherwise, treat it as a list\n            return [js_to_py(item) for item in js_obj]\n    else:\n        # Fallback for other types\n        return js_obj\n\n# Convert the JavaScript object to a Python dictionary\ninput_dict = js_to_py(js_object)\n\n# Step 0: get the correct data set of the workflow\ninner_data = input_dict[0].get('json').get('item')\n\n# Step 1: Convert the dictionary to a pretty-printed JSON string\njson_string = json.dumps(inner_data, indent=4)\n\n# Step 2: Encode the JSON string to bytes\njson_bytes = json_string.encode('utf-8')\n\n# Step 3: Convert the bytes to a base64 string\nbase64_string = base64.b64encode(json_bytes).decode('utf-8')\n\n# Step 5: Create the return object with the base64 string and its SHA-256 hash\nreturn_object = {\n    \"item\": base64_string\n}\n\n# Return the object\nreturn return_object"
      },
      "typeVersion": 2
    },
    {
      "id": "2d817c66-5aa0-45c9-b851-4b5e3dbecca4",
      "name": "Base64 编码创建",
      "type": "n8n-nodes-base.code",
      "position": [
        1520,
        640
      ],
      "parameters": {
        "language": "python",
        "pythonCode": "import json\nimport base64\nfrom js import Object\n\n# Assuming _input.all() returns a JavaScript object\njs_object = _input.all()\n\n# Convert the JsProxy object to a Python dictionary\ndef js_to_py(js_obj):\n    if isinstance(js_obj, (str, int, float, bool)) or js_obj is None:\n        # Base types are already Python-compatible\n        return js_obj\n    elif isinstance(js_obj, list):\n        # Convert lists recursively\n        return [js_to_py(item) for item in js_obj]\n    elif hasattr(js_obj, \"__iter__\") and not isinstance(js_obj, str):\n        # Handle JsProxy objects (JavaScript objects or arrays)\n        if hasattr(js_obj, \"keys\"):\n            # If it has keys, treat it as a dictionary\n            return {key: js_to_py(js_obj[key]) for key in Object.keys(js_obj)}\n        else:\n            # Otherwise, treat it as a list\n            return [js_to_py(item) for item in js_obj]\n    else:\n        # Fallback for other types\n        return js_obj\n\n# Convert the JavaScript object to a Python dictionary\ninput_dict = js_to_py(js_object)\n\n# Step 0: get the correct data set of the workflow\ninner_data = input_dict[0].get('json').get('item')\n\n# Step 1: Convert the dictionary to a pretty-printed JSON string\njson_string = json.dumps(inner_data, indent=4)\n\n# Step 2: Encode the JSON string to bytes\njson_bytes = json_string.encode('utf-8')\n\n# Step 3: Convert the bytes to a base64 string\nbase64_string = base64.b64encode(json_bytes).decode('utf-8')\n\n# Step 4: Create the return object with the base64 string in 'item'\nreturn_object = {\n    \"item\": base64_string\n}\n\n# Return the object\nreturn return_object"
      },
      "typeVersion": 2
    },
    {
      "id": "41a7da89-1c8c-4100-8c30-d0788962efc1",
      "name": "存在",
      "type": "n8n-nodes-base.if",
      "position": [
        1640,
        260
      ],
      "parameters": {
        "options": {
          "ignoreCase": false
        },
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "16a9182d-059d-4774-ba95-654fb4293fdb",
              "operator": {
                "type": "object",
                "operation": "notExists",
                "singleValue": true
              },
              "leftValue": "={{ $json.error }}",
              "rightValue": 404
            }
          ]
        }
      },
      "executeOnce": false,
      "typeVersion": 2.2,
      "alwaysOutputData": false
    },
    {
      "id": "ab9246eb-a253-4d76-b33b-5f8f12342542",
      "name": "已更改",
      "type": "n8n-nodes-base.if",
      "position": [
        2360,
        240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "e0c66624-429a-4f1f-bf7b-1cc1b32bad7b",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.item }}",
              "rightValue": "={{ $('GetGitea').item.json.content }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4278a176-6496-4817-82f8-591539619673",
      "name": "PutGitea",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2700,
        360
      ],
      "parameters": {
        "url": "={{ $('Globals').item.json.repo.url }}/api/v1/repos/{{ $('Globals').item.json.repo.owner }}/{{ $('Globals').item.json.repo.name }}/contents/{{ encodeURIComponent($('GetGitea').item.json.name) }}",
        "method": "PUT",
        "options": {},
        "sendBody": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "content",
              "value": "={{ $('Base64EncodeUpdate').item.json.item }}"
            },
            {
              "name": "sha",
              "value": "={{ $('GetGitea').item.json.sha }}"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "gTvBAgkOmqhl5Nmr",
          "name": "Gitea Token"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "12307a61-e7cc-42f9-a7c7-8abbcab9e3ab",
      "name": "GetGitea",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        1380,
        260
      ],
      "parameters": {
        "url": "={{ $('Globals').item.json.repo.url }}/api/v1/repos/{{ encodeURIComponent($('Globals').item.json.repo.owner) }}/{{ encodeURIComponent($('Globals').item.json.repo.name) }}/contents/{{ encodeURIComponent($json.name) }}.json",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "gTvBAgkOmqhl5Nmr",
          "name": "Gitea Token"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "24fda439-bb23-4392-a297-d8070907f9e6",
      "name": "PostGitea",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1920,
        640
      ],
      "parameters": {
        "url": "={{ $('Globals').item.json.repo.url }}/api/v1/repos/{{ $('Globals').item.json.repo.owner }}/{{ $('Globals').item.json.repo.name }}/contents/{{ encodeURIComponent($('ForEach').item.json.name) }}.json",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "content",
              "value": "={{ $json.item }}"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "gTvBAgkOmqhl5Nmr",
          "name": "Gitea Token"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "43a60315-d381-4ac4-be4c-f6a158651a00",
      "name": "ForEach",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1060,
        240
      ],
      "parameters": {
        "options": {}
      },
      "executeOnce": false,
      "typeVersion": 3
    },
    {
      "id": "88578dc4-2398-48d0-b0ba-2198b35bb994",
      "name": "便签 4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        380,
        440
      ],
      "parameters": {
        "width": 560,
        "height": 1620,
        "content": "### **📌 将工作流备份到 Gitea 上的 Git 仓库设置指南**"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "84ba3f3f-fbc8-4792-8e28-198f515fef4e",
  "staticData": {
    "node:Schedule Trigger": {
      "recurrenceRules": []
    }
  },
  "connections": {
    "n8n": {
      "main": [
        [
          {
            "node": "ForEach",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Exist": {
      "main": [
        [
          {
            "node": "SetDataUpdateNode",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "SetDataCreateNode",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Changed": {
      "main": [
        [
          {
            "node": "PutGitea",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "ForEach",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ForEach": {
      "main": [
        [],
        [
          {
            "node": "GetGitea",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Globals": {
      "main": [
        [
          {
            "node": "n8n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GetGitea": {
      "main": [
        [
          {
            "node": "Exist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PutGitea": {
      "main": [
        [
          {
            "node": "ForEach",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PostGitea": {
      "main": [
        [
          {
            "node": "ForEach",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Globals",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SetDataCreateNode": {
      "main": [
        [
          {
            "node": "Base64EncodeCreate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SetDataUpdateNode": {
      "main": [
        [
          {
            "node": "Base64EncodeUpdate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Base64EncodeCreate": {
      "main": [
        [
          {
            "node": "PostGitea",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Base64EncodeUpdate": {
      "main": [
        [
          {
            "node": "Changed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "triggerCount": 1
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

高级 - 其他

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量20
分类1
节点类型8
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

作者
Octoleo

Octoleo

@octoleo

Hi, I’m Llewellyn van der Merwe, also known as <<ewe>>yn, pioneering tools to automate freedom!

外部链接
在 n8n.io 查看

分享此工作流