![](/img/trans.png)
[英]Git merge submodule into parent tree cleanly and preserving commit history
[英]git merge multiple copies preserving history
我有一個項目,在不同的地方有一些文件的多個副本。 例如:
src/location1/foobar.h
src/location1/foobar.cpp
src/location2/foobar.h
src/location2/foobar.cpp
我正在將這些提取到自己的庫中。 所以我希望結束:
src/location3/foobar.h combining multiple versions of foobar.h
src/location3/foobar.cpp combining multiple versions of foobar.cpp
我已經通過了使用以下方法刪除所有不需要的文件的第一個障礙:
git filter-repo --path-glob \*foobar\*
在此過程中發現 filter-branch 最近已被高級 filter-repo 取代(值得重復,因為 filter-branch 仍然出現在此處的許多最佳答案中)。
我現在想將這些副本合並為一個副本,保留它們的所有歷史記錄。 這兩個候選者是merge
和merge-file
。
merge-file
需要識別每個文件的共同祖先,這可能很痛苦:
src/location3/foobar.h
這在提交歷史中是未知的。 我們有 git merge-base
來找到最好的共同祖先。
我不清楚如何為我想做的 git 合並文件指定文件版本:
git mv src/location1/foobar.h src/newlocation/foobar.h
git commit
git merge-file src/newlocation/foobar.h src/location3/foobar@<commitid> src/location2/foobar.h
...
git merge-file src/newlocation/foobar.h src/location3/foobar@<commitid> src/location3/foobar.h
這是非常費力的,必須對每個文件重復。 另一種方法是創建多個臨時分支:
git checkout -b newlibbranch
git mv src/location1/foobar.h src/newlocation/foobar.h
git mv src/location1/foobar.cpp src/newlocation/foobar.cpp
git commit
git checkout oldversion
git checkout -b v2
git mv src/location2/foobar.h src/newlocation/foobar.h
git mv src/location2/foobar.cpp src/newlocation/foobar.cpp
git commit
git checkout newlibbranch
git merge --allow-unrelated-histories v2
這也是相當辛苦的。 盡管它可能是可編寫腳本的。 還有一個實際問題,因為合並是“重命名/重命名”沖突,而不是實際文件的合並。 這似乎可以通過添加 --allow-unrelated-histories 來解決
所以我的問題是:
關於任務:
關於合並文件:
git merge-file-wrapper location1 location2 -->
base = `git merge-base location1 location2`
git merge-file location1 $base location2
難道這不存在是因為有什么隱患?
我還沒有找到任何自動化工具來執行此操作,因此生態系統中可能存在缺口。
在我的例子中,我有多個文件要移動,其中一些文件比其他文件有更多的副本,這增加了一些有趣的復雜性,但在重構以刪除重復時並不少見。
我最后做的是:
編寫一個腳本來創建一個新分支,其中每個變體都被移動到它的新位置。
我的腳本首先識別要移動的文件。
查找副本最多的文件並創建多個分支。
對於每個分支,它嘗試將每個文件的一個副本移動到其新位置
然后我手動合並每個分支。
這些合並中的大多數都是微不足道的事情,例如更改每個子項目的名稱空間。
結果是一組文件,其中包含我想要的所有更改以及每個文件的所有更改歷史記錄。
為了使這個更具體一點:
第 1 步:使用 filter-repo 創建一個只包含感興趣文件的項目
(注意這應該在項目的新克隆上完成)
git filter-repo --path-glob \*ThingIWant1\* --path-glob \*AnotherThingIWant\*
git filter-repo --invert --path-glob \*ThingIDontWant\*
#!/bin/bash
# find unique filenames
MAXLOCS=0
FILES=`find . -not -path '*/.*' -type f | grep -v makebranch | xargs -ifile basename file | sort -u`
for FILE in $FILES; do
echo FILE=$FILE
# find number of locations for each filename
NUMLOCS=`find . -not -path '*/.*' -name $FILE | wc -l`
if [ $NUMLOCS -gt $MAXLOCS ]; then
MAXLOCS=$NUMLOCS
fi
done
echo "$MAXLOCS branches required"
# for each branch
# move one location of each file to its final destination
L=0
while [ $L -lt $MAXLOCS ]; do
git checkout develop
git checkout -b ps$L
for FILE in $FILES; do
echo FILE=$FILE
LOCS=( $(find . -not -path '*/.*' -name $FILE) )
NUMLOCS=${#LOCS[@]}
if [ $L -lt $NUMLOCS ]; then
LOC=${LOCS[$L]}
echo "mv $LOC"
# Move source files to one place and test files to another
# In my case we have src and test
echo $LOC | grep -q /src/
if [ $? ]; then
mkdir -p FinalDestinationForSource
git mv $LOC FinalDestinationForSource/$FILE
if [ $? -ne 0 ];then
echo "BAD: git mv $LOC FinalDestinationForSource/$FILE"
fi
else
mkdir -p FinalDestinationForTests
git mv $LOC FinalDestinationForTests/$FILE
if [ $? -ne 0 ];then
echo "BAD: git mv $LOC FinalDestinationForTests/$FILE"
fi
fi
fi
done
git add -u
git status
git commit -m "#Ticket: move Things to new location $L"
((L = L + 1))
done
git checkout ps0
git merge ps1 -X rename-threshold=5%
# resolve manually... then
git commit
git merge ps2 -X rename-threshold=5%
# resolve manually... then
git commit
重命名閾值有助於說服 git 這些文件具有相同的來源。 否則,一個版本可能會簡單地替換另一個版本,而不會保留鏈接它們的更改歷史記錄。 我認為結果相當於使用 git 提交樹鏈接多個提交,這將是解決此問題的另一種方法。
您可以使用git blame
來驗證歷史記錄,以查看每個文件中每一行的來源,並git log
來查看實際提交。
Raymond Chen 有一系列關於此的博客,您可能會感興趣。 他使用提交樹來處理這個任務。 我認為這可行,但我認為它對我的案例來說有點太低級了。
第 4 步:將您的庫合並到它所屬的項目中
這是為了完整性而包括在內,因為您可能將文件移動到另一個項目。 有關詳細信息,請參閱“ 如何合並兩個 Git 存儲庫? ”
cd targetProject
git remote add sourceProject /path/to/sourceProject
git fetch sourceProject
git merge --allow-unrelated-histories sourceProject/ps0
我認為這個領域已經成熟,可以貢獻一個腳本來向 git 添加一個新的合並工具。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.