分类 Git 下的文章

git tag的操作

下半年,运维组将逐步接手各应用的部署上线工作

为了规范化整个流程,打算所有的部署都基于tag来进行

以前的git部署脚本是直接fetch最新的代码到master上

所以就需要进行相应的修改,对tag进行操作

以下是tag的一些基本操作

 

#打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

部署的部分脚本如下:

 

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;

搭建gitweb环境

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版本恢复命令reset

reset命令有3种方式:



  1. git reset --mixed:此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,回退commit和index信息

  2. git reset --soft:回退到某个版本,只回退了commit的信息,不会恢复到index file一级。如果还要提交,直接commit即可

  3. git reset --hard:彻底回退到某个版本,本地的源码也会变为上一个版本的内容


以下是一些reset的示例:



折叠复制代码




  1. #回退所有内容到上一个版本  

  2. git reset HEAD^  

  3. #回退a.py这个文件的版本到上一个版本  

  4. git reset HEAD^ a.py  

  5. #向前回退到第3个版本  

  6. git reset --soft HEAD~3  

  7. #将本地的状态回退到和远程的一样  

  8. git reset --hard origin/master  

  9. #回退到某个版本  

  10. git reset 057d  

  11. #回退到上一次提交的状态,按照某一次的commit完全反向的进行一次commit  

  12. git revert HEAD  






如果我们某次修改了某些内容,并且已经commit到本地仓库,而且已经push到远程仓库了


这种情况下,我们想把本地和远程仓库都回退到某个版本,该怎么做呢?


前面讲到的git reset只是在本地仓库中回退版本,而远程仓库的版本不会变化


这样,即时本地reset了,但如果再git pull,那么,远程仓库的内容又会和本地之前版本的内容进行merge


这并不是我们想要的东西,这时可以有2种办法来解决这个问题:



  1. 直接在远程server的仓库目录下,执行git reset --soft 10efa来回退。注意:在远程不能使用mixed或hard参数

  2. 在本地直接把远程的master分支给删除,然后再把reset后的分支内容给push上去,如下:


  3. 折叠复制代码




    1. #新建old_master分支做备份  

    2. git branch old_master  

    3. #push到远程  

    4. git push origin old_master:old_master  

    5. #本地仓库回退到某个版本  

    6. git reset --hard bae168  

    7. #删除远程的master分支  

    8. git push origin :master  

    9. #重新创建master分支  

    10. git push origin master  







在删除远程master分支时,可能会有问题,见下:



折叠复制代码




  1. $ git push origin :master  

  2. error: By default, deleting the current branch is denied, because the next  

  3. error: 'git clone' won't result in any file checked out, causing confusion.  

  4. error:  

  5. error: You can set 'receive.denyDeleteCurrent' configuration variable to  

  6. error: 'warn' or 'ignore' in the remote repository to allow deleting the  

  7. error: current branch, with or without a warning message.  

  8. error:  

  9. error: To squelch this message, you can set it to 'refuse'.  

  10. error: refusing to delete the current branch: refs/heads/master  

  11. To git@xx.sohu.com:gitosis_test  

  12.  ! [remote rejected] master (deletion of the current branch prohibited)  

  13. error: failed to push some refs to 'git@xx.sohu.com:gitosis_test'  






这时需要在远程仓库目录下,设置git的receive.denyDeleteCurrent参数



折叠复制代码




  1. git receive.denyDeleteCurrent warn  






然后,就可以删除远程的master分支了


虽然说有以上2种方法可以回退远程分支的版本,但这2种方式,都挺危险的,需要谨慎操作......

从Git仓库中恢复已删除的分支或丢失的commit

在使用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 clone远程分支

git clone默认会把远程仓库整个给clone下来


但只会在本地默认创建一个master分支


如果远程还有其他的分支,此时用git branch -a查看所有分支:



折叠复制代码




  1. * master   

  2. remotes/origin/HEAD -> origin/master   

  3. remotes/origin/master   

  4. remotes/origin/python_mail.skin   

  5. remotes/origin/udisk   

  6. remotes/origin/vip






 能看到远程的所有的分支,如remotes/origin/python_mail.skin


