Git指令学习笔记

rebase

多人在同一个分支上协作时,很容易出现冲突。即使没有冲突,后push的童鞋不得不先pull,在本地合并,然后才能push成功。那么怎么才能让提交历史变得干净,易读呢?可以使用rebase对某一段线性提交历史进行编辑、删除、复制、粘贴;因此,合理使用rebase命令可以使我们的提交历史干净、简洁!




$ git rebaseFirst, 

rewinding head to replay your work on top of it...Applying:add commentUsingindex info to reconstruct a base tree...Mhello.pyFallingback to patching baseand3-way merge...Auto-merging hello.pyApplying:add authorUsingindex info to reconstruct a base tree...Mhello.pyFallingback to patching baseand3-way merge...Auto-merging hello.py


reset

git reset命令用于将当前HEAD复位到指定状态。一般用于撤消之前的一些操作(如:git add,git commit等)。

git reset [-q] [] [--] …​

git reset (--patch | -p) [] [--] […​]

git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] []

在第一和第二种形式中,将条目从<tree-ish>复制到索引。 在第三种形式中,将当前分支头(HEAD)设置为<commit>,可选择修改索引和工作树进行匹配。所有形式的<tree-ish>/<commit>默认为HEAD。

这里的HEAD关键字指的是当前分支最末梢最新的一个提交。也就是版本库中该分支上的最新版本。

在git的一般使用中,如果发现错误的将不想暂存的文件被git add进入索引之后,想回退取消,则可以使用命令:git reset HEAD <file>,同时git add完毕之后,git也会做相应的提示,


Submodule

当项目越来越庞大之后,不可避免的要拆分成多个子模块,我们希望各个子模块有独立的版本管理,并且由专门的人去维护,这时候我们就要用到git的submodule功能。

常用命令

git clone <repository> --recursive 递归的方式克隆整个项目

git submodule add <repository> <path> 添加子模块

git submodule init 初始化子模块

git submodule update 更新子模块

git submodule foreach git pull 拉取所有子模块


创建project版本库,并提交readme.txt文件

git init --bare project.git

git clone project.git project1

cd project1

echo "This is a project." > readme.txt

git add .

git commit -m "add readme.txt"

git push origin master

cd ..

创建moduleA版本库,并提交a.txt文件

git init --bare moduleA.git

git clone moduleA.git moduleA1

cd moduleA1

echo "This is a submodule." > a.txt

git add .

git commit -m "add a.txt"

git push origin master

cd ..

在project项目中引入子模块moduleA,并提交子模块信息

cd project1

git submodule add ../moduleA.git moduleA

git status

git diff

git add .

git commit -m "add submodule"

git push origin master

cd ..

2. 克隆带子模块的版本库

方法一,先clone父项目,再初始化submodule,最后更新submodule,初始化只需要做一次,之后每次只需要直接update就可以了,需要注意submodule默认是不在任何分支上的,它指向父项目存储的submodule commit id。

git clone project.git project2

cd project2

git submodule init

git submodule update

cd ..

方法二,采用递归参数--recursive,需要注意同样submodule默认是不在任何分支上的,它指向父项目存储的submodule commit id。

git clone project.git project3 --recursive

 修改子模块

cd project1/moduleA

git branch

echo "This is a submodule." > b.txt

git add .

git commit -m "add b.txt"

git push origin master

cd ..

git status

git diff

git add .

git commit -m "update submodule add b.txt"

git push origin master

cd ..

更新子模块

方法一,先pull父项目,然后执行git submodule update,注意moduleA的分支始终不是master。

cd project2

git pull

git submodule update

cd ..

方法二,先进入子模块,然后切换到需要的分支,这里是master分支,然后对子模块pull,这种方法会改变子模块的分支。

cd project3/moduleA

git checkout master

cd ..

git submodule foreach git pull

cd ..

5. 删除子模块

网上有好多用的是下面这种方法

git rm --cached moduleA

rm -rf moduleA

rm .gitmodules

vim .git/config

删除submodule相关的内容,例如下面的内容

[submodule"moduleA"]      url =/Users/nick/dev/nick-doc/testGitSubmodule/moduleA.git

然后提交到远程服务器

git add .

git commit -m "remove submodule"


.reflog

  如果在回退以后又想再次回到之前的版本,git reflog 可以查看所有分支的所有操作记录(包括commit和reset的操作),包括已经被删除的commit记录,git log则不能察看已经删除了的commit记录

Administrator@USER-20171026MG MINGW64 ~/Desktop/lyf (master)

$ git reflog

e1bdff6 (HEAD -> master) HEAD@{0}: commit: 第二次提交

62e6739 HEAD@{1}: reset: moving to HEAD^

8113f0d HEAD@{2}: reset: moving to HEAD^

dc6bb4e HEAD@{3}: reset: moving to dc6bb4e

8113f0d HEAD@{4}: reset: moving to HEAD^

dc6bb4e HEAD@{5}: commit: my.txt增加44444内容

8113f0d HEAD@{6}: commit: 文件增加33333内容

62e6739 HEAD@{7}: commit (initial): my第一次提交



