Git学习整理

2018-01-04  本文已影响99人  忆江南_1569

之前参照莫烦的Git教程整理过一遍Git总结,后来使用Git的时候发现还是有很多操作一知半解,所以再次梳理下Git使用

安装Git

windows上使用Git,可以从Git官网直接下载安装程序,选择默认安装即可
安装完成后,开始菜单-->Git-->Git Bash,打开后会弹出一个命令行窗口,就说明Git安装成功

git config --global user.name "NAME"
git config --global user.email "email@test.com"

创建Git版本库

版本库可以简单理解为一个目录,这个目录下的所有文件都可以被Git管理起来,每个文件的修改删除,Git都能跟踪,以便查看修改记录或还原到某个时刻

mkdir learn_git
cd learn_git
pwd
/e/learn_git
$ git init
Initialized empty Git repository in E:/git_learn/.git/

可以看到创建了一个空的git仓库,并且当前目录下多了一个.git目录这个目录是git用来跟踪管理版本库的

把文件添加到版本库

在当前目录下创建一个readme.txt文件,写入内容

vi readme.txt

Git is a version control system
Git is free software
$ git add readme.txt

没有任何输出,则表示添加暂存区成功

$ git commit -m "wrote a readme file"
 1 file changed, 2 insertions(+)
 create mode 100644 readme.txt

git commit命令的-m参数后面输入的是本次提交的说明
git commit命令执行完成输出会提示1个文件被改动(新创建readme.txt),插入了2行(readme.txt文件有2行)
git commit命令一次可以提交多个文件,可以多次使用git add不同文件

git status

git status命令可以查看当前仓库的状态(哪些有修改的,哪些修改文件在暂存区待提交)
修改readme.txt文件内容

$ git status
On branch master
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

no changes added to commit (use "git add" and/or "git commit -a")

输出信息显示
在master分支
没有提交的修改:
使用git add <file>将文件添加到暂存区
使用git checkout -- <file>丢弃当前工作目录中的修改
被修改文件:readme.txt
还没有准备提交的修改

git diff

git diff用来查看工作区和暂存区的不同

$ git diff
diff --git a/readme.txt b/readme.txt
index f7249b8..2fdf0c4 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,2 @@
-Git is a version control system
+Git is a distributed version control system
 Git is free software

可以看到两次的不同
-Git is a version control system - 表示删除了这部分内容
+Git is a distributed version control system + 表示添加了这部分内容

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   readme.txt

可以看到输出
在master分支上
将要被提交的修改:
使用git reset HEAD <file>取消已经进入暂存区的文件
修改文件:readme.txt

$ git commit -m "add distributed"
[master 015cd95] add distributed
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git status
On branch master
nothing to commit, working directory clean

可以看到输出当前没有需要提交的修改,工作目录是干净的

git log

使用git log 命令可以显示之前提交到版本库的记录,包括commit的id号、提交人、日期、提交说明

$ git log
commit 13cd2aa93fc97391a81fc28bf5319e86342ee2c1
Author: tyq <email@test.com>
Date:   Thu Jan 4 18:52:53 2018 +0800

    append GPL

commit 015cd9545760909630f59e612020f59d52d8cb76
Author: tyq <email@test.com>
Date:   Thu Jan 4 18:46:38 2018 +0800

    add distributed

commit f5302fbafba412e62b22f7bdae20437cd27a0eac
Author: tyq <email@test.com>
Date:   Thu Jan 4 17:52:44 2018 +0800

    wrote a readme file

如果觉的输出的内容太多,想要简洁一些,可以使用命令git log --oneline

$ git log --oneline
13cd2aa append GPL
015cd95 add distributed
f5302fb wrote a readme file

git log --oneline显示对应提交的id号和说明

回到过去

在GIt中用HEAD表示当前版本也就是commit id为13cd2aa,上个版本表示为HEAD^,上上个版本表示为HEAD^^,依次类推,也可以用commit id号表示对应的版本
想把‘append GPL’回退到‘add distributed’可以使用git reset命令

$ git reset --hard HEAD^
HEAD is now at 015cd95 add distributed

查看readme.txt文件,果然回退到了'add distributed'版本

$ cat readme.txt
Git is a distributed version control system
Git is free software

Git版本的回退速度非常快,因为Git内部有个指向当前版本的指针,当回退版本的时候Git仅仅把HEAD从指向append GPL改为指向add distributed,顺便把工作区的文件更新了,所以让HEAD指向哪个版本号,就把当前版本定位在哪
使用git log --oneline查看当前版本记录

$ git log --oneline
015cd95 add distributed
f5302fb wrote a readme file

