//独占鳌头日,功封万里侯

前言:Git是最近七八年来非常流行的版本控制工具,逐渐取代SVN、VSS,成为业内主流的控制器。Git最早是Linux系统开源使用的工具,不得不说,创建Linux世界的创世大神们确实造福了一代又一代开发工程师。后来逐步扩展版本应用,功能逐渐强大,与Gitlab、GitHub,并称Git家族三剑客。

Git代码状态转换图

其中:未被Git跟踪的状态为unstage状态

已经被Git跟踪的状态为stage状态,因此包括staging状态和staged状态

untrack files是指尚未被git所管理的文件。changed but not updated是指文件被git管理,并且发生了改变,但改动还没被git管理。这两种状态,都可以看成是改动还没被git管理的状态,我们这里称非stage状态,在IDEA文件中一般会呈现红色。 

changes to be commited是指进入stage状态的文件,stage是commit和未管理之间的一个状态,也有别名叫index状态,也就是git已经管理了这些改动,但是还没完成提交。 

.gitignore中的文件,不会出现在以上三个状态中。

Git的个人本地Bash使用及操作

创建Git库

cd 源码目录

git init    #初始化  在源码目录内生成一个.git的目录

  注册用户信息(之后可以vim调整)

git config --global user.:name XXX    用户名(形式符合bash环境要求)

git config --global user:  email XXX    用户邮箱

git config –list              #查看用户信息

  向git库中添加或删除文件

git add XX                #加单个文件

git add .                  #加所有

git add [path]会把对应目录或文件,添加到stage状态 

    git add . 会把当前所有的untrack files和changed but not updated添加到stage状态 

  向版本库提交变化

git commit –m “XXXX”     #直接添加简单提交信息,添加注释

[注:直接调用git commit命令,会提示填写注释。通过如下方式在命令行就填写提交注释:git commit -m "Initial commit of gittutor reposistory"。 注意,和CVS不同,git的提交注释必须不能为空,否则就会提交失败。 
       git commit还有一个 -a的参数,可以将那些没有通过git add标识的变化一并强行提交,但是不建议使用这种方式。 
每一次提交,git就会为全局代码建立一个唯一的commit标识代码,用户可以通过git reset命令恢复到任意一次提交时的代码。 
       git commit –-amend –m “message” (在一个commit id上不断修改提交的内容) ]

git status                  #查看当前代码库的状态

git log                    #查看版本信息

git log –p #查看版本信息并显示每次修改的diff

git show sdjf974654dd….    #查看指定版本信息

 #(show后面为每次提交系统自动生成的一串哈希值)[注:git  show sdji97也会显示本版本修改的diff ]

git show sdji97             #一般只使用版本号的前几个字符即可

 [git log参数注:-p 按补丁格式显示每个更新之间的差异(具体改动)

--stat 显示每次更新的文件修改统计信息(变更概要)

--shortstat 只显示 --stat 中最后的行数修改添加移除统计。

--name-only 仅在提交信息后显示已修改的文件清单。

--name-status 显示新增、修改、删除的文件清单。

--abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符。

--relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)。

--graph 显示 ASCII 图形表示的分支合并历史。

--pretty 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)。

-<n>(<n>为数字),显示最近的<n>条日志。]

  撤销与恢复

git reset

git reset --hard              #回到原来编辑的地方,改动会丢失。

#(同样适用于团队对于其他人的修改恢复)

git reset --hard sdv143kvf…...  #可回到指定的版本

#(hard后面为每次提交系统自动生成的一串哈希值)

  

git reset [path] 会改变path指定的文件或目录的stage状态,到非stage状 

    git reset 会将所有stage的文件状态,都改变成非stage状 

回退1个change的写法就是git reset HEAD^,2个为HEAD^^,3个为HEAD~3,以此类推。 

git revert

git revert是撤销某次操作,此次操作之前和之后的commit都会被保留,并且 会把这次 撤销 作为一次最新的提交

  • git revert HEAD                  撤销前一次 commit
  • git revert HEAD^               撤销前前一次 commit
  • git revert commit (比如:fa042ce57ebbe5bb9c8db709f719cec2c58ee7ff)撤销指定的版本,撤销也会作为一次提交进行保存。