执行git blame;命令时,会逐行显示文件,并在每一行的行首显示commit号,提交者,最早的提交日期

给具体文件执行$git blame后的效果如下

6c2414fb (liangfei 2014-05-12 05:32:01 -0400  1) from markdown import markdown

be442bb4 (liangfei 2014-05-09 10:26:27 -0400  2) from django.shortcuts import render

be442bb4 (liangfei 2014-05-09 10:26:27 -0400  3) from django.core.paginator import Paginator, InvalidPage, EmptyPage

be442bb4 (liangfei 2014-05-09 10:26:27 -0400  4) from blog.models import Post, Category

be442bb4 (liangfei 2014-05-09 10:26:27 -0400  5)

be442bb4 (liangfei 2014-05-09 10:26:27 -0400  6)

be442bb4 (liangfei 2014-05-09 10:26:27 -0400  7) def category(request, cat_name, page_num=1):

be442bb4 (liangfei 2014-05-09 10:26:27 -0400  8)    if cat_name.lower() == 'home':

be442bb4 (liangfei 2014-05-09 10:26:27 -0400  9)        posts = Post.objects.all().order_by('-date')

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 10)    else:

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 11)        posts = Post.objects.all().filter(category__name=cat_name).order_by('-date')

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 12)

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 13)    paginator = Paginator(posts, 3)

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 14)    try:

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 15)        page = int(page_num)

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 16)    except ValueError:

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 17)        page = 1

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 18)

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 19)    try:

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 20)        posts = paginator.page(page)

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 21)    except (InvalidPage, EmptyPage):

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 22)        posts = paginator.page(paginator.num_pages)

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 23)

6c2414fb (liangfei 2014-05-12 05:32:01 -0400 24)    for post in posts:

6c2414fb (liangfei 2014-05-12 05:32:01 -0400 25)        post.body = markdown(post.body)

6c2414fb (liangfei 2014-05-12 05:32:01 -0400 26)

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 27)    return render(request, 'blog/index.html',

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 28)                  {

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 29)                      'posts': posts,

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 30)                      'cat_now': cat_name,

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 31)                      'cat_all': map(lambda cat: cat.name, Category.objects.all())

be442bb4 (liangfei 2014-05-09 10:26:27 -0400 32)                  })


git stash 的作用

git stash用于想要保存当前的修改,但是想回到之前最后一次提交的干净的工作仓库时进行的操作.git stash将本地的修改保存起来,并且将当前代码切换到HEAD提交上.

通过git stash存储的修改列表,可以通过git stash list查看.git stash show用于校验,git stash apply用于重新存储.直接执行git stash等同于git stash save.



开发到一半,同步远端代码

当你的开发进行到一半,但是代码还不想进行提交 ,然后需要同步去关联远端代码时.如果你本地的代码和远端代码没有冲突时,可以直接通过git pull解决.但是如果可能发生冲突怎么办.直接git pull会拒绝覆盖当前的修改.

遇到这种情况,需要先保存本地的代码,进行git pull,然后再pop出本地代码:

git stash

git pull

git stash pop

工作流被打断,需要先做别的需求

当开发进行到一半,老板过来跟你说"线上有个bug,你现在给我改好,不然扣你鸡腿".当然,你可以开一个新的分支,把当前代码提交过去,回头再merge,具体代码如下

繁琐的工作流示例# ... hack hack hack ...git checkout -b my_wip git commit -a -m"WIP"git checkout master edit emergency fix git commit -a -m"Fix in a hurry"git checkout my_wip git reset --soft HEAD^# ... continue hacking ...

我们可以通过git stash来简化这个流程

正确姿势# ... hack hack hack ...git stash//保存开发到一半的代码edit emergency fix git commit -a -m"Fix in a hurry"git stash pop//将代码追加到最新的提交之后# ... continue hacking ...

提交特定文件

如果对多个文件做了修改,但是只想提交几个文件,或者想先暂时保存几个修改,测试其他文件的执行结果.可以通过git stash save --keep-index来进行.

# ... hack hack hack ...git add --patch foo//只将第一部分加入管理the indexgit stash save --keep-index//将其余部分保存起来edit/build/test first part git commit -m'First part'//提交全部的git管理中的代码git stash pop//继续进行存储代码的工作# ... repeat above five steps until one commit remains ...edit/build/test remaining parts git commit foo -m'Remaining parts'

恢复被错误clear/drop的存储

如果因为失误对存储仓库进行了clear或者drop操作,在一般机制下是不能恢复的.但是可以通过以下指令来获取仍在仓库中的,但是已经不可获取的存储列表

git fsck --unreachable |grep commit | cut -d\  -f3 |xargs gitlog--merges --no-walk --grep=WIP



git fetch

git fetch从远程分支拉取代码。

fetch常结合merge一起用,git fetch + git merge == git pull

一般要用git fetch+git merge,因为git pull会将代码直接合并,造成冲突等无法知道,fetch代码下来要git diff orgin/xx来看一下差异然后再合并。

作者:忆飞

链接:https://www.jianshu.com/p/a5c4d2f99807

来源:简书

简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容