目录
1. 环境部署
1.1 linux环境部署
1.1.1 git安装
首先,你可以试着输入 git,看看系统有没有安装 Git:
$ git
The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git
像上面的命令,有很多 Linux 会友好地告诉你 Git 没有安装,还会告诉你如何安装 Git。
如果你碰巧用 Debian 或 Ubuntu Linux,通过一条sudo apt-get install git
就可以直接完成 Git 的安装,非常简单。
如果是其他 Linux 版本,可以直接通过源码安装。先从 Git 官网下载源码,然后解压,依次输入:./config,make,sudo make install
这几个命令安装就好了。
1.1.2 创建版本库
什么是版本库呢?版本库又名仓库,英文名 repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被 Git 管理起来,每个文件的修改、删除,Git 都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
所以,创建一个版本库非常简单,首先,选择一个合适的地方,创建一个空目录:
$ mkdir learngit
$ cd learngit
$ pwd
/Users/michael/learngit
pwd
命令用于显示当前目录。在我的 Mac 上,这个仓库位于/Users/michael/learngit
。
如果你使用 Windows 系统,为了避免遇到各种莫名其妙的问题,请确保目录名(包括父目录)不包含中文。
第二步,通过git init
命令把这个目录变成 Git 可以管理的仓库:
$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/
瞬间 Git 就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository),细心的读者可以发现当前目录下多了一个.git
的目录,这个目录是 Git 来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把 Git 仓库给破坏了。
如果你没有看到.git
目录,那是因为这个目录默认是隐藏的,用ls -ah
命令就可以看见。
如果项目代码版本库已经存在的话,则只需要通过git clone xxxx 命令将远程仓库代码拉取到本地仓库就可以。先进入到本地仓库文件夹目录下,,如下图:
使用Git Bash或命令行工具,在系统合适位置(如:E:\MyWorkspace)拉取远程仓库代码,这个位置将作为本地仓库
如果已有对应远程仓库的本地仓库,在本地仓库执行指令”git pull”获取到最新代码,再继续下面的步骤。
1.1.2 git 文件修改提交操作示例
言归正传,现在我们编写一个 readme.txt 文件,内容如下:
Git is a version control system.
Git is free software.
一定要放到 learngit 目录下(子目录也行),因为这是一个 Git 仓库,放到其他地方 Git 再厉害也找不到这个文件。
和把大象放到冰箱需要 3 步相比,把一个文件放到 Git 仓库只需要两步。
第一步,用命令git add
告诉 Git,把文件添加到仓库:
$ git add readme.txt
执行上面的命令,没有任何显示,这就对了,Unix 的哲学是“没有消息就是好消息”,说明添加成功。
第二步,用命令git commit
告诉 Git,把文件提交到仓库:
$ git commit -m "wrote a readme file"
[master (root-commit) cb926e7] wrote a readme file
1 file changed, 2 insertions(+)
create mode 100644 readme.txt
简单解释一下git commit
命令,-m
后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。
嫌麻烦不想输入-m "xxx"
行不行?确实有办法可以这么干,但是强烈不建议你这么干,因为输入说明对自己对别人阅读都很重要。实在不想输入说明的童鞋请自行 Google,我不告诉你这个参数。
git commit
命令执行成功后会告诉你,1 个文件被改动(我们新添加的 readme.txt 文件),插入了两行内容(readme.txt 有两行内容)。
为什么 Git 添加文件需要 add,commit 一共两步呢?因为 commit 可以一次提交很多文件,所以你可以多次 add 不同的文件,比如:
$ git add file1.txt
$ git add file2.txt file3.txt
$ git commit -m "add 3 files."
小结:
现在总结一下今天学的两点内容:
初始化一个 Git 仓库,使用git init
命令。
添加文件到 Git 仓库,分两步:
第一步,使用命令git add <file>
,注意,可反复多次使用,添加多个文件;
第二步,使用命令git commit
,完成。
1.2 windows环境部署
1.2.1 git安装
msysgit 是 Windows 版的 Git,从 http://msysgit.github.io/ 下载,然后按默认选项安装即可。
安装完成后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明 Git 安装成功!
安装完成后,还需要最后一步设置,在命令行输入:
因为 Git 是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和 Email 地址。你也许会担心,如果有人故意冒充别人怎么办?这个不必担心,首先我们相信大家都是善良无知的群众,其次,真的有冒充的也是有办法可查的。
注意git config
命令的--global
参数,用了这个参数,表示你这台机器上所有的 Git 仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和 Email 地址。
注:
千万不要使用 Windows 自带的记事本编辑任何文本文件。原因是 Microsoft 开发记事本的团队使用了一个不合理的方法来保存 UTF-8 编码的文件,他们在每个文件开头添加了 0xefbbbf(十六进制)的字符,你会遇到很多不可思议的问题,比如,网页第一行可能会显示一个“?”,明明正确的程序一编译就报语法错误,等等,都是由记事本的弱智行为带来的。建议你下载Notepad++代替记事本,不但功能强大,而且免费!记得把 Notepad++ 的默认编码设置为 UTF-8 without BOM 即可:
2. 开发应用
概述
开发人员接到新的开发任务后,如果没有拉取过远程仓库代码,就拉取一次。否则请先更新到代码最新状态。然后,由第一个人创建一个新的开发分支并推送到远程。再然后,所有开发同一功能的开发人员跟踪对应的远程开发分支,进行开发。最后功能开发完成时,由最后一人提交代码统一提交代码Review,通过后将代码提交到master。功能开发完成。
原文链接:https://blog.csdn.net/gotofind/article/details/78960737
正常的开发流程应该是上面这样,但有些地方使用gerrit(code review),可能会直接在Master本地分支上进行开发,因为修改完代码之后首先提交代码到gerrit,review 完成之后,才会被合入到Master远端分支。
2.1 git常用命令列表
git commend | commend discription |
git init | 在当前目录新建一个Git代码库 |
git status | 查看文件状态 |
git log | 1、log后面不带参数,表示显示有变更的文件 2、log后面带--stat ,表示显示commit历史,以及每一次commit发生变更的文件。 3、log后面带 -S [keyword],表示搜索提交历史,根据关键词。 4、log后面带 [tag] HEAD --pretty=format:%s,显示某个commit之后的所有变动,每个commit占据一行。 5、log后面带 [tag] HEAD --grep feature,显示某个commit之后的所有变动,其“提交说明”必须符合条件。
|
git config -e [--global] | 编辑Git配置文件 |
git config --list | 显示当前的Git配置 |
git config [--global] user.name "[name]" | 设置提交代码时的用户信息 |
git config [-global] user.email "[email address]" | |
git reset --hard HEAD^ | 可以通过该命令回退到上一个版本或者之前的某一个版本 |
git clone [url] | 下载一个项目和它的整个代码历史 |
git add ./xxxx | 1、add 后面跟".",监控工作去的状态树,使用它会把工作时的所有变化提交到暂存区,包括文件内容修改(modified)以及新文件(new),但不包括被删除的文件,。 2、后面如果跟文件则代表添加指定文件到暂存区。 3、add 后面还可以跟路径。 |
git rm --cached [file] | 停止追踪指定文件,但该文件会保留在工作区 |
git rm [file1] [file2] | 删除工作区文件,并且将这次删除放入暂存区 |
git commit -m [message] | 主要是将暂存区里的改动给提交到本地的版本库。每次使用git commit 命令我们都会在本地版本库生成一个40位的哈希值,这个哈希值也叫commit-id,commit-id在版本回退的时候是非常有用的,它相当于一个快照,可以在未来的任何时候通过与git reset的组合命令回到这里。 |
git commit [file1] [file2] ... -m [message] | 提交暂存区的指定文件到仓库去 |
git commit -a | 提交工作区自上次commit 之后的变化,直接到仓库区 |
git commit -v | 提交时显示所有diff信息 |
git commit --amend -m [message] | 使用依次新的commit,替代上一次提交,如果代码没有变化,则用来改写上一次commit的提交信息。 |
git commit -amend [file1] [file2] ... | 重做上一次commit,并包括指定文件的新变化 |
git diff HEAD --readme.txt命令 | 可以查看工作区和版本库里面最新版本的区别 |
git branch | 1、branch 后面不带参数,表示列出所有本地分支。 2、后面参数为 -r,表示列出所有远程分支。 3、后面参数为-a, 表示列出所有本地分支和远程分支。 |
git branch [branch -name] | 新建一个分支,但依然停留在当前分支 |
git branch [branch] [commit] | 新建一个分支,指向指定commit |
git branch --set -upstream [branch] [remote-branch] | 建立追踪关系,在现有分支与指定的远程分支之间 |
git branch -d [branch-name] | 删除指定分支 |
git push origin --delete [branch-name] | 删除远程分支 |
git branch -dr [remote/branch] | 删除远程分支 |
git merge [branch] | 合并指定分支到当前分支 |
git cherry-pick [commit] | 选择一个commit,合并进当前分支 |
git checkout [branch-name] | 切换到指定分支,并跟新工作区 |
git checkout - | 切换到上一个分支 |
git checkout -b [branch] origin/[remote-brank] | 以远端分支为基础新建一个分支,并切换到该分支 |
git tag [tag] | 新建一个tag 在当前commit |
git tag -d [tag] | 删除本地tag |
git push origin :refs/tags/[tagName] | 删除远程tag |
git show [tag] | 查看指定tag信息 |
git push [remote] [tag] | 提交指定tag |
git tag | 列出所有tag |
git checkout -b [branch] [tag] | 新建一个分支,指向某个tag |
git fetch [remote] | 下载远程仓库的所有变动 |
git remote -v | 显示所有远程仓库 |
git remote show [remote] | 显示某个远程仓库的信息 |
git push [remote] [branch] | 上传本地指定分支到远程仓库 |
git pull [remote] [branch] | 取回远程仓库的变化,并与本地分支合并 |
git rebase | |
git checkout [file] | 恢复暂存区的指定文件到工作区 |
git checkout [commit] [file] | 恢复某一个commit的指定文件到暂存区和工作去 |
git checkout . | 恢复暂存区的所有文件到工作区 |
git pull --rebase | 获取一下当前最新版本 |
下面是我整理的常用 Git 命令清单。几个专用名词的译名如下。
- Workspace:工作区
- Index / Stage:暂存区
- Repository:仓库区(或本地仓库)
- Remote:远程仓库
参考链接:https://blog.csdn.net/web_csdn_share/article/details/79243308
2.2 git 创建一个自己的远端Master分支
拿github来举例,假设已经创建好本地master分支,现在需要创建一个远端master分支,并且让本地分支和远端分支建立关联。
2.2.1添加远程库
现在的情景是,你已经在本地创建了一个 Git 仓库后,又想在 GitHub 创建一个 Git 仓库,并且让这两个仓库进行远程同步,这样,GitHub 上的仓库既可以作为备份,又可以让其他人通过该仓库来协作,真是一举多得。
首先,登陆 GitHub,然后,在右上角找到“Create a new repo”按钮,创建一个新的仓库:
在 Repository name 填入 learngit,其他保持默认设置,点击“Create repository”按钮,就成功地创建了一个新的 Git 仓库:
目前,在 GitHub 上的这个 learngit 仓库还是空的,GitHub 告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到 GitHub 仓库。
现在,我们根据 GitHub 的提示,在本地的 learngit 仓库下运行命令:
$ git remote add origin git@github.com:michaelliao/learngit.git
请千万注意,把上面的 michaelliao 替换成你自己的 GitHub 账户名,否则,你在本地关联的就是我的远程库,关联没有问题,但是你以后推送是推不上去的,因为你的 SSH Key 公钥不在我的账户列表中。
添加后,远程库的名字就是 origin,这是 Git 默认的叫法,也可以改成别的,但是 origin 这个名字一看就知道是远程库。
下一步,就可以把本地库的所有内容推送到远程库上:
$ git push -u origin master
Counting objects: 19, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (19/19), done.
Writing objects: 100% (19/19), 13.73 KiB, done.
Total 23 (delta 6), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
* [new branch] master -> master
Branch master set up to track remote branch master from origin.
把本地库的内容推送到远程,用git push
命令,实际上是把当前分支 master 推送到远程。
由于远程库是空的,我们第一次推送 master 分支时,加上了-u
参数,Git 不但会把本地的 master 分支内容推送的远程新的 master 分支,还会把本地的 master 分支和远程的 master 分支关联起来,在以后的推送或者拉取时就可以简化命令。
推送成功后,可以立刻在 GitHub 页面中看到远程库的内容已经和本地一模一样:
从现在起,只要本地作了提交,就可以通过命令:
$ git push origin master 把本地master分支的最新修改推送至GitHub,现在,你就拥有了真正的分布式版本库!
小结:
要关联一个远程库,使用命令git remote add origin git@server-name:path/repo-name.git
;
关联后,使用命令git push -u origin master
第一次推送 master 分支的所有内容;
此后,每次本地提交后,只要有必要,就可以使用命令git push origin master
推送最新修改;
分布式版本系统的最大好处之一是在本地工作完全不需要考虑远程库的存在,也就是有没有联网都可以正常工作,而SVN在没有联网的时候是拒绝干活的!当有网络的时候,再把本地提交推送一下就完成了同步,真是太方便了!
2.2.2 从远程库克隆
上次我们讲了先有本地库,后有远程库的时候,如何关联远程库。
现在,假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆。
首先,登陆 GitHub,创建一个新的仓库,名字叫 gitskills:
我们勾选Initialize this repository with a README
,这样 GitHub 会自动为我们创建一个README.md
文件。创建完毕后,可以看到README.md
文件:
现在,远程库已经准备好了,下一步是用命令git clone
克隆一个本地库:
$ git clone git@github.com:michaelliao/gitskills.git
Cloning into 'gitskills'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.
$ cd gitskills
$ ls
README.md
注意把 Git 库的地址换成你自己的,然后进入 gitskills 目录看看,已经有 README.md 文件了。
如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。
你也许还注意到,GitHub 给出的地址不止一个,还可以用https://github.com/michaelliao/gitskills.git这样的地址。实际上,Git 支持多种协议,默认的git://
使用 ssh,但也可以使用 https 等其他协议。
使用 https 除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放 http 端口的公司内部就无法使用 ssh 协议而只能用 https。
小结:
要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone
命令克隆。
Git 支持多种协议,包括 https,但通过 ssh 支持的原生 git 协议速度最快。
原文链接:https://wiki.jikexueyuan.com/project/git-tutorial/clone-repository.html
2.3 git 基于Master 分支创建个人分支
2.3.1 创建与合并分支
在版本回退里,你已经知道,每次提交,Git 都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在 Git 里,这个分支叫主分支,即 master 分支。HEAD 严格来说不是指向提交,而是指向 master,master 才是指向提交的,所以,HEAD指向的就是当前分支。
一开始的时候,master 分支是一条线,Git 用 master 指向最新的提交,再用 HEAD 指向 master,就能确定当前分支,以及当前分支的提交点:
每次提交,master 分支都会向前移动一步,这样,随着你不断提交,master 分支的线也越来越长:
当我们创建新的分支,例如 dev 时,Git 新建了一个指针叫 dev,指向 master 相同的提交,再把 HEAD 指向 dev,就表示当前分支在 dev 上:
你看,Git 创建一个分支很快,因为除了增加一个 dev 指针,改改 HEAD 的指向,工作区的文件都没有任何变化!
不过,从现在开始,对工作区的修改和提交就是针对 dev 分支了,比如新提交一次后,dev 指针往前移动一步,而 master 指针不变:
假如我们在 dev 上的工作完成了,就可以把 dev 合并到 master 上。Git 怎么合并呢?最简单的方法,就是直接把 master 指向 dev 的当前提交,就完成了合并:
所以 Git 合并分支也很快!就改改指针,工作区内容也不变!
合并完分支后,甚至可以删除 dev 分支。删除 dev 分支就是把 dev 指针给删掉,删掉后,我们就剩下了一条 master 分支:
真是太神奇了,你看得出来有些提交是通过分支完成的吗?
首先,我们创建 dev 分支,然后切换到 dev 分支:
$ git checkout -b dev
Switched to a new branch 'dev'
git checkout
命令加上-b
参数表示创建并切换,相当于以下两条命令:
$ git branch dev
$ git checkout dev
Switched to branch 'dev'
2.4 git 分支间的切换操作
,用git branch
命令查看当前分支:
$ git branch
* dev
master
git branch
命令会列出所有分支,当前分支前面会标一个*
号。
git checkout dev/Master //切换到个人分支或Master主分支
dev 分支的工作完成,我们就可以切换回 master 分支:
$ git checkout master
Switched to branch 'master'
切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!因为那个提交是在dev分支上的,而master分支此刻的提交点并未改变:
2.5 git 个人分支代码merge到Master分支
现在,我们把 dev 分支的工作成果合并到 master 分支上:
$ git merge dev
Updating d17efd8..fec145a
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)
git merge
命令用于合并指定分支到当前分支。合并后,再查看 readme.txt 的内容,就可以看到,和 dev 分支的最新提交是完全一样的。
注意到上面的Fast-forward
信息,Git 告诉我们,这次合并是“快进模式”,也就是直接把 master 指向 dev 的当前提交,所以合并速度非常快。
当然,也不是每次合并都能 Fast-forward,我们后面会将其他方式的合并。
2.6 git 修改代码提交
修改代码之后提交
$ git add readme.txt
$ git commit -m "branch test"
[dev fec145a] branch test
1 file changed, 1 insertion(+)
2.7 git 合入Master分支时有冲突处理
人生不如意之事十之八九,合并分支往往也不是一帆风顺的。
准备新的 feature1 分支,继续我们的新分支开发:
$ git checkout -b feature1
Switched to a new branch 'feature1'
修改 readme.txt 最后一行,改为:
Creating a new branch is quick AND simple.
在 feature1 分支上提交:
$ git add readme.txt
$ git commit -m "AND simple"
[feature1 75a857c] AND simple
1 file changed, 1 insertion(+), 1 deletion(-)
切换到 master 分支:
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
Git 还会自动提示我们当前 master 分支比远程的 master 分支要超前 1 个提交。
在 master 分支上把 readme.txt 文件的最后一行改为:
Creating a new branch is quick & simple.
提交:
$ git add readme.txt
$ git commit -m "& simple"
[master 400b400] & simple
1 file changed, 1 insertion(+), 1 deletion(-)
现在,master 分支和 feature1 分支各自都分别有新的提交,变成了这样:
这种情况下,Git 无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看:
$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
果然冲突了!Git 告诉我们,readme.txt 文件存在冲突,必须手动解决冲突后再提交。git status 也可以告诉我们冲突的文件:
$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: readme.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
我们可以直接查看 readme.txt 的内容:
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> feature1
Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改如下后保存:
Creating a new branch is quick and simple.
再提交:
$ git add readme.txt
$ git commit -m "conflict fixed"
[master 59bc1cb] conflict fixed
现在,master 分支和 feature1 分支变成了下图所示:
用带参数的git log
也可以看到分支的合并情况:
$ git log --graph --pretty=oneline --abbrev-commit
* 59bc1cb conflict fixed
|\
| * 75a857c AND simple
* | 400b400 & simple
|/
* fec145a branch test
...
最后,删除 feature1 分支:
$ git branch -d feature1
Deleted branch feature1 (was 75a857c).
工作完成。
2.8 git 删除分支
合并完成后,就可以放心地删除 dev 分支了:
$ git branch -d dev
Deleted branch dev (was fec145a).
删除后,查看 branch,就只剩下 master 分支了:
$ git branch
* master
小结:
Git 鼓励大量使用分支:
查看分支:git branch
创建分支:git branch
切换分支:git checkout
创建+切换分支:git checkout -b
合并某分支到当前分支:git merge
删除分支:git branch -d
引用链接:https://wiki.jikexueyuan.com/project/git-tutorial/resolve-the-conflict.html