Git使用手册

Git使用手册

0、前言

自用的Git使用手册。不适合Git入门,可以用于Git速查和复习。持续更新 …

1、创建Git版本库

在项目目录下:

git init

提示Initialized empty Git repository in xxx即表示成功创建一个Git repository(仓库)。初始化repository时不会自动track(跟踪)项目中的已有文件。

此时,打开项目目录,可以发现一个.git目录,记录git初始化信息和之后的版本信息,修改它可能导致版本丢失

2、添加文件到暂存区

使用git add命令将文件添加到暂存区中。实际使用中,可能添加单个、多个、某些、所有文件,可通过参数来实现。

  1. 添加指定文件到暂存区。git add后面跟文件名,支持单个或多个文件,适用于你修改了较少文件且记得每个文件名的时候,注意,即使文件被删除了,你也要add被删除的文件,这样暂存区才会记录它给删除了。

    git add file1.txt file2.txt
    

    可以多次使用git add来在不同时间添加不同文件,如上面可写成

    git add file1.txt
    git add file2.txt
    
  2. 添加所有文件。有时候,我们不清楚哪些被修改过了,那直接添加所有的文件最简单不过。

    git add -A    # all,添加全部被修改过的文件
    

    它等价于git add .git add *

  3. 添加某些文件。如果你想添加某些文件,一一列出文件名比较繁琐,可以使用通配符。

    git add *.txt   #添加所有后缀为.txt的文件
    
  4. 添加某个文件夹下的文件。如果add后的文件名是一个文件夹(/可有可无),它会自动添加该文件夹下的所有文件。

    git add dirname     
    
  5. 更新文件。“更新”一词是git对已经跟踪的文件而言,所有它不会添加untracked(未跟踪文件)的文件,即你新增的文件。

    git add -u
    

值得一提,你可能错误添加了某个你不想添加的文件,可以使用git reset HEAD filename达到加其从暂存区删除的效果。

3、提交到仓库

使用git commit命令将暂存区的文件提交到版本库,同时生成一个版本。

-m参数用于指定commit信息,是必须的,而且不能为空,如果漏了,git会自动打开文本编辑器要求输入。如果实在不想指定commit信息,可以使用git commit --allow-empty -m ""参数。这???还是-m "."省事。

  1. 经常地,会提交暂存区添加的文件到版本库:

    git commit -m "message"
    
  2. 可以直接把工作区的文件直接提交到版本库:

    git commit <filename> -m "message"
    

    该命令不会连同暂存区的文件一起commit。

  3. 如果想把上版本之后的修改全部commit,可以使用:

    git commit -am "add all files from working tree"
    

    省去git add .。当然上面用git commit . -m "message"也是可以。

一般来说,commit提交都会生成新的版本。如果某次提交后,发现add时漏了一个文件,或者文件有小差错,此时不想新增一个版本,而是对最近commit的版本的补充修改,可以使用--amend参数。设置了该参数的commit不会生成新的版本,而是更新修改上次commit的内容(包括文件和信息)。

  1. 如果上次commit时疏漏了file.txt,或者该文件有瑕疵,可以如下更新该文件:

    git add file.txt
    git commit --amend --no-edit
    

    这里--no-edit指明不修改commit信息。或者可以直接使用一条命令:

    git commit file.txt --amend --no-edit 
    
  2. 也可以修改commit信息,如:

    git add file.txt
    git commit --amend -m "message"
    
  3. 如果发现上次commit的时候信息写错了,想修改,可以在暂存区为空的情况下执行:

    git commit --amend -m "message"
    

4、查看信息

有很多git命令可以查看git版本控制相关的信息,这些信息对git的使用很有帮助。

4.1、文件状态

git status可查看文件状态信息, 该命令默认会显示所有未跟踪、在缓存区 、修改过的文件:

Git使用手册_第1张图片

上面file1.txt出现在两处是因为在执行git add之后又修改了。

git status filename可以接查看指定文件的状态信息。

4.2、版本日志

git log可查看版本日志。会显示版本的哈希码、提交人、提交message、提交时间等信息。按q可退出日志。

Git使用手册_第2张图片

使用git log --graph会以树状图的形式展示分支,更加清晰明了。

4.3、文件比较

git diff可以查看文件差异,跟踪我们修改了文件什么内容。

Git使用手册_第3张图片

默认会列出所有暂存区/工作区有区别的文件,命令后面接文件名git diff filename可以查看特定文件。

