<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>بلاگ امیر</title><link>https://amir.goodarzi.net/fa/</link><description>Amir Goodarzi blog</description><generator>Hugo -- gohugo.io</generator><language>fa</language><copyright>This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright><lastBuildDate>Thu, 17 Oct 2024 03:29:25 +0200</lastBuildDate><atom:link href="https://amir.goodarzi.net/fa/index.xml" rel="self" type="application/rss+xml"/><item><title>ساخت تصاویر داکر به صورت امن و سریع با Kaniko</title><link>https://amir.goodarzi.net/fa/kaniko/</link><pubDate>Thu, 17 Oct 2024 03:29:25 +0200</pubDate><author>امیر</author><guid>https://amir.goodarzi.net/fa/kaniko/</guid><description><![CDATA[<h2 id="مقدمه">مقدمه</h2>
<h3 id="کانیکو-چیست">کانیکو چیست؟</h3>
<p><a href="https://github.com/GoogleContainerTools/kaniko" target="_blank" rel="noopener noreffer ">کانیکو</a> یک سازنده تصویر داکر است. ممکن است از این معرفی راضی نباشید، اما این تمام چیزی است که کانیکو درباره‌اش است. تصاویر را ساخته و به یک رجیستری از جمله Dockerhub، ECR، ACR یا رجیستری شخصی خودتان ارسال کنید.</p>
<h3 id="چگونه-کار-میکند">چگونه کار می‌کند؟</h3>
<p>استفاده از آن فوق‌العاده آسان است. ابتدا سیستم فایل تصویر پایه را استخراج کنید. هر یک از دستورات (COPY, ADD, RUN) را در سیستم فایل تصویر پایه اجرا کنید. یک اسنپ‌شات از وضعیت فعلی سیستم فایل ایجاد می‌شود، فایل‌های جدید یا تغییر یافته به تصویر پایه اضافه می‌شوند و متادیتای تصویر به‌روزرسانی می‌شود. بسیار مفید است. نه؟ نه تا وقتی که یاد بگیرید چگونه از آن استفاده کنید.</p>
<h3 id="موارد-استفاده">موارد استفاده</h3>
<p>کانیکو <strong>تصاویر داکر</strong> را داخل یک کانتینر یا کلاستر Kubernetes ایجاد می‌کند. اگر با هر یک از این مشکلات مواجه هستید، این مقاله به شما کمک می‌کند تا آن‌ها را برطرف کنید:</p>
<ul>
<li>
<p>اگر در حال ساخت تصاویر روی یک ماشین یا رانر مشترک هستید، ممکن است بتوانید خطرات نقض امنیتی را کاهش دهید. روش‌های مختلفی برای ساخت تصاویر وجود دارد. شاید بتوانید برخی از اسکریپت‌های bash، playbookهای Ansible یا نوعی اسکریپت را به ارائه‌دهنده CI/CD خود بنویسید تا چیزی شبیه به <code>docker build -t blahblahblah:v0.0.1 -f SomeSortOfDockerfile</code> انجام دهد. شما می‌توانید این دستور را از bash یا از یک کانتینر (Docker in Docker) اجرا کنید. هیچ یک از این‌ها برای محیط‌های مشترک مناسب نیست. اول، تصور کنید یک سناریو که یک کاربر/توسعه‌دهنده/پایپلاین دیگر به کد شما دسترسی پیدا می‌کند، یا شما نیاز دارید به برخی داده‌های حیاتی از یک پایگاه داده دسترسی پیدا کنید، یا شاید نیاز دارید برخی اعتبارنامه‌های حیاتی (یا کلیدها) را از منبع دیگری دریافت کنید. این می‌تواند به یک فاجعه منجر شود. کد شما می‌تواند توسط دیگران دسترسی پیدا کند، داده‌های پایگاه داده شما می‌تواند نشت کند، یا کسی می‌تواند کلیدهای شما را بدزدد. این بدترین کابوس برای تیم‌های امنیت و عملیات است.</p>
</li>
<li>
<p>کاهش زمان ساخت یکی دیگر از ویژگی‌هایی است که ممکن است به آن علاقه‌مند باشید. سرورها (رانرها) گاهی اوقات برای تیم‌های DevOps مشکل‌ساز می‌شوند به دلیل زمان طولانی اجرای فرآیند ساخت. ممکن است روز بدی داشته باشید اگر پایگاه کد شما بزرگ باشد و بسیاری وابستگی‌ها را از اینترنت دریافت کنید.
هیچ‌کس (منظورم تیم‌های DevOps یا SRE است) نمی‌خواهد یک تیکت دیگر از تیم توسعه دریافت کند که &ldquo;پایپلاین‌های ساخت ما کند هستند. ما در فورس هستیم و باید هات‌فیکس‌ها فوراً در تولید ادغام شوند&rdquo;.</p>
</li>
<li>
<p>شاید بودجه محدودی برای زیرساخت داشته باشید، بنابراین کاملاً به کلاستر Kubernetes خود متکی هستید. از پایگاه داده تا محیط برای ساخت تصاویر داکر. (نکات حرفه‌ای: هیچ چیزی روی Kubernetes مستقر نکنید. در آینده، در مورد آن خواهم نوشت. پایگاه داده‌ها می‌توانند روی Kubernetes اجرا شوند، اما این کار را نکنید)</p>
</li>
</ul>
<p>ما <strong>کانیکو</strong> را برای رفع این مشکلات داریم. اگرچه یک ابرقهرمان نیست، اما می‌تواند ما را به ابرقهرمان شرکت تبدیل کند.</p>
<h2 id="مشکل">مشکل</h2>
<h3 id="چیزی-که-داشتیم">چیزی که داشتیم</h3>
<p>من از این فرصت استفاده می‌کنم تا به اشتراک بگذارم چگونه زیرساخت CI/CD ما در <a href="https://www.linkedin.com/company/alibaba-travels/" target="_blank" rel="noopener noreffer ">Alibaba Travels</a> مستقر شد و چه کارهایی انجام دادیم تا آن را قابل اعتمادتر کنیم. این یک زیرساخت قدیمی بود که نیاز به نوسازی یا بازسازی داشت. ما تازه چندین پروژه را به این ساختار جدید به محیط staging، توسعه و دیگر محیط‌ها به غیر از تولید منتقل کرده‌ایم، اما هنوز کارهای بسیاری باقی مانده که باید انجام شوند.</p>
<p>برمی‌گردیم به موضوع اصلی، ما پروژه‌هایی از استک‌های مختلف داریم. از Dotnet Core گرفته تا Nodejs و Python همه را استفاده می‌کنیم. قبلاً همه پروژه‌ها از یک رانر مشترک استفاده می‌کردند که بر روی Gitlab Continuous Integration اجرا می‌شد. چندین رانر shell و Docker روی آن سرور قوی نصب شده بودند (برای کاهش خطرات خرابی، هنوز در دسترس هستند اما برنامه داریم آن‌ها را مهاجرت دهیم). این‌ها انواع رانرهایی هستند که پروژه‌ها از آن‌ها استفاده می‌کنند. بدیهی است که پروژه‌هایی که فرآیند ساخت خود را بر روی Docker اجرا می‌کنند، به سوکت Docker دسترسی خواهند داشت، و در پایپلاین‌ها، همه افراد درون آن رانر می‌توانند یکدیگر را ببینند و حتی دسترسی shell به یک کانتینر دیگر بدهند.</p>
<h3 id="منطقه-خطر">منطقه خطر</h3>
<p>این می‌تواند به خواندن برخی داده‌ها و شاید کدها منجر شود. رانرهای shell نیز در دسترس هستند. آن‌ها دسترسی shell به رانر فراهم می‌کنند و می‌توانند هر کاری که می‌خواهند با کاربر gitlab-runner انجام دهند. چندین دلیل باعث شد تا رانرهای خود را به Kubernetes منتقل کنیم. کنترل بهتر منابع هر پروژه، کنترل بهتر شبکه، جداسازی بین کانتینرها و غیره.</p>
<h3 id="یک-قدم-جلوتر">یک قدم جلوتر</h3>
<p>پس از ایجاد چندین رانر Kubernetes، همه چیز به خوبی پیش می‌رفت، اما یک مشکل دیگر وجود داشت. امکان مونت کردن سوکت Docker میزبان به کانتینر وجود ندارد. این خیلی خطرناک است. کانتینر به کانتینرهای میزبان دسترسی پیدا می‌کند. برخی از شما گفتید که این مشکلی ندارد، ما می‌توانیم ماشین‌های اختصاصی برای اجرای آن‌ها ایجاد کنیم (که یک راه‌حل پرهزینه است). آیا می‌توانید یک سوکت Docker را به چندین کانتینر مونت کنید؟ علاوه بر این، شما باید با کانتکست امنیتی سروکار داشته باشید که در سیستم حفره‌های بیشتری ایجاد می‌کند.</p>
<p><strong>این یک فاجعه است.</strong></p>
<h2 id="راه-حل">راه حل</h2>
<h3 id="چیزی-که-نیاز-داریم">چیزی که نیاز داریم</h3>
<p>کانیکو به ما کمک می‌کند تا این شکاف‌ها را ببندیم. پس از پیاده‌سازی کانیکو، ساخت یک تصویر داکر از یک اپلیکیشن DotNet به 21 دقیقه زمان نیاز داشت. این فرآیند بدون رانر Kubernetes سه و نیم دقیقه طول می‌کشید. برای یک اپلیکیشن Node.js، این زمان به 45 دقیقه افزایش یافت. در رانرهای مشترک ما، این کار 11 دقیقه زمان می‌برد.</p>
<h3 id="کاری-که-ما-انجام-دادیم">کاری که ما انجام دادیم</h3>
<p>ما می‌خواستیم این کار قابل اعتمادتر باشد، اما کاری که انجام دادیم زمان بیشتری برد.</p>
<h4 id="کشینگ">کشینگ</h4>
<p>کشینگ به من کمک کرد تا آن را اصلاح کنم. ابتدا باید کشینگ فعال شود (فلگ <code>--cache=true</code>). دو انتخاب برای کشینگ داریم.</p>
<ul>
<li>کش کردن در یک دایرکتوری محلی (<code>--cache-dir</code>)</li>
<li>کش کردن در یک رجیستری مشخص (<code>--cache-repo</code> flag)
از آنجایی که ما منابع زیادی در رجیستری خود داریم، تصمیم گرفتیم آن‌ها را کش کنیم.</li>
</ul>
<p>فراموش نکنید که دستورهای COPY و RUN را می‌توان کش کرد زمانی که فلگ <code>--cache-copy-layers=true</code> را فعال کنید.
نکته ۲: این دو روش کشینگ زمانی در دسترس خواهند بود که <code>--cache=true</code> تنظیم شده باشد.</p>
<h4 id="dockerfile">Dockerfile</h4>
<p>این Dockerfile را بررسی کنید. به نظر می‌رسد همه چیز خوب است و توسعه‌دهنده با آن خوشحال است.</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-dockerfile">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="کپی به کلیپ‌بورد"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">FROM</span><span class="w"> </span><span class="s">mcr.microsoft.com/dotnet/sdk:6.0</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">RUN</span> apt update <span class="o">&amp;&amp;</span> apt install libgnutls30 <span class="o">&amp;&amp;</span> apt install ca-certificates <span class="o">&amp;&amp;</span> update-ca-certificates<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">WORKDIR</span><span class="w"> </span><span class="s">/app</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">ENV</span> <span class="nv">ASPNETCORE_ENVIRONMENT</span><span class="o">=</span>Production
</span></span><span class="line"><span class="cl"><span class="k">ENV</span> <span class="nv">ASPNETCORE_URLS</span><span class="o">=</span>http://+:80<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">COPY</span> . ./<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">RUN</span> dotnet restore   src/app/app.csproj --configfile src/app/nuget.config<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">RUN</span> dotnet publish src/app/apptifier.csproj -c Release -o /app/out<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">FROM</span><span class="w"> </span><span class="s">mcr.microsoft.com/dotnet/sdk:6.0</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">WORKDIR</span><span class="w"> </span><span class="s">/app</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">COPY</span> --from<span class="o">=</span>build-env /app/out .<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">EXPOSE</span><span class="w"> </span><span class="s">80</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">ENTRYPOINT</span> <span class="p">[</span><span class="s2">&#34;dotnet&#34;</span><span class="p">,</span><span class="s2">&#34;app.dll&#34;</span><span class="p">]</span></span></span></code></pre></div></div>
<p>کاملاً عادی به نظر می‌رسد، اما فکر می‌کنم این یک <strong>فاجعه</strong> دیگر است. اجازه دهید توضیح دهم:</p>
<ul>
<li>دستورهای COPY باید به بخش‌های کوچکتر تقسیم شوند. در این حالت من آن را تغییر دادم تا هر ماژول اپلیکیشن کپی شود.</li>
<li>امکان ادغام دو دستور RUN وجود دارد.</li>
<li>دستور apt بسته‌های کش شده را حذف نمی‌کند. این در این وضعیت اهمیت چندانی ندارد، اما ما همچنان آن را انجام خواهیم داد.</li>
</ul>
<p>کاهش تعداد خطوط در Dockerfile برای کانیکو کار نمی‌کند. از نوشتن خطوط بیشتر نترسید. این چیزی است که من آن را تغییر دادم:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-dockerfile">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="کپی به کلیپ‌بورد"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dockerfile" data-lang="dockerfile"><span class="line"><span class="cl"><span class="k">FROM</span><span class="w"> </span><span class="s">mcr.microsoft.com/dotnet/sdk:6.0</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="s">build-env</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">WORKDIR</span><span class="w"> </span><span class="s">/app</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">ENV</span> <span class="nv">ASPNETCORE_ENVIRONMENT</span><span class="o">=</span>Production
</span></span><span class="line"><span class="cl"><span class="k">ENV</span> <span class="nv">ASPNETCORE_URLS</span><span class="o">=</span>http://+:80<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">COPY</span> src/Module1 ./src/Module1<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">COPY</span> src/Module2 ./src/Module2<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">COPY</span> src/app ./src/app<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">COPY</span> tests/app.Test ./tests/Iapp.Test.Test<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">COPY</span> tests/app.integrity.Test ./tests/app.integrity.Test<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">COPY</span> app.sln ./<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">RUN</span> dotnet publish --configfile src/app/nuget.config src/app/app.csproj -c Release -o /app/out --nologo -verbosity:quiet<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">FROM</span><span class="w"> </span><span class="s">mcr.microsoft.com/dotnet/sdk:6.0</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">WORKDIR</span><span class="w"> </span><span class="s">/app</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">COPY</span> --from<span class="o">=</span>build-env /app/out .<span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">EXPOSE</span><span class="w"> </span><span class="s">80</span><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="k">ENTRYPOINT</span> <span class="p">[</span><span class="s2">&#34;dotnet&#34;</span><span class="p">,</span><span class="s2">&#34;app.dll&#34;</span><span class="p">]</span></span></span></code></pre></div></div>
<p>من از همین روش برای پروژه‌های دیگر هم استفاده کردم.</p>
<h4 id="اسنپشات">اسنپ‌شات</h4>
<p>در ابتدای پست خود اشاره کردم که اسنپ‌شات‌ها روشی برای ذخیره لایه‌های تصاویر و وضعیت‌های آن‌ها هستند. با <code>--single-snapshot=true</code>، شما فقط در پایان فرآیند یک اسنپ‌شات می‌گیرید، که بسیار سریع است اما برای کش مناسب نیست، یا می‌توانید از <code>--snapshotMode</code> استفاده کنید تا اطمینان حاصل کنید که روش صحیح اسنپ‌شات استفاده می‌شود. من فقط آرگومان‌های snapshot را از مستندات رسمی کپی و پیست کردم تا نحوه کار آن را نشان دهم.</p>
<table>
	<thead>
			<tr>
					<th>حالت</th>
					<th>نتیجه</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>full</td>
					<td>تمام محتویات و متادیتای فایل در هنگام اسنپ‌شات در نظر گرفته می‌شوند. این گزینه کم‌کارآمدترین است، اما همچنین پایدارترین است.</td>
			</tr>
			<tr>
					<td>redo</td>
					<td>زمان فایل، اندازه، حالت، مالک uid و gid هنگام اسنپ‌شات در نظر گرفته می‌شوند. این ممکن است تا 50٪ سریعتر از &ldquo;full&rdquo; باشد، به خصوص اگر پروژه شما تعداد زیادی فایل داشته باشد.</td>
			</tr>
			<tr>
					<td>time</td>
					<td>فقط زمان فایل در هنگام اسنپ‌شات در نظر گرفته می‌شود.</td>
			</tr>
	</tbody>
