# مهاجرت از Git

> یک مخزن Git را با سه دستور به zev بیاورید. اول ببینید چه می‌آید، بعد آن را در همان پوشه یا مستقیم از نشانی‌اش بیاورید و اثبات بگیرید که همهٔ کامیت‌ها و فایل‌ها با Git یکی است. با مثال‌های واقعی برای یک پروژهٔ متن‌باز، مخزن یک شرکت با LFS و زیرماژول و هوک، و تیمی که کم‌کم جابه‌جا می‌شود.

Source: https://zaryn.xyz/docs/fa/from-git

جابه‌جایی سه دستور است و لازم نیست همه‌چیز در یک روز عوض شود. zev تاریخچهٔ Git شما را می‌خواند و در zev می‌نویسد. به `.git` هیچ دستی نمی‌خورد، پس Git و zev کنار هم کار می‌کنند تا تیمتان آماده شود.

```bash
zev import-git --check      # ۱. پیش‌نمایش: چه می‌آید و چه کاری اول با شماست. چیزی نمی‌نویسد
zev import-git --verify     # ۲. آوردن، سپس اثبات اینکه هر کامیت و هر فایل با Git یکی است
zev new && zev push         # ۳. گذاشتن روی Zaryn
```

```diagram
type: flow
title: سه دستور، و در آخر اثبات
---
پیش‌نمایش | `--check` تاریخچه را می‌خواند و می‌گوید چه می‌آید و چه کاری اول با شماست. چیزی نوشته نمی‌شود | accent | 🔍
~ آماده
آوردن | همهٔ شاخه‌ها و برچسب‌ها، نویسنده‌ها، تاریخ‌ها، پیام‌ها، فایل‌های LFS، نام شما و هوک‌هایتان | | 📥
~ --verify
اثبات | هر کامیت و هر فایل سر هر شاخه، بایت به بایت با Git مقایسه می‌شود | good | ✓
~ zev push
اشتراک | روی Zaryn. هم‌تیمی‌ها zev clone می‌زنند و به Git نیازی ندارند | | ☁️
```

## پیش‌نمایش

در هر مخزن Git اجرایش کنید. تاریخچه را می‌خواند و هیچ چیزی نمی‌نویسد، حتی پوشهٔ `.zev` را:

```bash
cd web-app
zev import-git --check
```

```text
Moving this folder from Git to zev  (a preview: nothing is written)

  History   10 commits · 2 branch(es) · 1 tag(s) · 2 author(s) · 2021 → 2026
  Size      200 KiB in Git
  Files     8 at the current commit
  Biggest   design/hero.psd 2.3 MiB

  ✓ Every branch and tag comes over, with each commit's author, date and full message
  ✓ 1 Git LFS file(s) come over whole: zev keeps big files itself, no LFS server
  ✓ Your name carries over: commits you make with zev say Sara Kim <sara@example.com>
  ✓ Git hooks carry over to zev: pre-commit
  ✓ CI files stay where they are: .github/workflows/ci.yml
  ✓ .git isn't touched: Git keeps working while your team switches
  · Submodule vendor/ui-kit: after import, zev sub add <its zev address> vendor/ui-kit pins it (https://github.com/example/ui-kit.git)
  · 1 commit(s) that only exist inside merges arrive as part of their merge commit

Ready. Run zev import-git --verify: it imports, then proves every file matches Git.
```

نشانه‌ها را این‌طور بخوانید:

```diagram
type: cards
title: نشانه‌های ‎--check چه می‌گویند
---
✓ | می‌آید | کاری با شما نیست | good
! | اول این را انجام دهید | کلون کم‌عمق، یا فایل‌های LFS که فقط اشاره‌گرشان هست. دستور دقیق در همان خط آمده | warn
· | خوب است بدانید | به شکل دیگری می‌آید، مثل زیرماژول که زیرمخزن می‌شود |
```

## آوردن

