Git 命令详解

Git 命令详解


  

1 Git 下载和安装

1.1 Git 下载地址

根据自己电脑型号下载对应版本即可。本机是win10 64位,下载对应64位版本。

1.2 Git 安装

  • 默认安装到C盘,一路next点击就行。
  • 指定安装,本机指定安装到D:Git,修改路径一路next点击就行。

git有名为git-bash的终端,使用该终端执行git命令。


2 创建版本库

2.1 用户配置

使用如下命令为所有版本库配置用户名和Email地址,因为Git是分布式版本控制系统,每位用户需要自报家门。

$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"

 --global参数表示为本机器上所有Git仓库都使用这个配置,当然也可以为每个Git仓库配置不同的用户名和Email地址。

2.2 创建仓库

使git init命令可以将任何目录夹创建成Git仓库,本机Git仓库存放目录为D:GitRepository,打开git-bash,进入上述所述目录,然后使用git init命令将learngit目录创建为仓库:

$ cd D:/Git/Repository/learngit/
$ git init

 Tipswindows使用git-bash终端输入文件路径是使用斜杠而不是反斜杠。


3 添加和提交文件到仓库

在learngit目录下新建一个readme.txt文件,并用Notepad++编辑如下内容并保存:

$ Git is a version control system.
$ Git is free sofware.

Tips不要用记事本进行编辑,windows的记事本进行编辑,以为它会在每个文件开头添加了0xefbbbf(十六进制)的字符,你会遇到很多不可思议的问题,比如,网页第一行可能会显示一个“?”。

编辑保存完readme.txt文件后,按如下步骤将其放入版本库:

1.使用git add命令将readme.txt添加到仓库。

$ git add readme.txt

2.使git commit命令将readme.txt提交到仓库。

$ git commit -m "wrote a readme file"

-m参数表示本次提交的说明,最好填写有意义的内容。

Tipsgit add 可以一次添加多个文件,文件之间用空格分开。git commit 一次可以提交多个文件。


4 查询仓库当前状态

修改readme.txt文件内容如下:

$ Git is a distributed version control system.
$ Git is free software.

使git status命令查看仓库当前状态:

$ 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")

结果显示readme.txt被修改过,但是还没准备提交。

使git diff命令查看readme.txt哪些地方被修改过:

$ git diff readme.txt
diff --git a/readme.txt b/readme.txt
index d8036c1..013b5bc 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.
 No newline at end of file

Tips:在提交之前查看被修改的地方是有必要的。

接下来将文件添加到仓库:

$ git add readme.txt

git status查看仓库当前状态:

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

            modified: readme.txt        

果显示将要被提交的修改包括readme.txt。

这个时候如果使用git diff命令是查看不到readme.txt哪些地方被修改了:

$ git diff readme.txt

有任何输出结果,但是可以使用git diff命令来查看工作区中的readme.txt和版本库中最新readme.txt的不同:

$ git diff HEAD -- readme.txt
diff --git a/readme.txt b/readme.txt
index d8036c1..013b5bc 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.
 No newline at end of file

 接下来可以放心提交:

$ git commit -m "add distributed"
[master 1245bca] add distributed
1 file changed, 1 insertion(+), 1 deletion(-)

交完成后,用git status命令查看当前仓库状态:

$ git status
On branch master
nothing to commit, working tree clean

结果显示没有需要提交的修改,而且工作目录是干净的。


5 版本回退

修改readme.txt文件如下:

Git is a distributed version control system.
Git is free software distributed under the GPL.

 然后尝试提交:

$ git commit -m "add GPL"
[master 49c07cc] add GPL
1 file changed, 1 insertion(+), 1 deletion(-)

 一次的commit就相当于保存一个快照,一旦你将文件弄乱或者误删了文件,就可以从最近的一个commit恢复,继续工作。

以使用git log命令来查看历史版本:

$ git log
commit 49c07cc0c5b1bd1bf5df2199129a7ed063709f4e (HEAD -> master)
Author: StrivePy <1013974267@qq.com>
Date: Sun Mar 18 19:49:59 2018 +0800

    add GPL

commit 73a55c6fadf4380e784380b28e8e3ca49b85ba40
Author: StrivePy <1013974267@qq.com>
Date: Sun Mar 18 19:42:16 2018 +0800

    add distributed

 使--pretty=oneline参数可以简化输出:

$ git log --pretty=oneline
49c07cc0c5b1bd1bf5df2199129a7ed063709f4e (HEAD -> master) add GPL
73a55c6fadf4380e784380b28e8e3ca49b85ba40 add distributed

 49c07cc0c5b1bd1bf5df2199129a7ed063709f4e一串表示commit id,只要知道任何commit id就可以使用git reset命令切换到该提交版本:

$ git reset --hard 73a55
HEAD is now at 73a55c6 add distributed

结果显示已经回退到add distributed版本。

想回到add GPL版本,同样适用commit id

$ git reset --hard 49c07
HEAD is now at 49c07cc add GPL

结果显示回到add GPL版本。

可以使用HEAD指针来进行版本回退,Git中,用HEAD表示当前版本,HEAD^表示上一版本,HEAD^^表示上上版本,当然往上100个版本写100个^数不过来,用HEAD~100表示。用HEAD指针进行回退:

$ git reset --hard HEAD^
HEAD is now at 73a55c6 add distributed

结果显示已经回退到add distributed版本。

在关闭git-bash,再重新打开并进入learngit目录,使用git log命令:

$ git log
commit 73a55c6fadf4380e784380b28e8e3ca49b85ba40 (HEAD -> master)
Author: StrivePy <1013974267@qq.com>
Date: Sun Mar 18 19:42:16 2018 +0800

  add distributed

果已经看不见add GPL版本了,想使用commit id前进到add GPL版本但是没有commit id,此时可以使用git reflog来查看每一次你输入的命令:

$ git reflog
73a55c6 (HEAD -> master) HEAD@{0}: reset: moving to HEAD^
49c07cc HEAD@{1}: reset: moving to 49c07
73a55c6 (HEAD -> master) HEAD@{2}: reset: moving to 73a55
49c07cc HEAD@{3}: commit: add GPL
73a55c6 (HEAD -> master) HEAD@{4}: commit: add distributed

果显示add GPL的commit id49c07cc,使用该id进行回退:

$ git reset --hard 49c07cc
HEAD is now at 49c07cc add GPL

结果显示已经回退到add GPL版本。

小结:

  • HEAD指向的是当前版本,可以使用如下命令在版本之间穿梭:
    $ git reset --hard commit_id
  • 穿梭前,可以使用如下命令查看历史版本的commit_id

    $ git log
  • 重返未来,可以使用如下命令查看commit_id
    $ git reflog

6 管理修改

Git管理的是修改而不是文件,文件内容的增减,文件的创建和删除都属于修改。

对readme.txt新增一行后保存:

Git is a distributed version control system.
Git is free software distributed under the GPL.
Git tracks changes.

  然后添加到仓库:

$ git add readme.txt

  查看仓库当前状态:

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

            modified: readme.txt    

  结果显示readme.txt的修改将被提交,然后再修改readme.txt如下后保存:

Git is a distributed version control system.
Git is free software distributed under the GPL.
Git tracks changes of files.

 然后提交修改:

$ git commit -m "git tracks changes"
[master 6ea23a0] git tracks changes
 1 file changed, 2 insertions(+), 1 deletion(-)

再查看仓库当前状态:

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

            modified: readme.txt

果显示,readme.txt还有修改没有提交。原因是commit是负责提交缓存区的修改,第二次的修改没有添加到缓存区,所以没有没提交到版本库。可以用git diff HEAD -- readme.txt命令开查看readme.txt第二次修改和版本库中的不同。

Tips:Git跟踪的是修改,若修改没有用git add命令添加到缓存区,就不会被git commit命令提交到版本库。


7 撤销修改

先查看learngit仓库的当前状态:

$ git status
On branch master
nothing to commit, working tree clean

  结果显示工作区是干净的,现对readme.txt做如下修改:

Git is a distributed version control system.
Git is free software distributed under the GPL.
Git tracks changes of files.
Git revokes modification.

  此时不想要最后添加的一行了,可以直接在编辑器中删除,也可以使用git checkout命令来撤销工作区中的修改

$ git checkout -- readme.txt

  然后查看readme.txt,果然修改被撤销了:

$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git tracks changes of files.

 Tips:撤销修改的git checkout命令后面必须带上--,不然变成了切换分支命令。

