0 文章背景

Git在其版本2.23后又引入了git switchgit rerstore,同时Git命令的使用在实际工作过程中不可缺少,因此博主本人自己花了一天时间从头复习并深入了Git的使用过程并撰写了这篇文章,也希望帮助到各位一天掌握Git。
本文主要参考了廖雪峰的Git教程,简化了其中简单的Git命令,同时额外详细描述了git mergegit rebase等重点Git命令的使用方式以及原理。

1 安装Git

如果你正在使用Mac做开发,有两种安装Git的方法。

一是安装homebrew,然后通过homebrew安装Git,具体方法请参考homebrew的文档:http://brew.sh/。

安装完成后,还需要最后一步设置,在命令行输入:

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

因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址。你也许会担心,如果有人故意冒充别人怎么办?这个不必担心,首先我们相信大家都是善良无知的群众,其次,真的有冒充的也是有办法可查的。

注意git config命令的--global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址。

2 创建版本库

创建一个Git仓库的文件夹:

$ mkdir learngit
$ cd learngit
$ pwd
/Users/michael/learngit

初始化Git仓库:

$ git init

把文件添加到版本库:

$ git add readme.txt
$ git commit -m "wrote a readme file"

3 时光机穿梭

$ git status
//git diff将暂存区的版本跟工作区的版本进行对比
$ git diff readme.txt

git diff跟不同的参数,比较不同的区间的版本。

  1. git diff:是查看working tree与stage的差别的。
  2. git diff --cached:是查看stage与repository的差别的。
  3. git diff HEAD:是查看working tree和repository的差别的。其中:HEAD代表的是最近的一次commit的信息。

3.1 版本回退

$ git add readme.txt
$ git commit -m "append GPL"
$ git log
$ git log --pretty=online

在Git中用HEAD表示当前版本,也就是最新的提交1094adb...,上一个版本就是HEAD,上上一个版本就是HEAD^,上100个版本可以写成HEAD~100。

$ git reset --hard HEAD^
HEAD is now at e475afc add distributed
$ git reset --hard 1094a
$ git reflog

git log查看提交历史,git reflog查看命令历史。

3.2 工作区和暂存区

3.3 管理修改

3.4 撤销修改

操作 Git V2.23- Git 2.23+
从unstaged恢复到worktree git checkout – <file> git restore <file>
从staged恢复到unstaged git reset – <file> git restore --staged <file>
从staged恢复到worktree git checkout --HEAD <commit_id>或者git checkout --HEAD <commit_id> git restore --staged --worktree <file>
从当前提交返回到上一个提交 git checkout --HEAD <commit_id>或者git checkout --HEAD <commit_id> git checkout --HEAD <commit_id>或者git checkout --HEAD <commit_id>
$ git checkout -- readme.txt
$ git restore readme.txt
$ git restore .
$ git reset HEAD readme.txt
$ git restore --staged readme.txt
$ git restore --staged .

$ git reset HEAD readme.txt是撤销添加到暂存区中对该文件的修改,工作区的修改不会被撤销。而$ git reset --hard HEAD便是撤销所有工作区和暂存区的修改。

3.5 删除文件

$ git rm test.txt

git rm <file>是从工作区中删除<file>文件,并在暂存区中记录该文件已改变(内容改变、文件新建或删除)的动作,即其等价于:

$ rm fileName.txt
$ git add fileName.txt

4 远程仓库

4.1 添加远程库

//关联一个远程库
$ git remote add origin git@github.com:jed/learngit.git
//使用命令第一次推送master分支的所有内容
$ git push -u origin master
//此后,每次本地提交后想提交到远程仓库可使用下面的命令提交最新修改
$ git push origin master

4.2 从远程库克隆

//从远程仓库克隆了一个本地库
$ git clone git@github.com:jed/gitskills.git

Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。

5 分支管理

操作 Git V2.23- Git V2.23+
查看所有分支 git branch git branch
创建分支 git branch <branch> git branch <branch>
切换分支 git checkout <branch> git switch <branch>
新建并切换分支 git checkout -b <branch> git switch -c <branch>
切换到commit_id git checkout <commit_id> git checkout <commit_id>

5.1 创建与合并分支

HEAD指向分支,而master才指向master分支的提交,并且HEAD指向的就是当前分支。

当Git创建新分支时,例如一个dev分支,Git则新建一个指针指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上。