可以看到只显示了2个版本,现在想要回到append GPL的版本时,可以有2种方式
第一种, 往上翻找到append GPL的commit id号,使用命令git reset --hard id号回到append GPL版本
如果之前的窗口关掉了commit id号往上翻找不到了可以使用下面的方法
第二种,使用git reflog,这个命令用来记录你的每一次执行的命令

$ git reflog
015cd95 HEAD@{0}: reset: moving to HEAD^
13cd2aa HEAD@{1}: commit: append GPL
015cd95 HEAD@{2}: commit: add distributed
f5302fb HEAD@{3}: commit (initial): wrote a readme file

可以看到append GPL的commit id号为13cd2aa,使用git reset --hard 13cd2aa回到append GPL版本

工作区和暂存区

Git跟踪管理的是修改

每次修改如果不add到暂存区,就不会加入到commit

撤销修改

删除文件

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

        test.txt

nothing added to commit but untracked files present (use "git add" to track)
$ rm test.txt
$ git status
On branch master
nothing to commit, working directory clean

可以看到test.txt已成功删除

添加远程库

当本地已经有了一个git仓库,想要创建一个远程库时,可以先关联,然后进行推送
如果从零开始,先创建远程库,再从远程库进行克隆

创建与合并分支

Git中的HEAD实际上执行的是当前的分支,每个分支中都有一个指针指向当前的提交

$ git checkout -b dev
Switched to a new branch 'dev'

git checkout加上-b参数表示创建并切换,相当与以下2条命令

$ git branch dev
$ git checkout dev
Switched to branch 'dev'

然后用git branch命令查看当前分支

$ git branch
* dev
  master

git branch命令会列出所有的分支,当前的分支会用一个*标出
现在可以在dev分支上进行正常的修改提交

$ vi readme.txt
$ git add readme.txt
$ git commit -m "branch test"
[dev 6f978d0] branch test
 1 file changed, 1 insertion(+)

现在dev分支上的工作完成,我们就可以切换回master分支

$ git checkout master
Switched to branch 'master'

切换回master分支后会看到刚才提交的修改不见了,因为刚才的修改在dev分支上,而master分支此刻的提交点并没有变

$ git merge dev
Updating eb42341..6f978d0
Fast-forward
 readme.txt | 1 +
 1 file changed, 1 insertion(+)

git merge命令用于合并指定分支到当前分支。合并后查看readme.txt文件可以看到和dev分支上最新提交的是一样的
上面的输出中有一行Fast-forward,表示这是合并是“快进模式”,也就是直接把master指向dev的当前提交,所有合并速度非常快

$ git branch -d dev
Deleted branch dev (was 6f978d0).
$ git branch
* master

解决冲突

准备新的feature1分支进行开发

$ git checkout -b feature1
Switched to a new branch 'feature1'

修改readme.txt文件,并提交

$ vi readme.txt
$ git add readme.txt
$ git commit -m "AND simple"
[feature1 029a3b2] AND simple
 1 file changed, 1 insertion(+), 1 deletion(-)

切换到master分支,修改readme.txt并提交

$ git checkout master
Switched to branch 'master'
$ vi readme.txt
$ git add readme.txt
$ git commit -m "& simple"
[master 9243e69] & simple
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

从输出可以看到Automatic merge failed; fix conflicts and then commit the result.合并失败了,Git让先解决冲突然后在提交结果
使用git status命令也可以告诉我们冲突的文件

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")

直接vi查看readme.txt

$ vi 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用<<<<<< ====== >>>>>>标记出了不同分支的内容

<<<<<<< HEAD
Creating a new branch is quick & simple.

表示当前master分支的内容

Creating a new branch is quick AND simple.
>>>>>>> feature1

表示feature1分支的内容
在此模式下修改这个文件为想要的内容,然后保存再提交

$ git add readme.txt
$ git commit -m "conflict fixed"
[master 7ff0a70] conflict fixed

可以看到输出提示冲突已解决,查看readme.txt内容为刚刚保存的内容
用带参数的git log命令可以查看当前的分支合并情况

$ git log --graph --pretty=oneline --abbrev-commit
*   7ff0a70 conflict fixed
|\
| * 029a3b2 AND simple
* | 9243e69 & simple
|/
* 6f978d0 branch test
* eb42341 remove test.txt
* 28abff3 add test.txt
* 665e753 remove test.txt
* 232dc37 add text.txt

最后删除分支

$ git branch -d feature1
Deleted branch feature1 (was 75a857c).
$ git branch -d dev  #dev分支未合并,所以删除失败
error: The branch 'dev' is not fully merged.
If you are sure you want to delete it, run 'git branch -D dev'.
$ git branch -D dev  # 强行删除
Deleted branch dev (was e32273c).