现在继续加上最后一行的修改,并将readme.txt添加到缓存区继续工作:

$ git add readme.txt

查看仓库当前状态:

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

            modified: readme.txt

 结果显示readme.txt的修改将被提交,但是现在不想提交,因为工作就剩一步就完成了,然后一起提交,但是当工作快完成的时候,最后一步的思路被完全打乱,文件非常混乱怎么都整理不好了,readme.txt文件被修改如下:

$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git tracks changes of files.
Git revokes modification.
My stupied boss still prefers SVN.

时可以使用git checkout命令回到上一次git add状态:

$ git checkout -- readme.txt

查看readme.txt:

$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git tracks changes of files.
Git revokes modification.

果显示git add后的修改被撤销了,回到了上一次git add时的状态,查看仓库当前状态:

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

            modified: readme.txt

果显示上上次的修改添加到缓存区了将要被提交。此时接到新的需求,已经提交到缓存区的修改也不需要了,可以使用git reset命令撤销已经添加到缓存区中的修改,回到最初的工作区状态:

$ git reset HEAD readme.txt
Unstaged changes after reset:
M        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")

 结果显示readme.txt的修改还没有被添加到缓存区,查看readme.txt:

$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git tracks changes of files.
Git revokes modification.

果显示修改还保存在工作区,继续使用git checkout命令撤销工作区的需改:

$ git checkout -- readme.txt

查看仓库当前状态:

$ git status
On branch master
nothing to commit, working tree clean

结果显示工作区是干净的,工作区的修改已经被撤销。查看readme.txt:

$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git tracks changes of files.

确认修改已经被撤销。

小结:

  • 当弄乱了工作区,想要撤销修改,可以使用命令:
    $ git checkout -- filename

     当弄乱了工作区,并已经添加到缓存区,可以使用如下命令后,再使用上述命令:

  • $ git reset HEAD filename
  • 当已经提交不合适的内容到版本库,可以使用版本回退命令回到你想要的版本,参考版本回退。如果已经推送到远程仓库,那就。。呵呵。

8 删除文件

Git中删除和新增文件也是修改操作,在learngit仓库中新增test.txt文件,产看仓库仓前状态:

$ 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)

 结果显示test.txt还没有被跟踪,现在将test.txt添加到仓库并提交:

$ git commit -m "add test.txt"
[master 07332c3] add test.txt
1 file changed, 1 insertion(+)
create mode 100644 test.txt

般要删除test.txt可以直接在文件资源管理器中直接删除,或者使用rm命令删除:

$ rm test.txt

时,Git知道你删除了哪些文件,可以用git status命令查看哪些文件被删除了:

$ git status
On branch master
Changes not staged for commit:
    (use "git add/rm <file>..." to update what will be committed)
    (use "git checkout -- <file>..." to discard changes in working directory)

            deleted: test.txt

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

结果显示,test.txt文件被删除了,但是这个修改还没有被提交到版本库,也就是说版本库中test.txt文件还存在。现在有两种情况:

  • 定要删除该文件,并且需要删除版本库中的该文件。用git rm命令删除版本库中的test.txt文件,并用git commit提交修改:
    $ git rm test.txt
    rm 'test.txt'

    查看仓库当前状态:

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

    提交修改:

    $ git commit -m "delete test.txt"
    [master bd9ecd8] delete test.txt
    1 file changed, 1 deletion(-)
    delete mode 100644 test.txt

    至此,版本库中的test.txt文件就被删除了。

  • 是在工作区误删了该文件,可以使用git checkout -- filename命令可以撤销该文件的删除操作。
    查看仓库当前状态:
    $ git status
    On branch master
    Changes not staged for commit:
        (use "git add/rm <file>..." to update what will be committed)
        (use "git checkout -- <file>..." to discard changes in working directory)
    
                deleted: test.txt
    
    no changes added to commit (use "git add" and/or "git commit -a")

小结:

  • 要删除版本库中的文件,使用命令:
    $ git rm filename
  • 果一个文件已经提交到版本库,你永远不用担心误删,可以使用如下命令恢复到你最近一次提交到版本库时的版本,但你会丢失提交后的修改
    $ git checkout -- filename

9 远程仓库

将Github作为远程仓库,该网站提供Git仓库托管服务。

