当前位置:   article > 正文

git&github 常用命令详解

github


本文仅用作自己笔记用途,可能不系统,勿喷,教程见 廖雪峰官网
安装教程网上自行google,安装后先注册全局信息

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

1. git基本操作

1.1 初始化

$ git init //把某个目录变成Git可以管理的仓库

$ git add <文件名> //用命令git add告诉Git,把文件添加到仓库Git添加

文件需要add,commit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:

$ git add file1.txt
$ git add file2.txt file3.txt
$ git commit -m "add 3 files."
  • 1
  • 2
  • 3

1.2 git add 和 git commit

git add * 添加所有修改文件到暂存区
git add <filename> 添加某个文件到暂存区
git commit -m "自定义记录" 提交暂存区的修改到版本库
这里写图片描述
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;

第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

实战集锦
如果commit

1.3 git status

git status命令可以让我们时刻掌握仓库当前的状态Untracked
这里写图片描述
这三个分别是:
第一个是add之后但是没有commit的
第二个是没有add的
第三个是新文件,未被追踪的

1.4 git push

  • git push:更新本地git版本库到remote版本库:
  • git push origin master:将本地的master分支推送到origin主机的master分支。如果master不存在,则会被新建。
  • git push origin master --force:表示将本地版本库强制推到远程版本库,该操作比较危险,如果不是很有把握,一定不要这么做

1.5 git diff

git diff 这里显示的是本地没有提交的和提交的版本上的差异,显示的格式正是Unix通用的diff格式

1.6 git log

git log 命令显示从最近到最远的提交日志
git log --pretty=oneline 显示一行
git log --graph 分支合并图
git log --pretty=oneline 分支合并图 每个一行显示

1.7 git reset

