আপনি দুটি গিট সংগ্রহস্থল কীভাবে মার্জ করবেন?


1619

নিম্নলিখিত পরিস্থিতিতে বিবেচনা করুন:

আমি তার নিজস্ব গিট রেপোতে একটি ছোট পরীক্ষামূলক প্রকল্প এ তৈরি করেছি। এটি এখন পরিপক্ক হয়েছে, এবং আমি এটিকে বৃহত প্রকল্প বি এর অংশ হতে চাই, যার নিজস্ব বৃহত ভাণ্ডার রয়েছে। আমি এখন বি এর একটি উপ-ডিরেক্টরি হিসাবে যুক্ত করতে চাই

কোনও দিকের ইতিহাস না হারিয়ে আমি কীভাবে এটিকে বিতে মিশাব?


8
আপনি যদি কেবল দু'টি সংগ্রহস্থল রাখার দরকার না রেখে একটিতে দু'টি সংগ্রহস্থল একত্রিত করার চেষ্টা করছেন তবে এই প্রশ্নটি একবার দেখুন: স্ট্যাকওভারফ্লো
ফ্লিম

সংরক্ষণ সাথে কাস্টম দির Git রেপো মার্জ সমস্ত comits ব্যবহার stackoverflow.com/a/43340714/1772410
আন্দ্রে Izman

উত্তর:


436

অন্য সংগ্রহস্থলের একটি একক শাখা সহজেই তার ইতিহাস বজায় রেখে একটি সাব-ডাইরেক্টরির অধীনে স্থাপন করা যেতে পারে। উদাহরণ স্বরূপ:

git subtree add --prefix=rails git://github.com/rails/rails.git master

এটি একক প্রতিশ্রুতি হিসাবে উপস্থিত হবে যেখানে রেল মাস্টার শাখার সমস্ত ফাইল "রেলস" ডিরেক্টরিতে যুক্ত করা হয়েছে। তবে কমিটের শিরোনামে পুরানো ইতিহাস গাছের উল্লেখ রয়েছে:

কমিট থেকে 'রেল /' যোগ করুন <rev>

যেখানে <rev>একটি SHA-1 কমিট হ্যাশ রয়েছে। আপনি এখনও ইতিহাস দেখতে পারেন, কিছু পরিবর্তনকে দোষ দিন।

git log <rev>
git blame <rev> -- README.md

মনে রাখবেন যে আপনি এখান থেকে ডিরেক্টরি উপসর্গ দেখতে পাচ্ছেন না কারণ এটি প্রকৃত পুরানো শাখা অক্ষত রয়েছে। আপনার এটি একটি সাধারণ ফাইল মুভ কমিটের মতো আচরণ করা উচিত: এটি পৌঁছানোর সময় আপনার অতিরিক্ত লাফের প্রয়োজন হবে।

# finishes with all files added at once commit
git log rails/README.md

# then continue from original tree
git log <rev> -- README.md

ম্যানুয়ালি এটি করা বা অন্যান্য উত্তরে বর্ণিত ইতিহাস পুনরায় লেখার মতো আরও জটিল সমাধান রয়েছে।

গিট-সাবট্রি কমান্ডটি অফিসিয়াল গিট-অবদানের একটি অংশ, কিছু প্যাকেট পরিচালক এটি ডিফল্টরূপে ইনস্টল করে (ওএস এক্স হোমব্রিউ)। তবে আপনাকে গিট ছাড়াও এটি নিজেই ইনস্টল করতে হতে পারে।


2
গিট সাবট্রি কীভাবে ইনস্টল করবেন সে সম্পর্কে এখানে নির্দেশাবলী রয়েছে (জুন ২০১৩ হিসাবে): stackoverflow.com/a/11613541/694469 (এবং আমি এর সাথে প্রতিস্থাপন git co v1.7.11.3 করেছি ... v1.8.3)।
কাজম্যাগনুস

1
নীচের উত্তর সম্পর্কে মাথা আপ জন্য ধন্যবাদ। গিট 1.8.4 হিসাবে 'সাবট্রি' এখনও অন্তর্ভুক্ত নেই (কমপক্ষে উবুন্টু 12.04 গিট পিপিএ তে নয় (পিপিএ: গিট-কোর / পিপিএ))
ম্যাট ক্লিন

1
আমি নিশ্চিত করতে পারি যে এর পরে, git log rails/somefileফাইলটির কমিটের ইতিহাসটি মার্জ কমিট ব্যতীত প্রদর্শিত হবে না। @Artfulrobot এর পরামর্শ অনুসারে গ্রেগ হিউগিলের উত্তরটি পরীক্ষা করুন । এবং আপনাকে git filter-branchযে রেপো অন্তর্ভুক্ত করতে চান তা ব্যবহার করতে পারে।
জিফেং ঝাং

6
অথবা এরিক লি'র "ফাইলের ইতিহাস হারিয়ে না দিয়ে একটি গিলে
ঝাং

4
অন্যরা যেমন বলেছে, git subtreeআপনি যা ভাবেন তা নাও করতে পারে! আরও সম্পূর্ণ সমাধানের জন্য এখানে দেখুন ।
পল ড্রাগার

1906

আপনি একত্রীকরণ করতে চান project-aমধ্যে project-b:

cd path/to/project-b
git remote add project-a path/to/project-a
git fetch project-a --tags
git merge --allow-unrelated-histories project-a/master # or whichever branch you want to merge
git remote remove project-a

থেকে নেওয়া: গিটটি বিভিন্ন ভান্ডারগুলিকে একীভূত করবেন?

এই পদ্ধতিটি আমার পক্ষে বেশ ভালভাবে কাজ করেছে, এটি সংক্ষিপ্ত এবং আমার মতে অনেক পরিষ্কার।

যদি আপনি লাগাতে চান project-aএকটি সাব-, আপনি ব্যবহার করতে পারেন মধ্যে git-filter-repo( filter-branchহয় নিরুৎসাহিত )। উপরের কমান্ডগুলির আগে নিম্নলিখিত কমান্ডগুলি চালান:

cd path/to/project-a
git filter-repo --to-subdirectory-filter project-a

2 টি বড় সংগ্রহস্থল মার্জ করার একটি উদাহরণ, এর মধ্যে একটিকে উপ-ডিরেক্টরিতে রেখে: https://gist.github.com/x-yuri/9890ab1079cf4357d6f269d073fd9731

নোট:--allow-unrelated-histories প্যারামিটার শুধুমাত্র Git> = 2.9 থেকে বিদ্যমান। দেখুন গীত - Git একত্রীকরণ ডকুমেন্টেশন / --allow-সম্পর্কহীন-ইতিহাস

আপডেট : --tagsট্যাগগুলি রাখার জন্য @ jstadler এর পরামর্শ অনুযায়ী যুক্ত করা হয়েছে।


8
এটি আমার জন্য ব্যবসা করেছে। .Gitignore ফাইলটিতে কেবলমাত্র একটি দ্বন্দ্ব নিয়ে প্রথমবারের মতো মনোমোহনের মতো কাজ করেছেন! এটি পুরোপুরি প্রতিশ্রুতিবদ্ধ ইতিহাস সংরক্ষণ করে। সরলতার পাশাপাশি - অন্যান্য পদ্ধতির চেয়েও বড় প্লাস হ'ল এটির সাথে মার্জ করা রেপোর কোনও চলমান রেফারেন্স থাকার দরকার নেই। তবে আপনার মতো লক্ষ্য রাখার একটি বিষয় - আপনি যদি আমার মতো আইওএস বিকাশকারী হন - লক্ষ্য রেপোর প্রকল্প ফাইলটি কর্মক্ষেত্রের মধ্যে ফেলে দেওয়ার জন্য খুব সতর্কতা অবলম্বন করা উচিত।
ম্যাক্সলিউড