9.1 创建SSH Key

用户主目录下看有没有.ssh目录,若有看该目录有没有id_rsaid_rsa.pub文件,这两个文件就是SSH Key的密钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以告诉任何人。如果没有这两个文件,可以打开git-bash输入以下命令:

$ ssh-keygen -t rsa -C "youremail@example.com"

 上述email地址换成自己的,一路回车即可,然后可以看见.ssh目录下生成了这两个文件。可以直接在git-bash下使用cat命令来查看id_rsa.pub文件的内容。

9.2 给Github账户添加SSH Key

GitHub,打开Account settingsSSH Keys页面。后,点Add SSH Key,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容

9.3 创建Github仓库

在Github上创建一个名为learngit的空仓库,该仓库有两个地址:

  • SSH地址:git@github.com:StrivePy/learngit.git
  • HTTPS地址:https://github.com/StrivePy/learngit.git

一般使用是SSH地址,传输速度较快,HTTPS地址除传输速度慢外,还需要额外输入端口地址。

9.4 关联Github仓库

在本机上有一个名为learngit的本地仓库,Github上有一个名为learngit的远程仓库,使用git remote命令可以将本地仓库和远程仓库关联起来:

$ git remote add origin git@github.com:StrivePy/learngit.git

StrivePy是本机用户的Github用户名,该账户已经添加了本机的SSH Key,可以进行关联和推送,但是其它机器也可以关联,但是SSH Key不在StrivePy账户的SSH Key列表中,所以不能推送消息到该用户的仓库。origin表示远程仓库的名字,当然也可以取你自己喜欢的名字。

9.5 向远程仓库推送文件

程仓库关联完成后,就可以使用git push命令将本地仓库当前分支文件推送到远程仓库:

$ git push -u origin master
Counting objects: 18, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (18/18), done.
Writing objects: 100% (18/18), 1.80 KiB | 614.00 KiB/s, done.
Total 18 (delta 5), reused 0 (delta 0)
remote: Resolving deltas: 100% (5/5), done.
To github.com:StrivePy/learngit.git
    be0db50..07332c3 master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

入Github的learngit仓库,可以看见仓库里面有文件,而且文件和本地learngit仓库文件一样,说明推送成功。本次是将本地master分支内容到远程仓库的master分支,-u参数表示在将本地master分支推送到远程master分支的同时,并将两个master分支关联起来,以后就可以使用简化的git push命令进行推送。 现在只要在本地仓库做了提交,就可以使用git push命令将提交推送到远程仓库:

$ git push origin master

 以上是理想的状况,实际操作中,Github新建的仓库默认会有一个README.md文件,在使用git push -u origin master命令时,会提示远程仓库还有文件没有同步到本地,推送失败,而且会提示本地分支和远程仓库没有关联,可以使用如下命令进行关联:

$ git branch --set-upstream-to=origin/remote_branch  your_branch

 然后再用git push命令进行推送,但是还会提示:

fatal: refusing to merge unrelated histories

原因是在合并了两个不同的提交仓库时(本地仓库和远程仓库),git会发现这两个仓库可能不是同一个,为了防止推送错误,所以给出上述提示。

如果的却清楚需要合并,可是在git pull命令后加上参数--allow-unrelated-histories来进行版本的合并:

$ git pull origin master --allow-unrelated-histories

 如果还不能合并,看是否存在冲突,解决冲突后再进行合并。

小结:

  • 关联远程仓库使用命令:
    $ git remote add origin git@github.com:StrivePy/learngit.git
  • 第一次推送分支使用命令:

    $ git push -u origin master
  • 此后,本地提交后若有需要推送到远程仓库,使用命令:
    $ git push origin master

9.6 从远程仓库克隆

本地仓库learngit的同级目录下新建一个名为clone的目录,使用git-bash进入clone目录,使用如下命令将远程仓库learngit克隆到该目录:

$ git clone git@github.com:StrivePy/learngit.git

 进入clone目录可以看见远程仓库learngit已经被克隆下来了。

小结:

  • 要克隆一个远程仓库,必须先知道该仓库的地址,然后使用如下命令进行克隆:
    $ git clone repository_address
  • Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快。

10 分支管理

10.1 创建与合并分支

master是默认的主分支,我们一般不在上面进行工作,只是将其它分支合并到该分支,如有需要再将master分支推送到远程仓库。

