下半年,运维组将逐步接手各应用的部署上线工作
为了规范化整个流程,打算所有的部署都基于tag来进行
以前的git部署脚本是直接fetch最新的代码到master上
所以就需要进行相应的修改,对tag进行操作
以下是tag的一些基本操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| #打tag t1
git tag -a -m 'for tag t1'
git tag t2 b389 为某次的commit打一个tag
#显示所有的tag
git tag
#查看本地tag
git show t2
#查看远程tag
git ls-remote -t
#删除本地tag t1
git tag -d t1
#删除远程tag
git push origin :refs/tags/t4
#以tag t4为基础生成新的分支b4
git branch b4 t4
#把某个tag push到远程,默认的git push是不会push tag信息的
git push origin t_master_20100713
#push所有的tag
git push origin --tags
#切换到某个tag上
git checkout t2 |
部署的部分脚本如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| echo "Begin git fetch from remote repositories"
ori_commit_id=`cd $local_module_path;git log -1 --format="%h"`
cd $local_module_path;git checkout master;git reset --hard;git fetch origin
new_commit_id=`cd $local_module_path;git log -1 --format="%h" $tag_name`
echo "From commitid $ori_commit_id to $new_commit_id have some changed files........................................."
echo ""
cd $local_module_path;git log --name-status --pretty=format:"%ci %Cgreen%aN%Creset %s" $ori_commit_id..$new_commit_id
echo ""
echo "End commitid $ori_commit_id to $new_commit_id have some changed files.........................................."
cd $local_module_path;git reset --hard;git pull origin master;git checkout $tag_name; |
发表在Git
|
标签有Git、tag
|
gitweb是git提供的一个基于web的版本查看工具
在新版的git源码中,它已经打包进去了
我们可以使用cgi方式,让gitweb运行在apache中
安装配置如下:
#进入git的src目录中
cd /opt/ysz/src/git-1.7.0
make clean
#编译gitweb,GITWEB_PROJECTROOT为要查看的git仓库目录,bindir为git目录
make GITWEB_PROJECTROOT="/opt/gitroot/repositories/" bindir=/usr/local/bin gitweb
mkdir /opt/gitroot/repositories/gitweb
#将cgi文件和静态文件拷贝到某个地方
cp gitweb/gitweb.cgi /opt/gitroot/repositories/gitweb
cp gitweb/*.js gitweb/*.css gitweb/*.png /opt/gitroot/repositories/gitweb
配置Apache2:
<VirtualHost *:80>
DocumentRoot /opt/gitroot/repositories/gitweb
ServerName 10.10.71.10
ScriptAlias /gitweb /opt/gitroot/repositories/gitweb/gitweb.cgi
<Location />
AuthName "Access auth"
AuthType Basic
AuthUserFile /usr/local/apache2/conf/passwd
Require valid-user
</Location>
<Directory /opt/gitroot/repositories/gitweb>
Options Indexes FollowSymLinks MultiViews
Order allow,deny
Allow from all
</Directory>
ErrorLog "/opt/log/apache2log/gitweb_error.log"
CustomLog "/opt/log/apache2log/gitweb_access.log" common
</VirtualHost>
这样配置后,就可以通过以下url访问gitweb了
http://10.10.71.10/gitweb
由于是基于web访问git仓库,所以加上基本的权限认证
发表在Git
|
标签有Git、gitweb
|
reset命令有3种方式:
- git reset –mixed:此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,回退commit和index信息
- git reset –soft:回退到某个版本,只回退了commit的信息,不会恢复到index file一级。如果还要提交,直接commit即可
- git reset –hard:彻底回退到某个版本,本地的源码也会变为上一个版本的内容
以下是一些reset的示例:
折叠
复制代码
- #回退所有内容到上一个版本
- git reset HEAD^
- #回退a.py这个文件的版本到上一个版本
- git reset HEAD^ a.py
- #向前回退到第3个版本
- git reset –soft HEAD~3
- #将本地的状态回退到和远程的一样
- git reset –hard origin/master
- #回退到某个版本
- git reset 057d
- #回退到上一次提交的状态,按照某一次的commit完全反向的进行一次commit
- git revert HEAD
如果我们某次修改了某些内容,并且已经commit到本地仓库,而且已经push到远程仓库了
这种情况下,我们想把本地和远程仓库都回退到某个版本,该怎么做呢?
前面讲到的git reset只是在本地仓库中回退版本,而远程仓库的版本不会变化
这样,即时本地reset了,但如果再git pull,那么,远程仓库的内容又会和本地之前版本的内容进行merge
这并不是我们想要的东西,这时可以有2种办法来解决这个问题:
- 直接在远程server的仓库目录下,执行git reset –soft 10efa来回退。注意:在远程不能使用mixed或hard参数
- 在本地直接把远程的master分支给删除,然后再把reset后的分支内容给push上去,如下:
折叠
复制代码
- #新建old_master分支做备份
- git branch old_master
- #push到远程
- git push origin old_master:old_master
- #本地仓库回退到某个版本
- git reset –hard bae168
- #删除远程的master分支
- git push origin :master
- #重新创建master分支
- git push origin master
在删除远程master分支时,可能会有问题,见下:
折叠
复制代码
- $ git push origin :master
- error: By default, deleting the current branch is denied, because the next
- error: 'git clone' won't result in any file checked out, causing confusion.
- error:
- error: You can set 'receive.denyDeleteCurrent' configuration variable to
- error: 'warn' or 'ignore' in the remote repository to allow deleting the
- error: current branch, with or without a warning message.
- error:
- error: To squelch this message, you can set it to 'refuse'.
- error: refusing to delete the current branch: refs/heads/master
- To git@xx.sohu.com:gitosis_test
- ! [remote rejected] master (deletion of the current branch prohibited)
- error: failed to push some refs to 'git@xx.sohu.com:gitosis_test'
这时需要在远程仓库目录下,设置git的receive.denyDeleteCurrent参数
折叠
复制代码
- git receive.denyDeleteCurrent warn
然后,就可以删除远程的master分支了
虽然说有以上2种方法可以回退远程分支的版本,但这2种方式,都挺危险的,需要谨慎操作……
发表在Git
|
标签有Git、reset
|
在使用Git的过程中,有时可能会有一些误操作
比如:执行checkout -f 或 reset -hard 或 branch -d删除一个分支
结果造成本地(远程)的分支或某些commit丢失
这时,我们可以通过reflog来进行恢复,前提是丢失的分支或commit信息没有被git gc清除
一般情况下,gc对那些无用的object会保留很长时间后才清除的
reflog是git提供的一个内部工具,用于记录对git仓库进行的各种操作
可以使用git reflog show或git log -g命令来看到所有的操作日志
恢复的过程很简单:
1. 通过git log -g命令来找到我们需要恢复的信息对应的commitid,可以通过提交的时间和日期来辨别
2. 通过git branch recover_branch commitid 来建立一个新的分支
这样,我们就把丢失的东西给恢复到了recover_branch分支上了
发表在Git
|
标签有Git、reflog
|
git clone默认会把远程仓库整个给clone下来
但只会在本地默认创建一个master分支
如果远程还有其他的分支,此时用git branch -a查看所有分支:
折叠
复制代码
- * master
- remotes/origin/HEAD -> origin/master
- remotes/origin/master
- remotes/origin/python_mail.skin
- remotes/origin/udisk
- remotes/origin/vip
能看到远程的所有的分支,如remotes/origin/python_mail.skin
可以使用checkout命令来把远程分支取到本地,并自动建立tracking
折叠
复制代码
- $ git checkout -b python_mail.skin origin/python_mail.skin
- Branch python_mail.skin set up to track remote branch python_mail.skin from origin.
- Switched to a new branch 'python_mail.skin'
或者使用-t参数,它默认会在本地建立一个和远程分支名字一样的分支
折叠
复制代码
- $ git checkout -t origin/python_mail.skin
也可以使用fetch来做:
折叠
复制代码
- $ git fetch origin python_mail.skin:python_mail.skin
不过通过fetch命令来建立的本地分支不是一个track branch,而且成功后不会自动切换到该分支上
注意:不要在本地采用如下方法:
折叠
复制代码
- $ git branch python_mail.skin
- $ git checkout python_mail.skin
- $ git pull origin python_mail.skin:python_mail.skin
因为,这样建立的branch是以master为基础建立的,再pull下来的话,会和master的内容进行合并,有可能会发生冲突…
发表在Git
|
标签有branch、clone、Git
|
在使用git的过程中,如果我们的项目是跨平台开发的
那么CRLF的处理也许会成为一个很头疼的事情,有可能会出以下的莫名其妙的问题:
我们的某个开发人员在linux上提交的一个文件
当从windows上pull下来后,没做任何的修改,查看其status,它的状态已经是modifed了
即使你使用git checkout -f来恢复改文件,它的状态仍然是modified,真是郁闷…
后来,才发现就是CRLF惹的祸
我们都知道,在Windows上是CRLF来作为一行的结束符,而Linux上则是LF作为行结束符
在git中提供了autocrlf的设置,可以用来自动转换CRLF,它可以设置成true,false,input
Windows上的msysgit默认设置了autocrlf为true
这样,在提交时自动地把行结束符CRLF转换成LF,而在签出代码时把LF转换成CRLF
这样保证了从windows平台上提交的代码,都是以LF作为行结束符
在linux平台上,git默认设置autocrlf为false,也即它不会自动处理CRLF
这样就有一个问题,如果我们把windows上的一个文件给上传到linux上,并提交
那么,提交到仓库中的代码就会以CRLF来换行了,
这样就会导致我们在windows上查看改文件的状态就会是modified
解决这个问题有以下2个办法:
- 在Linux上设置autocrlf为input,这样,Git在提交时把CRLF转换成LF,签出时不转换
- 对于从Windows上直接拷到Linux上的文件,首先把它转换成linux格式后,再进行提交
发表在Git
|
标签有autocrlf、Git
|
Git和CVS一个很大的不同是,它没有一个完善的权限控制系统
即使采用了Gitosis工具,它实际上是通过公钥来控制某台服务器的权限
用户在使用git前,依然需要设置user.name来控制提交时的用户名
但即使你没有设置,会有一个默认的空用户名或者是自己的登录用户名,如root
这样通过git log就很难看到对应的代码到底是哪个人员修改的了
不过,可以通过hook来初步解决这个问题
在git目录下的hooks目录里,新建一个pre-receive的hook,代码如下:
折叠
复制代码
- while read old new name; do
- name=$(git log -1 –pretty=format:%aN $new)
- email=$(git log -1 –pretty=format:%ae $new)
- user_prefix=`echo $name | awk -F'_' '{print $1}'`
- check_user=`echo $GIT_VALID_USER | grep -c $user_prefix`
- if [ "$check_user" == "0" ]
- then
- echo "Username $name denied, please set user.name"
- exit 43
- else
- exit 0
- fi
- done
需要在服务器上设置一个环境变量GIT_VALID_USER,保存合法的用户名列表
当用户名校验不通过,则返回一个非0的值即可
如果需要严格的用户名校验,即提交的user.name必须是gitosis里配置的对应Client的用户名
则可以在/usr/local/lib/python2.5/site-packages/gitosis-0.2-py2.5.egg/gitosis/serve.py中第202行增加如下代码:
os.environ['GIT_USER']=user
然后在hook里校验name是否等于这个环境变量的值即可
但由于我们有一些公共的服务器,可能很多开发人员都会在上面push代码,所以不能使用此严格的校验方式
只能使用上述的有效用户名列表的验证方式
发表在Git
|
标签有Git、hook、user.name
|
项目的版本控制切换到git后,相对于cvs来说,部署java程序有了一些问题
主要是因为:
1.cvs权限控制比较简单,只需要开个username,即可在服务器上update
但是,我们用gitosis来管理权限,就需要把各服务器的公钥给传到gitosis上
2.cvs可以支持部分update,比如我们可以指定只update某个jsp
但git是不可以的,pull下的就是最新的所有的代码,所以在pull之前一定要把更新内容给显示出来,便于确认
这样,我们需要写脚本,来完成从服务器上集中部署
大概有以下2种方案:
1.每个server上安装git,分配其只读的权限,从中央服务器上ssh到要部署的server上,并获取本次更新的文件,核心代码如下
ori_commit_id=`ssh root@$host “cd $module_path;git log -1 –format=”%h””`
ssh root@$host “cd $module_path;git reset –hard;git fetch origin”
new_commit_id=`ssh root@$host “cd $module_path;git log -1 –format=\”%h\” origin/master”`
ssh root@$host “cd $module_path;git log –name-status –pretty=format:\”%ci %Cgreen%aN%Creset %s\” $ori_commit_id..$new_commit_id”
这种部署方式,相对比较可靠,因为它直接ssh到server上,把该server本次更新的文件给列表了出来,确认后即可部署
2.在中央服务器上使用rsync来同步远程server的目录
之所以用rsync是因为:scp和tar方式都无法来根据文件修改时间来确定要拷贝的文件,只能是全部覆盖或者每次修改部署脚本
如果采用tar后再scp,那么所有文件都会被更新了,这样ant会把所有的src都重新编译一次,很麻烦的
rsync的命令很简单,如下:
rsync -e ssh -tpogrv /opt/test/ –exclude=.git $host://usr/local/src/test
注意需要后面的-t参数,它表明把文件的时间也给rsync到远程server上。
-exclude表明是排除.git目录,主要是相对路径
这种部署方式,相对比较简单,不需要为每个服务器开git权限
但由于比较的版本是中央服务器的目录,所以必须保证远程服务器的版本和中央服务器的版本相同,否则可能会有问题的
发表在Git
|
标签有Git、rsync
|
快捷键:
Alt+Space+E+K: 选择文字,拷贝
Insert: 粘贴文字
Alt+Back: 删除到前一个空格
Ctl+Back: 删除之前的所有文字
设置alias
git config –global alias.l 'log -n 10 –format=”%h %ci %Cgreen%aN%Creset %s %n”'
查看2个版本之间修改的文件列表
git log –name-status –pretty=format:\”%ci %Cgreen%aN%Creset %s\” 1258e..a3584
发表在Git
|
标签有alias、Git、msysgit
|
Git默认使用自己的diff来比较合并版本的
但它也能配置外部的工具来完成
对于Windows下的Msysgit,推荐使用winmerge
当然也还有其它很多的工具,如p4merge,Beyond Compare …
在Linux下我们可以使用vimdiff来代替
下面是配置的过程:
1.安装winmerge
2.在c:\Program Files\WinMerge下建一个diff.bat文件,放在其它Path能找到的路径下也可以
#!/bin/sh
“c:\Program Files\WinMerge\WinMergeU.exe” “$2″ “$5″
3.配置git
git config –global diff.external diff.bat
然后,再使用git diff时,就会自动打开winmerge,可视化的显示文件的差别了
如果要配置git merge使用外部的工具,以p4merge为例,需要设置
git config –global merge.tool extMerge
git config –global mergetool.extMerge.cmd \
'extMerge “$BASE” “$LOCAL” “$REMOTE” “$MERGED”'
git config –global mergetool.trustExitCode false
以下是extMerge的内容
#!/bin/sh
“c:\Program Files\Perforce\p4merge.exe” $*