git使用方法
- git和svn
- git和github
- 使用
- 首先安装git
- 使用bash
- 初始化
- git基本概念
- 将数据提交到git仓库(本地仓库)
- 状态查询 git status
- 改动查询 git diff
- 取消改动 git reset HEAD
- 删除文件 git rm
- 移动、重命名等操作git mv
- 分支管理
- 列出分支`git branch`
- 创建分支`git branch (testing)`
- 删除分支`git branch -d testing`
- 合并分支`git merge`,保留分支纪录`--no-ff`
- 合并冲突
- bug分支 `git stash`
- 版本退回
- 查看提交历史 `git log`
- 查看简洁版` --oneline`
- 查看拓扑图` --graph`
- 逆向显示`--reverse`
- 指定用户`--author`
- 指定日期等`--since 和 --before --until 和 --after。`
- 版本退回 `git reset --hard`
- 操作纪录`git reflog`
- 标签管理
- 远程仓库(github)
git和svn
区别就不说了,我们公司用的是svn,感觉还是很方便的,不能同时更改相同的代码就是了。因为模块化开发,应该来说避免了很多冲突问题,即使冲突了的话,解决起来也不麻烦。
那为什么还要用git呢?我个人用git,这里更多的说的是github,不外乎它是放在互联网上的,任何人都可以看到,虽然也别人也不一定会看,但是心理上是舒服的,可以告诉自己,我不是一个人在写代码!
git和github
合作开发嘛,肯定要有个公有的仓库,要不然一个人就不好玩了。这个公有的仓库可以在自己公司内部局域网搭建。把一些棒棒哒的东西放在在公网上分享就更有意思了。github就是这样的。(github也有托管私有仓库,要给钱就是了。)把仓库放在公网上,全世界的小伙伴都可以参与到项目中,是不是很有意思。想要本地仓库与github相关联,总体说来有两种方法,一种是自己配置sshkey,还有一种就是使用客户端,客户端会自己创建一个sshkey,并且可视化方便些。这两种方法都会在以后讲到。
使用
因为我用的windows,就只纪录windows的方法了,
简单使用:
首先安装git
git官网下载安装程序,然后默认选项安装。安装完成后,随便打开一个文件夹,鼠标右键,就会出现Git GUI Here
和Git Bash Here
。如果点击GUI是打开一个可视化桌面了,bash就会打开一个命令行工具。
在使用之前,应该要在git bash中,进行配置,输入自己的用户名和邮箱
$ git config --global user.name "Your Name"
$ git config --global user.email "[email protected]"
注意git config
命令的--global
参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址。
#获取配置信息
git config -- list
使用bash
初始化
使用init命令将当前目录初始化为Git仓库
$ git init
此时,会在该文件夹中创建一个.git
目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。
特别说明
所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。
而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。
因为windows记事本保存文本时添加了十六进制字符,不要使用Windows自带的记事本编辑任何文本文件。
git基本概念
这个在菜鸟教程中说得很清楚
- 工作区:就是你在电脑里能看到的目录。
- 暂存区:英文叫stage, 或index。一般存放在 “.git目录下” 下的index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
- 版本库:工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
下面这个图展示了工作区、版本库中的暂存区和版本库之间的关系:
1.图中左侧为工作区,右侧为版本库。在版本库中标记为 “index” 的区域是暂存区(stage, index),标记为 “master” 的是 master 分支所代表的目录树。不过我的.git
目录里面好像没有index
目录,不影响理解。
图中我们可以看出此时 “HEAD” 实际是指向 master 分支的一个"游标"。所以图示的命令中出现 HEAD 的地方可以用 master 来替换。
图中的 objects 标识的区域为 Git 的对象库,实际位于 “.git/objects” 目录下,里面包含了创建的各种对象及内容。
2.当对工作区修改(或新增)的文件执行 git add
命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。
当执行提交操作git commit
时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。
当执行 “git reset HEAD” 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。
当执行 "git rm --cached " 命令时,会直接从暂存区删除文件,工作区则不做出改变。
当执行 “git checkout .” 或者 "git checkout – " 命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。
当执行 “git checkout HEAD .” 或者 “git checkout HEAD 《file》” 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。
将数据提交到git仓库(本地仓库)
1.首先在根目录中创建文件或者复制一些文件过来,然后肯定是要想把文件传上到仓库。
上传到仓库有两个步骤,先把文件上传到暂存区,然后再上传到仓库中。上传文件的时候,肯定有两种需求,一种是上传一部分文件,多批次上传,一种是一下子全部上传。
# 上传一个或者多个文件到缓存区 换一个正确的说法,就是告诉Git,要对这些文件进行跟踪,并且将修改的内容放入对应的新对象中
$ git add index.html indexs.html
# 上传全部同类型文件到缓存区
$ git add *.html
# 上传所以文件到缓存区
$ git add
# 注意,git add 可反复多次使用,添加多个文件;
2.添加到缓存之后,就可以把文件传到仓库了
# 通常 提交添加到缓存区的文件,每次修改都要add
$ git commit -m "这是提交描述"
# 如果觉得add过于频繁,-a 提交修改过,包括没有添加到缓存区的文件(修改过的就能提交)
$ git commit -a -m "这是提交描述"
# 也许会追加提交,它可以在不增加一个新的commit-id的情况下将新修改的代码追加到前一次的commit-id中,
$ git commit --amend
3.查看提交的内容
使用git show
就可以看到某个分支某次提交的内容了
$ git show
commit a7b73afd3a0726b17d3e25bdb930c1e6d46cc45d (HEAD -> master)
Author: xxx
Date: Fri Oct 12 11:37:38 2018 +0800
测试git show
diff --git a/public/src/static/js/index.js b/public/src/static/js/index.js
index 3fc6838..e723e0e 100644
--- a/public/src/static/js/index.js
+++ b/public/src/static/js/index.js
@@ -2,5 +2,6 @@
* @Author: ZZZ
* @Date: 2018-10-12 11:00:28
* @Last Modified by: ZZZ
-* @Last Modified time: 2018-10-12 11:00:31
+* @Last Modified time: 2018-10-12 11:11:25
*/
+测试添加
\ No newline at end of file
状态查询 git status
git status
显示工作目录和暂存区的状态,查看某个文件是否添加到缓存区,是否进行过修改等
有几种状态:
1.Changes to be committed
被跟踪(已经add)使用-s
显示为A
2.Changes not staged for commit
被跟踪之后进行了修改,但是没有add, 使用-s
显示为AM
3.Untracked files
没有被跟踪的文件,(没有add) 使用-s
显示为??
4.如果已经commit
,A
显示为M
,表示已经被提交过
git status -uno
可以只列出所有已经被git管理的且被修改但没提交的文件
-s
表示简略显示
改动查询 git diff
执行 git diff
来查看执行 git status
的结果的详细信息。
git status
显示你上次commit
的更改或者写入缓存的改动, 而 git diff
一行一行地显示这些改动具体是啥。
git diff 命令后面跟文件与add一样,可跟文件名 查询多个文件空格隔开。
git diff
比较工作区与暂存区git diff commit-id
比较工作区与指定版本库id的差异git diff --cached
比较暂存区与最新本地版本库(本地库中最近一次commit的内容),完成之后按q
退出git diff --cached commit-id
指定版本库idgit diff HEAD <filename>
比较工作区与最新本地版本库git diff <commit-id> <commit-id>
比较两个commit-id之间的差异--stat
显示摘要而非整个 diff
取消改动 git reset HEAD
git reset HEAD
命令用于清除已经add
的内容,被 master 分支指向的目录树所替换,但是工作区不受影响。
比如:
$ git reset HEAD hello.php
暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。
$ git checkout -- <file>
删除文件 git rm
已经commit
文件,不能仅仅再工作目录中手工删除,要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除,然后提交。
$ git rm <file>
如果删除之前修改过并且已经(add)放到暂存区域的话,则必须要用强制删除选项 -f
$ git rm -f <file>
如果把文件从暂存区域移除,但仍然希望保留在当前工作目录中,换句话说,仅是从跟踪清单中删除,使用 –cached 选项即可
# 和 git reset HEAD <file> 效果类似,但reset HEAD是从分支替换暂存区,rm是清除暂存区。
$ git rm --cached <file>
后面跟的是一个目录做为参数,则会递归删除整个目录中的所有子目录和文件**-r**
$ git rm –r *
进入某个目录中,执行此语句,会删除该目录下的所有文件和子目录。
移动、重命名等操作git mv
$ git mv README.txt README.md
$ ls
README.md
分支管理
列出分支git branch
$ git branch
没有参数时,git branch 会列出你在本地的分支
$ git branch
* master
意思就是,我们有一个叫做"master"的分支,并且该分支是当前分支。
当你执行 git init 的时候,缺省情况下 Git 就会为你创建"master"分支。
创建分支git branch (testing)
如果我们要手动创建一个分支。执行 git branch (branchname) 即可。添加分支testing
$ git branch testing
$ git branch
* master
testing
分支之间相互独立,使用git checkout -b (branchname)
命令来复制当前分支,创建新分支并立即切换到该分支下。
删除分支git branch -d testing
$ git branch
* master
testing
$ git branch -d testing
Deleted branch testing (was 85fc7e7).
$ git branch
* master
使用git branch -D testing
删除没有合并的分支
合并分支git merge
,保留分支纪录--no-ff
使用git merge
$ git branch
* master
newtest
$ ls
README test.txt test2.txt
$ git merge newtest
Updating 2e082b7..556f0a0
Fast-forward
test2.txt | 1 -
1 file changed, 1 deletion(-)
delete mode 100644 test2.txt
$ ls
README test.txt
因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
合并冲突
与使用svn一样,同一个文件的同一位置内容不同,会发生冲突,冲突时可以用git diff检查,然后手动编辑文档,让后add即可。
$ git status -s
UU test.txt
$ git add test.txt
$ git status -s
M test.txt
$ git commit
[master 88afe0e] Merge branch 'change_site'
bug分支 git stash
主要用于合作开发,再某个分支还没有完成,没有提交的情况下,修复某个分支的bug。(一般情况,在没有提交的情况下,无法切换分支)
再未commit
的情况下,创建分支
先把当前工作现场“储藏”起来
$ git stash
Saved working directory and index state WIP on dev: f52c633 add merge
然后再创建分支
$ git checkout -b issue-101
Switched to a new branch 'issue-101'
修复bug后,切回到之前的分支,然后删除bug分支
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
(use "git push" to publish your local commits)
$ git merge --no-ff -m "merged bug fix 101" issue-101
Merge made by the 'recursive' strategy.
readme.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
bug修复完毕,回到之前被stash
的分支,git status
发现工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看
$ git stash list
stash@{0}: WIP on dev: f52c633 add merge
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
另一种方式是用git stash pop,恢复的同时把stash内容也删了:
$ git stash pop
On branch dev
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: hello.py
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: readme.txt
Dropped refs/stash@{0} (5d677e2ee266f39ea296182fb2354265b91b3b2a)
再用git stash list
查看,就看不到任何stash内容了。
你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:
$ git stash apply stash@{0}
版本退回
查看提交历史 git log
$ git log
commit 88afe0e02adcdfea6844bb627de97da21eb10af1
Merge: 14b4dca d7e7346
Author: runoob <[email protected]>
Date: Sun Mar 1 15:03:42 2015 +0800
Merge branch 'change_site'
Conflicts:
test.txt
commit 14b4dcadbdc847207651d5a9fae0d315057f346e
Author: runoob <[email protected]>
Date: Sun Mar 1 14:53:15 2015 +0800
新增加一行
查看简洁版--oneline
$ git log --oneline
88afe0e Merge branch 'change_site'
14b4dca 新增加一行
d7e7346 changed the site
556f0a0 removed test2.txt
2e082b7 add test2.txt
048598f add test.txt
85fc7e7 test comment from runoob.com
查看拓扑图--graph
$ git log --oneline --graph
* 88afe0e Merge branch 'change_site'
|\
| * d7e7346 changed the site
* | 14b4dca 新增加一行
|/
* 556f0a0 removed test2.txt
* 2e082b7 add test2.txt
* 048598f add test.txt
* 85fc7e7 test comment from runoob.com
逆向显示--reverse
$ git log --reverse --oneline
85fc7e7 test comment from runoob.com
048598f add test.txt
2e082b7 add test2.txt
556f0a0 removed test2.txt
d7e7346 changed the site
14b4dca 新增加一行
88afe0e Merge branch 'change_site'
指定用户--author
$ git log --author=Linus --oneline -5
81b50f3 Move 'builtin-*' into a 'builtin/' subdirectory
3bb7256 make "index-pack" a built-in
377d027 make "git pack-redundant" a built-in
b532581 make "git unpack-file" a built-in
112dd51 make "mktag" a built-in
指定日期等--since 和 --before --until 和 --after。
$ git log --oneline --before={3.weeks.ago} --after={2010-04-18} --no-merges
5469e2d Git 1.7.1-rc2
d43427d Documentation/remote-helpers: Fix typos and improve language
272a36b Fixup: Second argument may be any arbitrary string
b6c8d2d Documentation/remote-helpers: Add invocation section
5ce4f4e Documentation/urls: Rewrite to accomodate transport::address
00b84e9 Documentation/remote-helpers: Rewrite description
03aa87e Documentation: Describe other situations where -z affects git diff
77bc694 rebase-interactive: silence warning when no commits rewritten
636db2c t3301: add tests to use --format="%N"
版本退回 git reset --hard
git reset --hard HEAD
当前版本
git reset --hard HEAD^
上个版本
git reset --hard HEAD^^
上上个版本
或者后面直接跟版本号
$ git reset --hard 1094a
HEAD is now at 83b0afe append GPL
操作纪录git reflog
$ git reflog
c83ac5e (HEAD -> master) HEAD@{0}: commit (merge): 结束测试
d92dece HEAD@{1}: checkout: moving from testing to master
9cfa807 (testing) HEAD@{2}: commit: 再次测试b
852c35f HEAD@{3}: checkout: moving from master to testing
d92dece HEAD@{4}: commit (merge): 修改冲突
f10e8c5 HEAD@{5}: checkout: moving from testing to master
852c35f HEAD@{6}: commit: 再次测试a
6d30501 HEAD@{7}: checkout: moving from master to testing
标签管理
个人理解标签就是某个被打了记号的commit
,方便调用。
创建标签
切换到要打标签的分支,然后git tag <name>
即可
git tag
查看标签
$ git branch
* dev
master
$ git checkout master
Switched to branch 'master'
$ git tag v1.0
$ git tag
v1.0
标签默认打在分支的最新commit
上,如果要打在指定的commit
上,查找出commit id,然后打标签即可。
$ git log --pretty=oneline --abbrev-commit
12a631b (HEAD -> master, tag: v1.0, origin/master) merged bug fix 101
4c805e2 fix bug 101
e1e9c68 merge with no-ff
f52c633 add merge
cf810e4 conflict fixed
比方说要对add merge
这次提交打标签,它对应的commit id是f52c633
,敲入命令:
$ git tag v0.9 f52c633
$ git tag
v0.9
v1.0
可以用git show <tagname>
查看标签信息:
$ git show v0.9
commit f52c63349bc3c1593499807e5c8e972b82c8f286 (tag: v0.9)
Author: Michael Liao <[email protected]>
Date: Fri May 18 21:56:54 2018 +0800
add merge
diff --git a/readme.txt b/readme.txt
创建带有说明的标签,用-a指定标签名,-m指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 1094adb
用命令git show <tagname>
可以看到说明文字:
$ git show v0.1
tag v0.1
Tagger: Michael Liao <[email protected]>
Date: Fri May 18 22:48:43 2018 +0800
version 0.1 released
commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (tag: v0.1)
Author: Michael Liao <[email protected]>
Date: Fri May 18 21:06:15 2018 +0800
操作标签
删除标签-d
:
$ git tag -d v0.1
Deleted tag 'v0.1' (was f15b0dd)
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
如果要推送某个标签到远程,使用命令git push origin <tagname>
:
$ git push origin v1.0
Total 0 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
* [new tag] v1.0 -> v1.0
或者,一次性推送全部尚未推送到远程的本地标签:
$ git push origin --tags
Total 0 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
* [new tag] v0.9 -> v0.9
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
$ git tag -d v0.9
Deleted tag 'v0.9' (was f52c633)
然后,从远程删除。删除命令也是push,但是格式如下:
$ git push origin :refs/tags/v0.9
To github.com:michaelliao/learngit.git
- [deleted] v0.9
远程仓库(github)
使用github,相当于把自己的本地仓库放到网上,其他人也可以clone,或者接受其他人的更改。
本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,如果没有使用github desktop这类工具,需要手动配置。
第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa
和id_rsa.pub
这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
$ ssh-keygen -t rsa -C "[email protected]"
在用户主目录里找到.ssh目录,里面有id_rsa
和id_rsa.pub
两个文件,这两个就是SSH Key的秘钥对,id_rsa
是私钥,不能泄露出去,id_rsa.pub
是公钥,可以放心地告诉任何人。
第2步:登陆GitHub,打开“Account settings”,“SSH Keys”页面。
然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub
文件的内容。
当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。如果是若干个人,也就是协同开发了。
github仓库
自己的github仓库有两种来源,一种是自己新建,一种是fork别人的仓库。主要讲创建自己的仓库后,让它与本地仓库同步。
在GitHub上创建仓库很简单,就不说了。提一点就是,根目录下的README.md文件会显示在仓库首页下。
然后再本地目录输入命令,连接本地仓库和github仓库
提交到GitHub git push 拉取 git pull
$ git remote add origin [email protected]:jiejiege123/gulp-html-cli.git
remote的意思是远程的,origin的意思是根源
然后将本地仓库的内容推送到github仓库中
$ git push -u origin master
Counting objects: 20, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (20/20), 1.64 KiB | 560.00 KiB/s, done.
Total 20 (delta 5), reused 0 (delta 0)
remote: Resolving deltas: 100% (5/5), done.
To 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
分支关联起来,在以后的推送或者拉取时就可以简化命令。
此后,每次本地commit
后,只要有必要,就可以使用命令git push origin master
推送最新修改,其他分支也是一样的。
删除GitHub上的内容 git rm --cached
如果上传了错误的文档,就需要删除远程仓库的文件,那就要先git pull origin master,然后删除缓存,命令如下:
git rm --cached -r useless
-r
指删除文件夹及子目录
然后一定要commit
然后直接 git push origin master
,就可以同步到github上了
参与github开源项目
github很有趣的一个地方就是参与开源项目了。不然纯粹为了工作的话,自己搭建一个git服务器,公司的小伙伴协作就行了。
git clone
和 fork
的区别。
git clone
通过链接,直接将代码复制到本地,相当于直接下载。如果是从别人的仓库下载,由于没有权限(公钥),不能push到源仓库的。
当我们要参与别人的项目时,先在别人的github仓库中fork
一下,这个仓库就会clone到自己的账号下。自己账号下的这个仓库就相当于是fork
源的一个分支。然后我们把fork
的仓库clone
到本地,就可以修改文件或添加代码了,但是现在最好不要直接修改刚刚clone的文件,为了保持原文件不动,应该创建一个人特性分支git checkout -b 分支名
然后添加代码,修改后commit
到自己账号的仓库中。那这不是和直接clone
一样吗?当然不一样,还没完,这时候你想让别人采取自己的功能时,我们可以推送pull request,源仓库接受了这个pull request后,我们的修改就会出现在源仓库中,是不是感觉很有成就感?
fork
下来的项目是源项目当前的项目,也就是说你fork
后,源仓库做了修改,自己fork
的仓库是不会修改的。想要保持同步的话,可以直接star
源仓库,这样在自己的star
中就可以看到这样仓库了。相当于是保留了这个链接。
但是有个问题我fork
了一个项目,做了更改,推送pull request,希望更改被采纳到源项目中, 但是源项目维护者并没有同意,我想在保留自己的更改的情况下,又能获取源项目的更新,这要怎么办呢?