Git常用命令手册


Git常用命令手册

阅读前说明

本手册总结了Git的常用命令,目的是方便平时使用Git可视化工具管理代码的同事学习和查询命令行下Git的命令,一些不常用的高级用法并没有写入

符号说明

  • 中括号 []

本文中使用中括号 [] 表示要自定义输入的内容,例如git add [test.text]表示在命令行中输入git add test.text

Git基础操作

Git仓库创建

有两种创建Git项目仓库的方法,第一种是在现存的目录下,通过导入所有文件来创建新的 Git 仓库。第二种是从已有的 Git 仓库克隆出一个新的镜像仓库。

  1. 在已有的工作目录中创建Git仓库:

打开命令行,输入

cd [需要创建Git仓库的文件夹路径]

移动到需要使用Git管理的目录下,可以直接将文件夹拖入命令行窗口快速输入路径,然后再输入

git init

在当前目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中。不过目前,仅仅是按照既有的结构框架初始化好了里边所有的文件和目录,但我们还没有开始跟踪管理项目中的任何一个文件。

如果当前目录下有几个文件想要纳入版本控制,需要先用

git add [fileName]

命令告诉 Git 开始对名字为fileName文件进行跟踪,也可以输入

git add .

对该文件夹下的所有文件进行跟踪

然后

git commit -m [initial project version]

提交这次改动,所有被跟踪的文件就被记录进Git的数据库中。

  1. 从现有仓库克隆:
    假设某项目在GitHub上的仓库地址为URL,输入

git clone [URL]

如果希望在克隆的时候,自己定义要新建的项目目录名称,可以在上面的命令末尾指定新的名字

git clone [URL] [myProject]

新建的目录名字会变成myProject。

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

Git的工作流程

上一步我们已经创建了一个Git仓库,并将一些文件加入了跟踪列表,在进行下一步操作之前,我们有必要了解一下Git的工作流程:

image

我们创建Git仓库的目录叫做工作目录,工作目录下面的所有文件处于两种状态:已跟踪或未跟踪。已跟踪的文件指使用git add命令加入版本控制管理的文件,工作一段时间后,它们的状态可能是未更新,已修改或者已放入暂存区。而没有加版本控制管理入都属于未跟踪文件。初次克隆某个仓库时,工作目录中的所有文件都属于已跟踪文件,且状态为未修改。

在编辑过某些文件之后,Git将这些文件标为已修改。我们可以把这些修改过的文件放到暂存区域,当我们使用git commit命令后暂存区的文件会被保存进数据库,状态变为未修改,如此重复。

检查当前文件状态

要确定哪些文件当前处于什么状态,可以用:

git status

如果是刚创建的仓库,则会显示

On branch master

nothing to commit, working directory clean

这说明现在的工作目录是干净的。所有已跟踪文件在上次提交后都未被更改过。此外还表明当前目录下没有任何处于未跟踪的文件,否则 Git会在这里列出来。最后该命令还显示了当前所在的分支是 master,这是默认的分支名称。

现在在当前目录下创建一个新文件 README,保存退出后运行

git status

会看到该文件出现在未跟踪文件列表中:

On branch master 
Untracked files:
(use "git add <file>..." to include in what will be committed)
README
nothing added to commit but untracked files present (use "git add" to track)

可以看到新建的README文件出现在“Untracked files”下面。用

git add README

命令将该文件加入跟踪后再运行

git status

会看到 README 文件已被跟踪,并处于暂存状态

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

new file:   README

加入我们对仓库中一个叫newText.text的文件进行一些修改以后,再运行

git status

会看到

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

new file:   README

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:   newText.text

文件 newText.text 出现在 “Changes not staged for commit” 这行下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区。要暂存这次更新,需要运行 git add 命令(这是个多功能命令,根据目标文件的状态不同,此命令的效果也不同:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等)。现在让我们运行 git add 把newText.text 放到暂存区,然后再看看 git status 的输出

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

