
سأتحدث في هذه المقالة عن خدعة واحدة مفيدة ولكنها غير معروفة للعمل مع git - كيفية إنشاء التزام بسهولة باستخدام شجرة من التزام آخر. ببساطة ، كيفية الحصول على الحالة المطلوبة للمشروع على أي فرع ، إذا كانت هذه الحالة موجودة بالفعل في مكان ما وفي مكان ما في المستودع من قبل. سيتم تقديم عدة أمثلة حول كيفية قيام ذلك بحل بعض المشكلات العملية بأناقة. وعلى وجه الخصوص ، سأتحدث عن الطريقة التي وجدتها ، والتي يمكن أن تبسط بشكل كبير تصحيح تعارضات متعددة أثناء rebase. بالإضافة إلى ذلك ، تعتبر هذه المقالة طريقة رائعة لفهم ما يشكل التزامًا في الممارسة العملية.
المحتويات
الجزء النظري. حول يرتكب والأشجار
بوابة الالتزام شجرة
الجزء العملي
1. التزامن مع فرع آخر
2. مقارنة بين فرعين
3. فرع عكس
4. عكس جزئي
5. دمج الاصطناعي
6 أ. Rebase طريقة عبر دمج - الوصف
6 ب. Rebase طريقة عبر دمج - النصي
7. الاسم المستعار
الخاتمة
الجزء النظري. حول يرتكب والأشجار
ربما يكون الالتزام هو المفهوم الأساسي في git ، دعنا نرى ما الذي يتكون منه. لكل التزام معرف فريد خاص به في شكل علامة تجزئة ، على سبيل المثال 5e45ecb . ومع الأمر التالي ، ومعرفة التجزئة ، يمكننا أن نرى محتوياته.
git cat-file -p 5e45ecb
tree 8640790949c12690fc71f9abadd7b57ec0539376 parent 930741d1f5fd2a78258aa1999bb4be897ba3d015 author Mark Tareshawty <tareby...@github.com> 1542718283 -0500 committer Mark Tareshawty <tareby...@github.com> 1542718283 -0500 gpgsig -----BEGIN PGP SIGNATURE----- ... -----END PGP SIGNATURE----- Fix scoping so that we don't break the naming convention
هذه الأسطر القليلة هي محتويات الالتزام:
- شجرة - رابط إلى حالة مشروع معين
- الوالد - رابط الالتزام الوالد
- مؤلف - مؤلف الالتزام الأصلي + التاريخ
- committer - خالق هذا الالتزام + التاريخ
- gpgsig - التوقيع الرقمي (إن وجد)
- رسالة - نص الالتزام
اسمحوا لي أن أذكرك أن الالتزام في بوابة (على عكس VCS) لا يصف التغييرات التي تم إجراؤها. إنه عكس ذلك: يصف كل التزام الحالة المحددة للمشروع ككل ، وما نراه على أنه التغييرات التي يتم إجراؤها هو في الواقع فرق محسوب ديناميكيًا مقارنة بالحالة السابقة. تجدر الإشارة أيضًا إلى أن جميع الالتزامات غير قابلة للتغيير (غير قابلة للتغيير) ، أي على سبيل المثال ، مع rebase / cherry-pick / edit ، يتم إنشاء تعهدات جديدة تمامًا.
شجرة (شجرة) - في الواقع ، هو مجرد مجلد مع محتوى ثابت غير قابل للتغيير. يحتوي كائن شجرة النوع على قائمة بالملفات ذات المحتويات المحددة (النقط) والمجلدات الفرعية (الأشجار). والشجرة التي يرتكبها كل طرف هي المجلد الجذر للمشروع ، أو بالأحرى حالته الخاصة.
عرض محتويات الشجرةيمكن أن يتم ذلك بنفس الطريقة تمامًا لأي كائن آخر (الالتزام / الشجرة / النقطة) ، ويكفي أن تأخذ الأحرف الأولى القليلة المميزة: 8640790949c12690fc71f9abadd7b57ec0539376 -> 8640790.
git cat-file -p 8640790
100644 blob 7ab08294a46f158c51460be3e7df6a190e15023b .env.example 100644 blob 0a1a4d1ad9ff3f35b67678ca893811e91b423af5 .gemset 040000 tree 033aa38ce0eab11fe229067c14ccce95e2b8b601 .github 100644 blob ca49bb7ffa6273b0be4ce7ba1accba456032fb11 .gitignore 100644 blob c99d2e7396e14ac072c63ec8419d9b8fede28d86 .rspec 100644 blob 65e77a2f59f635a8f24eb4714e8e43745c5c0eb9 .rubocop.yml 100644 blob 8e8299dcc068356889b365e23c948b92c6dfcd78 .ruby-version 100644 blob 19028f9885948aca2ba61f9d062e9dc21c21ad03 .stylelintrc.json 100644 blob 2f7a032fbc3f4f7195bfd91cb33889a684b572b9 .travis.yml 100644 blob 121615722a6c206a9fe24b9a1c9b647662a460d2 ARCHITECTURE.md 100644 blob 898195daeea0bbf8c5930deeaf1020ba8abab34a Gemfile 100644 blob de7ca707f9fe9172db941b65cdacaba7e024fc06 Gemfile.lock 100644 blob e6ff62fefd071b1a8ca279bae94ddbc4dd17b7a3 Gruntfile.js 100644 blob 0cac5b30fb32d36cce2aeb7d936be7b6207d68c7 MIT-LICENSE.txt 100644 blob c2c566e8cc3d440d3ee8041b79cded416db28136 Procfile 100644 blob d1fb2f575380e1e093a4d82e3f19e51f0b99a0a1 Procfile.dev 100644 blob 3a88e138f10fa65bd2cfe1a1d3292348205508b5 README.md 100644 blob 5366e6e073cc426518894cc379d3a07cf3c9cfb3 Rakefile 100644 blob e6d3d2d3e9d5122c5f75bbeee8ed0917ad38c131 app.json 040000 tree 94f83cf03bd6f1cf14672034877b14604744b7a2 app 040000 tree d4d859e82564250b4c4f2047de21e089e7555475 bin 100644 blob 1f71007621f17334fd6f2dd71c87b7a16867119c config.ru 040000 tree 9e8e4bf5ec44541aefff544672b94ca8a9d07bbf config 040000 tree 31b8d0e1fa2bb789dbd6319e04fc9f115952cf2a db 040000 tree 38e7a13e0e772c2a13e46d2007e239f679045bee doc 040000 tree a6e35ded8b35837660cf786e637912377f845515 lib 040000 tree d564d0bc3dd917926892c55e3706cc116d5b165e log 100644 blob 843523565ddee5e00f580d9c4e37fc2478fdaecc package-lock.json 100644 blob 791ee833ad316d75b1d2c83a64a3053fc952d254 package.json 040000 tree 4645317c52675d9889f89b26f4dd4d2ae1d8cbad public 040000 tree 31d3f8ae4a4ffe62787134642743ed32a35dbae2 resources 040000 tree 807ffa29868ef9c25ddb4b4126a4bb7f1b041bf0 script 040000 tree 4c3bf9a7f3679ba059b0f1c214a500d197546462 spec 040000 tree 136c8174412345531a9542cafef25ce558d2664f test 040000 tree e6524eafe066819e4181bc56c503320548d8009b vendor
هذه هي في الحقيقة أهم ميزة لكيفية عمل git ، معرف الالتزام هو في الحقيقة جزء من محتوياته. تماما مثل تجزئة الكائنات المضمنة فيه (الأشجار ، النقط).
الآن دعونا نرى ما يحدث عندما نفعل
git commit -m "Fixed bug"
ينشئ هذا الأمر التزامًا جديدًا يلتقط ما يلي:
- حالة مشروع التدريج (تم حفظه ككائن شجرة جديد والتجزئة الخاصة به)
- الارتباط الحالي (الأصل) الالتزام
- المؤلف + المرسل + تاريخان
- ارتكاب النص
يتم حفظ كل هذا ، تجزئة ، ويتم الحصول على كائن التزام جديد. ويقوم الفريق تلقائيًا برفع مؤشر الفرع الحالي إليه.
قليلا عن المصطلحاتكما نعلم بالفعل ، الشجرة هي كائن يحتوي على حالة المشروع في مرحلة معينة في الماضي - عندما تم إنشاء التزام باستخدام هذه الشجرة.
يسمى مجلد العمل دليل العمل / نسخة العمل / الشجرة ، وهو منطقي تمامًا.
لدينا أيضا - منطقة التدريج / مؤشر - مجال التغييرات المعدة. ولكن من الناحية المنطقية ، هذه أيضًا شجرة ، أو بالأحرى ، الحالة التي يتم حفظها عند ارتكابها كشجرة. لذلك ، يبدو لي أنه سيكون من المنطقي أكثر استدعاء شجرة مرحلية.
بوابة الالتزام شجرة
أخيرًا ، يمكننا أن ننتقل إلى وصف أمر الالتزام - git الذي نحتاجه. من الناحية الرسمية ، هذا هو أحد الأوامر ذات المستوى المنخفض ، لذلك نادراً ما يتم ذكره واستخدامه. لن نأخذ في الاعتبار الأوامر الأخرى ذات المستوى المنخفض المرتبطة بها (مثل git-tree-git-update-index ، فهي تعرف أيضًا باسم أوامر السباكة). نحن مهتمون فقط بنتيجة معينة: من خلال هذا الأمر ، يمكننا بسهولة نسخ (إعادة استخدام) شجرة حالة المشروع من أي التزام آخر.
انظروا الى تحديها
git commit-tree 4c835c2 -m "Fixed bug" -p a8fc5e3
d9aded78bf57ca906322e26883644f5f36cfdca5
يتم تنفيذ الأمر git ارتكاب الشجرة أيضًا ، ولكن بطريقة منخفضة المستوى. هنا يجب أن تحدد بشكل صريح الشجرة الحالية (الشجرة) 4c835c2 ورابطًا إلى الوالد الالتزام a8fc5e3. وتقوم بإرجاع تجزئة الالتزام الجديد d9aded7 ، ولا يتغير وضع الفرع (لذلك ، يبدو أن هذا الالتزام يتجمد في الهواء).
الجزء العملي
يتم عرض أمثلة على استخدام هذا الأمر في مستودع التخزين البسيط التالي.

