ইতিহাস সংরক্ষণ করে কীভাবে ফাইলগুলি একটি গিট রেপো থেকে অন্য ক্লোন (ক্লোন নয়) এ স্থানান্তরিত করতে পারে


483

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

project1/branches
        /tags
        /trunk
project2/branches
        /tags
        /trunk

স্পষ্টতই, ফাইলগুলি একে অপরের সাথে অন্যটিতে স্থানান্তরিত করা বেশ সহজ ছিল svn mv। কিন্তু গীত মধ্যে প্রতিটি প্রকল্পরই নিজস্ব সংগ্রহস্থলের মধ্যে, এবং আজ আমি থেকে একটি সাব সরাতে জিজ্ঞাসা করা হল project2থেকে project1। আমি এরকম কিছু করেছি:

$ git clone project2 
$ cd project2
$ git filter-branch --subdirectory-filter deeply/buried/java/source/directory/A -- --all
$ git remote rm origin  # so I don't accidentally overwrite the repo ;-)
$ mkdir -p deeply/buried/different/java/source/directory/B
$ for f in *.java; do 
>  git mv $f deeply/buried/different/java/source/directory/B
>  done
$ git commit -m "moved files to new subdirectory"
$ cd ..
$
$ git clone project1
$ cd project1
$ git remote add p2 ../project2
$ git fetch p2
$ git branch p2 remotes/p2/master
$ git merge p2 # --allow-unrelated-histories for git 2.9+
$ git remote rm p2
$ git push

তবে এটি বেশ সংশ্লেষিত বলে মনে হচ্ছে। এই ধরণের জিনিসটি সাধারণভাবে করার কি আরও ভাল উপায় আছে? নাকি আমি সঠিক পন্থা অবলম্বন করেছি?

মনে রাখবেন যে এটিতে ইতিহাসের বিদ্যমান সংগ্রহস্থলের সাথে একত্রীকরণের পরিবর্তে অন্যটির অংশ থেকে নতুন স্ট্যান্ডেলোন রিপোজিটরি তৈরি করার পরিবর্তে ( পূর্ববর্তী প্রশ্নের মতো ) জড়িত রয়েছে ।


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

1
@ ইবনেটার - শেল স্ক্রিপ্টগুলি ব্যবহার করে আমি নিজে এটি (একটি এসএনএন রেপো থেকে অন্যটিতে স্থানান্তরিত ইতিহাস) করেছি। মূলত আমি নির্দিষ্ট ফাইল / ডায়ার থেকে দ্বিতীয় সংগ্রহস্থলে ইতিহাস পুনরায় খেলাম (ডিফগুলি, লগ বার্তা সরবরাহ করি) ed
অ্যাডাম মনসেন

1
আমি ভাবছি কেন আপনি এর git fetch p2 && git merge p2বদলে করবেন না git fetch p2 && git branch .. && git merge p2? সম্পাদনা করুন: ঠিক আছে, দেখে মনে হচ্ছে আপনি বর্তমান ব্রাঞ্চের পরিবর্তে পি 2 নামের একটি নতুন শাখায় পরিবর্তন পেতে চান।
লেকেনস্টেইন

1
- ফিল্টার-শাখাকে ডিরেক্টরি কাঠামোটি ধ্বংস করার কোনও উপায় নেই? এই "গিট এমভি" পদক্ষেপের ফলে ফাইল মুছে ফেলা এবং ফাইল তৈরিতে পূর্ণ কমিট হয়।
এডওয়ার্ড ফালক

1
নোট করুন যে গিট ২.৯ হিসাবে সম্পর্কিত নয় এমন ইতিহাসকে মার্জ করা ডিফল্টরূপে অনুমোদিত নয়। এটিকে কাজ করতে, এটিকে কাজ করতে --allow-unrelated-historiesসর্বশেষে যুক্ত করুন git merge
স্কট বেরেরোয়েটস

উত্তর:


55

হাঁ, উপর আঘাত --subdirectory-filterএর filter-branchচাবি ছিল। আপনি এটি প্রয়োজনীয়ভাবে ব্যবহার করেছেন তা প্রমাণ করে যে এর চেয়ে সহজ আর সহজ উপায় নেই - আপনার ইতিহাসের পুনর্লিখন ছাড়া কোনও বিকল্প ছিল না, যেহেতু আপনি কেবল ফাইলগুলির একটি (নাম পরিবর্তিত) উপসেটটি শেষ করতে চেয়েছিলেন, এবং এটি সংজ্ঞা দ্বারা হ্যাশগুলিকে পরিবর্তন করে। যেহেতু কোনও মানক কমান্ড (উদাহরণস্বরূপ pull) ইতিহাসের পুনর্লিখন নেই, আপনি এগুলি সম্পাদন করতে তাদের ব্যবহার করার কোনও উপায় নেই।

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


1
আপনার ফাইলটি যদি বেশ কয়েকটি ডিরেক্টরি থেকে সরানো থাকে এবং এখন একটিতে বাস করে - তাহলে কি সাব-ডাইরেক্টরি-ফিল্টারটি কাজ করবে? (যেমন আমি ধরে নিচ্ছি যে আমি যদি কেবল একটি ফাইল সরিয়ে নিতে চাই, তবে আমি এটির নিজস্ব উপ-ডিরেক্টরিতে স্থানান্তর করতে পারি এবং এটি কাজ করবে?)
রোজারডপ্যাক

1
@ আরগারডপ্যাক: না, এটি নামটির মাধ্যমে ফাইলটি অনুসরণ করবে না। আমি বিশ্বাস করি এটি নির্বাচিত উপ-ডিরেক্টরিতে স্থানান্তরিত হওয়ার সময় এটি তৈরি করা হবে বলে মনে হয়। আপনি যদি কেবল একটি ফাইল নির্বাচন করতে চান --index-filterতবে filter-branchম্যানপেজে একবার দেখুন।
ক্যাসাবেল