//创建并切换分支
$ git checkout -b dev
switched to a new branch 'dev'
//git checkout -b dev等价于下面的命令
//创建分支
$ git branch dev
//切换分支
$ git checkout dev
Switched to branch 'dev'
//用git branch命令查看当前所有分支
$ git branch
* devmaster

git branch命令会列出所有分支,当前分支前面会标一个*号,然后,我们就可以在dev分支上正常提交。

$ git add readme.txt
$ git commit -m "branch test"
//把dev分支的工作成果合并到master分支上,且此次合并是快速合并
$ git merge dev
//合并后可删除dev分支
$ git branch -d dev

注意:git merge会把两个分支最新提交以及两者最近的共同祖先进行三方合并,合并的结果是生成一个新的提交。在master分支执行git merge dev命令,与在dev分支执行git merge master命令,这两个命令的执行效果是不相同的。

Git新版本的切换分支命令为git switch:

//撤销修改命令
$ git checkout -- <file>
//新版本撤销修改命令
$ git restore <file>
//创建分支
$ git branch <branch>
//切换分支命令
$ git checkout <branch>
//新版本切换分支命令
$ git switch <branch>
//创建并切换分支
$ git checkout -b <branch>
//新版本创建并切换分支命令
$ git switch -c <branch>

5.2 解决冲突

准备新分支feature1,继续新分支的开发:

$ git switch -c feature1
Switched to a new branch `feature1`
$ 修改feature1分支此时的工作区文件readme.txt
//在feature1分支上提交:
$ git add readme.txt
$ git commit  -m "and simple"
//切换到master分支
$ git switch master
$ 修改master分支此时的工作区文件readme.txt
//在master分支上提交:
$ git add readme.txt
$ git commit -m "& simple"

这种情况下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告诉我们,readme.txt文件存在冲突,必须手动解决冲突后再提交。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.txtno changes added to commit (use "git add" and/or "git commit -a")

我们可以直接查看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 add readme.txt
$ git commit -m "conflict fixed"
[master cf810e4] conflict fixed

用带参数的git log也可以看到分支的合并情况:

$ git log --graph --pretty=oneline --abbrev-commit
*   cf810e4 (HEAD -> master) conflict fixed
|\
| * 14096d0 (feature1) AND simple
* | 5dc6824 & simple
|/
* b17d20e branch test
* d46f35e (origin/master) remove test.txt
* b84166e add test.txt
* 519219b git tracks changes
* e43a48b understand how stage works
* 1094adb append GPL
* e475afc add distributed
* eaadf4e wrote a readme file

最后,删除feature1分支:

$ git branch -d feature1
Deleted branch feature1 (was 14096d0).

工作完成。

5.3 分支管理策略

合并分支时,Git会尽可能用Fast Forward模式,但这种模式下,删除分支后会丢失分支信息,如果要强制禁用Fast Forward模式,Git就会merge时生成一个新的commit,这样从分支历史就可以看出分支信息。。,下面来实战一下==no-ff方式的git merge

//首先创建并切换dev分支
$ git switch -c dev
$ 修改readme.txt文件,并提交一个新的commit
$ git add .
$ git commit -m "add merge"
//切换回master
$ git switch master
//禁用快速合并模式的合并,本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去
$ git merge --no-ff -m "merge with no-ff" dev
//合并后用git log查看分支历史:
$ git log --graph --pretty=oneline --abbrev-commit
*   e1e9c68 (HEAD -> master) merge with no-ff
|\
| * f52c633 (dev) add merge
|/
*   cf810e4 conflict fixed
...

–no–ff 模式其实就是相当于master指针new了一个跟dev指针一样的空间并且放了相同的内容然后指向这个空间。而原来的快速模式,就是简单将master指针指向dev指针指向的内容而已,并没有自己创造空间。

5.4 Bug分支

在Git中每个Bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。

当你接到一个修复一个代号101的Bug的任务时,可以创建一个分支issue-101来修复它,但是如果当前正在dev分支上进行的工作还未提交,因为工作只做到一半无法提交则可以用git stash命令将当前工作现场储藏起来,等以后恢复现场后继续工作:

$ git bash
Saved working directory and index state WIP on dev: f52c633 add merge

git stash不能将未被追踪的文件(untracked file)压栈,也就是从未被git add过的文件,也就是你在使用git status命令看到的提示Untracked files所列出的文件,所以在git stash之前一定要用git status确认没有Untracked files

