Git'teki dosyaları taşımak / yeniden adlandırmak ve geçmişlerini korumak mümkün müdür?


667

Git'te bir proje alt ağacını yeniden adlandırmak / taşımak istiyorum

/project/xyz

için

/components/xyz

Bir ova kullanırsam git mv project components, o zaman tüm taahhüt geçmişi xyz projectkaybolur. Bunu tarih korunacak şekilde taşımanın bir yolu var mı?



2
Sadece dosyaları dosya sistemi üzerinden test ettim ve (intellij yoluyla) taahhüt ettikten sonra daha sonra (tekrar intellij) tarihini görüntülerken tüm geçmişi (farklı bir konumda iken tarih dahil) görebilirsiniz. Intellij'in bunu yapmak için özel bir şey yapmadığını varsayıyorum, bu yüzden en azından tarihin izlenebileceğini bilmek güzel.
BT

Bir dizinin yeniden adlandırılmasını algılarken Git tarafından izlenen kurallar için, aşağıdaki cevabım bakın
VonC

Buraya bir cevap yazdım. Umarım işe yarar. stackoverflow.com/questions/10828267/…
Mahmut EFE

Yanıtlar:


651

Git, taahhüdü ile çalışmaya devam etmek yerine yeniden adlar algılar, bu nedenle kullansanız git mvda kullanmasanız da fark mvetmez.

logKomutu bir sürer --followo Sezgisel yöntem kullanarak benzer içerik aramaları, bir adlandırma ameliyattan önce geçmişini devam argüman, yani:

http://git-scm.com/docs/git-log

Geçmişin tamamını aramak için aşağıdaki komutu kullanın:

git log --follow ./path/to/file

63
Bunun bir performans değerlendirmesi olduğundan şüpheleniyorum. Tam geçmişe ihtiyacınız yoksa, içeriğin taranması daha uzun sürecektir. En kolay yol bir takma ad oluşturmak git config alias.logf "log --follow"ve yazmaktır git logf ./path/to/file.
Troels Thomsen

13
@TroelsThomsen Linus Torvalds'ın bu cevaptan bağlandığı bu e-postayı , yeniden adlandırmaları izleme vb. İzlemekten çok daha güçlü olduğu iddia edilen Git'in kasıtlı bir tasarım seçeneği olduğunu gösteriyor
Emil Lundberg

127
Bu cevap biraz yanıltıcı. Git "isimleri tespit eder" fakat oyunda çok geç kalır; soru Git'in parça adlarını nasıl değiştirdiğinizi sormaktır ve bunu okuyan biri Git'in sizin için otomatik olarak algılayıp not aldığını kolayca anlayabilir. O değil. Git'in yeniden adlandırmalarla ilgili gerçek bir kullanımı yoktur ve bunun yerine, ne olduğunu anlamaya çalışan ve nadiren doğru olan birleştirme / günlük araçları vardır. Linus, git'in neden asla doğru yolu yapmaması ve isimleri açık bir şekilde izlememesi gerektiğine dair yanlış ama şiddetli bir argümana sahiptir. Yani, burada sıkışıp kaldık.
Chris Moschini

29
Önemli: Bir dizini yeniden adlandırırsanız, örneğin bir Java paketini yeniden adlandırırken, önce 'git mv {old} {new}' komutu için ikinci, ardından değiştirilen paket dizini. Aksi takdirde git --follow parametresiyle bile tek tek dosyaları izleyemez.
nn4l

44
Linus muhtemelen çok az hata yapsa da, bu bir gibi görünüyor. Bir klasörü yeniden adlandırmak GitHub'a büyük bir deltanın yüklenmesine neden olur. Bu da klasörleri yeniden adlandırmam konusunda ihtiyatlı davranıyor ... ama bu bir programcı için oldukça büyük bir düz ceket. Bazen, bir şeyin anlamını yeniden tanımlamam veya şeylerin nasıl sınıflandırıldığını değiştirmem gerekiyor. Linus: "Başka bir deyişle, haklıyım. Her zaman haklıyım, ama bazen diğer zamanlardan daha haklıyım. Ve kahretsin, 'dosyalar önemli değil' dediğimde gerçekten haklıyım ( tm)." ... bu konuda şüphelerim var.
Gabe Halsmer

94