git revert是提交一个新的版本,将需要revert的版本的内容再反向修改回去,

版本会递增,不影响之前提交的内容

git reset 是撤销某次提交,但是此次之后的修改都会被退回到暂存区;

git reset是还原到指定的版本上,这将扔掉指定版本之后的版本

 [注:撤消操作

接下来,我们会介绍一些基本的撤消操作相关的命令。请注意,有些操作并不总是可以撤消的,所以请务必谨慎小心,一旦失误,就有可能丢失部分工作成果修改最后一次提交

有时候我们提交完了才发现漏掉了几个文件没有加,或者提交信息写错了。想要撤消刚才的提交操作,可以使用--amend 选项重新提交

$ git commit --amend -m"修改 提交 说明"

此命令将使用当前的暂存区域快照提交。如果刚才提交完没有作任何改动,直接运行此命令的话,相当于有机会 重新编辑提交说明,但将要提交的文件快照和之前的一样。

启动文本编辑器后,会看到上次提交时的说明,编辑它确认没问题后保存退出,就会使用新的提交说明覆盖刚才失误的提交。

如果刚才提交时忘了暂存某些修改,可以先补上暂存操作,然后再运行 --amend 提交:

$ git commit -m 'initial commit'

$ git add forgotten_file

$ git commit --amend

上面的三条命令最终只是产生一个提交,第二个提交命令修正了第一个的提交内容。

取消已经暂存的文件

接下来的两个小节将演示如何取消暂存区域中的文件,以及如何取消工作目录中已修改的文件。不用担心,查看文件状态的时候就提示了该如何撤消,所以不需要死记硬背。来看下面的例子,有两个修改过的文件,我们想要分开提交,但不小心用git add . 全加到了暂存区域。该如何撤消暂存其中的一个文件呢?其实,git status 的命令输出已经告诉了我们该怎么做:

$ git add .

$ git status

# On branch master

# Changes to be committed:

#   (use "git reset HEAD <file>..." to unstage)

#

#       modified:   README.txt

#       modified:   benchmarks.rb

#

就在 “Changes to be committed” 下面,括号中有提示,可以使用git reset HEAD <file>... 的方式取消暂存。好吧,我们来试试取消暂存 benchmarks.rb 文件:

$ git reset HEAD benchmarks.rb

benchmarks.rb: locally modified

$ git status

# On branch master

# Changes to be committed:

#   (use "git reset HEAD <file>..." to unstage)

#

#       modified:   README.txt

#

# Changed but not updated:

#   (use "git add <file>..." to update what will be committed)

#   (use "git checkout -- <file>..." to discard changes in working directory)

#

#       modified:   benchmarks.rb

#

这条命令看起来有些古怪,先别管,能用就行。现在 benchmarks.rb 文件又回到了之前已修改未暂存的状态。

取消对文件的修改,之前已经暂存

如果觉得刚才对 benchmarks.rb 的修改完全没有必要,该如何取消修改,回到之前的状态(也就是修改之前的版本)呢?git status 同样提示了具体的撤消方法,接着上面的例子,现在未暂存区域看起来像这样:

# Changed but not updated:

#   (use "git add <file>..." to update what will be committed)

#   (use "git checkout -- <file>..." to discard changes in working directory)

#

#       modified:   benchmarks.rb

#

在第二个括号中,我们看到了抛弃文件修改的命令(至少在 Git 1.6.1 以及更高版本中会这样提示,如果你还在用老版本,我们强烈建议你升级,以获取最佳的用户体验),让我们试试看:

$ git checkout -- benchmarks.rb

$ git status

# On branch master

# Changes to be committed:

#   (use "git reset HEAD <file>..." to unstage)

#

#       modified:   README.txt

#

可以看到,该文件已经恢复到修改前的版本。你可能已经意识到了,这条命令有些危险,所有对文件的修改都没有了,因为我们刚刚把之前版本的文件复制过来重写了此文件。所以在用这条命令前,请务必确定真的不再需要保留刚才的修改。如果只是想回退版本,同时保留刚才的修改以便将来继续工作,可以用下章介绍的 stashing 和分支来处理,应该会更好些。

记住,任何已经提交到 Git 的都可以被恢复。即便在已经删除的分支中的提交,或者用 --amend 重新改写的提交,都可以被恢复(关于数据恢复的内容见第九章)。所以,你可能失去的数据,仅限于没有提交过的,对 Git 来说它们就像从未存在过一样。]

  向服务器提交变化

