Long

欢迎来到Long的博客站点

Git使用教程

前言

Git是世界上最流行的分布式版本控制系统,同理,既然有分布式,也有集中式版本控制系统,著名的就是CVS和SVN,集中式的版本控制系统顾名思义就是几台电脑连接到服务器中,如果我们需要写代码,就要先从服务器中把代码拷贝到本地,然后修改,修改完了之后再拷贝到服务器中,这在局域网中是非常方便的,但是放置到互联网环境中不可行,提交一个文件,网速太慢,导致提交很久也是可能的,同时,如果服务器奔溃了,那么代码就消失了,这显然是不可接受的。分布式版本控制系统就不一样,在每台电脑上都有完整的项目代码,这样一台电脑项目代码没了,可以直接从其他地方进行拷贝就行。但是,如果两个人要进行合并代码,需要把代码互相推送给对方,这有点不方便,为了便于交换代码,这时就是弄了一台服务器作为交换使用,这里的服务器仅作为交换使用,不像集中式版本控制那样,作为整个数据中心来使用。

Git安装

在不同的平台上有不同的安装方式。在linux中(Ubuntu),直接apt install git;或者去Git官网下载源码,进行源码安装,./config make sudo make install。

Windows平台,直接去Git官网上面下载镜像即可,和安装普通软件没什么区别。安装完毕后,运行git bash,这个就是一个命令控制窗口,相当于一个模拟终端,通过这个窗口可以使用在linux中的一些常用命令,非常分别,如果你不想使用windonws提供的cmd控制台,可以直接使用git bash。

安装完Git之后,需要设置一些东西

git config --global user.name "Your name"
git config --global user.email "You email"

这个配置主要用户管理用户提交文件时确定是哪个用户提交的。

–global表示的是你这台机器中的所有Git库用的都是这个用户名和邮箱,如果你不想使用全局的用户名和邮箱,也就是对某个库指定其他的用户名和邮箱,把 –global去掉即可。

创建版本库

git init

进入你需要通过Git管理的目录下面,比如在我当前目录下面有一个目录test,我需要通过git来管理该test目录下面的所有文件,则

cd test
git init

这样在test目录下面的所有文件都通过git管理起来了,如果我们修改,删除该目录下的文件,git都可以跟踪到。这样就方便我们回到之前没有修改的文件了。此时在test目录下面还有一个隐藏目录.git,这个目录就是git用来管理Git库的,我们最好不要对该目录下面的文件进行修改,不然Git管理整个库就会发生混乱。

把文件添加到暂存区

这里需要进行一定的说明,git版本控制工具,当我们使用 git init建了一个版本控制库之后,git就把库分成了三个区,分别是工作区、暂存区和本地库,我们使用 git add file 将工作区的文件添加到暂存区,通过git commit -m “some message” 将我们暂存区的所有文件都提交到本地库中,下面是具体的使用。

此时我在test目录下面新建一个文件

echo "hello, world" > a.txt

使用git status来查看工作区的文件状态,显示如下

On branch master

No commits yet

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

        a.txt

nothing added to commit but untracked files present (use "git add" to track)

此时git提示我们a.txt文件没有被跟踪到,也就是说我们在a.txt中所做的任何修改,都无法通过git来进行管理,需要通过git来进行管理,就需要将该文件添加到暂存区。使用 git add a.txt

git add a.txt

此时再使用 git status来查看工作区的状态

On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   a.txt

此时显示在工作区中我们添加了一个新文件a.txt,但是没有提交到本地库中,此时我们突然后悔了,想把暂存区中的文件撤销,也是有办法的,那就是使用

git reset a.txt

此时位于暂存区中的文件a.txt就撤销了,使用 git status 显示工作区信息,如下

On branch master

No commits yet

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

        a.txt

nothing added to commit but untracked files present (use "git add" to track)

和上面刚开始新建文件时一样,提示没有跟踪文件,应该使用git add

如果我们修改一个文件之后,想要撤回刚刚修改的内容,应该使用 git add a.txt(先使用这个命令)来使得Git可以跟踪到a.txt,此时如果修改文件,git就是跟踪到我们的修改。