Öyle mümkün o havuza ait bütün tarihi boyunca yeniden adlandırılması için dosyayı neden olsa da, bir dosyayı yeniden adlandırmak ve sağlam bir geçmişi tutmak için. Bu muhtemelen sadece obsesif git-log severler içindir ve aşağıdakiler de dahil olmak üzere bazı ciddi etkileri vardır:

  • Git'i kullanırken en önemli DON'T olan paylaşılan bir geçmişi yeniden yazıyor olabilirsiniz. Havuzu başkası klonladıysa, bunu yaparak onu kıracaksınız. Baş ağrılarını önlemek için yeniden klonlamaları gerekecek. Yeniden adlandırma yeterince önemliyse bu iyi olabilir, ancak bunu dikkatlice düşünmeniz gerekir - sonuçta tüm açık kaynak topluluğunu altüst edebilirsiniz!
  • Dosyayı, geçmişte daha önce eski adını kullanarak referans aldıysanız, önceki sürümleri etkili bir şekilde bozuyorsunuz. Bunu düzeltmek için biraz daha fazla çember atlaması yapmanız gerekecek. İmkansız değil, sadece sıkıcı ve muhtemelen buna değmez.

Şimdi, hala benimleyken, muhtemelen tamamen izole edilmiş bir dosyayı yeniden adlandıran solo geliştiricisin. Kullanarak bir dosyayı taşıyalım filter-tree!

Bir dosyayı oldbir klasöre taşıyacağınızı dirve ona bir ad vereceğinizi varsayınnew

Bu ile yapılabilirdi git mv old dir/new && git add -u dir/new, ama bu tarihi bozar.

Yerine:

git filter-branch --tree-filter 'if [ -f old ]; then mkdir dir && mv old dir/new; fi' HEAD

olacaktır yinelemek her yineleme için keneler komutunu çalıştırarak, her dalında taahhüt. Bunu yaptığınızda birçok şey yanlış gidebilir. Normalde dosyanın var olup olmadığını görmek için test ederim (aksi takdirde henüz hareket etmek için orada değildir) ve daha sonra ağacı benim beğenime göre atmak için gerekli adımları uygulayın. Burada dosyaya yapılan referansları değiştirmek için dosyalar arasında geçiş yapabilirsiniz. Kendinizi nakavt edin! :)

Tamamlandığında, dosya taşınır ve günlük bozulmadan kalır. Ninja korsan gibi hissediyorsun.

Ayrıca; Mkdir dir, yalnızca dosyayı elbette yeni bir klasöre taşırsanız gereklidir. Eğer tarihinin daha önce bu klasörün oluşturulmasını önlemek olacaktır dosya var daha.


57
Obsesif bir git-log-sevgilisi olarak, bunun için gitmek olmaz. Dosyalar, zamanın bu noktalarında, dolayısıyla tarihin hiç var olmayan bir durumu yansıttığı şeklinde adlandırılmamıştır. Geçmişte hangi testlerin kırılabileceğini kim bilebilir! Önceki sürümleri kırma riski hemen hemen her durumda buna değmez.
Vincent

7
@Vincent Kesinlikle haklısın ve bu çözümün uygun olmasının mümkün olmadığı konusunda olabildiğince açık olmaya çalıştım. Ayrıca "tarih" kelimesinin iki anlamı hakkında konuştuğumuzu düşünüyorum, bu durumda ikisini de takdir ediyorum.
Øystein Steimler

6
Birinin buna ihtiyaç duyabileceği durumlar olduğunu düşünüyorum. Diyelim ki kendi kişisel şubemde, şimdi yukarı havayı birleştirmek istediğim bir şey geliştirdim. Ancak dosya adını uygun bulmuyorum, bu yüzden tüm kişisel şubem için değiştiriyorum. Bu şekilde temiz ve doğru bir geçmişi tutabilirim ve en başından doğru isme sahip olabilirim.
user2291758

3
@ user2291758 bu benim kullanım durumum. Bu daha güçlü git komutları tehlikelidir, ancak ne yaptığınızı biliyorsanız çok zorlayıcı kullanım durumları olmadığı anlamına gelmez!
philix

1
mümkünse, --index-filterağaç adlarının kullanılması çok daha hızlı olacaktır çünkü ağacın her teslimde teslim alınması ve tekrar teslim edilmesi gerekmez. --index-filterher taahhüt dizinine doğrudan etki eder.
Thomas Guyot-Sionnest

87

Hayır.