30
ধন্যবাদ। আমার জন্য কাজ করেছেন। আমাকে একত্রীকরণ করা ডিরেক্টরিটি একটি সাব-ফোল্ডারে স্থানান্তরিত করতে হবে যাতে আমি কেবলমাত্র উপরে ব্যবহৃত পদক্ষেপগুলি অনুসরণ করার পরেgit mv source-dir/ dest/new-source-dir
সিড

13
git mergeধাপ এখানে ব্যর্থ fatal: refusing to merge unrelated histories; --allow-unrelated-historiesসংশোধন করা হয়েছে যে হিসাবে ব্যাখ্যা করা দস্তাবেজ
এসএসসি

19
--allow-unrelated-histories2.9 গিট চালু করা হয়েছিল । পূর্ববর্তী সংস্করণগুলিতে এটি ছিল ডিফল্ট আচরণ।
ডগলাস রয়েডস

11
অপেক্ষাকৃত ছোট: git fetch /path/to/project-a master; git merge --allow-unrelated-histories FETCH_HEAD
jthill

614

এখানে দুটি সম্ভাব্য সমাধান রয়েছে:

Submodules

হয় কপি সংগ্রহস্থল এ বৃহত প্রকল্প বি-তে একটি পৃথক ডিরেক্টরিতে, অথবা (সম্ভবত আরও ভাল) ক্লোন সংগ্রহস্থল এটিকে প্রকল্প বিতে একটি উপ-ডিরেক্টরিতে রূপান্তর করা হবে তারপরে এই সংগ্রহস্থলকে একটি রেপোজিটরি বিয়ের একটি সাবমডিউল হিসাবে গিট সাবমডিউল ব্যবহার করুন

এটি স্বল্প-যুগল সংগ্রহস্থলগুলির জন্য একটি ভাল সমাধান, যেখানে সংগ্রহশালা এ-তে বিকাশ অব্যাহত রয়েছে এবং বিকাশের প্রধান অংশটি এ-এর একটি পৃথক একা একা বিকাশ , গিট উইকির সাবমডিউলসপোর্ট এবং গিটসবুডমুলেউল টিউটোরিয়াল পৃষ্ঠাও দেখুন ।

সাবট্রি মার্জ

আপনি সাবট্রি মার্জ কৌশলটি ব্যবহার করে একটি প্রকল্প বি এর একটি উপ ডিরেক্টরিতে ভান্ডার এটিকে মার্জ করতে পারেন। এটি সাবট্রি মার্জিং এবং ইউ মার্কস প্রিন্জে বর্ণনা করেছেন ।

git remote add -f Bproject /path/to/B
git merge -s ours --allow-unrelated-histories --no-commit Bproject/master
git read-tree --prefix=dir-B/ -u Bproject/master
git commit -m "Merge B project as our subdirectory"
git pull -s subtree Bproject master

( --allow-unrelated-historiesগিট> = ২.৯.০ এর জন্য বিকল্পের প্রয়োজন))

অথবা আপনি ব্যবহার করতে পারেন Git সাবট্রি সরঞ্জাম ( GitHub থেকে সংগ্রহস্থলের ) apenwarr দ্বারা (Avery, Pennarun), তার ব্লগ পোস্টে উদাহরণস্বরূপ ঘোষণা Git সাবট্রি: গীত submodules একটি নতুন বিকল্প


আমি মনে করি আপনার ক্ষেত্রে (এ বড় প্রকল্প বি এর অংশ হতে হবে) সঠিক সমাধানটি সাবট্রি মার্জ ব্যবহার করা হবে


1
এটি কাজ করে এবং ইতিহাস সংরক্ষণ করে বলে মনে হচ্ছে, তবে এমনটি নয় যে আপনি মার্জ করার মাধ্যমে ফাইলগুলি পৃথক করতে বা দ্বিখণ্ডিত করতে পারেন could আমি কি একটি পদক্ষেপ মিস করছি?
জেটেরো

55
এটি অসম্পূর্ণ । হ্যাঁ আপনি প্রচুর কমিট পেয়ে থাকেন তবে সেগুলি আর সঠিক পথগুলিকে বোঝায় না। git log dir-B/somefileএকত্রীকরণ ব্যতীত আর কিছুই দেখাবে না। দেখুন গ্রেগ Hewgill এর উত্তর রেফারেন্স এই গুরুত্বপূর্ণ সমস্যা।
আর্টফুল্রবট

2
গুরুত্বপূর্ণ: গিট টান - নো-রিবেস -s সাবট্রি বিপ্রজেক্ট মাস্টার যদি আপনি এটি না করেন এবং আপনি স্বয়ংক্রিয়ভাবে পুনঃব্যবস্থা করতে প্রস্তুত হন তবে আপনি "অবজেক্টটি পার্স করতে পারছেন না" দিয়ে শেষ করবেন। Osdir.com/ml/git/2009-07/msg01576.html
এরিক

4
এই উত্তরটি বিভ্রান্তিকর হতে পারে কারণ এটি বিতে মিশে যাওয়া সাবট্রি হিসাবে বি রয়েছে যখন প্রশ্নে এটি ছিল ক। অনুলিপি এবং পেস্টের ফলাফল?
vfclists

11
যদি আপনি কেবল দুটি সংগ্রহস্থল একসাথে আঠালো করার চেষ্টা করছেন, সাবমডিউল এবং সাবট্রি মার্জগুলি ব্যবহার করার ভুল সরঞ্জাম কারণ তারা সমস্ত ফাইলের ইতিহাস সংরক্ষণ করে না (যেমন অন্যান্য মন্তব্যকারীরা উল্লেখ করেছেন)। স্ট্যাকওভারফ্লো . com/ প্রশ্নগুলি / ১১৩০৪০৯৮৮/২ দেখুন ।
এরিক লি

194

আপনি যদি প্রকল্পটি আলাদাভাবে বজায় রাখতে চান তবে সাব-মডুলের পদ্ধতিটি ভাল। তবে, আপনি যদি সত্যিই একই প্রকল্পগুলিতে উভয় প্রকল্পকে মার্জ করতে চান তবে আপনার আরও কিছু কাজ করতে হবে।

প্রথমটি git filter-branchহ'ল দ্বিতীয় সংগ্রহস্থলের প্রত্যেকটির নাম পুনর্লিখনের জন্য সাব-ডিরেক্টরিতে থাকতে হবে যেখানে আপনি তাদের শেষ করতে চান। সুতরাং পরিবর্তে foo.c, bar.html, আপনি হবে projb/foo.cএবং projb/bar.html

তারপরে, আপনি নিম্নলিখিতগুলির মতো কিছু করতে সক্ষম হবেন:

git remote add projb [wherever]
git pull projb

git pullএকটি কি করতে হবে git fetchএকটি দ্বারা অনুসরণ git merge। কোনও দ্বন্দ্ব হওয়া উচিত নয়, আপনি যে সংগ্রহশালাটি টানছেন তার মধ্যে এখনও একটি projb/ডিরেক্টরি নেই।

আরও অনুসন্ধান ইঙ্গিত দেয় যে অনুরূপ কিছু মার্জ করার জন্যই gitkকরা হয়েছিল git। জুনিও সি হামানো এ সম্পর্কে এখানে লিখেছেন: http://www.mail-archive.com/git@vger.kernel.org/msg03395.html


4
সাবট্রি একীকরণ আরও ভাল সমাধান হতে পারে, এবং অন্তর্ভুক্ত প্রকল্পের পুনর্লিখনের ইতিহাসের প্রয়োজন হবে না
জাকুব নারাবস্কি

8
আমি git filter-branchএটি অর্জন করতে কীভাবে ব্যবহার করব তা জানতে চাই । ম্যান পেজে এটি চারপাশে বিপরীত উপায় সম্পর্কে বলে: সাবডির তৈরি / মূল হয়ে যায়, তবে অন্যভাবে নয়।
আর্টফুলরোবট