可以使用参数查看别处的文件差异对比,如下:

  1. git diff --cached    #查看仓库与暂存区的差异
    
  2. git diff HEAD #查看仓库与工作区的差异
    
  3. git diff [<commit-id>] [<commit-id>]  #比较两个commit之间的差异
    
  4. git diff branch1 branch2  #比较两个分支之间的差异
    

4.4、操作记录

git reflog可以查看所有分支操作记录,包括被删除的版本或分支的记录。

5、版本穿梭

一个项目在在上个版本能正常运行,修改文件之后,发现运行不了,又找不到是修改了哪里导致的问题,这时候,庆幸用了git版本记录,回退到上个版本就行了。

git reset命令可以进行版本穿梭。

在此之前,了解HEAD指针,默认地,它总指向最新的一次commit,可以理解为它指向当前版本。版本切换的本质就是改变HEAD指向的commit,从单词reset也是reset HEAD之意。

除了第一个commit,每一个commit都有且仅有一个前继commit,也就是有明确的上一版本,并且每个版本也会记录其前继版本。HEAD^表示前一版本,HEAD^^HEAD~2表示上上版本,HEAD^^^HEAD~3表示往前3个版本,以此类推。

每个commit都有对应的commit id,用于表示每次commit,它是一串长长的十六进制哈希码。

现在,可以开始随意的版本切换了。

最常用的,就是回退到上一个版本:

git reset HEAD^

如果不想数往上多少个版本,可以通过指定commit id进行切换,commit id很长,但一般指定4位就够了。如:

git reset 8c6a     #commit id全长:8c6a47caf4de1d9e227a89e6421db4fd03a87ba9

因为git没有记录下继版本,所以,当你回退到某个版本之后,使用git log发现只有在当前commit之前的commit,而之后的commit丢失了。是的,回退之后,不能再前进。虽然丢失了,但并没有被删除,通过git reflog可以检出HEAD的指向的历史commit,包括丢失了的,从中获取commit id,通过git reset commit-id就可以跳到该版本了。

如果细心点,会发现使用git reset的过程中,工作目录中的文件并没有变化。这涉及到一个问题,版本切换的时候,想把工作目录的文件与目标版本一致吗?暂存区要恢复到什么状态?还是只想更改HEAD指针而已?reset的mode参数指明了这个。reset有三种模式,默认--mixed, 还有--hardsoft

  1. git reset --soft HEAD^。只把HEAD指针指向上一版本,暂存区和工作区文件都不变化。
  2. git reset --hard HEAD^。把HEAD指针指向上版本,工作目录和文件和指定版本一致,暂存区清空。
  3. git reset --mixed HEAD^。把HEAD指针指向上版本,工作目录不变,暂存区清空,即所有在目标commit之后add到暂存区的文件都会变成unstaged。

如果指向恢复某个文件,可以使用git checkout命令。

  1. 撤销工作区对文件的修改:

    git checkout <filename>
    

    git的修改是指相对于上次add到暂存区而言的。如果你最近commit之后没有add该文件,它会恢复到HEAD指向的commit,如果被add过,则恢复到与暂存区一致。

  2. 指定了commit之后,工作区和暂存区的文件都会和commit保持一致。

    git checkout HEAD <filename>
    

6、分支管理

分支(branch)是Git中极为重要的概念,分支上的工作不会影响主线,保证了多人开发的并发性。git默认分支称为主分支(master)。想查看分区,可以使用命令

git branch

如果还没有创建任何分支,只会看到master主分支。

6.1、创建分支

git branch接分支名可以创建一个新分支。

git branch branchA	 # 创建分支branchA

可以用git branch查看分支,此时*在master前面,说明当前所在的分支为master,也就是上面的命令不会自动转到新建分支。

6.2、切换分支

很自然的,你想要到新分支下工作。可以使用git checkout切换分支。

git checkout branchA

再使用git brach看看*号的位置。

经常都是想到新分支上工作才创建新分支的,可以使用参数-b在创建后自动切换到该分支上。

git checkout -b branchB

我一开始以为是git branch -b branchname。。。好吧,这条命令不是"创建并切换", 它意思是"切换到该分支,如果分支不存在,新建后再切换",然后我试着用一个已存在分支切换,无法执行,提示“该branch已存在”。意思还是“创建并切换”,那我就搞不懂这个事为什么不归git branch管了。

6.3、合并分支

当某个分区支的工作完成后,需要把它和master分支合并起来,使用git merge可以合并分支。

git merge branchB

合并后HEAD仍然指向当前分支。所以,一般会先切换到master,在master上与分支合并,然后删除分支。

如果两个分支存在祖先关系,即一个分支是另一个分支的祖先,Git会采用Fast-forward合并方式。

