git 使用笔记
git原理:
文件(blob)对象,树(tree)对象,提交(commit)对象
tree对象 : {指针,权限模式,类型,文件名}
commit对象: {上层tree指针,作者,时间戳,上次提交对象id,注释} 可通过git log 获取
文件对象blob:{文件内容}
- Git保存文件完整内容。
- 储键值对key-value。
- 文件的不同版本,都有一个(40位)的 SHA-1校验和与之对应。
- SHA-1 校验和是文件的指针,Git依靠它来区分文件。
- 每一个文件都会在Git的版本库里生成blob对象来保存。
- 对于没有变化的文件,Git只会保留上一个版本的指针。
- Git实际上是通过维持复杂的文件树来实现版本控制的。
- 使用Git的工作流程基本就是就是文件在三个工作区域之间的流动。
- 应该大量使用分支进行团队协作。
- 分支只是对提交对象的一个引用。
SHA-1 校验和:
是文件指针,每个文件不同版本都有一个指针对应
分布式版本控制
默认分支是master,存储在.git\refs\heads\master文件中
引用就是SHA-1 校验和的别名,存储在.git/refs文件夹中
引用master,Git默认创建的始终指向你项目主分支的最后一次提交记录
创建分支只是copy一份引用,非常轻量,只有commit提交操作是重量的
git commit 文件改变 生成新的blob对象 存入一份新的文件快照
git commit 文件未改变 存入上一版本的文件指针
当前分支的最后一次的提交ID cat .git/HEAD
tag指向一个commit对象,固定不变的。
存储键值对(key-value)
工作目录,暂存区域,以及本地仓库
已提交(committed),已修改(modified)和已暂存(staged)
git config 配置
换行符问题:
Windows(\r\n)、Linux(\n)和MacOS(\r)三个系统的换行符不同,在跨平台合作的时候就会出现换行符的问题。 Git 提供了 autocrlf 和 safecrlf 两个参数来解决这个问题。
例如,出现这种情况: A和B两个开发人员,A使用LF(\n)做换行符,B使用CRLF(\r\n)做换行符,且都没有开启 autocrlf 参数,那么A在迁出B的文件,并使用自己的编辑器打开之后就会发现,虽然没有对文件做任何修改,但它的状态是modified。这是由于A的编辑器自动将B的文件中的所有换行符替换成了(LF),这与版本库中的(CRLF)不同。
autocrlf:
git config --global core.autocrlf true # 签出时将换行符转换成CRLF,签入时转换回 LF。
git config --global core.autocrlf input #签出时不转换换行符,签入时转换回 LF
git config --global core.autocrlf false #签出签入均不转换
safecrlf:
如果你把换行符搞乱了,在一个文件中既包含windows风格的换行符也包含unix风格换行符。
git config --global core.safecrlf true # 拒绝提交包含混合换行符的文件
git config --global core.safecrlf false # 允许提交包含混合换行符的文件
git config --global core.safecrlf warn # 提交包含混合换行符的文件时候给出警示
问题描述
项目组现在用git做版本控制,使用中遇到不同平台下换行符不同造成的问题,windows下的换行符为crlf,linux和MAX OS 下换行符是 lf。linux和MAX os就按说明设置为core.autocrlf input(貌似是默认值),windows设置为core.autocrlf true。可是有时候还是会遇到换行符的问题。review的时候就会发现有的commit的变化是所有行都被删除重建
解决方案:
无论什么系统,把所有人的编辑器的换行符模式设置成Unix格式,然后把autocrlf设置成false。
修改git设置 core.autocrlf=input.检出时不转换,提交转换为lf,这样可以避免提交windows换行符的情况;
修改eclipse设置 windows>General> workspace 下 new text file line delimiter 选择Unix。
已有的项目可能已经存在换行符不同的问题需要修正一下。 如果当前开发有多个分支且各分支不同步,需要每个分支进行一次转换:选中项目 file> convert line delimiter to > Unix ,创建新的commit; 如果只有一个分支或多个分支处于同一节点。可以从master切换一个新分支,进行第2步的修改操作,然后commit ,将此分支合并到所有分支。
将修改过的分支push到gitlab,其他成员更新代码即可。 (ps:由于每个人系统不同或者就是git的问题,可能出现更新完代码换行符不变,这时以服务器上的代码为准重新clone一份最新代码即可)
.ignore文件
*.html #忽略所有html
!foo.html # 不忽略foo.html
*.[oa] # 忽略所有.o和 .a文件
dbg # 忽略dbg文件和dbg目录
dbg/ # 只忽略dbg目录
!dbg/ #不忽略dbg目录
/dbg # 只忽略当前目录下的dbg文件和目录,子目录的dbg不在忽略范围内
错误解决方案:注意带sudo
git Please move or remove them before you can merge. 错误解决方案
git clean -d -fx ""
x -----删除忽略文件已经对git来说不识别的文件
d -----删除未被添加到git的路径中的文件
f -----强制运行
修改git commit 提交
- 没有git push : git commit --amend参数
- 已 git push :
git commit --amend改写单次commit
git rebase -i
git checkout
git reset [--hard]
git revert
git push -f
https://github.com/uolcano/blog/issues/12
git pull****失败当本地commit一个提交和远端服务器中的代码有冲突(别人也改了相同的文件)时
git pull --rebase
- 把本地 repo. 从上次 pull 之后的变更暂存
- 恢复到上次 pull 时的状态
- 合并远端的变更到本地
- 最后再合并刚刚暂存下來的本地变更
git rebase 合并
rebase的时候,修改冲突后的提交不是使用commit命令,而是执行rebase命令指定 --continue选项。若要取消rebase,指定 --abort选项。
$ git add myfile.txt
$ git rebase --continue
git stash 保存工作区
保存:git stash 保存当前操作 git stash save “msg”
查看:git stash list
恢复: git stash apply
git stash pop
删除: git stash drop
git stash clear 清空所有记录
git diff
git diff HEAD^^ HEAD main.c //两个提交之间查看文件" main.c"的差异
你还可以在两个不同版本中比较两个不同的文件,如下所示:
git diff <revision_1>:<file_1> <revision_2>:<file_2>**
git 远程操作 5个命令
- git clone git clone -o <参数-o命名远程主机> <版本库的网址> <本地目录名>
- git remote 改名:git remote rename <原主机名> <新主机名> 添加远程主机:git remote add <主机名> <网址> 查看详情:git remote show <主机名>
- git fetch 取回远程分支更新: git fetch <远程主机名> <分支名>
- git pull git push <远程主机名> <来源地>:<目的地>
- git push
git tag 标签(打在HEAD指向的commit里)
轻标签(名称) 本地临时使用 git tag
注解标签(名称,注解,签名) 发版使用
git tag
git tag stable-1 1b2e3f
git tag [-a|-s|-u] stable-1 1b2e3f
git tag -a
git tag -am “注解”标签名
如果在tag命令指定-n选项执行,可以显示标签的列表和注解
BASIC:
git add files 把当前文件放入暂存区域
git commit 给暂存区域生成快照并提交
git status 查看状态 gst
git diff 对比工作区与版本库内容
git log 查看所有commit记录
git reflog 查看所有操作记录
git checkout xxx 切换到xxx分支
git branch 查看分支
git checkout -b xxx 创建并切换到新分支
git merge xxx 合并xxx分支到当前
git branch -d xxx 删除xxx分支
git diff HEAD -- <文件名> 对比工作区和版本库最新版本的修改
修改回退:
git reset HEAD <文件名> 退出暂存区 修改保留
git checkout -- <文件名> 没git add 拿暂存区替换;已git add拿版本库替换
git reset –hard HEAD^ 回退上一版本(本地源码一起改变)
git reset --hard commitID 回退到指定版本
撤销git add
git reset --mixed 版本回退,所有文件退出暂存区,但是修改保留
git reset <文件目录>/ 撤销目录
git reset –soft:修改保留在暂存区,如果还要提交直接commit即可
git reset –hard:彻底回退到某个版本,本地的源码也会变为上一个版本的内容
git reset 提交层面 在私有分支上舍弃一些没有提交的更改
git reset 文件层面 将文件从缓存区中移除
git checkout 提交层面 切换分支或查看旧版本
git checkout 文件层面 舍弃工作目录中的更改
git revert 提交层面 在公共分支上回滚更改
git revert 文件层面 (木有)
删除文件
git rm <文件名> && git commit -m 从版本库删除 (git rm 从暂存区删除)
git checkout -- <文件名> 从版本库恢复
其他操作
git reset -- files 撤销最后一次git add files,git reset撤销所有暂存区文件
git checkout -- files 从暂存区域复制到工作区,丢弃没有git add的修改
git commit -a 相当于git add + git commit
git commit files
git checkout HEAD -- files 回滚到复制最后一次提交
远程操作
git clone <库地址> 克隆远程库到本地
git remote -v 列出关联的远程主机
git remote add <库名><库地址> 关联远程库
git remote rm <库地址> 取消远程库关联
git push :gh-pages 删除远程分支(原理:推送空白分支覆盖)
git remote rename <原名> <新名> 参数rename,远程库改名
git fetch <远程主机名> <分支名> 拉取远程库更新
git branch -r <远程主机名> <分支名> 查看远程分支
git branch -a 查看所有分支(包括远程分支)
git pull <远程库名> <远程分支名>:<本地分支名> 取回远程主机某个分支的更新,再与本地的指定分支合并
git push <远程库名> <本地分支名>:<远程分支名>
git push origin dev:dev_branch // 推送本地dev分支到远程dev_branch分支
在命令行上创建新的存储库
echo“#LargeScreen”>> README.md
git init
git add README.md
git commit -m“first commit”
git remote add origin [email protected]:qiansr/LargeScreen.git
git push -u origin master
从命令行推送现有存储库
git remote add origin [email protected]:qiansr/LargeScreen.git
git push -u origin master
git reset --soft HEAD^
终极恢复
git reflog 显示整个本地仓储的commit(所有branch,包括已撤销的commit)
git log 只包括当前分支的commit.
git reflog --relative-date 显示相对时间的commit纪录
分支
git branch 查看分支
git branch <分支> 创建分支
git checkout <分支> 切换到分支
git checkout -b <分支> 创建+切换分支
git merge <分支> 合并分支到当前分支
git branch -d <分支> 删除分支
git branch -D <分支> 强行删除没被合并的分支
git merge --no-ff -m "" dev merge时会生成一个新的commit
分支策略
master分支 发布新版本
dev分支 每个人都有自己的分支,往dev分支上合并
—no-ff参数 用普通模式合并,能看出曾经做过合并
fast forward合并 看不出来曾经做过合并
Bug****修复
首先,隐藏当前工作现场
git stash
确定要在哪个分支上修复****bug****,就从那个分支创建临时****bug****分支
$ git checkout master
$ git checkout -b issue-101
修复****bug****,然后提交
$ git add readme.txt
$ git commit -m "fix bug 101"
切换到****master****分支,完成合并,最后删除****bug****分支
git checkout master
git merge --no-ff -m "merged bug fix 101" issue-101
最后回到****dev****分支干活
$ git checkout dev
工作流程模式:
- 首先,可以试图用git push origin branch-name推送自己的修改
- 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并
- 如果合并有冲突,则解决冲突,并在本地提交
- 没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
注意:
如果git pull提示“no tracking information”,则用命令git branch --set-upstream dev origin/dev 创建本地分支和远程分支的关链。
查看远程库信息,使用git remote -v;
本地新建的分支如果不推送到远程,对其他人就是不可见的;
标签管理
Git的标签是版本库的快照,它指向某个commit的指针。发布一个版本时,先打一个版本标签,这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。
git tag git tag用来为某个提交创建一个轻量级标签
$git tag stable-1 1b2e3f
如果想为标签添加注释,那么需要创建一个标签对象。创建标签对象后,一个对象就会被添加到git对象库中,然后标签指向这个对象
$git tag [-a|-s|-u] stable-1 1b2e3f
签名的标签
git config user.signingkey
git diff $git diff [--cached]
--cached参数只显示将要被提交的改变
$git diff branch1..branch2
比较两个分支
$git diff HEAD
比较当前工作目录和上次提交(HEAD)
$git diff file
比较file在当前工作目录和上次提交
[--stat] 统计数据
git pull $git pull repourl branchname
默认的branch_name是master,这会将远程的repo拉过来并且和当前分支合并。
远程工作时,可以添加别名
$git remote add aliasname repourl
$git fetch alias_name
fetch命令只会拉下来更新,而不会执行merge工作
$git merge aliasname/branchname
github 创建项目主页****page
- 登录github 新建一个 mybook项目 仓库
- 建立本地git的远程关联
git remote add mybook [email protected]/xxx.git //
git checkout -b ph-pages // 建立ph-pages分支
git add xxx
git commit -m "" //将要发布的内容提交入库
git push mybook -u ph-pages //推送到远程仓库并 -u参数建立绑定
通过访问****http:///github.io/<****项目名****> 访问项目主页
git log 查看提交日志
glgga git log --all --decorate --graph --decorate参数 显示所标记的标签
glola ||**glol **
ZSH git命令简写
gb='git branch'
gba='git branch -a'
gbda='git branch --merged | command grep -vE "^(*|\smaster\s$)" | command xargs -n 1 git branch -d'**
gbl='git blame -b -w'
gbnm='git branch --no-merged'
gbr='git branch --remote'
gbs='git bisect'
gbsb='git bisect bad'
gbsg='git bisect good'
gbsr='git bisect reset'
gbss='git bisect start'
g='git'
ga='git add'
gaa='git add --all'
gapa='git add --patch'
gc='git commit -v'
gc!='git commit -v --amend'
gca='git commit -v -a'
gca!='git commit -v -a --amend'
gcan!='git commit -v -a -s --no-edit --amend'
gcam='git commit -a -m'
gcb='git checkout -b'
gcf='git config --list'
gcl='git clone --recursive'
gclean='git clean -fd'
gpristine='git reset --hard && git clean -dfx'
gcm='git checkout master'
gcmsg='git commit -m'
gco='git checkout'
gcount='git shortlog -sn'
compdef gcount=git
gcp='git cherry-pick'
gcs='git commit -S'
gd='git diff'
gdca='git diff --cached'
gdct='git describe --tags git rev-list --tags --max-count=1
'
**gdt='git diff-tree --no-commit-id --name-only -r' **
gdw='git diff --word-diff'
gf='git fetch'
gfa='git fetch --all --prune'
gfo='git fetch origin'
gg='git gui citool'
gga='git gui citool --amend'
ggpull='git pull origin $(git_current_branch)'
ggpush='git push origin $(git_current_branch)'
ggsup='git branch --set-upstream-to=origin/$(git_current_branch)'
ggpur='ggu'
gignore='git update-index --assume-unchanged'
gignored='git ls-files -v | grep "^[[:lower:]]"'
git-svn-dcommit-push='git svn dcommit && git push github master:svntrunk'
gk='\gitk --all --branches'
gke='\gitk --all $(git log -g --pretty=format:%h)'
gl='git pull'
git log --all --decorate --graph
glg='git log --stat'
glgp='git log --stat -p'
glgg='git log --graph'
glgga='git log --graph --decorate --all'
glgm='git log --graph --max-count=10'
glo='git log --oneline --decorate'
glol="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
glola="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --all"
glog='git log --oneline --decorate --graph'
glp="_git_log_prettily"
gm='git merge'
gmom='git merge origin/master'
gmt='git mergetool --no-prompt'
gmtvim='git mergetool --no-prompt --tool=vimdiff'
gmum='git merge upstream/master'
gp='git push'
gpd='git push --dry-run'
gpoat='git push origin --all && git push origin --tags'
gpu='git push upstream'
gpv='git push -v'
gr='git remote'
gra='git remote add'
grb='git rebase'
grba='git rebase --abort'
grbc='git rebase --continue'
grbi='git rebase -i'
grbm='git rebase master'
grbs='git rebase --skip'
grh='git reset HEAD'
grhh='git reset HEAD --hard'
grmv='git remote rename'
grrm='git remote remove'
grset='git remote set-url'
grt='cd $(git rev-parse --show-toplevel || echo ".")'
gru='git reset --'
grup='git remote update'
grv='git remote -v'
gsb='git status -sb'
gsd='git svn dcommit'
gsi='git submodule init'
gsps='git show --pretty=short --show-signature'
gsr='git svn rebase'
gss='git status -s'
gst='git status'
gsta='git stash'
gstaa='git stash apply'
gstd='git stash drop'
gstl='git stash list'
gstp='git stash pop'
gsts='git stash show --text'
gsu='git submodule update'
gts='git tag -s'
gtv='git tag | sort -V'
gunignore='git update-index --no-assume-unchanged'
gunwip='git log -n 1 | grep -q -c "--wip--" && git reset HEAD~1'
gup='git pull --rebase'
gupv='git pull --rebase -v'
glum='git pull upstream master'
gwch='git whatchanged -p --abbrev-commit --pretty=medium'
gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit -m "--wip--"'
分支合并
rebase,merge
分支变基:
$ git checkout dev
$ git rebase master
git checkout master
$ git merge dev
git与svn命令对比
常用的svn与git命令对比如下:
svnadmin create ------------------------------> git init
svn co ------------------------------> git clone
svn update ------------------------------> git pull
svn add ------------------------------> git add
svn commit ------------------------------> git add, git commit
svn status ------------------------------> git status
svn switch
svn merge
svn revert