Kısa cevap HAYIR . Git'te bir dosyayı yeniden adlandırmak ve geçmişi hatırlamak mümkün değildir. Ve bu bir acı.

Söylenti git log --follow--find-copies-harderişe yarayacak, ancak dosya içeriğinde sıfır değişiklik olsa ve hamle yapılmış olsa bile benim için çalışmıyor git mv.

(Başlangıçta ben adlandırmak ve Git karıştırmış olabileceği güncelleme paketleri bir operasyonda, için Eclipse kullandım. Ama bunun için çok yaygın bir şeydir. --followBir yalnızca işe görünüyor mvyapılır ve daha sonra bir commitve mvçok uzak değildir.)

Linus, bir yazılım projesinin tüm içeriğini tek tek izlemenize gerek kalmadan bütünsel olarak anlamanız gerektiğini söylüyor. Ne yazık ki, küçük beynim bunu yapamaz.

Öyle gerçekten sinir bozucu bir çok insan sersemce Git otomatik hamle izlediği açıklamayı tekrarlayarak bildirildi. Zamanımı boşa harcadılar. Git böyle bir şey yapmaz. Tasarım gereği (!) Git hareketleri hiç takip etmez.

Benim çözüm dosyaları orijinal konumlarına geri adlandırmaktır. Yazılımı kaynak denetimine uyacak şekilde değiştirin. Git ile sadece ilk seferde doğru "gitmeniz" gerekiyor.

Ne yazık ki, bu Eclipse kırıyor, hangi kullanmak gibi görünüyor --follow. git log --followbazen karmaşık yeniden adlandırma geçmişleri olan dosyaların tam geçmişini göstermese de git log. (Sebebini bilmiyorum.)

(Geri dönüp eski işleri tavsiye eden çok akıllıca kesmek var, ancak oldukça korkutucu. Bkz. GitHub-Gist: emiller / git-mv-geçmiş ile .)


2
Doğru olduğuna inanıyorum. Laravel 5 projemin kaynağını yeniden biçimlendirmek için php-cs-fixer'ı kullanmaya çalışıyordum, ancak uygulama klasörünün küçük harfiyle eşleşecek şekilde ad alanı maddelerinin büyük harf kullanımını değiştirmekte ısrar ediyor. Ancak ad alanları (veya besteci otomatik yüklemeleri) yalnızca CamelCase ile çalışır. Klasör App büyük harf değiştirmek gerekir ama bu benim değişiklikleri kaybolmasına neden olur. Bu en önemsiz örneklerdir, ancak git sezgisel yönteminin en basit isim değişikliklerini bile nasıl takip edemediğini gösterir (--follow ve --find-copies-harder kural değil, kural değil).
Zack Morris

6
git -1, yıkım +1
Cosmin

Bu hala doğru mu? Şimdilik tfs ile kalmamın daha fazla nedeni, taşınan / yeniden adlandırılan bir dosyanın geçmişini tutmak büyük bir projede şart.
Cesar

@ Sezar Eğer "geçmişi hatırla" demekle, "günlüğü görüntülerken isimleri takip et" anlamına gelirse (umursamamız gereken tek yararlı şey), o zaman bu asla doğru değildi! Git yeniden adlandırma işlemlerini "kaydetmez", ancak araçlar bunları kolayca algılayabilir ve bize yeniden adlandırma ve taşıma işlemleri sunabilir. Birisi için "işe yaramazsa", kullandığı araçları değiştirmelidir. Bu yeteneğe sahip birçok harika Git GUI var.
Muhammed Dehghan

Kısa cevap Evet. Git geçerli sürümü "git log --follow" özelliğini de destekler. ve ben @MohammadDehghan katılıyorum
insung

42
git log --follow [file]

geçmişi yeniden adlandırmalarla gösterecektir.


29
Bu, dosyayı değiştirmeye başlamadan önce yalnızca yeniden adlandırma yapmanızı gerektirir. Dosyayı (kabukta) taşır ve değiştirirseniz, tüm bahisler kapalı olur.
yoyo

22
@yoyo: çünkü git yeniden adlandırmaları izlemez, onları algılar. Bir git mvtemelde yapar git rm && git add. -M90/ --find-renames=90% 90 özdeş olduğunda yeniden adlandırılacak bir dosya / gibi düşünmek için seçenekler vardır .
vdboor

22

Yaparım:

git mv {old} {new}
git add -u {new}