يحتوي على ثلاثة فروع:
سيد - الفرع الرئيسي
ألفا - الفرع الذي نعمل ونعمل عليه
بيتا - فرع تم إيقافه سابقًا في برنامج الماجستير
من السهل تكرار جميع الإجراءات محليًا ، لذلك يكفي استنساخ المستودع ، والحصول على فرع ألفا ، ثم تنفيذ الأوامر من الأمثلة. هذه الحالة الأولية مشتركة بين جميع الأمثلة.
git clone https://github.com/capslocky/git-commit-tree-example.git cd ./git-commit-tree-example/ git checkout alpha
تحت النوافذجميع الأوامر ، بما في ذلك البرنامج النصي ، تعمل أيضًا تحت النوافذ. تحتاج فقط إلى فتح محطة bash في مجلد المشروع ، على سبيل المثال ، مثل هذا
"C:\Program Files\Git\git-bash.exe" --cd="D:\path\project"
1. التزامن مع فرع آخر
التحدي:
مزامنة حالة المشروع على فرع ألفا مع فرع بيتا . أي أنك تحتاج إلى إنشاء مثل هذا الالتزام الجديد على فرع ألفا بحيث تصبح حالة المشروع تمامًا كما في فرع بيتا .
على وجه التحديد ، من غير المحتمل أن تنشأ مثل هذه المهمة على الإطلاق ، ولكن هذه هي الحالة الأنسب لإظهار النهج.
إن أبسط الحلول هو أخذ الشجرة الموجودة التي يشير إليها فرع بيتا والإشارة إليها من الالتزام الجديد لفرع ألفا. نظرًا لأن هذا هو المثال الأول ، يتم اعتبار كل منطقه بتفاصيل كافية.
أولاً ، ابحث عن تجزئة الالتزام التي أشار إليها فرع بيتا:
git rev-parse origin/beta
280c30ff81a574f8dd41721726cf60b22fb2eced
280c30f - فقط خذ الأحرف القليلة الأولى
الآن يمكنك العثور على علامة التجزئة الخاصة بشجرتها من خلال عرض محتويات الالتزام من خلال ملف cat git:
git cat-file -p 280c30f
tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent 560b449675513bc8f8f4d6cda56a922d4e36917a author Baur <atanov...@gmail.com> 1540619512 +0600 committer Baur <atanov...@gmail.com> 1540619512 +0600 Added info about windows
3c1afe7 - هذه هي الشجرة التي نحتاجها
والآن سننشئ التزامًا يشير إلى هذه الشجرة ، ومع الالتزام الوالد سنشير إلى الالتزام الحالي:
git commit-tree 3c1afe7 -m "Synced with branch 'beta'" -p HEAD
eb804d403d4ec0dbeee36aa09da706052a7cc687
هذا كل شيء ، تم إنشاء الالتزام ، وحصل الفريق على التجزئة. علاوة على ذلك ، ستظل هذه القيمة فريدة من نوعها دائمًا ، حيث يتم حسابها ليس فقط من الشجرة ، ولكن أيضًا من المؤلف والوقت. يتم تجميد الالتزام نفسه في الهواء ، طالما أنه لا يدخل أي من الفروع. يكفي أن نأخذ الأحرف القليلة الأولى: eb804d4 ، هذه القيمة ، الفريدة لكل حالة ، سأقوم بتعيينها كسكسكسكسكسكس . دعنا ننظر إلى محتوياته:
git cat-file -p xxxxxxx
tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent 64fafc79e8f6d22f5226490daa5023062299fd6c author Peter <peter...@gmail.com> 1545230299 +0600 committer Peter <peter...@gmail.com> 1545230299 +0600 Synced with branch 'beta'
عظيم ، لديه نفس الشجرة مثل الالتزام على فرع الأصل / بيتا. ولأن هذا الالتزام هو سليل مباشر للفرع الحالي ، لإدراجه في الفرع ، ما عليك سوى دمج دمج سريع للأمام
git merge --ff xxxxxxx
Updating 64fafc7..xxxxxxx Fast-forward Azure.txt | 3 --- Bill.txt | 6 +----- Linus.txt | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 8 deletions(-)
تم الآن حالة المشروع على فرع ألفا هو نفسه تمامًا كما هو الحال في فرع بيتا. [تحديث] وإذا نظرت إلى حقيقة أن هذا الالتزام قد تغير ، فسنرى: أنه عكس جميع التزامات فرع ألفا (التغييرات) وأضاف جميع التزامات بيتا الفريدة (التغييرات) إلى سلف الالتزام المشترك.