echo "god is a girl" >> a.txt
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   a.txt

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:   a.txt

上面的信息显示我们向文件a.txt添加了内容,也就是修改了文件a.txt,可以使用 git add 来把修改添加到暂存区,注意暂存区中的a.txt是没有进行修改的。也就是说我们对a.txt的修改只是在工作区中,在暂存区还是原来没有修改之前的。同时,因为Git跟踪到了我们的修改,但是在暂存区中没有,所以它提示我们可以使用 git checkout -- 来撤销我们在工作区中对a.txt的修改。

git checkout -- a.txt

此时我们cat下一a.txt就发现我们刚刚向文件中添加的内容没有了。

通过上面的介绍,这里再总结一下,git add 命令使得Git可以追踪我们的文件,其把文件的镜像放置到暂存区。然后当我们不想把文件放置到暂存区,也就是我们现在不想把我们的文件添加到本低库中时,可以使用该命令 git reset 。这时我们是把位于暂存区中的文件撤销,也就是说Git没有跟踪到file,我们重新使用 git add 让git跟踪到file,然后当我们修改文件后,这时的文件修改是位于暂存区的,如果我们撤销修改,可以使用 git checkout — 撤销我们的修改,这时位于工作区的文件就是修改之前的内容了。

以上的操作都是位于暂存区和工作区中,如果我们对整个文件都修改完毕并且确认后,这时可以提交到本地仓库。

git commit -m "some message"

这里的messge就是一些信息,当我们把文件提交到本地仓库后,需要对提交的文件进行一些说明,这样就便于我们知道该提交操作的具体事宜。

$git log
commit 41c3c4236d128170cad3d4d9702990df34402bb3 (HEAD -> master)
Author: dengxinlong <1552549826@qq.com>
Date:   Tue Dec 24 19:39:59 2019 +0800

    dxl: modified a.txt

使用git log 命令可以查看到我们所有提交到本地仓库的信息。关于该信息的详细信息,后面通过介绍完分支后再进行详细的说明。

时光穿梭

当我们把我们的文件通过git commit 提交到本地仓库后,这时我们又想起来文件需要再次修改,我们往a.txt文件中添加了一句话 talk is cheep, show me your code。

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:   a.txt

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

上面的信息告诉我们,我们对a.txt文件的修改没有通过commit来提交到本地仓库。

我们想要将修改后的a.txt文件提交到本地仓库中,但是想要知道我们修改了什么内容,进行再次确认。如下:

$git diff
diff --git a/a.txt b/a.txt
index 512f3e4..95343a7 100644
--- a/a.txt
+++ b/a.txt
@@ -1,3 +1,4 @@
 hello, world
 god is a girl
 god is a girl
+talk is cheep, show me you code

通过上面的 + 号可以知道,我们添加的就是这句话。

这时我们要提交到本地仓库,就是进行前面讲过的命令,git add, git commit

进行完git add a.txt后,我们通过 git status来查看一下仓库的当前状态.

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

        modified:   a.txt

上述信息告诉我们,可以通过git reset HEAD a.txt把刚刚存储在暂存区中的文件撤销。modified: a.txt 告诉我们,我们将要提交的文件时已经修改过好的a.txt,没错,这正是我们想要提交的,直接 git commit -m “some message”

然后我们在运行:

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

告诉我们工作区是干净的,没有什么新内容需要提交了,如果我们想要提交到远程仓库,可以直接提交,这后面会进行介绍。

上面的就是我们将修改过后的文件重新提交到本地仓库,和新建一个文件提交到本地仓库没什么区别(但是提交前最好使用 diff 查看一下修改过后的内容)。

这里我们再次对a.txt文件进行修改,然后commit,添加的内容为 “NVIDIA, F**K YOU”。这时候我们的a.txt在Git仓库中就有三个版本了。

通过git log可以查看我们的文件有几个版本。