现在,用git status查看工作区,就是干净的(除非有未被Git管理的文件),因此可放心创建分支来修复Bug。

先确定在哪个分支修复Bug,加入需要在master分支上修复,就从master创建临时分支:

$ git checkout master
//创建并切换到issue-101分支
$ git switch -c issue-101
$ 修复Bug涉及的文件
$ git add .
$ git commit -m "修复Bug-101"
$ git merge --no-ff -m "合并Bug-101" issue-101
//修复完Bug,切换回dev分支工作
$ git switch dev
Switched to branch 'dev'
$ git status
On branch dev
nothing to commit, working tree clean
//工作区是干净的,用`git stash list`命令查看:
$ git stash list
stach@{0}: WIP on dev: f52c633 and merge

我们发现用git stash存储的工作现场还存在,如果想要恢复有两个方法:

  1. git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除。
  2. git stash pop恢复工作现场的同时把stash内容也删了。
$ git stash pop
On branch dev
Changes to be committed:(use "git reset HEAD <file>..." to unstage)new file:   hello.pyChanges 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.txtDropped refs/stash@{0} (5d677e2ee266f39ea296182fb2354265b91b3b2a)

再用git stash list查看,就看不到任何stash内容了。

可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:

$ git stash apply stash@{0}

在master分支上修复bug后,仔细一想dev分支是早期从master分支分出来的,所以这个bug其实在当前dev分支上也存在。

要想修复dev分支上同样的Bug,我们只要把4c805e2 fix bug 101这个提交所做的修改“复制”到dev分支。注意:我们只想复制4c805e2 fix bug 101这个提交所做的修改,并不是把整个master分支merge过来。为了方便操作,Git专门提供了一个git cherry-pick命令,让我们能复制一个特定的提交到当前分支:

$ git branch
* devmaster
$ git cherry-pick 4c805e2
[master 1d4b803] fix bug 1011 file changed, 1 insertion(+), 1 deletion(-)

Git自动给dev分支做了一次提交,注意这次提交的commit是1d4b803,它并不同于master和issue-101合并后的提交4c805e2,因为这两个commit只是改动内容相同,但确实是两个不同的commit。用git cherry-pick,我们就不需要在dev分支上手动再把修bug的过程重复一遍。

git cherry-pick <commitHash>将指定的提交应用于当前分支,它也会跟git merge一样产生冲突,其解决冲突的方法跟git merge解决冲突的方法一样:想在文件中解决冲突,再用 git add <fileName>对修正后的文件做标记,然后用 ‘git commit’ 将修改动作提交到本地仓库。

5.5 Feature分支

添加一个新功能时,肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。

接到了一个新任务,即开发代号为Vulcan的新功能:

$ git switch -c frature-vulcan
//开发完毕后
$ git add .
$ git commit -m "add feature vulcan"

但是现在这个需求废弃了,需要删除掉:

//在vulcan分支中删除vulcan分支
$ git branch -d vulcan
error: 无法删除检出于 '/Users/didi/AndroidStudioProjects/MyDemo' 的分支 'vulcan'。
//切换分支到master中
$ git switch master
//在master分支中删除vulcan分支
$ git branch -d vulcan
error: 分支 'vulcan' 没有完全合并。
如果您确认要删除它,执行 'git branch -D vulcan'
$ git branch -D vulcan
已删除分支 vulcan(曾为 58bd560)。

5.6 多人协作

当从远程仓库克隆时,实际上Git自动建立本地仓库master分支与远程仓库master分支的跟踪,并且远程仓库的默认名称是origin。

要查看远程仓库的信息用命令git remote

$ git remote
origin

其中用git remote -v显示更详细的信息:

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

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

5.6.1 推送分支

推送分支就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样Git就会把该分支推送到远程库对应的远程分支上:

//下述命令的origin是指远程仓库,master是要推送的本地分支,因为如果本地仓库master分支与远程仓库master分支建立了跟踪,那他两分支名都一样的,所以这行命令中只指定了本地分支的名字,而没有指定远程分支的名字
$ git push origin master
//如果想要推送其他本地分支,甚至该分支并不存在于远程仓库,例如dev
$ git push origin dev

git push --set-upstream origin featured等价于git push origin featured吗?

