---
title: "استخدم SSH بدل HTTPS مع Git"
description: "أوقفت GitHub قبول كلمات المرور مع Git عبر HTTPS في آب 2021. و‏credential helper يريحك من الكتابة لا من انتهاء الصلاحية؛ أما المفتاح فيريحك منهما معًا، ويطال روابط HTTPS التي لم تكتبها أنت."
author: "Omar Albeik"
date: 2021-08-23
type: note
topics: [tooling, software, engineering]
language: ar
reading_time_minutes: 5
canonical_url: https://omaralbeik.com/ar/blog/enforce-ssh-instead-of-http-for-git-operations
translation_url: https://omaralbeik.com/en/blog/enforce-ssh-instead-of-http-for-git-operations
source_url: https://omaralbeik.com/ar/blog/enforce-ssh-instead-of-http-for-git-operations.md
---

# استخدم SSH بدل HTTPS مع Git

قبل عشرة أيام أوقفت GitHub قبول كلمات مرور الحسابات مع Git عبر HTTPS.
فإن كنت تدفع تعديلاتك عبر HTTPS صرتَ اليوم تلصق personal access token بدل كلمة
المرور: سرٌّ أطول، محفوظٌ حيث كانت كلمة المرور، تنتهي صلاحيته في موعدٍ عليك أن
تتذكّره.

ويكفيك `credential helper` عناءَ الكتابة — ‏`osxkeychain` أو Git Credential
Manager أو `gh auth login` — وإن كان الـ‏token يناسبك فهو جوابٌ وجيه. لكنّ ما لا
يكفيك إياه انتهاءُ الصلاحية: فكل بضعة أشهر تنتهي صلاحيته، فتعود إلى صفحة
الإعدادات تولّد غيره وتحاول أن تتذكّر أيّ scopes كانت له.

أما مفتاح SSH فلا صلاحية له تنتهي. تُولّد زوجًا مرة واحدة، وتُبقي النصف الخاص
على جهازك، وتُسلّم النصف العام إلى الخادم، ويبقى الأمر قائمًا حتى تُلغيه أنت.
وهو يبلغ أيضًا ما لا يبلغه الـ‏helper: روابط HTTPS التي لم تكتبها أنت، في
مستودعاتٍ وملفات تبعيّاتٍ يملكها غيرك.

والخطوتان الأوليان تجدهما في كل شرح. أما الخطوتان بعدهما فهما ما يجعل هذا
الإعداد يثبت.

## توليد المفتاح

```bash
ssh-keygen -t ed25519 -C "personal github" -f ~/.ssh/personal-github
```

‏Ed25519 بدل RSA: مفاتيح أقصر، ومصافحةٌ أسرع، ولا وسيطَ لحجم المفتاح تخطئ فيه.
وإن كان ما تتعامل معه أقدم من OpenSSH 6.5 فالبديل `-t rsa -b 4096`.

سمِّ المفتاح باسم ما يفتحه — `personal-github` أو `work-gitlab` — وشغّل
`ssh-keygen` مرةً لكل حساب. فـ‏GitHub ترفض مفتاحًا عامًّا مسجَّلًا في حسابٍ آخر،
وحسابان يفرضان مفتاحين شئتَ أم أبيت. وولّد على كل جهازٍ مفتاحه، ولا تنقل نصفًا
خاصًّا من جهازٍ إلى جهاز: فمفتاحٌ يوجد في مكانٍ واحد مفتاحٌ تُلغيه من مكانٍ
واحد. أما `id_ed25519_2` فلن يخبرك بشيء يوم تحتاج إلى إلغائه.

واستعمل عبارة مرور؛ فهي مع `ssh-agent` تكلّفك طلبًا واحدًا في الجلسة، لا طلبًا
مع كل دفعة.

## إضافة المفتاح العام إلى الخادم

انسخ النصف العام، أي الملف المنتهي بـ `.pub`. أما الذي بلا امتدادٍ فيبقى حيث
وُلِّد:

```bash
# macOS
pbcopy < ~/.ssh/personal-github.pub

# Linux
xclip -selection clipboard < ~/.ssh/personal-github.pub
```