$git log
commit 51dab7dafd005b116091720eea95b3907a2be9a2 (HEAD -> master)
Author: dengxinlong <1552549826@qq.com>
Date:   Tue Dec 24 20:13:54 2019 +0800

    dxl: add a words

commit ade3e154d096a5db780e397651ff2dd0ef1eaf90
Author: dengxinlong <1552549826@qq.com>
Date:   Tue Dec 24 20:06:16 2019 +0800

    dxl: add a words

commit 41c3c4236d128170cad3d4d9702990df34402bb3
Author: dengxinlong <1552549826@qq.com>
Date:   Tue Dec 24 19:39:59 2019 +0800

    dxl: modified a.txt

如果我们嫌这些信息过多,可以使用另外一个命令

$git log --pretty=oneline
51dab7dafd005b116091720eea95b3907a2be9a2 (HEAD -> master) dxl: add a words
ade3e154d096a5db780e397651ff2dd0ef1eaf90 dxl: add a words
41c3c4236d128170cad3d4d9702990df34402bb3 dxl: modified a.txt

上面的一窜字符,其实是用十六进制表示的commit id(版本号),Git就是通过commit id来管理不同的版本的。同时Git是一个分布式的版本控制系统,也就说有多个人在同一个仓库中对某些文件进行修改,为了区分,就使用commit id 来进行识别,其是用SHA1生成的一窜数字。

版本回退

当我们不想要当前最新的版本后,想使用上一次的版本,当前版本用HEAD指向,可以使用HEAD^(上一个版本), 上上个版本就是HEAD^^。

$ git reset --hard HEAD^

此时我们就回退到上一次的版本了,同时Git也将工作区中的文件改成了上一次版本的内容。

这时候我们使用git log

$git log
commit ade3e154d096a5db780e397651ff2dd0ef1eaf90 (HEAD -> master)
Author: dengxinlong <1552549826@qq.com>
Date:   Tue Dec 24 20:06:16 2019 +0800

    dxl: add a words

commit 41c3c4236d128170cad3d4d9702990df34402bb3
Author: dengxinlong <1552549826@qq.com>
Date:   Tue Dec 24 19:39:59 2019 +0800

    dxl: modified a.txt

发现最新的版本信息没有了,但这时候我们又想要最新版本的文件,怎么办,我们知道要使用某个版本,使用的是commit id,那就要想办法找到最新版本的commit id,我们可以手动往上翻,找到我们提交最新版本时出现的那个id,就是我们要的。

但是,我们关机了,想要使用最新的版本,找不到版本号,怎么办,没关系,可以使用git reflog

$git reflog
ade3e15 (HEAD -> master) HEAD@{0}: reset: moving to HEAD^
51dab7d HEAD@{1}: reset: moving to 51dab7d
ade3e15 (HEAD -> master) HEAD@{2}: reset: moving to HEAD^
51dab7d HEAD@{3}: commit: dxl: add a words
ade3e15 (HEAD -> master) HEAD@{4}: commit: dxl: add a words
41c3c42 HEAD@{5}: commit (initial): dxl: modified a.txt

git reflog 用于记录我们之前使用过的每一条命令(关于本地仓库)。

回顾

这里回顾一下,如果我们想要从当前的版本回退到历史版本,使用git log 获知我们想要回退的版本,使用git reset --hard commit-id(或者HEAD^, HEAD^^)。这时候想要回到最新的版本,就是通过git reflog 来获知我们使用过的命令来知道最新版本的commit-id。通过上面所说的可以知道,我们想要回退到某个版本,就是先要想办法知道版本号。这里涉及到Git的一些内部机制,就不赘述了,感兴趣的可以自行了解。

管理修改

Git版本控制其实管理的是修改,在我们的库中,添加一个文件也是修改,修改一个文件也是对库进行了修改。