در پوشهٔ مخزن Git، آن را در یک گام بیاورید و اثبات کنید:

```bash
zev import-git --verify
```

```text
Reading the Git history of this folder…
✓ Brought in 10 commit(s), 15 file version(s) and 1 tag(s) from Git.
  feature/search  new
  main  new
  1 Git LFS file(s) brought in whole: zev stores large files itself, no LFS server needed
  Your Git name carries over: zev commits will say Sara Kim <sara@example.com>
  Git hooks carried over to .zev/hooks: pre-commit

Proving the import against Git…
✓ Verified: 3 branch(es) and tag(s) checked against Git
  10 commit(s): same Git commit, author, date, message and order
  9 file version(s) at the tips: Git's SHA-1 recomputed from zev's own copy, all identical
  1 Git LFS file(s): zev has the whole file, its SHA-256 matches the pointer
```

اثبات به خود آوردن تکیه نمی‌کند. zev هر فایل را دوباره از انبار خودش می‌خواند، همان SHA-1 که Git به آن می‌دهد را از نو حساب می‌کند و با Git مقایسه می‌کند. بیشتر ابزارهای مهاجرت از شما می‌خواهند به آن‌ها اعتماد کنید؛ این یکی نتیجه را نشانتان می‌دهد.

```diagram
type: sequence
title: ‎--verify چطور آوردن را اثبات می‌کند
lanes: Git | zev
alt: برای هر شاخه و برچسب، zev تاریخچهٔ Git و تاریخچهٔ خودش را کنار هم پیمایش می‌کند و شناسهٔ Git، نویسنده، تاریخ و پیام هر کامیت را مقایسه می‌کند؛ سر هر شاخه هر فایل را از انبار خودش می‌خواند، SHA-1 گیت را از نو حساب می‌کند و مقایسه می‌کند، و برای فایل‌های LFS هش SHA-256 را با اشاره‌گر می‌سنجد
---
Git -> zev : کامیت‌های هر شاخه و برچسب، از تازه‌ترین
note zev : همان شناسهٔ Git، نویسنده، تاریخ و پیام، به همان ترتیب؟ | accent
Git -> zev : هر فایل سر شاخه: مسیر، حالت، SHA-1
note zev : نسخهٔ خودش را بخوان و مثل Git هش کن: یکی است؟ | good
Git -> zev : اشاره‌گر LFS (هش SHA-256 فایل واقعی)
note zev : SHA-256 فایل کاملی که دارد: همان است؟ | good
```

اگر چیزی نخواند، دقیقاً می‌گوید چه چیزی و کجا، با کد ۱ خارج می‌شود، و `zev undo` آوردن را برمی‌گرداند:

```text
✗ 2 difference(s) from Git:
  branch main: zev commit 7c01d2e9aa stands for Git 4f2a9c1e0b, expected 9b3e77a1c2
zev undo takes the import back.
```

## گذاشتن روی Zaryn

```bash
zev new                   # روی Zaryn می‌سازد و به‌عنوان origin وصل می‌کند
zev push
```

هم‌تیمی‌هایتان `zev clone owner/name` می‌زنند و اصلاً به Git نیاز ندارند.

## یا مستقیم از نشانی‌اش

لازم نیست اول کلونش کنید. نشانی را به `zev import-git` بدهید: با Git کلون می‌کند، اگر پروژه از Git LFS استفاده کند فایل‌هایش را هم می‌گیرد، و می‌آوردشان، همه در یک گام:

```bash
zev import-git https://github.com/example/web-app.git --verify
zev import-git git@gitlab.com:team/api.git api-service     # در پوشه‌ای که خودتان نام می‌برید
zev import-git https://git.example.com/infra.git --check   # فقط کلون و پیش‌نمایش
```

