Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上。怎么分布呢?最早, 肯定只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库, 而且每台机器的版本库其实都是一样的,并没有主次之分。

实际情况往往是这样,找一台电脑充当服务器的角色,每天24小时开机, 其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里, 也从服务器仓库中拉取别人的提交。也就是说这个”服务器“只不过是用来作为一个桥梁, 提供给各个主机进行修改的交换。

使用GitHub

在GitHub出现以前,开源项目开源容易,但让广大人民群众参与进来比较困难,也只能把diff文件用邮件发过去,很不方便。

但是在GitHub上,利用Git极其强大的克隆和分支功能,广大人民群众真正可以第一次自由参与各种开源项目了。

  • 在GitHub上,可以任意Fork开源仓库;
  • 自己拥有Fork后的仓库的读写权限;
  • 可以推送pull request给官方仓库来贡献代码。

关于GitHub的使用比较简单,参考官方指南, 大概20分钟就能看懂整个流程。

看完之后就可以自己创建一个远程仓库了,比如我现在创建了一个叫”gitdemo”的repository 注意,我在初始化的时候还选择了创建一个README.md和一个LICENSE文件。

克隆远程仓库

先有远程仓库,直接通过远程仓库初始化本地仓库,比如:

git clone https://github.com/yidao620c/gitdemo.git

添加远程库

先有本地库,后有远程库的时候,如何关联远程库呢?就使用git remote add命令:

git remote add origin https://github.com/yidao620c/gitdemo.git

查看远程库信息:

[root@controller161 gitdemo]# git remote -v
origin  https://github.com/yidao620c/gitdemo.git (fetch)
origin  https://github.com/yidao620c/gitdemo.git (push)

上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。

推送分支

推送分支,就是把该分支上的所有本地提交推送到远程库。推送时要指定本地分支, Git就会把该分支推送到远程库对应的远程分支上:

git push origin master

如果推送的是dev分支就要这样写:

git push origin dev

但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?

  • master分支是主分支,因此要时刻与远程同步;
  • dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
  • bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
  • feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。

抓取分支

多人协作时,大家都会往master和dev分支上推送各自的修改。

这里我新创建的远程仓库还没有dev分支,这时候我先在本地创建dev分支,再push上去。 在dev分支上面,修改README.md内容如下:

# gitdemo
just for gitdemo testdev branch add by "自己"

然后add,commit,push三部曲:

[root@controller161 gitdemo]# vim README.md
[root@controller161 gitdemo]# git add README.md
[root@controller161 gitdemo]# git commit -m "dev branch modify readme by self"
[dev 796e584] dev branch modify readme by self1 file changed, 2 insertions(+)
[root@controller161 gitdemo]# git push origin dev
...后面省略...

现在,模拟另外一个协作着,可以在另一个目录下克隆:

mkdir -p /root/work1 && cd /root/work1
git clone https://github.com/yidao620c/gitdemo.git
# 克隆单个分支
git clone -b mybranch --single-branch git://sub.domain.com/repo.git

现在我本地有两个仓库:

[root@controller161 gitdemo]# pwd
/root/work/gitdemo[root@controller161 gitdemo]# pwd
/root/work1/gitdemo

不妨把/root/work1/gitdemo这个仓库使用者暂时称为”小明”,原来仓库使用者叫”自己”。

从远程库clone时,默认情况下小明只能看到本地的master分支,用git branch命令看看:

[root@controller161 gitdemo]# git branch
* master

现在,小明要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用这个命令创建本地dev分支:

[root@controller161 gitdemo]# git checkout -b dev origin/dev
Branch dev set up to track remote branch dev from origin.
Switched to a new branch 'dev'

现在,小明就可以在dev上继续修改,然后,时不时地把dev分支push到远程。 他也修改了README.md文件,并且修改的同一行,内容如下:

# gitdemo
just for gitdemo testdev branch add by "自己", add by xiao ming

然后也commit后push到dev上面:

[root@controller161 gitdemo]# vim README.md
[root@controller161 gitdemo]# git add README.md
[root@controller161 gitdemo]# git commit -m "modify readme by xiao ming"
[dev 10c9f30] modify readme by xiao ming1 file changed, 1 insertion(+), 1 deletion(-)
[root@controller161 gitdemo]# git push origin dev
...后面省略...

这时候你自己再次修改README.md,然后推送:

[root@controller161 gitdemo]# vim README.md
[root@controller161 gitdemo]# git add README.md
[root@controller161 gitdemo]# git commit -m "modify README again"
[dev 3c18f63] modify README again1 file changed, 1 insertion(+), 1 deletion(-)
[root@controller161 gitdemo]# git push origin dev
Username for 'https://github.com': yidao620c
Password for 'https://yidao620c@github.com':
To https://github.com/yidao620c/gitdemo.git! [rejected]        dev -> dev (fetch first)
error: failed to push some refs to 'https://github.com/yidao620c/gitdemo.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 integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

提示很明显,你要先拉取最新代码合并才能push,好,那我先执行git pull合并:

[root@controller161 gitdemo]# git pull origin dev
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From https://github.com/yidao620c/gitdemo* branch            dev        -> FETCH_HEAD796e584..10c9f30  dev        -> origin/dev
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

自动合并失败,需要手动解决冲突,这时候我手动去解决README.md这个文件的冲突,方法和分支管理篇的解决方法一样。 先自己去修改这个文件,内容修改成如下:

# gitdemo
just for gitdemo test1111111 dev branch add by "自己", add by xiao ming

改好了,再add, commit,push:

[root@controller161 gitdemo]# git add README.md
[root@controller161 gitdemo]# git commit -m "ok , I resolve confict"
[dev ad6fa66] ok , I resolve confict
[root@controller161 gitdemo]# git push origin dev
...后面省略...

因此,多人协作的工作模式通常是这样:

  1. 首先,可以试图用git push origin branch-name推送自己的修改;
  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
  3. 如果合并有冲突,则解决冲突,并在本地提交;
  4. 没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
  5. 如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建, 用命令git branch --set-upstream branch-name origin/branch-name

这就是多人协作的工作模式,一旦熟悉了,就非常简单。

再总结一下远程分支使用:

  • 查看远程库信息,使用git remote -v
  • 本地新建的分支如果不推送到远程,对其他人就是不可见的;
  • 从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
  • 在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
  • 建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name
  • 从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。

pull requests

这个是GitHub上面最主要的协作开发模式,有了这个普通平民也能参与开发顶级项目了。

如果你想对某个开源软件做贡献,就先fork这个仓库,这样就会在你自己的远程仓库中复制一份一模一样的仓库。

GitHub官网指南上面有个官方的仓库,专门用来给大家fork用,就是https://github.com/octocat/Spoon-Knife

我把它fork下来后,就是下面这样:

然后你所有的修改就在自己的这个远程仓库上面完成,等你修改好以后。登陆GitHub,在项目主页, 点击”Pull requests” 菜单,点击”New pull request”按钮,填写你的修改说明提交就可以了。

至于你的这个Pull requests能不能被合并,就看该项目维护者的心情了。

保持fork之后的项目和上游同步

团队协作,为了规范,一般都是fork组织的仓库到自己帐号下,再提交pr,组织的仓库一直保持更新, 下面介绍如何保持自己fork之后的仓库与上游仓库同步。

下面以我 fork 团队的博客仓库为例

点击 fork 组织仓库到自己帐号下,然后就可以在自己的帐号下 clone 相应的仓库

使用 git remote -v 查看当前的远程仓库地址,输出如下:

origin  git@github.com:ibrother/staticblog.github.io.git (fetch)
origin  git@github.com:ibrother/staticblog.github.io.git (push)

可以看到从自己帐号 clone 下来的仓库,远程仓库地址是与自己的远程仓库绑定的(这不是废话吗)

接下来运行

git remote add upstream https://github.com/staticblog/staticblog.github.io.git

这条命令就算添加一个别名为 upstream(上游)的地址,指向之前 fork 的原仓库地址。git remote -v 输出如下:

origin   git@github.com:ibrother/staticblog.github.io.git (fetch)
origin   git@github.com:ibrother/staticblog.github.io.git (push)
upstream https://github.com/staticblog/staticblog.github.io.git (fetch)
upstream https://github.com/staticblog/staticblog.github.io.git (push)

之后运行下面几条命令,就可以保持本地仓库和上游仓库同步了

git fetch upstream
git checkout master
git merge upstream/master

或者更简单的命令:

git pull upstream {branch name}

接着就是熟悉的推送本地仓库到远程仓库

git push origin master

然后可以去github上自己的托管空间上创建pull request

git工作流

这里讲最常见的三种工作流:

Centralized Workflow

和svn类似,就一个master分支,push/pull循环

Feature Branch workflow

所有的feature开发都必须在特定的branch下而不是直接在master分之下开发

feature分支开发完成后,发起merge requests,项目经理在code review后合并