new file:   README
modified:   newText.text

可以看出两个文件都已经被放入了暂存区,下次提交的时候会一起被写入数据库。

提交修改

在我们新增、修改文件后,使用

git commit -m [initial project version]

命令提交修改,initial project version是提交时的说明,在这里写明做了什么修改,方便自己和别人过后查看代码。

提交代码之前必须先用add命令将修改后的文件加入暂存区,如果想跳过这一步,也可以使用

git commit -am [initial project version]

或者

git commit -a -m [initial project version]

来直接提交改动,这样会直接将已经加入跟踪的并且发生了改动的文件先加入暂存区然后提交,省略了add步骤。

设置忽略目录

有时会有些文件我们不希望纳入Git的管理,也不希望它们总出现在未跟踪文件列表,比如日志文件、配置文件等。我们可以在仓库的根目录下使用

touch .gitignore

创建一个名为 .gitignore的文件,然后使用

echo ["rule"]>>.gitignore

向.gitignore文件中写入要忽略的文件的规则,其中rule是字符串例如:

echo *.[oa]>>.gitignore

表示忽略所有以 .o 或 .a 结尾的文件

echo *~>>.gitignore

表示忽略所有以波浪符(~)结尾的文件
新增了.gitignore文件后也需要进行提交。

有些时候,你想添加一个文件到Git,但发现添加不了,原因可能是这个文件被.gitignore忽略了,如果你确实想添加该文件,可以用

git add -f [App.class]

强制添加App.class这个文件到Git,如果你想知道是哪一个规则限制了添加,可以使用

git check-ignore -v App.class

来检查,git会输出信息表明是第几行规则忽略了该文件。

查看已暂存和未暂存的更新

git status的显示的信息比较简单,仅仅是列出了修改过的文件,如果要查看具体修改了什么地方,可以用

git diff

来查看当前工作目录中当前文件和暂存区域快照之间的差异,也就是修改之后还没有暂存起来的变化内容,注意git diff只是显示还没有暂存起来的改动,而不是这次工作和上次提交之间的差异。所以暂存了所有更新过的文件后,运行 git diff 是什么都没有的。

查看暂存区文件与上次提交后的变化,可以使用

git diff --cached

查看两次commit之间的变化,可以使用

git diff [commit_id1] [commit_id2]

比较工作区与最新本地版本库,可以使用

git diff HEAD

比较工作区与指定commit-id的差异,可以使用

git diff [commit_id1]

撤销操作

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

git commit --amend

输入指令后将会弹出文本编辑器,可以看到上一次提交的说明,按shift + i组合键进入编辑模式可以修改提交信息,修改完成后按esc退出编辑模式,再按shift + :组合键,输入wq,回车保存改动,提交说明就会被修改。

如果不是只修改说明而是想要补上其他的改动,则可以将其他改动先暂存,然后在提交的时候带上--amend:

git commit -m 'initial commit'

git add forgotten_file

git commit --amend

这样会将第二次提交和第一次提交合并,最终只产生一个提交。

如果我们将某个文件误加入了暂存区,可以使用

git reset HEAD <fileName>

将名为fileName的文件移出暂存区,这个文件将会回到已修改未暂存的状态。

如果我们想放弃改动将某个文件返回修改前的状态,可以使用

git checkout -- <fileName>

将名为fileName的文件恢复成未修改的状态,这个操作将会清空所有已经修改,需要谨慎操作。

在Git中所有已经提交过的改动都可以被恢复,即便在已经删除的分支中的提交,或者用 --amend 重新改写的提交,没有提交过的的改动无法恢复,对Git 来说它们就像从未存在过一样。

标签操作

Git可以对某一时间点上的版本打上标签,方便未来某个时间能回退到打标签时刻的状态
要列出所有tag:

git tag

显示的标签按字母顺序排列,标签太多的时候我们可以用特定的搜索模式列出符合条件的标签

git tag -l 'v1.4.2.*'

只显示v1.4.2系列版本