先创建名为dev的分支,并切换到该分支,使用如下命令:

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

  -b参数表示创建并切换,该命令等效于:

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

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

$ git branch
* dev
master

在我们就可以在dev分支上正常工作了,因为是从master分支创建的dev分支,所有现在dev分支现在的工作区和master分支的工作区是一样的,现在在readme.txt加上一行:

Creating a new branch is quick.

 然后添加并提交:

$ git add readme.txt
$ git commit -m "branch test"
[dev a9f9dbb] branch test
1 file changed, 4 insertions(+), 9 deletions(-)

在切回master分支:

$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

 看readme.txt内容发现刚刚添加的一样没有添加上,原因是在dev分支上添加的,现在将dev分支的工作合并到master分支上:

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

git merge用于合并指定分支到当前分支,合并后发现dev的添加的一行合并过来了,Fast-forward表示快进合并,直接把master指向dev,最后删除dev分支:

$ git branch -d dev
Deleted branch dev (was fec145a).

 再查看分支:

$ git branch
* master

 小结:

  • 查看分支:
    $ git branch
  • 创建分支:
    $ git branch name
  • 切换分支:
    $ git checkout branch_name
  • 创建并切换分支:
    $ git checkout -b name
  • 合并某分支到当前分支:
    $ git merge name
  • 删除分支:
    $ git branch -d name

10.2 解决冲突

 时候合并并不是一帆风顺的,例如新建并切换到feature1分支:

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

在readme.txt最后添加一行:

Creating a new branch is quick AND simple.

添加并提交:

$ git add readme.txt
$ git commit -m "AND simple"
[feature1 ddd008d] AND simple
1 file changed, 2 insertions(+), 1 deletion(-)

后切换到master分支:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)

果显示本地仓库比远程仓库要新,这个不用管。在master分支对readme.txt最后添加一行:

Creating a new branch is quick & simple.

  添加并提交:

$ git add readme.txt
$ git commit -m "& simple"
[master 8368fab] & simple
1 file changed, 2 insertions(+), 1 deletion(-)

接下来合并,但是这种情况下,Git无法执行快进合并,只能尝试把各自的修改合并起来,有可能产生冲突,接下来尝试一下:

$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

果提示产生冲突,需要手动解决冲突后再提交,使用git status可以查看冲突的文件:

$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
    (use "git push" to publish your local commits)

    You have unmerged paths.
    (fix conflicts and run "git commit")
    (use "git merge --abort" to abort the merge)

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")

可以查看一下readme.txt:

$ cat 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用<<<<<<<=======>>>>>>>标记出不同分支的内容,我们修改如下后保存:

Creating a new branch is quick and simple.

再提交:

$ git commit -m "confict fixed"
[master 4de6f5f] confict fixed

带参数的git log命令查看分支合并情况:

$ git log --graph --pretty=oneline --abbrev-commit
* 4de6f5f (HEAD -> master) confict fixed
|
| * ddd008d (feature1) AND simple
* | 8368fab & simple
|/
* 14b0a6e modify readme.txt

最后删除feature1分支:

$ git branch -d feature1
Deleted branch feature1 (was ddd008d)

小结:

  • Git无法自动完成合并时,需要手动解决冲突,再提交,完成合并。
  • 查看分支合并图可以使用如下命令:
    $ git log --graph 

11 分支管理策略

11.1 禁用Fast Forward合并模式

Git默认采用的是快进合并模式,快进合并模式下,删除分支后,会丢掉分支信息。果要强制禁用Fast forward模式,Git在merge时会产生一个新的commit,这样在分支历史上就可以看出分支信息,接下来实验一下。

先创建并切换到分支dev:

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

在readme.txt后增加一行内容:

Git fast forward merge.

并将修改提交:

$ git commit -m "no fast forward merge"
[dev 44e4f6f] no fast forward merge
1 file changed, 1 insertion(+), 1 deletion(-)

在切换回master分支:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 13 commits.
    (use "git push" to publish your local commits)

后用--no-ff模式将dev分支合并到master分支:

$ 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(-)

Tips:因为本次合并要新建一个commit所以带上-m参数添加提交说明

后用git log命令查看日志:

$ git log --graph --pretty=oneline --abbrev-commit
* df99854 (HEAD -> master) merge with --no-ff
|
| * 44e4f6f (dev) no fast forward merge
|/
* 9e4a116 merge with --no-ff model

 日志图形结果显示了分支的历史信息。

小结:

  • 使git merge命令带上--no-ff参数就表示用普通模式进行合并,合并后的历史有分支,能看出来曾经做过合并,而Fast forward模式则看不出来曾经做过合并。

11.2 Bug分支

一个Bug都可以通过一个新的临时分支来修复,然后在合并分支,最后将临时分支删除。假设正在dev分支上工作,对readme.txt文件修改工作,但接到任务说master分支上有一个名为issue-001的Bug被发现了,需要紧急修改,此时看一下dev分支的工作状态:

$ 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分支上还有没有提交的修改,但是修改只进行了一半,无法立刻提交,而现在又要去修改Bug,该怎么处理,好在Git有一个git stash命令可以将工作现场暂时保存起来,等待以后恢复现场继续工作:

$ git stash
Saved working directory and index state WIP on dev: df99854 merge with --no-ff

 再查看工作区的状态:

$ git status
On branch dev
nothing to commit, working tree clean

果显示工作区是干净的。接下来就可以到master分支上去修复Bug了。 切换到master分支,再该分支上创建并切换到名为issue-001的分支来修复Bug:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 15 commits.
    (use "git push" to publish your local commits)
$ git checkout -b issue-001
Switched to a new branch 'issue-001'

现在修复Bug需要删除readme.txt的最后一行,修改完毕后添加并提交:

$ git add readme.txt
$ git commit -m "fixed issue-001"
[issue-001 3dfa376] fixed issue-001
1 file changed, 1 insertion(+), 1 deletion(-)

后切换到master分支,完成合并,并删除issue-001分支:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 15 commits.
(use "git push" to publish your local commits)
$ git merge --no-ff -m "merge bug fix issue-001" issue-001
Merge made by the 'recursive' strategy.
 readme.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git branch -d issue-001
Deleted branch issue-001 (was 3dfa376).

Bug修复完毕,回到dev分支继续工作,查看工作区状态:

$ git status
On branch dev
nothing to commit, working tree clean

果显示工作区是空的,使用git stash list查看工作现场的保存地址:

$ git stash list
stash@{0}: WIP on dev: df99854 merge with --no-ff 

恢复工作现场的两种方式:

  • 使git stash apply stash@{0},但是恢复后,stash的内容并不会被删除,需要使用git stash drop stash@{0}命令来删除stash内容。
  • 使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} (eb9fe8bbd71a8abc5a6e3badaa6a526d6c774ee8) 

     可以看见工作现场恢复了,而且使用git stash list命令查看不到任何stash内容。

以多次保存stash,然后用git stash list查看,然后用git stash apply stash@{number}来恢复指定的现场。

小结:

  • 修复Bug时,新建临时分支,解决完Bug后,合并分支,最后删除分支。
  • 使git stash可以保存工作现场,然后去完成其工作,最后回来恢复现场继续工作。
  • 丢弃一个没有合并的分支,可以使用git branch -D name强行铲除分支。

12 多人协作

12.1 远程仓库信息

从远程仓库clone时,Git实际上把本地的master分支和远程master分支关联起来,并且远程仓库的默认名称为origin,要查看远程仓库信息。

git remote命令:

$ git remote
origin

者用git remote -v查看远程仓库更详细的信息:

$ git remote -v
origin git@github.com:StrivePy/learngit.git (fetch)
origin git@github.com:StrivePy/learngit.git (push)

面显示了抓取和推送origin的地址。如果没有推送权限,就看不见origin的推送地址。

12.2 推送分支

推送分支,就是把本地分支上的所有提交推送到远程仓库。推送时加上分支名,Git就把该本地分支上的所有提交推送到对应的远程分支上:

$ git push origin master

要推送其它分支,使用对应的分支名称即可:

$ git push origin dev

并不是所有的分支都需要推送到远程仓库,需要推送到远程仓库的分支:

  • master分支作为主分支,需要时刻与远程仓库同步。
  • dev作为开发分支,团队成员都需要在上面工作,也需要时刻与远程仓库同步。
  • bug分支只在本地修改bug,不需要推送到分支。
  • feature分支是否推送到远程仓库,取决于是否和团队成员在该分支上合作开发。

