git使用方法

git和svn

区别就不说了,我们公司用的是svn,感觉还是很方便的,不能同时更改相同的代码就是了。因为模块化开发,应该来说避免了很多冲突问题,即使冲突了的话,解决起来也不麻烦。
那为什么还要用git呢?我个人用git,这里更多的说的是github,不外乎它是放在互联网上的,任何人都可以看到,虽然也别人也不一定会看,但是心理上是舒服的,可以告诉自己,我不是一个人在写代码!

git和github

合作开发嘛,肯定要有个公有的仓库,要不然一个人就不好玩了。这个公有的仓库可以在自己公司内部局域网搭建。把一些棒棒哒的东西放在在公网上分享就更有意思了。github就是这样的。(github也有托管私有仓库,要给钱就是了。)把仓库放在公网上,全世界的小伙伴都可以参与到项目中,是不是很有意思。想要本地仓库与github相关联,总体说来有两种方法,一种是自己配置sshkey,还有一种就是使用客户端,客户端会自己创建一个sshkey,并且可视化方便些。这两种方法都会在以后讲到。

使用

因为我用的windows,就只纪录windows的方法了,
简单使用:

首先安装git

git官网下载安装程序,然后默认选项安装。安装完成后,随便打开一个文件夹,鼠标右键,就会出现Git GUI HereGit 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指定版本库id
  • git 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_rsaid_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:

$ ssh-keygen -t rsa -C "[email protected]"

在用户主目录里找到.ssh目录,里面有id_rsaid_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 clonefork的区别。
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,希望更改被采纳到源项目中, 但是源项目维护者并没有同意,我想在保留自己的更改的情况下,又能获取源项目的更新,这要怎么办呢?

猜你喜欢

转载自blog.csdn.net/jkqwjkqw/article/details/82861176