2. مقارنة بين فرعين
التحدي:
مقارنة فرع ألفا مع فرع بيتا .
يوضح المثال الأول أن الالتزام الذي تم إنشاؤه يعرض جميع تلك التغييرات التي تمثل الفرق الفعلي بين الفرعين. هذه الخاصية تجعل من السهل مقارنة فرع واحد بآخر. يكفي إنشاء فرع مؤقت ثالث والتزام مماثل فيه.
لذا ، أولاً ، أعد فرع ألفا إلى حالته الأصلية
git reset --hard origin/alpha
دعونا إنشاء فرع مؤقت على الفرع الحالي والوقوف عليه
git checkout -b temp
وتركنا أن نفعل الشيء نفسه كما في المثال السابق. ولكن هذه المرة سنلتقي سطر واحد. للقيام بذلك ، نستخدم بناء الجملة الخاص للوصول إلى أصل شجرة الالتزام / بيتا ^ {شجرة} أو نفس 280c30f ^ {شجرة} .
git merge --ff $(git commit-tree origin/beta^{tree} -m "Diff with branch 'beta'" -p HEAD)
فعلت ، ونحن أساسا تجسدت بمثابة فرق بين فرعين
git show
git diff alpha origin/beta
بالطبع ، يمكننا إنشاء مثل هذا الالتزام "المقارن" لأي التزامين (حالات) في المستودع.

