{"id":12203,"date":"2025-04-14T00:25:39","date_gmt":"2025-04-13T15:25:39","guid":{"rendered":"https:\/\/www.webcyou.com\/?p=12203"},"modified":"2025-04-14T00:25:39","modified_gmt":"2025-04-13T15:25:39","slug":"taurirust-x-ai-%e3%81%a7%e4%bd%9c%e3%82%8b-gitgui%e3%82%af%e3%83%a9%e3%82%a4%e3%82%a2%e3%83%b3%e3%83%88%e3%82%a2%e3%83%97%e3%83%aa-%e3%81%9d%e3%81%ae5","status":"publish","type":"post","link":"https:\/\/www.webcyou.com\/?p=12203","title":{"rendered":"Tauri(Rust) \u00d7 AI \u3067\u4f5c\u308b GitGUI\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u30a2\u30d7\u30ea \u305d\u306e5"},"content":{"rendered":"\n<p>\u3069\u3082\u3067\u3059\u3002<\/p>\n<p>\u4eca\u56de\u306f\u524d\u56de\u306e\u300c<a href=\"https:\/\/www.webcyou.com\/?p=12180\">Tauri(Rust) \u00d7 AI \u3067\u4f5c\u308b GitGUI\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u30a2\u30d7\u30ea \u305d\u306e4<\/a>\u300d\u306e\u7d9a\u304d\u3068\u306a\u308a\u3001Rust\u5074\u306e\u30ec\u30dd\u30b8\u30c8\u30ea\u306e\u30af\u30ed\u30fc\u30f3\u51e6\u7406\u3082\u8ffd\u52a0\u3057\u3066\u3044\u3053\u3046\u3068\u601d\u3044\u307e\u3059\u3002<\/p>\n<p>\u307e\u305a\u306f\u3001<span data-lexical-text=\"true\">Local\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30d1\u30b9\u3092Mac\u3060\u3068\u3001<\/span><\/p>\n<p><span data-lexical-text=\"true\">\u300c\u30e9\u30a4\u30d6\u30e9\u30ea\uff1eApplication Support\uff1eBranchie\uff1erepository\u300d<\/span><\/p>\n<p>\u306b\u8a72\u5f53\u3059\u308b\u7b87\u6240\u306b\u30af\u30ed\u30fc\u30f3\u3067\u304d\u308b\u3088\u3046\u306b\u8a2d\u5b9a\u3057\u307e\u3059\u3002<\/p>\n<p>\u00a0<\/p>\n<h4>\u30ed\u30fc\u30ab\u30eb\u30ec\u30dd\u30b8\u30c8\u30ea\u4f5c\u6210\u5148\u306e\u6307\u5b9a\u306a\u3069\u3092\u8abf\u6574<\/h4>\n<p>Cursor\u306b\u4ee5\u4e0b\u3092\u6307\u793a\u3002<\/p>\n<p><span data-lexical-text=\"true\">\u300c<strong>git \u306e\u30ec\u30dd\u30b8\u30c8\u30eaURL\u5165\u529b\u753b\u9762\u306b\u3066\u3001<\/strong><\/span><strong>Local\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30d1\u30b9\u3092<\/strong><span data-lexical-text=\"true\"><strong>dirs::data_dir() + &#8220;Branchie\/repository&#8221; \u306b\u3057\u305f\u3044\u3002<\/strong>\u300d<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">dirs = \"5.0\"<\/pre>\n<p>dirs\u30af\u30ec\u30fc\u30c8\u3092install\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">#[tauri::command]\nfn get_default_repository_path() -&gt; Result&lt;String, String&gt; {\n    let data_dir = dirs::data_dir()\n        .ok_or_else(|| \"\u30c7\u30fc\u30bf\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\".to_string())?;\n    \n    let repo_dir = data_dir.join(\"Branchie\").join(\"repository\");\n    \n    \/\/ \u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u304c\u5b58\u5728\u3057\u306a\u3044\u5834\u5408\u306f\u4f5c\u6210\n    if !repo_dir.exists() {\n        std::fs::create_dir_all(&amp;repo_dir)\n            .map_err(|e| format!(\"\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u4f5c\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {}\", e))?;\n    }\n    \n    Ok(repo_dir.to_string_lossy().to_string())\n}<\/pre>\n<p>\u30c7\u30d5\u30a9\u30eb\u30c8\u30d1\u30b9\u3092\u53d6\u5f97\u3059\u308b\u95a2\u6570\u306e\u4f5c\u6210\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">const defaultPath = await invoke&lt;string&gt;(\"get_default_repository_path\");\nlocalPath.value = defaultPath;<\/pre>\n<p>\u30d5\u30ed\u30f3\u30c8\u5074\u3067\u53d6\u5f97\u3057\u3066\u30bb\u30c3\u30c8\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">\u3053\u308c\u3067\u3001\u4ee5\u4e0b\u306e\u6a5f\u80fd\u304c\u5b9f\u88c5\u3055\u308c\u307e\u3057\u305f\uff1a\n1.Rust\u5074\uff1a\n  \u30fbdirs\u30af\u30ec\u30fc\u30c8\u3092\u4f7f\u7528\u3057\u3066\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30fc\u30bf\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u53d6\u5f97\n  \u30fb\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30ea\u30dd\u30b8\u30c8\u30ea\u30d1\u30b9\u3092data_dir() + \"Branchie\/repository\"\u306b\u8a2d\u5b9a\n  \u30fb\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u304c\u5b58\u5728\u3057\u306a\u3044\u5834\u5408\u306f\u81ea\u52d5\u7684\u306b\u4f5c\u6210\n2.\u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u5074\uff1a\n  \u30fb\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u30de\u30a6\u30f3\u30c8\u6642\u306b\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30ea\u30dd\u30b8\u30c8\u30ea\u30d1\u30b9\u3092\u53d6\u5f97\n  \u30fb\u53d6\u5f97\u3057\u305f\u30d1\u30b9\u3092\u30ed\u30fc\u30ab\u30eb\u30d1\u30b9\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3068\u3057\u3066\u8a2d\u5b9a\n\u3053\u308c\u306b\u3088\u308a\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u52d5\u4f5c\u306b\u306a\u308a\u307e\u3059\uff1a\n1.\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u8d77\u52d5\u6642\uff1a\n  \u30fb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30fc\u30bf\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u53d6\u5f97\n  \u30fbBranchie\/repository\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u4f5c\u6210\uff08\u5b58\u5728\u3057\u306a\u3044\u5834\u5408\uff09\n  \u30fb\u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u306b\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30ea\u30dd\u30b8\u30c8\u30ea\u30d1\u30b9\u3092\u63d0\u4f9b\n2.\u30ea\u30dd\u30b8\u30c8\u30ea\u30af\u30ed\u30fc\u30f3\u6642\uff1a\n  \u30fb\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30ea\u30dd\u30b8\u30c8\u30ea\u30d1\u30b9\u304c\u81ea\u52d5\u7684\u306b\u8a2d\u5b9a\u3055\u308c\u308b\n  \u30fb\u30e6\u30fc\u30b6\u30fc\u304c\u5225\u306e\u30d1\u30b9\u3092\u6307\u5b9a\u3059\u308b\u3053\u3068\u3082\u53ef\u80fd\n\u30ea\u30f3\u30bf\u30fc\u30a8\u30e9\u30fc\u306ftsconfig.json\u306e\u8a2d\u5b9a\u306b\u95a2\u9023\u3057\u3066\u3044\u307e\u3059\u304c\u3001\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u52d5\u4f5c\u306b\u306f\u5f71\u97ff\u3057\u307e\u305b\u3093\u3002\u5fc5\u8981\u306b\u5fdc\u3058\u3066tsconfig.json\u306e\u8a2d\u5b9a\u3092\u8abf\u6574\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\n\u6b21\u306e\u30b9\u30c6\u30c3\u30d7\u3068\u3057\u3066\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u6a5f\u80fd\u3092\u8ffd\u52a0\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\uff1a\n1.\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u9078\u629e\u30c0\u30a4\u30a2\u30ed\u30b0\u306e\u5b9f\u88c5\n2.\u30ea\u30dd\u30b8\u30c8\u30ea\u30d1\u30b9\u306e\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\n3.\u30ea\u30dd\u30b8\u30c8\u30ea\u306e\u5b58\u5728\u30c1\u30a7\u30c3\u30af\n\u3053\u308c\u3089\u306e\u6a5f\u80fd\u3092\u8ffd\u52a0\u3057\u307e\u3059\u304b\uff1f<\/pre>\n<p>\u7d50\u69cb\u3001\u30b0\u30a4\u30b0\u30a4\u304d\u307e\u3059\u306d\u3002\u305d\u308c\u3067\u306f\u63d0\u6848\u3055\u308c\u305f\u307e\u307e\u9032\u3081\u3066\u307f\u307e\u3059\u3002<\/p>\n<p>\u300c<strong>1. 2. 3\u306e\u5b9f\u88c5\u3092\u9032\u3081\u3066\u304f\u3060\u3055\u3044<\/strong>\u300d<\/p>\n<p>\u3059\u308b\u3068\u3001<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">use tauri::api::dialog::FileDialogBuilder;<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">#[tauri::command]\nasync fn select_directory() -&gt; Result&lt;String, String&gt; {\n    let path = FileDialogBuilder::new()\n        .set_title(\"Select Directory\")\n        .pick_folder()\n        .await\n        .ok_or_else(|| \"\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u304c\u9078\u629e\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f\".to_string())?\n        .to_string_lossy()\n        .to_string();\n    \n    Ok(path)\n}<\/pre>\n<p>\u3068\u3044\u3063\u305f\u611f\u3058\u3067\u3001\u300c<span style=\"color: initial; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;\">FileDialogBuilder<\/span>\u300d\u3092\u8ffd\u52a0\u3057\u3001\u751f\u6210\u3057\u3088\u3046\u3068\u3057\u307e\u3059\u304c\u3001\u3053\u308c\u306f\u591a\u5206Tauri \u30d0\u30fc\u30b8\u30e7\u30f31.0\u306e\u4ed5\u69d8\u306a\u306e\u304b\u3068\u3002ChatGPT\u306b\u304a\u9858\u3044\u3057\u305f\u969b\u3082\u3053\u3061\u3089\u3092\u8ffd\u52a0\u3057\u3088\u3046\u3068\u3057\u3066\u4f55\u5ea6\u3082\u30a8\u30e9\u30fc\u306b\u306a\u308a\u30cf\u30de\u3063\u305f\u899a\u3048\u304c\u3002<\/p>\n<p>\u3053\u3061\u3089\u306f\u624b\u52d5\u3067\u5909\u66f4\u3057\u307e\u3057\u305f\u3002<\/p>\n<p>\u307e\u305a\u3001Rust\u5074\u3067\u4f7f\u7528\u3059\u308b\u30af\u30ec\u30fc\u30c8\u306f\u3001<\/p>\n<p>Cargo.tmol<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">tauri-plugin-dialog = \"2.2.1\"<\/pre>\n<p>\u305d\u3057\u3066\u3001<code>src-tauri\/capabilities\/default.json<\/code>\u306b&#8221;dialog:allow-open&#8221;\u306e\u8ffd\u52a0\u304c\u5fc5\u8981\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">\"permissions\": [\n  \"core:default\",\n  \"opener:default\",\n  \"dialog:allow-open\"\n]<\/pre>\n<p>\u305d\u3057\u3066\u3001<span style=\"color: initial; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;\">tauri::Builder::default()\u306b\u4ee5\u4e0b\u3092\u8ffd\u52a0<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">.plugin(tauri_plugin_dialog::init())<\/pre>\n<p>\u5168\u4f53\u7684\u306b\u306f\u3053\u3093\u306a\u611f\u3058\u3067\u3059\u304b\u306d\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">    tauri::Builder::default()\n        .plugin(tauri_plugin_dialog::init())\n        .invoke_handler(tauri::generate_handler![\n            save_credentials,\n            get_credentials,\n            get_default_repository_path,\n            validate_repository_path,\n            check_repository_exists,\n        ])\n        .run(tauri::generate_context!())\n        .expect(\"error while running tauri application\");\n}<\/pre>\n<p>\u30d5\u30ed\u30f3\u30c8\u5074\u306f\u3001\u547c\u3073\u51fa\u3057\u306e\u305f\u3081\u3001<span style=\"color: initial; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;\">&#8220;@tauri-apps\/plugin-dialog&#8221;\u30d1\u30c3\u30b1\u30fc\u30b8\u304c\u5fc5\u8981\u3068\u306a\u308b\u306e\u3067\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3059\u3002<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">npm install @tauri-apps\/plugin-dialog<\/pre>\n<p>\u00a0<\/p>\n<p>open\u30e1\u30bd\u30c3\u30c9\u3092\u7528\u3044\u3066\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u9078\u629e\u3059\u308b\u30c0\u30a4\u30a2\u30ed\u30b0\u3092\u8868\u793a\u3057\u307e\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">import { open } from \"@tauri-apps\/plugin-dialog\";\n\n....\n\nconst handleBrowse = async () =&gt; {\n    const selected = await open({\n        multiple: false,\n        directory: true,\n    });\n    if (selected) {\n        localPath.value = selected;\n    }\n};<\/pre>\n<p>\u3053\u308c\u3067\u3001\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30d1\u30b9\u306b\u306f\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30d1\u30b9\u304c\u6307\u5b9a\u3055\u308c\u3066\u304a\u308a\u3001\u30d1\u30b9\u6307\u5b9a\u3059\u308b\u30a4\u30f3\u30d7\u30c3\u30c8\u306e\u96a3\u306e\u30a2\u30a4\u30b3\u30f3\u3092\u30af\u30ea\u30c3\u30af\u3059\u308b\u3068\u3001\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u9078\u629e\u3059\u308b\u30c0\u30a4\u30a2\u30ed\u30b0\u304c\u8868\u793a\u3059\u308b\u3088\u3046\u306b\u306a\u308a\u307e\u3057\u305f\u3002<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone  wp-image-12206\" src=\"https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_1-1024x768.png\" alt=\"\" width=\"463\" height=\"347\" srcset=\"https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_1-1024x768.png 1024w, https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_1-300x225.png 300w, https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_1-768x576.png 768w, https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_1-1536x1152.png 1536w, https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_1.png 1600w\" sizes=\"auto, (max-width: 463px) 100vw, 463px\" \/><\/p>\n<h4>Git\u30ec\u30dd\u30b8\u30c8\u30ea\u306e\u30af\u30ed\u30fc\u30f3\u51e6\u7406<\/h4>\n<p>\u5f8c\u306f\u5b9f\u969b\u306b\u30af\u30ed\u30fc\u30f3\u3057\u3066\u304f\u308b\u51e6\u7406\u3092\u8ffd\u52a0\u3057\u307e\u3057\u3087\u3046\u3002<\/p>\n<p>Git\u5468\u308a\u3092\u64cd\u4f5c\u3059\u308b\u305f\u3081\u3001Git2\u30af\u30ec\u30fc\u30c8\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002\u305d\u308c\u3067\u306f\u6307\u793a\u3092\u3002<\/p>\n<p>\u300c<strong>git2\u30af\u30ec\u30fc\u30c8\u3092\u4f7f\u3063\u3066\u3001\u5b9f\u969b\u306bRepository URL\u3092\u5143\u306bLocal Destination\u306b\u30af\u30ed\u30fc\u30f3\u3059\u308b\u51e6\u7406\u3092\u8ffd\u52a0\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/strong>\u300d<\/p>\n<p>\u3053\u308c\u4e00\u767a\u3067\u884c\u304f\u304b\u306a\u3068\u601d\u3063\u305f\u306e\u3067\u3059\u304c\u3001\u8272\u3005\u3068\u30a8\u30e9\u30fc\u304c\u51fa\u3066\u3057\u307e\u3044\u307e\u3057\u305f\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">git2 = \"0.18\"<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">use git2::Repository;<\/pre>\n<p>git2\u30af\u30ec\u30fc\u30c8\u304c\u8ffd\u52a0\u3055\u308c\u307e\u3059\u3002<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">#[tauri::command]\nfn clone_repository(url: String, path: String) -&gt; Result&lt;(), String&gt; {\n    \/\/ \u30af\u30ed\u30fc\u30f3\u5148\u306e\u30d1\u30b9\u3092PathBuf\u306b\u5909\u63db\n    let path = PathBuf::from(path);\n\n    \/\/ \u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u30af\u30ed\u30fc\u30f3\n    Repository::clone(&amp;url, &amp;path)\n        .map_err(|e| format!(\"\u30ea\u30dd\u30b8\u30c8\u30ea\u306e\u30af\u30ed\u30fc\u30f3\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {}\", e))?;\n\n    Ok(())\n}<\/pre>\n<p><strong>\u25a0 \u30d5\u30ed\u30f3\u30c8\u5074<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">\/\/ \u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u30af\u30ed\u30fc\u30f3\nawait invoke(\"clone_repository\", {\n    url: repositoryUrl.value,\n    path: localPath.value,\n});<\/pre>\n<p>\u3068\u3044\u3063\u305f\u5f62\u3067\u8ffd\u52a0\u3055\u308c\u305f\u306e\u3067\u3059\u304c\u3001\u3053\u308c\u3060\u3068\u30d7\u30e9\u30a4\u30d9\u30fc\u30c8\u30ec\u30dd\u30b8\u30c8\u30ea\u306b\u30a2\u30af\u30bb\u30b9\u51fa\u6765\u306a\u3044\u306e\u3067\u3001\u30ad\u30fc\u30c1\u30a7\u30fc\u30f3\u306b\u767b\u9332\u3055\u308c\u305f\u30d1\u30b9\u30ef\u30fc\u30c9\u3068\u3001loaclstorage\u306b\u4fdd\u5b58\u3057\u305fusername\u3092\u4f7f\u3063\u3066git <span style=\"color: initial; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;\">credentials\u3092\u8a2d\u5b9a\u3002<\/span><\/p>\n<p>\u3055\u3089\u306b\u3001\u6307\u5b9a\u3055\u308c\u305f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u76f4\u4e0b\u306bclone\u3057\u3066\u3057\u307e\u3046\u72b6\u6cc1\u3060\u3063\u305f\u306e\u3067\u3001\u30ec\u30dd\u30b8\u30c8\u30ea\u540d\u3092\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u540d\u3068\u3057\u3066\u4f5c\u6210\u3057\u3064\u3064\u3001\u65e2\u306bclone\u3057\u3066\u3044\u308b\u5834\u5408\u306fpull\u3092\u884c\u3046\u51e6\u7406\u306a\u3069\u3092\u8ffd\u52a0\u3002<\/p>\n<p>\u6700\u7d42\u7684\u306b\u51fa\u6765\u305f\u51e6\u7406\u306f\u3001\u30d5\u30ed\u30f3\u30c8\u5074<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">const handleSubmit = async () =&gt; {\n    try {\n        isLoading.value = true;\n        error.value = \"\";\n\n        \/\/ \u30ea\u30dd\u30b8\u30c8\u30eaURL\u306e\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\n        if (!repositoryUrl.value) {\n            throw new Error(\"\u30ea\u30dd\u30b8\u30c8\u30eaURL\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\");\n        }\n\n        \/\/ \u30ed\u30fc\u30ab\u30eb\u30d1\u30b9\u306e\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\n        const isValid = await invoke&lt;boolean&gt;(\"validate_repository_path\", {\n            path: localPath.value,\n        });\n\n        if (!isValid) {\n            throw new Error(\"\u7121\u52b9\u306a\u30ed\u30fc\u30ab\u30eb\u30d1\u30b9\u3067\u3059\");\n        }\n\n        \/\/ \u30ea\u30dd\u30b8\u30c8\u30ea\u306e\u5b58\u5728\u30c1\u30a7\u30c3\u30af\n        const exists = await invoke&lt;boolean&gt;(\"check_repository_exists\", {\n            path: localPath.value,\n        });\n\n        if (exists) {\n            throw new Error(\"\u6307\u5b9a\u3055\u308c\u305f\u30d1\u30b9\u306b\u306f\u65e2\u306bGit\u30ea\u30dd\u30b8\u30c8\u30ea\u304c\u5b58\u5728\u3057\u307e\u3059\");\n        }\n\n        \/\/ localStorage\u304b\u3089lastUsername\u3092\u53d6\u5f97\n        const lastUsername = localStorage.getItem(\"lastUsername\");\n        if (!lastUsername) {\n            throw new Error(\n                \"\u30ed\u30b0\u30a4\u30f3\u60c5\u5831\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002\u30ed\u30b0\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044\u3002\"\n            );\n        }\n\n        \/\/ \u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u30af\u30ed\u30fc\u30f3\n        const result = await invoke&lt;string&gt;(\"clone_repository\", {\n            url: repositoryUrl.value,\n            path: localPath.value,\n            username: lastUsername,\n        });\n        console.log(\"\u30af\u30ed\u30fc\u30f3\u7d50\u679c:\", result);\n\n        emit(\"clone\", {\n            repositoryUrl: repositoryUrl.value,\n            localPath: localPath.value,\n        });\n    } catch (e) {\n        console.error(\"\u30af\u30ed\u30fc\u30f3\u30a8\u30e9\u30fc:\", e);\n        error.value = e instanceof Error ? e.message : \"\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\";\n    } finally {\n        isLoading.value = false;\n    }\n};<\/pre>\n<p>\u3068\u306a\u3063\u3066\u304a\u308a\u3001Rust\u5074\u306f<\/p>\n<p><strong>\u25a0 Rust\u5074<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">#[tauri::command]\nfn clone_repository(url: String, path: String, username: String) -&gt; Result&lt;String, String&gt; {\n    \/\/ \u30af\u30ed\u30fc\u30f3\u5148\u306e\u30d1\u30b9\u3092PathBuf\u306b\u5909\u63db\n    let mut path = PathBuf::from(path);\n\n    \/\/ \u30ea\u30dd\u30b8\u30c8\u30ea\u540d\u3092\u62bd\u51fa\n    let repo_name = url\n        .split('\/')\n        .last()\n        .ok_or_else(|| \"\u30ea\u30dd\u30b8\u30c8\u30eaURL\u304c\u7121\u52b9\u3067\u3059\".to_string())?\n        .trim_end_matches(\".git\");\n\n    \/\/ \u30ea\u30dd\u30b8\u30c8\u30ea\u540d\u3092\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u540d\u3068\u3057\u3066\u8ffd\u52a0\n    path = path.join(repo_name);\n\n    \/\/ \u8a8d\u8a3c\u60c5\u5831\u3092\u53d6\u5f97\n    let password = get_credentials(username.clone())?;\n\n    \/\/ \u8a8d\u8a3c\u30b3\u30fc\u30eb\u30d0\u30c3\u30af\u3092\u8a2d\u5b9a\n    let mut callbacks = git2::RemoteCallbacks::new();\n    callbacks.credentials(move |_url, username_from_url, _allowed_types| {\n        git2::Cred::userpass_plaintext(&amp;username, &amp;password)\n    });\n\n    \/\/ \u30d5\u30a7\u30c3\u30c1\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u8a2d\u5b9a\n    let mut fetch_options = git2::FetchOptions::new();\n    fetch_options.remote_callbacks(callbacks);\n\n    \/\/ \u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u304c\u5b58\u5728\u3057\u306a\u3044\u5834\u5408\u306f\u4f5c\u6210\n    if !path.exists() {\n        std::fs::create_dir_all(&amp;path)\n            .map_err(|e| format!(\"\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u4f5c\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {}\", e))?;\n    }\n\n    \/\/ \u30ea\u30dd\u30b8\u30c8\u30ea\u306e\u5b58\u5728\u30c1\u30a7\u30c3\u30af\n    let git_dir = path.join(\".git\");\n    if git_dir.exists() &amp;&amp; git_dir.is_dir() {\n        \/\/ \u3059\u3067\u306b\u30ea\u30dd\u30b8\u30c8\u30ea\u304c\u3042\u308b\u5834\u5408\u306f pull \u7b49\u306e\u51e6\u7406\n        let repo = Repository::open(&amp;path).map_err(|e| e.to_string())?;\n        {\n            let mut remote = repo.find_remote(\"origin\").map_err(|e| e.to_string())?;\n            remote\n                .fetch(&amp;[\"master\"], Some(&amp;mut fetch_options), None)\n                .map_err(|e| e.to_string())?;\n        }\n        Ok(format!(\"Pulled existing repo at {:?}\", path))\n    } else {\n        \/\/ \u65b0\u3057\u3044\u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u30af\u30ed\u30fc\u30f3\n        let mut builder = git2::build::RepoBuilder::new();\n        builder.fetch_options(fetch_options);\n        builder.clone(&amp;url, &amp;path).map_err(|e| e.to_string())?;\n        Ok(format!(\"Cloned new repo at {:?}\", path))\n    }\n}<\/pre>\n<p>\u3068\u3044\u3063\u305f\u611f\u3058\u306b\u4f5c\u6210\u3055\u308c\u3001\u4e00\u5fdc\u4efb\u610f\u306e\u30ec\u30dd\u30b8\u30c8\u30ea\u3092\u4efb\u610f\u306e\u30d1\u30b9\u306bclone\u3059\u308b\u3068\u3053\u308d\u307e\u3067\u5b8c\u6210\u3057\u307e\u3057\u305f\u3002<\/p>\n<p>\u8a66\u3057\u306b\u3001\u300c<a href=\"https:\/\/github.com\/webcyou-org\/open-texture-packer\" target=\"_blank\" rel=\"noopener\">open-texture-packer<\/a>\u300d\u3092\u30c7\u30b9\u30af\u30c8\u30c3\u30d7\u4e0a\u306bclone\u3057\u3066\u307f\u308b\u3068\u3002<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone  wp-image-12207\" src=\"https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_2-1024x768.png\" alt=\"\" width=\"507\" height=\"380\" srcset=\"https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_2-1024x768.png 1024w, https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_2-300x225.png 300w, https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_2-768x576.png 768w, https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_2-1536x1152.png 1536w, https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_2.png 1600w\" sizes=\"auto, (max-width: 507px) 100vw, 507px\" \/><\/p>\n<p>\u30db\u30fc\u30e0\u753b\u9762\u306b\u9077\u79fb\u3057\u3001<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone  wp-image-12208\" src=\"https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_3-1024x777.png\" alt=\"\" width=\"509\" height=\"386\" srcset=\"https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_3-1024x777.png 1024w, https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_3-300x228.png 300w, https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_3-768x583.png 768w, https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_3-1536x1166.png 1536w, https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_3.png 1836w\" sizes=\"auto, (max-width: 509px) 100vw, 509px\" \/><\/p>\n<p>\u7121\u4e8b\u30af\u30ed\u30fc\u30f3\u3055\u308c\u3066\u304a\u308a\u307e\u3057\u305f\u3002<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone  wp-image-12209\" src=\"https:\/\/www.webcyou.com\/wp-content\/uploads\/2025\/04\/tauri_5_4.png\" alt=\"\" width=\"108\" height=\"121\" \/><\/p>\n<p>\u3068\u3044\u3063\u305f\u611f\u3058\u3067\u3001\u6b86\u3069Cursor\u3055\u3093\u306b\u304a\u4efb\u305b\u3057\u3066\u4f5c\u6210\u3057\u3066\u304d\u305f\u306e\u3067\u3059\u304c\u3001\u6b21\u56de\u304b\u3089\u306f\u305d\u308d\u305d\u308d\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u3082\u30ab\u30aa\u30b9\u3063\u3066\u304d\u305f\u306e\u3067\u30ea\u30d5\u30a1\u30af\u30bf\u30ea\u30f3\u30b0\u3092\u4e2d\u5fc3\u306b\u884c\u3044\u3064\u3064\u3001\u30af\u30ed\u30fc\u30f3\u306e\u51e6\u7406\u304c\u540c\u671f\u7684\u306a\u306e\u3067\u975e\u540c\u671f\u3067\u5b9f\u884c\u3057\u3064\u3064\u3001clone\u306e\u9032\u6357\u72b6\u6cc1\u3082\u53d6\u5f97\u51fa\u6765\u308b\u3088\u3046\u306b\u5b9f\u88c5\u3092\u9032\u3081\u3066\u884c\u3053\u3046\u3068\u601d\u3044\u307e\u3059\u3002<\/p>\n<p>\u3067\u306f\u3067\u306f\u3041\u3002<\/p>\n<p>\u307e\u305f\u307e\u305f\u3041\u3002<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u3069\u3082\u3067\u3059\u3002 \u4eca\u56de\u306f\u524d\u56de\u306e\u300cTauri(Rust) \u00d7 AI \u3067\u4f5c\u308b GitGUI\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u30a2\u30d7\u30ea \u305d\u306e4\u300d\u306e\u7d9a\u304d\u3068\u306a\u308a\u3001Rust\u5074\u306e\u30ec\u30dd\u30b8\u30c8\u30ea\u306e\u30af\u30ed\u30fc\u30f3\u51e6\u7406\u3082\u8ffd\u52a0\u3057\u3066\u3044\u3053\u3046\u3068\u601d\u3044\u307e\u3059\u3002 \u307e\u305a\u306f\u3001Local\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":11849,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[299],"tags":[182,140,308,166,37,327,357,365,289,45,78,118],"class_list":["post-12203","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-rust","tag-git","tag-github","tag-gui","tag-iphone","tag-iphone-","tag-rust","tag-rust-webpack","tag-tauri","tag-tool","tag-web","tag-78","tag-118"],"_links":{"self":[{"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/posts\/12203","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=12203"}],"version-history":[{"count":3,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/posts\/12203\/revisions"}],"predecessor-version":[{"id":12210,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/posts\/12203\/revisions\/12210"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=\/wp\/v2\/media\/11849"}],"wp:attachment":[{"href":"https:\/\/www.webcyou.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=12203"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=12203"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcyou.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=12203"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}