Git常用命令介绍

1.创建仓库、commit、查看状态、版本跳转

  git只能跟踪文本文件的改动;

  在合适的目录里建 仓库(版本库),里面的文件被git管理起来,所有文件的修改、增加、删除会被git记录,随时追踪,需要的时候还原,新建命令: 

 

//新建git仓库
git init
  这样就可以在当前位置下新建一个空的 .git 文件夹,这就是git仓库了。
  向git仓库中添加文件: 

 

// 向git仓库中添加(并不是提交)文件readme.txt
git add readme.txt

  把文件提交到仓库:

//把文件提交到仓库
git commit
//或者可以给本次提交加一个备注
git commit -m  "备注"
  其中,commit可以一次提交很多文件,所以可以先用add增加多个文件,再用commit 一次性提交,比如:

 

// 一次添加很多文件
git add file1.txt
git add file2.txt
// 或者一次添加所有本次修改的文件
git add .
// 将添加好的文件,全部提交
git commit

  查看当前状态:

//查看当前状态
git status

 

  这个命令可以用来查看当前git仓库的状态,比如如果你的文件 readme.txt 当前有一个变化(文件修改),不过还没有提交或add,它的信息是这样的:

  还可以查看具体的变化:

//查看文件具体变化
git diff readme.txt
  结果将以”+-“号的形式给出,比如在上面的例子中,可见是文件里增加了一个“distribute”字段:
  还可以查看之前几次commit的情况:

 

git  log
//或者
git  log  —pretty=oneline
//这样会显示的比较简洁,只有版本号等一些信息

 

  每个提交的版本都有一个版本号,另外还可以用HEAD代表当前版本,规律如下:

 

//当前版本
HEAD
//上一个提交的版本
HEAD^
//往前数第二个
HEAD^^
//或者
HEAD ~2
//往前数第100个
HEAD ~100
  使用git reset命令来退回到之前的版本:

 

//回到上一个版本
git reset HEAD^
//切到指定版本号
git reset 3628164
  这时再使用git log命令,就看不到最新的那个commit了,想再换回去最新的版本,除了往上翻窗口记录找到版本号,还可以使用git reflog命令, 会显示之前的所有命令和执行那条命令时候的版本号,这样就可以知道回退之前的版本号,可以再使用reset命令切换回去:

 

//查看commit历史
git  log
//查看命令历史和执行那条命令时所在的版本号
git reflog
  head指针的概念:

 

2.工作区、版本库、暂存区、删除、撤销

 

  工作区即是.git文件夹所在目录,我们在这里工作、编写。
  .git即是版本库,中间存放着stage(暂存区)、master分支以及指向master的HEAD指针:
  结合这个概念,则1中的命令有如下意思:
//将文件的修改添加到暂存区
git add readme.txt
//将 暂存区的所有内容 提交到当前分支
git commit
  提交就是向当前所在分支提交,当前我们还没有新建别的分支,所以是向master分支上提交。
  commit之后,如果没有再对工作区修改,那么这时候暂存区应该是空白的: 

 

  只有先放到了暂存区,才可以提交成功。
  每次修改,如果不add到暂存区,那就不会加入到commit中,如果在第一次修改之后放到暂存区,然后又做了修改,之后没有add立即提交,则这次提交不会记录第二次的修改。
  用checkout--命令来对修改进行撤销:

 

//对这个文件在工作区的修改撤销;
//如果这次修改没有存入暂存区,则恢复到和版本库一样,也就是用版本库里的版本替换工作区的版本;
//如果已经修改并存入暂存区后而且再次修改,就恢复成添加到暂存区的状态
git checkout --readme.txt
  checkout后面"--"不可少,否则就变成了切换分支的命令。
  如果直接想将已经在暂存区的修改一并撤销,还可以使用reset的另一种用法,将已经存入暂存区的修改撤销,也就是将暂存区清空: 

 

//将已经存入暂存区的修改撤销,只保留工作区的修改
git reset HEAD readme.txt
//之后再执行checkout --,就可以将工作区的修改也撤销了(当然既然是在自己的工作区,也可以手动撤销了)

  如果已经commit了,还想要撤销,就只能使用之前的reset命令回退版本了;如果已经推送到了远程库,那就没办法了。
  删除文件也是一种修改,所以如果当前工作区commit 过,之后在工作区删除了文件的话,这时工作区和版本库已经不一样了,可以通过回退版本的方法来找回这次在工作区删除的文件。
  如果真的想删,可以直接用rm命令,将已经commit到版本库的那个文件彻底删除: 

 

git rm readme.txt
//接着执行commit
git commit
  如果删错了,自然可以使用之前的checkout --命令来回到最新版本,或者使用reset回之前到任何一个版本,不过这次除了删除之外的修改,也不再保留了。

 