并不是一定要把本地分支往远程推送,那么哪些分支需要推送,而哪些分支不需要推送呢:

  1. master分支是主分支,因此要时刻与远程同步。
  2. dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步。
  3. bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周修复了几个bug。
  4. feature分支是否推送到远程仓库,取决于是否与其他团队成员合作开发。

5.6.2 抓取分支

多人协作时,大家都会往master和dev分支上推送各自的修改。

现在模拟一个团队成员在另一个目录下克隆该项目:

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

当从远程仓库克隆项目后,默认情况下该团队成员只能看到本地的master分支:

$ git branch
* master

现在,该团队成员要在dev分支开发, 则要建立远程仓库的dev分支与本地仓库dev分支的跟踪关系:

git checkout -b dev origin/dev

现在,该团队成员可以在dev分支上继续修改,然后时不时把dev分支推送到远程仓库:

$ 修改env.txt文件
$ git add env.txt
$ git commit -m "add env"
$ git push origin dev
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 308 bytes | 308.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:jed/learngit.gitf52c633..7a5e5dd  dev -> dev

而我同时在dev分支上对同一文件的同一处代码进行了修改,再试图推送到远程仓库:

$ 修改env.txt文件
$ git add env.txt
$ git commit -m "add env"
$ git push origin dev
To github.com:jed/learngit.git! [rejected]        dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@github.com:jed/learngit.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

推送失败,因为该团队成员的最新提交和我试图推送的提交有冲突,解决方法便是先用git pull把最新的提交从origin/dev抓下来,然后在本地合并解决冲突再推送:

$ git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.git pull <remote> <branch>If you wish to set tracking information for this branch you can do so with:git branch --set-upstream-to=origin/<branch> dev

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

$ git branch --set-upstream-to=origin/dev dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.

再pull:

$ git pull
Auto-merging env.txt
CONFLICT (add/add): Merge conflict in env.txt
Automatic merge failed; fix conflicts and then commit the result.

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

$ git commit -m "fix env conflict"
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 621 bytes | 621.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To github.com:jed/learngit.git7a5e5dd..57c53ab  dev -> dev

5.6.3 多人协作的工作模式总结

因此,多人协作的工作模式通常是这样:

  1. 首先,可以试图用git push origin <branch-name>推送自己的修改;
  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
  3. 如果合并有冲突,则解决冲突,并在本地提交;
  4. 没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!

如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>

这就是多人协作的工作模式,一旦熟悉了,就非常简单。

5.7 Rebase

5.7.1 git rebase原理

$ git rebase <topic-branch>

git rebase的原理是首先找到这两个分支(即当前分支experiment、变基操作的目标基底分支master)的最近共同祖先提交,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底分支master最新提交,最后以此将之前另存为临时文件的修改依序应用。

git rebase完成后可以切换到master分支进行一次快进合并,而这种合并方式与git merge没有任何区别,但是变基使得提交历史更加整洁。

一般我们这样做的目的是为了确保在向远程分支推送时能保持提交历史的整洁——例如向某个其他人维护的项目贡献代码时。 在这种情况下,你首先在自己的分支里进行开发,当开发完成时你需要先将你的代码变基到 origin/master 上,然后再向主项目提交修改。 这样的话,该项目的维护者就不再需要进行整合工作,只需要快进合并便可。

5.7.2 git rebase实例

假设现在基于远程仓库origin的origin分支,该分支已有C1、C2两个提交,接着创建了一个叫mywork的分支:

$ git checkout -b mywork origin

现在另一个团队成员在origin分支上做一些修改,生成两个commit提交,即C3和C4:

$ vi file.txt
$ git add .
$ git commit -m "第一次commit"
$ vi file2.txt
$ git add .
$ git commit -m "第二次commit"

与此同时,我们在mywork分支做一些修改,生成两个commit提交,即C5和C6:

$ vi file.txt
$ git add .
$ git commit -m "第一次commit"
$ vi file2.txt
$ git add .
$ git commit -m "第二次commit"

此时,我们可在mywork分支使用git pull命令把origin分支上的修改拉下来并且跟我们的修改合并,最后生成一个新的提交C7。

但是,如果我们想让mywork分支历史看起来像没有经过任何合并一样,也可以用git rebase

$ git checkout mywork
$ git rebase origin

这些命令会把你的mywork分支里的每个提交取消掉,并且把他们临时保存为补丁(这些补丁放到.git/rebase目录中),然后把mywork分支更新到最新的origin分支,最后把保存的这些补丁应用到mywork分支上。