3. فرع عكس
التحدي:
دحر الإلتزامات القليلة الماضية.
دعنا نعود إلى فرع ألفا وحذف فرع مؤقت
git checkout alpha git branch -D temp
لنفترض أننا نحتاج إلى استعادة آخر إعدامات في فرع ألفا. هناك طريقتان تقليديتان للقيام بذلك:
- تشغيل بوابة العودة مرتين - لكل التزام
- git reset ، أي إعادة تعيين موضع الفرع
ولكن يمكنك القيام بذلك بطريقة ثالثة:
git merge --ff $(git commit-tree 7a714bf^{tree} -m "Reverted to commit 7a714bf" -p HEAD)
سيؤدي ذلك إلى إضافة التزام جديد واحد يسترجع التغييرات في الالتزامين السابقين. على عكس الطريقة الأولى ، يتم إنشاء التزام واحد فقط ، حتى إذا كنت بحاجة إلى استعادة آخر عشر تعهدات. والفرق بين الأسلوب مع git reset هو أننا لا نرمي هذه الالتزامات من الفرع نفسه.
علاوة على ذلك ، إذا كنت بحاجة إلى إعادة الحالة الأصلية للفرع ، فيمكن القيام بذلك بطريقة مماثلة
git merge --ff $(git commit-tree 64fafc7^{tree} -m "Reverted back to commit 64fafc7" -p HEAD)
في الوقت نفسه ، سيبقى هذان الالتزامان في تاريخ الفرع ، والذي سيتبين أنه تم إرجاعه وإعادته.

