git随记

写作思路

  • git历史简介

  • git原理简介

  • git使用场景举例

  • git命令随记

分个人篇和社区篇写

git概念:
工作区--workspace 暂存区 -- stage/index 版本库 -- repository
查看以上三者的文件树:

  1. ll --fulltime
  2. git ls-tree -l master => 查看tree object内容,非raw content
  3. git ls-files -s=>暂存区的文件

git cat-file -s =>查看文件大小
或者
git write-tree
git ls-tree -l
repository object

git对象种类:
commit tree blob

git的hash设计可以保证每一个版本的文件都有唯一的hash值,生成策略是commit/tree/blog+size+\000(null)+content,即使用文件大小和文件内容生成sha1sum,生成时机是添加到index上时。

git hash的sha1生成原理见《git权威指南》6.2

常用命令

git branch ---- 列出所有分支,-r(remote branch) -a(local and remote branch)
git branch feture1 --- 新建一个分支feture1
git checkout feture1 --- 切换到分支feture1
git status ---- 查看目前分支下文件控制情况
git -d/-D feture1 --- 删除分支feture1,d会检查feture1是否已经merge到其父分支,如果没有,不予删除。D直接删除
git log -1 --stat --- 查看log信息,最近1条
git log --oneline
git whatchanged --- 显示文件变化情况
git add test --- 添加test到index上
git add -u/-i => add files in index
git add -a =>add all files with modified and new
git reset --test ----作用与add相反,将test reset到某个commit版本,即自该版本之后的所有更改需要重新提交。不是信息回滚,保留当前文件内容,只是给予了再次提交文件的机会,可以借机修改提交信息,整理文档。
git commit test -m"add file test" --- 提交test文件到版本库
git commit -a -m"all changes"
git commit --amend --- 合并到上一次的提交中

git merge feture1 --- 合并并提交feture1的所有版本到当前分支,如果当前分支自建立feture1后无更改,则启动fastforward,可以添加参数--no-ff关闭该效果
git merge --squash feture1 ---- 不合并feture1的所有版本到当前分支,而是将其文件变化合并,由用户决定再次提交一个版本,该命令可以保证主分支的整洁。
git commit -v ----可以查看diff内容

git ls-tree master

开启分支,合并的常用命令

git branch feture1

git checkout feture1

git add file
git commit ..

git checkout master

git merge --squash --no-ff feture1

git commit -v

git branch -d feture1

取消某些错误提交

git reset file

git diff =>比较工作区和暂存区的差异
git diff master => 比较工作区和master的差异

git diff --cached =>比较暂存区和HEAD的差异

git diff --cached master => 比较暂存区和master分支比较

git commit -m"revert file"

撤销某一此commit造成的影响

git log --oneline
git revert

回到某一次commit

git reset

使用git checkout file,即可将文件回复到以前的状态

git reflog

git reset HEAD@{1}

git reset --hard ---彻底回退到某一个版本,所有文件退回,不保存当前文件的内容此时只能通过上面的方式回去。

--soft 只回退commit信息,index文件仍然会保留,即直接commit就可以,不用add

--mixed 回退commit信息和index文件,源码保留,需要add了之后才能commit

分支合并上游分支的代码变化

git checkout feture1

git rebase master

这样master的代码修改就可以在feture1中使用了

临时保存代码

git stash

git stash apply

修改到一半的代码,又需要临时切换回去修改bug,此时派上用场

远程协作

git clone user@url:/path [local] #clone一个镜像

git branch -a #查看所有分支

git checkout branch_name #进入分支查看

git fetch origin master # fetch是把远程分支和提交信息等抓取下来,将FETCH_HEAD指向该分支
git merge origin/master #也可以改为FETCH_HEAD

后面三条可以改用pull
git pull origin master #默认执行git merge FETCH_HEAD,存在fastforward的可能
但推荐用fetch,还有机会决定是否提交

在此时使用git reset HEAD^会回退两个commit,估计是因为merge的commit版本是自动生成的原因

git fetch orgin master:test
直接check到新分支test,否则是FETCH_HEAD

一般pull下orgin/master,然后在自己的分支上,rebase一下即可
git checkout branch
git pull origin master
git rebase master