31
এই উত্তরটি দুর্দান্ত হবে যদি এটি ব্যাখ্যা করে যে কীভাবে পছন্দসই ফলাফল অর্জন করতে ফিল্টার-শাখা ব্যবহার করা যায়
অ্যান্ট্রপিক

14
আমি এখানে ফিল্টার-শাখা কীভাবে ব্যবহার করব তা খুঁজে পেয়েছি: stackoverflow.com/questions/4042816/…
ডেভিড মাইনর

3
গ্রেগের রূপরেখা বাস্তবায়নের জন্য এই উত্তরটি দেখুন ।
পল ড্রাগার

75

git-subtree দুর্দান্ত, তবে এটি সম্ভবত আপনি চান না।

উদাহরণস্বরূপ, যদি projectAবিতে ডিরেক্টরি তৈরি করা হয়, পরে git subtree,

git log projectA

একমাত্র প্রতিশ্রুতি তালিকাবদ্ধ করে : মার্জ। একীভূত প্রকল্প থেকে করা কমিটগুলি বিভিন্ন পাথের জন্য, তাই তারা প্রদর্শিত হয় না।

গ্রেগ হিউগিলের উত্তর নিকটতম আসে, যদিও এটি কীভাবে পাথগুলি পুনরায় লিখতে হয় তা বাস্তবে বলা হয় না।


সমাধান আশ্চর্যজনকভাবে সহজ।

(1) এ তে,

PREFIX=projectA #adjust this

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

দ্রষ্টব্য: এটি ইতিহাস পুনর্লিখন করে, তাই আপনি যদি এই রেপো এ ব্যবহার চালিয়ে যেতে চান, আপনি প্রথমে এটির একটি নিক্ষেপ অনুলিপি (অনুলিপি) ক্লোন করতে চাইতে পারেন।

দ্রষ্টব্য বেনিফিট: আপনি ফাইলের নাম বা পথে অ-এস্কি অক্ষর (বা সাদা অক্ষর) ব্যবহার করার ক্ষেত্রে সেড কমান্ডের অভ্যন্তরে বিকল্প স্ক্রিপ্টটি পরিবর্তন করতে হবে। সেক্ষেত্রে "এলএস-ফাইল-এস" দ্বারা উত্পাদিত একটি রেকর্ডের মধ্যে ফাইলের অবস্থান উদ্ধৃতি চিহ্ন দিয়ে শুরু হয়।

(2) তারপরে বি তে, চালান

git pull path/to/A

ভাল খবর! projectAবি তে আপনার একটি ডিরেক্টরি রয়েছে যদি আপনি চালনা করেন তবে আপনি git log projectAএ থেকে সমস্ত কমিটগুলি দেখতে পাবেন from


আমার ক্ষেত্রে, আমি দুটি উপ-ডিরেক্টরি চাইছিলাম, projectAএবং projectB। সেক্ষেত্রে আমি বি তেও পদক্ষেপ (1) করেছি।


1
দেখে মনে হচ্ছে আপনি নিজের উত্তরটি স্ট্যাকওভারফ্লো . com/a/618113/586086 থেকে অনুলিপি করেছেন ?
অ্যান্ড্রু মাও

1
@ অ্যান্ড্রুমাও, আমিও তাই মনে করি ... আমি আসলে মনে করতে পারি না। আমি এই স্ক্রিপ্টটি বেশ খানিকটা ব্যবহার করেছি।
পল ড্রাগার

6
আমি যুক্ত করব যে ওএস এক্সে কাজ করে না এবং আপনাকে <tab>
মুনিব আলি

2
"$GIT_INDEX_FILE"অবশ্যই উদ্ধৃত করতে হবে (দুবার), অন্যথায় আপনার পদ্ধতিটি ব্যর্থ হবে যদি উদাহরণে পথের ফাঁক থাকে contains
রব ডাব্লু

4
যদি আপনি ভাবছেন, অক্সে <ট্যাব> >োকানোর জন্য আপনার প্রয়োজনCtrl-V <tab>
কেসি

48

উভয় ভান্ডারগুলিতে যদি একই ধরণের ফাইল থাকে (বিভিন্ন প্রকল্পের জন্য দুটি রেলের সংগ্রহস্থলের মতো), তবে আপনি আপনার বর্তমান সংগ্রহস্থলের মাধ্যমিকের সংগ্রহস্থলের ডেটা আনতে পারেন:

git fetch git://repository.url/repo.git master:branch_name

এবং তারপরে এটি বর্তমান সংগ্রহস্থলে মার্জ করুন:

git merge --allow-unrelated-histories branch_name

আপনার গিট সংস্করণ যদি ২.৯-এর চেয়ে কম হয় তবে সরান --allow-unrelated-histories

এর পরে, দ্বন্দ্ব দেখা দিতে পারে। আপনি উদাহরণস্বরূপ এগুলি সমাধান করতে পারেন git mergetoolkdiff3সম্পূর্ণ কীবোর্ডের সাহায্যে ব্যবহার করা যেতে পারে, তাই কোডটি পড়ার সময় কয়েক মিনিটের মধ্যে 5 টি সংঘাতের ফাইল লাগে।

মার্জ শেষ করতে ভুলবেন না:

git commit

25

মার্জ ব্যবহার করার সময় আমি ইতিহাস হারাতে থাকি, তাই আমি রিবেসটি ব্যবহার করে শেষ করেছি যেহেতু আমার ক্ষেত্রে দুটি প্রতিলিপি প্রতিটি প্রতিশ্রুতিতে মার্জ না করে যথেষ্ট আলাদা:

git clone git@gitorious/projA.git projA
git clone git@gitorious/projB.git projB

cd projB
git remote add projA ../projA/
git fetch projA 
git rebase projA/master HEAD

=> বিরোধগুলি সমাধান করুন, তারপরে চালিয়ে যান, যতবার প্রয়োজন ...

git rebase --continue

এটি করার ফলে একটি প্রকল্পে প্রজায় সমস্ত কমিট থাকে এবং এরপরে প্রজবি থেকে কমিট হয়


25

আমার ক্ষেত্রে, আমার কাছে একটি my-pluginসংগ্রহশালা এবং একটি main-projectসংগ্রহস্থল ছিল এবং আমি ভান করতে চাই my-pluginযা সর্বদা pluginsসাব-ডিরেক্টরিতে উন্নত ছিল main-project

মূলত, আমি my-pluginসংগ্রহস্থলের ইতিহাসটি পুনরায় লিখেছিলাম যাতে এটি প্রদর্শিত হয়েছিল যে সমস্ত বিকাশ plugins/my-pluginউপ - ডিরেক্টরিতে ঘটেছিল । তারপর, আমি উন্নয়নের ইতিহাস যোগ my-pluginমধ্যে main-projectইতিহাস, এবং দুই গাছ একসঙ্গে মিশে গিয়ে তৈরি। যেহেতু plugins/my-pluginইতিমধ্যে কোনও ডিরেক্টরি main-projectসংগ্রহস্থলটিতে উপস্থিত ছিল না , এটি ছিল একটি তুচ্ছ নন-বিরোধ। ফলস্বরূপ সংগ্রহস্থল দুটি মূল প্রকল্পের সমস্ত ইতিহাস ধারণ করে এবং এর দুটি শিকড় ছিল।

টি এল; ডিআর

$ cp -R my-plugin my-plugin-dirty
$ cd my-plugin-dirty
$ git filter-branch -f --tree-filter "zsh -c 'setopt extended_glob && setopt glob_dots && mkdir -p plugins/my-plugin && (mv ^(.git|plugins) plugins/my-plugin || true)'" -- --all
$ cd ../main-project
$ git checkout master
$ git remote add --fetch my-plugin ../my-plugin-dirty
$ git merge my-plugin/master --allow-unrelated-histories
$ cd ..
$ rm -rf my-plugin-dirty

দীর্ঘ সংস্করণ

প্রথমে, my-pluginসংগ্রহশালার একটি অনুলিপি তৈরি করুন , কারণ আমরা এই সংগ্রহস্থলের ইতিহাস পুনর্লিখন করব।