git push                    #向服务器提交

git --version                 #查看git版本

git remote                   #查看远程仓库链接

 暂存改动 

git stash可以把当前的改动(stage和unstage,但不包括untrack的文件)暂存。然后通过git stash list查看。并通过git stash apply重新取出来。但apply之前要保证worktree是干净的。

[注:git stash 可用来暂存当前正在进行的工作, 比如想pull 最新代码, 又不想加新commit, 或者另外一种情况,为了fix 一个紧急的bug,  先stash, 使返回到自己上一个commit, 改完bug之后再stash pop, 继续原来的工作。
基础命令:
$git stash
$do some work
$git stash pop

git stash save "work in progress for foo feature"

当你多次使用’git stash’命令后,你的栈里将充满了未提交的代码,这时候你会对将哪个版本应用回来有些困惑,

git stash list’ 命令可以将当前的Git栈信息打印出来,你只需要将找到对应的版本号,例如使用’git stash apply stash@{1}’就可以将你指定版本号为stash@{1}的工作取出来,当你将所有的栈都应用回来的时候,可以使用’git stash clear’来将栈清空。]

git rm 

从当前的工作目录中和索引中删除文件。 
可以递归删除,即如果后面跟的是一个目录做为参数,则会递归删除整个目录中的所有子目录和文件。例如: 
       git rm –r * (进入某个目录中,执行此语句,会删除该目录下的所有文件和子目录) 
       git rm f1    (删除文件f1,包含本地目录和index中的此文件记录) 
       git rm --ached f1 (删除文件f1,不会删除本地目录文件,只删除index中的文件记录;将已经git add的文件remove到cache中,这样commit的时候不会提交这个文件, 适用于一下子添加了很多文件, 却又想排除其中个别几个文件的情况.) 

6.差异比较:git diff

比较里程碑B和里程碑A:git diff B A

比较工作区和里程碑A:git diff A

比较暂存区和里程碑A:git diff –-cached A

比较工作区和暂存区:git diff

比较暂存区和HEAD:git diff –cached

比较工作区和HEAD:git diff HEAD

git的团队开发及操作

1,  获取项目

cd 本地工作目录(自定)

git clone 服务器帐户@IP:项目.根路经

这里具体操作为:

git clone git@github.com.git

这会在 当前目录下 创建一个名为 “git” 的目录,其中包含一个 .git 的目录,用于保存下载下来的所有版本记录,然后从中取出最新版本 的文件拷贝。如果进入这个新建的 grit 目录,你会看到项目中的所有文件已经在里边了,准备好后续的开发和使用。如果希望在克隆的时候,自己定义要新建的项目目录名称,可以在上面的命令末尾指定新的名字:

$ git clone git://github.com/schacon/grit.git mygrit

#注释:这是https方法,gitlab提供两种方法,ssh和https两种方式。

唯一的差别就是,现在新建的目录成了 mygrit,其他的都和上边的一样。

Git 支持许多数据传输协议。之前的例子使用的是 git:// 协议,不过你也可以用 http(s):// 或者user@server:/path.git 表示的 SSH 传输协议。]

团队开发的基本流程

git add 改动的文件

git  commit  #(提交至本地)

git  pull     #(将服务器项目与本地项目合并)