12.3 抓取分支

人协作时,团队成员都会时不时往master分支和dev分支推送自己的修改。

本地learngit仓库同级目录下新建一个cooperation目录来模拟另一个团队成员,进入cooperation目录将远程learngit仓库克隆下来:

$ git clone git@github.com:StrivePy/learngit.git
Cloning into 'learngit'...
remote: Counting objects: 81, done.
remote: Compressing objects: 100% (49/49), done.
remote: Total 81 (delta 28), reused 77 (delta 25), pack-reused 0
Receiving objects: 100% (81/81), 7.71 KiB | 281.00 KiB/s, done.
Resolving deltas: 100% (28/28), done.

认情况下,clone完成后只能看见master分支:

$ git branch
* master

要在dev分支上进行开发,就必须创建远程origindev分支到本地:

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

时就能dev分支上进行工作了:

$ git branch
* dev
master

先查看readme.txt的内容:

$ cat readme.txt
git is a distributed version control system
git is a free software distributed under GPL
git has a mutable index called stage
git tracks changes of files
test git merge
create a new branch is simple And quick
add merge
test stash
add usr/bin/evn

将最后一行修改为:

add usr/bin/evn/test

然后提交并推送到远程仓库:

$ git add readme.txt
$ git commit -m "add usr/bin/evn/test"
[dev 62c782a] add usr/bin/evn/test
1 file changed, 1 insertion(+), 1 deletion(-)
$ git push origin dev
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 293 bytes | 293.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To github.com:StrivePy/learngit.git
    23625fd..62c782a dev -> dev

时,回到本地非clone的learngit仓库,查看readme.txt内容:

$ cat readme.txt
git is a distributed version control system
git is a free software distributed under GPL
git has a mutable index called stage
git tracks changes of files
test git merge
create a new branch is simple And quick
add merge
test stash
add usr/bin/evn/

将最有一行修改为:

add usr/bin/evn/tests

然后提交修改并尝试推送到远程仓库:

$ git commit -m "add usr/bin/evn/tests"
[dev 9c1fa27] add usr/bin/
1 file changed, 1 insertion(+), 1 deletion(-)
$ git push origin dev
To github.com:StrivePy/learngit.git
! [rejected] dev -> dev (fetch first)
error: failed to push some refs to 'git@github.com:StrivePy/learngit.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.

果因为另外的远程推送导致本次推送失败,你可能需要先整合(合并)远程修改再进行推送,所以使用git pull命令拉一下远程仓库:

$ git pull
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 2), reused 3 (delta 2), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:StrivePy/learngit
  9c1fa27..1dacdbc dev -> origin/dev
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

git pull失败,结果提示合并时,在readme.txt文件中有冲突,查看readme.txt文件:

$ cat readme.txt
git is a distributed version control system
git is a free software distributed under GPL
git has a mutable index called stage
git tracks changes of files
test git merge
create a new branch is simple And quick
add merge
test stash
<<<<<<< HEAD
add usr/bin/evn/tests
=======
add usr/bin/evn/test
>>>>>>> 1dacdbc0ca9202c1e11c366ce6b9c13f44cb5b47

将最后一行修改为:

add usr/bin/evn/

然后提交到本地仓库,再远程推送:

$ git add readme.txt
$ git commit -m "merge and fixed"
[dev 1a26ae2] merge and fixed
$ git push origin dev
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 572 bytes | 286.00 KiB/s, done.
Total 6 (delta 4), reused 0 (delta 0)
remote: Resolving deltas: 100% (4/4), completed with 2 local objects.
To github.com:StrivePy/learngit.git
    1dacdbc..1a26ae2 dev -> dev

结果显示推送成功,远程仓库中的readme.txt文件以解决冲突后文件为准。

小结:

  • 查看远程库信息,使用命令:
    $ git remote -v
  • 本地创建的分支,如果不推送到远程,对其他人是不可见的。
  • 多人协作的工作模式:
    • 先可试图用命令git push origin branch_name远程推送对自己的修改。
    • 果推送失败,则因为远程分支要比本地分支更新,用命令git pull拉取一下试图合并,如果拉取时提示no tracking information,用命令git branch --set-upstream=origin/remote_branch your_branch建立本地分支和远程分支的联系。
    • 如何合并失败,手动解决冲突,并在本地提交。
    • 有冲突或者解决冲突后,使用命令git push origin your_branch推送。