Gitlab关于这种工作流的说明: https://docs.gitlab.com/ee/workflow/workflow.html

Forking workflow

不同于使用唯一一个server-side repo作为中央库,这种工作流给每一个开发人员都定义分配一个server-side repo。 这意味着每一个contributor都有两个git repo:一个local one,一个public server-side one;

但是有个官方的official repo,大家的server-side repo都是从这个official repo通过fork操作获得。

一般流程为:

  • 项目经理初始化”official repo“
  • 开发人员从official repo来做fork
  • 开发人员从他们forked repo来做clone到本地
  • 开发人员在他们自己的feature上进行开发工作
  • git pull upstream master
  • git push origin feature-branch
  • 提交一个pull requests
  • 项目经理合并开发人员申请的feature
  • 开发人员和official repo保持同步更新
  • 其他开发人员同步更新:git pull upstream master

三种工作流使用场景

  1. Centralized Workflow => 习惯了svn,团队很小,项目简单
  2. Feature Branch workflow => 一般的内部团队项目开发
  3. Forking workflow => 大型分布式协作开发,开源软件

标签管理

最后还有标签就放这里讲吧,因为要涉及远程标签。 发布一个版本时,我们通常先在版本库中打一个标签(tag),这样就唯一确定了打标签时刻的版本,标签也是版本库的一个快照。 其实就是一个commit的别名而已,方便我们记忆,不如你说你要发布软件新版本号为”7b66ea9e”,这都什么跟什么啊。

创建标签:

git tag v1.0

查看所有标签:

git tag

默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,比如现在已经是周五了,但应该在周一打的标签没有打,怎么办? 还记得以前的git log命令么,它能记录所有commit历史:

[root@controller161 gitdemo]# git log --pretty=oneline --abbrev-commit
ad6fa66 ok , I resolve confict
3c18f63 modify README again
10c9f30 modify readme by xiao ming
796e584 dev branch modify readme by self
dbf4ee5 Initial commit

比如你要对”modify readme by xiao ming”这个提交打个标签,就这样做:

git tag v0.2 10c9f30

查看单个标签:

git show v0.2

还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字

git tag -a v0.3 -m "version 0.3 released" 3c18f63

再次使用git show就可以看到说明信息:

[root@controller161 gitdemo]# git show v0.3
tag v0.3
Tagger: xiongneng <xiongneng@winhong.com>
Date:   Mon Mar 6 17:00:06 2017 +0800version 0.3 releasedcommit 3c18f63fb6d1ecf2e08608083050cd1a9d280667
Author: xiongneng <xiongneng@winhong.com>
Date:   Mon Mar 6 16:45:46 2017 +0800modify README again

标签还能用PGP签名,这里就不多讲了,好像暂时用不到。

删除标签:

git tag -d v0.2

推送标签到远程仓库:

git push origin v0.3

一次性推送全部尚未推送到远程的本地标签:

git push origin --tags

如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:

git tag -d v0.3
Deleted tag 'v0.3' (was 6d3cf45)

然后,从远程删除,删除命令也是push,但是格式如下:

git push origin :refs/tags/v0.3
To https://github.com/yidao620c/gitdemo.git- [deleted]         v0.3

总结一下标签命令:

  • 命令git tag <name>用于新建一个标签,默认为HEAD,也可以指定一个commit id;
  • 命令git tag -a <tagname> -m "blablabla..."可以指定标签信息;
  • 命令git tag -s <tagname> -m "blablabla..."可以用PGP签名标签;
  • 命令git tag可以查看所有标签。
  • 命令git push origin <tagname>可以推送一个本地标签;
  • 命令git push origin --tags可以推送全部未推送过的本地标签;
  • 命令git tag -d <tagname>可以删除一个本地标签;
  • 命令git push origin :refs/tags/<tagname>可以删除一个远程标签。

FAQ

怎样不合并拉取远程服务器最新的某个文件:

git fetch {remote}
git checkout FETCH_HEAD -- {file}

git 获取某个提交变更的文件,如果不加commit id表示最后一次提交:

# git show -r --pretty="" --name-status
M       README.md
A       image/dd.txt
D       test.json

转自:
https://www.xncoding.com/2017/02/08/fullstack/git03.html