这里我们再对a.txt文件进行修改,然后 add,然后 status,发现git提示我们将要提交已经修改的文件a.txt,我们先不 commit;再次修改文件a.txt,然后commit, 然后status,发现Git仍然提示我们修改的文件没有提交,这是因为第二次修改的文件没有添加到暂存区,commit提交的只是暂存区的文件。使用 git diff a.txt(比较暂存区文件和工作区文件的差别),发现有 + 号。同时我们使用 git diff HEAD -- a.txt(比较工作区和库中文件的区别),发现也提示新添加的内容。始终记住,commit是将暂存区中的文件提交的本地仓库中,add 将工作区的文件添加到暂存区中。同时,commit 一次性将暂存区中的文件全部提交到本地仓库中。

前面讲到的git checkout -- a.txt,其实是将暂存区中的文件和工作区中的向比较,如果不一样,就将工作区文件替换成暂存区文件。所以我们在使用checkout时需要注意,我们先往a.txt中添加了一些内容,没有添加到暂存区中,第二天又添加内容,但想要使用通过checkout删除刚刚添加的内容,这时是使用暂存区的文件替换掉工作区的文件,可能并不是修改之前需要的内容,这里肯定不是,因为之前修改的文件没有添加到暂存区中。

删除文件

我们新建一个文件b.txt,然后add, commit提交到本地仓库,然后发现b.txt文件我们不想提交到本地仓库,但是提交了。我们可以先手动删除b.txt rm -fr b.txt,然后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:    b.txt

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

提示我们修改也就是删除文件b.txt没有提交到本地仓库,这时我们使用git rm b.txt,将暂存区中的b.txt删除,这时再commit提交,然后status,发现没有提示需要提交的文件了。

如果我们想要恢复b.txt文件,我们知道使用git checkout — b.txt是可以恢复的;但是我们使用git rm b.txt删除该文件后,使用checkout会现在暂存区中查找该文件,发现没有,然后再本地库中查找发现没有,恢复失败。要想恢复怎么办,有办法,直接切换到历史版本就行,就是通过git reset –hard commit-id 返回到历史版本就行了。

远程仓库

如果我们想要把我们的代码通过git提交到远程仓库,这时候我们直接使用github的仓库,这里假设你已经有了一个github账户,如果我们想要将代码提交到github中,由于github仓库和本地仓库之间传输数据是通过ssh加密的。所以需要我们先生成一个密钥对。如果在你的家目录下面已经有了,就不需要生成了,如果没有,就使用ssh-keygen -t rsa。这时候,我们,登录到github中,在seting->SSH and GPG keys中添加pub_keys

为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。

当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。

推送到远程仓库

要将本地仓库 push到远程仓库,我们需要先在github中新建一个仓库,一路默认就行,然后

git remote add origin git@github.com:dengxinlong/pratice_git.git``
git push -u origin master

由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

当本地仓库中的文件重新修改后,需要提交到远程仓库,使用git push origin master

关于从github中拷贝一个仓库就不介绍了,这直接操作就是。

分支管理

Git强大的功能莫过于分支管理。之前的操作都是在主分支(master)中进行的,但是,当我们被分派一个任务之后,是需要创建一个分支,然后在该分支上修改内容的。这时候的修改提交都不会影响master,除非把分支和master合并。当你认为你的工作做完了,可以把分支进行合并,然后删除刚刚创建的分支。

创建分支

git checkout -b dev

这里就是创建dev分支,同时,切换到dev分支进行工作,相当于下面这两条命令

git branch dev                  //创建新分支dev
git checkout dev                //切换到dev分支

git branch命令可以知道你当前有多少分支,同时*指示你当前在哪个分支工作。

$git branch
* dev
  master

这时候我们往a.txt文件中新增加内容,然后add, commit,然后切换会master分支git checkout master, 这时候在显示一下a.txt的内容,发现和没修改之前是一样的,这时因为我们的修改是在dev分支中的,此时没有把dev分支和master分支进行合并。这时如果你认为你在dev分支的工作做完了,切换回master分支,然后合并分支git merge dev,该命令就是合并指定分支dev到当前分支中,然后cat a.txt发现内容是修改完的内容,然后我们如果认为在中的dev工作全部做完了,就可以删除dev分支了,git branch -d dev

切换分支

git checkout 分支