4. عكس جزئي
التحدي:
استرجع التغييرات التي أجريت على بعض الملفات خلال آخر بضع مرات.
مرة أخرى ، أعد فرع ألفا إلى حالته الأصلية
git reset --hard origin/alpha
يحتوي فرع ألفا على 3 تعهدات ، يتم إجراء تغييرات في كل منها على ملف Bill.txt ، وفي الالتزام الأخير ، تتم إضافة ملف Azure.txt أيضًا. لنفترض أننا نحتاج إلى استعادة التغييرات التي تم إجراؤها على ملف Bill.txt الخاص بعمليتي الاستخدام الأخيرتين ، دون لمس أي ملفات أخرى.
أولاً ، استرجع جميع الملفات 2
git merge --ff $(git commit-tree 7a714bf^{tree} -m "any text" -p HEAD)
بعد ذلك ، أعد الفرع إلى الالتزام السابق ، ولكن دون لمس حالة المشروع على القرص
git reset HEAD~1
والآن يكفي رفع الملفات الضرورية والالتزام بها ، ويمكن تجاهل التغييرات الأخرى.
git add Bill.txt git commit -m "Reverted file Bill.txt to 7a714bf" git reset --hard HEAD

5. دمج الاصطناعي
التحدي:
رفع فرع واحد إلى آخر ، والحصول على نتيجة محددة سلفا.
تخيل هذا الموقف. تم اكتشاف خطأ حرج في الإنتاج ، وكما هو معتاد ، يجب إصلاحه بشكل عاجل. ومع ذلك ، ليس من الواضح كم من الوقت سيستغرق لدراسته وإجراء الإصلاح الصحيح ، لذلك تم إجراء إصلاح عاجل مؤقت بسرعة ، مما عزل التفاعل مع الوحدة النمطية للمشكلة. لذلك ، في الفرع الرئيسي ، يظهر الالتزام باستخدام هذا التصحيح المؤقت ، وبعد مرور بعض الوقت بدلاً من ذلك بشكل رئيسي ، تحتاج إلى إيقاف إصلاح عاجل كامل بالفعل.
وبالتالي ، نحن بحاجة إلى دمج دمج فرع ألفا في الرئيسي ، ولكن لا ينبغي أن يكون هذا دمجًا تقليديًا عندما تتم إضافة جميع التغييرات الفريدة من فرع ألفا إلى المعلم من أعلى ويكون هناك تعارض ، ويجب علينا استبدال المعلم بالكامل بفرع ألفا.
بادئ ذي بدء ، دعنا نتذكر ما يدور حوله أمر الدمج - إنه في الواقع نفس الالتزام العادي ، لكن لديه فقط إثنين من الوالدين ، يكون هذا مرئيًا بوضوح إذا نظرت إلى محتوياته (كيف تتشكل شجرة الشجرة مشكلة منفصلة) . ومن الذي يحدده من هو بسيط - يعتبر الوالد الأول الالتزام الرئيسي.
git cat-file -p 7229df8
tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a parent fd54ab7dde87593b9892b6d1ffbf1afd39ba6f9e parent 280c30ff81a574f8dd41721726cf60b22fb2eced author Baur <atanov...@gmail.com> 1540619579 +0600 committer Baur <atanov...@gmail.com> 1540619592 +0600 Merge branch 'beta' into 'master'
إعادة تعيين فرع ألفا الحالي والتبديل إلى الرئيسي
git reset --hard origin/alpha git checkout master
والآن نفس الفريق ، ولكن مع اثنين من الوالدين يلتزم
git merge --ff $(git commit-tree alpha^{tree} -m "Merge 'alpha' into 'master', but take 'alpha' tree" -p HEAD -p alpha)
انتهى الأمر ، لقد نظمنا فرع ألفا في الرئيسي ، ولم يكن علينا حذف الشفرة المؤقتة وحل التعارضات ، لأنه في هذه الحالة كان علينا فقط إعادة كتابة آخر التغييرات.

