結論:
對於想要指定特定分支進行拉取,最好的四種沒有二義性的寫法是:
refs/heads/<branchName>
refs/remotes/<remoteRepoName>/<branchName>
refs/tags/<tagName>
<commitId>
最近在使用Jenkins拉取Git工程編譯代碼時候遇到一個很奇怪的的問題:Jenkins的GitPlugin下載代碼的版本不對(commitId不對)。由於線上部署和線下部署的編譯產物是同一版本,導致最後發佈到生產環境的代碼版本也不對。這個問題在線上驗證階段才最終被發現,回顧整個job構建過程,控制檯沒有報錯,也成功編譯出來了上線包,那到底是哪裏出了問題?
初步定位
我最開始懷疑是本地Git工程殘留的問題,於是嘗試刪除jenkins對應job所運行的機器節點上的WORKSPACE目錄,保證下次觸發Jenkins構建能拉取到最新代碼。
刪除方式:
\1. 登陸到運行這個job的節點的機器(在控制檯中查看這個job運行的節點,在第一行有打印)。
\2. 查看$WORKSPACE(在job的控制檯中查看;如果找不到,直接在shell executor中加一行echo $WORKSPACE,重新執行job)
\3. 刪除對應的WORKSPACE信息。請謹慎操作,先看清楚WORKSPACE的值對不對(echo $WORKSPACE),別搞錯導致刪除了根目錄!!!。
[ -d "$WORKSPACE" ] && rm -rf ${WORKSPACE}
4.刪除後重新觸發job
這麼操作後,最終打包出來的編譯產物還是版本不對。
既然不是本地代碼緩存問題,那有沒有可能在GIt拉取代碼的時候版本就不對呢?
二次排錯
打開Jenkins上job的配置詳情,我在BranchSpecifier這裏只填寫了"/qa",我的預期是匹配git特定工程(Repository URL)中的qa*分支。
然後看看之前有問題那次構建的記錄(打開job當次構建的詳情頁),點擊Git Build Data(左側):
這裏顯示了兩個remote的branch,我在GitPlugin裏面只配置了一個qa分支,這裏應該只有一個叫做qa的分支被下載纔對,怎麼會有兩個分支呢?
我開始懷疑可能是在配置Git Plugin中BranchName的規則匹配問題,導致在這裏匹配了兩個分支(一個叫做qa,一個叫origin/qa)。
再次打開Jenkins上對應job的配置,我們看到在BranchSpecifier這裏填的是"/qa",是一個通配符,會不會在這個工程下正好有兩個branch,如上圖中的(origin/qa和qa),正好匹配到了*/qa呢?
這麼一想就有點解釋得通了,於是我點擊了Branches Specifier這一欄右側的問號查看幫助,可以看到使用幫助信息。
詳情分析
//下面這句話的意思是:如果你不填寫branch specifier(留空或者寫的是any),那麼任意分支都會被匹配,也就是你無法工程使用的是哪個分支。一般不建議這麼用。
Specify the branches if you'd like to track a specific branch in a repository. If left blank, all branches will be examined for changes and built.
//下面這句話的意思是:最安全的方式是使用refs/heads/
The safest way is to use the refs/heads/
//如果你的分支裏面包含‘/’(例如叫origin/qa),最好就用上面提到的語法:refs/heads/
If your branch name has a / in it make sure to use the full reference above. When not presented with a full path the plugin will only use the part of the string right of the last slash. Meaning foo/bar will actually match bar.
If you use a wildcard branch specifier, with a slash (e.g. release/), you'll need to specify the origin repository in the branch names to make sure changes are picked up. So e.g. origin/release/
Possible options:
//branchName只是個通配符,比如realese可以匹配release分支,也可能匹配origin/release,一般不要這麼寫(否則會和我一樣踩同樣的坑)
//由於指定
Tracks/checks out the specified branch. If ambiguous the first result is taken, which is not necessarily the expected one. Better use refs/heads/
E.g. master, feature1,...
- refs/heads/
Tracks/checks out the specified branch. //checkout遠程的某個分支
E.g. refs/heads/master, refs/heads/feature1/master,...
/
Tracks/checks out the specified branch. If ambiguous the first result is taken, which is not necessarily the expected one.
Better use refs/heads/
E.g. origin/master
- remotes/
/
Tracks/checks out the specified branch. //這種指定方式也是比較精確的。
E.g. remotes/origin/master
- refs/remotes/
/
Tracks/checks out the specified branch.
E.g. refs/remotes/origin/master //checkout指定的tag,實際上這裏tagName不會被當做tag,不建議這麼寫。
This does not work since the tag will not be recognized as tag.
Use refs/tags/
E.g. git-2.3.0
- refs/tags/
Tracks/checks out the specified tag.
E.g. refs/tags/git-2.3.0
Checks out the specified commit. //checkout指定的commitid
E.g. 5062ac843f2b947733e6a3b105977056821bd352, 5062ac84, ...
- ${ENV_VARIABLE}
It is also possible to use environment variables. In this case the variables are evaluated and the result is used as described above.
E.g. ${TREEISH}, refs/tags/${TAGNAME},...
The syntax is of the form: REPOSITORYNAME/BRANCH. In addition, BRANCH is recognized as a shorthand of /BRANCH, '' is recognized as a wildcard, and '' is recognized as wildcard that includes the separator '/'. Therefore, origin/branches* would match origin/branches-foo but not origin/branches/foo, while origin/branches would match both origin/branches-foo and origin/branches/foo.
- :
The syntax is of the form: :regexp. Regular expression syntax in branches to build will only build those branches whose names match the regular expression.
Examples:
-
:^(?!(origin/prefix)).*
-
matches: origin or origin/master or origin/feature
-
does not match: origin/prefix or origin/prefix_123 or origin/prefix-abc
-
:origin/release-\d{8}
-
matches: origin/release-20150101
-
does not match: origin/release-2015010 or origin/release-201501011 or origin/release-20150101-something
-
:^(?!origin/master$|origin/develop$).*
-
matches: origin/branch1 or origin/branch-2 or origin/master123 or origin/develop-123
-
does not match: origin/master or origin/develop
所以對於想要指定特定分支進行拉取,最好的四種沒有二義性的寫法是:
refs/heads/<branchName>
refs/remotes/<remoteRepoName>/<branchName>
refs/tags/<tagName>
<commitId>
到這裏基本問題就真相大白了,我去gitlab上看了下這個工程的分支列表,發現還真有一個叫做origin/qa的分支,經過和其他同事的確認,有人手抖創建了這個origin/qa的分支。
我把原來的/qa換成refs/heads/qa*,這樣就精確地匹配到了具體的分支。嘗試再次觸發job構建,這次下載的Git代碼版本也正確了。