РЕДАКТИРОВАТЬ: вы можете добавить дополнительные echo $ix >> bb/bb.txt
в цикл for
в сценарии testgit.sh
в OP, чтобы выходные данные в этом сообщении совпадали.
Хорошо, я полагаю, что так и должно быть - по крайней мере, в отношении ОП (где у нас пока нет удаленных репо); сначала скопируйте oldrepo:
cp -a oldrepo_git oldrepo_filt_git
Тогда, очевидно, нам нужно удалить все ненужное в скопированном oldrepo, используя git filter-branch
в сочетании с git rm
- часть этой команды, которую я нашел здесь: Отсоединение многих подкаталогов в новый, отдельный репозиторий Git
cd oldrepo_filt_git
git filter-branch --index-filter "git rm --cached --ignore-unmatch -r $(bash -O extglob -c 'ls -xd !(a*)')" --prune-empty -- --all
Обратите внимание, поскольку здесь мы хотим сообщить git rm
, что удалять, мы хотим указать, что мы не хотим сохранять, как обратное тому, что мы хотим сохранить; и здесь я хочу сохранить файл a.txt
и папку aa
- таким образом, глобальное совпадение будет a*
. Тогда вам нужна функция bash
extglob, чтобы получить это; так что если весь список:
$ ls
a.txt aa b.txt bb README
... тогда раздел extglob, который даст нам только имена файлов / папок для удаления, даст:
$ bash -O extglob -c 'ls -xd !(a*)'
b.txt bb README
Итак, после git filter-branch
запускается команда:
$ git filter-branch --index-filter "git rm --cached --ignore-unmatch -r $(bash -O extglob -c 'ls -xd !(a*)')" --prune-empty -- --all
Rewrite 252bf7ff5f385dad880240d5d80e68f24ae09b59 (1/8) (0 seconds passed, remaining 0 predicted) rm 'README'
Rewrite f318d9712cd7aacdb5dd45febbcdbbce6b741e08 (2/8) (1 seconds passed, remaining 3 predicted) rm 'README'
Rewrite 00b62e7da8784d45850d7483cbea88fdc4aa844c (2/8) (1 seconds passed, remaining 3 predicted) rm 'README'
rm 'b.txt'
rm 'bb/bb.txt'
Rewrite c618eff47d38412c54a8381a5bacc921bddefe2d (2/8) (1 seconds passed, remaining 3 predicted) rm 'README'
rm 'b.txt'
rm 'bb/bb.txt'
Rewrite 2cada8d822d83f37bdc4a37bcfb03047c1cc1ded (5/8) (3 seconds passed, remaining 1 predicted) rm 'README'
rm 'b.txt'
rm 'bb/bb.txt'
Rewrite 7b296b70018f4105f190d06ed4d9c58e3f80532f (5/8) (3 seconds passed, remaining 1 predicted) rm 'README'
rm 'b.txt'
rm 'bb/bb.txt'
Rewrite 18a1ad1d35cd8573c39485d0a29b630325f9727d (7/8) (5 seconds passed, remaining 0 predicted) rm 'README'
rm 'b.txt'
rm 'bb/bb.txt'
Rewrite 2ffbbf03d51363f1ced3aaaf000d5921c9d8b919 (7/8) (5 seconds passed, remaining 0 predicted) rm 'README'
rm 'b.txt'
rm 'bb/bb.txt'
Ref 'refs/heads/master' was rewritten
Ref 'refs/heads/testbranch' was rewritten
... у нас есть:
$ git log --oneline --graph --stat
* 31cd8b5 (HEAD -> master) Merge branch 'testbranch'
|\
| * 42b153d (testbranch) change 5 made
| | a.txt | 1 +
| | aa/aa.txt | 1 +
| | aa/ab.txt | 1 +
| | 3 files changed, 3 insertions(+)
| * ff1be9d change 4 made
| | a.txt | 1 +
| | aa/aa.txt | 1 +
| | aa/ab.txt | 1 +
| | 3 files changed, 3 insertions(+)
| * 90f050c change 3 made
| | a.txt | 1 +
| | aa/aa.txt | 1 +
| | aa/ab.txt | 1 +
| | 3 files changed, 3 insertions(+)
| * d2d2136 change 2 made
| | a.txt | 1 +
| | aa/aa.txt | 1 +
| | aa/ab.txt | 1 +
| | 3 files changed, 3 insertions(+)
| * ab237ac change 1 made
|/
| a.txt | 1 +
| aa/aa.txt | 1 +
| aa/ab.txt | 1 +
| 3 files changed, 3 insertions(+)
* ea0a32d added a.txt
a.txt | 1 +
1 file changed, 1 insertion(+)
... что подтверждает, что это отфильтрованное состояние репозитория, который я хотел - и я думаю, это я бы хотел объединить с моим newrepo_git
сейчас.
Хорошо, получается, я не совсем хочу "сливаться" с newrepo_git
, я хочу "присоединиться" - большую часть информации я нашел в Присоединяйтесь к двум репозиториям Git и сохраняйте исходные даты фиксации. - axiac @ web
Итак, сначала мы изменили каталог на newrepo:
cd ../newrepo_git
Обратите внимание, что на данный момент большинство ресурсов онлайн будут рекомендовать:
git remote add oldrepo ../oldrepo_filt_git/
git pull oldrepo master --allow-unrelated-histories
... но это приведет к истории с двумя корнями - а это не то, что я хочу:
$ git log --oneline --graph --stat
* 845c81e (HEAD -> master) Merge branch 'master' of ../oldrepo_filt_git
|\
| * 31cd8b5 (oldrepo/master) Merge branch 'testbranch'
| |\
| | * 42b153d (oldrepo/testbranch) change 5 made
| | | a.txt | 1 +
| | | aa/aa.txt | 1 +
| | | aa/ab.txt | 1 +
| | | 3 files changed, 3 insertions(+)
| | * ff1be9d change 4 made
| | | a.txt | 1 +
| | | aa/aa.txt | 1 +
| | | aa/ab.txt | 1 +
| | | 3 files changed, 3 insertions(+)
| | * 90f050c change 3 made
| | | a.txt | 1 +
| | | aa/aa.txt | 1 +
| | | aa/ab.txt | 1 +
| | | 3 files changed, 3 insertions(+)
| | * d2d2136 change 2 made
| | | a.txt | 1 +
| | | aa/aa.txt | 1 +
| | | aa/ab.txt | 1 +
| | | 3 files changed, 3 insertions(+)
| | * ab237ac change 1 made
| |/
| | a.txt | 1 +
| | aa/aa.txt | 1 +
| | aa/ab.txt | 1 +
| | 3 files changed, 3 insertions(+)
| * ea0a32d added a.txt
| a.txt | 1 +
| 1 file changed, 1 insertion(+)
* 8e99c2d Initial commit by Bob
README | 1 +
1 file changed, 1 insertion(+)
Вместо этого я хочу, чтобы коммит ea0a32d added a.txt
следовал / проистекает из 8e99c2d Initial commit by Bob
->, что будет «объединением» репозиториев, упомянутых ранее.
Обратите внимание, что вы можете сделать git format-patch --root HEAD -o ../
из oldrepo_git
, а затем импортировать патчи в newrepo_git
с for ix in ../*.patch; do echo $ix; git am -k < $ix; done
- но это не сохранит историю слияния (вся история будет сглажена )!
Итак, чтобы сделать правильное «соединение», вместо этого я сначала делаю выборку:
$ git remote add old-repo ../oldrepo_filt_git
$ git fetch old-repo
warning: no common commits
remote: Enumerating objects: 29, done.
remote: Counting objects: 100% (29/29), done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 29 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (29/29), done.
From ../oldrepo_filt_git
* [new branch] master -> old-repo/master
* [new branch] testbranch -> old-repo/testbranch
... затем добавление и переименование веток (и сохранение временных меток в /tmp/hashlist
), как рекомендовано в посте, - и затем cherry-pick первый коммит в old-repo:
$ git branch oldrepo-head old-repo/master
Branch 'oldrepo-head' set up to track remote branch 'master' from 'old-repo'.
$ git branch oldrepo-root $(git log oldrepo-head --reverse --pretty=%H | head -n 1)
$ git log --pretty='%T %ct' ..oldrepo-head > /tmp/hashlist
$ git branch -m master new-master
$ git cherry-pick --strategy-option=theirs oldrepo-root
[new-master 427cf77] added a.txt
Author: tester <tester@example.com>
Date: Mon May 27 14:31:10 2019 +0200
1 file changed, 1 insertion(+)
create mode 100644 a.txt
На данный момент состояние репо:
$ git log --oneline --graph
* 427cf77 (HEAD -> new-master) added a.txt
* 8e99c2d Initial commit by Bob
Теперь мы можем выполнить ребазинг - обратите внимание, что в цитируемом сообщении они получают здесь ошибку, но для этого конкретного примера, похоже, она работает без ошибки:
$ git rebase --preserve-merges --onto new-master --root oldrepo-head
Successfully rebased and updated refs/heads/oldrepo-head.
На данный момент история newrepo почти - единственная проблема в том, что метки времени фиксации отличаются:
$ git log --graph --pretty=fuller
* commit 61fbe54721a9432e91e48917ed036f55da4105a4 (HEAD -> oldrepo-head)
|\ Merge: 427cf77 f8e8f8a
| | Author: tester <tester@example.com>
| | AuthorDate: Mon May 27 14:32:10 2019 +0200
| | Commit: bob <bob@example.com>
| | CommitDate: Tue May 28 12:57:00 2019 +0200
| |
| | Merge branch 'testbranch'
| |
| * commit f8e8f8aedaa7bc999bdfdd49542c9ee04edb770c
| | Author: tester <tester@example.com>
| | AuthorDate: Mon May 27 14:32:00 2019 +0200
| | Commit: bob <bob@example.com>
| | CommitDate: Tue May 28 12:56:58 2019 +0200
| |
| | change 5 made
| |
| * commit b084029040d6596e0795e7567b2684dc59c02241
| | Author: tester <tester@example.com>
| | AuthorDate: Mon May 27 14:31:50 2019 +0200
| | Commit: bob <bob@example.com>
| | CommitDate: Tue May 28 12:56:56 2019 +0200
| |
| | change 4 made
| |
| * commit b62dabca3a46efbe76edb10591935db136f74aaa
| | Author: tester <tester@example.com>
| | AuthorDate: Mon May 27 14:31:40 2019 +0200
| | Commit: bob <bob@example.com>
| | CommitDate: Tue May 28 12:56:54 2019 +0200
| |
| | change 3 made
| |
| * commit 252f3e9697b87b4f59cd0a74681ef25401340fcf
| | Author: tester <tester@example.com>
| | AuthorDate: Mon May 27 14:31:30 2019 +0200
| | Commit: bob <bob@example.com>
| | CommitDate: Tue May 28 12:56:51 2019 +0200
| |
| | change 2 made
| |
| * commit c382c8a713489ca0e5dc106bed29fdce379952b0
|/ Author: tester <tester@example.com>
| AuthorDate: Mon May 27 14:31:20 2019 +0200
| Commit: bob <bob@example.com>
| CommitDate: Tue May 28 12:56:49 2019 +0200
|
| change 1 made
|
* commit 427cf77417a2406db5dd6a0e9bd4fb60542f2ee1 (new-master)
| Author: tester <tester@example.com>
| AuthorDate: Mon May 27 14:31:10 2019 +0200
| Commit: bob <bob@example.com>
| CommitDate: Tue May 28 12:55:43 2019 +0200
|
| added a.txt
|
* commit 8e99c2d71048b4999d012b33d34386351d6d0fef
Author: bob <bob@example.com>
AuthorDate: Mon May 27 14:31:00 2019 +0200
Commit: bob <bob@example.com>
CommitDate: Mon May 27 14:31:00 2019 +0200
Initial commit by Bob
У них такая же проблема и в цитируемом сообщении, и предлагается использовать filter-branch
, чтобы переписать метки времени фиксации, чтобы они совпадали с метками времени автора:
$ git filter-branch --env-filter 'export GIT_COMMITTER_DATE=$(fgrep -m 1 $(git log -1 --pretty=%T $GIT_COMMIT) /tmp/hashlist | cut -d" " -f2)' new-master..oldrepo-head
Rewrite 61fbe54721a9432e91e48917ed036f55da4105a4 (3/6) (1 seconds passed, remaining 1 predicted)
Ref 'refs/heads/oldrepo-head' was rewritten
... однако, у меня это не сработало, потому что к настоящему времени хеши коммитов изменились по сравнению с тем, что было в /tmp/hashlist
.
Итак, я использовал более простой подход - просто filter-branch
читайте метку даты автора при каждом коммите и копируйте / повторно применяйте его как дату коммиттера (заметьте, я здесь использую -f
, чтобы компенсировать эффекты предыдущего filter-branch
, в противном случае появляется сообщение «Невозможно создать новую резервную копию. Принудительно перезаписать резервную копию с помощью -f»):
$ git filter-branch -f --env-filter 'export GIT_COMMITTER_DATE=$(git log -1 --pretty=%at $GIT_COMMIT)' new-master..oldrepo-head
Rewrite f2b2385d85c74dbf0cbf8fabc02ec30cb50d8f2a (3/6) (1 seconds passed, remaining 1 predicted)
Ref 'refs/heads/oldrepo-head' was rewritten
На данный момент мы можем видеть, что состояние репо почти , как мне нужно - за исключением первого коммита oldrepo, в котором не изменена временная метка коммита; поэтому я попробую еще раз:
sd@DESKTOP-RO11QOC MSYS /c/Users/sd/AppData/Local/Temp/newrepo_git
$ git filter-branch -f --env-filter 'export GIT_COMMITTER_DATE=$(git log -1 --pretty=%at $GIT_COMMIT)' 427cf77417a
You must specify a ref to rewrite.
sd@DESKTOP-RO11QOC MSYS /c/Users/sd/AppData/Local/Temp/newrepo_git
$ git filter-branch -f --env-filter 'export GIT_COMMITTER_DATE=$(git log -1 --pretty=%at $GIT_COMMIT)' new-master
Rewrite 427cf77417a2406db5dd6a0e9bd4fb60542f2ee1 (2/2) (0 seconds passed, remaining 0 predicted)
Ref 'refs/heads/new-master' was rewritten
... но он все равно показывает ту же разницу между временными метками в журнале:
$ git log --graph --stat --pretty=fuller
* commit cdaa4b82f3833770a9051a2490487548603e3af8 (HEAD -> oldrepo-head)
|\ Merge: 427cf77 9bfc6cd
| | Author: tester <tester@example.com>
| | AuthorDate: Mon May 27 14:32:10 2019 +0200
| | Commit: bob <bob@example.com>
| | CommitDate: Mon May 27 14:32:10 2019 +0200
| |
| | Merge branch 'testbranch'
| |
...
* commit 427cf77417a2406db5dd6a0e9bd4fb60542f2ee1 (refs/original/refs/heads/new-master)
| Author: tester <tester@example.com>
| AuthorDate: Mon May 27 14:31:10 2019 +0200
| Commit: bob <bob@example.com>
| CommitDate: Tue May 28 12:55:43 2019 +0200
|
| added a.txt
|
| a.txt | 1 +
| 1 file changed, 1 insertion(+)
...
В любом случае, теперь мы должны "очистить", как рекомендовано в посте:
$ git branch -m oldrepo-head master
$ git branch -D oldrepo-root
Deleted branch oldrepo-root (was ea0a32d).
$ git branch -D new-master
Deleted branch new-master (was 4ac225e).
$ rm .git/refs/original/refs/heads/new-master
$ git remote remove old-repo
И, наконец, мне удалось переписать временную метку коммита для коммита 427cf774, добавив туда временную ветвь (так как ветвь фильтра нуждается в ссылке, он, по-видимому, не может использовать хеш коммита напрямую) и использовав ее для указания tmp^..tmp
как диапазон ответвления фильтра:
$ git branch tmp 427cf774
$ git filter-branch -f --env-filter 'export GIT_COMMITTER_DATE=$(git log -1 --pretty=%at $GIT_COMMIT)' tmp^..tmp
Rewrite 427cf77417a2406db5dd6a0e9bd4fb60542f2ee1 (1/1) (0 seconds passed, remaining 0 predicted)
Ref 'refs/heads/tmp' was rewritten
$ git log --graph --stat --pretty=fuller tmp
* commit 4ac225e308e280e3a96be0168c6e9dece44d4979 (tmp)
| Author: tester <tester@example.com>
| AuthorDate: Mon May 27 14:31:10 2019 +0200
| Commit: bob <bob@example.com>
| CommitDate: Mon May 27 14:31:10 2019 +0200
|
| added a.txt
|
| a.txt | 1 +
| 1 file changed, 1 insertion(+)
|
...
$ git branch -D tmp
Deleted branch tmp (was 4ac225e).
... и, наконец, я вижу, что newrepo содержит коммиты oldrepo, как я их себе представлял:
$ git log --graph --stat --pretty=fuller
* commit cdaa4b82f3833770a9051a2490487548603e3af8
|\ Merge: 427cf77 9bfc6cd
| | Author: tester <tester@example.com>
| | AuthorDate: Mon May 27 14:32:10 2019 +0200
| | Commit: bob <bob@example.com>
| | CommitDate: Mon May 27 14:32:10 2019 +0200
| |
| | Merge branch 'testbranch'
| |
| * commit 9bfc6cde58be9102102f839e5cc0fe8f25f0f78c
| | Author: tester <tester@example.com>
| | AuthorDate: Mon May 27 14:32:00 2019 +0200
| | Commit: bob <bob@example.com>
| | CommitDate: Mon May 27 14:32:00 2019 +0200
| |
| | change 5 made
| |
| | a.txt | 1 +
| | aa/aa.txt | 1 +
| | aa/ab.txt | 1 +
| | 3 files changed, 3 insertions(+)
| |
| * commit 485ae0f50054610b6a41098fb695e59d194cc856
| | Author: tester <tester@example.com>
| | AuthorDate: Mon May 27 14:31:50 2019 +0200
| | Commit: bob <bob@example.com>
| | CommitDate: Mon May 27 14:31:50 2019 +0200
| |
| | change 4 made
| |
| | a.txt | 1 +
| | aa/aa.txt | 1 +
| | aa/ab.txt | 1 +
| | 3 files changed, 3 insertions(+)
| |
| * commit b6804b6e8e313b5c4766568a287f0785503e3a11
| | Author: tester <tester@example.com>
| | AuthorDate: Mon May 27 14:31:40 2019 +0200
| | Commit: bob <bob@example.com>
| | CommitDate: Mon May 27 14:31:40 2019 +0200
| |
| | change 3 made
| |
| | a.txt | 1 +
| | aa/aa.txt | 1 +
| | aa/ab.txt | 1 +
| | 3 files changed, 3 insertions(+)
| |
| * commit 8b463423d2a99929a6a248e38ba1368a56d3769d
| | Author: tester <tester@example.com>
| | AuthorDate: Mon May 27 14:31:30 2019 +0200
| | Commit: bob <bob@example.com>
| | CommitDate: Mon May 27 14:31:30 2019 +0200
| |
| | change 2 made
| |
| | a.txt | 1 +
| | aa/aa.txt | 1 +
| | aa/ab.txt | 1 +
| | 3 files changed, 3 insertions(+)
| |
| * commit 3bc0bed30ebea1498a15711825b2ea8347cc374d
|/ Author: tester <tester@example.com>
| AuthorDate: Mon May 27 14:31:20 2019 +0200
| Commit: bob <bob@example.com>
| CommitDate: Mon May 27 14:31:20 2019 +0200
|
| change 1 made
|
| a.txt | 1 +
| aa/aa.txt | 1 +
| aa/ab.txt | 1 +
| 3 files changed, 3 insertions(+)
|
* commit 427cf77417a2406db5dd6a0e9bd4fb60542f2ee1
| Author: tester <tester@example.com>
| AuthorDate: Mon May 27 14:31:10 2019 +0200
| Commit: bob <bob@example.com>
| CommitDate: Tue May 28 12:55:43 2019 +0200
|
| added a.txt
|
| a.txt | 1 +
| 1 file changed, 1 insertion(+)
|
* commit 8e99c2d71048b4999d012b33d34386351d6d0fef
Author: bob <bob@example.com>
AuthorDate: Mon May 27 14:31:00 2019 +0200
Commit: bob <bob@example.com>
CommitDate: Mon May 27 14:31:00 2019 +0200
Initial commit by Bob
README | 1 +
1 file changed, 1 insertion(+)
Полегче, а? :)
Но я не совсем уверен, что это правильный процесс - так что, если кто-то более знающий может подтвердить это - или если есть более простой способ - это было бы здорово ...