8
আমি কীভাবে নামগুলি অনুসরণ করতে পারি তার কোনও রেসিপি রয়েছে?
নাইট ওয়ারিয়ার

আমি মনে করি ইতিহাস বজায় রাখা এবং চিকিত্সা করা গীটের অন্যতম প্রধান বিষয়।
আর্টবার্কার্ট

287

যদি আপনার ইতিহাস বুদ্ধিমান হয় তবে আপনি কমিটগুলি প্যাচ হিসাবে নিতে পারেন এবং সেগুলি নতুন ভাণ্ডারে প্রয়োগ করতে পারেন:

cd repository
git log --pretty=email --patch-with-stat --reverse --full-index --binary -- path/to/file_or_folder > patch
cd ../another_repository
git am --committer-date-is-author-date < ../repository/patch 

বা এক লাইনে

git log --pretty=email --patch-with-stat --reverse -- path/to/file_or_folder | (cd /path/to/new_repository && git am --committer-date-is-author-date)

( এক্সের্বোর ডক্স থেকে নেওয়া )


21
তিন বা চারটি ফাইলের জন্য আমার এটি স্থানান্তরিত হওয়া দরকার ছিল এটি গৃহীত উত্তরের চেয়ে অনেক বেশি সহজ সমাধান। আমি প্যাচ ফাইলে পাথগুলিতে আমার নতুন রেপোর ডিরেক্টরি কাঠামোর সাথে এটি ফিট করার জন্য অনুসন্ধান-প্রতিস্থাপনের সাথে পাথগুলি ছাঁটাই করে শেষ করেছি।
রিয়ান স্যান্ডারসন

8
আমি অপশন যুক্ত করেছেন যাতে বাইনারি ফাইল (চিত্র মত) এছাড়াও সঠিকভাবে মাইগ্রেট করা হয়: git log --pretty=email --patch-with-stat --full-index --binary --reverse -- client > patch। সমস্যা ছাড়াই কাজ করে
এমমানুয়েল টাজারি

35
প্রয়োগের পদক্ষেপে আমি --committer-date-is-author-dateফাইলগুলি সরানোর তারিখের পরিবর্তে মূল প্রতিশ্রুতি তারিখ সংরক্ষণ করার বিকল্পটি ব্যবহার করেছি used
darrenmc

6
ইতিহাসে একত্রিত হওয়ার পরে "am" কমান্ডটি ভেঙে যায়। উপরের গিট লগ কমান্ডে আপনি "-m --first-father" যুক্ত করতে পারেন, তারপরে এটি আমার পক্ষে কাজ করেছিল।
গ্যাবার লিপটিক

6
@ ড্যানিয়েল গোল্ডেন আমি সরানো হয়েছে এমন ফাইলগুলির সাথে সমস্যাটি সমাধান করতে সক্ষম হয়েছি ( git logএটি কোনও বাগের ফলস্বরূপ , যাতে এটি উভয় --followএবং --reverseসঠিকভাবে কাজ করে না )। আমি এই উত্তরটি ব্যবহার করেছি , এবং এখানে একটি সম্পূর্ণ স্ক্রিপ্ট যা আমি এখন ফাইলগুলি সরাতে ব্যবহার করি
tsayen

75

একটি গিট সংগ্রহস্থল থেকে অন্য ফাইলটিতে ফোল্ডার বা ফোল্ডার স্থানান্তরিত করার জন্য বিভিন্ন পদ্ধতির চেষ্টা করার পরে কেবল নির্ভরযোগ্যভাবে কাজ করা মনে হয় কেবল নীচে উল্লিখিত হয়েছে।

এর মধ্যে আপনি যে ফাইলটি বা ফোল্ডারটি রুট থেকে সরানো, সেই ফাইল বা ফোল্ডারটি রুটে নিয়ে যেতে চান, গিট ইতিহাসের পুনর্লিখন, টার্গেটের সংগ্রহস্থলকে ক্লোন করা এবং ইতিহাসের সাথে ফাইল বা ফোল্ডারটিকে সরাসরি এই টার্গেটের সংগ্রহস্থলে টানতে চান cl

এক মঞ্চ

  1. নীচের পদক্ষেপগুলি আপনার অনুলিপি করা উচিত নয় যা এই অনুলিপিটিতে বড় ধরনের পরিবর্তন হিসাবে সংগ্রহস্থল এ এর ​​একটি অনুলিপি তৈরি করুন!

    git clone --branch <branch> --origin origin --progress \
      -v <git repository A url>
    # eg. git clone --branch master --origin origin --progress \
    #   -v https://username@giturl/scm/projects/myprojects.git
    # (assuming myprojects is the repository you want to copy from)
    
  2. এটিতে সিডি

    cd <git repository A directory>
    #  eg. cd /c/Working/GIT/myprojects
    
  3. দুর্ঘটনাক্রমে কোনও দূরবর্তী পরিবর্তন (যেমন, ধাক্কা দিয়ে) এড়ানোর জন্য মূল সংগ্রহস্থলের লিঙ্কটি মুছুন

    git remote rm origin
    
  4. ডিরেক্টরি ১-তে নেই এমন কিছু মুছে ফেলুন এবং আপনার ইতিহাস এবং ফাইলগুলি দিয়ে যান The ফলাফলটি হ'ল ডিরেক্টরি 1 এর ডিরেক্টরি 1 এর সংগ্রহস্থলের ভিত্তিতে তৈরি করা হয় A.

    git filter-branch --subdirectory-filter <directory> -- --all
    # eg. git filter-branch --subdirectory-filter subfolder1/subfolder2/FOLDER_TO_KEEP -- --all
    
  5. একক ফাইল সরানোর জন্য: যা বাকী রয়েছে তার মধ্যে দিয়ে যান এবং কাঙ্ক্ষিত ফাইল ব্যতীত সমস্ত কিছু সরিয়ে দিন। (আপনার একই নাম এবং প্রতিশ্রুতি যুক্ত নয় এমন ফাইলগুলি মুছতে হবে))

    git filter-branch -f --index-filter \
    'git ls-files -s | grep $'\t'FILE_TO_KEEP$ |
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
    git update-index --index-info && \
    mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE || echo "Nothing to do"' --prune-empty -- --all
    # eg. FILE_TO_KEEP = pom.xml to keep only the pom.xml file from FOLDER_TO_KEEP
    