merge后取消操作

git reset --hard

打tag

git tag =>显示所有的tag
git tag v1 =>打一个轻标签v1,无附带信息
git tag -a v1 -m"version1" => 打一个附注标签,推荐方法
git tag -d v1 =>删除标签
git tag -a => 给某一个commit版本打标签

git checkout v1 => 切换到v1的tag,但是做的所有更改不会予以记录,必须git checkout -b newbranch才可以。

git push origin v1 => 将标签v1提交到git服务器
git push origin -tags => 将本地所有标签一次性提交到git服务器

重写提交说明

git commit --amend => 可以修改上一次的提交说明

git rm => remove a file from workspace and index
git rm --cached => reomve a file from index/stage,change file to be untracked

git checkout . git checkout -- =>使用stage的file来替换workspace的file
git checkout . git checkout => 使用版本库的file来替换workspace的file和暂存区的file,意味着未提交的内容被丢弃

git commit -a => 应该避免使用,因为它丢掉了通过缓冲区对内容提交进行控制的能力

git stage上的更改,在切换分支后依然保留????

git ls-tree == git cat-file -p

git cat-file -t/-p=> repositroy object

git cat-file commit/blob/tree =>查看某个提交版本的情况

恢复删除的文件

删除了一个文件后,想要恢复,结合checkout和add命令即可恢复。
git checkout HEAD~1 -- file
git add -A

或者高阶用法

git cat-file -p HEAD~1:file > file
从blob对象中取出数据放入新建的文件中。

移动文件

git mv file file2

Git忽略语法

.gitignore文件编写,可以忽略自身。

.a #忽略.a的文件
!lib.a #不要忽略lib.a
/TODO #忽略此目录下的TODO文件,子目录下的TODO文件不忽略
build/ #忽略所有build/目录下的文件
doc/
.txt #忽略文件入doc/notes.txt,但是子目录下的txt不被忽略
.gitignore

打包发布

git本身提供栏打包命令,如下:

基于最新提交建立归档文件latest.zip
git archive -o latest.zip HEAD

只将目录src doc建立到归档partial.tar中。
git archive -o partial.tar HEAD src doc

基于里程碑(tag)v1.0建立归档,并且为归档中的文件添加目录前缀1.0。
git archive --format=tar --prefix=1.0/ v1.0 |gzip > foo-1.0.tar.gz