Git使用的标签有两种类型:轻量级的(lightweight)和含附注的(annotated)。轻量级标签就像是个不会变化的分支,实际上它就是个指向特定提交对象的引用。而含附注标签,实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明,在这里只举例轻量级标签的使用方法:

git tag v1.4

则打上了V1.4的标签

Git分支操作

创建切换新分支

git branch testing

可以新建一个名为testing的新分支,但是不会自动切换到该分支,要切换到该分支:

git checkout testing

也可以使用

git branch -b testing

一步完成创建和切换工作。

在切换分支的时候,如果暂存区或者工作目录里还没有提交的修改和你即将检出的分支会产生冲突,Git会阻止你切换分支,此时可以使用

git stash

将这些内容暂存起来,切换分支或者当再回到这个分支后,使用

git stash pop

方法就会将这些内容取出到当前分支。

删除分支

如果需要删除的分支不是当前正在打开的分支,使用branch -d直接删除

git branch -d <branchName>

如果我们在试图删除一个分支时自己还没转移到另外的分支上,Git就会给出一个警告,并拒绝该删除操作。如果坚持要删除该分支的话,就需要在命令中使用-D选项

git branch -D <branchName>

当我们删除一个分支时,Git只是删除了指向相关提交的指针,但该提交对象依然会留在版本库中,如果我们知道这个分支的Hash值,那么我们可以使用

git branch <branchName> <hashValue>

来恢复这个分支,如果不知道这个分支的Hash值,可以使用

git reflog

来查看所有所有的commit信息,包括所有branch的commit,甚至包括已经撤销的commit

分支的合并

git checkout master

git merge fixIssue

可以将fixIssue分支合并回master分支

关于分支的合并,需要注意的是,如果从master分支分离出来的分支fixIssue过后又合并进了master分支,如果此时master分支上没有其他新增的内容的话,合并成功后会出现Fast-forward的提示,表明实际上是将master的指针快进到了fixIssue的指针处,如果此时master分支上已经有了其他的改动,则Git会自动生成一个新的合并提交并将master的指针指向这个提交

处理冲突

如果在不同的分支中都修改了同一个文件的同一部分则在合并时会产生冲突,提示如下:

Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

此时Git已经做了合并,但是没有提交,此时可以用git status来查看哪些文件产生了冲突:

On branch master
You have unmerged paths.
(fix conflicts and run "git commit")

Unmerged paths:
(use "git add <file>..." to mark resolution)

both modified:      index.html

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

包含没有解决的冲突的文件都会被标记为unmerged状态,从上面的结果可以看出index.html这个文件产生了冲突,用文本编辑器打开这个文件,会出现以下的内容:

<<<<<<< HEAD
var a = 1

=======

var a = 2
>>>>>>> fixIssue

Git使用=======符合将有冲突的部分分隔开

<<<<<<< HEAD
var a = 1

=======

表示当前分支的内容

=======

var a = 2
>>>>>>> fixIssue

表示合并进来的分支的内容,选择要保留的部分,将<<<<<<< HEAD、=======和>>>>>>> fixIssue标记删除,再用git add命令将修改好的文件标记为冲突已解决并加入暂存区,然后使用git commit提交。

在我们的日常开发中,使用pull request流程来提交代码,如果提交pr的时候提示有冲突,例如想将fixIssue分支合回master,最好在本地将master分支合并进fixIssue,在fixIssue中解决好冲突后,此时pr应该就会显示冲突已经解决可以自动合并,不要在master分支上合并冲突防止出现误操作破坏master分支。

管理分支

git branch命令除了能创建删除分支,也可以查看分支的信息,直接使用

git branch

会列出所有的分支清单:

iss53
* master
testing

带*号的是当前选中的分支,也可以使用

git branch -v

来查看每个分支最后一次提交的信息

iss53   93b412c fix javascript issue
* master  7a98805 Merge branch 'iss53'
testing 782fd34 add scott to the author list in the readmes