এখন, my-pluginসংগ্রহস্থলের মূলটিতে নেভিগেট করুন, আপনার মূল শাখাটি পরীক্ষা করুন (সম্ভবত master), এবং নিম্নলিখিত কমান্ডটি চালান। অবশ্যই, আপনি খেলোয়াড়রা উচিত my-pluginএবং pluginsযাই হোক না কেন আপনার প্রকৃত নাম।

$ git filter-branch -f --tree-filter "zsh -c 'setopt extended_glob && setopt glob_dots && mkdir -p plugins/my-plugin && (mv ^(.git|plugins) plugins/my-plugin || true)'" -- --all

এখন একটি ব্যাখ্যা জন্য। পৌঁছনীয় প্রতিটি প্রতিশ্রুতিতে কমান্ড git filter-branch --tree-filter (...) HEADচালায় । নোট করুন যে এটি প্রতিটি প্রতিশ্রুতিবদ্ধতার জন্য সঞ্চিত ডেটাতে সরাসরি কাজ করে, সুতরাং আমাদের "ওয়ার্কিং ডিরেক্টরি", "সূচক", "মঞ্চায়ন" ইত্যাদির ধারণাগুলি নিয়ে উদ্বিগ্ন হওয়ার দরকার নেই।(...)HEAD

যদি আপনি কোনও filter-branchকমান্ড .gitচালিয়ে যান যা ব্যর্থ হয়, তবে এটি ডিরেক্টরিতে কিছু ফাইল রেখে যাবে এবং পরের বার আপনি চেষ্টা করার পরে filter-branchএটি সম্পর্কে অভিযোগ করবেন, যদি না আপনি -fবিকল্পটি সরবরাহ করেন filter-branch

প্রকৃত কমান্ড হিসাবে, আমি bashযা চেয়েছিলাম তা করার মতো ভাগ্য আমার ছিল না , তাই পরিবর্তে আমি একটি কমান্ড কার্যকর zsh -cকরতে ব্যবহার করি zsh। প্রথমে আমি extended_globবিকল্পটি সেট করি , যা এটি ^(...)সিন্টেক্সকে সক্ষম করেmv কমান্ডের সেইসাথে glob_dotsবিকল্পটিও, যা আমাকে গ্লোব ( .gitignore) সহ ডটফাইলে (যেমন ) নির্বাচন করতে দেয় ^(...)

এরপরে, আমি এটি ব্যবহার করি mkdir -p উভয় pluginsএবং plugins/my-pluginএকই সাথে তৈরি কমান্ডটি ।

অবশেষে, সংগ্রহ ব্যতীত মূল ডিরেক্টরিতে সমস্ত ফাইলের সাথে মিলে zsh"নেতিবাচক গ্লোব" বৈশিষ্ট্যটি ^(.git|plugins)ব্যবহার করি.git এবং নতুন তৈরি হওয়া my-pluginফোল্ডার । (বাদ দেওয়া .gitএখানে প্রয়োজনীয় নাও হতে পারে তবে ডিরেক্টরিকে নিজের মধ্যে স্থানান্তরিত করার চেষ্টা করা একটি ত্রুটি))

আমার সংগ্রহশালায়, প্রাথমিক প্রতিশ্রুতিতে কোনও ফাইল অন্তর্ভুক্ত ছিল না, তাই mv আদেশটি প্রাথমিক কমিটের ত্রুটি ফিরিয়েছিল (যেহেতু স্থানান্তরিত করার জন্য কিছুই উপলভ্য ছিল না)। অতএব, আমি || trueএমন একটি যুক্ত করেছি যাতে git filter-branchগর্ভপাত না হয়।

--allবিকল্প বলে filter-branchইতিহাস পুনর্লিখন সব সংগ্রহস্থলের মধ্যে শাখা, এবং অতিরিক্ত --বল করা প্রয়োজনgit পরিবর্তে একটি বিকল্প হিসাবে, পুনর্লিখন শাখা জন্য বিকল্প তালিকা একটি অংশ হিসাবে এটা ব্যাখ্যা করা filter-branchনিজেই।

এখন, আপনার main-projectসংগ্রহস্থল নেভিগেট করুন এবং আপনি যে শাখায় মার্জ করতে চান তা দেখুন check আপনার স্থানীয় কপিটি my-pluginসংগ্রহস্থলের (এর ইতিহাস সংশোধিত সহ) এর main-projectসাথে রিমোট হিসাবে যুক্ত করুন :

$ git remote add --fetch my-plugin $PATH_TO_MY_PLUGIN_REPOSITORY

আপনার প্রতিশ্রুতিবদ্ধ ইতিহাসে এখন দুটি সম্পর্কিত নয় এমন গাছ থাকবে যা আপনি সুন্দরভাবে ব্যবহার করে ভিজ্যুয়ালাইজ করতে পারবেন:

$ git log --color --graph --decorate --all

তাদের মার্জ করতে, ব্যবহার করুন:

$ git merge my-plugin/master --allow-unrelated-histories

নোট করুন যে প্রাক-২.৯.০ গিটে --allow-unrelated-historiesবিকল্পটি বিদ্যমান নেই। আপনি যদি এই সংস্করণগুলির মধ্যে একটি ব্যবহার করে থাকেন তবে কেবলমাত্র বিকল্পটি বাদ দিন: ত্রুটি বার্তা যা --allow-unrelated-historiesপ্রতিরোধ করে was আরো 2.9.0 যোগ।

আপনার কোনও মার্জ সংঘাত থাকা উচিত নয়। যদি আপনি এটি করেন তবে এর অর্থ সম্ভবত হ'ল filter-branchকমান্ডটি সঠিকভাবে কাজ করে না বা ইতিমধ্যে একটি ছিলplugins/my-plugin ডিরেক্টরি রয়েছে main-project

ভবিষ্যতে কোনও অবদানকারীদের জন্য দুটি শিকড় দিয়ে একটি সংগ্রহশালা তৈরি করার জন্য হ্যাকারি কী চলছে তা ভেবে বিস্ময়কর প্রতিশ্রুতি বার্তা প্রবেশ করার বিষয়টি নিশ্চিত করুন।

উপরের git logকমান্ডটি ব্যবহার করে আপনি নতুন কমিট গ্রাফটি ভিজ্যুয়ালাইজ করতে পারেন, যার দুটি মূল কমিট থাকতে হবে । মনে রাখবেন যে কেবল masterশাখাটি মার্জ হবে । এর অর্থ হ'ল যদি আপনি অন্য my-pluginশাখাগুলিতে গুরুত্বপূর্ণ কাজ করে থাকেন যা আপনি main-projectগাছের সাথে একত্রীকরণ করতে চান , আপনি my-pluginএই মার্জগুলি না করা পর্যন্ত আপনাকে রিমোটটি মোছা থেকে বিরত থাকা উচিত । যদি আপনি এটি না করেন, তবে সেই শাখাগুলি থেকে করা কমিটগুলি এখনও main-projectসংগ্রহশালার মধ্যে থাকবে তবে কিছুগুলি অ্যাক্সেসযোগ্য এবং শেষ অবধি আবর্জনা সংগ্রহের পক্ষে সংবেদনশীল। (এছাড়াও, আপনাকে তাদের এসএএএ দ্বারা উল্লেখ করতে হবে, কারণ একটি রিমোট মোছা তার দূরবর্তী ট্র্যাকিং শাখাগুলি সরিয়ে দেয়))

Allyচ্ছিকভাবে, আপনি যে জিনিসগুলি থেকে রাখতে চান তা মার্জ করার পরে আপনি রিমোটটি ব্যবহার করে my-pluginএটি সরিয়ে ফেলতে পারেন my-plugin:

$ git remote remove my-plugin