分支管理策略

通常分支合并时,如果可能,Git会用Fast forword模式,在这种模式下删除分支,会丢掉分支信息

$ git log --graph --pretty=oneline --abbrev-commit
* 6106360 test fast forword
*   7ff0a70 conflict fixed

像上面的test fast forword不会保留dev分支信息
git merge命令加上--no-ff参数会禁用Fast forword模式,Git会在merge时生成一个新的commit,这样从分支历史上就可以看出分支信息

$ git checkout -b dev
Switched to a new branch 'dev'
$ vi readme.txt
$ git add readme.txt
$ git commit -m "test --no--ff"
[dev 8de91d1] test --no--ff
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git checkout master
Switched to branch 'master'

使用git merge --no-ff命令合并

$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
 readme.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

这里的-m参数相当与commit 时候的说明。因为会生成一个新的commit所以使用-m参数添加提交说明
使用git log查看提交历史

$ git log --graph --pretty=oneline --abbrev-commit
*   4286431 merge with no-ff
|\
| * 8de91d1 test --no--ff
|/
* 6106360 test fast forword
*   7ff0a70 conflict fixed

可以看到这里和上一次merge的test fast forword不同,显示了分支上test--no-ff的提交,并创建了一个新的commit记录
Fast forword模式相当与直接将master提交指向了dev提交,将HEAD指向master

Git stash

正在dev分支上工作,还没有提交,突然需要解决线上bug,这个时候就需要将dev分支上的内容储藏起来,等以后恢复现场再使用,可以使用git stash命令

$ vi readme.txt
$ git status
On branch dev
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

no changes added to commit (use "git add" and/or "git commit -a")

可以看到当前dev分支正在工作

$ git stash
Saved working directory and index state WIP on dev: 8de91d1 test --no--ff
HEAD is now at 8de91d1 test --no--ff
$ git status
On branch dev
nothing to commit, working directory clean

使用git stash命令将当前工作储藏起来,可以看到现在当前dev分支是干净的
使用git stash list命令可以查看储藏的列表

$ git stash list
stash@{0}: WIP on dev: 8de91d1 test --no--ff

可以看到工作现场还在GIt把它存储在某个地方了
想要恢复有2中方法
1.使用git stash apply恢复,但是恢复后stash内容不会删除,需要使用git stash drop来删除

$ git stash apply
On branch dev
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

no changes added to commit (use "git add" and/or "git commit -a")
$ git stash list
stash@{0}: WIP on dev: 8de91d1 test --no--ff
$ git stash drop
Dropped refs/stash@{0} (e83c20f2d39c1b48e25108923f4f7013e3855ed4)
$ git stash list

2.使用git stash pop恢复的同时把stash的内容也删了

$ git stash pop
On branch dev
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

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (f94abd78b7ae06ada2581a2b92e63bc74c1fd164)

可以多次stash,然后使用git stash apply stash@{0},恢复指定的stash

git remote

要查看远程库的信息,用git remote

$ git remote
origin

可以看到远程仓库的默认名称是origin
git remote -v可以查看更详细的信息

$ git remote -v
origin  https://github.com/tangxq/test.git (fetch)
origin  https://github.com/tangxq/test.git (push)

上面显示了可以抓取和推送的远程地址,如果没有推送权限就看不到push的地址

推送分支

推送分支,就是把该分支上所有本地提交推送到远程库,推送时,要指定本地分支,这样Git就会把该分支推送到远程库对应的远程分支上
$ git push origin master #推送master分支至远程库的master分支上
$ git push origin dev # 推送dev分支到远程库dev分支

抓取分支

当clone一个项目时,默认只会clone下来master分支,例如想要抓取远程库的dev分支,就必须创建远程的origindev分支到本地,可以使用如下命令

$ git checkout -b dev origin/dev
Branch dev set up to track remote branch dev from origin.
Switched to a new branch 'dev'

这样本地创建的dev分支就与远程库的dev分支相对应了

多人协作
$ git push origin dev
To https://github.com/tangxq/test.git
 ! [rejected]        dev -> dev (fetch first)
error: failed to push some refs to 'https://github.com/tangxq/test.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

推送失败,从提示信息可以看到是因为本次提交的推送和远程库中的内容有冲突(原因是别的小伙伴修改了同一个文件并且已经提交至远程dev分支),GIt已经提示我们先用git pull 把最新的提交抓取下来,在本地合并冲突提交,再推送

$ git pull origin dev
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From https://github.com/tangxq/test
 * branch            dev        -> FETCH_HEAD
   ee45e18..ae94d9c  dev        -> origin/dev