3
-U benim için hiçbir şey yapmıyor gibi görünüyor, tarihi güncellemesi gerekiyor mu?
jeremy

1
Belki -Abunun yerine davranışını mı istiyorsunuz ? Tekrar bakın, buraya bakın: git-scm.com/docs/git-add
James M. Greene

1
Dosyaları ekler, ancak geçmişi gitmez, böylece 'git log file name' tam geçmişi gösterir. Tam geçmişi yalnızca --follow seçeneğini hala kullanırsanız gösterir.
jeremy

3
Bir içerme dizini (mv kullanarak git mv değil) taşındı ve daha sonra yeniden adlandırılmış dosyaları içinde #include yolları çok değişti karmaşık bir refactor yaptım. git geçmişi takip etmek için yeterli benzerlik bulamadı. Ama git add -u sadece ihtiyacım olan şeydi. git durumu artık "yeniden adlandırıldı" ifadesini gösterir; burada daha önce "silinmiş" ve "yeni dosya" gösterilir.
AndyJost

1
SO üzerinde amacına hitap eden birçok soru var git add -u. Git belgeleri yararsız olma eğilimindedir ve bakmak istediğim son yer. İşte git add -ueylem gösteren bir yazı : stackoverflow.com/a/2117202 .
nobar

17

Git'te bir proje alt ağacını yeniden adlandırmak / taşımak istiyorum

/project/xyz

için

/ Bileşenleri / xyz

Bir ova kullanırsam git mv project components, xyzproje için tüm taahhüt geçmişi kaybolur.

Hayır (8 yıl sonra Git 2.19, Q3 2018), çünkü Git dizin yeniden adlandırmasını algılar ve bu artık daha iyi belgelenmiştir.

Bkz. Taahhüt b00bf1c , taahhüt 1634688 , taahhüt 0661e49 , taahhüt 4d34dff , taahhüt 983f464 , taahhüt c840e1a , taahhüt 9929430 (27 Haziran 2018) ve taahhüt d4e8062 , taahhüt 5dacd4a (25 Haz 2018), Elijah Newren ( newren) .
(Tarafından Birleştirilmiş - Junio C Hamano gitster- içinde 0ce5a69 taahhüt 2018, 24 Tem)

Şimdi şu şekilde açıklanmaktadır Documentation/technical/directory-rename-detection.txt:

Misal:

Ne zaman tüm x/a, x/bve x/ctaşındı z/a, z/bve z/cbüyük olasılıkla olduğunu, x/dbu arada eklenen da taşımak isteyeyim z/dbütün dizin 'o ipucu alarak x' taşındı ' z'.

Ancak bunlar diğer birçok örnektir, örneğin:

geçmişin bir tarafı yeniden adlandırılır x -> z, diğeri ise bir dosyayı yeniden adlandırır x/eve birleşmenin geçişli yeniden adlandırma yapmasına neden olur.

Dizin yeniden adlandırma algılamasını basitleştirmek için bu kurallar Git tarafından uygulanır:

dizin yeniden adlandırma algılaması uygulandığında birkaç temel kural sınırı vardır:

  1. Bir dizinin her iki tarafında hala belirli bir dizin varsa, yeniden adlandırıldığını düşünmüyoruz.
  2. Yeniden adlandırılacak dosyaların bir alt kümesinde bir dosya veya dizin varsa (veya birbirlerinin yolundaysa), söz konusu alt yollar için dizin yeniden adlandırmasını "kapatın" ve çakışmayı kullanıcıya bildirin .
  3. Geçmişin diğer tarafı, geçmişinizin tarafının yeniden adlandırdığı bir yol için bir dizin yeniden adlandırdıysa, örtük dizin adlarının tarihinin diğer tarafından bu yeniden adlandırmayı yok sayın (ancak kullanıcıyı uyarın).

Şunu da gösteren birçok test görebilirsiniz t/t6043-merge-rename-directories.sh:

  • a) Yeniden adlandırmalar bir dizini iki veya daha fazla klasöre ayırırsa, en çok yeniden adlandırılan dizin "kazanır".
  • b) Bir yolun her iki tarafında bir yeniden adlandırma kaynağıysa, bir yol için dizin yeniden adlandırma algılamasından kaçının.
  • c) Örtük dizin yeniden adlarını dizinlere yalnızca geçmişin diğer tarafı yeniden adlandırma yapan kişi ise dizinlere uygulayın.

15