[注:从服务器的仓库中获取代码,和本地代码合并。(与服务器交互,从服务器上下载最新代码,等同于: Git fetch + Git merge) 
从其它的版本库(既可以是远程的也可以是本地的)将代码更新到本地,例如:“git pull origin master ”就是将origin这个版本库的代码更新到本地的master主分支。 
       git pull可以从任意一个git库获取某个分支的内容。用法如下: 
git pull username@ipaddr:远端repository名远端分支名 本地分支名。这条命令将从远端git库的远端分支名获取到本地git库的一个本地分支中。其中,如果不写本地分支名,则默认pull到本地当前分支。 
需要注意的是,git pull也可以用来合并分支。 和git merge的作用相同。 因此,如果你的本地分支已经有内容,则git pull会合并这些文件,如果有冲突会报警。 ]

git  push    #(将本地项目上传至服务器)(在提交前要git  pull  --rebase一下,确保当前的本地的代码为最新。)[注:git push好像不会自动合并文件。因此,如果git push时,发生了冲突,就会被后push的文件内容强行覆盖,而且没有什么提示。 这在合作开发时是很危险的事情。]

git fetch  从服务器的仓库中下载代码。(与服务器交互,从服务器上下载最新代码) 相当于从远程获取最新版本到本地,不会自动merge,比Git pull更安全些。 使用此方法来获取服务器上的更新。 
例如:如果使用git checkout nov/eclair_rocket (nov/eclair_rocket为服务器上的分支名),则是获取上次使用git fetch命令时从服务器上下载的代码;如果先使用 git fetch ,再使用git checkout nov/eclair_rocket,则是先从服务器上获取最新的更新信息,然后从服务器上下载最新的代码。

git blame  文件追溯,逐行显示文件,在每一行的行首显示此行最早是什么版本引入的,由谁引入

只想查看某几行,使用-L n,m参数,如:git blame –L 6,+5 README

git的分支管理

git分支操作在本地建立分支,然后与本地主枝合并,最终提交到服务器。有效的避免了因个人操作不当向服务器提交过多脏数据,避免频繁git clone服务器来更新本地库。

分支操作指令:

1,  建立分支

git branch AAA     #建立分支AAA

2,分支切换

git checkout AAA    #从当前分支切换到AAA分支

3,  将分支与主枝master合并

git checkout master     #(首先切换回主枝)

git merge AAA         #(将分支AAA与主枝合并)

4,  当前分支查看

git  branch            #默认有master(也称为主枝)

git  branch –a 查看当前所有分支

5,  删除分支

git branch –d  AAA     #删除分支AAA