还可以使用

git branch --merged

来查看哪些分支已经合并回了当前分支

iss53
* master

结果显示iss53这个分支已经合并回了master分支,如果不是有特殊用途要保留一般可以删除,因为这个分支的改动已经包含在master分支中,使用

git branch --no-merged

可以查看哪些分支还没有合并进当前分支

远程仓库的使用

远程分支的概念

远程分支是本地分支在Git服务器上的对应,一般我们都是使用GitHub的Git服务器服务,假如我们在GitHub上有一个仓库,当我们使用第一节提到的git clone将这个仓库克隆到本地的话,将会在本地复制一个与远程仓库一样的本地仓库,并给远程仓库起一个默认名字origin,假如远程仓库的默认分支叫master的话,将会在本地创建一个命名为origin/master分支,但你无法在本地更改其数据,接着Git 建立一个属于你自己的本地master分支,和origin上的master分支指向相同的位置

你不能直接修改origin/master分支的数据,但是你可以通过修改本地master分支的数据,然后推送到远程仓库的方式来改变origin/master分支的数据,或者通过拉取操作来把本地master分支的数据更新到和origin/master一样

假如你在本地master分支做了些改动,与此同时其他人向origin/master推送了他们的更新,那么服务器上的master分支就会向前推进,而与此同时,你在本地的提交历史正朝向不同方向发展。不过只要你不和服务器通讯,你的origin/master 指针仍然保持原位不会移动

推送数据到远程分支

使用

git push origin serverfix

可以将本地的serverfix分支推送到远程仓库的serverfix分支上,这里是简便写法,Git会自动将serverfix扩展为refs/heads/serverfix:refs/heads/serverfix,意思是“取出我在本地的serverfix分支,推送到远程仓库的serverfix分支中去,也可以使用

git push origin serverfix:serverfix

来达到相同效果,如果想让远程分支和本地分支使用不同的名字,可以用

git push origin localBranchName:originBranchName

来将本地叫localBranchName的分支推送到远程仓库,在远程仓库上的分支名字叫originBranchName

当你运行

git fetch origin

时,会同步远程服务器上的数据到本地。该命令首先找到 origin 是哪个服务器,然后从上面获取你尚未拥有的数据,更新你本地的数据库,然后把 origin/serverfix 的指针移到它最新的位置上

需要注意的是,在 fetch操作下载好新的远程分支之后,本地的serverfix分支并没有更新,本地只是多了一个不能操作的origin/serverfix 分支,必须要在本地的serverfix分支使用

git merge origin/serverfix

命令将远程分支的变化合并回本地分支

跟踪远程分支

假如远程分支不是自己创建的,则需要跟踪远程分支,假如其他人推送了一个新分支newBranch到远程仓库,则在调用git fetch origin时本地会出现一个origin/newBranch分支,使用

git checkout -b newBranch origin/newBranch

则本地会多一个newBranch分支,此时的分支叫跟踪分支,在跟踪分支里输入

git push

Git会自行推断应该向哪个服务器的哪个分支推送数据,在这些分支里运行

git pull

会获取所有远程索引,并把它们的数据都合并到本地分支中来,git pull相当于git fetch和git merge的组合,在克隆仓库时,Git通常会自动创建一个名为master的分支来跟踪 origin/master。这正是git push和git pull一开始就能正常工作的原因,跟踪分支可以和远程分支不同名:

git checkout -b anotherBranch origin/newBranch

删除远程分支

删除远程分支的命令是:

git push origin :serverfix

和推送远程分支的区别就是本地分支的名字为空

Git进阶用法

变基操作

如果有一个分支master,上面有两个提交A、B,此时开了一个新分支new,然后在new分支上提交了一系列提交,此时master也有了新提交,此时分支的情况如下图所示:

C new
/
A---B---D master

此时如果我们将new分支合回master分支,此时会在master分支上进行一次三方合并,生成一个新的提交D',现在分支的情况如下:

C new
/     \
A---B---D--- D' master

除了merge外,还有另一种整合两个分支的方法,就是rebase方法,回到合并new到master之前,假如在new分支上执行:

git rebase master

则分支的情况如下:

C---D’ new 
/       
A---B---D master

对master分支进行一次快进合并,现在的情况如下:

C---D’ new 
/       master
A---B---D 

此时相当于new分支是在D提交之后才开出来的分支,然后再提交了C提交,然后再做了一个补丁操作,再把master的指针移动到new分支指针的位置。使用rebase指令后,master和直接merge在内容上没有区别。

使用变基操作一般是想要得到一个能在远程分支上干净应用的补丁,比如某些项目你不是维护者,但想帮点忙的话,最好用变基:先在自己的一个分支里进行开发,当准备向主项目提交补丁的时候,根据最新的 origin/master进行一次变基操作然后再提交,这样维护者就不需要做任何整合工作,只需根据你提供的仓库地址作一次快进合并,或者直接采纳你提交的补丁。实际上是把解决分支补丁同最新主干代码之间冲突的责任,化转为由提交补丁的人来解决。

变基操作除了可以在分叉的两个分支上进行,也可以将分支上的分支rebase到主分支上,假如目前的分支情况如下:

E---F anotherBranch 
/
C---D oneBranch 
/       
A---B master

使用

git rebase --onto master oneBranch anotherBranch

此时的分支状况会变成

C---D oneBranch 
/       
A---B--C'--D'--E'--F' anotherBranch
|
master

变基操作虽然有用,但是最好是在还未同步到远程分支的本地分支上使用,不要在远程分支上使用。

变基操作的其他用途

当我们有了数个提交之后,突然发现其中的某一个提交是错的不想要了,或者想改变一下提交的顺序的时候,可以使用

git rebase -i [commitID]

-i 的意思是interactive,交互式操作的意思,例如当我们输入

git rebase -i HEAD~3

后,会出现如下的提示:

pick c24b68f3 删除节点崩溃
pick c1049e31 修改issue1087
pick b57a1f89 修改首页点击router图标数据错误issue

# Rebase 7a173fb4..b57a1f89 onto 7a173fb4 (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
~                                                                               
"~/Documents/mercku_ios/.git/rebase-merge/git-rebase-todo" 22L, 767C

这表明从当前指针往前数的三个提交被重新拿了出来,有机会能再次提交,注释中给出了提示pick代表使用本次提交,reword表示使用这次提交但是改变提交信息,sqush表示将这次提交与上次提交合并,并能改变提交信息,drop表示丢弃这次提交。
按command加i组合键进入编辑模式,可以修改关键字,修改完成以后按esc退出编辑模式,再按command加:,输入wq保存退出即可生效。

变基操作的其他用途

在利用github实现多人合作程序开发的过程中,我们有时会出现错误提交的情况,此时我们希望能撤销提交操作,让程序回到提交前的样子,总结了两种解决方法:回退(reset)、反做(revert)。

  1. 查看版本号:

git log

  1. 本地版本回退:

git reset --hard [commit id]

  1. 强制更新远程

git push -f

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • 入门配置 用户信息git config –global user.name Jason.Zeng 设置自己的用户名...
    Jason_Zeng阅读 547评论 0 0
  • 前言: git的各个流程如图 手册内容: git init # 初始化,表示在当前文件夹建立本地版本仓库进行版本...
    Gavininn阅读 281评论 0 1
  • 找回来未提交的版本代码 git reflog 我们要找回我们最晚的提交,只需要做如下操作: 查看未推送的提交版本号...
    CarlosLynn阅读 760评论 0 2
  • 版本控制工具有很多,比如 CVS、SVN[https://subversion.apache.org/]、Git[...
    越前君阅读 395评论 0 1
  • 项目开发中,管理代码 1.提交代码 git add . //提交所有文件 git commit -m "此处...
    龍吟丶阅读 253评论 0 0