سؤال

لدي مستودع جيت في مجلد يسمى XXX., ، ولدي مستودع جيت الثاني يسمى yyy..

أريد استيراد XXX. مستودع في yyy. مستودع كدليل فرعي يدعى زز ويضاف جميع XXX.تغيير التاريخ إلى yyy..

هيكل المجلد قبل:

XXX
 |- .git
 |- (project files)
YYY
 |- .git
 |- (project files)

هيكل المجلد بعد:

YYY
 |- .git  <-- This now contains the change history from XXX
 |-  ZZZ  <-- This was originally XXX
      |- (project files)
 |-  (project files)

هل يمكن القيام بذلك، أو يجب أن ألجأ لاستخدام الوحدات الفرعية؟

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

المحلول

ربما أبسط طريقة ستكون لسحب XXX. الاشياء في فرع في yyy. ثم دمجها في ماجستير:

في yyy.:

git remote add other /path/to/XXX
git fetch other
git checkout -b ZZZ other/master
mkdir ZZZ
git mv stuff ZZZ/stuff                      # repeat as necessary for each file/dir
git commit -m "Moved stuff to ZZZ"
git checkout master                
git merge ZZZ --allow-unrelated-histories   # should add ZZZ/ to master
git commit
git remote rm other
git branch -d ZZZ                           # to get rid of the extra branch before pushing
git push                                    # if you have a remote, that is

أنا فعلا حاولت هذا فقط مع اثنين من ريبوس ويعمل. على عكس إجابة Jörg لن يسمح لك بالاستمرار في استخدام الريبو الآخر، لكنني لا أعتقد أنك حددت على أي حال.

ملاحظة: نظرا لأن هذا كان مكتوبا في الأصل في عام 2009، فقد أضاف GIT دمج الفرعية المذكورة في الإجابة أدناه. ربما أستخدم هذه الطريقة اليوم، على الرغم من أن هذه الطريقة لا تزال تعمل.

نصائح أخرى

إذا كنت ترغب في الاحتفاظ بالتاريخ الالتزام بالضبط في مستودع المستودع الثاني، وبالتالي تحتفظ بالقدرة على دمج التغييرات المنبع بسهولة في المستقبل، فهي الطريقة التي تريدها. ينتج عنه تاريخ غير محدد من الشجرة الفرعية التي يتم استيرادها في ريبو بالإضافة إلى دمج واحد يلتزم بنقل المستودع المدمج إلى الدليل الفرعي.

git remote add XXX_remote <path-or-url-to-XXX-repo>
git fetch XXX_remote
git merge -s ours --no-commit --allow-unrelated-histories XXX_remote/master
git read-tree --prefix=ZZZ/ -u XXX_remote/master
git commit -m "Imported XXX as a subtree."

يمكنك تتبع التغييرات المنبع مثل ذلك:

git pull -s subtree XXX_remote master

أرقام GIT من تلقاء نفسها حيث تكون الجذور قبل القيام بالدمج، لذلك لا تحتاج إلى تحديد البادئة حول الدمج اللاحق.

إصدارات git قبل 2.9: لا تحتاج إلى تمرير --allow-unrelated-histories الخيار ل git merge.

الطريقة في الإجابة الأخرى التي تستخدم read-tree ويتخطى merge -s ours لا يختلف الخطوة بشكل فعال عن نسخ الملفات مع CP وارتكاب النتيجة.

المصدر الأصلي كان من GitHub's "دمج السكر" مساعدة المادة.

git-subtree هو برنامج نصي مصمم لهذه الحالة بالضبط حالة دمج مستودعات متعددة في واحد أثناء الحفاظ على السجل (و / أو تقسيم تاريخ السكتوماتي، على الرغم من أنه يبدو أنه غير ذي صلة بهذا السؤال). يتم توزيعها كجزء من شجرة الجيت منذ الإصدار 1.7.11..

لدمج مستودع <repo> في المراجعة <rev> كدليل فرعي <prefix>, ، استعمال git subtree add كالآتي:

git subtree add -P <prefix> <repo> <rev>

git-subtree ينفذ استراتيجية دمج الفرعية بطريقة أكثر سهولة الاستخدام.

لحالتك، داخل مستودع YYY، سوف تعمل:

git subtree add -P ZZZ /path/to/XXX.git master

هناك مثيل مشهور لهذا في مستودع GIT نفسه، والذي يعرف بشكل جماعي في مجتمع GIT باسم "أروع دمج على الإطلاق"(بعد سطر الموضوع Linus Torvalds المستخدمة في البريد الإلكتروني إلى القائمة البريدية GIT التي تصف هذه الدمج). في هذه الحالة، gitk GIT واجهة المستخدم الرسومية التي هي الآن جزء من GIT مناسبة، تستخدم بالفعل مشروع منفصل. تمكن Linus من دمج المستودع في مستودع GIT بطريقة

  • يظهر في مستودع GIT كما لو كان قد تم تطويره دائما كجزء من GIT،
  • يتم الاحتفاظ بجميع التاريخ سليمة و
  • لا يزال بإمكانه تطويره بشكل مستقل في مستودعه القديم، مع التغييرات ببساطة git pullإد.