13 标签管理

13.1 创建标签

要创建标签,首先切换到要打标签的分支:

$ git branch
* dev
master
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

后使用git tag tag_name创建标签:

$ git tag v1.0

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

$ git tag
v1.0

认标签是打在最新提交的commit上的,可以使用git tag tag_name commit_id命令对任何提交打上标签:

$ git log --pretty=oneline --abbrev-commit
1ba8102 (HEAD -> master, tag: v1.0, origin/master) delete dev
cd05c0d merge bug fix issue-001
3dfa376 fixed issue-001
df99854 merge with --no-ff
44e4f6f no fast forward merge
9e4a116 merge with --no-ff model
3a6b35d merge test..
ce6ca91 merge test
3f0ad45 conflict fixed
4de6f5f confict fixed
8368fab & simple

果相对fixed issue-001这次提交打上标签:

$ git tag v0.9 3dfa376

 git show tag_name查看标签信息:

$ git show v0.9
commit 3dfa3760095617a41a068cf8b839c2a278e249c4 (tag: v0.9)
Author: StrivePy <1013974267@qq.com>
Date: Mon Mar 19 20:19:37 2018 +0800

        fixed issue-001

diff --git a/readme.txt b/readme.txt
index 23580ea..294d3b9 100644
--- a/readme.txt
+++ b/readme.txt
@@ -3,4 +3,4 @@ Git is free software distributed under the GPL.
 Git has a mutable index called stage.
 Git tracks changes of files.
 Creating a new branch is quick and simple.
-Git fast forward merge.
+

 签确实打在fixed issue-001这次提交上。

以使用git tag -a tag_name -m "information" commit_id打上带说明信息的标签,-a表示标签名,-m表示说明信息:

$ git tag -a v0.1 -m "version 0.1 released" cd05c0d

查看标签信息:

$ git show v0.1
tag v0.1
Tagger: StrivePy <1013974267@qq.com>
Date: Thu Mar 22 19:40:32 2018 +0800

version 0.1 released

commit cd05c0d4223a76abfa4dd6d55fb1dcc7eac8c10c (tag: v0.1)
Merge: df99854 3dfa376
Author: StrivePy <1013974267@qq.com>
Date: Mon Mar 19 20:23:09 2018 +0800
    
            merge bug fix issue-001    

小结:

  • 对默认的最新提交打标签使用命令:
    $ git tag tag_name
  • 要标签上带上说明信息,使用如下命令:
    $ git tag -a tag_name -m "information" commit_id
  • PGP签名标签,使用如下命令:
    $ git tag -s tag_name -m "information" commit_id 
  • 显示所有标签,使用命令:
    $ git tag
  • 显示标签详细信息,使用命令:
    $ git show tag_name 

13.2 操作标签

要删除一个标签,使用git tag -d tag_name命令:

$ git tag -d v0.1
Deleted tag 'v0.1' (was 4630d67)

推送本地标签到远程:

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

或者使用如下命令,将本地所有未推送的标签一次性推送到远程仓库:

$ git push origin --tags
Total 0 (delta 0), reused 0 (delta 0)
To github.com:StrivePy/learngit.git
* [new tag]         v1.0 -> v1.0

如果标签已经推送到了远程仓库,可以用以下步骤删除远程仓库标签:

  • 先删除本地标签:
    $ git tag -d v0.9
    Deleted tag 'v0.9' (was 3dfa376)
  • 再删除远程仓库的标签:
    $ git push origin :refs/tags/v0.9
    To github.com:StrivePy/learngit.git
    - [deleted]         v0.9

     登陆Github查看该标签确实被删除了。

小结:

  • 推送一个本地标签,使用命令:
    $ git push origin tag_name
  • 推送本地所有未推送的标签,使用命令:
    $ git push origin --tags
  • 删除一个本地标签,使用命令:
    $ git tag -d tag_name
  • 删除一个远程标签,使用命令:
    $ git push origin :refs/tags/tag_name 

14 参考资料

廖雪峰老师Git 教程:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

原文地址:https://www.cnblogs.com/strivepy/p/9676146.html