本文为个人整理笔记,参考与廖雪峰老师的官方GIT教程:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 

在之前的GIT入门介绍中,我们了解了本地一些GIT操作的命令和原理,在这一节将一起学习一下GIT远程管理和版本管理的相关内容。


远程仓库

如果要在github上管理我们的代码,并在本地进行修改提交就需要了解git 远程仓库的相关内容。github是git官方提供的一个代码托管平台,个人可以申请免费的,但是所上传的内容可以方便大家共享,如果要使用私密仓库,需要付费。

在github上添加SSH KEY:

在github上注册好账户之后,添加本机的SSH公钥,这样在本地在对远程仓库操作时就不用频繁的使用账号密码。

ssh-keygen -t rsa -C "[email protected]"

一路默认回车之后,cat .ssh/id_rsa.pub ,然后将cat的内容添加到账户的SSH Key中。


创建第一个个人仓库

首先在github上注册一个个人账户,在New repository中直接输入新建仓库的名称即可。根据提示使用SSH的方法在本地添加一个个人仓库:

git remote add origin [email protected]:YourName/gitrepo.git
git push -u origin master  # -u更新所有分支 origin默认远程仓库名称

当第一次同步了所有的本地文件之后,在对文件做了commit,就可以直接使用:

git push origin master

这样就直接将本地更新的文件推到了远程管理库。


从远程仓库克隆

github上有很多很优秀的代码和应用,如果我们要是用别人的代码,直接可以用git clone命令将代码拉到我们本地,如果是自己的代码库可以直接拉取:

 git clone [email protected]:YourName/gitrepo.git


分支管理

在进行开发的过程中,很多情况下我们需要对分支进行管理。例如,如果是本地对一个文件进行修改,那么这个文件就是线性的修改方式,如果要对多个文件进行多次修改,而且不同的修改最终会确认一个最终的版本,最终合并的这个分支就是这个文件的最终版本,需要注意的是,只有当执行了commit 命令之后,本地的master分支才会建立。

创建并切换分支:

git branche dev    #创建dev分支
git checkout dev   #切换分支到dev
===============
git checkout -b dev    # 创建并切换分支, 一条命令搞定

查看分支:

git branch

对分支修改后git add , git commit 之后就可切换到master分支上合并。

合并dev到master分支:

git merge dev

删除分支:

git branch -d dev


当在两个分支上同时修改了文件并且提交后,在git合并时就会出现冲突的报错。这是因为当我们在合并的时候程序也不知道我们到底需要更新哪一个,这就需要我们手动去更新文件,解决冲突。然后再合并。

[root@work gitrepo]# git merge test # 在master和test分支上都commit后,再merge会报错
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
[root@work gitrepo]# cat readme.txt 
test
<<<<<<< HEAD              #查看编辑的文件,系统对我们手动要修改的地方做了标注
this is master 
=======
this is test 
>>>>>>> test

修改文件统一后,再次执行git add 和git commit就可以解决冲突了:

[root@work gitrepo]# git log --graph  --pretty=oneline --abbrev-commit
*   52ed4df confilt
|\  
| * 310f7e7 IT        # 显示了一个分支的修改
* | a8fa78b master
|/  
* b040742 test

git log --graph命令可以看到分支合并图。


合并分支时,默认使用的是fast forward模式,但是使用这种模式是不记录其它分支的修改日志的,在实际应用中,为了更加清楚分支上的修改时间,需要加上--no-ff参数,可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。


在一般的开发过程中大豆会有如下流程:

1、leader在远程仓库创建2个分支:master和dev

2、张三和李四克隆远程仓库到本地

3、张三和李四都切换到dev分支

4、张三创建分支z3,李四创建分支l4

5、开发完成后,张三合并z3到dev,李四合并l4到dev

6、张三和李四把本地库的dev分支推送到远程dev

7、leader拉取远程库里的dev和masterd,在本地将dev合并到master 并推送到远程master


BUG分支管理