همهٔ شاخه‌های روی سرور می‌آیند، حتی آن‌هایی که هیچ‌وقت checkout نکرده‌اید. Git در کلون فقط شاخهٔ فعلی را می‌سازد، اما zev هر شاخهٔ `origin/…` را هم با نام خودش می‌آورد. اگر پوشه‌ای ندهید، نام پوشه از نام مخزن گرفته می‌شود، و zev هیچ‌وقت روی پوشه‌ای که از قبل هست کلون نمی‌کند.

## همچنان Git تایپ کنید

سال‌ها کار با Git در دست‌هایتان است. `zev` را جلویش بگذارید: zev می‌گوید دستور Git شما در zev چیست، و همان را اجرا می‌کند:

```bash
zev git commit -am "Fix login"
```

```text
git commit -am "Fix login"
→ zev add .
→ zev commit -m "Fix login"
  zev add . also stages new files; git commit -a only takes files Git already tracks. Commits are signed automatically.
```

با `-n` فقط شکل zev را ببینید، و خود `zev git` به‌تنهایی دستورهایی را که بیشتر به کار می‌روند فهرست می‌کند:

```bash
zev git -n commit --amend -m "Fix the login form"
```

```text
git commit --amend -m "Fix the login form"
→ zev undo
→ zev commit -m "Fix the login form"
  zev undo takes the last commit back and keeps its changes staged; then it commits again with the new message.
```

```diagram
type: cards
title: zev git با دستور Git شما چه می‌کند
---
= | یکسان | zev آن را با همان نام دارد: git status → zev status | good
≈ | نزدیک | همان دستور با گزینه‌های zev: git checkout -b x → zev switch -c x | good
→ | دستوری دیگر | zev آن را جور دیگری انجام می‌دهد: git reset --soft HEAD~1 → zev undo | accent
! | اول می‌پرسد | کاری را دور می‌ریزد (git reset --hard، git checkout -- file). با y اجرا می‌شود، یا در اسکریپت با ‎--yes | warn
× | لازم نیست | zev می‌گوید چرا: git lfs، git rebase --continue. چیزی اجرا نمی‌شود |
```

دستورهایی که کاری را دور می‌ریزند پیش از اجرا می‌پرسند:

```text
git checkout -- login.js
→ zev restore login.js
  Throws away your unsaved changes to these files (zev recover can bring them back).
Run it? [y/N]
```

اگر دستوری را که فقط در Git هست مستقیم در zev تایپ کنید هم به‌جای «دستور ناشناخته» جواب می‌گیرید:

```text
$ zev reset --hard HEAD~1
zev has no 'reset'. git reset --hard HEAD~1 in zev:
  zev undo
  zev restore .
Or let zev do it: zev git reset --hard HEAD~1
```

### git تایپ کنید، zev بگیرید

یک خط در `~/.bashrc` یا `~/.zshrc`، و `git` در مخزن‌های zev هم کار می‌کند. در پوشه‌ای که `.zev` دارد (و `.git` ندارد)، `git` همان `zev git` را اجرا می‌کند؛ هر جای دیگر مثل قبل Git است:

```bash
eval "$(zev git --shell-setup)"
```

```diagram
type: flow
title: بعد از ‎--shell-setup، git کجا می‌رود
---
مخزن Git | ‎.git اینجاست (حتی وقتی در حال جابه‌جایی هستید): Git است | | 🌿
~
مخزن zev | فقط ‎.zev: git همان zev git را اجرا می‌کند، که شکل zev را می‌گوید و اجرایش می‌کند | accent | ⚡
~
هر جای دیگر | مثل قبل Git است | | 📁
```

برای اسکریپت‌ها و عامل‌های هوش مصنوعی، `zev git --json <command>` شکل zev را به‌صورت داده می‌دهد و چیزی اجرا نمی‌کند:

```bash
zev git --json commit -am "Fix login"
```

```json
{"git":["commit","-am","Fix login"],"kind":"close","zev":["zev add .","zev commit -m \"Fix login\""],
 "argv":[["add","."],["commit","-m","Fix login"]],"note":"zev add . also stages new files; …"}
```