3.远程仓库

 

  一般使用git的情况:
  一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的最新提交。
  所以,就分为本地仓库和远端仓库两个概念, 远端库的名字一般叫做" origin"。
  可以自己在本地建立一个仓库之后,再在远端建一个,然后将二者关联:

 

//将本地的库与远端的仓库关联
git remote add origin git@github.com:michaelliao/learngit.git
  关联之后,就可以将本地库的东西推送到远端库去了,可以作为备份,也可以供多人协作开发:

 

//把本地库所有内容推送到远端库
git push -u origin master
  把本地库的内容推送到远程,用git push命令,实际上是把所在的当前分支推送到远程,这其中包含了merge的操作;
  这是第一次推送,由于远程库是空的,我们第一次推送master分支时,加上了  -u 参数,Git不但会把本地的master分支内容推送到远程新的master分支,还会 把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
  这样做之后,可以立刻看到远程库的内容已经和本地一模一样。
  在这之后,只要本地的修改进行了本地的提交(commit),就可以再将它推送到远端的版本库了:

 

//将本地master分支上的(已经提交的)新修改推送到远端的master
git push origin master

 

  更推荐的做法,是先在远端建立仓库,然后拉到本地进行工作(从远程库克隆),命令是git clone:

 

//克隆远程库到本地
git clone git@github.com:michaelliao/gitskills.git
如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了(克隆的是远端的最新commit)。

4.分支的概念

之前偶尔提到分支的概念,现在就来具体解释一下,下面的图来自网络,个人感觉这种图形有些歧义,这里先暂时贴一下。

一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:

  创建新的分支并切换过去,如dev,git就将新建指针叫做dev,然后将这个指针指向和master相同的提交:

 

  所以HEAD指针就是说明当前在哪个分支的哪个commit。

 

  保持当前的状态,继续开发,则就是在dev分支上进行的了,如果再进行提交,也就是dev前进一步: 
如果在dev分支上开发完成,就可以将两个分支合起来,一个简单的方法就是让master分支向dev分支的当前提交,其实也就是将master指针换个指向的问题:

这叫做快速合并,之后还会提到具有冲突的合并情况。

之后直接删除dev分支,完成这次开发:


 

  相关命令行语句:

//新建分支
git branch dev
//跳转到刚才新建的分支
git checkout dev
 
//这两句可以用一句来实现:
git checkout -b dev
 
//查看当前所有分支
git branch
//切换到master分支
git checkout master
//将dev的改动合并到master上
git merge dev
//删除dev分支
git branch -d dev
  其中git branch命令会列出所有分支,当前分支前面会标一个 *号,如下:
  因为创建、合并和删除分支非常快,所以Git鼓励使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。

5.冲突(conflict)的概念

  从master分支新建分支feature1,在feature1中修改并提交(commit),回到master分支,在相同位置再做其他修改并提交,现在两个分支都做了修改并有新的提交,试图将两个分支合并,将会出现冲突:

//试图合并两个分支(当前在master分支)
git merge feature1
  出现冲突导致无法合并,是因为这两个commit是在 相同的位置做了不一样的修改,git无法判断应该留下哪个,如果是不同的地方的修改,git会将两个修改都保留下来并合并成功。
  冲突的信息如下,git会让你解决冲突:

   用编辑器查看具体的文件内容,会用符号标出冲突的位置:

   

   这里就可以看到两个commit都修改了同一个地方,让Git不知道怎么合并,所以这时需要我们手动的去解决冲突。

 

   可以在两处修改中,去掉在master中修改的地方,或者直接将两者都保留,但将git增加的标记符号删掉,表明master是做了两处修改,其中包含feature1上的修改, 再次提交之后,就重新执行merge命令,合并成功了。
   所以,合并时候的重点是: 如果有冲突,解冲突,然后再合并
   PS:个人理解,合并分支就是将二者的最新commit指针指向同一个修改。 
  
  在实际开发中,我们应该按照几个基本原则进行分支管理:首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
  你和你的小伙伴们每个人都拉取dev分支到本地,然后在本地的dev分支上干活,每个人都有自己的分支,时不时地往远端的dev分支上推送并合并就可以了(当然有时候会需要解决冲突)。
  所以,团队合作的分支看起来就像这样: 

 

6.暂存的概念

 

  加入当前正在dev分支进行开发,开发到一半,意识到之前的代码出现bug时,可以切换回master分支新开一个分支专门用来解决bug,之后合并分支,删除新分支即可。
  但这时正在dev分支开发新的功能,只开发了一半,所以也没法add和commit,则这时可以使用暂存功能stash。 
  我一开始以为stash和add是同一个操作(因为add进去的那个stage区域也被叫做暂存区...),后来仔细看了内容才知道 stash和add完全不同,这个操作会将本地和暂存区(add)的文件一起存起来。

 

