前文:
Git有三种状态,你的文件可能处于其中之一:已提交(committed),已修改(modiffied)和已暂存(staged)
三个工作区域概念:Git仓库、工作目录以及暂存区
Git保存信息的方式是以快照的形式保存的。在进行提交操作时,Git 会保存一个提交对象(commit object)。该提交对象会包含一个指向暂存内容快照的指针。该提交对象还包含了作者的姓名和邮箱(配置用户信息时候记录的)、提交时输入的信息以及指向它的父对象的指针。首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象。
基本的Git工作流程如下:
1,在工作目录修改文件
2,将文件的快照放入暂存区
3,找到暂存区域的文件,将快照永久性存储到Git仓库中。
git status --检查当前文件状态
工作目录下的每一个文件都不外乎这两种状态:已跟踪或未跟踪
说明你现在的工作目录相当的干净,没有出现任何处于未跟踪状态的新文件
echo '路径' > 文件名 ------- 添加一个新的文件
bb.txt出现在 Untrached files下面。未跟踪的文件意味着Git在之前的快照(提交)中没有这些文件。
git add 开始跟踪一个新的文件
只要在 Changes to be committed这行下面的,就说明是已暂存状态,这个时候该文件还没有提交到仓库中。
修改已暂存的文件 此时我修改了 aa.txt文件
出现在 Changes not staged for commit
这行下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区
现在两个文件都已暂存,下次提交时就会一并记录到仓库
这个时候我又修改了aa.txt文件,(aa.txt修改了一次添加到了暂存区,然后有修改了)
现在 aa.txt
文件同时出现在暂存区和非暂存区,你只用在add一遍就可以实现更新了。最新的是下面修改过后的aa.txt版本
git status -s 状态简览
注:
新添加的未跟踪文件前面有 ??
新添加到暂存区中的文件前面有 A
靠右M表示该文件被修改了但是还没放入暂存区
靠左M表示文件被修改了并放入暂存区
MM表示在工作区被修改并提交到暂存区后又在工作区被修改了,表示在暂存区和工作区都有该文件被修改了的记录
git diff 查看具体的修改
当你修改了一个文件并且没有添加到暂存区
git diff --cached(staged) 可以查看已暂存区的将要添加到下次提交的内容
git commit 提交更新
提交只会把暂存区的文件提交到仓库里面。
git commit -m ‘注释’
每次提交的时候可以使用git status 查看一下那些文件是在暂存区那些文件是在未暂存区
跳过暂存区提交
这种提交是可以跳过暂存区提交到仓库里面,也就是在未暂存区的文件可以直接提交到仓库中
git commit -a -m '注释'
rm filename 移除文件
rm bb.txt 会出现在未暂存区
这只是手动从工作目录上移除,会出现在未暂存的清单中
git rm bb.txt 不会出现在暂存区
下次提交时bb.txt不在纳入版本管理了。 如果删除之前修改过并且已经放到暂存区域的话,则必须要用强制删除选项 -f
(译注:即 force 的首字母)
git rm --cached filename --这样删除文件只会保留在磁盘上,Git仓库里面(暂存区)不会存在此文件,就是不想让git继续跟踪了,当你忘记添加 .gitignore
文件(后面会介绍这个)
git rm file_from file_to 可以移动位子/重命名
相当于运行了
$git rm aa.txt
$git add aa1.txt
git log 查看历史提交
会列出你所以的提交,一般一个提交会显示Commit id,作者,日期以及提交所写的信息。
git log -p -2 -p可以显示每次提交的内容差异
git log --pretty=oneline 只显示commit id 和解释 (这个很常用)
git log --pretty=format:"%h - %an, %ar : %s" 自定义格式显示
选项 | 说明 |
---|---|
|
提交对象(提交)的完整哈希字串 |
|
提交对象的简短哈希字串 |
|
树对象(树)的完整哈希字串 |
|
树对象的简短哈希字串 |
|
父对象(父)的完整哈希字串 |
|
父对象的简短哈希字串 |
|
作者(作者)的名字 |
|
作者的电子邮件地址 |
|
作者修订日期(可以用--date =选项定制格式) |
|
作者修订日期,按多久以前的方式显示 |
|
提交者(提交者)的名字 |
|
提交者的电子邮件地址 |
|
提交日期 |
|
提交日期,按多久以前的方式显示 |
|
提交说明
|
选项 | 说明 |
---|---|
|
按补丁格式显示每个更新之间的差异。 |
|
显示每次更新的文件修改统计信息。 |
|
只显示--stat中最后的行数修改添加移除统计。 |
|
仅在提交信息后显示已修改的文件清单。 |
|
显示新增,修改,删除的文件清单。 |
|
只显示SHA-1的前几个字符,而非所有的40个字符。 |
|
使用较短的相对时间显示(比如,“2周前”)。 |
|
显示ASCII图形表示的分支合并历史。 |
|
使用其他格式显示历史提交信息。可用的选项包括oneline,short,full,fuller和format(后跟指定格式)。 |
选项 | 说明 |
---|---|
|
仅显示最近的n条提交 |
|
仅显示指定时间之后的提交。 |
|
仅显示指定时间之前的提交。 |
|
仅显示指定作者相关的提交。 |
|
仅显示指定提交者相关的提交。 |
|
仅显示含指定关键字的提交 |
|
仅显示添加或移除了某个关键字的提交
|
git log 很灵活,需要怎么显示就看自己。
撤销操作
git commit --amend 撤销提交(例如:当你把暂存区里面的文件提交了,发现还差个文件,这个时候你可以先把文件添加到暂存区,然后运行此命令,可以修改提交信息)
我修改了aa1.txt文件,然后还想修改bb.txt并且只产生一个提交
我修改了bb.txt文件并且 add了。然后执行 git commit --amend 就会进入这个界面(vim) 注:输入小写i才能修改内容, ESC切换模式, w保存,q退出,!q强制退出不保存修改
这样就实现了共用一个提交。。
git reset HEAD <file>...
来取消暂存 (文件修改了,add之后在暂存区没有提交,是个时候使用让文件回到修改之前(上个版本的暂存区))
例如:目前 aa1.txt文件的内容
然后为修改为
接着添加到暂存区
显示了文件不在暂存区了,内容还没变,可以删除在添加。
git checkout -- <file>... 撤销对文件的修改
文件处于未暂存区的时候可以用这个,接着上面的来。上面已经让在暂存区的文件还原成不在暂存区(内容存在)。 然后接着运行改命令。
文件回到开始的时候了。。
远程仓库的使用 默认远程仓库名称为:origin 分支为:master
git remote -v 查看远程仓库
添加远程仓库
git remote add <shortname> <url> 这个命令再基础篇里面用过,就是把本地的仓库和远程仓库实现关联
从远程仓库中抓取与拉取
git fetct [remote-name] 从远程仓库获取数据,它并不会自动合并或修改你当前的工作
git pull [remote-name] 从远程仓库获取数据并自动尝试合并到当前所在的分支。
推送到远程仓库
git push [remote-name] [branch-name] 推送分支到你的远程仓库, push -u:第一次推送的时候再push后面加个-u,实现本地和远程跟踪
查看远程仓库
git remote show [remote-name]
远程仓库的移除与重命名
git remote rename
去修改一个远程仓库的简写名
git remote rm
删除远程仓库
标签
git tag 列出标签
创建标签
Git 使用两种主要类型的标签:轻量标签(lightweight)与附注标签(annotated)。
一个轻量标签很像一个不会改变的分支 - 它只是一个特定提交的引用。
然而,附注标签是存储在 Git 数据库中的一个完整对象。 它们是可以被校验的;其中包含打标签者的名字、电子邮件地址、日期时间;还有一个标签信息;并且可以使用 签名与验证。 通常建议创建附注标签,这样你可以拥有以上所有信息;但是如果你只是想用一个临时的标签,或者因为某些原因不想要保存那些信息,轻量标签也是可用的。
附注标签
git tag -a name -m '解释' 创建一附注标签并写入类容
git show name 可以看到标签信息与对应的提交信息
轻量标签
git tag name 后面不需要提供-a,-s,-m
后期打标签
git tag -a name commitID 可以指定在那个提交的ID哪里创建标签
共享标签
共享就是需要把本地的标签上传到远程仓库里面。
git push origin name(标签名字) 就跟推送分支是一样的
检出标签
在 Git 中你并不能真的检出一个标签,因为它们并不能像分支一样来回移动。 如果你想要工作目录与仓库中特定的标签版本完全一样,可以使用
git checkout -b [branchname] [tagname]
在特定的标签上创建一个新分支。
Git起别名
起别名就是声明一个简单的,好记的字符串来代替git命名。
例如:
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
这意味着,当要输入git commit
时,只需要输入git ci
。
为了解决取消暂存文件的易用性问题,可以向Git中添加你自己的取消暂存别名:
git config --global alias.unstage 'reset HEAD --'
这会使下面的两个命令等价:
$ git unstage fileA
$ git reset HEAD -- fileA
这样看起来更清楚一些。通常也会添加一个last
命令,像这样:
$ git config --global alias.last 'log -1 HEAD'
语法:
git config --global alias.别名 '需要替换的命名'
对于查看历史提交很方便,你可以把一句很长的命名用简单的替代。
分支 分支是Git里面一个很重要的东西
使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。
Git 中的分支,其实本质上仅仅是个指向 commit 对象的可变指针。Git 会使用 master 作为分支的默认名字。
在若干次提交后,你其实已经有了一个指向最后一次提交对象的 master 分支,它在每次提交的时候都会自动向前移动。
git branch xx 创建分支,这会使你在当前的提交对象上创建一个指针
我们又如何区分我们现在在那个分支上呢?它有一个名为 HEAD
的特殊指针。HEAD指针总是指向当前分支的。
git checkout -b demo 创建并切换分支
git checkout testing 切换分支
分支的效果:
① 在tesing分支下修改aa.txt文件
这是aa.txt在testing下的文本
②我们现在把HEAD指向master,然后打开aa.txt
刚刚我们做的修改看不到,可以说明我们在testing分支上做的修改并不影响master分支
③在master分支下修改aa.txt文件并提交
现在就成了这样的
④合并这两个分支 git merge xx 把当前分支和xx分支合并,并生成一个新的对象
如果在两个分支中对同一个分支进行了修改,合并的时候就会出现冲突,我们来看看aa.txt文件
这里会有 ========分割开
⑤解决冲突 在当前分支下手动修改冲突文件
然后添加文件并提交
⑥删除不需要的分支 git branch -d xx 删除xx分支 (在当前分支下不能删除当前分支)
git branch 查看分支
master前面有 * ,说明现在在master分支上(HEAD指针指向当前分支)
git branch -v 查看分支最后的一次提交
git branch --merged / --no-merged 分别是查看与当前分支已经合并或未合并
远程分支
git ls-remote (remote)
来显式地获得远程引用的完整列表
git remote show (remote) 获得远程分支的更多信息
远程跟踪分支
远程跟踪分支是远程分支状态的引用。 它们是你不能移动的本地引用,当你做任何网络通信操作时,它们会自动移动。 远程跟踪分支像是你上次连接到远程仓库时,那些分支所处状态的书签。
git push (remote) (branch) 推送分支到远程库来实现共享
git push origin testing:testing 推送本地的testing分支到远程的testing分支上
多人工作:
git fetch origin 当你的合作者抓取远程库的数据的时候,在本地是不会生成testing分支的,而只是会有一个远程分支(origin/tetsing)的指针。
可以运行 git merge origin/testing
将这些工作合并到当前所在的分支。 如果想要在自己的 testing分支上工作,可以将其建立在远程跟踪分支之上:
git checkout -b tetsing origin/testing
跟踪分支
从一个远程跟踪分支检出一个本地分支会自动创建一个叫做 “跟踪分支”(有时候也叫做 “上游分支”)。 跟踪分支是与远程分支有直接关系的本地分支。 如果在一个跟踪分支上输入 git pull
,Git 能自动地识别去哪个服务器上抓取、合并到哪个分支。
设置跟踪分支
git checkout --track [remotename]/[branch] 在本地创建了一个跟远程分支一样的跟踪分支
git checkout -b [branch] [remotename]/[branch] 可以定义不同的名字
改变你的跟踪分支
-u
或 --set-upstream-to
选项运行 git branch
来显式地设置。 可以任何时间允许此命令
git branch -u [remotename]/[branch]
查看设置的所以分支
git branch -vv 这会将所有的本地分支列出来并且包含更多的信息,如每一个分支正在跟踪哪个远程分支与本地分支是否是领先、落后或是都有。
这里可以看到 iss53
分支正在跟踪 origin/iss53
并且 “ahead” 是 2,意味着本地有两个提交还没有推送到服务器上。 也能看到 master
分支正在跟踪 origin/master
分支并且是最新的。 接下来可以看到 serverfix
分支正在跟踪 teamone
服务器上的 server-fix-good
分支并且领先 3 落后 1,意味着服务器上有一次提交还没有合并入同时本地有三次提交还没有推送。 最后看到 testing
分支并没有跟踪任何远程分支。
拉取 上面提过了
由于 git pull
的魔法经常令人困惑所以通常单独显式地使用 fetch
与 merge
命令会更好一些。 git pull命令相当于是执行了 fetch与merge命令。
删除远程分支
git push origin --delete testing 这个会删除你服务器上的testing分支
变基
在 Git 中整合来自不同分支的修改主要有两种方法:merge
以及 rebase。merge我们已经了解过了,而rebase命令就是关于变基的。
①merge是三方合并。 它会把两个分支的最新快照(C3
和 C4
)以及二者最近的共同祖先(C2
)进行三方合并,合并的结果是生成一个新的快照(并提交)。
------->
②你可以提取在 C4
中引入的补丁和修改,然后在 C3
的基础上应用一次。 在 Git 中,这种操作就叫做 变基。 你可以使用 rebase
命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。
先切换到experiment分支,执行rebase命令
在切换回master分支,执行合并命令。
现在C4’和C5就是一样的了。
git rebase [basebranch] [topicbranch]
命令可以直接将特性分支(即本例中的 server
)变基到目标分支(即 master
)上
一个变基列子:
你创建了一个特性分支 server
,为服务端添加了一些功能,提交了 C3
和 C4
。 然后从 C3
上创建了特性分支 client
,为客户端添加了一些功能,提交了 C8
和 C9
。
最后,你回到 server
分支,又提交了 C10
。
假设你希望将 client
中的修改合并到主分支并发布,但暂时并不想合并 server
中的修改,因为它们还需要经过更全面的测试。 这时,你就可以使用 git rebase
命令的 --onto
选项,选中在 client
分支里但不在 server
分支里的修改(即 C8
和 C9
),将它们在 master
分支上重放:
以上命令的意思是:“取出 client
分支,找出处于 client
分支和 server
分支的共同祖先之后的修改,然后把它们在 master
分支上重放一遍”。
变基需要遵守一条规则:
不要对在你的仓库外有副本的分支执行变基。如果你已经将提交推送至某个仓库,你的同伴已经获取最新的提交,你再使用git rebase然后推送,
这样你的同伴再次获取的时候就会很麻烦。
变基 vs. 合并
对未推送或分享给别人的本地修改执行变基操作,对已经推送给别人提交不要执行变基。