Amaç

  • Kullanım (ilham Smar , ödünç Exherbo )git am
  • Kopyalanan / taşınan dosyaların işleme geçmişini ekle
  • Bir dizinden diğerine
  • Ya da bir depodan diğerine

sınırlama

  • Etiketler ve şubeler tutulmaz
  • Yol dosyasının yeniden adlandırılmasında geçmiş kesiliyor (dizin yeniden adlandırılıyor)

özet

  1. Kullanarak geçmişi e-posta biçiminde ayıklayın
    git log --pretty=email -p --reverse --full-index --binary
  2. Dosya ağacını yeniden düzenleyin ve dosya adlarını güncelleyin
  3. Kullanarak yeni geçmiş ekle
    cat extracted-history | git am --committer-date-is-author-date

1. Geçmişi e-posta biçiminde ayıklayın

Örnek: hulasası geçmişi file3, file4vefile5

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

Hedefi ayarlayın / temizleyin

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

Her dosyanın geçmişini e-posta biçiminde ayıklayın

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"' {} ';'

Ne yazık ki seçenek --followveya --find-copies-harderbirleştirilemez --reverse. Dosya yeniden adlandırıldığında (veya bir üst dizin yeniden adlandırıldığında) geçmişin kesilmesinin nedeni budur.

E-posta biçimindeki geçici geçmiş:

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

Dan Bonachea , git günlüğü komutunun döngülerini bu ilk adımda tersine çevirmeyi önerir: dosya başına git günlüğünü çalıştırmak yerine, komut satırında bir dosya listesi ile tam olarak bir kez çalıştırın ve tek bir birleştirilmiş günlük oluşturun. Bu şekilde, birden fazla dosyayı değiştirmenin sonuçta tek bir taahhüt olarak kalması ve tüm yeni taahhütlerin orijinal göreceli sıralarının korunması söz konusudur. Bunun ayrıca (şimdi birleştirilmiş) günlüğünde dosya adlarını yeniden yazarken aşağıdaki ikinci adımda değişiklik yapılmasını gerektirir.


2. Dosya ağacını yeniden düzenleyin ve dosya adlarını güncelleyin

Bu üç dosyayı başka bir repoda taşımak istediğinizi varsayalım (aynı repo olabilir).

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

Bu nedenle dosyalarınızı yeniden düzenleyin:

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

Geçici geçmişiniz şimdi:

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

Geçmişteki dosya adlarını da değiştirin:

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

3. Yeni geçmiş uygulayın

Diğer repo:

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

Geçici geçmiş dosyalarından taahhütleri uygula:

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

--committer-date-is-author-dateorijinal taahhüt zaman damgalarını korur ( Dan Bonachea'nın yorumu).

Diğer repo şimdi:

my_other_repo
├── dirF
│   ├── file55
│   └── file56
├── dirB
│   ├── dirB1
│   │   ├── file33
│   │   └── file44
│   └── dirB2
│        └── file5
└── dirH
    └── file77

Kullanılmaya git statushazır taahhüt miktarını görmek için kullanın :-)


Ek numara: Reponuz içindeki yeniden adlandırılmış / taşınmış dosyaları kontrol edin

Yeniden adlandırılan dosyaları listelemek için:

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

Daha fazla özelleştirme: veya git logseçeneklerini kullanarak komutu tamamlayabilirsiniz . İlk iki sütunu, '{. * =>. *}' Deseninin tamamını kullanarak ve selamlayarak da kaldırabilirsiniz .--find-copies-harder--reversecut -f3-

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

4
DİKKAT: Bu teknik, 2 veya daha fazla dosyayı ayrı parçalanmış komutlara dönüştürmeyi taahhüt eder ve ayrıca dosya adına göre sıralayarak sıralarını karıştırır (böylece bir orijinal işlemin parçaları doğrusal geçmişte bitişik görünmez). Sonuçta ortaya çıkan geçmiş yalnızca dosya bazında "doğrudur". Birden fazla dosya taşıyorsanız, sonuç geçmişindeki yeni işlemlerin HİÇBİRİ, orijinal depo geçmişinde var olan taşınan dosyaların tutarlı bir anlık görüntüsünü temsil etmez.
Dan Bonachea