//暂存当前状态,之后可以恢复现场重新工作
git stash
// 暂存同时添加备注,方便查找
git stash save -a  "message" // 其中 -a 这个选项的作用:
  其中 -a 这个option的作用: git stash 命令
  使用git status查看当前状态,会发现工作区是干净的,可以安心新建分支进行bug的修复。
  bug修改结束切换回dev分支,工作区是干净的,使用git stash apply或git stash pop命令恢复之前暂存的工作状态: 

 

//查看之前暂存的版本
git stash list
//弹出暂存的版本(之后stash区域的内容就没有了)
git stash pop
 
//应用暂存的内容,但是stash区域的内容仍然保留
git stash apply
//可以再使用drop语句来清空stash区域的内容
git stash drop

   可以多次使用stash功能暂存并重新使用,在这之前可以先用list命令查看对应stash号。如果使用source tree一类的GUI工具,会更加直观。

   在实际操作中意识到,应用(apply)之前暂存的stash时,如果当前的工作区不是干净的,那么可能会需要手动解决冲突。

   另外在网络上查阅资料时还得到一个结论:如果没有事先commit或者stash,git不会让你切换(checkout)到别的分支去。

 

7.多人协作


  开发新功能时,为防止把dev分支弄乱,最好每个新功能都新建一个feature分支,在上面开发完毕后合到dev分支,然后删除feature分支。
  从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin

 

//查看远端库的信息
git remote
//更详细信息
git remote -v
  推送分支,就是把 该分支上的所有本地提交推送到远程库(这里也有merge的操作在里面)。推送时,要指定本地分支,这样,Git就会把 该分支推送到远程库对应的远程分支上:

 

//将当前分支推送到远程库的master分支
git push origin master
//推到远程库的dev分支
git push origin dev
  多人协作刚开始时,大家需要从远程库上clone项目文件,注意这里是clone, 和后面的pull(拉取)有些区别。
  从远程库clone时,默认情况下,只能看到本地的master分支:

 

//直接使用clone命令克隆时,只能拉到master分支
git clone git@github.com:michaelliao/learngit.git

   要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是用这个命令创建本地dev分支:

//拉取对应其他分支
git checkout -b dev origin/dev

   现在,就可以在dev上继续修改,然后,时不时地把本地的dev分支push到远程的dev(记得先commit):

  如果合作的开发者已经向远程的dev分支(origin/dev分支)推送了提交,而自己也对相同的文件进行了修改并试图推送时,可能会发现对方已经推送的提交和我准备推送的提交有冲突,导致提交失败的情况,即是说因为包含了merge的操作在里面,所以可能会需要解决冲突:

  这时可以使用git pull把最新的提交从远端拉下来,在本地与自己想推送的commit进行合并(或者用另外会提到的rebase),解决冲突,之后再推送就可以了,关于pull操作可以参考 git pull、git push、git rebase 。

  具体的操作可能是:暂存当前修改(工作区变为空白)、拉取最新提交分支、apply之前的暂存(包含了merge的操作,需要解决冲突)、提交、再次push到远端;

  当然不是说本地的dev就只能推到远端的dev,如果你要推送的目标分支名和你的本地开发分支名并不一样(我们组平时开发就是这样的,因为会用这个分支相关的task来给分支命名,推过去之后等待大家review过后才有权限进行合并,push和merge并不是一步完成的,也可以理解成推送时在远端新建了同名分支,之后再由有权限者将这个分支合到远端的dev中去)。这里假设推送的本地分支名字叫bugfix,推送目标时远端的dev,那么你也可以这么操作:切换到本地的dev、pull最新dev、将本地bugfix与本地dev进行合并或rebase(解决冲突)、push向远端的dev。

另外,在使用pull时也可能出现问题,如下例:

这是说明没有进行本地dev分支与远端dev分支之间的链接 (参考git pull、git push、git rebase),需要按照提示先进行如下操作:

//指定本地和远端dev分支之间的链接
git branch —set-upstream dev origin/dev
之后就可以pull成功,但是在pull到本地并自动合并时,会出现冲突:

 

  这时需要和之前一样,手动解决冲突, 提交,之后再推送。
  总的来说,多人协作的工作模式:
 a.试图推送自己的修改到远端;

 

//向远端提交自己的修改
git push origin branch-name

 

 b.可能会推送失败,因为远程分支比本地更新,这时需要用pull命令将最新提交拉下来,然后进行本地的合并(解决冲突),最后再次提交、推送。

 

8.Reference

参考了很多网络上的资源和wiki,这里不一一列出,主要参考:Git教程

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值