特别声明,本博文仅作个人日常使用Git参考之用。主要内容总结来源于:廖雪峰官网的Git教程
Git是目前世界上最先进的分布式版本控制系统,是Linux的创建者用C开发的。GitHub网站2008上线,它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub。所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。
版本库又名仓库,英文名repository,可以简单理解成一个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。使用Git作版本管理需要理解它工作的几个基本概念:工作区,暂缓区,版本分支。工作区就是被管理的那个目录,工作区中有一个隐藏目录.git(不属于工作区)而是Git的版本库。Git的版本库里存了很多东西,其中最重要的就是称为stage的暂缓区,还有Git为我们自动创建的第一个分支master,以及指向master分支当前版本的一个指针叫HEAD。
【工作机理】工作区的修改通过git add xxx
逐个放到暂存区,然后通过git commit
一次性提交暂存区的所有修改到对应分支。git status
指令可以查看当前工作区所有文件所处几种状态:文件未被跟踪(Untracked files);修改未放到暂存区(Changes not staged for commit);暂存区的内容未提交(Changes to be committed)。
sudo apt-get install git
。老一点的系统需要把命令改成sudo apt-get install git-core
,因为以前有个软件也叫GIT(GNU Interactive Tools)。git config --global user.name accountname
,git config --global user.email [email protected]
。方式2是创建秘钥对。在用户主目录下看是否有.ssh目录(一般包含id_rsa
和id_rsa.pub
这两个文件)。如果没有,打开Shell创建SSH Key:ssh-keygen -t rsa -C "[email protected]"
,一直按回车,不需要设密码。id_rsa
是私钥,不能泄露出去,id_rsa.pub
是公钥,可以放心地告诉任何人。登陆GitHub,打开“Account settings”,“SSH Keys”页面点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub
文件的内容。git init
,然后对应目录下会添加一个.git的目录,这个目录是Git来跟踪管理版本库的。git add readme.txt
;2. 从暂存区提交到版本库git commit -m 'add a new file'
。注意:add可以逐个文件添加,而commit会把暂缓区的所有修改一次性提交当前的分支结点。rm filename
)。这时Git将检测到这一修改操作,因为工作区和版本库不一致了。现在有两个选择:1. 确实要从版本库删除该文件,那就git rm filename
并且git commit
;2. 如果是不小心删错了,可以从版本库恢复到工作区git checkout -- filename
。git add .
或git add *
:将修改操作的文件和未跟踪的新添加文件都添加到版本库的暂缓区(不包括删除操作)。git add -u .
:-u
表示将已经跟踪的文件中的修改和删除添加到暂缓区。git add -A .
:将所有已跟踪的文件的修改、删除、以及为跟踪的新添加文件都加到暂缓区。建议在工作区新建一个.gitignore
的文件记录那些需要忽略的文件。git add readme.txt
,然后在继续修改readme.txt并执行git commit -m "minor changes"
。此时git status
查看当前工作区的状态会发现第二次的修改并没有提交,因为这个修改从未add到暂存区。git diff HEAD -- filename
。git log
。该命令命令显示从最近到最远的提交日志,每次commit的版本都对应一个十六进制的commit id。在Git中,用HEAD
表示当前版本,上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,往上100个版本写成HEAD~100
。git reset --hard HEAD^
,工作区的文件即可更新为对应版本。此时,用git log
发现之前最新的版本已经看不到了,因为该命令只显示当前版本及之前的版本。现在如果要回到那个最新的版本,就需要执行git reflog
打印命令的记录,并从中找到他的commit id。git reset --hard commit_id
。git checkout -- readme.txt
可丢弃工作区的修改,回到和版本库或暂缓区(若该文件已经添加到暂存区后又作了修改)一模一样的状态。git reset HEAD readme.txt
可以把暂存区的修改撤销掉(unstage),重新放回工作区。git reset
命令既可以回退版本,也可把暂存区的修改回退到工作区。在版本回退里,每次提交Git都把它们串成一条时间线,这条时间线就是一个分支。默认情况下只有一条时间线,在Git里这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
【1】开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点;每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。
【2】当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上;Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!
【3】从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变;
【4】假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并;
【5】合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支。
dev
并切换到改分支:git checkout -b dev
。-b
参数表示创建并切换,相当于以下两条命令:git branch dev
和git checkout dev
。最新版本的Git提供了新的git switch master
命令来切换分支,以及创建并切换到新的分支git switch -c dev
。git branch
。当前分支前面会标一个*号。git merge dev
把dev分支的工作成果合并到master分支上。git branch -d dev
。注意:当分支还没有被合并,如果删除将丢失掉修改,这种情况下要强行删除,需要使用大写的-D参数git branch -D dev
。当master分支和feature分支各自都分别有新的提交,就变成了分支结点图【6】。这种情况下Git无法执行“快速合并(Fast-forward)”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突。当有文件存在冲突,必须手动解决冲突后再提交,或者放弃这次合并git merge --abort
。git status
也可以告诉我们冲突的文件。合并完成后的分支结点图如【7】。
通常合并分支时,如果可能,Git会用Fast forward模式,但这种模式下合并分支后,会丢掉分支信息。如果要强制禁用Fast forward模式,可用git merge --no-ff -m "merge with no-ff" dev
(因为本次合并要创建一个新的commit,所以加上-m参数把commit描述写进去)。这样Git就会在merge时生成一个新的commit,从分支历史上就可以看出分支信息。
用带参数的git log --graph --pretty=oneline --abbrev-commit
也可以看到分支的合并情况。
stash
功能。git stash
把当前工作现场“储藏”起来,等以后恢复现场后继续工作。此时用git status
查看工作区可以发现是干净的,可以创建分支修复bug。git stash list
命令看看"储藏"起来的工作现场列表。恢复现场有两种方式:1. git stash apply
恢复现场后stash内容不会被删除,需要显式地git stash drop
来删除;2. git stash pop
恢复现场的同时把stash内容也删除了。git stash apply stash@{0}
。git cherry-pick bug_commit_id
,Git自动给dev分支做了一次新的提交。Git是分布式版本控制系统,同一个Git仓库可以分布到不同的机器上。怎么分布呢?最早,肯定只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且每台机器的版本库其实都是一样的,并没有主次之分。实际情况往往是这样,找一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。GitHub这个网站就是提供Git仓库托管服务的,只要注册一个GitHub账号,就可以免费获得Git远程仓库。
git remote add origin [email protected]:yourname/reponame.git
与Github上新建的空仓库关联。关联成功后,远程库的名字就是origin,这是Git默认的叫法,也可改成别的。git push -u origin master
。由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。git clone [email protected]:yourname/reponame.git
即可克隆一个本地库。当我们从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。git remote rm
命令。使用前,建议先用git remote -v
查看远程库信息。此处的“删除”其实是解除了本地和远程的绑定关系,并不是物理上删除了远程库。远程库本身并没有任何改动。git push origin master
,Git就会把该分支推送到远程库对应的远程分支上。实际开发中,并不是一定要把本地分支往远程推送:
git checkout -b dev origin/dev
。在dev分支开发时,可以把dev分支push到远程:git push origin dev
。在协同开发中,push的修改可能与远程仓库版本已有的修改冲突(可能其他成员已经推送了类似的修改)而导致push失败。推送存在冲突时,一般需要git pull
把最新的提交从origin/dev抓取下来,然后在本地手动解决冲突合并后,再推送。git pull
也会失败。需先要通过指令git branch --set-upstream-to=origin/dev dev
建立二者的链接。------------------------------------------------------------------------------------ 底线 ------------------------------------------------------------------------------------