দ্বিতীয় পর্যায়

  1. পরিষ্কারের পদক্ষেপ

    git reset --hard
    
  2. পরিষ্কারের পদক্ষেপ

    git gc --aggressive
    
  3. পরিষ্কারের পদক্ষেপ

    git prune
    

আপনি এই ফাইলগুলি মূল ডিরেক্টরি নয় এমন একটি ডিরেক্টরিতে রিপোজিটরি বিতে আমদানি করতে চাইতে পারেন:

  1. ডিরেক্টরিটি তৈরি করুন

    mkdir <base directory>             eg. mkdir FOLDER_TO_KEEP
    
  2. ফাইলগুলি সেই ডিরেক্টরিতে সরান

    git mv * <base directory>          eg. git mv * FOLDER_TO_KEEP
    
  3. ডিরেক্টরিতে ফাইল যুক্ত করুন

    git add .
    
  4. আপনার পরিবর্তনগুলি প্রতিশ্রুতিবদ্ধ এবং আমরা এই ফাইলগুলি নতুন ভাণ্ডারে একীভূত করতে প্রস্তুত

    git commit
    

তিন মঞ্চ

  1. আপনার কাছে ইতিমধ্যে যদি না থাকে তবে ভান্ডার বি এর একটি অনুলিপি তৈরি করুন

    git clone <git repository B url>
    # eg. git clone https://username@giturl/scm/projects/FOLDER_TO_KEEP.git
    

    (ধরে নিই যে FOLDER_TO_KEEP আপনি অনুলিপি করছেন এমন নতুন ভাণ্ডারের নাম)

  2. এটিতে সিডি

    cd <git repository B directory>
    #  eg. cd /c/Working/GIT/FOLDER_TO_KEEP
    
  3. সংগ্রহস্থল বিতে একটি শাখা হিসাবে সংগ্রহস্থল এ-তে একটি রিমোট সংযোগ তৈরি করুন

    git remote add repo-A-branch <git repository A directory>
    # (repo-A-branch can be anything - it's just an arbitrary name)
    
    # eg. git remote add repo-A-branch /c/Working/GIT/myprojects
    
  4. এই শাখাটি (কেবলমাত্র যে ডিরেক্টরিটি আপনি সরিয়ে নিতে চান সেগুলি সহ) বিশিষ্ট বিতে টানুন

    git pull repo-A-branch master --allow-unrelated-histories
    

    টান ফাইল এবং ইতিহাস উভয়ই অনুলিপি করে। দ্রষ্টব্য: আপনি একটি টানার পরিবর্তে মার্জটি ব্যবহার করতে পারেন, তবে টান ভাল কাজ করে।

  5. অবশেষে, আপনি সম্ভবত সংগ্রহস্থল এ এর ​​রিমোট সংযোগটি সরিয়ে কিছুটা পরিষ্কার করতে চান

    git remote rm repo-A-branch
    
  6. ধাক্কা এবং আপনি প্রস্তুত।

    git push
    

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

আমি মনে করি এটি সঠিক এবং আপনি যে কোনও শাখাগুলি থেকে ফাইল বা ফোল্ডারগুলি সরাতে চান তার জন্য আপনাকে একই ধরণের পদক্ষেপ নিতে হবে। শাখায় স্যুইচ করুন যেমন সংগ্রহস্থলের এ, ফিল্টার-শাখায় MyBranch ইত্যাদি এরপর আপনাকে "Git টান রেপো-এ-শাখা MyBranch" সংগ্রহস্থল বি মধ্যে হবে
mcarans

জবাবের জন্য ধন্যবাদ. আপনি কি জানেন যে শাখাগুলিতে ট্যাগগুলি পাশাপাশি স্থানান্তরিত হবে?
বাও-লং এনগুইন-ট্রং

আমি ভীত আমি জানি না, তবে অনুমান করতাম যে তারা হবে।
mcrans

1
@ এমকারানস দুর্ভাগ্যক্রমে, এটি নির্ভরযোগ্য উপায় নয়, যদিও এটি মনে হচ্ছে। এটি অন্যান্য সমস্ত সমাধানের মতো একই সমস্যায় ভুগছে - এটি ইতিহাসের অতীতের নামটি ধরে রাখে না। আমার ক্ষেত্রে, আমি প্রথমে প্রতিশ্রুতিবদ্ধ হয় যখন আমি ডিরেক্টরি / ফাইলটির নাম পরিবর্তন করি। এর বাইরে সবই হারিয়ে গেছে।
xZero

20

আমি দেখেছি এই খুব দরকারী। এটি একটি খুব সহজ পদ্ধতির যেখানে আপনি প্যাচগুলি তৈরি করেন যা নতুন রেপোতে প্রয়োগ করা হয়। আরও তথ্যের জন্য লিঙ্কযুক্ত পৃষ্ঠাটি দেখুন।

এটিতে কেবল তিনটি ধাপ রয়েছে (ব্লগ থেকে অনুলিপি করা):

# Setup a directory to hold the patches
mkdir <patch-directory>

# Create the patches
git format-patch -o <patch-directory> --root /path/to/copy