假设在master上创建并切换到一个新分支newbranch,没有切换到newbranch分支,而是在master上做了文件修改并commit后,发现本来是想在newbranch做这些修改的,那这时候,能直接在master上使用git merge newbranch合并吗?结果newbranch并没有被合并,而是提示已是最新。想要合并二者,必须切换到newbranch上执行git merge master。从使用者意图来说,我们希望Fast-forward总是把旧的分支合并到新分支上。但是,从设计上来说,允许前者以为着在当前分支上修改了另一个分支,这是不合适的,显然这里采用了后者,保证merge命令只是修改HEAD指向的分支指向。

如果两个分支分别commit过,git会合并到一个新commit,当前分支指向新commit,而被合并的分支不变。此时采用three-way-merge的方式,即根据公共祖先、当前分支、被合并分支比较合并。合并原理可以看怎么理解Git里的 “three-way merge” ? - Lazykid的回答 - 知乎。

6.4、解决冲突

然而,合并过程往往不是一帆风顺。如果两个分支对同一个文件的同一地方做了不同的修改,git无法明确该采用哪个文件。这种情况也就是出现了冲突。

出现冲突的时候,Git不会生成合并commit,而是进入冲突待解决状态,可以使用git status查看。冲突文件被标记为冲突的,产生冲突的地方使用<<<<< ===== >>>>>标记出来。此时,你必须解决冲突或者中断本次合并。放弃合并使用git merge --abort

冲突需要手动解决。也就是修改文件上标记的地方。修改完之后,使用git add命令告诉git你已经解决了冲突。然后使用git commit完成合并。

假设某次尝试合并的过程中file.txt产生冲突。手动修改file.txt之后,使用:

git add file.txt
git commit -m "merge message"

即可完成合并。

6.4、删除分支

合并之后,分支的任务一般就结束了,应该删除该分支。即使开发新功能,也是新建一个branch。下面命令删除分支newbranch

git branch -d newbranch

前提是HEAD不指向newbranch。

7、远程仓库

以Github为例。

7.1、创建远程仓库

7.1.1、设置ssh密钥

初次使用github时,为了本机的推送都可以不用账号密码通过验证,需要创建SSH密钥对。

在电脑cmd上创建密钥对:

ssh-keygen -t rsa -C "[email protected]"

登录github,在个人设置里面,把公钥码复制到上面。

7.1.2、创建github仓库

github 创建仓库很简单,按照指引就行。

7.2、向远程库推送

7.2.1、首次推送

创建github仓库之后,本地仓库需要与远程仓库建立连接。

git remote add origin <your repository url>

建立连接之后就可推送到远程库了。

git push -u origin master

查看远程库,确实推上去了。

7.2.2、后续推送

因为在首次推送之后,本地与远程仓库已经建立连接,所以可以简化命令,直接使用:

git push origin master

7.3、从远程库克隆

把远程库内容克隆到本地:

git clone <your repository url>

7.4、从远程库拉取分支

使用

git fetch origin <branch name>

可以从远程库拉取分支。

拉取的分支以origin/xxx存在,需要用git branch -a才能看到。拉取分支并不会对本地工作产生影响,相当于新建了一个分支。

如果想把远程分支跟本地分支合并,可以使用git merge origin/master

或者直接使用

git pull origin <branch name>

可以实现上面拉取并合并的效果。当然,合并可能会产生在本地分支合并过程中的冲突,用同样的方式解决即可。

多人协作时,如果推送失败,需要先拉取,再推送。

8. 其它

8.1、保存本地修改

git stash       #保存本地修改
git stash list  #查看stash列表
git stash apply #应用最新的stash
git stash apply stash@{1} #应用特定stash
git stash drop  #删除最新stash
git stash drop stash@{1} #删除特定stash
git stash pop   #应用并删除最新stash

8.2、复刻commit

在其它分支上完成的工作可能对目前工作有帮助,如bug消除,在别的分支消除bug并commit之后,本分支无须重复一次工作,使用:

git cherry-pick commit-id

在本分支上复刻其它分支的commit。

8.1、保存本地修改

git stash       #保存本地修改
git stash list  #查看stash列表
git stash apply #应用最新的stash
git stash apply stash@{1} #应用特定stash
git stash drop  #删除最新stash
git stash drop stash@{1} #删除特定stash
git stash pop   #应用并删除最新stash

8.2、复刻commit

在其它分支上完成的工作可能对目前工作有帮助,如bug消除,在别的分支消除bug并commit之后,本分支无须重复一次工作,使用:

git cherry-pick commit-id

在本分支上复刻其它分支的commit。

你可能感兴趣的:(Git)