如果当前正在dev分支上开发,突然线上出了一个BUG,需要立即修复,这时候我需要暂时隐藏当前的工作,也就是保存当前dev分支上的进度 git statsh:

[root@work gitrepo]# git stash
Saved working directory and index state WIP on dev: f241242 test
HEAD is now at f241242 test

[root@work gitrepo]# git status  #隐藏工作区之后,显示的工作目录为空了
# On branch dev
nothing to commit, working directory clean

保存了当前的工作后,我们就要去修复线上的bug了,切换到master分支,并创建一个修复的issue分支:

[root@work gitrepo]# git checkout master
Switched to branch 'master'
[root@work gitrepo]# git checkout -b issue
Switched to a new branch 'issue'
[root@work gitrepo]# git branch
  dev
* issue
  master

在issue上完成修复工作后,执行git add ,git commit 提交代码,然后在master上合并issue分支上的代码删除issue分支:

[root@work gitrepo]# git branch
  dev
* issue
  master
[root@work gitrepo]# git add readme.txt 
[root@work gitrepo]# git commit -m "fix issue"
[issue 8b29da7] fix issue
 1 file changed, 1 insertion(+)
 
[root@work gitrepo]# git checkout master # 回到master上合并issue分支
Switched to branch 'master'
[root@work gitrepo]# git merge --no-ff -m "fix bug issue" issue # 记录分支日志信息
Merge made by the 'recursive' strategy.
 readme.txt | 1 +
 1 file changed, 1 insertion(+)
 
[root@work gitrepo]# git branch -d issue  #删除issue分支
Deleted branch issue (was 8b29da7).

bug修复完成之后,我们要回到自己的dev分支继续我们的工作了:

[root@work gitrepo]# git checkout dev
Switched to branch 'dev'

[root@work gitrepo]# git status # 原来的dev分支是空的
# On branch dev
nothing to commit, working directory clean

[root@work gitrepo]# git stash list # 查看我们隐藏的分支
stash@{0}: WIP on dev: f241242 test

[root@work gitrepo]# git stash pop # 显示出隐藏的分支,并将隐藏的分支删除
# On branch dev
# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#       modified:   file.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (5a7f46b8a24f1a557a37b0378ee75c65387e024a)

[root@work gitrepo]# git status
# On branch dev
# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#       modified:   file.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

恢复隐藏的分支有两种方法:

git stash apply   # 恢复隐藏的分支

git stash drop    # 删除隐藏的分支记录

============================

git statsh pop  # 恢复隐藏的分支,并将隐藏的分支删除,用一条命令做上面两条命令的事情。


tips:

如果要开发一个新的特性,最好新建一个分支,如果开发的新分支完成一半需要删除(此时还没有提交)删除一个未提交的分支,可以使用git branch -D BranchName 强制删除。


多人协作分支管理

在进行多人协作开发的团队中,由于每个人都会去不断的修改文件,合并文件,就会出现当你想远程提交自己的代码时,碰巧别人也修改了相同的文件,这样你本地的文件和远程的文件内容就不一样了,需要手动解决冲突再进行提交。

[root@work gitrepo]# git remote  # 查看远程分支
origin
[root@work gitrepo]# git remote -v # 查看远程分支详细信息
origin  [email protected]:AndySkyL/gitrepo.git (fetch)
origin  [email protected]:AndySkyL/gitrepo.git (push)

提交是出现冲突:

[root@work gitrepo]# git add readme.txt 
[root@work gitrepo]# git commit -m "dev2"
[dev 41ad4f8] dev2
 1 file changed, 1 insertion(+), 3 deletions(-)
 
[root@work gitrepo]# git push origin dev   # 推送dev分支冲突

▽! [rejected]        dev -> dev (fetch first)
error: failed to push some refs to '[email protected]:AndySkyL/gitrepo.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first merge the remote changes (e.g.,
hint: 'git pull') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

[root@work gitrepo]# git pull   # 根据提示使用git pull
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:AndySkyL/gitrepo
 * [new branch]      dev        -> origin/dev
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details
    git pull       