my-pluginযার ইতিহাস আপনি বদলেছেন সে অনুলিপি আপনি এখন নিরাপদে মুছতে পারেন । আমার ক্ষেত্রে, আমি my-pluginমার্জ সম্পূর্ণ হওয়ার পরে এবং ধাক্কা দেওয়ার পরেও সত্যিকারের সংগ্রহস্থলটিতে অবমূল্যায়নের বিজ্ঞপ্তি যুক্ত করেছি ।


ম্যাক ওএস এক্স এল ক্যাপিটনে git --version 2.9.0এবং এর সাথে পরীক্ষিত zsh --version 5.2। আপনার মাইলেজ পরিবর্তিত হতে পারে.

তথ্যসূত্র:


1
কোথা --allow-unrelated-historiesথেকে আসছেন?
xpto

3
পরীক্ষা করে দেখুন @MarceloFilho man git-mergeডিফল্টরূপে, গিট মার্জ কমান্ড হিস্ট্রিগুলিকে একীভূত করতে অস্বীকার করে যা কোনও সাধারণ পূর্বপুরুষকে ভাগ করে না। এই প্রকল্পটি এই সুরক্ষাকে ওভাররাইড করতে ব্যবহার করা যেতে পারে যখন দুটি প্রকল্পের ইতিহাস স্বাধীনভাবে তাদের জীবন শুরু করেছিল mer যেহেতু এটি একটি খুব বিরল উপলক্ষ্য, তাই এটি ডিফল্টরূপে সক্ষম করার জন্য কোনও কনফিগারেশন ভেরিয়েবল বিদ্যমান নেই এবং যুক্ত করা হবে না।
র‌্যাডন রোসবারো

পাওয়া উচিত git version 2.7.2.windows.1?
xpto

2
@ মার্সেলোফিলহ এটি ২.৯.০ এ যুক্ত করা হয়েছে, তবে পুরানো সংস্করণগুলিতে আপনাকে বিকল্পটি পাস করতে হবে না (এটি কেবল কার্যকর হবে)। github.com/git/git/blob/…
রেডন রোসবারো

এটি ভাল কাজ করেছে। এবং একত্রীকরণের আগে আমি গাছটিতে যেখানে চেয়েছিলাম সেখানে ফাইলের নামগুলি আবার লিখতে আমি ফিল্টার শাখাটি ব্যবহার করতে সক্ষম হয়েছি। আমি মনে করছি আপনি যদি মাস্টার ব্রাঞ্চের পাশাপাশি ইতিহাস সরিয়ে নিতে চান তবে আরও কাজ জড়িত রয়েছে।
কোডড্র

9

আমি কয়েক দিন ধরে একই জিনিস করার চেষ্টা করছি, আমি গিট ২.7.২ ব্যবহার করছি। সাবট্রি ইতিহাস সংরক্ষণ করে না।

আপনি যদি পুরানো প্রকল্পটি আবার ব্যবহার না করেন তবে আপনি এই পদ্ধতিটি ব্যবহার করতে পারেন।

আমি আপনাকে পরামর্শ দিচ্ছি যে আপনি প্রথমে বি শাখা করুন এবং শাখায় কাজ করুন।

এখানে শাখা ছাড়াই পদক্ষেপ রয়েছে:

cd B

# You are going to merge A into B, so first move all of B's files into a sub dir
mkdir B

# Move all files to B, till there is nothing in the dir but .git and B
git mv <files> B

git add .

git commit -m "Moving content of project B in preparation for merge from A"


# Now merge A into B
git remote add -f A <A repo url>

git merge A/<branch>

mkdir A

# move all the files into subdir A, excluding .git
git mv <files> A

git commit -m "Moved A into subdir"


# Move B's files back to root    
git mv B/* ./

rm -rf B

git commit -m "Reset B to original state"

git push

আপনি এখন সাবডির এ-তে যে কোনও ফাইল লগইন করলে আপনি সম্পূর্ণ ইতিহাস পাবেন

git log --follow A/<file>

এটি পোস্টটিই আমাকে এটি করতে সহায়তা করেছিল:

http://saintgimp.org/2013/01/22/merging-two-git-repositories-into-one-repository-without-losing-file-history/


8

আপনি যদি একটি মধ্যে রেপো বি একটি শাখা থেকে ফাইল লাগাতে চান তাহলে সাবট্রি রেপো A -এর এবং এছাড়াও ইতিহাস সংরক্ষণ, পড়ার রাখা। (নীচের উদাহরণে, আমি ধরে নিচ্ছি যে আমরা রেপো বি এর মাস্টার শাখাটি রেপো এ এর ​​মাস্টার শাখায় একীভূত করতে চাই))

রেপো এ-তে, রেপো বি উপলক্ষে প্রথমে নিম্নলিখিতটি করুন:

git remote add B ../B # Add repo B as a new remote.
git fetch B

এখন আমরা একটি ব্র্যান্ড নতুন শাখা (সঙ্গে শুধুমাত্র এক কমিট) রেপো একটি তৈরি যে আমরা কল new_b_root। ফলস্বরূপ প্রতিশ্রুতিবদ্ধ করা ফাইলগুলি রেপো বি এর মাস্টার শাখার প্রথম কমিটে প্রতিশ্রুতিবদ্ধ ছিল তবে ডাকা একটি সাব-ডিরেক্টরিতে রাখে path/to/b-files/

git checkout --orphan new_b_root master
git rm -rf . # Remove all files.
git cherry-pick -n `git rev-list --max-parents=0 B/master`
mkdir -p path/to/b-files
git mv README path/to/b-files/
git commit --date="$(git log --format='%ai' $(git rev-list --max-parents=0 B/master))"

ব্যাখ্যা: --orphanচেকআউট কমান্ডের বিকল্পটি এ এর ​​মাস্টার শাখা থেকে ফাইলগুলি পরীক্ষা করে তবে কোনও প্রতিশ্রুতি তৈরি করে না। আমরা যে কোনও প্রতিশ্রুতি নির্বাচন করতে পারতাম কারণ পরবর্তী আমরা যাইহোক সমস্ত ফাইল সাফ করে দিই। তারপরে, এখনও প্রতিশ্রুতি না দিয়ে ( -n), আমরা বি এর মাস্টার শাখা থেকে প্রথম কমিট চেরি-বাছাই করি। (চেরি-পিকটি মূল প্রতিশ্রুতি বার্তাটি সংরক্ষণ করে যা কোনও সরল চেকআউট করে বলে মনে হয় না)) তারপরে আমরা সাবট্রিটি তৈরি করি যেখানে আমরা রেপো বি থেকে সমস্ত ফাইল স্থাপন করতে চাই We সাবেরিতে চেরি-পিক করুন। উপরের উদাহরণে, READMEসরানোর জন্য কেবল একটি ফাইল রয়েছে তারপরে আমরা আমাদের বি-রেপো মূল প্রতিশ্রুতিবদ্ধ এবং একই সাথে আমরা মূল কমিটের টাইমস্ট্যাম্পও সংরক্ষণ করি।

এখন, আমরা B/masterসদ্য নির্মিত তৈরির উপরে একটি নতুন শাখা তৈরি করব new_b_root। আমরা নতুন শাখা কল b:

git checkout -b b B/master
git rebase -s recursive -Xsubtree=path/to/b-files/ new_b_root

এখন, আমরা আমাদের bশাখাটিকে এতে মার্জ করি A/master:

git checkout master
git merge --allow-unrelated-histories --no-commit b
git commit -m 'Merge repo B into repo A.'

অবশেষে, আপনি Bদূরবর্তী এবং অস্থায়ী শাখা মুছে ফেলতে পারেন :

git remote remove B
git branch -D new_b_root b

চূড়ান্ত গ্রাফের মতো কাঠামো থাকবে:

এখানে চিত্র বর্ণনা লিখুন


দুর্দান্ত উত্তর, ধন্যবাদ! অ্যান্ড্রেস সার্জের "গিট সাবট্রি" বা "মার্জ - নিবন্ধ-সম্পর্কহীন-ইতিহাস" সহ অন্যান্য জবাবগুলি আমি সত্যিই মিস করেছি যে সাব ডিরেক্টরিটিতে লগ নেই।
ইলেন্দির

8

স্ট্যাক ওভারফ্লো ইত্যাদিতে আমি এখানে প্রচুর তথ্য সংগ্রহ করেছি এবং একসাথে একটি স্ক্রিপ্ট রেখেছি যা আমার জন্য সমস্যার সমাধান করে।

সতর্কবাণীটি হ'ল এটি কেবল প্রতিটি ভান্ডারের 'বিকাশ' শাখাকে বিবেচনা করে এবং একে একে সম্পূর্ণ নতুন সংগ্রহস্থলে একটি পৃথক ডিরেক্টরিতে একীভূত করে।

ট্যাগ এবং অন্যান্য শাখা অগ্রাহ্য করা হয় - এটি আপনি চান তা নাও হতে পারে।

স্ক্রিপ্ট এমনকি বৈশিষ্ট্যযুক্ত শাখা এবং ট্যাগগুলি পরিচালনা করে - তাদের নতুন প্রকল্পে নামকরণ করে যাতে আপনি জানেন যে তারা কোথা থেকে এসেছিল।

#!/bin/bash
#
################################################################################
## Script to merge multiple git repositories into a new repository
## - The new repository will contain a folder for every merged repository
## - The script adds remotes for every project and then merges in every branch
##   and tag. These are renamed to have the origin project name as a prefix
##
## Usage: mergeGitRepositories.sh <new_project> <my_repo_urls.lst>
## - where <new_project> is the name of the new project to create
## - and <my_repo_urls.lst> is a file contaning the URLs to the respositories
##   which are to be merged on separate lines.
##
## Author: Robert von Burg
##            eitch@eitchnet.ch
##
## Version: 0.3.2
## Created: 2018-02-05
##
################################################################################
#

# disallow using undefined variables
shopt -s -o nounset

# Script variables
declare SCRIPT_NAME="${0##*/}"
declare SCRIPT_DIR="$(cd ${0%/*} ; pwd)"
declare ROOT_DIR="$PWD"
IFS=$'\n'