显示分支信息

git bracnch

合并分支

git merge 分支 //合并分支到当前的分支

删除分支

git branch -d 分支

上面的一段文字已经对这些命令的使用进行了说明,就不再进行解释了。

之前介绍了撤销修改命令,git checkout -- <file>,这和切换分支和创建分支并切换有点容易搞乱,所以这里推荐其他更容易理解的命令。

创建并切换分支

git switch -c 分支

切换分支

git switch 分支

在Ubuntu18.04通过apt方式安装的git无法使用git switch命令,需要注意。

合并冲突

之前我们删除了dev分支,现在我们git checkout -b dev重新创建一个分支,然后修改a.txt,然后git add, git commit,这时候我们在切换会master分支中git checkout master,然后修改a.txt文件,git add, git commit。现在master分支和dev分支中分别有了各自的提交,变成了下面这个样子:
《Git使用教程》

这时候我们想要合并git merge dev

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

Git告诉我们合并产生冲突,这是可以理解的,我们的a.txt文件相当于有两个不同版本,我们想要把这两个不同的版本进行合并,这时候Git是不知道我们究竟想要哪个版本,所以需要我们自行决定我们想要哪个版本。也就是在master或dev中修改文件,然后再add, commit,就可以了。

其实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:   a.txt

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

我们再查看一下a.txt文件的内容

$cat a.txt
hello, world
god is a girl
god is a girl
talk is cheep, show me you code
I love me
I love you
<<<<<<< HEAD
I love dengxinlong
=======
I love xinlong
>>>>>>> dev

<<<<<<<< ========= >>>>>>>>>> 标记出不同的分支,HEAD指代的就是当前分支了,dev就是我们新创建的分支。我们手动解决好冲突,然后add, commit,这时候就是这个样子了:
《Git使用教程》

我们通过带参数的git log也可以看出来

$git log --graph --pretty=oneline --abbrev-commit
*   ce3d54e (HEAD -> master) conflicts fix
|\  
| * a81ca88 dev: add some words
* | 2141926 master: add some words
|/  
* ca04eb4 dev: add I love you
* a7e48f1 (origin/master) deltet b.txt----
* 0396473 add b.txt --
* b6b45b2 delete: b.txt --
* 32efd00 add b.txt
* 6ddb4b4 delete: b.txt
* 0e596cc add b.txt
* 38012db add I love me
* ade3e15 dxl: add a words
* 41c3c42 dxl: modified a.txt

上面的命令中 --graph才是真正能显示分支情况的,--pretty=oneline使得显示的信息少一点, --abbrev-commit使得现实的commit-id短一点。

这时候我们认为我们的在dev分支中的工作完成了,可以删除dev分支了,则git branch -d dev即可。

分支管理策略

之前我们合并分支是通过fast-forward方式的,这合并方式非常简单和快速,其就是使得master指向dev分支;然后我们删除dev分支,此时我们通过git logg --graph --pretty=oneline --abbrev-commit,我们是看不到我们合并信息的,也就是说这种合并方式会丢失合并信息,有时候这不是我们想要的效果。

这时候我们合并就采用普通方式。

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

然后我们通过git log --graph --pretty=oneline --abbrev-commit来查看分支信息。

大概的样子如下:
《Git使用教程》

*   72ff6c7 (HEAD -> master) merge with no-ff
|\  
| * fa20ad5 (dev) dev: add I love China
|/  
*   ce3d54e conflicts fix
|\  
| * a81ca88 dev: add some words
* | 2141926 master: add some words
|/  
* ca04eb4 dev: add I love you
* a7e48f1 (origin/master) deltet b.txt----
* 0396473 add b.txt --
* b6b45b2 delete: b.txt --
* 32efd00 add b.txt
* 6ddb4b4 delete: b.txt
* 0e596cc add b.txt

说明,在合并分支之前,我创建一个新分支dev,并且往a.txt文件中添加了I love China,然后提交,这时候采用普通方式合并分支,因为这种合并方式会创建一个commit,所以需要加上-m选项。然后通过带参数的git log 可以查看分支合并信息。如果我们通过fast-forward方式合并,删除分支后,通过带参数的git log,如下:

$ git log --graph --pretty=oneline --abbrev-commit
* 4d0f231 (HEAD -> master) dev: add some words
*   72ff6c7 merge with no-ff
|\  
| * fa20ad5 dev: add I love China
|/  
*   ce3d54e conflicts fix
|\  
| * a81ca88 dev: add some words
* | 2141926 master: add some words
|/  
* ca04eb4 dev: add I love you
* a7e48f1 (origin/master) deltet b.txt----
* 0396473 add b.txt --
* b6b45b2 delete: b.txt --
* 32efd00 add b.txt
* 6ddb4b4 delete: b.txt

此时是看不到合并信息的。

分支策略

在实际开发中,我们应该按照几个基本原则进行分支管理:

首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;

那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;

你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。

所以,团队合作的分支看起来就像这样:
《Git使用教程》

bug分支

有这样一种常见的情形,此时你在dev分支中写代码。但是在master分支的项目中突然发现了bug,要及时修复。此时你必须放弃手中事情去修复bug。如下:

xinlongdeng@ubuntu:~/Git_test$ echo "I am 6666666666666666666666666" >> a.txt 
xinlongdeng@ubuntu:~/Git_test$ ls
a.txt  b.txt  c.txt
xinlongdeng@ubuntu:~/Git_test$ echo "666666666666666" > d.txt
xinlongdeng@ubuntu:~/Git_test$ git add d.txt 
xinlongdeng@ubuntu:~/Git_test$ ls
a.txt  b.txt  c.txt  d.txt
xinlongdeng@ubuntu:~/Git_test$ ls
a.txt  b.txt  c.txt  d.txt
xinlongdeng@ubuntu:~/Git_test$ git status
On branch dev
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   d.txt

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:   a.txt

此时我修改了a.txt文件,同时增加了一个d.txt文件,然后我的工作没有完成,不想把这些修改commit,怎么办。使用git stash可以把这些修改暂时存储起来。不用git stash命令是不能切换分支的,因为你的修改没有commit。然后切换到master分支中,创建一个新分支issue-101git checkout -b issue-101,然后修改bug,修改完了之后add,commit,回到master分支中进行合并:

xinlongdeng@ubuntu:~/Git_test$ git add a.txt 
xinlongdeng@ubuntu:~/Git_test$ git commit -m "fixed conflict"
[issue-101 6003ff5] fixed conflict
 1 file changed, 1 insertion(+), 1 deletion(-)
xinlongdeng@ubuntu:~/Git_test$ ls
a.txt  b.txt  c.txt
xinlongdeng@ubuntu:~/Git_test$ git branch
  dev
* issue-101
  master
xinlongdeng@ubuntu:~/Git_test$ ls
a.txt  b.txt  c.txt
xinlongdeng@ubuntu:~/Git_test$ 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)
xinlongdeng@ubuntu:~/Git_test$ git merge --no-ff -m "merge fixed bug" issue-101 
Merge made by the 'recursive' strategy.
 a.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

然后我们回到dev分支继续之前的工作,但是我们dev是从master分支中来的,此时的dev分支中也存在和之前master中同样的bug,可以选择手动重复修改,但这样就愚蠢了。可以使用git cherry-pick commit-id这里的commit-id就是我们在commit issue-101分支时生成的id,然后dev分支中的bug也同样修复了:

inlongdeng@ubuntu:~/Git_test$ git cherry-pick 6003ff5
[dev 2850700] fixed conflict
 Date: Wed Dec 25 19:57:38 2019 +0800
 1 file changed, 1 insertion(+), 1 deletion(-)

我们只需要把修复bug时的这个提交所做的修改“复制”到dev分支。注意:我们只想复制修改bug时的这个提交所做的修改,并不是把整个master分支merge过来。

为了方便操作,Git专门提供了一个cherry-pick命令,让我们能复制一个特定的提交到当前分支:

xinlongdeng@ubuntu:~/Git_test$ git cherry-pick 6003ff5
[dev 2850700] fixed conflict
 Date: Wed Dec 25 19:57:38 2019 +0800
 1 file changed, 1 insertion(+), 1 deletion(-)

然后我们使用git stash pop来恢复之前的工作:

$ git stash pop
Auto-merging a.txt
On branch dev
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   d.txt

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:   a.txt

Dropped refs/stash@{0} (ea675346fb6e490a06bd3da8ffa1851b0cb469d0)

恢复现场时也可以使用git stash apply stash@{0},但是使用这个命令不会把stash中的内容删除,所以需要使用git stash drop stash@{0}来删除。使用git stash list查看stash中我们stash了多少次内容,stash可以使用多次,相当于一个栈一样。

推送分支

之前我们把本地仓库的内容推送到github中,其实是将本地仓库的master推送的githubgit push origin master

如果我们要将其他分支dev推送到github呢,使用git push origin dev

origin就是表示远程库的意思,也可以使用其他名字,origin就将本地库和远程库关联起来了,如果想要将本地库关联到不同的远程库,在关联时使用不同的远程库名字即可。

git remote查看当前有那么关联的远程库

git remote -v可以看到更加详细的信息

设想一下这种情形,Git是用于多人合作的版本控制系统,这时你的小伙伴从github仓库中拷贝了一份代码git clone 链接,这时他只看到master分支

标签管理

Git的便签创建非常简单,标签总是和某个commit挂钩,也就是说,如果我们在master的某个commit打上tag,同时这个commit也在dev中,那么这个tag也会出现在dev中。

我们要给某个commit打上标签,首先切换到需要打上标签的分支上.

git tag 标签号给当前的commit打上标签

使用git tag可以查看当前的所有便签

使用git show 标签可以查看标签的信息

如果我们要想给某个之前的commit打上标签,则git tag 标签名 commit-id

同时,我们也可以给某个标签加上说明.

git tag -a 标签名 -m "说明" commit-id

使用git show 标签名

$ git show v0.3
tag v0.3
Tagger: dengxinlong <1552549826@qq.com>
Date:   Wed Dec 25 16:45:24 2019 +0800

release v0.3

commit 80a4607933a16ecdf1c47e0677bd60a7a222a016 (tag: v0.3)
Merge: 914d4da 89ffd18
Author: dengxinlong <1552549826@qq.com>
Date:   Wed Dec 25 15:53:34 2019 +0800

    complish some work

删除标签也简单git tag -d <tagname>

将标签push到远程

标签是只在本地出现的东西,如果想要将标签push到远程库中。
git push origin <tagname>

git push origin --tags一次性推送全部尚未推送到远程的本地标签

如果我们要删除远程库中的某个标签,操作有点麻烦。
先在本地删除标签
git tag -d v0.9

然后,从远程删除。删除命令也是push,但是格式如下:
git push origin :refs/tags/v0.9

远程管理

之前我们介绍远程库的时候是直接将我们的代码git push origin master,其实是将master分支push到github中,其中origin就是使得本地仓库和github远程仓库相关联,如果我们想要把本地库关联到不同的远程库中,在关联的时候使用不同 的远程库名字即可,就是不要使用origin作为远程库名字。

把其他分支dev分支push到github中 git push origin dev

git remote 查看远程库

git remote -v 详细查看远程库

设想一下这种情形,小明从github中拷贝了一份仓库,同时他也可以把他的代码push到这个远程库中,此时他只能看到master分支。使用git checkout dev origin/dev创建dev分支同时和origin/dev关联,这时候他就能在dev分支中进行操作了,不用在master分支中操作。此时他完成了他的工作,然后git push origin dev

然后你也在你本地的dev分支中修改了代码,然后add,commit,push。

推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送

git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接

这回git pull成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,提交,再push:

点赞
  1. 匿名说道:

    :arrow:

  2. 匿名说道:

    :eek:

  3. 匿名说道:

    :cry:

发表评论

电子邮件地址不会被公开。