في الواقع ، ليس غريباً إنشاء دمج مع شجرة يتم نسخه من التزام آخر. يمكن أن تنشأ مثل هذه المواقف لأن git هي أداة مرنة للغاية تتيح لك تنفيذ مجموعة متنوعة من الأساليب للتعامل مع الفروع والمستودعات. ومع ذلك ، فإن المثال الأكثر شيوعًا كان في مستودعنا منذ البداية - حاول تحليله بنفسك أو افتح المفسد لقراءة التفسير.
المفسددعنا ننتبه إلى كيفية خنق فرع بيتا لإتقانه. خلال الوقت الذي ظهر فيه التزامان ، لم تكن هناك تعهدات جديدة في الفرع الرئيسي نفسه. هذا يعني أنه مع دمج النسخة التجريبية في برنامج الماجستير ، يتم استبعاد أي تعارض بسبب التغييرات المتزامنة.


إذا فعلنا git merge beta ، فسيحدث دمج سريع للأمام (السلوك الافتراضي ) ، أي أن الفرع الرئيسي سيكون على نفس الالتزام مثل فرع beta ، ولن يكون هناك التزام دمج. سيكون مثل هذا:

ولكن هنا لم يتم إجراء دمج سريع للأمام باستخدام الأمر git merge beta --no-ff. وهذا هو ، أجبرنا على إنشاء التزام دمج ، على الرغم من أنه لم يكن ضروريا. وحيث أن الحالة النهائية المطلوبة للمشروع في المستقبل كانت معروفة ، فهذه شجرة تجريبية ، نسخت ببساطة الرابط إلى هذه الشجرة إلى التزام جديد:
git cat-file -p origin/beta
tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent 560b449675513bc8f8f4d6cda56a922d4e36917a author Baur <atanov...@gmail.com> 1540619512 +0600 committer Baur <atanov...@gmail.com> 1540619512 +0600 Added info about windows
git cat-file -p 7229df8
tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent fd54ab7dde87593b9892b6d1ffbf1afd39ba6f9e parent 280c30ff81a574f8dd41721726cf60b22fb2eced author Baur <atanov...@gmail.com> 1540619579 +0600 committer Baur <atanov...@gmail.com> 1540619592 +0600 Merge branch 'beta' into 'master'
6 أ. Rebase طريقة عبر دمج - الوصف
التحدي:
من الضروري إنشاء فرع rebase "ثقيل" (العديد من التعارضات على عمليات مختلفة).
هناك مثل هذا holivar الكلاسيكية في بوابة - rebase مقابل دمج. لكنني لن holivarit. على العكس من ذلك ، سأتحدث عن كيفية تكوين صداقات في سياق هذه المهمة.
بشكل عام ، لقد تم تصميم git خصيصًا حتى نتمكن من القيام بالدمج بشكل فعال. وعندما جئت إلى المشروع حيث يعتمد سير العمل على rebase ، كانت المرة الأولى التي كنت فيها غير مريح وغير عادي ، حتى قمت بتطوير التقنيات التي سهّلت عملي اليومي مع بوابة. واحد منهم هو طريقتي الأصلية للقيام rebase الثقيلة.
لذلك ، نحن بحاجة إلى إعادة إنشاء فرع alpha عند التطوير ، بحيث يتم تلوينه لاحقًا بشكل جميل مثل فرع beta. إذا بدأنا rebase كالمعتاد ، سينتج عن الالتزام الأول والأخير تعارضين مختلفين في مكانين مختلفين. ولكن إذا قمنا بدمج ، بدلاً من rebase ، سيكون هناك تعارض واحد فقط في مكان واحد في التزام دمج واحد.
إذا كنت تريد التأكد من هذا ، فأنا أقدم فرقًا جاهزة تحت المفسد.
النص المخفيعودة الفروع إلى حالتها الأصلية
git checkout master git reset --hard origin/master git checkout alpha git reset --hard origin/alpha
إنشاء والوقوف على فرع ألفا rebase- الصراعات وإعادة rebase على ماجستير
git checkout -b alpha-rebase-conflicts git rebase master
سيكون هناك صراعات في ارتكاب مختلف ، بما في ذلك صراع الوهمية.
الآن دعونا نجرب الدمج ، ونعود إلى فرع ألفا وحذف الفرع من أجل rebase.
git checkout alpha git branch -D alpha-rebase-conflicts
التبديل إلى إتقان وجعل الدمج
git checkout master git merge alpha
لن يكون هناك سوى صراع واحد بسيط ، ونحن تصحيحه والقيام به
git add Bill.txt git commit -m "Merge branch 'alpha' into 'master'"
مارج الانتهاء بنجاح.
تعد الصراعات التي تحدث في بوابة غزة جزءًا طبيعيًا من حياتنا ، ويوضح هذا المثال البسيط أن الاندماج هو بالتأكيد أكثر ملاءمة من rebase في هذا الصدد. في مشروع حقيقي ، يتم قياس هذا الاختلاف بمقدار أكبر بكثير من الوقت والأعصاب التي تقضيها. لذلك ، على سبيل المثال ، هناك توصية غامضة لسحق كافة الالتزامات الخاصة بفرع الميزة في التزام واحد قبل الدمج.
فكرة هذه الطريقة هي جعل دمج مؤقت خفي سنحل فيه جميع النزاعات في وقت واحد. تذكر النتيجة (الشجرة). بعد ذلك ، قم بتشغيل rebase المعتاد ، ولكن باستخدام الخيار "حل النزاعات تلقائيًا ، واختيار تغييراتنا". وفي النهاية ، أضف التزامًا إضافيًا إلى الفرع ، والذي سيعيد الشجرة الصحيحة.
لنبدأ. مرة أخرى ، أعد كلا الفرعين إلى حالتهما الأصلية.
git checkout master git reset --hard origin/master git checkout alpha git reset --hard origin/alpha
دعونا إنشاء مؤقت فرع مؤقت الذي سنقوم دمج.
git checkout -b temp git merge origin/master
الصراع.
دعنا نحل تعارضًا بسيطًا واحدًا في ملف Bill.txt كالمعتاد (في أي محرر).
لاحظ أن هناك تعارضًا واحدًا فقط وليس تعارضًا ، كما هو الحال مع rebase.
git add Bill.txt git commit -m "Merge branch 'origin/master' into 'temp'"
نعود إلى فرع ألفا وننفذ حلاً مع الدقة التلقائية لجميع النزاعات لصالحنا ، ونعيد فرع درجة الحرارة إلى الحالة ، ونحذف فرع temp نفسه.
git checkout alpha git rebase origin/master -X theirs git merge --ff $(git commit-tree temp^{tree} -m "Fix after rebase" -p HEAD) git branch -D temp

