سؤال

هذا السؤال لديه بالفعل إجابة هنا:

مع git rebase --interactive <commit> يمكنك الاسكواش أي عدد من الالتزام معا في واحد واحد.

هذا كل شيء رائع إلا إذا كنت ترغب في الالكحق بالركز في الالتزام الأولي. هذا يبدو من المستحيل القيام به.

هل هناك أي طرق لتحقيق ذلك؟


ذات صلة بشكل معتدل:

في سؤال ذي صلة، تمكنت من التوصل إلى نهج مختلف للحاجة إلى الاسكواش ضد الالتزام الأول، وهو، حسنا، لجعلها الثانية.

إذا كنت مهتما: git: كيفية إدراج الالتزام كأول، تحول جميع الآخرين؟

هل كانت مفيدة؟

المحلول

تحديث يوليو 2012 (git 1.7.12+)

يمكنك الآن Rebase جميع يرتكب حتى الجذر، وحدد الالتزام الثاني Y ليتم سحقها مع الأول X.

git rebase -i --root master

pick sha1 X
squash sha1 Y
pick sha1 Z
git rebase [-i] --root $tip

يمكن الآن استخدام هذا الأمر لإعادة كتابة جميع المحفوظات المؤدية من "$tip"وصولا إلى جذر الالتزام.

يرى ارتكاب DF5DF20C1308F936EA542C86DF1E9C6974168472 على جيثب من كريس ويب (arachsys).


الإجابة الأصلية (فبراير 2009)

أعتقد أنك ستجد وصفات مختلفة لذلك في السؤال حتى "كيف يمكنني الجمع بين الأولين الأولين من مستودع جيت؟"

تشارلز بيلي قدمت هناك أكثر إجابة مفصلة, ، تذكيرنا بأن الالتزام عبارة عن شجرة كاملة (لا تنفذ فقط عن الدول السابقة).
وهنا الالتزام القديم ("الالتزام الأولي") والالتزام الجديد (نتيجة الاسكواش) لن يكون له سلف مشترك.
هذا يعني أنك لا تستطيع "commit --amend"الالتزام الأولي إلى واحد جديد، ثم Rebase على الالتزام الأولي الجديد بتاريخ الالتزام الأولي السابق (الكثير من النزاعات)

(أن الجملة الأخيرة لم تعد صحيحة git rebase -i --root <aBranch>)

بدلا من ذلك (مع A الأصلي "الالتزام الأولي"، و B يلزم الالتزام اللاحق بالاسكناء في الأول الأولي):

  1. العودة إلى آخر الالتزام الذي نريد تشكيل الالتزام الأولي (رأس فصل):

    git checkout <sha1_for_B>
    
  2. إعادة تعيين مؤشر الفرع إلى الالتزام الأولي، ولكن ترك الفهرس وشجرة العمل سليمة:

    git reset --soft <sha1_for_A>
    
  3. تعديل الشجرة الأولية باستخدام الشجرة من "B":

    git commit --amend
    
  4. علامة مؤقتا هذا الالتزام الأولي الجديد (أو يمكنك أن تتذكر الالتزام الجديد SHA1 يدويا):

    git tag tmp
    
  5. العودة إلى الفرع الأصلي (افترض سيد لهذا المثال):

    git checkout master
    
  6. إعادة تشغيل جميع الالتزام بعد ب على الالتزام الأولي الجديد:

    git rebase --onto tmp <sha1_for_B>
    
  7. إزالة العلامة المؤقتة:

    git tag -d tmp
    

بهذه الطريقة، "rebase --onto"لا يعرض صراعات أثناء الدمج، لأنه يربي التاريخ صنع بعد ذلك الالتزام الأخير (B) ليتم سحقها في الأولي (الذي كان A) ل tmp (تمثل الالتزام الأولي الجديد بالاستحمام): دمج تافهة سريعة إلى الأمام فقط.