# Detect proper usage
if [ "$#" -ne "2" ] ; then
  echo -e "ERROR: Usage: $0 <new_project> <my_repo_urls.lst>"
  exit 1
fi


## Script variables
PROJECT_NAME="${1}"
PROJECT_PATH="${ROOT_DIR}/${PROJECT_NAME}"
TIMESTAMP="$(date +%s)"
LOG_FILE="${ROOT_DIR}/${PROJECT_NAME}_merge.${TIMESTAMP}.log"
REPO_FILE="${2}"
REPO_URL_FILE="${ROOT_DIR}/${REPO_FILE}"


# Script functions
function failed() {
  echo -e "ERROR: Merging of projects failed:"
  echo -e "ERROR: Merging of projects failed:" >>${LOG_FILE} 2>&1
  echo -e "$1"
  exit 1
}

function commit_merge() {
  current_branch="$(git symbolic-ref HEAD 2>/dev/null)"
  if [[ ! -f ".git/MERGE_HEAD" ]] ; then
    echo -e "INFO:   No commit required."
    echo -e "INFO:   No commit required." >>${LOG_FILE} 2>&1
  else
    echo -e "INFO:   Committing ${sub_project}..."
    echo -e "INFO:   Committing ${sub_project}..." >>${LOG_FILE} 2>&1
    if ! git commit -m "[Project] Merged branch '$1' of ${sub_project}" >>${LOG_FILE} 2>&1 ; then
      failed "Failed to commit merge of branch '$1' of ${sub_project} into ${current_branch}"
    fi
  fi
}


# Make sure the REPO_URL_FILE exists
if [ ! -e "${REPO_URL_FILE}" ] ; then
  echo -e "ERROR: Repo file ${REPO_URL_FILE} does not exist!"
  exit 1
fi


# Make sure the required directories don't exist
if [ -e "${PROJECT_PATH}" ] ; then
  echo -e "ERROR: Project ${PROJECT_NAME} already exists!"
  exit 1
fi


# create the new project
echo -e "INFO: Logging to ${LOG_FILE}"
echo -e "INFO: Creating new git repository ${PROJECT_NAME}..."
echo -e "INFO: Creating new git repository ${PROJECT_NAME}..." >>${LOG_FILE} 2>&1
echo -e "===================================================="
echo -e "====================================================" >>${LOG_FILE} 2>&1
cd ${ROOT_DIR}
mkdir ${PROJECT_NAME}
cd ${PROJECT_NAME}
git init
echo "Initial Commit" > initial_commit
# Since this is a new repository we need to have at least one commit
# thus were we create temporary file, but we delete it again.
# Deleting it guarantees we don't have conflicts later when merging
git add initial_commit
git commit --quiet -m "[Project] Initial Master Repo Commit"
git rm --quiet initial_commit
git commit --quiet -m "[Project] Initial Master Repo Commit"
echo


