这个答案提供了基于git am的有趣命令,并使用示例一步一步地展示。
客观的
您希望将部分或全部文件从一个存储库移动到另一个存储库。
你想保留他们的历史。
但是您并不关心是否保留标记和分支。
您接受重命名文件(以及重命名目录中的文件)的有限历史记录。
过程
提取历史在电子邮件格式使用
Git日志——pretty=email -p——reverse——full-index——二进制
重新组织文件树并更新历史记录中的文件名更改[可选]
使用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"' {} ';'
不幸的是,“跟随”或“更难找到副本”选项不能与“反向”组合。这就是为什么重命名文件(或重命名父目录)时删除历史记录的原因。
After:邮件格式的临时历史
/tmp/mail/dir
├── subdir
│ ├── file3
│ └── file4
└── file5
2. 重新组织文件树并更新历史记录中的文件名更改[可选]
假设您希望将这三个文件移动到另一个repo(可能是同一个repo)中。
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状态查看准备推送的提交量:-)
注意:由于历史已经被重写,以反映路径和文件名的变化:
(即与上一份回购合约内的地点/名称比较)
不需要git mv来更改位置/文件名。
不需要git log -follow来访问完整的历史记录。
额外的技巧:检测重命名/移动文件在你的回购
列出已重命名的文件。
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow {} ';' | grep '=>'
更多自定义:您可以使用选项——find-copies-harder或——reverse来完成命令git日志。您还可以使用cut -f3-和grepping complete pattern '{删除前两列。* => .*}'。
find -name .git -prune -o -exec git log --pretty=tformat:'' --numstat --follow --find-copies-harder --reverse {} ';' | cut -f3- | grep '{.* => .*}'