GitHub使用的相关命令

  • create a new repository in github, such as helloworld. Then you will get an address "git@github.com:rockybean/helloworld.git".
  • In your own workspace, use the following commands.

    mkdir helloworld;
    git init;
    touch README.md
    cat "haha" >> README.md
    git add -A/-u
    git ss
    git la
    git ci -m""
    git remote add origin ""
    git push [-u] origin master
    git ci --amend [--reset-author] [-C HEAD]
    git push -f => force push

    Branch管理:.git/refs/heads
    git checkout -b newbranch
    git push -u origin newbranch => 默认会在本地建立一个对应远程的分支,所以直接git push是可以提交的。

    git branch -d/-D newbranch

    git push origin :newbranch => 删除远程分支,该分支不能是默认分支

    Tag管理:.git/refs/tags
    一共有三种创建方式:
    轻量级创建:git tag [commit] => 创建的引用直接指向一个commit对象,
    带说明的里程碑: git tag -a [] => 创建一个tag对象保存里程碑说明、里程碑的指向、创建里程碑的用户信息等,而tag引用指向该tag对象。
    带签名的里程碑: git tag -s [] => 在上面的基础上引入PGP签名,保证tag的完整性和不可拒绝性。

    -m添加附注
    
    example:
        git tag -m "msg tag0" tag0 HEAD^
        git tag -m "msg tag0" -a tag0 HEAD^
        git tag mytag3
    
        git tag -l -n1
    
        git push origin refs/tags/*
    
        git tag -d tag0
    
        git push origin :tag0 => delete tag from remote server
    

github pull request记录

clone一个源码

修改之后,创建一个pull-request即可

收到一个pull-request,一般不用网络提供的方法,在命令行自己完成更好

git remote add alfredway url
git fetch url/alfredway

git merge alfredway/master

git pull alfredway master

git fetch origin master => store the fetched tip in FETCH_HEAD,not origin/master. to update origin/master,use fetch origin.
git merge FETCH_HEAD

git fetch url => 抓取所有分支t

git rebase/merge都是合并命令

merge不是线性的,即一旦merge了一定会产生一个新的commit对象;而rebase可以线性提交,不产生新的commit信息

git rebase遇到冲突时,解决后,git rebase --continue即可,如果放弃了--abort,如果使用分支的信息,--skip
--interactive可以交互式操作

git rebase branch=>当前分支为master,该命令相当于将master与branch共同祖宗节点开始的master修改文件的patch打到branch后面,提交是以master的commit进行的,最后master的指针指向的依然是其之前的commit变化,只不过commit对象的sha值不同了而已,当然打patch的过程中是会遇到冲突的。

git rebase适用与冲突不多,因为它可能要改好几次冲突(同一个文件被多次commit修改),不会产生额外的merge信息;merge适合冲突多,只要改一次就可以,会产生额外的merge信息。
"rebase", as in "replay my work in my branch starting from a recent point from the branch B

rebase和merge结合使用:
你开发一个branch好了,想merge到master,并且push
git co branch
git rebase master
git co master
git merge branch => use fast forward merge
git push
一般这样都是可以提交成功,否则就-f

远程分支,可以先check下来
git fetch url master:newbranch
之后进行同样的操作的,使得分支的变化在最上面

**push 本地分支a到远程分支b
git push github a:b

**some command learned later

git remote -v

git show

git blame

git show 显示某次提交的信息

git show HEAD
显示master分支的版本信息
HEAD代表当前分支的头(也就是最近一次commit)
每一次commit都会有”parent commit”,可以使用^表示parent:

git show HEAD^ //查看HEAD的父母的信息
git show HEAD^^ //查看HEAD的父母的父母的信息
git show HEAD~4 //查看HEAD上溯4代的信息

要注意的是git-merge是会产生双父母的,这种情况这样处理:
git show HEAD^1 //查看HEAD的第一个父母
git show HEAD^2 //查看HEAD的第二个父母

git merge-base commit1 commit2 确定commit1 和 commit2的父commit

git 实现文件read-only属性的方法

使用 git update-index --skip-worktree [file] 可以实现修改本地文件不会被提交,但又可以拉取最新更改的需求。适用于一些不经常变动,但是必须本地化设置的文件。

另外还有 git update-index --assume-unchanged [file] 该命令只是假设文件没有变动,使用reset时,会将文件修改回去。

参见链接

You need:

git update-index --really-refresh --no-assume-unchanged Makefile
That will make any local modification to Makefile "invisible" to git, while keeping Makefile under source control.

链接说明了如何避免reset的时候把文件替换掉,方法是使用work-tree

update-index with the assume-unchanged is meant to be used to increase performance if your tree on your OS's file system takes a long time to gather changes for a particular path. I would not recommend using it in your case unless you are ignoring those files due to lengthy git status or git diff or other command execution times.

assume-unchanged vs skip-worktree

git ignore文件

  1. 在.gitignore中添加文件,如果已经被管理了,那么闲使用git rm [-r] --cached [file/dir] 删除,然后就会生效。注意.gitignore可以用于版本管理,git是不会上传空文件夹的,此时可以使用空的.gitignore文件来上传。

  2. 在.git/info/exclude里面设置,这是本地的管理

github ignore

git大小写命名修改

git默认忽略大小写,即如果只是把文件名由大写改为小写,git会不记录该变化。配置core.ignorecase=false,既可以区别大小写,如果不想这样的话,可以执行如下命令:

mv Abc Abc.temp
git add .
mv Abc.temp abc
git add .
git ci

这样就可以提交大小写命名修改了。

如果遇到无法切换的远程分支,那么使用如下命令
git co -b web origin/web

将本地当前分支与远程分支关联

git br --set-upstream-to origin/branch
git br -u origin/branch

查看文件的所有历史,包含merge branch的提交

git log -- file 的时候不会显示merge产生的修改,如果要查看所有的log,使用下面的命令
git log --full-history -- file

在当前分支做squash操作

git rebase -i HEAD~3
然后交互操作即可

标签: git

添加新评论