当补丁被应用后,mywork分支的HEAD指针会指向新创建的提交C5’和C6’,而那些老的提交(C5和C6)会被丢弃。如果运行垃圾收集命令(pruning garbage collection),这些丢弃的提价就会删除。

在rebase过程中也许会出现冲突,Git则会停止rebase并让我们去解决冲突,解决冲突后用git add命令去更新这些内容的索引,然后无需执行git commit(在git rebase时git commit不等价于git rebase --continue),只需执行git rebase --continue,这样git会继续rebase,根据要rebase的提交次数,git rebase --continue要执行相同的rebase的提交次数。

任何时候可以用git reabse --abort 终止rebase操作,并且mywork分支会回到rebase开始前的状态。

如果想让master分支跟进到dev分支最新的提交,可直接使用git merge命令快速模式合并,即让master分支的HEAD指针直接指向dev分支最新的提交。

5.7.3 git rebase风险

git rebase要遵循一条准则:

如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。

变基操作的实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交。如果你已经将体积哦啊推送到远程仓库,而且他人也已经从该仓库拉取提交并进行了后续工作,此时如果你用git rebase命令重新整理了提交并再次推送,你的同伴因此将不得不再次将他们手头的工作与你的提交进行整合,如果接下你还要拉取并整合他们修改过的提交,情况会变得很糟糕。

6 标签管理

发布一个版本时,我们通常现在版本库中打一个标签Tag,这样就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。

6.1 创建标签

在Git中打标签非常简单,首先切换到要打标签的分支上:

$ git bash
* devmaster
$ git checkout master
Switched to branch 'master'

然后,敲命令git tag <name>就可以打一个新标签:

$ git tag V1.0

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

$ git tag
V1.0

默认标签是搭载最新提交的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
5dc6824 & simple
14096d0 AND simple
b17d20e branch test
d46f35e remove test.txt
b84166e add test.txt
519219b git tracks changes
e43a48b understand how stage works
1094adb append GPL
e475afc add distributed
eaadf4e wrote a readme file

比如说要对add merge这次提交打标签,它对应的commit_id是f52c633,敲入命令:

$ git tag V0.9 f52c633

再用命令git tag查看标签:

$ git tag
v0.9
v1.0

注意,标签不是按时间顺序列出,而是按字母排序的,可以用git show <tagname>查看标签信息:

$ git show v0.9
commit f52c63349bc3c1593499807e5c8e972b82c8f286 (tag: v0.9)
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Fri May 18 21:56:54 2018 +0800add mergediff --git a/readme.txt b/readme.txt
...

可以看到,v0.9确实打在add merge这次提交上,还可以创建带有说明的标签,用-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 <askxuefeng@gmail.com>
Date:   Fri May 18 22:48:43 2018 +0800version 0.1 releasedcommit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (tag: v0.1)
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Fri May 18 21:06:15 2018 +0800append GPLdiff --git a/readme.txt b/readme.txt
...

注意:标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签。

6.2 操作标签

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

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

因为创建的标签斗志存储在本地,不会自动推送到远程仓库,所以,打错的标签可以在本地安全删除。

如果想要推送某个标签到远程仓库,使用命令git push origin <tagname>

$ git push origin v1.0

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

$ git push origin --tags

如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:

$ git tag -d 0.9

然后从远程仓库删除,删除命令也是push,但是格式如下:

$ git push origin :refs/tags/v0.9

要看看是否真的从远程库删除了标签,可以登陆GitHub查看。

本文参考文献:

Git教程

Git新命令switch和restore

3.6 Git 分支 - 变基

git rebase命令