# Merge all projects into the branches of this project
echo -e "INFO: Merging projects into new repository..."
echo -e "INFO: Merging projects into new repository..." >>${LOG_FILE} 2>&1
echo -e "===================================================="
echo -e "====================================================" >>${LOG_FILE} 2>&1
for url in $(cat ${REPO_URL_FILE}) ; do

  if [[ "${url:0:1}" == '#' ]] ; then
    continue
  fi

  # extract the name of this project
  export sub_project=${url##*/}
  sub_project=${sub_project%*.git}

  echo -e "INFO: Project ${sub_project}"
  echo -e "INFO: Project ${sub_project}" >>${LOG_FILE} 2>&1
  echo -e "----------------------------------------------------"
  echo -e "----------------------------------------------------" >>${LOG_FILE} 2>&1

  # Fetch the project
  echo -e "INFO:   Fetching ${sub_project}..."
  echo -e "INFO:   Fetching ${sub_project}..." >>${LOG_FILE} 2>&1
  git remote add "${sub_project}" "${url}"
  if ! git fetch --tags --quiet ${sub_project} >>${LOG_FILE} 2>&1 ; then
    failed "Failed to fetch project ${sub_project}"
  fi

  # add remote branches
  echo -e "INFO:   Creating local branches for ${sub_project}..."
  echo -e "INFO:   Creating local branches for ${sub_project}..." >>${LOG_FILE} 2>&1
  while read branch ; do
    branch_ref=$(echo $branch | tr " " "\t" | cut -f 1)
    branch_name=$(echo $branch | tr " " "\t" | cut -f 2 | cut -d / -f 3-)

    echo -e "INFO:   Creating branch ${branch_name}..."
    echo -e "INFO:   Creating branch ${branch_name}..." >>${LOG_FILE} 2>&1

    # create and checkout new merge branch off of master
    if ! git checkout -b "${sub_project}/${branch_name}" master >>${LOG_FILE} 2>&1 ; then failed "Failed preparing ${branch_name}" ; fi
    if ! git reset --hard ; then failed "Failed preparing ${branch_name}" >>${LOG_FILE} 2>&1 ; fi
    if ! git clean -d --force ; then failed "Failed preparing ${branch_name}" >>${LOG_FILE} 2>&1 ; fi

    # Merge the project
    echo -e "INFO:   Merging ${sub_project}..."
    echo -e "INFO:   Merging ${sub_project}..." >>${LOG_FILE} 2>&1
    if ! git merge --allow-unrelated-histories --no-commit "remotes/${sub_project}/${branch_name}" >>${LOG_FILE} 2>&1 ; then
      failed "Failed to merge branch 'remotes/${sub_project}/${branch_name}' from ${sub_project}"
    fi

    # And now see if we need to commit (maybe there was a merge)
    commit_merge "${sub_project}/${branch_name}"

    # relocate projects files into own directory
    if [ "$(ls)" == "${sub_project}" ] ; then
      echo -e "WARN:   Not moving files in branch ${branch_name} of ${sub_project} as already only one root level."
      echo -e "WARN:   Not moving files in branch ${branch_name} of ${sub_project} as already only one root level." >>${LOG_FILE} 2>&1
    else
      echo -e "INFO:   Moving files in branch ${branch_name} of ${sub_project} so we have a single directory..."
      echo -e "INFO:   Moving files in branch ${branch_name} of ${sub_project} so we have a single directory..." >>${LOG_FILE} 2>&1
      mkdir ${sub_project}
      for f in $(ls -a) ; do
        if  [[ "$f" == "${sub_project}" ]] ||
            [[ "$f" == "." ]] ||
            [[ "$f" == ".." ]] ; then
          continue
        fi
        git mv -k "$f" "${sub_project}/"
      done

      # commit the moving
      if ! git commit --quiet -m  "[Project] Move ${sub_project} files into sub directory" ; then
        failed "Failed to commit moving of ${sub_project} files into sub directory"
      fi
    fi
    echo
  done < <(git ls-remote --heads ${sub_project})


  # checkout master of sub probject
  if ! git checkout "${sub_project}/master" >>${LOG_FILE} 2>&1 ; then
    failed "sub_project ${sub_project} is missing master branch!"
  fi

  # copy remote tags
  echo -e "INFO:   Copying tags for ${sub_project}..."
  echo -e "INFO:   Copying tags for ${sub_project}..." >>${LOG_FILE} 2>&1
  while read tag ; do
    tag_ref=$(echo $tag | tr " " "\t" | cut -f 1)
    tag_name_unfixed=$(echo $tag | tr " " "\t" | cut -f 2 | cut -d / -f 3)

    # hack for broken tag names where they are like 1.2.0^{} instead of just 1.2.0
    tag_name="${tag_name_unfixed%%^*}"

    tag_new_name="${sub_project}/${tag_name}"
    echo -e "INFO:     Copying tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}..."
    echo -e "INFO:     Copying tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}..." >>${LOG_FILE} 2>&1
    if ! git tag "${tag_new_name}" "${tag_ref}" >>${LOG_FILE} 2>&1 ; then
      echo -e "WARN:     Could not copy tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}"
      echo -e "WARN:     Could not copy tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}" >>${LOG_FILE} 2>&1
    fi
  done < <(git ls-remote --tags --refs ${sub_project})

  # Remove the remote to the old project
  echo -e "INFO:   Removing remote ${sub_project}..."
  echo -e "INFO:   Removing remote ${sub_project}..." >>${LOG_FILE} 2>&1
  git remote rm ${sub_project}

  echo
done


# Now merge all project master branches into new master
git checkout --quiet master
echo -e "INFO: Merging projects master branches into new repository..."
echo -e "INFO: Merging projects master branches into new repository..." >>${LOG_FILE} 2>&1
echo -e "===================================================="
echo -e "====================================================" >>${LOG_FILE} 2>&1
for url in $(cat ${REPO_URL_FILE}) ; do

  if [[ ${url:0:1} == '#' ]] ; then
    continue
  fi

  # extract the name of this project
  export sub_project=${url##*/}
  sub_project=${sub_project%*.git}

  echo -e "INFO:   Merging ${sub_project}..."
  echo -e "INFO:   Merging ${sub_project}..." >>${LOG_FILE} 2>&1
  if ! git merge --allow-unrelated-histories --no-commit "${sub_project}/master" >>${LOG_FILE} 2>&1 ; then
    failed "Failed to merge branch ${sub_project}/master into master"
  fi

  # And now see if we need to commit (maybe there was a merge)
  commit_merge "${sub_project}/master"

  echo
done


# Done
cd ${ROOT_DIR}
echo -e "INFO: Done."
echo -e "INFO: Done." >>${LOG_FILE} 2>&1
echo

exit 0

আপনি এটি http://paste.ubuntu.com/11732805 থেকেও পেতে পারেন

প্রথমে প্রতিটি সংগ্রহস্থলের URL সহ একটি ফাইল তৈরি করুন, যেমন:

git@github.com:eitchnet/ch.eitchnet.parent.git
git@github.com:eitchnet/ch.eitchnet.utils.git
git@github.com:eitchnet/ch.eitchnet.privilege.git

তারপরে স্ক্রিপ্টটিকে প্রকল্পের নাম এবং স্ক্রিপ্টের পথে একটি নাম্বার কল করুন:

./mergeGitRepositories.sh eitchnet_test eitchnet.lst

স্ক্রিপ্টটিতে নিজেই অনেক মন্তব্য রয়েছে যা এটি কী করে তা ব্যাখ্যা করা উচিত।


পাঠকদের কোনও উত্তরের নির্দেশ দেওয়ার পরিবর্তে দয়া করে উত্তরটি এখানে পোস্ট করুন (উক্ত মন্তব্যে আপনি যা বলেছিলেন তা উত্তরটিতে উত্তর দিন)।
জোস্লিবার

1
অবশ্যই, নিজেকে পুনরাবৃত্তি না
করাই

আপনি যদি মনে করেন যে এই প্রশ্নটি অন্য একটির মতো, তবে আপনি নিজেই প্রশ্নের অধীনে "পতাকা" লিঙ্কটি ব্যবহার করে এবং অন্য প্রশ্নের ইঙ্গিত হিসাবে এটি সদৃশ হিসাবে পতাকাঙ্কিত করতে পারেন। যদি এটি সদৃশ প্রশ্ন না হয় তবে আপনি মনে করেন যে একই উত্তর দুটি সমস্যা সমাধানে ব্যবহার করা যেতে পারে তবে কেবলমাত্র উভয় ইস্যুতে একই উত্তর পোস্ট করুন (আপনি এখন যেমন করেছেন)। অবদানের জন্য ধন্যবাদ!
জোস্লিবার

অ্যামেজিং! উইন্ডোজ ব্যাশ প্রম্পটে কাজ করেনি, তবে এটি নির্বিঘ্নে উবুন্টুতে চলমান একটি ভ্যাগ্রান্ট বক্স তৈরি করে। কি সময় রক্ষাকারী!
xverges

সেবার হতে
পেরে

7

আমি জানি এটি বাস্তবের অনেক পরে, তবে আমি এখানে অন্যান্য উত্তরগুলি পেয়ে খুশি নই, তাই আমি এটি লিখেছিলাম:

me=$(basename $0)

TMP=$(mktemp -d /tmp/$me.XXXXXXXX)
echo 
echo "building new repo in $TMP"
echo
sleep 1

set -e

cd $TMP
mkdir new-repo
cd new-repo
    git init
    cd ..

x=0
while [ -n "$1" ]; do
    repo="$1"; shift
    git clone "$repo"
    dirname=$(basename $repo | sed -e 's/\s/-/g')
    if [[ $dirname =~ ^git:.*\.git$ ]]; then
        dirname=$(echo $dirname | sed s/.git$//)
    fi

    cd $dirname
        git remote rm origin
        git filter-branch --tree-filter \
            "(mkdir -p $dirname; find . -maxdepth 1 ! -name . ! -name .git ! -name $dirname -exec mv {} $dirname/ \;)"
        cd ..

    cd new-repo
        git pull --no-commit ../$dirname
        [ $x -gt 0 ] && git commit -m "merge made by $me"
        cd ..

    x=$(( x + 1 ))
done

2
এটি ঠিক আমি যা খুঁজছিলাম ছিল। ধন্যবাদ! যাইহোক, আমাকে 22 টি লাইনটি পরিবর্তন করতে হয়েছিল:if [[ $dirname =~ ^.*\.git$ ]]; then
হিমান

2
^। * ব্লগার waste অযথা লোভী আরআর। .Blarg say বলা ভাল এবং সামনের অ্যাঙ্করটি এড়িয়ে যান।
জেটেরো

7

যদি আপনি কেবল দুটি সংগ্রহস্থল একসাথে আঠালো করার চেষ্টা করছেন, সাবমডিউলগুলি এবং সাবট্রি মার্জগুলি ব্যবহার করার ভুল সরঞ্জাম কারণ এগুলি ফাইলের ইতিহাসের সমস্ত সংরক্ষণ করে না (যেমন লোকেদের অন্যান্য উত্তরে উল্লেখ করেছে)। এটি করার সহজ এবং সঠিক উপায়ের জন্য এই উত্তরটি এখানে দেখুন ।


1
আপনার সমাধানটি কেবলমাত্র নতুন সংগ্রহশালার জন্যই ভাল কাজ করে তবে কীভাবে ফাইল সংঘাতের সাথে রেপো অন্য একটিতে মার্জ করা যায়?
Andrey Izman

6

আমার অনুরূপ চ্যালেঞ্জ ছিল, তবে আমার ক্ষেত্রে, আমরা রেপো এ-তে কোডবেসের একটি সংস্করণ তৈরি করেছি, তারপরে পণ্যটির নতুন সংস্করণটির জন্য ক্লোনিটিকে একটি নতুন রেপো, রেপো বিতে পরিণত করেছি। রেপো এ-তে কিছু বাগ ফিক্স করার পরে, আমাদের রেপো বিতে পরিবর্তনগুলি এফআইয়ের দরকার ছিল নিম্নলিখিতগুলি শেষ করে শেষ করা:

  1. বি রেপোতে একটি রিমোট যুক্ত করা হচ্ছে যা রেপো এ নির্দেশ করেছে (গিট দূরবর্তী অ্যাড ...)
  2. বর্তমান শাখাটি টানছে (আমরা বাগ ফিক্সের জন্য মাস্টার ব্যবহার করছিলাম না) (গিট টান রিমোটফোরআরপিওএ বাগ ফিক্স ব্রাঞ্চ)
  3. ঠেলাঠেলি গিথুবে মার্জ করে

একটি ট্রিট কাজ করেছেন :)


5

@ স্মার এর মতো তবে প্রাথমিক ও দ্বিতীয় স্থানে সেট করা ফাইল সিস্টেমের পাথগুলি ব্যবহার করে:

PRIMARY=~/Code/project1
SECONDARY=~/Code/project2
cd $PRIMARY
git remote add test $SECONDARY && git fetch test
git merge test/master

তারপরে আপনি ম্যানুয়ালি মার্জ করুন।

( আনার মানাফভ পোস্ট থেকে অভিযোজিত )


5

2 টি পুনরায় মার্জ করা হচ্ছে

git clone ssh://<project-repo> project1
cd project1
git remote add -f project2 project2
git merge --allow-unrelated-histories project2/master
git remote rm project2

delete the ref to avoid errors
git update-ref -d refs/remotes/project2/master

4

আপনি যখন একক প্রতিশ্রুতিতে তিন বা ততোধিক প্রকল্পকে মার্জ করতে চান , তখন অন্যান্য উত্তরে ( remote add -f, merge) বর্ণিত পদক্ষেপগুলি করুন । তারপরে, (নরম) সূচকটি পুরানো মাথায় পুনরায় সেট করুন (যেখানে কোনও মার্জ হয়নি)। সমস্ত ফাইল যুক্ত করুন ( git add -A) এবং সেগুলি প্রতিশ্রুতি দিন ("প্রকল্পগুলির এক, বি, সি এবং ডি একত্রিত করে" বার্তা দিন) এটি এখন মাস্টারের কমিট-আইডি।

এখন, .git/info/graftsনিম্নলিখিত সামগ্রী সহ তৈরি করুন :

<commit-id of master> <list of commit ids of all parents>

চালান git filter-branch -- head^..head head^2..head head^3..head। আপনার যদি তিনটির বেশি শাখা থাকে তবে আপনার যত head^n..headশাখা রয়েছে তেমন যুক্ত করুন । ট্যাগগুলি আপডেট করতে, সংযোজন করুন --tag-name-filter cat। সর্বদা এটি যুক্ত করবেন না, কারণ এটি কিছু কমিটগুলির পুনর্লিখনের কারণ হতে পারে। বিশদগুলির জন্য ফিল্টার-শাখার ম্যান পৃষ্ঠা দেখুন , "গ্রাফ্টস" অনুসন্ধান করুন।

এখন, আপনার শেষ প্রতিশ্রুতিবদ্ধ সঠিক পিতামাতার সাথে যুক্ত।


1
অপেক্ষা করুন, আপনি কেন একক প্রতিশ্রুতিতে তিনটি প্রকল্প মার্জ করতে চান?
স্টিভ বেনেট

আমি সংগ্রহস্থল, সংগ্রহশালা-ক্লায়েন্ট এবং মডেলারের সাথে পৃথক গিট প্রকল্প হিসাবে শুরু করেছি। সহকর্মীদের পক্ষে এটি কঠিন ছিল, তাই আমি তাদের সাথে একটি গিট প্রকল্পে যোগদান করি। নতুন প্রকল্পের "মূল" অন্য তিনটি প্রকল্প থেকে উদ্ভূত হয়েছে তা সক্ষম হতে, আমি একক মার্জ কমিট থাকতে চেয়েছিলাম ।
কোপ্পোর

4

খ এর মধ্যে একটি এ মার্জ করতে:

1) প্রকল্পে এ

git fast-export --all --date-order > /tmp/ProjectAExport

2) প্রকল্পে খ