# Apply the patches in the new repo using a 3 way merge in case of conflicts
# (merges from the other repo are not turned into patches). 
# The 3way can be omitted.
git am --3way <patch-directory>/*.patch

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

git am --3way <patch-directory>/*.patch

উইন্ডোজ এর অধীনে আমি একটি অবৈধ ত্রুটি পেয়েছি। সুতরাং আমাকে একের পর এক সমস্ত প্যাচ প্রয়োগ করতে হয়েছিল।


কোনও সময় শ-হ্যাশগুলি অনুপস্থিত থাকায় আমার পক্ষে কাজ করেনি। এই আমাকে সাহায্য stackoverflow.com/questions/17371150/...
dr0i

"গিট লগ" পদ্ধতির বিপরীতে, এই বিকল্পটি আমার পক্ষে নিখুঁতভাবে কাজ করেছে! ধন্যবাদ!
আলেজান্দ্রোভিডি

1
প্রকল্পগুলিকে নতুন রেপোতে সরানোর জন্য বিভিন্ন পদ্ধতির চেষ্টা করা হয়েছে। এটিই আমার পক্ষে কাজ করেছে। বিশ্বাস করা যায় না যে এ জাতীয় সাধারণ কাজটি অবশ্যই জটিল হতে হবে।
ক্রিস_ডি_তুর্ক

রস হেন্ড্রিকসনের ব্লগ ভাগ করে নেওয়ার জন্য ধন্যবাদ । এই পদ্ধতির আমার জন্য কাজ করে।
কৌশিক আচার্য

1
এটি খুব মার্জিত সমাধান, তবে আবারও, এটি অন্যান্য সমস্ত সমাধানের মতো একই সমস্যা থেকে ভোগে - এটি ইতিহাসের পূর্বের নামটি ধরে রাখবে না।
xZero

6

ডিরেক্টরি নাম রাখা

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

আমার সমাধানটি ছিল ট্রি-ফিল্টারটি ব্যবহার করা এবং উত্স সংগ্রহস্থলের অস্থায়ী ক্লোন থেকে অনাকাঙ্ক্ষিত ফাইল এবং ডিরেক্টরিগুলি সরিয়ে ফেলা, তারপরে 5 টি সহজ ধাপে সেই ক্লোনটি থেকে আমার টার্গেটের সংগ্রহস্থলে টানুন।

# 1. clone the source
git clone ssh://<user>@<source-repo url>
cd <source-repo>
# 2. remove the stuff we want to exclude
git filter-branch --tree-filter "rm -rf <files to exclude>" --prune-empty HEAD
# 3. move to target repo and create a merge branch (for safety)
cd <path to target-repo>
git checkout -b <merge branch>
# 4. Add the source-repo as remote 
git remote add source-repo <path to source-repo>
# 5. fetch it
git pull source-repo master
# 6. check that you got it right (better safe than sorry, right?)
gitk

এই স্ক্রিপ্টটি আপনার মূল রেপোতে কোনও পরিবর্তন করবে না। মানচিত্রের ফাইলে নির্দিষ্ট করা ডেস্ট রেপো উপস্থিত না থাকলে এই স্ক্রিপ্টটি এটি তৈরির চেষ্টা করবে।
চিতাবাহন

1
আমি আরও মনে করি ডিরেক্টরি ডিরেক্টরি অক্ষত রাখা অত্যন্ত গুরুত্বপূর্ণ is অন্যথায় আপনি টার্গেট সংগ্রহস্থলে অতিরিক্ত নামকরণের প্রতিশ্রুতি পাবেন।
ipuustin

6

এক আমি সবসময় ব্যবহার এখানে http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/ । সহজ এবং দ্রুত।

স্ট্যাকওভারফ্লো স্ট্যান্ডার্ডগুলির সাথে সম্মতি পাওয়ার জন্য, পদ্ধতিটি এখানে:

mkdir /tmp/mergepatchs
cd ~/repo/org
export reposrc=myfile.c #or mydir
git format-patch -o /tmp/mergepatchs $(git log $reposrc|grep ^commit|tail -1|awk '{print $2}')^..HEAD $reposrc
cd ~/repo/dest
git am /tmp/mergepatchs/*.patch

5

এই উত্তরটি git amধাপে ধাপে উদাহরণগুলির উপর ভিত্তি করে উপস্থাপিত আকর্ষণীয় কমান্ড সরবরাহ করে।

উদ্দেশ্য

  • আপনি কিছু বা সমস্ত ফাইল একটি সংগ্রহস্থল থেকে অন্যটিতে সরিয়ে নিতে চান।
  • আপনি তাদের ইতিহাস রাখতে চান।
  • তবে আপনি ট্যাগ এবং শাখা রাখার বিষয়ে চিন্তা করেন না।
  • নাম বদলে দেওয়া ফাইলগুলির (এবং নাম পরিবর্তিত ডিরেক্টরিগুলির ফাইলগুলিতে) সীমাবদ্ধ ইতিহাস আপনি গ্রহণ করেন।

কার্যপ্রণালী

  1. ইমেল ফর্ম্যাটে ব্যবহার করে ইতিহাস বের করুন
    git log --pretty=email -p --reverse --full-index --binary
  2. ফাইল ট্রি পুনর্গঠিত করুন এবং ইতিহাসের ফাইল নাম পরিবর্তন আপডেট করুন [alচ্ছিক]
  3. ব্যবহার করে নতুন ইতিহাস প্রয়োগ করুন git am

1. ইমেল ফর্ম্যাটে ইতিহাস বের করুন

উদাহরণ: এর এক্সট্র্যাক্ট ইতিহাস file3, file4এবংfile5

my_repo
├── dirA
│   ├── file1
│   └── file2
├── dirB            ^
│   ├── subdir      | To be moved
│   │   ├── file3   | with history
│   │   └── file4   | 
│   └── file5       v
└── dirC
    ├── file6
    └── file7

অস্থায়ী ডিরেক্টরি গন্তব্য পরিষ্কার করুন

export historydir=/tmp/mail/dir  # Absolute path
rm -rf "$historydir"             # Caution when cleaning

আপনার রেপো উত্স পরিষ্কার করুন

git commit ...           # Commit your working files
rm .gitignore            # Disable gitignore
git clean -n             # Simulate removal
git clean -f             # Remove untracked file
git checkout .gitignore  # Restore gitignore

ইমেল ফর্ম্যাটে প্রতিটি ফাইলের ইতিহাস বের করুন

cd my_repo/dirB
find -name .git -prune -o -type d -o -exec bash -c 'mkdir -p "$historydir/${0%/*}" && git log --pretty=email -p --stat --reverse --full-index --binary -- "$0" > "$historydir/$0"' {} ';'

দুর্ভাগ্যক্রমে বিকল্প --followবা --find-copies-harderএকত্রিত করা যায় না --reverse। এই কারণেই ফাইলটি পুনরায় নামকরণ করা হলে (বা যখন কোনও পিতামহিত ডিরেক্টরি পুনরায় নামকরণ করা হয়) ইতিহাস কাটা হয়।

পরে: ইমেল ফর্ম্যাটে অস্থায়ী ইতিহাস

/tmp/mail/dir
    ├── subdir
    │   ├── file3
    │   └── file4
    └── file5

২. ফাইল ট্রি পুনর্গঠিত করুন এবং ইতিহাসের ফাইলের নাম পরিবর্তন করুন [alচ্ছিক]

মনে করুন আপনি এই তিনটি ফাইলকে এই অন্যান্য রেপোতে স্থানান্তরিত করতে চান (একই রেপো হতে পারে)।

my_other_repo
├── dirF
│   ├── file55
│   └── file56
├── dirB              # New tree
│   ├── dirB1         # was subdir
│   │   ├── file33    # was file3
│   │   └── file44    # was file4
│   └── dirB2         # new dir
│        └── file5    # = file5
└── dirH
    └── file77

সুতরাং আপনার ফাইলগুলি পুনর্গঠিত করুন:

cd /tmp/mail/dir
mkdir     dirB
mv subdir dirB/dirB1
mv dirB/dirB1/file3 dirB/dirB1/file33
mv dirB/dirB1/file4 dirB/dirB1/file44
mkdir    dirB/dirB2
mv file5 dirB/dirB2

আপনার অস্থায়ী ইতিহাস এখন:

/tmp/mail/dir
    └── dirB
        ├── dirB1
        │   ├── file33
        │   └── file44
        └── dirB2
             └── file5

ইতিহাসের মধ্যে ফাইলের নামও পরিবর্তন করুন:

cd "$historydir"
find * -type f -exec bash -c 'sed "/^diff --git a\|^--- a\|^+++ b/s:\( [ab]\)/[^ ]*:\1/$0:g" -i "$0"' {} ';'

দ্রষ্টব্য: পথ এবং ফাইলের নাম পরিবর্তন প্রতিফলিত করতে এটি ইতিহাস পুনর্লিখন করে।
      (অর্থাত্ নতুন রেপোর মধ্যে নতুন অবস্থান / নাম পরিবর্তন)


৩. নতুন ইতিহাস প্রয়োগ করুন

আপনার অন্যান্য রেপো হ'ল:

my_other_repo
├── dirF
│   ├── file55
│   └── file56
└── dirH
    └── file77

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

cd my_other_repo
find "$historydir" -type f -exec cat {} + | git am 

আপনার অন্যান্য রেপো এখন:

my_other_repo
├── dirF
│   ├── file55
│   └── file56
├── dirB            ^
│   ├── dirB1       | New files
│   │   ├── file33  | with
│   │   └── file44  | history
│   └── dirB2       | kept
│        └── file5  v
└── dirH
    └── file77

git statusচাপ দেওয়ার জন্য প্রস্তুত কমিটের পরিমাণ দেখতে ব্যবহার করুন :-)

দ্রষ্টব্য: ইতিহাসটি যেমন পথ এবং ফাইলের নাম পরিবর্তন প্রতিফলিত করতে পুনরায় রচনা করা হয়েছে:
      (যেমন পূর্ববর্তী রেপোর মধ্যে অবস্থান / নামের সাথে তুলনা করা)

  • git mvঅবস্থান / ফাইলের নাম পরিবর্তন করার দরকার নেই ।
  • git log --followসম্পূর্ণ ইতিহাস অ্যাক্সেস করার প্রয়োজন নেই ।

অতিরিক্ত কৌশল: আপনার রেপোর মধ্যে পুনরায় নামকরণ / সরানো ফাইলগুলি সনাক্ত করুন

নতুন নামকরণ করা ফাইলগুলি তালিকা করতে:

find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow {} ';' | grep '=>'

আরো কাস্টমাইজেশন: আপনি কমান্ড সম্পন্ন করতে পারবেন git logবিকল্পগুলি ব্যবহার করে --find-copies-harderবা --reverse। আপনি cut -f3-সম্পূর্ণ প্যাটার্ন '{। * =>। *}' ব্যবহার করে এবং গ্রেপিং করে প্রথম দুটি কলামও মুছে ফেলতে পারেন ।

find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'

3

স্ক্র্যাচ করার মতো একই রকম চুলকানি (কেবলমাত্র কোনও প্রদত্ত সংগ্রহস্থলের কিছু ফাইলের জন্য যথেষ্ট) এই স্ক্রিপ্টটি সত্যই সহায়ক হিসাবে প্রমাণিত: গিট-আমদানি

সংক্ষিপ্ত সংস্করণটি হ'ল এটি $objectবিদ্যমান সংগ্রহস্থল থেকে প্রদত্ত ফাইল বা ডিরেক্টরি ( ) এর প্যাচ ফাইল তৈরি করে:

cd old_repo
git format-patch --thread -o "$temp" --root -- "$object"

যা একটি নতুন ভান্ডারে প্রয়োগ করা হবে:

cd new_repo
git am "$temp"/*.patch 

বিশদ জন্য দয়া করে দেখুন:


2

এটা চেষ্টা কর

cd repo1

এটি কেবলমাত্র এই ডিরেক্টরিগুলির জন্য ইতিহাস সংরক্ষণ করে উল্লিখিত ডিরেক্টরিগুলি বাদ দিয়ে সমস্ত ডিরেক্টরি সরিয়ে ফেলবে

git filter-branch --index-filter 'git rm --ignore-unmatch --cached -qr -- . && git reset -q $GIT_COMMIT -- dir1/ dir2/ dir3/ ' --prune-empty -- --all

এখন আপনি নিজের গিটের রিমোটে আপনার নতুন রেপো যুক্ত করতে এবং এটিতে চাপ দিতে পারেন

git remote remove origin <old-repo>
git remote add origin <new-repo>
git push origin <current-branch>

যোগ -fওপর দিয়েই লিখতে


সতর্কতা: গিট-ফিল্টার-শাখায় গ্যাংচাসের আঠা রয়েছে যা ম্যাংলেড ইতিহাসের পুনর্লিখন তৈরি করে। গর্ভপাত স্থির করার আগে Ctrl-C চাপুন, তারপরে বিকল্প গ্যারান্টিং সরঞ্জাম ব্যবহার করুন যেমন 'গিট ফিল্টার-রেপো' ( github.com/newren/git-filter-repo ) এর পরিবর্তে। আরও বিশদের জন্য ফিল্টার-শাখা ম্যানুয়াল পৃষ্ঠাটি দেখুন; এই সতর্কতাটি ছত্রভঙ্গ করতে FILTER_BRANCH_SQUELCH_WARNING = 1 সেট করুন।
কলিন

1

Http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/ থেকে অনুপ্রেরণা ব্যবহার করে , আমি এটি করার জন্য এই পাওয়ারশেল ফাংশন তৈরি করেছি, যা রয়েছে আমার জন্য এ পর্যন্ত দুর্দান্ত কাজ করেছে:

# Migrates the git history of a file or directory from one Git repo to another.
# Start in the root directory of the source repo.
# Also, before running this, I recommended that $destRepoDir be on a new branch that the history will be migrated to.
# Inspired by: http://blog.neutrino.es/2012/git-copy-a-file-or-directory-from-another-repository-preserving-history/
function Migrate-GitHistory
{
    # The file or directory within the current Git repo to migrate.
    param([string] $fileOrDir)
    # Path to the destination repo
    param([string] $destRepoDir)
    # A temp directory to use for storing the patch file (optional)
    param([string] $tempDir = "\temp\migrateGit")

    mkdir $tempDir

    # git log $fileOrDir -- to list commits that will be migrated
    Write-Host "Generating patch files for the history of $fileOrDir ..." -ForegroundColor Cyan
    git format-patch -o $tempDir --root -- $fileOrDir

    cd $destRepoDir
    Write-Host "Applying patch files to restore the history of $fileOrDir ..." -ForegroundColor Cyan
    ls $tempDir -Filter *.patch  `
        | foreach { git am $_.FullName }
}

এই উদাহরণের জন্য ব্যবহার:

git clone project2
git clone project1
cd project1
# Create a new branch to migrate to
git checkout -b migrate-from-project2
cd ..\project2
Migrate-GitHistory "deeply\buried\java\source\directory\A" "..\project1"

আপনি এটি করার পরে, migrate-from-project2শাখাগুলিতে মার্জ করার আগে আপনি ফাইলগুলি পুনরায় সংগঠিত করতে পারেন ।


1

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

এটি একটি অবাধ ফোল্ডার সরাতে করতে সক্ষম হয় /path/to/fooথেকে repo1মধ্যে /some/other/folder/barথেকে repo2(ফোল্ডার পাথ একই বা ভিন্ন, রুট ফোল্ডার থেকে দূরত্ব আলাদা হতে পারে হতে পারে)।

যেহেতু এটি কেবলমাত্র ইনপুট ফোল্ডারে ফাইলগুলিকে স্পর্শ করে (উত্স রেপোর সমস্ত কমিটের চেয়ে বেশি নয়) কমিটগুলি অতিক্রম করে, তাই আপনি যদি খুব গভীরভাবে নেস্টেড সাবফোল্ডারটি প্রত্যাহার করেননি তবে এটি খুব দ্রুত হওয়া উচিত বড় উত্সের রেপোতেও should কমিট।

যেহেতু এটি করা হয় তা সমস্ত পুরানো রেপুর ইতিহাসের সাথে একটি অনাথ শাখা তৈরি করা এবং তারপরে এটিকে প্রধানের সাথে একীভূত করা, এটি ফাইলের নাম সংঘর্ষের ক্ষেত্রেও কাজ করবে (তারপরে অবশ্যই আপনাকে শেষের দিকে একীকরণের সমাধান করতে হবে) ।

যদি কোনও ফাইলের নাম সংঘর্ষ git commitনা হয় তবে মার্জটি চূড়ান্ত করার জন্য আপনার কেবল শেষে দরকার ।

ক্ষতিটি হ'ল এটি সম্ভবত REWRITE_FROMসোর্স রেপোতে ফাইলের নামগুলি ( ফোল্ডারের বাইরে ) অনুসরণ করবে না - এটির জন্য সামঞ্জস্য করতে অনুরোধগুলি গিটহাবে স্বাগত জানায়।

গিটহাব লিঙ্ক: গিট-মুভ-ফোল্ডার-মধ্যে-রেপো-রাখুন-ইতিহাস

#!/bin/bash

# Copy a folder from one git repo to another git repo,
# preserving full history of the folder.

SRC_GIT_REPO='/d/git-experimental/your-old-webapp'
DST_GIT_REPO='/d/git-experimental/your-new-webapp'
SRC_BRANCH_NAME='master'
DST_BRANCH_NAME='import-stuff-from-old-webapp'
# Most likely you want the REWRITE_FROM and REWRITE_TO to have a trailing slash!
REWRITE_FROM='app/src/main/static/'
REWRITE_TO='app/src/main/static/'

verifyPreconditions() {
    #echo 'Checking if SRC_GIT_REPO is a git repo...' &&
      { test -d "${SRC_GIT_REPO}/.git" || { echo "Fatal: SRC_GIT_REPO is not a git repo"; exit; } } &&
    #echo 'Checking if DST_GIT_REPO is a git repo...' &&
      { test -d "${DST_GIT_REPO}/.git" || { echo "Fatal: DST_GIT_REPO is not a git repo"; exit; } } &&
    #echo 'Checking if REWRITE_FROM is not empty...' &&
      { test -n "${REWRITE_FROM}" || { echo "Fatal: REWRITE_FROM is empty"; exit; } } &&
    #echo 'Checking if REWRITE_TO is not empty...' &&
      { test -n "${REWRITE_TO}" || { echo "Fatal: REWRITE_TO is empty"; exit; } } &&
    #echo 'Checking if REWRITE_FROM folder exists in SRC_GIT_REPO' &&
      { test -d "${SRC_GIT_REPO}/${REWRITE_FROM}" || { echo "Fatal: REWRITE_FROM does not exist inside SRC_GIT_REPO"; exit; } } &&
    #echo 'Checking if SRC_GIT_REPO has a branch SRC_BRANCH_NAME' &&
      { cd "${SRC_GIT_REPO}"; git rev-parse --verify "${SRC_BRANCH_NAME}" || { echo "Fatal: SRC_BRANCH_NAME does not exist inside SRC_GIT_REPO"; exit; } } &&
    #echo 'Checking if DST_GIT_REPO has a branch DST_BRANCH_NAME' &&
      { cd "${DST_GIT_REPO}"; git rev-parse --verify "${DST_BRANCH_NAME}" || { echo "Fatal: DST_BRANCH_NAME does not exist inside DST_GIT_REPO"; exit; } } &&
    echo '[OK] All preconditions met'
}

# Import folder from one git repo to another git repo, including full history.
#
# Internally, it rewrites the history of the src repo (by creating
# a temporary orphaned branch; isolating all the files from REWRITE_FROM path
# to the root of the repo, commit by commit; and rewriting them again
# to the original path).
#
# Then it creates another temporary branch in the dest repo,
# fetches the commits from the rewritten src repo, and does a merge.
#
# Before any work is done, all the preconditions are verified: all folders
# and branches must exist (except REWRITE_TO folder in dest repo, which
# can exist, but does not have to).
#
# The code should work reasonably on repos with reasonable git history.
# I did not test pathological cases, like folder being created, deleted,
# created again etc. but probably it will work fine in that case too.
#
# In case you realize something went wrong, you should be able to reverse
# the changes by calling `undoImportFolderFromAnotherGitRepo` function.
# However, to be safe, please back up your repos just in case, before running
# the script. `git filter-branch` is a powerful but dangerous command.
importFolderFromAnotherGitRepo(){
    SED_COMMAND='s-\t\"*-\t'${REWRITE_TO}'-'

    verifyPreconditions &&
    cd "${SRC_GIT_REPO}" &&
      echo "Current working directory: ${SRC_GIT_REPO}" &&
      git checkout "${SRC_BRANCH_NAME}" &&
      echo 'Backing up current branch as FILTER_BRANCH_BACKUP' &&
      git branch -f FILTER_BRANCH_BACKUP &&
      SRC_BRANCH_NAME_EXPORTED="${SRC_BRANCH_NAME}-exported" &&
      echo "Creating temporary branch '${SRC_BRANCH_NAME_EXPORTED}'..." &&
      git checkout -b "${SRC_BRANCH_NAME_EXPORTED}" &&
      echo 'Rewriting history, step 1/2...' &&
      git filter-branch -f --prune-empty --subdirectory-filter ${REWRITE_FROM} &&
      echo 'Rewriting history, step 2/2...' &&
      git filter-branch -f --index-filter \
       "git ls-files -s | sed \"$SED_COMMAND\" |
        GIT_INDEX_FILE=\$GIT_INDEX_FILE.new git update-index --index-info &&
        mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" HEAD &&
    cd - &&
    cd "${DST_GIT_REPO}" &&
      echo "Current working directory: ${DST_GIT_REPO}" &&
      echo "Adding git remote pointing to SRC_GIT_REPO..." &&
      git remote add old-repo ${SRC_GIT_REPO} &&
      echo "Fetching from SRC_GIT_REPO..." &&
      git fetch old-repo "${SRC_BRANCH_NAME_EXPORTED}" &&
      echo "Checking out DST_BRANCH_NAME..." &&
      git checkout "${DST_BRANCH_NAME}" &&
      echo "Merging SRC_GIT_REPO/" &&
      git merge "old-repo/${SRC_BRANCH_NAME}-exported" --no-commit &&
    cd -
}

# If something didn't work as you'd expect, you can undo, tune the params, and try again
undoImportFolderFromAnotherGitRepo(){
  cd "${SRC_GIT_REPO}" &&
    SRC_BRANCH_NAME_EXPORTED="${SRC_BRANCH_NAME}-exported" &&
    git checkout "${SRC_BRANCH_NAME}" &&
    git branch -D "${SRC_BRANCH_NAME_EXPORTED}" &&
  cd - &&
  cd "${DST_GIT_REPO}" &&
    git remote rm old-repo &&
    git merge --abort
  cd -
}

importFolderFromAnotherGitRepo
#undoImportFolderFromAnotherGitRepo

0

আমার ক্ষেত্রে, আমার আগের কোনও ইতিহাস থেকে স্থানান্তরিত হওয়া রেপো সংরক্ষণ করার দরকার ছিল না। আমার কাছে একই শাখার প্যাচ ছিল, অন্য দূরবর্তী থেকে

#Source directory
git remote rm origin
#Target directory
git remote add branch-name-from-old-repo ../source_directory

এই দুটি পদক্ষেপে, আমি অন্য রেপোর শাখাটি একই রেপোতে উপস্থিত হতে সক্ষম হয়েছি।

অবশেষে, লক্ষ্য রেপোর মূললাইনটি অনুসরণ করার জন্য আমি এই শাখাটি (আমি অন্যান্য রেপো থেকে আমদানি করে) সেট করেছিলাম (যাতে আমি তাদের সঠিকভাবে আলাদা করতে পারি)

git br --set-upstream-to=origin/mainline

এখন এটি এমন আচরণ করল যেন এটি অন্য একটি শাখা আমি একই রেপোর বিরুদ্ধে ঠেলে দিয়েছিলাম।


0

যদি প্রশ্নোত্তর ফাইলগুলির জন্য পাথগুলি দুটি রেপগুলিতে একই থাকে এবং আপনি কেবল একটি ফাইল বা সম্পর্কিত ফাইলের একটি ছোট সেট আনতে চান তবে এটির একটি সহজ উপায় হ'ল ব্যবহার করা git cherry-pick

প্রথম পদক্ষেপটি হ'ল অন্যান্য রেপো থেকে কমিটগুলি আপনার নিজস্ব স্থানীয় রেপো ব্যবহার করে নিয়ে আসা git fetch <remote-url>। এটি FETCH_HEADঅন্যান্য রেপো থেকে মাথা প্রতিশ্রুতিবদ্ধ দিকে ইশারা করে ছেড়ে যাবে ; যদি আপনি একটি রেফারেন্স যে কমিট সংরক্ষণ করতে ইচ্ছুক পর আপনি অন্যান্য রক্ষিত রাখে সম্পন্ন করেছি আপনার সাথে এটিকে ট্যাগ করতে পারেন git tag other-head FETCH_HEAD

তারপরে আপনাকে সেই ফাইলটির জন্য প্রাথমিক প্রতিশ্রুতি তৈরি করতে হবে (যদি এটি বিদ্যমান না থাকে) বা ফাইলটি এমন অবস্থায় আনার প্রতিশ্রুতি তৈরি করতে হবে যা আপনি আনতে চান এমন অন্যান্য রেপো থেকে প্রথম কমিটের সাহায্যে প্যাচ করতে পারে You আপনি যে ফাইলগুলি চান git cherry-pick <commit-0>তা commit-0পরিচয় করিয়ে দিয়ে একটি দিয়ে এটি করতে সক্ষম হন বা আপনার হাতে 'কমিট' তৈরি করার প্রয়োজন হতে পারে। যোগ -nচেরি-বাছাই অপশন যদি আপনি পরিবর্তন করতে প্রাথমিক করার, যেমন, কমিট ড্রপ ফাইল থেকে আনতে চাই না কমিট প্রয়োজন।

এর পরে, আপনি যেখানে প্রয়োজন সেখানে git cherry-pickআবার ব্যবহার করে পরবর্তী কমিটগুলি চালিয়ে যেতে পারেন -n। সরলতম যদি (সমস্ত করে ঠিক হয় কি আপনি চান এবং পরিচ্ছন্নভাবে প্রযোজ্য) আপনি চেরি-বাছাই কমান্ড লাইন করে সম্পূর্ণ তালিকা দিতে পারেন: git cherry-pick <commit-1> <commit-2> <commit-3> ...


0

গিট-ফিল্টার-রেপো ব্যবহার করে এটি সহজ হয়ে যায়।

যাতে সরানোর project2/sub/dirজন্য project1/sub/dir:

# Create a new repo containing only the subdirectory:
git clone project2 project2_subdir
cd project2_subdir
git filter-repo --force --path sub/dir

# Merge the new repo:
cd ../project1
git remote add project2_subdir ../project2_subdir/
git merge remotes/project2_subdir/master --allow-unrelated-histories
git remote remove project2_subdir

সরঞ্জামটি সহজভাবে ইনস্টল করতে: pip3 install git-filter-repo ( আরও বিশদ এবং README- এ বিকল্পগুলি )

# Before: (root)
.
|-- project1
|   `-- 3
`-- project2
    |-- 1
    `-- sub
        `-- dir
            `-- 2

# After: (project1)
.
├── 3
└── sub
    └── dir
        └── 2

-2

সমস্ত শাখা রক্ষণাবেক্ষণ করে এবং ইতিহাস সংরক্ষণ করে আমার জিআইটি স্ট্যাশকে গিটল্যাবে স্থানান্তরিত করতে নীচের পদ্ধতিটি method

স্থানীয়তে পুরানো সংগ্রহস্থলটি ক্লোন করুন।

git clone --bare <STASH-URL>

গিটল্যাবে একটি খালি সংগ্রহস্থল তৈরি করুন।

git push --mirror <GitLab-URL>

উপরের আমি সম্পাদন করেছি যখন আমরা আমাদের কোডটি স্ট্যাশ থেকে গিটল্যাবে স্থানান্তরিত করেছি এবং এটি খুব ভালভাবে কাজ করেছে worked

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