وأخيرا ، جميل mergim ألفا في الماجستير.
git checkout master git merge alpha --no-ff --no-edit

لاحظ أن الفرع الرئيسي و alpha و temp البعيد يشير كلهم إلى نفس الشجرة ، على الرغم من أنها ثلاث عمليات مختلفة.
سلبيات هذه الطريقة:
- لا يوجد تصحيح يدوي لكل التزام صراع - يتم حل النزاعات تلقائيًا. قد لا يتم تجميع مثل هذا الالتزام الوسيط.
- تمت إضافة (ولكن ليس دائمًا) التزامًا إضافيًا على كل عملية إعادة تحويل
الايجابيات:
- نحن فقط إصلاح الصراعات الحقيقية (لا الصراعات الوهمية)
- يتم إصلاح جميع الصراعات مرة واحدة فقط.
- أول نقطتين توفير الوقت
- يتم حفظ محفوظات كاملة من الالتزامات وجميع التغييرات (على سبيل المثال ، يمكنك اختيار الكرز)
- يتم تنفيذ هذه الطريقة كبرنامج نصي ويمكن استخدامها دائمًا إذا لزم الأمر لإعادة تشغيلها (لا تتطلب أي معرفة بالأشجار وما إلى ذلك)
6 ب. Rebase طريقة عبر دمج - النصي
يتم نشر البرنامج النصي هنا: https://github.com/capslocky/git-rebase-via-merge
دعونا التحقق من عملها على مثالنا. مرة أخرى ، أعد كلا الفرعين إلى حالتهما الأصلية
git checkout master git reset --hard origin/master git checkout alpha git reset --hard origin/alpha
قم بتنزيل البرنامج النصي وجعله قابلاً للتنفيذ
curl -L https://git.io/rebase-via-merge -o ~/git-rebase-via-merge.sh chmod +x ~/git-rebase-via-merge.sh
النوافذسيظهر الملف هنا: C: \ Users \ user-name \ git-rebase-via-merge.sh
قم بتغيير الفرع الافتراضي الذي تحتاج إلى إعادة تشغيله ، وفي حالتنا نحتاج إلى الأصل / الرئيسي
nano ~/git-rebase-via-merge.sh
default_base_branch='origin/master'
لنقم أيضًا بإنشاء فرع مؤقت والوقوف فيه حتى لا نلمس فرع ألفا نفسه
git checkout -b alpha-rebase-test
والآن يمكنك تشغيل البرنامج النصي (بدلاً من الأصل / الرئيسي rebase git)
~/git-rebase-via-merge.sh