## مثال‌ها

### یک پروژهٔ متن‌باز از GitHub

یک نگه‌دارنده پروژهٔ عمومی را جابه‌جا می‌کند و از مشارکت‌کننده‌ها می‌خواهد از Zaryn کلون کنند:

```bash
zev import-git https://github.com/example/parser.git --verify
cd parser
zev new                   # می‌پرسد: عمومی یا خصوصی
zev push
```

شناسه‌های قدیمی کامیت Git در issueها، تغییرنامه‌ها و نوشته‌های وبلاگ همچنان کار می‌کنند:

```bash
zev show 4f2a9c1          # شناسهٔ کامیت Git، کوتاه یا کامل
zev log --json -n 1       # روی هر کامیت آورده‌شده: "git": "4f2a9c1e…"
```

### مخزن یک شرکت با LFS، زیرماژول و هوک

مخزن یک تیم طراحی فایل‌های فتوشاپ را در Git LFS نگه می‌دارد، یک کیت رابط کاربری را به‌صورت زیرماژول دارد و هوک‌های Husky اجرا می‌کند. هر کدام از این‌ها در zev شکلی دارد:

```diagram
type: flow
title: هر افزونهٔ Git در zev شکلی دارد
---
Git LFS | فایل‌های بزرگ کامل می‌آیند. zev خودش نگهشان می‌دارد، پس به سرور یا سهمیهٔ LFS نیازی نیست | good | 🗄️
~
زیرماژول‌ها | کیت رابط کاربری را هم بیاورید، سپس zev sub add آن را به‌عنوان زیرمخزن سنجاق می‌کند | | 🧩
~
هوک‌ها | pre-commit، commit-msg، post-commit، pre-push و post-merge می‌آیند. پوشهٔ ‎.husky همچنان کار می‌کند | good | 🪝
```

```bash
git lfs fetch --all                     # فقط اگر ‎--check بگوید بعضی فایل‌های LFS فقط اشاره‌گرند
zev import-git --verify

cd vendor/ui-kit && zev import-git && zev new && zev push && cd ../..
zev sub add acme/ui-kit vendor/ui-kit
zev commit -m "UI kit as a subrepository"
```

هوکی که در `.git/hooks` است در `.zev/hooks` کپی می‌شود. هوکی که در پوشه‌ای است که کامیتش می‌کنید، مثل `.husky` در Husky، یک فایل دوخطی در `.zev/hooks` می‌گیرد که آن را از همان‌جا اجرا می‌کند؛ پس تغییر `.husky/pre-commit` برای Git و zev هر دو اعمال می‌شود. هوکی که خودش `git` را صدا می‌زند، مثل `lint-staged`، هنوز به staging گیت نگاه می‌کند؛ وقتی Git را کنار گذاشتید، نسخهٔ zev آن را بنویسید.

### تیمی که کم‌کم جابه‌جا می‌شود

دو هفته، نیمی از تیم هنوز در Git کامیت می‌کند. یک نفر هر وقت خواست آوردن را اجرا می‌کند و فقط کامیت‌های تازهٔ Git می‌آیند:

```diagram
type: sequence
title: دو هفته Git و zev کنار هم
lanes: کاربران Git | مخزن | کاربران zev
---
کاربران Git -> مخزن : git commit و git push
مخزن -> کاربران zev : zev import-git (فقط کامیت‌های تازه)
کاربران zev -> مخزن : zev commit و zev push
note مخزن : شاخه‌ای که کامیت‌های zev خودش را دارد هیچ‌وقت بازنویسی نمی‌شود | warn
note کاربران zev : همه روی zev: ‎.git را پاک کنید | good
```

```bash
zev import-git --check            # "Imported before: 12 new Git commit(s) to bring in"
zev import-git --verify
```