يحتوي البريد الإلكتروني على الخطوات اللازمة لإعادة التكاثر، لكنها ليست لضعف القلب: أولا، لينوس كتب بوابة، لذلك ربما يعرف أكثر قليلا عن ذلك منك أو لي، والثانية، وكان هذا منذ حوالي 5 سنوات وقد تحسن جيت إلى حد كبير منذ ذلك الحين، لذلك ربما يكون الآن أسهل بكثير.

على وجه الخصوص، أعتقد أن المرء في الوقت الحاضر سيستخدم تنويق Gitk، في هذه الحالة المحددة.

الطريقة البسيطة للقيام بذلك هي استخدام تنسيق GIT-Patch.

افترض أن لدينا 2 مستودعات جيت فور و شريط.

فور يحتوي على:

  • foo.txt.
  • .شخص سخيف

شريط يحتوي على:

  • bar.txt.
  • .شخص سخيف

ونحن نريد أن ينتهي فور تحتوي على شريط التاريخ وهذه الملفات:

  • foo.txt.
  • .شخص سخيف
  • foobar / bar.txt.

لذلك للقيام بذلك:

 1. create a temporary directory eg PATH_YOU_WANT/patch-bar
 2. go in bar directory
 3. git format-patch --root HEAD --no-stat -o PATH_YOU_WANT/patch-bar --src-prefix=a/foobar/ --dst-prefix=b/foobar/
 4. go in foo directory
 5. git am PATH_YOU_WANT/patch-bar/*

وإذا كنا نريد إعادة كتابة جميع الرسائل يرتكب من شريط يمكننا القيام به، على سبيل المثال في Linux:

git filter-branch --msg-filter 'sed "1s/^/\[bar\] /"' COMMIT_SHA1_OF_THE_PARENT_OF_THE_FIRST_BAR_COMMIT..HEAD

سيؤدي ذلك إلى إضافة [بار] في بداية كل رسالة ارتكاب.

على أساس على هذه المادة, ، باستخدام Subtree هو ما كان يعمل بالنسبة لي ونقل التاريخ القابل للتطبيق فقط. النشر هنا في حالة يحتاج أي شخص إلى الخطوات (تأكد من استبدال العناصر النائبة بالقيم المطبقة عليك):

في مستودع المستودع الخاص بك تقسيم المجلد الفرعي في فرع جديد

git subtree split --prefix=<source-path-to-merge> -b subtree-split-result

في وظيفتك repo دمج في فرع النتيجة المنقسمة

git remote add merge-source-repo <path-to-your-source-repository>
git fetch merge-source-repo
git merge -s ours --no-commit merge-source-repo/subtree-split-result
git read-tree --prefix=<destination-path-to-merge-into> -u merge-source-repo/subtree-split-result

تحقق من التغييرات والالتزام

git status
git commit

لا تنسى

تنظيف عن طريق حذف subtree-split-result فرع شجرة

git branch -D subtree-split-result

قم بإزالة جهاز التحكم عن بعد الذي أضفته لجلب البيانات من المصدر Repo

git remote rm merge-source-repo

ستكون هذه الوظيفة استنساخ Repo Repo في Dir Repo المحلي، بعد دمج جميع الالتزام سيتم حفظها، git log سوف تظهر ارتكابها الأصلي والمسارات المناسبة:

function git-add-repo
{
    repo="$1"
    dir="$(echo "$2" | sed 's/\/$//')"
    path="$(pwd)"

    tmp="$(mktemp -d)"
    remote="$(echo "$tmp" | sed 's/\///g'| sed 's/\./_/g')"

    git clone "$repo" "$tmp"
    cd "$tmp"

    git filter-branch --index-filter '
        git ls-files -s |
        sed "s,\t,&'"$dir"'/," |
        GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
        mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
    ' HEAD

    cd "$path"
    git remote add -f "$remote" "file://$tmp/.git"
    git pull "$remote/master"
    git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master"
    git remote remove "$remote"
    rm -rf "$tmp"
}

كيف تستعمل:

cd current/package
git-add-repo https://github.com/example/example dir/to/save

إذا كان إجراء تغييرات صغيرة، فيمكنك نقل الملفات / المؤسسات المدمجة Repo إلى مسارات مختلفة، على سبيل المثال:

repo="https://github.com/example/example"
path="$(pwd)"

tmp="$(mktemp -d)"
remote="$(echo "$tmp" | sed 's/\///g' | sed 's/\./_/g')"

git clone "$repo" "$tmp"
cd "$tmp"

GIT_ADD_STORED=""

function git-mv-store
{
    from="$(echo "$1" | sed 's/\./\\./')"
    to="$(echo "$2" | sed 's/\./\\./')"

    GIT_ADD_STORED+='s,\t'"$from"',\t'"$to"',;'
}

# NOTICE! This paths used for example! Use yours instead!
git-mv-store 'public/index.php' 'public/admin.php'
git-mv-store 'public/data' 'public/x/_data'
git-mv-store 'public/.htaccess' '.htaccess'
git-mv-store 'core/config' 'config/config'
git-mv-store 'core/defines.php' 'defines/defines.php'
git-mv-store 'README.md' 'doc/README.md'
git-mv-store '.gitignore' 'unneeded/.gitignore'

git filter-branch --index-filter '
    git ls-files -s |
    sed "'"$GIT_ADD_STORED"'" |
    GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
    mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
' HEAD

GIT_ADD_STORED=""

cd "$path"
git remote add -f "$remote" "file://$tmp/.git"
git pull "$remote/master"
git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master"
git remote remove "$remote"
rm -rf "$tmp"

إشعارات
المسارات تحل محلها عبر sed, ، لذلك تأكد من نقلها في المسارات المناسبة بعد الدمج.
ال --allow-unrelated-histories المعلمة موجودة فقط منذ git> = 2.9.

إضافة إجابة أخرى كما أعتقد أن هذا أبسط قليلا. يتم سحب repo_dest في repo_to_import ثم url repstream repstream: repo_dest قد تم القيام به.

عملت هذه الطريقة بالنسبة لي استيراد العديد من repos أصغر إلى واحدة أكبر.

كيفية استيراد: repo1_to_import إلى Repo_dest

# checkout your repo1_to_import if you don't have it already 
git clone url:repo1_to_import repo1_to_import
cd repo1_to_import

# now. pull all of repo_dest
git pull url:repo_dest
ls 
git status # shows Your branch is ahead of 'origin/master' by xx commits.
# now push to repo_dest
git push --set-upstream url:repo_dest master

# repeat for other repositories you want to import

إعادة تسمية أو نقل الملفات والأغوال إلى الموضع المطلوب في Repo الأصلي قبل أن تقوم بالاستيراد. على سبيل المثال

cd repo1_to_import
mkdir topDir
git add topDir
git mv this that and the other topDir/
git commit -m"move things into topDir in preparation for exporting into new repo"
# now do the pull and push to import

الطريقة الموضحة في الرابط التالي ألهمت هذه الإجابة. أحببت ذلك كما بدا أكثر بساطة. ولكن حذار! أن يكون هناك التنين! https://help.github.com/articles/importing-an-external-git-repository. git push --mirror url:repo_dest يدفع تاريخ الريبو المحلي وحالتك إلى جهاز التحكم عن بعد (URL: Repo_dest). لكنه يحذف التاريخ القديم وحالة جهاز التحكم عن بعد. تحب المرح! :

أردت استيراد بعض الملفات فقط من المستودع الآخر (XXX) في حالتي. كانت الفرعية معقدة للغاية بالنسبة لي ولن تعمل الحلول الأخرى. وهذا هو ما فعلته:

ALL_COMMITS=$(git log --reverse --pretty=format:%H -- ZZZ | tr '\n' ' ')

يمنحك هذا قائمة منفصلة فضائية بجميع الالتزام الذي يؤثر على الملفات التي أردت استيرادها (ZZZ) بترتيب عكسي (قد تضطر إلى إضافة - متابعة لالتقاط إعادة تسمية كذلك). ثم ذهبت إلى المستودع المستهدف (YYY)، وأضاف المستودع الآخر (XXX) باعتباره عن بعد، فعل جلب منه وأخيرا:

git cherry-pick $ALL_COMMITS

مما يضيف كل الالتزام إلى فرعك، وبالتالي سيكون لديك جميع الملفات مع تاريخهم ويمكن أن تفعل ما تريد معهم كما لو كانوا دائما في هذا المستودع.

كنت في موقف كنت أبحث عنه -s theirs ولكن بالطبع، هذه الاستراتيجية غير موجودة. كان تاريخي أنني قد شوني مشروعا على جيثب، والآن لسبب ما، محلي master لا يمكن دمجها upstream/master على الرغم من أنني لم أجد تغييرات محلية لهذا الفرع. (حقا لا أعرف ماذا حدث هناك - أعتقد أن المنبع قد فعلت بعض يدفع القذرة وراء الكواليس، ربما؟)

ما انتهى به الأمر كان

# as per https://help.github.com/articles/syncing-a-fork/
git fetch upstream
git checkout master
git merge upstream/master
....
# Lots of conflicts, ended up just abandonging this approach
git reset --hard   # Ditch failed merge
git checkout upstream/master
# Now in detached state
git branch -d master # !
git checkout -b master   # create new master from upstream/master

حتى الآن بلدي master مرة أخرى في المزامنة مع upstream/master (ويمكنك تكرار ما ورد أعلاه لأي فرع آخر تريد مزامنة منه أيضا بالمثل).

يرى مثال أساسي في هذه المقالة والنظر في مثل هذا التعيين على المستودعات:

  • A <-> YYY,
  • B <-> XXX

بعد كل النشاط الموصوف في هذا الفصل (بعد الدمج)، قم بإزالة الفرع B-master:

$ git branch -d B-master

ثم، دفع التغييرات.

انه يعمل بالنسبة لي.

أستطيع أن أقترح حلا آخر (بديل git-suitodules.) لمشكلتك - جيل (git links) أداة

يسمح لوصف وإدارة التبعيات المستودعات GIT المعقدة.

كما أنه يوفر حلا لل بوابة تكريس تكريس مشكلة التبعية.

ضع في اعتبارك أن لديك تبعيات المشروع التالية:نموذج الرسم البياني التبعية

ثم يمكنك تحديد .gitlinks ملف مع مستودعات الوصف الوصف:

# Projects
CppBenchmark CppBenchmark https://github.com/chronoxor/CppBenchmark.git master
CppCommon CppCommon https://github.com/chronoxor/CppCommon.git master
CppLogging CppLogging https://github.com/chronoxor/CppLogging.git master

# Modules
Catch2 modules/Catch2 https://github.com/catchorg/Catch2.git master
cpp-optparse modules/cpp-optparse https://github.com/weisslj/cpp-optparse.git master
fmt modules/fmt https://github.com/fmtlib/fmt.git master
HdrHistogram modules/HdrHistogram https://github.com/HdrHistogram/HdrHistogram_c.git master
zlib modules/zlib https://github.com/madler/zlib.git master

# Scripts
build scripts/build https://github.com/chronoxor/CppBuildScripts.git master
cmake scripts/cmake https://github.com/chronoxor/CppCMakeScripts.git master

يصف كل سطر ارتباط GIT بالتنسيق التالي:

  1. اسم فريد من المستودع
  2. المسار النسبي للمستودع (بدأ من طريق ملف .gitlinks)
  3. مستودع GIT الذي سيتم استخدامه في فرع مستودع الأوامر GIT استنساخ عند المغادرة
  4. خط فارغ أو خط بدأ مع # غير محور (تعامل مع التعليق).

أخيرا، يجب عليك تحديث مستودع عينة الجذر الخاص بك:

# Clone and link all git links dependencies from .gitlinks file
gil clone
gil link

# The same result with a single command
gil update

نظرا لأن النتيجة ستستنسف جميع المشاريع المطلوبة وربطها ببعضها البعض بطريقة مناسبة.

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

gil commit -a -m "Some big update"

سحب، يدفع أوامر تعمل بطريقة مماثلة:

gil pull
gil push

تدعم أداة GIL (GIT Links) الأوامر التالية:

usage: gil command arguments
Supported commands:
    help - show this help
    context - command will show the current git link context of the current directory
    clone - clone all repositories that are missed in the current context
    link - link all repositories that are missed in the current context
    update - clone and link in a single operation
    pull - pull all repositories in the current directory
    push - push all repositories in the current directory
    commit - commit all repositories in the current directory

المزيد عن بوابة تكريس تكريس مشكلة التبعية.

أنا لا أعرف وسيلة سهلة للقيام بذلك. يمكنك القيام بذلك:

  1. استخدم GIT Filter-Branch لإضافة دليل ZZZ Super-Directory على مستودع XXX
  2. دفع الفرع الجديد إلى مستودع يوي
  3. دمج الفرع المدفوع مع جذع yyy.

يمكنني تعديل التفاصيل إذا كان هذا يبدو جذابا.

أعتقد أنه يمكنك القيام بذلك باستخدام "Git MV" و "GIT STUT".

أنا مستجد جيت عادل - لذا كن حذرا مع مستودعك الرئيسي - لكنني جربت هذا فقط في DIR DIR ويبدو أن العمل.

أولا - إعادة تسمية بنية XXX لتتناسب مع ما تريده أن ننظر عندما يكون داخل YYY:

cd XXX
mkdir tmp
git mv ZZZ tmp/ZZZ
git mv tmp ZZZ

الآن XXX تبدو وكأنها هذه:

XXX
 |- ZZZ
     |- ZZZ

الآن استخدم "GIT سحب" لإحضار التغييرات عبر:

cd ../YYY
git pull ../XXX

الآن يبي يشبه هذا:

YYY
 |- ZZZ
     |- ZZZ
 |- (other folders that already were in YYY)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top