可以使用checkout命令来把远程分支取到本地,并自动建立tracking



折叠复制代码




  1. $ git checkout -b python_mail.skin origin/python_mail.skin   

  2. Branch python_mail.skin set up to track remote branch python_mail.skin from origin.   

  3. Switched to a new branch 'python_mail.skin'




或者使用-t参数,它默认会在本地建立一个和远程分支名字一样的分支



折叠复制代码




  1. $ git checkout -t origin/python_mail.skin




 也可以使用fetch来做:



折叠复制代码




  1. $ git fetch origin python_mail.skin:python_mail.skin





 不过通过fetch命令来建立的本地分支不是一个track branch,而且成功后不会自动切换到该分支上


注意:不要在本地采用如下方法:



折叠复制代码




  1. $ git branch python_mail.skin   

  2. $ git checkout python_mail.skin   

  3. $ git pull origin python_mail.skin:python_mail.skin





因为,这样建立的branch是以master为基础建立的,再pull下来的话,会和master的内容进行合并,有可能会发生冲突...

git中配置autocrlf来正确处理crlf

在使用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个办法:



  1. 在Linux上设置autocrlf为input,这样,Git在提交时把CRLF转换成LF,签出时不转换

  2. 对于从Windows上直接拷到Linux上的文件,首先把它转换成linux格式后,再进行提交

使用Git hook来校验push用户名的合法性

Git和CVS一个很大的不同是,它没有一个完善的权限控制系统


即使采用了Gitosis工具,它实际上是通过公钥来控制某台服务器的权限


用户在使用git前,依然需要设置user.name来控制提交时的用户名


但即使你没有设置,会有一个默认的空用户名或者是自己的登录用户名,如root


这样通过git log就很难看到对应的代码到底是哪个人员修改的了


不过,可以通过hook来初步解决这个问题


在git目录下的hooks目录里,新建一个pre-receive的hook,代码如下:



折叠复制代码




  1. while read old new name; do

  2. name=$(git log -1--pretty=format:%aN $new)

  3. email=$(git log -1--pretty=format:%ae $new)

  4. user_prefix=`echo $name | awk -F'_' '{print $1}'`

  5. check_user=`echo $GIT_VALID_USER | grep -c $user_prefix`

  6. if [ "$check_user" == "0" ]

  7. then

  8. echo "Username $name denied, please set user.name"

  9. exit 43

  10. else

  11. exit 0

  12. fi

  13. 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代码,所以不能使用此严格的校验方式


只能使用上述的有效用户名列表的验证方式

使用rsync+git来部署java代码

项目的版本控制切换到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权限
  但由于比较的版本是中央服务器的目录,所以必须保证远程服务器的版本和中央服务器的版本相同,否则可能会有问题的

Msysgit优化

快捷键:
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中使用外部工具来进行diff和merge

Git默认使用自己的diff来比较合并版本的
但它也能配置外部的工具来完成
对于Windows下的Msysgit,推荐使用winmerge
当然也还有其它很多的工具,如p4mergeBeyond 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" $*

最新文章

最近回复

  • feifei435:这两个URI实际是不一样的
  • zsy: git push origin 分支 -f 给力!
  • 冼敏兵:简单易懂,good fit
  • Jack:无需改配置文件,看着累! # gluster volume se...
  • Mr.j:按照你的方法凑效了,折腾死了。。。。
  • zheyemaster:补充一句:我的网站路径:D:\wamp\www ~~菜鸟站长, ...
  • zheyemaster:wamp2.5(apache2.4.9)下局域网访问403错误的...
  • Git中pull对比fetch和merge | 炼似春秋:[…] 首先,我搜索了git pull和git fe...
  • higkoo:总结一下吧, 性能调优示例: gluster volume s...
  • knowaeap:请问一下博主,你维护的openyoudao支持opensuse吗

分类

归档

其它