2
Merhaba @ DanBonachea. İlginç geri bildiriminiz için teşekkür ederiz. Başarıyla bu tekniği (hatta yeniden adlandırılmış dosyalar ve dizinler arasında taşınan dosyalar ile) kullanarak birkaç dosya içeren bazı depolar geçirdik. Bu cevapta neyi değiştirmek için önerirsin? Bu cevabın üstüne, bu tekniğin sınırlamalarını açıklayan bir UYARI başlığı eklememiz gerektiğini düşünüyor musunuz? Şerefe
olibre

2
Bu tekniği 1. adımdaki git log oluşturma komutunun döngülerini tersine çevirerek sorunu önlemek için uyarladım. git log'u dosya başına bir kez çalıştırmak yerine, komut satırında bir dosya listesiyle tam olarak bir kez çalıştırın ve tek bir birleşik günlük oluşturun. Bu şekilde, 2 veya daha fazla dosyayı değiştirmenin sonuçta tek bir taahhüt kalmasını taahhüt eder ve tüm yeni taahhütler orijinal göreceli sıralarını korur. Bunun, (şimdi birleştirilmiş) günlüğünde dosya adlarını yeniden yazarken 2. adımda da değişiklik yapılmasını gerektirdiğini unutmayın. Ben de orijinal tamamlama zaman damgalarını korumak için git am --committer-date-is-author-date kullandım.
Dan Bonachea

1
Deneyimleriniz ve paylaşımınız için teşekkür ederiz. Diğer okuyucular için cevabı biraz güncelledim. Ancak işleminizi test etmek için zaman aldım. Komut satırı örnekleri vermek isterseniz, lütfen bu yanıtı düzenlemekten çekinmeyin. Şerefe;)
olibre

4

Kodu üst dizine ve geçmişini korumak için bu çok adımlı işlemi izledim.

Adım 0: Koruma için 'master'dan bir' tarih 'dalı oluşturuldu

Adım 1: Geçmişi yeniden yazmak için git-filter-repo aracı kullanıldı. Aşağıdaki bu komut 'FolderwithContentOfInterest' klasörünü bir seviye yukarı taşıdı ve ilgili işleme geçmişini değiştirdi

git filter-repo --path-rename ParentFolder/FolderwithContentOfInterest/:FolderwithContentOfInterest/ --force

Adım 2: Bu zamana kadar GitHub deposu uzak depo yolunu kaybetti. Uzaktan referans eklendi

git remote add origin git@github.com:MyCompany/MyRepo.git

3. Adım: Depo hakkındaki bilgileri alın

git pull

Adım 4: Yerel kayıp dalı başlangıç ​​şubesine bağlayın

git branch --set-upstream-to=origin/history history

Adım 5: İstenirse klasör yapısı için adres birleştirme çakışması

Adım 6: İt !!

git push

Not: Değiştirilen geçmiş ve taşınan klasör zaten taahhütlü görünüyor. enter code here

Bitti. Kod, geçmişini koruyarak üst / istenen dizine taşınır!


2

Git'in çekirdeği, Git tesisatının isimleri takip etmesine rağmen, Git günlüğü "porselen" ile görüntülediğiniz geçmiş isterseniz bunları algılayabilir.

Belirli bir git logkullanım için -M seçeneğini kullanın:

git log -p -M

Git'in geçerli bir sürümü ile.

Bu, diğer komutlar için git diffde geçerlidir.

Karşılaştırmaları az çok titiz yapmak için seçenekler var. Bir dosyayı aynı anda önemli değişiklikler yapmadan yeniden adlandırırsanız Git günlüğü ve arkadaşlarının yeniden adlandırmayı algılamaları kolaylaşır. Bu nedenle bazı insanlar dosyaları bir işlemde yeniden adlandırır ve başka bir işlemde değiştirir.

Git'ten dosyaların nerede yeniden adlandırıldığını bulmasını istediğinizde CPU kullanımında bir maliyet söz konusudur, bu nedenle kullansanız da kullanmasanız da size bağlıdır.

Geçmişinizin her zaman belirli bir depoda yeniden adlandırma algılamasıyla raporlanmasını istiyorsanız şunları kullanabilirsiniz:

git config fark.renimler 1

Başka bir dizinden hareketli Dosyalar edilir algıladı. İşte bir örnek:

commit c3ee8dfb01e357eba1ab18003be1490a46325992
Author: John S. Gruber <JohnSGruber@gmail.com>
Date:   Wed Feb 22 22:20:19 2017 -0500

    test rename again