Auto-merging test1.txt
CONFLICT (content): Merge conflict in test1.txt
Automatic merge failed; fix conflicts and then commit the result.

这里也可以使用另一种方法,先使用git branch --set-upstream dev origin/dev命令将本地的dev分支与远程dev分支关联,然后再使用git pull命令

On branch dev
Your branch and 'origin/dev' have diverged,
and have 1 and 1 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:   test1.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        logs/
        test.txt

no changes added to commit (use "git add" and/or "git commit -a")

2.使用vi命令编辑解决冲突
$ vi test1.txt
3.提交修改

$ git add test1.txt
$ git commit -m "merge & fixed test1.txt"
[dev 2cc8eb9] merge & fixed test1.txt
$ git push origin dev
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 410 bytes | 0 bytes/s, done.
Total 4 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
To https://github.com/tangxq/test.git
   ae94d9c..2cc8eb9  dev -> dev

标签管理

发布一个版本时,通常会先在版本库中打一个标签(tag),这样就确定了打标签时刻的版本,tag相当与是当前commit id的一个指针,是全局的,和分支没有关系
使用git tag name命令在git中打标签

$ git branch
* dev
  master
$ git tag v1.0

可以使用git tag命令查看所有标签

$ git tag
v1.0

默认标签都是打在最新的commit id上,如果要在指定的commit id上打标签,使用git tag name id号即可
使用git log命令列出所有的commit id

2cc8eb9 merge & fixed test1.txt
f00abb4 add hehe
ae94d9c edit test1.txt
ee45e18 Merge tag 'v1.0' of https://github.com/xxx/test into dev
454eb54 write dev dev1
64f1c6c add write dev1
e3fef54 add write dev
606b1dc add test1

比如要对add hehe这个commit打tag,使用如下命令即可

$ git tag v0.9 f00abb

使用git tag命令查看tag列表

$ git tag
v0.9
v1.0

标签不是按照时间顺序列出的,而是按照字母顺序列出。
可以使用git show tagname查看tag详细信息

$ git show v0.9
commit f00abb43d5a68dae01b73978657b964353baabb1
Author: tyq <tangyaqiang@huimin100.cn>
Date:   Sat Jan 6 11:22:58 2018 +0800

    add hehe

diff --git a/test1.txt b/test1.txt
index 5ad28e2..844e587 100644
--- a/test1.txt
+++ b/test1.txt
@@ -1 +1,2 @@
-haha
+haha.
+hehe

还可以创建带有说明的标签,-a指定标签名-m指定说明文字

$ git tag -a v0.8 -m "version 0.8 released" ee45e

使用git show tagname命令可以看到文字说明

$ git show v0.8
tag v0.8
Tagger: tyq <tangyaqiang@huimin100.cn>
Date:   Sat Jan 6 14:58:43 2018 +0800

version 0.8 released

commit ee45e18527440d7ba9e72a2ad8240cb80306a4a9
Merge: 454eb54 6229764
Author: tyq <tyq@email.com>
Date:   Thu Jun 29 11:24:57 2017 +0800

    Merge tag 'v1.0' of https://github.com/xxx/test into dev

操作标签

如果标签打错了,也可以删除

$ git tag -d v0.8
Deleted tag 'v0.8' (was 4d86fe9)

如果想要推送某个标签到远程可以使用git push origin tagname

$ git push origin v0.9
Total 0 (delta 0), reused 0 (delta 0)
To https://github.com/xxx/test.git
 * [new tag]         v0.9 -> v0.9

或者一次性推送全部尚未推送到远程的标签

$ git push origin --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 554 bytes, done.
Total 1 (delta 0), reused 0 (delta 0)
To https://github.com/xxx/test.git
 * [new tag]         v0.2 -> v0.2
 * [new tag]         v0.9 -> v0.9

如果想要拉取远程库中的tag,使用git pull

$ git pull
From https://github.com/tangxq/test
 * [new tag]         v1.0       -> v1.0
Already up-to-date.

如果tag已经推送到远程仓库删除,需要2步
1.首先删除本地的tag

$ git tag -d v0.8
Deleted tag 'v0.8' (was 4d86fe9)

2.删除远程仓库中的tag

$ git push origin :refs/tags/v.08
To https://github.com/tangxq/test.git
 - [deleted]         v0.8
# git 拉取远程指定的分支并关联
git checkout -b 本地分支名 origin/远程分支名
# 更改关联本地分支和远程的分支
git branch --set-upstream-to origin/远程分支名 本地分支名
# 提交当前分支的内容到远程对应的分支
git push origin HEAD: 远程分支名
上一篇下一篇

猜你喜欢

热点阅读