If you wish to set tracking information for this branch you can do so with:
    git branch --set-upstream-to=origin/ dev   # 这里已经给出提示
    
[root@work gitrepo]# git branch --set-upstream-to=origin/dev dev 
Branch dev set up to track remote branch dev from origin.

[root@work gitrepo]# git pull  #执行此命令之后再按照之前的方式修改文件,解决冲突
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

解决冲突后提交:

[root@work gitrepo]# git add readme.txt 
[root@work gitrepo]# git commit -m "fix m"
[dev 3267ad5] fix m

[root@work gitrepo]# git push origin dev
Counting objects: 10, done.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 570 bytes | 0 bytes/s, done.
Total 6 (delta 0), reused 0 (delta 0)
   17a9b60..3267ad5  dev -> dev

从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;

在本地创建和远程分支对应的分支,使用

git checkout -b branch-name origin/branch-name 
# 本地和远程分支的名称最好一致;


建立本地分支和远程分支的关联,使用:

git branch --set-upstream-to=origin/dev dev


标签管理

  • 标签可以是每一次commit 的标识,类似于给每次commit添加一个别名:

[root@work gitrepo]# git branch
  dev
* master
[root@work gitrepo]# git tag v1.0
[root@work gitrepo]# git tag
v1.0

默认标签是打在最新提交的commit上的。

  • 如果要对之前的某一次commit打标签后面直接接上commit ID即可:

[root@work gitrepo]# git log --pretty=oneline --abbrev-commit
e2ce160 fix bug issue
8b29da7 fix issue
881136a fix bug example
[root@work gitrepo]# git tag v0.9 881136a  #根据log 对对应的commit打标签,可以使用-m
[root@work gitrepo]# git tag               #添加说明
v0.9                                       # git标签的排列默认是以标签名的字母顺序排列的
v1.0
  • 使用tag查看具体信息:

[root@work gitrepo]# git show v1.0
commit e2ce160ad30d5433c033d9be7dc5dfe23ddbfd6d
Merge: 881136a 8b29da7
Author: trying 
Date:   Wed Dec 14 16:16:32 2016 +0800
    fix bug issue
  • 也可以在新建tag时添加说明:

 git tag -a v2.0 -m "version 2.0 released"   # -a 指定tag名称 -m 添加说明
  • 删除标签

# git tag -d v2.0
Deleted tag 'v2.0' (was 959f8b1)
  • 推送标签到远程

    由于在本地添加的标签不会自动推送到远程,如果需要推送本地的标签到远程,使用git push origin tagname:

# git push origin v1.0    # 推送指定的tag
# git push origin --tags  # 一次推送所有的tag
  • 删除远程标签

删除远程标签需要先删除本地标签:

# git tag
v0.9
v1.0

# git tag -d v0.9    # 删除本地tag
Deleted tag 'v0.9' (was 881136a)

# git push origin :refs/tags/v0.9   # 删除远程标签
 - [deleted]         v0.9

git push origin :refs/tags/tagname

GIT高亮显示字体颜色:

# git config --global color.ui true



搭建GIT服务器

如果自己不想使用github的付费仓库,可以自己搭建一个私有的git 服务器供企业内部使用。

安装git:

yum install git -y

创建一个git用户:

useradd git

禁止git 用户登录shell,编辑/etc/passwd文件,将git用户默认的shell改为:

git:x:823:823::/home/git:/usr/bin/git-shell

创建一个用于GIT仓库的目录:

mkdir /gitrepo
cd /gitrepo

初始化git仓库:

git init --bare  test.git

在/home/git用户的目录下创建密钥认证文件authorized_keys ,将本地的公钥导入服务端的authorized_keys 文件中:

cat id_rsa.pub  > /home/git/.ssh/authorized_keys

然回到本地,就可以获取git服务器上的工作目录了:

[root@work ~]# git clone [email protected]:/gitrepo/test.git
Cloning into 'test'...
warning: You appear to have cloned an empty repository.

这就可以和在github上一样操作了。