نتيجة البرنامج النصي $ ~/git-rebase-via-merge.sh This script will perform rebase via merge. Current branch: alpha-rebase-test (64fafc7) Base branch: origin/master (9c6b60a) Continue (c) / Abort (a) c Auto-merging Bill.txt CONFLICT (content): Merge conflict in Bill.txt Automatic merge failed; fix conflicts and then commit the result. You have at least one merge conflict. Fix all conflicts in the following files, stage them up and type 'c': Bill.txt Continue (c) / Abort (a) c [detached HEAD 785d49e] Hidden temp commit to save result of merging 'origin/master' into 'alpha-rebase-test' as detached head. Merge succeeded on hidden commit: 785d49e Starting rebase automatically resolving any conflicts in favor of current branch. First, rewinding head to replay your work on top of it... Auto-merging Bill.txt [detached HEAD a680316] Added history of windows Author: Baur <atanov...@gmail.com> Date: Sat Oct 27 11:45:50 2018 +0600 1 file changed, 6 insertions(+), 3 deletions(-) Committed: 0001 Added history of windows Auto-merging Bill.txt [detached HEAD dcd34a8] Replaced history of windows Author: Baur <atanov...@gmail.com> Date: Sat Oct 27 11:55:42 2018 +0600 1 file changed, 4 insertions(+), 5 deletions(-) Committed: 0002 Replaced history of windows Auto-merging Bill.txt [detached HEAD 8d6d82c] Added file about Azure and info about Windows 10 Author: Baur <atanov...@gmail.com> Date: Sat Oct 27 12:06:27 2018 +0600 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 Azure.txt Committed: 0003 Added file about Azure and info about Windows 10 All done. Restoring project state from hidden merge with single additional commit. Updating 8d6d82c..268b320 Fast-forward Bill.txt | 4 ++++ 1 file changed, 4 insertions(+) Done.
~/git-rebase-via-merge.sh origin/develop
, ours / theirs :
ours — (HEAD)
theirs — (, origin/develop)
rebase — .
7.
git .
.
git config alias.copy '!git merge --ff $(git commit-tree ${1}^{tree} -p HEAD -m "Tree copy from ${1}")'
git copy xxx, xxx — .
git copy xxx
git merge --ff $(git commit-tree xxx^{tree} -p HEAD -m "Tree copy from xxx")
git copy a8fc5e3
git copy origin/beta
git copy HEAD~3
git amend.
git commit --amend -m "Just for test"
:
git commit --amend
, , . , . — . , , . . " " " " . ( , devops), , .