我正在使用此脚本来修改提交:
rm -rf repo
echo "clonning $1"
git clone $1 repo
cd repo
git checkout dev
echo "setting remote origin to $2"
git remote set-url origin $2
array=( 'email1@gmail.com' 'email2@gmail.com' )
for OLD_EMAIL in "${array[@]}"
do
echo $OLD_EMAIL
git filter-branch -f --env-filter '
CORRECT_NAME="New name"
CORRECT_EMAIL="new@email.com"
if [ "$GIT_COMMITTER_EMAIL" = '$OLD_EMAIL' ]
then
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = '$OLD_EMAIL' ]
then
export GIT_AUTHOR_NAME="$CORRECT_NAME"
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --tags
done
echo "Authors list:"
git log --format='%cE' | sort -u
echo -n "Push to destination (y/n)? "
read answer
if echo "$answer" | grep -iq "^y" ;then
git push
else
echo Aborted
fi
cd ../
Run Code Online (Sandbox Code Playgroud)
它从第一个仓库中提取数据,修改提交者信息并推送到第二个仓库.
如果有人直接提交第二个回购,问题就出现了.如何将这些更改应用于第一个回购?
如果我正确理解你的问题(阅读评论后),你的回购目前看起来像这样:
第一个repo(ad)中的提交已被修改以创建备用提交(a'-d'),这些提交被推入第二个仓库,然后添加了其他提交(例如).
因为你在两个repos中的身份信息之间没有1:1的关系,试图用filter-branch修改'-d'以恢复原始历史,虽然理论上可行,但是需要一个积极的方法识别"原始提交",而没有确定提交(其哈希)所需的一条信息.
提交基本上由几条信息组成:
所有这些都经过哈希处理,以便为您的提交创建唯一标识符.改变了2,3,5和8之后,我们留下了树,它不一定是唯一的,时间戳(不一定是唯一的)和提交消息,它不一定是唯一的.
可能只是比较树和其中一个时间戳,你可以获得一个不错的匹配,所以让我们为该场景编写一些伪代码.
# create a variable to hold the information from teh current commit
pseudoidentifier=$TREE + $AUTHOR_TIMESTAMP
# go to the first repo
cd /path/to/firstrepo
# output the log | grep to search | sed to remove everything after delimeter
oldhash=`git log --format="{hash}~{tree}{authortimestamp}" | grep pseudoidenfier | sed "s/~.+$//"`
# get the new identity using a custom formatted show command
newidentity=`git show -q --format="{formatted identity}" $oldhash`
# parse out the name and email, probably with sed
CORRECT_NAME=`sed 's/pattern//' $newidentity`
CORRECT_EMAIL=`sed 's/pattern//' $newidentity`
# go to the second repo
cd /path/to/secondrepo
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
Run Code Online (Sandbox Code Playgroud)
不幸的是,编写速度慢,测试困难且耗时.可能需要多次重新运行整个事物.因为你的最终目标是重新统一代码.还有其他一些选项可能会减少头痛并且速度更快.特别是如果你确实需要保持第二个回复,身份更新完好无损.
如果没有共同的历史记录,您仍然可以使用更多手动方式将两者同步.在这种情况下,我建议使用以下三种方法.
在开始之前,我们可以检查d和d'处的代码是否确实相同.我们可以使用git show命令来做到这一点:
$ git show -q --format="%T" d
a017285da45ec06fc744815f33a2e22627f4a799
$ git show -q --format="%T" d'
a017285da45ec06fc744815f33a2e22627f4a799
Run Code Online (Sandbox Code Playgroud)
此命令将输出提交指向的树对象,如果两个树匹配,则表示您正在处理相同的代码.完全可能在没有匹配的代码库的情况下执行以下过程,但在这种情况下您可能必须解决冲突.这一步真的只是告诉你两者将如何轻松地融合在一起.
如果您最初修改提交的repo完好无损,则可以从两者中获取分支到单个repo中,并尝试使用cherry-pick复制提交.
git checkout <branch at d>
git cherry-pick d'...g
Run Code Online (Sandbox Code Playgroud)
(注意语法是3个点)这将在d'之后(但不包括)d'应用每个提交的更改,直到并包括g到d.创建新提交e'-g'.
如果您没有简单的方法将更改从两个分支转换为单个存储库,则可以为第二个存储库上的提交创建一系列修补程序并将其应用于第一个存储库.
git checkout <branch of g>
git format-patch --output-directory <dir> d'...g
Run Code Online (Sandbox Code Playgroud)
(再次,语法是3个点)这将在d'之后(并且不包括)d'之前和之后为每个提交输出一系列补丁文件.然后将这些文件复制到第一个存储库中可以获取这些文件的位置.
git checkout <branch of d>
git am /path/to/patches/*
Run Code Online (Sandbox Code Playgroud)
你最终会在樱桃采摘方法的同一个地方.
如果存在大量冲突并且您不需要保留身份更改信息,则还可以使用git replace执行移植.
git replace --graft e d
Run Code Online (Sandbox Code Playgroud)
这将创建一个commit e的副本,其中d作为父项,并添加一个引用,表示在尝试访问e时使用e'commit.有效地使d成为两者的共同祖先并允许您执行传统合并(h).
保持两个没有共同历史记录同步的回购将一直导致你这样的问题,并且随着两者的缓慢分歧(例如,当你解决冲突时)它们会变得更糟.随着时间的推移,这两种方法都需要越来越多的资源来维护两个回购.
我建议,一旦两个repos同步,选择其中一个并从那时起专门使用那个.如果您需要两个遥控器,只需将该回购推送给它们.然后,您可以轻松地使用许多经过验证的真实工作流程中的任何一个来维护两个回购.
如果这不是一个选项,我建议一丝不苟地检查两个回购头的树木,以验证它们是否经常一点一点地相同.
您有两种选择来完成此操作:
--global为所有存储库添加)Run Code Online (Sandbox Code Playgroud)git config user.email email@server.com