diff --git a/yyy/power.py b/zzz/power.py
similarity index 100%
rename from yyy/power.py
rename to zzz/power.py

commit ae181377154eca800832087500c258a20c95d1c3
Author: John S. Gruber <JohnSGruber@gmail.com>
Date:   Wed Feb 22 22:19:17 2017 -0500

    rename test

diff --git a/power.py b/yyy/power.py
similarity index 100%
rename from power.py
rename to yyy/power.py

Bunun farklý kullanýldýðýnda farklý olduðunda çalþtýðýný lütfen unutmayýn git log. Örneğin:

$ git diff HEAD c3ee8df
diff --git a/power.py b/zzz/power.py
similarity index 100%
rename from power.py
rename to zzz/power.py

Deneme olarak, bir özellik dalındaki bir dosyada küçük bir değişiklik yaptım ve bunu işledim ve ardından ana dalda dosyayı yeniden adlandırdım, taahhüt ettim ve sonra dosyanın başka bir bölümünde küçük bir değişiklik yaptım ve bunu taahhüt ettim. Özellik dalına gittiğimde ve master'dan birleştiğimde, birleştirme dosyayı yeniden adlandırdı ve değişiklikleri birleştirdi. İşte birleştirme çıktısı:

 $ git merge -v master
 Auto-merging single
 Merge made by the 'recursive' strategy.
  one => single | 4 ++++
  1 file changed, 4 insertions(+)
  rename one => single (67%)

Sonuç, dosya yeniden adlandırılmış ve her iki metin değişikliği yapılmış bir çalışma dizinidir. Bu nedenle Git'in adlarını açıkça izlememesine rağmen doğru şeyi yapması mümkündür.

Bu eski bir soruya geç bir cevaptır, bu nedenle diğer cevaplar o zaman Git sürümü için doğru olabilir.


1

Önce sadece bir yeniden adlandırma ile bağımsız bir taahhüt oluşturun.

Daha sonra dosya içeriğinde meydana gelen her türlü değişiklik ayrı taahhütte bulunur.


1

Bir dizin veya dosyayı yeniden adlandırmak için (karmaşık durumlar hakkında çok şey bilmiyorum, bu yüzden bazı uyarılar olabilir):

git filter-repo --path-rename OLD_NAME:NEW_NAME

Söz konusu dosyalarda bir dizini yeniden adlandırmak için (geri aramaları kullanmak mümkündür, ancak nasıl yapacağımı bilmiyorum):

git filter-repo --replace-text expressions.txt

expressions.txtgibi satırlarla dolu bir dosyadır literal:OLD_NAME==>NEW_NAME(Python'un RE'sini ile regex:veya glob ile kullanmak mümkündür glob:).

İşlemlerin mesajlarındaki bir dizini yeniden adlandırmak için:

git-filter-repo --message-callback 'return message.replace(b"OLD_NAME", b"NEW_NAME")'

Python'un düzenli ifadeleri de desteklenir, ancak Python'da manuel olarak yazılmalıdır.

Depo orijinal değilse, uzaktan kumanda olmadan, --forceyeniden yazmaya zorlamak için eklemeniz gerekir. (Bunu yapmadan önce deponuzun bir yedeğini oluşturmak isteyebilirsiniz.)

Ref'leri korumak istemiyorsanız (Git GUI'nin şube geçmişinde görüntülenirler) eklemeniz gerekir --replace-refs delete-no-add.


0

Dosyayı ve sahneyi şunlarla taşıyın :

git add .

Taahhüt etmeden önce durumu kontrol edebilirsiniz:

git status

Bu gösterecektir:

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    old-folder/file.txt -> new-folder/file.txt

Git sürüm 2.26.1 ile test ettim.

Çıkarılan GitHub Yardım Sayfa .


-3

Dosyaları hareket ettiriyorum ve sonra

git add -A

hangi sataging alanına tüm silinen / yeni dosyaları koymak. Burada git dosyanın taşındığını fark eder.

git commit -m "my message"
git push

Nedenini bilmiyorum ama bu benim için işe yarıyor.


Buradaki hile, bir şeyi değiştirip Ctrl + Z tuşlarına bassanız bile, tarihin kırılacağı tek bir harfi değiştirmek zorunda olmamanızdır. Bu durumda bir şey yazarsanız, dosyayı geri döndürün ve tekrar taşıyın ve tek bir eklenti yapın.
Ocak'ta Xelian
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.