التي تعمل من أجل "A-B"، ولكن أيضا "A-...-...-...-B"(يمكن سحق أي عدد من الالتزام في تلك الطريقة الأولى بهذه الطريقة)

نصائح أخرى

لقد أعادت إعادة صياغة البرنامج النصي Vonc للقيام بكل شيء تلقائيا وليس يسألني عن أي شيء. أنت تعطيها اثنين من ارتكاب Sha1s وسوف يسحق كل شيء بينهما في ارتكاب واحد يسمى "تاريخ سحق":

#!/bin/sh
# Go back to the last commit that we want
# to form the initial commit (detach HEAD)
git checkout $2

# reset the branch pointer to the initial commit (= $1),
# but leaving the index and working tree intact.
git reset --soft $1

# amend the initial tree using the tree from $2
git commit --amend -m "squashed history"

# remember the new commit sha1
TARGET=`git rev-list HEAD --max-count=1`

# go back to the original branch (assume master for this example)
git checkout master

# Replay all the commits after $2 onto the new initial commit
git rebase --onto $TARGET $2

ما يستحقه، أتجنب هذه المشكلة عن طريق إنشاء "No-Op" دائما دائما، حيث يكون الشيء الوحيد في المستودع فارغا. gitignore:

https://github.com/darwinawardwinner/git-custom-commands/blob/master/bin/git-myinit.

بهذه الطريقة، لا يوجد أي سبب للعيان مع الالتزام الأول.

إذا كنت ترغب ببساطة في الاسكواش جميع ارتكابها في الالتزام الأولي واحد، فقم بإعادة تعيين المستودع وتعديل الالتزام الأول:

git reset hash-of-first-commit
git add -A
git commit --amend

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

هذا سوف يسحق الثانية الالتزام في أول واحد:

A-B-C-... -> AB-C-...

git filter-branch --commit-filter '
    if [ "$GIT_COMMIT" = <sha1ofA> ];
    then
        skip_commit "$@";
    else
        git commit-tree "$@";
    fi
' HEAD

سيتم أخذ رسالة ارتكاب AB من B (على الرغم من أنني أفضل من أ).

له نفس التأثير مثل إجابة Uwe Kleine-König، ولكن يعمل لغير الأولي أيضا.

سيؤدي سحق الالتزام الأول والثاني إلى إعادة كتابة الالتزام الأول. إذا كان لديك أكثر من فرع واحد يعتمد على الالتزام الأول، فستقطع هذا الفرع.

النظر في المثال التالي:

a---b---HEAD
 \
  \
   '---d

سحق A و B في الالتزام الجديد "AB" أن يؤدي إلى أشجار اثنين متميزة والتي في معظم الحالات غير مرغوبة منذ ذلك الحين جيت دمج و git rebase. لن تعمل في جميع أنحاء الفرعين.

ab---HEAD

a---d

إذا كنت تريد حقا هذا، فيمكن القيام بذلك. القي نظرة على فرع GIT-Filter للحصول على أداة قوية (وخطيرة) لإعادة كتابة التاريخ.

يمكنك استخدام فرع المرشح GIT لذلك. على سبيل المثال

git filter-branch --parent-filter \
'if test $GIT_COMMIT != <sha1ofB>; then cat; fi'

ينتج عن هذا AB-C رمي سجل ارتكاب A.

يمكنك استخدام Rebase Interactivity لتعديل الاختلاف الأخيرين قبل أن يتم دفعها إلى جهاز التحكم عن بعد

git rebase HEAD^^ -i

هناك طريقة أسهل للقيام بذلك. دعونا نفترض أنك على master فرع شجرة

قم بإنشاء فرع جديد الأيتام الذي سيزيل كل سجل الالتزام:

$ git checkout --orphan new_branch

أضف رسالة الالتزام الأولية:

$ git commit -a

تخلص من فرع السيد غير المكتسب القديم:

$ git branch -D master

إعادة تسمية فرعك الحالي new_branch ل master:

$ git branch -m master
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top