توی این درس یاد میگیری GitHub چه چیزی بیشتر از «یک سرور Git» به تو میدهد و چطور یک مخزن در آن بسازی و مدیریت کنی: عمومی یا خصوصی، یک README که واقعاً به درد بخورد، LICENSE و .gitignore، و Issues برای ثبت باگ و ایده. میفهمی فرق مخزن خالی و مخزن با README چیست و چرا دومی ممکن است خطای refusing to merge unrelated histories بدهد (و با دو مخزن محلی آن را واقعاً میسازی و حل میکنی). با ابزار gh (مثل gh repo create --private و gh issue create) آشنا میشوی. تمرین: یک مخزن خصوصی با README و دو Issue بساز.
مسئله: Git فقط نیمی از ماجراست
Section titled “مسئله: Git فقط نیمی از ماجراست”Git تاریخچه را نگه میدارد و بین کامپیوترها هماهنگ میکند. ولی یک تیم چیزهای دیگری هم لازم دارد: جایی برای گفتوگو دربارهی باگها و ایدهها، بازبینی کد قبل از ادغام، اجرای خودکار تستها، مدیریت دسترسی (چه کسی بنویسد، چه کسی فقط بخواند)، و یک صفحهی معرفی پروژه. GitHub اینها را روی یک مخزن Git میگذارد: Issues، Pull Request، Actions، Projects، Wiki، Releases و تنظیمات دسترسی. تو هنوز همان Git را داری؛ GitHub لایهی همکاری رویش است.
تشبیه: ساختمان اداری
Section titled “تشبیه: ساختمان اداری”مخزن Git مثل یک اتاق پر از پرونده است. GitHub آن اتاق را در یک ساختمان اداری میگذارد: دفتر ثبت درخواستها (Issues)، اتاق جلسه برای بازبینی (Pull Request)، نگهبان که تعیین میکند چه کسی وارد شود (دسترسیها)، و کارگرانی که هر صبح خودکار چیزها را کنترل میکنند (Actions). خود پروندهها (کد و تاریخچه) همانهایی هستند که قبلاً داشتی.
مثالهای عملی
Section titled “مثالهای عملی”از این درس به بعد بیشتر با ویژگیهای GitHub سر و کار داریم که به حساب کاربری نیاز دارند و من به حساب تو وارد نمیشوم (ورود به حساب کار خودت است). پس هر چه به حساب GitHub وابسته است «نمونه (اجرا نشده)» برچسب دارد و دستورها از مستندات رسمی GitHub و gh گرفته شدهاند. بخشهایی که فقط Git هستند (مثل رفتار مخزن خالی و مخزن با README) را با مخزنهای bare محلی که نقش GitHub را بازی میکنند، واقعاً اجرا و تست کردهام.
مثال ۱ (نمونه): ساختن مخزن در مرورگر
Section titled “مثال ۱ (نمونه): ساختن مخزن در مرورگر”در GitHub: دکمهی New repository (علامت + بالای صفحه). فرم این گزینهها را دارد:
| گزینه | معنی | توصیه |
|---|---|---|
| Owner / Repository name | حساب یا سازمان و نام مخزن | نام کوتاه، با خط تیره، انگلیسی (my-shop)؛ بدون فاصله |
| Description | یک خط توضیح | همیشه بنویس؛ در نتیجهی جستوجو دیده میشود |
| Public / Private | همه ببینند یا فقط افراد دعوتشده | کار شخصی و ناتمام: Private؛ نمونهکار و متنباز: Public |
| Add a README file | یک README.md اولیه میسازد |
بستگی دارد: مثال ۴ |
| Add .gitignore | قالب آماده برای یک زبان (مثلاً Node) | بله، اگر پروژهی تازه میسازی |
| Choose a license | فایل LICENSE |
برای متنباز لازم (مثال ۶) |
بعد از ساخت، GitHub صفحهای با دستورهای اتصال نشان میدهد؛ مثال ۳ دقیقاً همانهاست.
مثال ۲ (نمونه): ساختن مخزن با gh
Section titled “مثال ۲ (نمونه): ساختن مخزن با gh”gh ابزار خط فرمان رسمی GitHub است (جدا از git؛ باید نصب و با gh auth login وارد حسابت شوی). این دستورها را اجرا نکردهام؛ شکل و گزینهها از مستندات رسمی cli.github.com/manual است:
# ساخت یک مخزن خصوصی از پوشهی فعلی، اتصال remote به اسم origin و ارسال commit هاgh repo create my-shop --private --source=. --remote=origin --push
# ساخت یک مخزن عمومی تازه با README و gitignore و license، و کلون کردنشgh repo create my-shop --public --add-readme --gitignore Node --license mit --clone
# بدون آرگومان: پرسشوپاسخ تعاملیgh repo createگزینههای مهم (از مستندات): --private و --public (و --internal در سازمانهای Enterprise)، -d/--description، --add-readme، -g/--gitignore قالب، -l/--license نام، -s/--source مسیر (از یک پوشهی موجود)، -r/--remote نام، --push و -c/--clone. و برای وارد شدن به حساب: gh auth login (یکبار؛ مرورگر باز میشود).
مثال ۳: مخزن خالی و اتصال یک پروژهی موجود
Section titled “مثال ۳: مخزن خالی و اتصال یک پروژهی موجود”وقتی مخزن را بدون README میسازی، GitHub یک مخزن کاملاً خالی (بدون هیچ commit ای) میدهد و این دستورها را نشان میدهد: «…or push an existing repository from the command line». آنها را عیناً روی یک «GitHub» محلی (مخزن bare) اجرا میکنم:
mkdir -p ~/gitlab/github && cd ~/gitlabgit init -q --bare github/my-shop.gitecho "--- «GitHub»: مخزن خالی، هنوز هیچ commit ای ندارد:"git -C github/my-shop.git log --oneline 2>&1 | head -1echo "--- پروژهی محلی که از قبل دارم:"mkdir my-shop && cd my-shop && git init -qecho "print('shop')" > app.py && git add app.py && git commit -qm "Add app"git branch -M maingit remote add origin ~/gitlab/github/my-shop.gitgit push -u origin main 2>&1 | tail -3echo "--- حالا «GitHub» پروژه را دارد:"git -C ~/gitlab/github/my-shop.git log --oneline--- «GitHub»: مخزن خالی، هنوز هیچ commit ای ندارد:fatal: your current branch 'main' does not have any commits yet--- پروژهی محلی که از قبل دارم:To /home/ali/gitlab/github/my-shop.git * [new branch] main -> mainbranch 'main' set up to track 'origin/main'.--- حالا «GitHub» پروژه را دارد:af0f74c Add appسه دستور اصلی: git branch -M main (شاخهی فعلی را به main تغییر نام بده؛ -M یعنی حتی اگر main از قبل بود)، git remote add origin آدرس و git push -u origin main. روی GitHub واقعی آدرس چیزی مثل git@github.com:USER/my-shop.git است (درس قبل).
مثال ۴: مخزن با README و دام «unrelated histories»
Section titled “مثال ۴: مخزن با README و دام «unrelated histories»”اگر هنگام ساخت مخزن «Add a README file» را بزنی، GitHub همان لحظه یک commit اول (با README.md) در مخزن میسازد. حالا اگر یک پروژهی محلی هم داری که تاریخچهی خودش را دارد، دو تاریخچهی بیارتباط داری. این را اینطور شبیهسازی میکنم: «GitHub» یک commit README دارد و پروژهی من هم تاریخچهی خودش را:
cd ~/gitlabgit init -q --bare github/with-readme.gitgit clone -q github/with-readme.git /tmp/lx-web 2>/dev/null(cd /tmp/lx-web && git config user.name "GitHub UI" && git config user.email "ui@example.com" && echo "# with-readme" > README.md && git add README.md && git commit -qm "Initial commit" && git push -q origin main)rm -rf /tmp/lx-webmkdir -p mine && cd mine && git init -qecho "print('my code')" > app.py && git add app.py && git commit -qm "Add my code"git remote add origin ~/gitlab/github/with-readme.gitecho "=== push:"git push -u origin main 2>&1 | head -4echo "=== pull:"git pull origin main --no-rebase 2>&1 | tail -3=== push:To /home/ali/gitlab/github/with-readme.git ! [rejected] main -> main (fetch first)error: failed to push some refs to '/home/ali/gitlab/github/with-readme.git'hint: Updates were rejected because the remote contains work that you do not=== pull: * branch main -> FETCH_HEAD * [new branch] main -> origin/mainfatal: refusing to merge unrelated historiesدو شکست پشتسرهم، و هر دو درستاند: ۱) push رد شد چون سرور commit ای دارد (README) که من ندارم. ۲) pull هم میگوید refusing to merge unrelated histories: این دو تاریخچه از ریشهی متفاوت شروع شدهاند (هیچ commit مشترکی ندارند) و Git نمیخواهد دو چیز بیارتباط را بیخبر یکی کند. دو راه دارد (از بهتر به سریعتر):
cd ~/gitlab/mineecho "=== راه ۱ (فقط اگر عمداً میخواهی دو تاریخچه یکی شوند): --allow-unrelated-histories"git pull origin main --no-rebase --allow-unrelated-histories --no-edit 2>&1 | tail -3git log --oneline --graphgit push -u origin main 2>&1 | tail -2=== راه ۱ (فقط اگر عمداً میخواهی دو تاریخچه یکی شوند): --allow-unrelated-histories README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md* 078fe32 Merge branch 'main' of /home/ali/gitlab/github/with-readme|\| * ee57b75 Initial commit* d37e990 Add my code ee57b75..078fe32 main -> mainbranch 'main' set up to track 'origin/main'.نتیجه یک commit ادغام با دو والد (هر دو ریشه) است. راه بهتر، که در پروژهی تازه معمولاً همان است: یا مخزن را خالی بساز (مثال ۳) یا اول مخزن GitHub را کلون کن و فایلهایت را داخل آن بریز. هر دو یک تاریخچهی واحد دارند:
cd ~/gitlabgit clone -q github/with-readme.git clonedcd clonedgit config user.name "Ali" && git config user.email "ali@example.com"echo "print('my code')" > app.py && git add app.py && git commit -qm "Add my code"git push -qgit log --oneline --graphOn branch mainYour branch is up to date with 'origin/main'.
nothing to commit, working tree clean* 078fe32 Merge branch 'main' of /home/ali/gitlab/github/with-readme|\| * ee57b75 Initial commit* d37e990 Add my codeمثال ۵ (نمونه): README.md، صفحهی اول پروژه
Section titled “مثال ۵ (نمونه): README.md، صفحهی اول پروژه”GitHub فایل README.md را بهصورت صفحهی اول مخزن نشان میدهد (Markdown رندر میشود). README خوب به سه سؤال جواب میدهد: این چیست؟ چطور اجرا کنم؟ چطور کمک کنم؟ یک قالب کوتاه که میشود شروع کرد (فایل را میسازم و ببین):
mkdir -p ~/gitlab/readme-demo && cd ~/gitlab/readme-demo && git init -qcat > README.md <<'EOF'# My Shop
یک فروشگاه کوچک با Python: سبد خرید، تخفیف و فاکتور.
## نصب و اجرا
~~~bashgit clone git@github.com:USER/my-shop.gitcd my-shoppython3 app.py~~~
## ساختار پروژه
- `app.py`: نقطهی شروع- `tests/`: تستها (`python3 -m unittest`)
## مشارکت
Issue باز کن یا یک Pull Request بفرست. راهنمای کامل: `CONTRIBUTING.md`.
## مجوز
MITEOFgit add README.md && git commit -qm "Add README"wc -l README.mdhead -4 README.md24 README.md# My Shop
یک فروشگاه کوچک با Python: سبد خرید، تخفیف و فاکتور.چکلیست README خوب:
| بخش | چرا |
|---|---|
| عنوان و یک جمله توضیح | خواننده در ۱۰ ثانیه بفهمد پروژه چیست |
| نصب و اجرا (دستورهای قابل کپی) | کسی که هیچچیز نمیداند بتواند اجرا کند |
| نمونهی استفاده یا اسکرینشات | نشان بده کار میکند |
| ساختار پوشهها | کمک به خوانندهی کد |
| مشارکت و تماس | چطور Issue بزند، چطور کمک کند |
| مجوز (License) | آیا دیگران قانوناً میتوانند استفاده کنند |
بلوک کد داخل README را برای اینکه با بلوک کد همین صفحه قاطی نشود با ~~~ نوشتم (Markdown و GitHub هر دو را میپذیرند؛ در README واقعی معمولاً ``` مینویسند). ظاهر رندرشدهی Markdown را فقط در GitHub میبینی؛ اینجا ساختار فایل را ساختم.
مثال ۶: LICENSE و .gitignore
Section titled “مثال ۶: LICENSE و .gitignore”بدون LICENSE، پروژهی عمومی طبق قانون «همهی حقوق محفوظ» است؛ یعنی دیگران حق استفاده، تغییر و بازتوزیع ندارند، حتی اگر کدت را ببینند. برای متنباز، یک مجوز انتخاب کن. هنگام ساخت مخزن در GitHub (یا با gh repo create --license) متن آمادهی آن اضافه میشود:
| مجوز | معنی (خلاصه) | برای |
|---|---|---|
| MIT | هر کاری بکنند؛ فقط اعلان کپیرایت و متن مجوز را نگه دارند | سادهترین، رایجترین |
| Apache-2.0 | مثل MIT + اعطای صریح حق ثبت اختراع (patent) | پروژههای بزرگتر یا شرکتی |
| GPL-3.0 | هر نسخهی تغییریافته که منتشر شود باید خودش هم متنباز با همین مجوز باشد (copyleft) | وقتی میخواهی کد باز بماند |
| (بدون مجوز) | همهی حقوق محفوظ | کد خصوصی |
(این جدول یک خلاصهی عمومی است و مشاورهی حقوقی نیست؛ برای تصمیم مهم، متن کامل مجوز را بخوان.) و .gitignore هم از قالبهای آمادهی GitHub میآید (درس .gitignore). فایلهای خاصی که GitHub میشناسد و در پوشهی .github/ میگذاری (فایلهایی عادی در مخزناند، و GitHub در رابط خودش از آنها استفاده میکند):
cd ~/gitlab/readme-demomkdir -p .github/ISSUE_TEMPLATEcat > .github/ISSUE_TEMPLATE/bug_report.md <<'EOF'---name: Bug reportabout: گزارش یک خطاlabels: bug---
## چه اتفاقی افتاد؟
## چه انتظاری داشتی؟
## مراحل بازتولید
1.2.EOFcat > .github/PULL_REQUEST_TEMPLATE.md <<'EOF'## چه چیزی عوض شد؟
## چطور آزمایش کردی؟EOFgit add .github && git commit -qm "Add issue and PR templates"git ls-files.github/ISSUE_TEMPLATE/bug_report.md.github/PULL_REQUEST_TEMPLATE.mdREADME.mdISSUE_TEMPLATE/ قالبهایی برای باز کردن Issue، و PULL_REQUEST_TEMPLATE.md متن پیشفرض Pull Request است (درس بعد). اینها فقط فایل در مخزناند؛ GitHub آنها را (روی خودش) هنگام باز کردن Issue یا PR نشان میدهد، و من فقط ساخت فایلها را آزمایش کردهام.
مثال ۷: Issues، ثبت و ارجاع
Section titled “مثال ۷: Issues، ثبت و ارجاع”Issue یک «برگهی کار» است: یک باگ، ایده یا سؤال با عنوان، توضیح، برچسب (label)، مسئول (assignee) و ماهنقطه (milestone). هر Issue یک شماره میگیرد (#12) و میشود در همهجا (Issue دیگر، Pull Request، commit) به آن اشاره کرد. اگر در پیام commit بنویسی Fixes #12 (یا Closes #12، Resolves #12)، وقتی آن commit به شاخهی پیشفرض برسد GitHub خودکار Issue را میبندد. این کلیدواژهها را فقط GitHub تفسیر میکند؛ ولی چون خود شماره داخل پیام commit میماند، میشود با Git هم ردشان را گرفت:
mkdir -p ~/gitlab/issues && cd ~/gitlab/issues && git init -qfor m in "Add login form (refs #3)" "Fix crash on empty cart. Fixes #7" "Update docs" "Validate email. Closes #3" "Fix typo (#7)"; do echo "$m" >> log.txt; git add log.txt; git commit -qm "$m"; doneecho "--- commit هایی که به Issue ها اشاره دارند:"git log --oneline --grep='#[0-9]'echo "--- همهی commit های مربوط به Issue شمارهی 3:"git log --oneline --grep='#3'echo "--- فهرست یکتای Issue های ذکرشده:"git log --format=%s | grep -oE '#[0-9]+' | sort -u--- commit هایی که به Issue ها اشاره دارند:1be0a6b Fix typo (#7)dd5048a Validate email. Closes #32e3e033 Fix crash on empty cart. Fixes #7f0549a3 Add login form (refs #3)--- همهی commit های مربوط به Issue شمارهی 3:dd5048a Validate email. Closes #3f0549a3 Add login form (refs #3)--- فهرست یکتای Issue های ذکرشده:#3#7با همین git log --grep میشود یادداشت انتشار ساخت (درس tag: git log v1.0.0..v1.1.0). پس هر commit را به یک Issue وصل کن؛ شش ماه بعد معلوم است «چرا» این تغییر داده شد.
مثال ۸ (نمونه): gh issue در ترمینال
Section titled “مثال ۸ (نمونه): gh issue در ترمینال”بدون رفتن به مرورگر، با gh Issue بساز و فهرست کن. اینها را اجرا نکردهام (نیاز به ورود به حساب دارند)؛ گزینهها طبق مستندات رسمی است:
# ساخت یک Issue با عنوان، توضیح و برچسبgh issue create --title "صفحهی ورود" --body "فرم ایمیل و رمز، با اعتبارسنجی" --label enhancement
# ساخت با ویرایشگر (عنوان و متن را آنجا مینویسی) یا در مرورگرgh issue create --editorgh issue create --web
# فهرست Issue های باز، دیدن یکی، بستنشgh issue listgh issue view 12gh issue close 12 --comment "در PR شمارهی 15 درست شد"گزینههای gh issue create (از مستندات): -t/--title، -b/--body، -F/--body-file، -l/--label، -a/--assignee، -m/--milestone، -p/--project، -e/--editor و -w/--web.
مثال ۹ (نمونه): همکاران و نقشها
Section titled “مثال ۹ (نمونه): همکاران و نقشها”وقتی مخزن خصوصی است فقط تو و کسانی که دعوت میکنی آن را میبینند (Settings ← Collaborators). برای مخزن یک سازمان (Organization)، نقشها دقیقترند:
| نقش | چه کاری میتواند |
|---|---|
| Read | کد را بخواند، Issue و Discussion باز کند |
| Triage | Issue ها و PR ها را مدیریت کند (برچسب، بستن) بدون تغییر کد |
| Write | به مخزن push کند، PR ادغام کند |
| Maintain | مدیریت مخزن بدون تنظیمات حساس |
| Admin | همهچیز: تنظیمات، حذف، دسترسیها |
(این نقشها طبق مستندات GitHub برای مخزنهای سازمان است؛ مخزن شخصی سادهتر است: مالک و همکاران با دسترسی نوشتن.) برای کمککردن به پروژهای که دسترسی نوشتن به آن نداری، fork میکنی (یک کپی از مخزن در حساب خودت) و از آن PR میفرستی (درس بعد).
پشت پرده: GitHub یک سرور Git بهاضافهی چیزهای دیگر
Section titled “پشت پرده: GitHub یک سرور Git بهاضافهی چیزهای دیگر”پشت صحنهی هر مخزن GitHub یک مخزن Git (bare) است، همانکه در این درس ساختیم، و چیزهای اضافه: یک پایگاه داده برای Issue ها و گفتوگوها، یک وبسرور، سرویس Actions و… . مخزن Git خودش مستقل است: میتوانی git clone کنی و روی GitLab یا سرور خودت ببری؛ فقط Issue ها و PR ها (که دادهی GitHubاند، نه Git) باید جداگانه منتقل شوند. برای همین تاریخچهی Git ات هیچوقت به GitHub وابسته نیست، ولی Issue هایت هستند؛ اگر مهماند، گهگاه خروجی بگیر. یک جزئیات مهم: GitHub برای Pull Request ها شاخههای ویژهای در خود مخزن میسازد (refs/pull/N/head)، که در درس بعد میبینی.
جدولهای مرجع
Section titled “جدولهای مرجع”| کار | رابط وب | gh |
|---|---|---|
| ساخت مخزن | New repository | gh repo create نام --private |
| کلون | Code ← Clone | gh repo clone USER/REPO |
| باز کردن مخزن در مرورگر | gh repo view --web |
|
| ساخت Issue | Issues ← New issue | gh issue create |
| فهرست Issue | Issues | gh issue list |
| بستن Issue | Close issue | gh issue close شماره |
| شکل مخزن | چه زمانی | اتصال |
|---|---|---|
| خالی (بدون README) | پروژهی محلی داری | git remote add و git push -u origin main |
| با README | از صفر شروع میکنی | git clone سپس کار کن |
| هر دو را قاطی کنی | unrelated histories |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) نام شاخهی اشتباه در push
Section titled “۱) نام شاخهی اشتباه در push”mkdir -p ~/gitlab/branchname && cd ~/gitlab/branchname && git init -qecho a > f && git add f && git commit -qm "Base"git init -q --bare ../github/names.gitgit remote add origin ~/gitlab/github/names.gitgit branch --show-currentgit push -u origin master 2>&1 | head -3mainerror: src refspec master does not match anyerror: failed to push some refs to '/home/ali/gitlab/github/names.git'error: src refspec master does not match any: شاخهی محلی main است ولی master را push کردی. (دستورهای قدیمی اینترنت اغلب master دارند.) راهحل: git branch --show-current را ببین و همان را بفرست؛ یا git branch -M main.
۲) مخزن خصوصی را عمومی بسازی
Section titled “۲) مخزن خصوصی را عمومی بسازی”وقتی در فرم ساخت مخزن اشتباهاً Public را انتخاب میکنی، هر چه push کنی (حتی رمز) برای همه دیده میشود. راهحل: قبل از اولین push، نوع مخزن را دوباره بخوان؛ و در Settings ← Danger Zone ← Change visibility میشود عوضش کرد؛ ولی اگر رمزی لو رفته باید عوض شود (درس .gitignore). GitHub برای push هایی که کلید و توکنهای شناختهشده دارند هشدار یا مسدودسازی (secret scanning) هم دارد؛ ولی به آن تکیه نکن.
۳) تصادم دو README
Section titled “۳) تصادم دو README”اگر هر دو طرف (مخزن GitHub و پروژهی محلی) یک README.md ساخته باشند، بعد از --allow-unrelated-histories یک conflict از نوع add/add میگیری (هر دو فایل با همین اسم ساختهاند، تمرین سخت). راهحل: مثل هر conflict، فایل را با دست ترکیب کن.
۴) Issue با عنوان مبهم
Section titled “۴) Issue با عنوان مبهم”«کار نمیکند» عنوان نیست. راهحل: عنوان کوتاه و دقیق («Cart total is wrong when a coupon is applied»)، و در متن: چه کردی، چه انتظار داشتی، چه شد، نسخه و محیط. قالب ISSUE_TEMPLATE (مثال ۶) همین را تحمیل میکند.
۵) فراموشکردن .gitignore و LICENSE
Section titled “۵) فراموشکردن .gitignore و LICENSE”مخزن را بدون .gitignore میسازی و node_modules را push میکنی؛ یا کد عمومی را بدون LICENSE میگذاری و کسی قانوناً نمیتواند استفاده کند. راهحل: هنگام ساخت مخزن هر دو را انتخاب کن.
یک README.md برای یک پروژهی فرضی بنویس که سه بخش «توضیح»، «نصب و اجرا» و «مجوز» داشته باشد، commit کن و تعداد خطها را بشمار.
دیدن جواب
mkdir -p ~/gitlab/ex1 && cd ~/gitlab/ex1 && git init -qprintf '# Todo CLI\n\nیک برنامهی سادهی کارهای روزانه.\n\n## نصب و اجرا\n\n python3 todo.py add "خرید نان"\n\n## مجوز\n\nMIT\n' > README.mdgit add README.md && git commit -qm "Add README"wc -l README.mdgrep -c '^## ' README.md11 README.md2تمرین اصلی: یک مخزن خصوصی با README و دو Issue بساز. روی GitHub واقعی این کار به حساب نیاز دارد و من اجرایش نکردهام؛ دستورهای gh و معادل مرورگر در پایین است (نمونه). بخش محلیاش را (README و commit هایی که به Issue ها اشاره دارند) واقعاً اجرا کردم.
دیدن جواب
gh auth login # یک بارmkdir my-private-repo && cd my-private-repo && git init -b mainprintf '# My Private Repo\n\nتوضیح پروژه\n' > README.mdgit add README.md && git commit -m "Add README"gh repo create my-private-repo --private --source=. --remote=origin --pushgh issue create --title "Add login page" --body "Email and password form" --label enhancementgh issue create --title "Fix typo in README" --body "The word 'Wellcome' is misspelled" --label buggh issue listبخش محلی که اجرا کردم (README و commit هایی که به Issue ها اشاره دارند):
mkdir -p ~/gitlab/ex2 && cd ~/gitlab/ex2 && git init -qprintf '# My Private Repo\n\nتوضیح پروژه\n' > README.mdgit add README.md && git commit -qm "Add README"echo "login" > login.txt && git add login.txt && git commit -qm "Add login page. Closes #1"sed -i 's/^توضیح/شرح/' README.md && git commit -qam "Fix README wording. Fixes #2"git log --onelinegit log --grep='#' --format='%s'6b1da64 Fix README wording. Fixes #2e93b20f Add login page. Closes #18ad8c1a Add READMEFix README wording. Fixes #2Add login page. Closes #1دو تاریخچهی بیارتباط بساز که هر دو README.md دارند («GitHub» با README و پروژهی محلی با README دیگر). با --allow-unrelated-histories ادغام کن، conflict نوع AA (add/add) را ببین و با ترکیب هر دو README حل کن.
دیدن جواب
cd ~/gitlabgit init -q --bare github/both.gitgit clone -q github/both.git /tmp/lx-web2 2>/dev/null(cd /tmp/lx-web2 && git config user.name "GitHub UI" && git config user.email "ui@example.com" && echo "# From GitHub" > README.md && git add README.md && git commit -qm "Initial commit" && git push -q origin main)rm -rf /tmp/lx-web2mkdir -p hard && cd hard && git init -qecho "# From my laptop" > README.md && git add README.md && git commit -qm "Add my README"git remote add origin ~/gitlab/github/both.gitgit fetch -qgit merge origin/main --allow-unrelated-histories --no-edit 2>&1 | tail -2git status -sprintf '# Project\n\nFrom GitHub and my laptop (merged).\n' > README.mdgit add README.md && git commit -q --no-editgit log --oneline --graphCONFLICT (add/add): Merge conflict in README.mdAutomatic merge failed; fix conflicts and then commit the result.AA README.md* 5f287d2 Merge remote-tracking branch 'origin/main'|\| * fbedae3 Initial commit* 448bf39 Add my READMEآزمونک
Section titled “آزمونک”مخزن را در GitHub با «Add a README file» ساختهای و یک پروژهی محلی با تاریخچهی خودت داری. git pull با چه خطایی روبهرو میشود و چرا؟
هر دو تاریخچه از commit اول جدایی شروع شدهاند. راه بهتر: مخزن خالی بساز یا اول مخزن را clone کن؛ و فقط اگر عمداً میخواهی با --allow-unrelated-histories ادغام کن.
فرق مخزن «خالی» و مخزن «با README» در GitHub؟
برای اتصال پروژهی موجود، مخزن را خالی بساز.
اگر در پیام commit بنویسی «Fixes #12» و آن commit به شاخهی پیشفرض برسد؟
کلیدواژهها: close/closes، fix/fixes، resolve/resolves. فقط GitHub تفسیرشان میکند.
پروژهی عمومی بدون فایل LICENSE چه وضعیتی دارد؟
برای متنباز یک مجوز (MIT، Apache-2.0، GPL...) انتخاب کن.
دستور gh repo create my-app --private --source=. --push چه میکند؟
--source مسیر مخزن محلی؛ --push ارسال؛ --private خصوصی.
تاریخچهی Git و Issue ها: اگر از GitHub به سرور دیگری بروی؟
مخزن Git مستقل از GitHub است.
جمعبندی
Section titled “جمعبندی”- GitHub = مخزن Git + Issues، Pull Request، Actions، دسترسیها و صفحهی پروژه؛ تاریخچهی Git مستقل از آن است.
- ساخت مخزن: عمومی/خصوصی، README، .gitignore، LICENSE. با
gh repo create نام --private --source=. --push(نیاز بهgh auth login). - پروژهی موجود ← مخزن خالی:
git branch -M main،git remote add origin آدرس،git push -u origin main. مخزن با README + تاریخچهی محلی ←unrelated histories؛ بهتر:git cloneو کار در آن. - README خوب: چیست، نصب و اجرا، نمونه، ساختار، مشارکت، مجوز. بدون LICENSE دیگران قانوناً حق استفاده ندارند.
- Issues: باگ و ایده با برچسب و مسئول؛ در commit با
#شمارهیاFixes #12ارجاع بده (بستن خودکار فقط روی GitHub).git log --grep='#12'ردش را میگیرد؛gh issue create/list/close. - نقشها: Read، Triage، Write، Maintain، Admin (سازمانها). رمز و کلید را هرگز push نکن.
| دستور | کاری که میکند |
|---|---|
gh auth login | ورود gh به حساب (یکبار) |
gh repo create نام --private --source=. --push | ساخت مخزن خصوصی از پوشهی فعلی |
git branch -M main | تغییر نام شاخهی فعلی به main |
git remote add origin آدرس | اتصال به مخزن |
git push -u origin main | ارسال و upstream |
git pull --allow-unrelated-histories | ادغام دو تاریخچهی بیارتباط (با احتیاط) |
gh issue create --title "..." --body "..." | ساخت Issue |
gh issue list / gh issue close 12 | فهرست / بستن |
git log --grep="#12" | commit های مربوط به Issue 12 |
Fixes #12 | بستن خودکار Issue با رسیدن commit به شاخهی پیشفرض |