之前在維護自己寫的WordPress插件時,爲了能夠方便地同時向GitHub倉庫和WordPress官方的svn倉庫提交,我只在本地維護了一個git工作目錄,然後用git svn dcommit向svn倉庫提交,用git push向GitHub提交。(詳見我之前寫的日誌。)
但可能是因爲WordPress官方的svn倉庫太大,歷史記錄太多,而git-svn的內部實現又有點問題,所以最近幾次我用git svn rebase和git svn dcommit都毫無反應。思來想去,爲了不耽誤時間,我還是決定老老實實用svn客戶端了。
於是現在我本地就有了兩個目錄:一個git工作目錄,用於向GitHub提交;一個svn工作目錄,用於向svn提交。由於svn裏的分支和標籤實際上就是目錄,因此svn工作目錄下還有trunk、branches和tags子目錄。trunk子目錄裏的內容才和git工作目錄裏的內容相同。
一般我是在git工作目錄下寫代碼,因此思路是在git工作目錄commit之後,用git diff生成patch文件, git log輸出提交日誌到另外一個文件。然後用patch命令將git diff應用到svn工作目錄。最後svn commit的時候利用git log的輸出,這樣就可以做svn trunk分支的提交和git master分支的提交一一對應。這個過程如下圖所示:
目錄結構如下所示:
$ pwd
/Users/zhixiangzhu/emwi
$ ls -R
git svn
./git:
README.md license.txt
external-media-without-import.css readme.txt
external-media-without-import.js screenshots
external-media-without-import.php
./git/screenshots:
screenshot-1.png screenshot-2.png
./svn:
assets branches tags trunk
./svn/assets:
banner-1544x500.jpg icon-128x128.jpg screenshot-1.png
banner-772x250.jpg icon-256x256.jpg screenshot-2.png
./svn/branches:
./svn/tags:
1.0 1.0.1 1.0.2 1.0.2.1
./svn/tags/1.0:
external-media-without-import.css license.txt
external-media-without-import.js readme.txt
external-media-without-import.php
...
./svn/trunk:
README.md license.txt
external-media-without-import.css readme.txt
external-media-without-import.js screenshots
external-media-without-import.php
./svn/trunk/screenshots:
screenshot-1.png screenshot-2.png
顯然我在其中一個工作目錄下做出改動後,還要將改動同步到另一個工作目錄並提交。人工同步改動顯然繁瑣耗時又容易出錯,需要自動化。我寫了一個腳本git2svn.sh,用於將git工作目錄中最新提交所做的改動應用到svn工作目錄並自動提交到svn倉庫。這個腳本就放在與git工作目錄和svn工作目錄同級的地方。可以在git工作目錄中執行,也可以在父目錄中執行:
$ pwd
/Users/zhixiangzhu/emwi
$ ls -R
git svn git2svn.sh
腳本內容如下:
# 如果當前是在父目錄,則進入git工作目錄
if [ $PWD != *git ]
then
cd git/
echo $PWD
fi
# 將git工作目錄最新提交的改動輸出到git.diff
git diff --no-prefix HEAD^ HEAD > ../git.diff
# 將git最新提交的提交日誌輸出到git_n.log
git log -1 --format="%B" HEAD > ../git_n.log
cd ..
# git_n.log的最後一行是空行,要將其刪掉
perl -pe 'chomp if eof' git_n.log > git.log
rm git_n.log
# 更新svn工作目錄
cd svn
svn update
# 將改動應用到svn/trunk目錄
cd trunk
patch -p0 < ../../git.diff
# 提交到svn倉庫,提交日誌與git相同
cd ..
svn commit -F ../git.log
cd ..
rm git.diff git.log
腳本第17行的perl命令的作用是將git log -1 --format命令輸出的git_n.log文件末尾的空行刪掉,見https://stackoverflow.com/a/1654042。其中-p的作用是打印輸入文件git_n.log的每一行, -e作用是執行-e後面的perl代碼。詳見這篇Perl命令行參數的說明。 chomp用於去除空行。
不過這個腳本沒有文件的添加和刪除。對這兩個情況還需要分別調用svn add和svn delete,等以後遇到這個需求再改進吧。
本文在我的獨立博客上的地址:http://zxtechart.com/2018/03/20/apply-git-diff-to-svn