2021年最新版Git一天入门教程相关推荐

  1. 【2023年最新版】渗透测试入门教程,手把手带你进阶渗透测试工程师,学完即可就业

    前言 学习网络渗透技术是一件靠兴趣驱动的事情,只有强烈热爱一件事才能持之以恒的去做,对于那些三分钟热度的人来说还是劝你放弃吧,因为网络渗透技术自学需要很多方面的知识,没耐心是无法学会的. 当然除了有想 ...

  2. Git和SourceTree入门教程

    转自CSDN:http://blog.csdn.net/collonn/article/details/39259227 -->本教程适用于主流的开源网站github和bitbucket,个人认 ...

  3. 【Git】最新版Git 详细安装配置教程

    软件下载 git官方:https://git-scm.com/ 下载对应的版本 下载慢的话就可以去找镜像! 淘宝镜像:https://registry.npmmirror.com/binary.htm ...

  4. 史上最全3DMAX入门教程来啦,小白赶紧收藏!

    [最新版]3DMAX自学入门教程,3dsmax建模基础教学,游戏建模新手教程,软件介绍和基本操作,3DMAX+PS+Bodypaint**(全集共42集)**,如果无法跳转请移步BILIBILI学习! ...

  5. c语言中结构体数组的引用,【C语言入门教程】7.2 结构体数组的定义和引用

    7.2 结构体数组的定义和引用 当需要使用大量的结构体变量时,可使用结构体定义数组,该数组包含与结构体相同的数据结构所组成的连续存储空间.如下例所示: struct student stu_a[50] ...

  6. 2021年最新版Web前端学习路线图-前端小白入门必读-推荐

    2021年最新版Web前端学习路线图-前端小白入门必读-推荐 Hello,大家好,相信很多学习前端的小伙伴,会有很多的疑惑: 我要学习那些技术? 我要到哪里去学习这些技术呢? 学习这些技术的目的对就业 ...

  7. Git快速入门篇—— Windows版本淘宝镜像快速下载安装详细步骤及简单入门教程(附带图文教程)

    Git快速入门篇-- Windows版本淘宝镜像快速下载安装详细步骤及简单入门教程(附带图文教程) 前言:我们平时在整理代码的时候,尤其是与别人一起开发项目的时候,常常涉及到代码的更新,因此代码版本问 ...

  8. 轻松Git与Github入门

    文章目录 前言 一.版本控制系统介绍 1.版本控制系统的概念 2.版本控制系统功能 3.版本控制系统分类 二.Git 与GitHub 简介 1.Git 2.GitHub 三.Git账户注册与管理 1. ...

  9. Git与Github入门(一)

    Git与Github入门(一) 环境: Git与GitHub的来历 Linux 之父 Linus 在 1991 年创建开源的 Linux 操作系统之后,多年来依靠全世界广大热心志愿者的共同建设,经过长 ...

  10. 【安装配置Git】最新版Git安装教程

    最新版Git安装教程 2.34.1 1. 点击https://git-scm.com/ 进入官网下载 2. 点击下载 3. 选择自己的系统,我这里为Windows 4. 点击这里,自动会下载属于你系统 ...

最新文章

  1. 网络请求方式Fetch简介
  2. 用于软件包管理的21个Linux YUM命令 转载
  3. 并发锁之二:ReentrantReadWriteLock读写锁
  4. mysql 5.0 乱码_MySQL 5.0.16 乱码问题处理办法
  5. ExtJs CheckboxSelectionModel 全选操作后 清空表格头的checkBox
  6. VVDocumenter 使用
  7. Javascript基础之-原型(prototype)
  8. linux下c语言俄罗斯方块,c语言做俄罗斯方块
  9. iptables二之防火墙SNAT源地址转换,MASQUERADE地址伪装之DNAT目标地址转换讲解和实验演示
  10. 机器学习第三回——正则化
  11. Hibernate HQL查询(2)
  12. 离线安装pymysql和dbutils
  13. 夏日葵电商:从5大方面谈微信商城怎样提高用户体验度
  14. IDEA中java文件的左下角有个像乐符一样的J符号
  15. c#教程与视频教程类专题资料免费下载整理合集
  16. QT学习之文件读写操作
  17. 微信小程序地图篇(腾讯地图)
  18. 基于PaddleX的化妆品识别
  19. 成都榆熙电子商务有限公司:拼多多店铺暂停运营有什么学问吗?
  20. secureFX上传中文文件名乱码

热门文章

  1. 数据共享,如何拆掉那些“部门的墙”?by 傅一平
  2. 名悦集团:什么是驾驶证终身免检,要满足什么条件
  3. 猿创征文|一个.Net过气开发工程师的成长之路
  4. 今天Delphi盒子打不开了
  5. Spring整合Mybatis遇到的错误一
  6. python实现21根火柴游戏
  7. 300ETF期权和50ETF期权的区别
  8. Java十进制转换为二进制
  9. oracle+rac+ogg部署,RAC环境下配置OGG同步
  10. 三星android手机工程模式设置中文,三星工程模式怎么进入?三星手机进入工程模式方法...