Ця відповідь дає цікаві команди на основі git am
подаються та представлені, використовуючи приклади, крок за кроком.
Об'єктивна
- Ви хочете перемістити деякі або всі файли з одного сховища в інше.
- Ви хочете зберегти їх історію.
- Але вам не байдуже зберігати теги та гілки.
- Ви приймаєте обмежену історію для перейменованих файлів (та файлів у перейменованих каталогах).
Порядок
- Витягнути історію у форматі електронної пошти за допомогою
git log --pretty=email -p --reverse --full-index --binary
- Реорганізуйте дерево файлів та оновіть зміни назви файлів в історії [необов’язково]
- Застосувати нову історію за допомогою
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
2. Реорганізуйте дерево файлів та оновіть зміну імені файлу в історії [необов’язково]
Припустимо, ви хочете перемістити ці три файли в інший репо-файл (може бути тим же репо).
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"' {} ';'
Примітка. Це переписує історію, щоб відобразити зміну шляху та назви файлу.
(тобто зміна нового місцезнаходження / назви в рамках нового репо)
3. Застосовуйте нову історію
Ваше інше репо:
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 '{.* => .*}'