[注:创建分支

git branch

  没有参数,显示本地版本库中所有的本地分支名称。

  当前检出分支的前面会有星号。

git branch newname

  在当前检出分支上新建分支,名叫newname。

git checkout newname

  检出分支,即切换到名叫newname的分支。

git checkout –b newname master

  这个命令将上面两个命令合并:在master分支上创建分支newname分支并检出到该分支。

合并分支间的修改 Merge

  合并操作将两条或多条分支合并到一起,实际上有好几种分支合并方法,下面介绍主要的三种:

1.直接合并(straight merge)

  把两条分支上的历史轨迹合并,交汇到一起。

  比如要把dev分支上的所有东东合并到master分支:

  首先先到master分支:git checkout master

  然后把dev给合并过来:git merge dev

  注意没参数的情况下merge是fast-forward的,即Git将master分支的指针直接移到dev的最前方。

  换句话说,如果顺着一个分支走下去可以到达另一个分支的话,那么Git在合并两者时,只会简单移动指针,所以这种合并成为快进式(Fast-forward)

2.压合合并(squashed commits):

  将一条分支上的若干个提交条目压合成一个提交条目,提交到另一条分支的末梢。

  把dev分支上的所有提交压合成主分支上的一个提交,即压合提交:

git checkout master

git merge --squash dev

  此时,dev上的所有提交已经合并到当前工作区并暂存,但还没有作为一个提交,可以像其他提交一样,把这个改动提交到版本库中:

git commit –m “something from dev”

3.拣选合并(cherry-picking):

  拣选另一条分支上的某个提交条目的改动带到当前分支上。

  每一次提交都会产生一个全局唯一的提交名称,利用这个名称就可以进行拣选提交。

  比如在dev上的某个提交叫:321d76f

  把它合并到master中:

git checkout master

git cherry-pick 321d76f

  要拣选多个提交,可以给git cherry-pick命令传递-n选项,比如:

git cherry-pick –n 321d76f

  这样在拣选了这个改动之后,进行暂存而不立即提交,接着可以进行下一个拣选操作,一旦拣选完需要的各个提交,就可以一并提交。 

冲突处理

  当两条分支对同一个文件的同一个文本块进行了不同的修改,并试图合并时,Git不能自动合并的,称之为冲突(conflict)。解决冲突需要人工处理。

  比如当前在master分支,想把dev分支merge过来,结果产生了一个冲突,打开文件内容可以看到这么一个冲突:

<<<<<<< HEAD

test in master

=======

test in dev

>>>>>>> dev

<<<<<<<标记冲突开始,后面跟的是当前分支中的内容。

HEAD指向当前分支末梢的提交。

=======之后,>>>>>>>之前是要merge过来的另一条分支上的代码。

>>>>>>>之后的dev是该分支的名字。

对于简单的合并,手工编辑,然后去掉这些标记,最后像往常的提交一样先add再commit即可。

删除分支

有些分支没有必要长期保存,比如分支中的代码已经打了标签并已发布,或者实验分支已经成功完成工作或中途废弃等等。 

注意:打了标签的分支,Git在删除该分支时,从版本树起始到此标签间的全部历史轨迹均会保留,此时删除分支操作只是删除分支本身的名称,因此可以说该分支没有必要长期保存。

  而在其他版本控制工具中,删除分支通常意味着删除分支上的所有历史轨迹,所以不能因为打了标签就认为其没有必要保存。

  删除一个分支dev2:

git branch –d dev2

  注意不能删除当前所在分支,需要转到别的分支上。

  如果要删除的分支已经成功合并到当前分支,删除分支的操作会直接成功。

  如果要删除的分支没有合并到当前所在分支,则会出现提示,如果确定无须合并而要直接删除,则执行命令:

git branch –D dev2

  进行强删。

分支重命名

重命名分支:

git branch –m oldname newname

-m不会覆盖已有分支名称,即如果名为newname的分支已经存在,则会提示已经存在了。

如果改成-M就可以覆盖已有分支名称了,即会强制覆盖名为newname的分支,这种操作要谨慎。]

git 忽略机制

在生成文档内容快照时,工作树中有一些文档是你不希望接受Git 管理的,譬如程序编译时生成的 中间文件,对于这样的文件如何避免为之生成快照?

 Git 提供了 文档忽略机制,可以将工作树中你不希望接受Git 管理的文档信息写到 同一目录 下的.gitignore文件中

1.在项目根目录下建立 .gitignore 文件

2.   .gitignore文件过滤有两种模式,开放模式 和 保守模式


2.1开放模式负责设置过滤哪些文件和文件夹

eg:

过滤文件夹设置:

mtk/       表示过滤这个文件夹

过滤文件设置

指定过滤某种类型的文件:
*.zip
*.rar
*.via
*.tmp
*.err

指定过滤某个文件:
/mtk/do.c

/mtk/if.h

2.2 b保守模式负责设置哪些文件不被过滤,也就是哪些文件要被跟踪。


跟踪某个文件夹

!/plutommi/mmi

跟踪某类文件

!*.c

!*.h

跟踪某个指定文件

!/plutommi/mmi/mmi_features.h

3.配置.gitignore 的简易原则

采用共享模式与保守模式结合配置的办法。eg:一个文件夹下有很多文件夹和文件,而我只想跟踪其中的一个文件,这样设置就可以满足这种情况,先用共 享模式把整个目录 都设置为不跟踪,然后再用保守模式把这个文件夹中想要跟踪的文件设置为被跟踪,配置很简单,就可以跟踪想要跟踪的文件。

需要注意的是:.gitignore 中的规则只对 未提交 且 未缓存 的文件有效。因此,如果在"未缓存的改动"中发现有需要忽略的文件, 马上修改 .gitignore,再重新扫描就会发现该文件被忽略了。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