git checkout -b projectA
git fast-import --force < /tmp/ProjectAExport

এই শাখায় আপনার যা যা করা দরকার তা করা এবং তাদের প্রতিশ্রুতিবদ্ধ।

গ) তারপরে মাস্টারের কাছে ফিরে যান এবং দুটি শাখার মধ্যে একটি ধ্রুপদী সংহত:

git checkout master
git merge projectA

2

এই ফাংশনটি স্থানীয় রেপো দিরের মধ্যে রিমোট রেপো ক্লোন করবে, মার্জ করার পরে সমস্ত প্রতিশ্রুতি সংরক্ষণ করা 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="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, তাই নিশ্চিত হয়ে নিন যে এটি মার্জ হওয়ার পরে সঠিক পথে সরানো হয়েছে। প্যারামিটার শুধুমাত্র Git> = 2.9 থেকে বিদ্যমান।
--allow-unrelated-histories


1

প্রদত্ত কমান্ড হ'ল আমি প্রস্তাবিত সেরা সমাধান।

git subtree add --prefix=MY_PROJECT git://github.com/project/my_project.git master

1

আমি প্রকল্পগুলি সামান্য ম্যানুয়ালি মার্জ করি, যা আমাকে মার্জ সংঘাতের সাথে মোকাবিলা করার প্রয়োজন এড়াতে দেয়।

প্রথমে অন্য প্রকল্প থেকে ফাইলগুলি অনুলিপি করুন তবে আপনি এটি চান।

cp -R myotherproject newdirectory
git add newdirectory

ইতিহাসের পরবর্তী টান

git fetch path_or_url_to_other_repo

শেষ আনীত জিনিসের ইতিহাসে একীভূত করতে গিটকে বলুন

echo 'FETCH_HEAD' > .git/MERGE_HEAD

এখন কমিট করুন তবে আপনি সাধারণত প্রতিশ্রুতিবদ্ধ হবে

git commit

0

আমি একটি ছোট প্রকল্পের বৃহত্তর একটি উপ-ডিরেক্টরিতে যেতে চেয়েছিলাম। যেহেতু আমার ছোট প্রকল্পটির অনেক কমিট নেই, তাই আমি ব্যবহার করেছি git format-patch --output-directory /path/to/patch-dir। তারপরে আরও বড় প্রকল্পে, আমি ব্যবহার করেছি git am --directory=dir/in/project /path/to/patch-dir/*

এই মতানুযায়ী উপায় একটি ফিল্টার-শাখা কম ভীতিকর এবং পথ আরো ক্লিনার। মঞ্জুর, এটি সমস্ত ক্ষেত্রে প্রযোজ্য নাও হতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.