هر اجرا می‌گوید کدام شاخه‌ها `updated` شدند، کدام `up to date` هستند و کدام `kept: it has zev commits of its own` ماندند. zev هیچ‌وقت شاخه‌ای را که در zev رویش کامیت کرده‌اید بازنویسی نمی‌کند. `zev undo` هر آوردنی را برمی‌گرداند.

### در یک اسکریپت یا کار CI

`--check` و `--verify` هر دو `--json` می‌گیرند، پس یک pipeline می‌تواند به آن‌ها مشروط شود:

```bash
zev import-git --check --json | jq -e .ready          # تا وقتی کاری اول مانده، شکست می‌خورد
zev import-git --verify --json | jq -e .verified      # اگر چیزی با Git فرق کند، شکست می‌خورد
```

```json
{"ready":true,"commits":10,"all_commits":11,"new_commits":null,"branches":2,"tags":1,
 "authors":2,"lfs_whole":1,"lfs_pointer_only":[],"submodules":[{"path":"vendor/ui-kit",
 "url":"https://github.com/example/ui-kit.git"}],"shallow":false,"hooks":["pre-commit"]}
```

## وقتی ‎--check می‌گوید «اول این را انجام دهید»

```text
  ! This is a shallow clone, so only the recent history is here. First: git fetch --unshallow
  ! 1 Git LFS file(s) have only a pointer here. First: git lfs fetch --all
      design/hero.psd

2 thing(s) to do first (marked !), then zev import-git --verify.
```

| می‌گوید | چرا | این کار را بکنید |
|---|---|---|
| shallow clone | `git clone --depth` فقط کامیت‌های اخیر را گرفته | `git fetch --unshallow`، سپس آوردن |
| فایل LFS فقط اشاره‌گر دارد | فایل واقعی هیچ‌وقت دانلود نشده | `git lfs fetch --all`، سپس آوردن |
| kept: it has zev commits of its own | کسی در zev روی آن شاخه کامیت کرده | هیچ. هر وقت آماده بودید کار Git را با `zev merge` بیاورید |
| Git hooks zev doesn't run | هوکی مثل `prepare-commit-msg` در zev شکلی ندارد | کارش را به `commit-msg` یا `pre-commit` ببرید |

## چه می‌آید و چه نمی‌آید

| | |
|---|---|
| **شاخه‌ها و برچسب‌ها** | همه‌شان، حتی شاخه‌هایی که فقط روی `origin` هستند. برچسب‌های annotated به کامیت خودشان اشاره می‌کنند |
| **کامیت‌ها** | نویسنده، تاریخ و پیام کامل. تاریخچهٔ هر شاخه خط first-parent آن است، پس یک merge در Git یک کامیت می‌شود که همهٔ کاری را که آن merge کرده می‌آورد (پایین‌تر را ببینید) |
| **فایل‌ها** | بایت به بایت، با بیت اجرایی، از جمله نام‌هایی که فاصله دارند |
| **نام و ایمیل شما** | `user.name` و `user.email` گیت هویت zev این مخزن می‌شوند |
| **هوک‌ها** | pre-commit، commit-msg، post-commit، pre-push و post-merge، از `.git/hooks` یا `core.hooksPath` (Husky) |
| **.gitignore** | همان‌طور که هست خوانده می‌شود. اگر `.zevignore` اضافه کنید، جایش را می‌گیرد |
| **Git LFS** | فایل‌هایی که محتوایشان در `.git/lfs` است کامل می‌آیند: zev خودش فایل‌های بزرگ را نگه می‌دارد، پس سرور LFS لازم نیست. برای آن‌هایی که فقط اشاره‌گر دارند، `git lfs fetch --all` بزنید و دوباره بیاورید؛ zev نامشان را می‌گوید |
| **زیرماژول‌ها** | zev هر کدام را با نشانی‌اش نام می‌برد. مخزنش را هم بیاورید، سپس `zev sub add <address> <folder>` آن را [زیرمخزن](/docs/fa/subrepos) می‌کند |
| **پیوندهای نمادین** | به‌صورت پیوند می‌آیند، همان‌طور که Git نگهشان می‌دارد: مقصد پیوند، نه فایلی که به آن اشاره می‌کند |
| **فایل‌های CI** | به‌صورت فایل، سر جای خودشان می‌مانند |
| **امضاها** | کامیت‌های آورده‌شده امضا ندارند: امضا می‌گوید چه کسی کامیت را ساخته، و آوردن آن را نساخته. هر چه بعد از آن کامیت کنید خودکار امضا می‌شود ([کامیت‌های امضاشده](/docs/fa/signed-commits)) |