</table>
<p>به دلایلی من حالت redo را انتخاب کردم.</p>
<h2 id="نتیجه">نتیجه</h2>
<p>ابتدا، کمی بیشتر از دستور <code>docker build</code> اصلی طول کشید، که قابل درک است. کانیکو تلاش می‌کند تا کش‌ها را ایجاد کند.
با این حال، پس از ایجاد چند تغییر در ماژول‌ها و فایل‌ها، نتایج چشمگیر بود.
در اینجا نگاهی به جدول می‌اندازیم:</p>
<table>
	<thead>
			<tr>
					<th>نوع پروژه</th>
					<th>زمان ساخت داکر</th>
					<th>کانیکو بدون کش</th>
					<th>کانیکو اولین بار با کش</th>
					<th>کانیکو بار دوم با کش</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Dotnet core</td>
					<td>3:10</td>
					<td>14:25</td>
					<td>3:40</td>
					<td>0:27</td>
			</tr>
			<tr>
					<td>NodeJS</td>
					<td>11:45</td>
					<td>45:20</td>
					<td>13:10</td>
					<td>2:10</td>
			</tr>
	</tbody>
</table>
<h3 id="استفاده-از-کانیکو">استفاده از کانیکو</h3>
<p>چهار مورد نیاز دارید تا از کانیکو استفاده کنید:</p>
<ul>
<li>یک Dockerfile و کد منبع به نام build context، به همراه یک تغییر جزئی در Dockerfile شما</li>
<li>یک رجیستری که تصاویر را به آن ارسال کنید</li>
<li>کانیکو</li>
<li><a href="https://github.com/GoogleContainerTools/kaniko#using-kaniko" target="_blank" rel="noopener noreffer ">مستندات کانیکو</a></li>
</ul>
<h4 id="روش-من">روش من</h4>
<p>این دستور کامل است که من استفاده می‌کنم:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-shell">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="کپی به کلیپ‌بورد"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">        /kaniko/executor
</span></span><span class="line"><span class="cl">        --context <span class="s2">&#34;projectDirectory&#34;</span>
</span></span><span class="line"><span class="cl">        --dockerfile <span class="s2">&#34;</span><span class="nv">$projectDirectory</span><span class="s2">/Dockerfile&#34;</span>
</span></span><span class="line"><span class="cl">        --destination <span class="s2">&#34;imageTag:version&#34;</span>
</span></span><span class="line"><span class="cl">        --cache-copy-layers<span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl">        --snapshotMode<span class="o">=</span><span class="nb">time</span>
</span></span><span class="line"><span class="cl">        --use-new-run
</span></span><span class="line"><span class="cl">        --cache<span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl">        --cache-repo<span class="o">=</span><span class="s2">&#34;imageTag:cache&#34;</span></span></span></code></pre></div></div>
<h2 id="نتیجهگیری">نتیجه‌گیری</h2>
<h3 id="یادداشتها">یادداشت‌ها</h3>
<h4 id="یادداشتهای-مربوط-به-تولید">یادداشت‌های مربوط به تولید</h4>
<p>این روش روی محیط‌های staging، توسعه و دیگر محیط‌های غیر از تولید اعمال شد. ممکن است تا شش ماه طول بکشد تا این روش و ابزارها به‌طور کامل پذیرش شوند.<br>
بنابراین، اگر مایل به پیاده‌سازی این روش هستید، مطمئن شوید که همه چیز را آزمایش کرده‌اید و هیچ مشکلی مانند مسائل امنیتی به وجود نمی‌آید که به محیط تولید شما آسیب بزند.<br>
این یک ابزار پایدار و عالی است، اما با مسئولیت خود از آن استفاده کنید.</p>
<h4 id="سایر-یادداشتها">سایر یادداشت‌ها</h4>
<p>هدف این پست این است که به شما کمک کند عملکرد و امنیت پایپلاین‌های ساخت داکر خود را بهبود بخشید. لطفاً هرگونه نظری دارید آزادانه بیان کنید.<br>
لطفاً اگر هرگونه تعارض یا مشکلی وجود دارد به من اطلاع دهید :)</p>
]]></description></item><item><title>امروز یاد گرفتم: استفاده از git restore برای بازگرداندن تغییرات فایل و همگام‌سازی با شاخه دیگر</title><link>https://amir.goodarzi.net/fa/til-16-10-2024-git-restore/</link><pubDate>Wed, 16 Oct 2024 13:25:00 +0200</pubDate><author>امیر</author><guid>https://amir.goodarzi.net/fa/til-16-10-2024-git-restore/</guid><description><![CDATA[<blockquote>
<p><strong>امروز یاد گرفتم</strong> که اگر نیاز دارید یک فایل خاص را به وضعیت اولیه‌اش برگردانید – حتی پس از چندین کامیت – یا می‌خواهید یک فایل را با شاخه دیگری همگام‌سازی کنید، می‌توانید از دستور <code>git restore</code> استفاده کنید.</p>
</blockquote>
<p>دستور <code>git restore</code> به شما اجازه می‌دهد یک فایل را به وضعیت قبلی‌اش برگردانید یا آن را با یک شاخه متفاوت همگام کنید. این دستور زمانی بسیار مفید است که بخواهید تغییرات یک فایل را لغو کرده و آن را با نسخه‌ای از شاخه دیگری مثل <code>main</code> هماهنگ کنید.</p>
<p>در این مثال، می‌خواهم تمام تغییرات کامیت‌شده در شاخه جاری برای یک فایل خاص را لغو کنم و آن را با نسخه موجود در شاخه <code>main</code> تطبیق دهم:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-bash">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="کپی به کلیپ‌بورد"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git restore --source<span class="o">=</span>main -- main.tf</span></span></code></pre></div></div>
<ul>
<li>مستندات <a href="https://git-scm.com/docs/git-restore" target="_blank" rel="noopener noreffer ">git-restore</a></li>
<li>تصویر کاور تحت مجوز <a href="https://creativecommons.org/licenses/by/3.0/deed.en" target="_blank" rel="noopener noreffer ">Creative Commons Attribution 3.0 Unported</a> منتشر شده و <a href="https://commons.wikimedia.org/wiki/File:Git-logo.svg" target="_blank" rel="noopener noreffer ">منبع آن</a> ویکی‌مدیا کامنز است.</li>
</ul>
]]></description></item></channel></rss>