git reset --hard HEAD^
首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交3628164…882e1e0(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD,上上一个版本就是HEAD,当然往上100个版本写100个比较容易数不过来,所以写成HEAD~100。
命令执行后会提醒:

Unstaged changes after reset:
M       README.md
  • 1
  • 2

这里直接把head指针修改了,但是文件的内容没有修改,需要借助1.7小节命令将其工作区的文本文件还原(具体原理见1.6),通过git status可查看,直接checkout就可以将文本变为想还原的版本了

后悔了,还想找到最新的怎么办呢?
办法其实还是有的,只要上面的命令行窗口还没有被关掉,你就可以顺着往上找啊找啊,找到那个append GPL的commit id是3628164…,于是就可以指定回到未来的某个版本:
git reset --hard 3628164
Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向append GPL:
这里写图片描述

改为指向add distributed:

这里写图片描述

然后顺便把工作区的文件更新了。所以你让HEAD指向哪个版本号,你就把当前版本定位在哪。
想恢复到新版本怎么办?找不到新版本的commit id怎么办?

在Git中,总是有后悔药可以吃的。当你用$ git reset --hard HEAD^回退到add distributed版本时,再想恢复到append GPL,就必须找到append GPL的commit id。Git提供了一个命令git reflog用来记录你的每一次命令

$ git reflog
a4a4527 (HEAD -> master, origin/master) HEAD@{0}: reset: moving to a4a45
dae796b HEAD@{1}: reset: moving to HEAD^
a4a4527 (HEAD -> master, origin/master) HEAD@{2}: commit: the third times modify readme.md
dae796b HEAD@{3}: commit: modify readme.md & add test2.txt
bdacecc HEAD@{4}: commit: new file readme.md
76b4650 HEAD@{5}: commit (initial): my first test
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意这里前面的那个id就是后面命令执行后最新的版本号,所以就可以回到最新的了

github怎么提交回退旧版本代码并更改后的文件到主分支上? (原文链接)
可能说的不是很明白,就是我代码写着写着,发现我已经不想这么弄了,用git reset --hard <版本号>退回到之前的某个版本重新写,这样当我当我写完之后,想在提交到远程仓库,它就会报错:
To https://github.com/zifenggao/wenda.git
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to ‘https://github.com/zifenggao/wenda.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 reset --hard,那就可以推断出你已经 addcommit 过了。
其次,根据报错,可以推断出你已经push过了(这个推断基于只有你一个人拥有 master branch 的更改权限。
那么当你执行 git reset --hard 之后,历史纪录是不能跟远程的记录直接合并的。因此才会有这个报错。
举个例子,远程是 A -> B -> C -> D,你git reset --hard之后是 A -> B。这时候除非远程那边抹掉 C 和 D,否则是不能合并的。
因此,这时候,你应该使用 git push origin master --force 来强行覆盖远程记录。
请不要根据提示使用 git pull。否则,你的本地又会变成 A -> B -> C -> D。因为 git pull 相当于 git fetch + git merge
(以下内容基于上面的例子,远程是 A -> B -> C -> D,你想回滚到 B 那个状态)
楼上提到了 git revert。其实,git reset --hard git revert都可以实现“回滚代码”。但区别在于:
git revert 会把你的本地变成 A -> B -> C -> D -> E。其中,E 干的事儿是删除 C 和 D。这样做的好处在于,你 git push origin master 就不会有上面的报错了。但,历史线上还是会保留 C 和 D 这两个 commit。如果使用这个命令,记得要 add 然后 commit
git reset --hard 会直接删掉 C 和 D,形成 A -> B 这样的结果。好处在于更直接更彻底。缺点在于,首先要通过 git push origin master --force 去强行更改。其次,一旦你后悔了,除非根据本地的 reflog 直接恢复 HEAD 指针,此外没有其他办法。
用哪个都是没错的,请根据自己的需要来选择。

1.8 git checkout

命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:

  • 一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
  • 一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。

总之,就是让这个文件回到最近一次git commitgit add时的状态。

使用场景:

场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout – file。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。

1.9 git rm

删除文件:

$ git rm test.txt
$ git commit -m "remove test.txt"
  • 1
  • 2

1.10 git remote

查看remote名称,增加-v可查看详细信息

2. git分支管理

廖雪峰“说”:

分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
其他版本控制系统如SVN等都有分支管理,但是用过之后你会发现,这些版本控制系统创建和切换分支比蜗牛还慢,简直让人无法忍受,结果分支功能成了摆设,大家都不去用。
但Git的分支是与众不同的,无论创建、切换和删除分支,Git在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。

每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。

一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点
这里写图片描述
而增加分支就相当于增加新的dev指针(详情

2.1 git checkout

-b参数表示创建并切换 :$git checkout -b dev ,上面相当于:git branch dev git checkout dev

回到master分支: $ git checkout master

切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>

2.2 git branch

git branch命令会列出所有分支,当前分支前面会标一个*号。
git branch <name> 创建分支
git branch -d <name> 删除分支

2.3 git merge

git merge <name> --no-ff -m "merge信息" 合并某分支到当前分支 --no-ff表示禁用fast forward

更多分支相关的问题参见Git 分支 - 分支的新建与合并

关于fast forward: Git- Fast Forward和no fast forward

2.4 git fetch

2.5 git merge

2.6 git pull

git pull相当于git fetch+git merge

2.7 远程git分支创建(如GitHub)

git push --set-upstream origin <分支名称> 远程创建分支,不过这里需要在本地存在已经创建的分支,说白了这个命令是将本地的分支push到远程版本库

2.8 分支实用技巧

正常情况下,我们可能不会显式的创建分支,但是在merge的时候其实实质上还是会用到分支的知识,下面介绍几种情形。

我们的代码从远程版本库clone之后,在我们修改的同时,别人已经先人一步提交他们的代码,这样我们再提交的时候,就会出现两种情况:

  • 我们修改的文件别人没有修改过,这个时候我们就可以通过两种方式进行merge:
    当然对于这种情况还是推荐用第一种方式,因为用第二种方式的时候会多出一个版本来,多多少少有点乱

    • git pull命令把远程代码同步下来,然后再用git add git commit命令来更新你的代码,git pull的效果图:
      这里写图片描述
    • 先用git add git commit命令在本地创建版本,然后再git pull,这个时候因为出现了版本冲突,会在pull的时候增加一个版本,就是merge的版本,如果没有什么文件上的冲突,在弹出的merge log里面添加日志,就可以合并到最新版本了。下面是详细的过程(左面和右面的一栏开始的内容是一样的,然后先增加text.txt,然后提交到远程版本库,第二个在增加text2.txt,最后提交时需要解决版本冲突~)
      这里写图片描述
  • 我们修改的文件别人已经修改过,提交到了远程仓库,这个时候再使用git pull就会报下面的错误了:
    这里写图片描述
    所以说上面的第一种方法失效,针对这种情况,我们只能通过一种方式进行解决了,流程和上面一种情况的方法二一样,只不过因为存在文件冲突,需要手动解决掉冲突然后在push:
    先用git add git commit命令在本地创建版本,然后再git pull,对于出现文本冲突的文档,手动选择修改,然后填写好merge日志之后就可以再次push了。详情如下:
    这里写图片描述
    这里大家会看到冲突的文件发生了变化,下面详细说下冲突文件出现变化的语法现象:
    这里写图片描述
    上图中被红框标记的部分,前两个红框之间的部分,是本地的内容。
    后两个红框之间的部分,是origin/master远端的内容。怎么修改决定于你。但是最后要把红框红的内容删除

综上,我们再做工程的时候,因为不知道本地修改的代码是在哪个基础上修改的,所以在提交的时候先git pull 一下:

  • 如果没有冲突,就先pull下最新的代码,然后再在这个基础上创建自己的新版本(或者西先本地提交一个版本,然后在git pull自动就merge了)
  • 如果提示冲突,肯定是你修改的文件别人已经修改过了,这样的话就先在本地创建版本,然后再git pull,这个时候就会出现conflict,然后对出现冲突的代码在修改,最后在提交一次就能得到最终的新版本了。

3. tag

Git有commit,为什么还要引入tag?
“请把上周一的那个版本打包发布,commit号是6a5819e…”
“一串乱七八糟的数字不好找!”
如果换一个办法:
“请把上周一的那个版本打包发布,版本号是v1.2”
tag应运而生!!!

3.1 tag的基本用法

git tag v1.0 //默认标签是打在最新提交的commit上的。
git tag -a <tagname> -m "blablabla..."//可以指定标签信息;
git tag v0.9 6224937 //提交打标签,对应的commit id是6224937
git tag //查看所有标签
git show v0.9 //查看标签信息
git tag -d v0.1 //删除标签
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3.2 tag的远程使用(如GitHub)

git push origin v1.0  //推送本地v1.0标签到远程
git push origin --tags  //推送本地所有标签到远程

/*远程删除tag,先在本地删除,再删除远程(好像直接远程也可以吧)*/
git tag -d v0.9
git push origin :refs/tags/v0.9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4. 自定义git

4.1 注册全局信息

绑定自己的账号和公开自己起的名字

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

Git显示颜色,会让命令输出看起来更醒目

$ git config --global color.ui true
  • 1

5. github

5.1 在命令行创建自己的仓库并上传

echo "# sss" >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin https://github.com/zsweet/xxx.git
git push -u origin master
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。
由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
从现在起,只要本地作了提交,就可以通过命令:

$ git push origin master
//或者直接 git push
  • 1
  • 2

5.2 直接上传已经存在的仓库

git remote add origin https://github.com/zsweet/xxx.git
git push -u origin master
  • 1
  • 2

5.3 git clone

克隆远程git到本地,两种方式都可以:我常用第二个

$ git clone git@github.com:michaelliao/gitskills.git
$ git clone https://github.com/michaelliao/gitskills.git
  • 1
  • 2

6.关于git中大文件的删除

参考:
彻底删除git中没用的大文件
寻找并删除Git记录中的大文件

7.git实战中的重要场景和命令

7.1. rebase

rebase的作用简要概括为:可以对某一段线性提交历史进行编辑、删除、复制、粘贴;因此,合理使用rebase命令可以使我们的提交历史干净、简洁!

蜗牛说

  • 其实在实际工作场景中,尤其是一些大厂或者好多人维护的项目,每一次push提交后合入主分支都需要管理员Code Review(简称CR),如果同时有多个commit id是无法上传的也不方便cr的,因此通过rebase命令,本地的一些提交就可以很随意,等push的时候再整理一下就可以了,可以大大提高开发的效率。
  • Git Merge vs Git Rebase: 更多详情[参考]
    相同点:git merge 和 git rebase 都是非常有用的命令
    不同点:1. 每当运行 git merge 时,都会创建一个额外的合并提交。每当你在本地仓库中工作时,合并提交过多会使提交历史看起来很混乱。避免合并提交的一种方法是改用 git rebase. 2. git rebase 是一个非常强大的功能,但是如果没有以正确的方式使用它也是有风险的。 git rebase 会更改提交历史记录,因此请谨慎使用。如果 rebase 是在远程仓库中完成的,那么当其他开发人员尝试从远程仓库中提取最新的代码更改时,可能会产生很多问题。请记住仅在本地仓库中运行 git rebase。

rebase常见的有如下几种使用场景:

  • 场景1. 合并多个commit为一个完整commit
  • 场景2. 将某一段commit粘贴到另一个分支上
  • 场景3. 本地开发基于的版本落后于或者不是远程分支最新版本,避免push出现新的commit id

场景1. 合并多个commit为一个完整commit
当我们在本地仓库中提交了多次,在我们把本地提交push到公共仓库中之前,为了让提交记录更简洁明了,我们希望把如下分支B、C、D三个提交记录合并为一个完整的提交,然后再push到公共仓库。
在这里插入图片描述
现在我们在测试分支上添加了四次提交,我们的目标是把最后三个提交合并为一个提交:
在这里插入图片描述
这里我们使用命令:

  git rebase -i  [startpoint]  [endpoint]
  • 1

其中-i的意思是--interactive,即弹出交互式的界面让用户编辑完成合并操作,[startpoint] [endpoint]则指定了一个编辑区间,如果不指定[endpoint],则该区间的终点默认是当前分支HEAD所指向的commit(注:该区间指定的是一个前开后闭的区间)。
在查看到了log日志后,我们运行以下命令:

git rebase -i 36224db
  • 1

git rebase -i HEAD~3 
  • 1

然后我们会看到如下界面:
在这里插入图片描述
上面未被注释的部分列出的是我们本次rebase操作包含的所有提交,下面注释部分是git为我们提供的命令说明。每一个commit id 前面的pick表示指令类型,git 为我们提供了以下几个命令:

pick:保留该commit(缩写:p)
reword:保留该commit,但我需要修改该commit的注释(缩写:r)
edit:保留该commit, 但我要停下来修改该提交(不仅仅修改注释)(缩写:e)
squash:将该commit和前一个commit合并(缩写:s)
fixup:将该commit和前一个commit合并,但我不要保留该提交的注释信息(缩写:f)
exec:执行shell命令(缩写:x)
drop:我要丢弃该commit(缩写:d)

根据我们的需求,我们将commit内容编辑如下:
在这里插入图片描述
然后是注释修改界面:
在这里插入图片描述
编辑完保存即可完成commit的合并了:
在这里插入图片描述
场景2. 将某一段commit粘贴到另一个分支上
当我们项目中存在多个分支,有时候我们需要将某一个分支中的一段提交同时应用到其他分支中,就像下图:
在这里插入图片描述
我们希望将develop分支中的C~E部分复制到master分支中,这时我们就可以通过rebase命令来实现(如果只是复制某一两个提交到其他分支,建议使用更简单的命令:git cherry-pick)。
在实际模拟中,我们创建了master和develop两个分支:
master分支:
在这里插入图片描述
develop分支:
在这里插入图片描述
我们使用命令的形式为:

 git rebase   [startpoint]   [endpoint]  --onto  [branchName]
  • 1

其中,[startpoint] ``[endpoint]仍然和上一个命令一样指定了一个编辑区间(前开后闭),--onto的意思是要将该指定的提交复制到哪个分支上。
所以,在找到C(90bc0045b)和E(5de0da9f2)的提交id后,我们运行以下命令:

git  rebase   90bc0045b^   5de0da9f2   --onto master
  • 1

注:因为[startpoint] [endpoint]指定的是一个前开后闭的区间,为了让这个区间包含C提交,我们将区间起始点向后退了一步。
运行完成后查看当前分支的日志:
在这里插入图片描述
可以看到,C~E部分的提交内容已经复制到了G的后面了,大功告成?NO!我们看一下当前分支的状态:
在这里插入图片描述
当前HEAD处于游离状态,实际上,此时所有分支的状态应该是这样:
在这里插入图片描述
所以,虽然此时HEAD所指向的内容正是我们所需要的,但是master分支是没有任何变化的,git只是将C~E部分的提交内容复制一份粘贴到了master所指向的提交后面,我们需要做的就是将master所指向的提交id设置为当前HEAD所指向的提交id就可以了,即:

git checkout master
git reset --hard  0c72e64
  • 1
  • 2

在这里插入图片描述
此时我们才大功告成!

场景3. 本地开发基于的版本落后于或者不是远程分支最新版本,避免push出现新的commit id
多人使用同一个远程分支合作开发,如果远程分支有新的 commit 未同步到本地,而自己的本地开发又有新的commit,在 push 代码的时候很可能出现以下问题,导致无法推送:
在这里插入图片描述
最简便的方法是直接采用git pull origin master从远程拉取并进行merge(git pull = git fetch & git merge),但是这样就会因为merge而多出来一个merge的commit节点,默认是这样的:
在这里插入图片描述
如果多人多次如此操作,那么提交记录就会出现很多条这种自动生成的 merge commit,非常难看。甚至在一些需要cr的场景中,这种操作也不太被允许和推荐。
那这就是需要运用rebase进行拉取,就不会产生merge的节点了。

git pull --rebase origin master
  • 1

执行 git pull --rebase 的时候必须保持本地目录干净。即:不能存在状态为 modified 的文件。(存在Untracked files是没关系的)
如果出现冲突,可以选择手动解决冲突后继续 rebase,也可以放弃本次 rebase。具体操作细节可参考:git pull --rebase

# 可选方式1: 手动解决 + 继续rebase。 手动解决冲突后
$ git add one.md
$ git rebase --continue
# 可选方式2: 放弃本次rebase 
git rebase --continue
  • 1
  • 2
  • 3
  • 4
  • 5

蜗牛说:
上面其实说的是将自己分支上跟远程分支rebase,但是我平时一般不直接跟远程分支rebase,而是喜欢新创建一个开发分支,需要rebase的时候,流程如下:
step1 : 从开发分支切换到本地master分支(git checkout master)
step2: 在master分支上git pull(因为本地master分支是干净的,不会出现merge节点)
step3: 切回开发分支并rebase:git checkout branch && git rebase master

更多git rebase可以参考官方文档:git-rebase

7.2. stash

7.3. cherry-pick

7.4. patch

参考:详解 git cherry-pick用法

Merge,Rebase,Cherry-Pick 了解一下

权威指南

参考资料

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/415640
推荐阅读
相关标签
  

闽ICP备14008679号