## چه چیزی متفاوت کار می‌کند

**تاریخچه یک خط صاف می‌ماند.** zev کامیت merge ندارد. `zev merge` کامیت‌های شما را روی شاخهٔ دیگر دوباره اجرا می‌کند، پس `zev log` همیشه از بالا به پایین خوانده می‌شود و چیزی برای باز کردن ندارد. همان تاریخچه‌ای است که کاربران Git از `git pull --rebase` می‌گیرند. وقتی آوردن به یک merge در Git می‌رسد، شاخه‌ای را دنبال می‌کند که merge روی آن انجام شده، و merge یک کامیت می‌شود که هر چه آورده را در خود دارد. `--check` می‌گوید این کار چند کامیت را در خود جمع می‌کند.

**برگرداندن یک دستور است.** نه `commit --amend` هست، نه دستورالعمل `reset`، نه reflog که به خاطر بسپارید: `zev undo` آخرین commit، merge، rebase یا آوردن را برمی‌گرداند و `zev op log` هر کاری که کرده‌اید را فهرست می‌کند ([برگرداندن هر چیز](/docs/fa/undo)).

**هنوز همه‌چیز اینجا نیست.** worktreeها و checkoutهای sparse و shallow هنوز در zev شکلی ندارند.

همهٔ دستورهای روزمره همان نام را دارند: [دستورهای Git شما در zev](/docs/fa/zev-vs-git#دستورهای-git-شما-در-zev).

## CI و ابزارهای شما

اسکریپت‌هایی که `git status --porcelain` را می‌خوانند می‌توانند `zev status --brief` را بخوانند، که همان دو حرف را به کار می‌برد. برای بقیه، همهٔ دستورهای روزمره `--json` دارند ([اسکریپت‌نویسی و عامل‌های هوش مصنوعی](/docs/fa/automation-and-agents)). Zaryn با هر push، CI را اجرا می‌کند ([شروع با CI](/docs/fa/get-started-ci)).

## دستورها

| دستور | چه می‌کند |
|---|---|
| `zev import-git --check` | پیش‌نمایش: تاریخچه، اندازه، بزرگ‌ترین فایل‌ها، چه می‌آید و چه کاری اول با شماست. چیزی نمی‌نویسد |
| `zev import-git` | تاریخچهٔ Git این پوشه را در همین‌جا می‌آورد |
| `zev import-git <folder>` | تاریخچهٔ Git پوشه‌ای دیگر را می‌آورد |
| `zev import-git <address> [<folder>]` | با Git کلون می‌کند (و فایل‌های LFS را می‌گیرد)، سپس می‌آورد |
| `zev import-git --verify` | می‌آورد، سپس اثبات می‌کند هر کامیت و هر فایل سر هر شاخه با Git یکی است |
| `zev git <a git command>` | شکل zev آن را می‌گوید و اجرا می‌کند؛ `-n` فقط می‌گوید، `--json` آن را به‌صورت داده می‌دهد |
| `eval "$(zev git --shell-setup)"` | در مخزن zev، `git` تایپ کنید و zev بگیرید |
| `--json`، `--brief` | خروجی ماشین‌خوان برای هر کدام از این‌ها |

همچنین ببینید: [zev و Git](/docs/fa/zev-vs-git)، [زیرمخزن‌ها](/docs/fa/subrepos)، [چرا zev](/docs/fa/why-zev).