ثم ألصقه في إعدادات حسابك:
[GitHub](https://docs.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account)
أو [GitLab](https://docs.gitlab.com/ee/ssh/)
أو [Bitbucket](https://support.atlassian.com/bitbucket-cloud/docs/set-up-an-ssh-key/).

## إخبار SSH بأيّ مفتاح يستعمل

يجرّب SSH إن تُرك وشأنه الأسماءَ الافتراضية — `id_ed25519` و‏`id_rsa` — فلا
يُعرَض مفتاحٌ اسمه `personal-github` أصلًا. في ملف `~/.ssh/config`:

```ssh-config
Host github.com
  User git
  IdentityFile ~/.ssh/personal-github
  IdentitiesOnly yes
  AddKeysToAgent yes

Host gitlab.com
  User git
  IdentityFile ~/.ssh/work-gitlab
  IdentitiesOnly yes
  AddKeysToAgent yes
```

و‏`IdentitiesOnly yes` سطرٌ لا غنى عنه. فبدونه يعرض SSH كل مفتاحٍ لدى
`ssh-agent`، وتوثّقك GitHub بالحساب الذي يطابق أولَ مفتاحٍ ينطبق — فيعود مستودعٌ
تملك صلاحية الوصول إليه بجواب «غير موجود». يبدو ذلك خللًا في الصلاحيات وليس
كذلك.

وعلى macOS يحفظ `UseKeychain yes` في كل كتلة عبارةَ المرور في Keychain فتبقى
بعد إعادة التشغيل. غير أنّ الخيار من نسخة آبل من OpenSSH لا من الأصل، فإن كانت
نسخة Homebrew من `openssh` أسبقَ في `PATH` رفض الإقلاع. وحمّل المفتاح إلى
‏Keychain مرةً واحدة بـ `ssh-add -K ~/.ssh/personal-github`.

واتّصل مرةً واحدة، لتتحقّق من المفتاح ولتجيب عن السؤال الذي يطرحه SSH أولَ مرةٍ
يلتقي فيها خادمًا:

```bash
ssh -T git@github.com
```

يعرض السؤال بصمة مفتاح الخادم. قارنها بالبصمات التي تنشرها GitHub قبل أن تجيب
بـ `yes`: فهذا السؤال هو كلّ ما يفعله SSH من توثيقٍ للخادم، وهو أسهل ما في هذه
الصفحة أن تجيب عنه بلا تفكير. وبعده تعني تحيةٌ باسم مستخدمك أن المفتاح يعمل.

وإن تعلّق الاتصال بدل ذلك فالأرجح أن الشبكة تحجب المنفذ 22، و‏GitHub تستقبل SSH
على المنفذ 443 أيضًا:

```ssh-config
Host github.com
  Hostname ssh.github.com
  Port 443
  # ...the rest of the block as above
```

والأولى أن تضبطه قبل أن تحتاجه، فبعد الخطوة التالية لن يبقى HTTPS متاحًا مخرجًا
احتياطيًا.

## إعادة كتابة روابط HTTPS إلى SSH

لا ينفع المفتاح ما دامت عناوين مستودعاتك البعيدة تبدأ بـ `https://`. وبدل
إصلاحها مستودعًا مستودعًا، اطلب من Git أن يستبدلها، في ملف `~/.gitconfig`:

```ini
[url "ssh://git@github.com/"]
  insteadOf = https://github.com/

[url "ssh://git@gitlab.com/"]
  insteadOf = https://gitlab.com/

[url "ssh://git@bitbucket.org/"]
  insteadOf = https://bitbucket.org/
```

الآن يُعاد كتابة كل رابط HTTPS لتلك المواقع قبل أن يغادر الطلبُ جهازك، بما في
ذلك الروابط التي لم تكتبها أنت. و‏submodules وحدها تبرّر هذا الإعداد: ملف
`.gitmodules` أودعه غيرك، يشير إلى HTTPS، في مستودعٍ لا رأي لك فيه. ومثله كل
تبعيّةٍ تسمّي مستودع Git برابط HTTPS — حزمة pod فيها سطر `:git =>`، أو
`go get` تحت `GOPRIVATE`، أو حزمة npm مكتوبة `git+https://`.

وهناك أمران لا يشملهما هذا الإعداد، وهذا هو الصحيح. فـ‏package managers التي
تجلب أرشيفًا بدل أن تستنسخ لا تسلّم Git رابطًا أصلًا: انتقلت CocoaPods إلى CDN
في الإصدار 1.8، و‏Go proxy يجلب الوحدات العامة، واختصار npm بصيغة
`github:user/repo` ينتهي إلى أرشيفٍ من codeload. وهذا الملف `~/.gitconfig` على
جهازك أنت، و‏CI runner له مستخدمه ومجلده الخاص ولن يراه أبدًا. وهذا هو المطلوب:
فالمفروض أن يوثّق CI نفسه بـ‏token محدود الصلاحيات عبر HTTPS، لا بمفتاحك
الشخصي.

## التحقق من إعادة الكتابة

يجري الاستبدال داخل Git قبل الشبكة، فيمكنك أن تراه دون أن تتصل بشيء:

```bash
git ls-remote --get-url https://github.com/omaralbeik/SwifterSwift.git
```

فإن طبع `ssh://git@github.com/omaralbeik/SwifterSwift.git` فالاستبدال يعمل.
والجأ إلى هذا بدل استنساخ مستودعٍ عام للاختبار: فاستنساخ المستودعات العامة عبر
HTTPS ينجح بلا بيانات اعتماد في الحالين، فلا يدلّك نجاحه على شيء.

وهذا هو الترتيب كلّه: Git يعيد كتابة الرابط، و‏SSH يختار المفتاح الذي يخصّ
الخادم. لا صلاحية تنتهي، ولا شيء تلصقه.