git简明教程 - 协作篇相关推荐

  1. 廖雪峰Git简明教程整理

    廖雪峰Git简明教程 声明:本教程完全搬运自廖雪峰老师的个人网站,仅限于学习使用.所有版权归廖雪峰老师所有.整理人为Megatron,如果侵权请联系本人zhangwz93@foxmail.com删除. ...

  2. git简明教程:基本操作命令

    **配置Git** #首先在本地创建ssh key: ssh-keygen -t rsa -C "your_email@youremail.com" #为了验证是否成功,在git ...

  3. git add 撤销_更科学地管理你的项目,Git 简明教程(二)

    修改文件内容 上回说到,我们已经成功创建并提交了一个 README.md 文件到 FirstGit 版本库中 1.修改文件 现在我们更改 README.md 内容 2.查看版本库状态 该文件夹内右键运 ...

  4. 简明教程 | Docker篇 · 其二:Dockerfile的编写

    Dockerfile的构建 Dockerfile是什么 一个包含用于组合 image 的命令的文本文件,docker 通过 dockerfile 和构建环境的上下文来构建 image . 编写Dock ...

  5. 简明教程 | Docker篇 · 其一:基础入门

    了解Docker Docker是什么 Docker是指容器化技术,用于支持创建和使用 Linux 容器,同时Docker也是软件容器平台. 什么是容器(container) 容器是主机上与其他进程隔离 ...

  6. Java Web 简明教程

    点此查看 所有教程.项目.源码导航 1. 前言 本教程用于介绍Java Web开发入门的方方面面,包括开发环境.工具.网页.Java.数据库等. 本教程写于2016年底,一些内容相对比较陈旧了,新版的 ...

  7. Git简明入土教程2.4万字-转自廖雪峰Git

    文章目录 0 前言 1 简介 2 切换仓库版本 2.1 版本回退 2.2 工作区与暂存区 2.3 管理修改 2.4 撤销修改 2.5 删除文件 3 远程仓库 3.1 添加远程库 3.2 从远程库克隆 ...

  8. Git GitHub 简明教程

    Git & GitHub 简明教程 文章目录 Git & GitHub 简明教程 @[toc] 一. Git 安装 Linux 上安装 Git Mac 上安装 Git Windows ...

  9. 如何团队协作,代码托管?Git使用教程:最详细、最浅显、一文读懂Git常用操作!...

    点击上方"Datawhale",选择"星标"公众号 第一时间获取价值内容 作者:涂根华 来源:www.cnblogs.com/tugenhua0707 Git使 ...

  10. Git篇——Git使用教程

    Git篇--Git使用教程 摘要 1. Git工作区域 1.1 工作区(Working Directory) 1.2 暂存区 1.3 Git Repository(Git 仓库) 2. 向仓库中添加文 ...

最新文章

  1. 【STM32】输入捕获实验代码详解
  2. python3 xpath_Python3使用Xpath解析网易云音乐歌手页面
  3. HTML中字体的垂直排列
  4. zend 修改默认view路径,添加扩展view
  5. Java多线程知识小抄集(一)
  6. python比较两个二进制文件_python三种方法判断文件是否为二进制文件
  7. lintcode: 把排序数组转换为高度最小的二叉搜索树
  8. 龙芯.NET正式发布 开源共享与开发者共成长
  9. php curl nginx post 空_【青藤云安全研究】绕过php的disable_functions(上篇)
  10. 统计输入的字母 c语言,请问这个用c怎么做:输入一串字符,分别统计其中数字和字母的个数...
  11. IDC:安全性、价格和低复杂性是企业采用SD-WAN的主要动因
  12. java 单例加锁方法的讨论
  13. c语言枚举常量,浅述C语言中枚举enum的用法
  14. ubuntu16.04 内核源码编译
  15. LED灯随机亮起几个灯
  16. 必先利其器——Python机器学习环境搭建
  17. python批量创建文件与批量创建文件夹
  18. 向量ab怎么用计算机打出来,向量怎么用wps打出来
  19. Linux搭建tor网络环境
  20. LINODE优惠码与服务器搭建

热门文章

  1. Excel怎么转PDF格式?这些方法值得收藏
  2. 清华大学计算机系学术委员会,清华大学学术委员会召开2018年度全体会议
  3. Android渠道包生成工具(支持V1、V2签名)
  4. exchange rate维护
  5. Dropping Pixels for Adversarial Robustness
  6. 幼儿园调查过程怎么写_幼儿园的调查报告范文
  7. android手机电话铃声设置,怎么设置来电铃声-安卓手机小技巧:教你传输自己喜欢的歌曲铃声到系统铃声设置里...
  8. [乐意黎原创]hosts文件位置及说明
  9. idea查看代码行数Statistic
  10. Debezium系列之:手动创建存放ddl database.history.kafka.topic对应的topic