git的使用

基本原理
Git的设计哲学
追求最强性能
分布式 - 不依赖中心服务器,几乎所有操作都是本地执行

  1. 快照而不是diff - 与几乎所有其它版本控制系统的重要区别
  2. 只添加而不删除- 总是可逆
  3. hash索引 - SHA-1, 40 digit hex 可以同时完成校验
  4. 三种状态 committed, modified, staged (初学者容易搞糊涂)

四种对象
commit tree blob tag
blob – 文件
tree – 目录
commit – tree, meta, pointer
构成一个小的文件系统
暂时无法在文档外展示此内容
cd .git/object/
git cat-file -t
git cat-file -p

为什么改一下commit msg, commit id就变了?
git commit --amend 修补, 修改对象指针
git reflog 找到刚才的commit
使用别名
git config --global alias.br branch
git config --global alias.ci commit
~/.gitconfig
[alias]
co = checkout
ci = commit
cia = commit --amend
br = branch
di = diff
lo = log --oneline
sb = submodule

git clone -depth=10
查看历史
辅助选项
git log --color --no-decorate --decorate 是否显示tag, branch
git log --stat
git log --graph 树状图
git log -p
git log -p --patience 生成更精确的diff
git log --merges --no-merges 只显示/不显示 合并节点

git log -g git reflog 查看历史丢失的节点, 包括commit --amend

author和committer 的区分
git log --pretty=full 同时显示author和committer

查看分支的差别
git log --oneline --cherry-pick A…B (注意3个点)

git log --oneline --left-right --cherry-mark A…B (注意3个点)

git log --first-parent 只看主线改动

git log --reverse 从旧到新
格式化
git log --pretty=“%h %an %s” 输出想要的字段和顺序
查看统计
git shortlog -n -s 按作者提交的committer数排序显示每个人的提交
代码提交
暂存

  • 临时修改一个bug
    git stash [push]
    git stash pop
    git stash -p

提交部分代码
git add
git add -p
git commit

变基到最新的节点
git checkout master
git checkout -b

…修改代码…
git fetch
git rebase master

git pull --rebase
设置默认pull rebase
~/.gitconfig
[pull]
rebase = true
撤回
git revert 去掉某个提交,实际上是生成一个新的反向的commit

整理历史提交
修改刚提交commit
把改动合入到刚提交的commit, 同时可修改commit message
git commit --amend
会生成新的节点,当前分支指向新的节点,原有节点丢失(可以git log -g 或git reflog中看到)

把刚提交的几个commit合成一个
git reset HEAD~4
git commit -a -m “xxxxx”

把当前工作分支回退到任何一个commit
git reset --hard 丢弃未提交的所有改动
git reset --hard HEAD^^ 退回到前两个节点
git reset --hard 同步到远程分支最新节点

拆分已提交commit
git reset -p HEAD^
git commit --amend

把选y的改动抽出, git commit --amend后,原有commit只留下部分,剩下改动可以提交新的commit或抛弃

本地分支重新整理
git rebase --whitespace=fix HEAD^
git rebase -i HEAD~5

git rebase --continue

定位问题

  • 某个版本发现了以前不存在一个问题,很难直接定位,怎么办?
  • 对某些代码有疑问,怎么找到最初是谁写的和他讨论?
    二分查找问题引入commit
    git bisect
    git bisect start [new bad] [old good] 标记出问题坏的节点和好的起始节点,checkout到中间节点
    git bisect good 测试没问题,标记成好的,checkout到新的中间节点
    git bisect bad 测试有问题,标记成坏的,checkout到新的中间节点
    git bisect log

自动定位
执行以下命令
git bisect run myscript.sh 自动执行测试,根据返回值决定checkout下一个commit来测试。
myscript退出值 0表示测试没问题, 1-127表示失败. 返回125表示不可测试(比如编译不通过), 跳过这个commit.

找到引入代码的人
git blame 找到谁引入了问题,区分是author还是committer
git blame -M 追踪代码行的移动, 可以找到原始改动,而不是挪到那些行的commit。
git blame -C 追踪文件中的重复代码行拷贝
git blame -C -C 追踪同一个commit中从其它文件拷贝过来的行。
git blame -C -C -C 追踪所有commit中从其它文件拷贝过来的行。
除了找到最原始是谁引入的代码, 也可用来检测是否有不必要复制代码。

分支的使用和管理

  • 分支合并和变基操作各是什么含义?
    分支创建与关联
    git checkout -b
    git checkout -B
    git branch -d / -D 删除分支
    git branch --set-upstream-to | git branch -u 和远程建立关联
    git branch --contain 找到包含某个commit的分支
    git merge-base 找到两个分支的分叉点

建议创建了本地个人临时分支,每天推到服务,备份代码,可用不同的remote服务器来存放个人临时分支
多remote

  • 可以用不同的服务器或相同服务器不同git路径来存放不同的分支,区分管理权限
  • 可以用专门的服务器来存放个人临时分支备份,每天自动提交和push
    git remote add auto git@gitlab.hobot.cc:auto/system/hobot-system/kernel-4.14
    git remote -v

git push auto mybrach:mybranch
注意对应关系
git config -l

分支合并
无法复制加载中的内容
主线历史产生分叉点,追溯比较麻烦,只能把merge节点当作一个commit.
冲突解决集中在一个merge节点中,merge节点中修改可能混合了多个模块的改动。
比较分支时,merge节点的改动不容易拆分
分叉时间较长含有很多commit的分支用merge会比较省力,因为中间可能有对某一个文件反复修改的多个commit, merge时只需要处理一次。
理解Fastforward 概念
git merge --ff (允许fastfoward合并,默认,自动) --no-ff(不允许)

不产生合并节点
无法复制加载中的内容
git merge --squash 把分支合成一个commit,再合过来(实际上就没有分支了)
merge的原理
两条修改历史的合并
git merge
3-way merge的工作方式
只比较分支头结点和共同的祖先节点
对比两边的修改,无冲突合入, 有冲突,显示两边各自的改动

冲突解决技巧
通过mergetool命令调用特定的编辑器
git mergetool --tool=<vimdiff/meld/diff3>
修改完会自动调用git add
git log --merge -p 显示有冲突的文件

使用diff3格式,更清楚的看到冲突的地方
git config --global merge.conflictStyle diff3
example:
ours

@@ -505,8 +505,6 @@ pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns)

        if (pid && ns->level <= pid->level) {
                upid = &pid->numbers[ns->level];
-               if (upid->ns == ns)
-                       nr = upid->nr;
        }
        return nr;
 }

theirs

@@ -505,8 +505,9 @@ pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns)

        if (pid && ns->level <= pid->level) {
                upid = &pid->numbers[ns->level];
-               if (upid->ns == ns)
+               if (upid->ns == ns) {
                        nr = upid->nr;
+               }
        }
        return nr;
 }

Merged

@@ -505,6 +505,15 @@ pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns)

        if (pid && ns->level <= pid->level) {
                upid = &pid->numbers[ns->level];
+<<<<<<< HEAD
+||||||| merged common ancestors
+               if (upid->ns == ns)
+                       nr = upid->nr;
+=======
+               if (upid->ns == ns) {
+                       nr = upid->nr;
+               }
+>>>>>>> feat2
        }
        return nr;
 }

Merge的策略
完全放弃分支改动
git merge -s ours topic_branch
完全同步上游
git checkout -b tmpbranch master
git merge -s ours mybranch
git checkout mybranch
git reset --hard tmpbranch
优先用哪个分支
git merge -Xours
git merge -Xtheirs
减少冲突
git merge -Xignore-space-change
Merge的风险

  • A分支上cherry-pick B分支一个commit, 但B分支后来又了revert了

  • 已经cherry-pick部分上游patch,再进行merge, 可能后续的commit改回了这个commit中增加、修改,删除的行。

      }
    
        //FOCUS ON
-       spin_lock_irqsave(&chan->vc.lock, flags);
+       raw_spin_lock_irqsave(&chan->vc.lock, flags);
        ret = dma_cookie_status(dchan, cookie, txstate);
        vd = vchan_find_desc(&chan->vc, cookie);
        if (vd) {
        //FOCUS ON
-       raw_spin_lock_irqsave(&chan->vc.lock, flags);
+       spin_lock_irqsave(&chan->vc.lock, flags);
        ret = dma_cookie_status(dchan, cookie, txstate);
        vd = vchan_find_desc(&chan->vc, cookie);
        if (vd) {

Cherry-pick
单独拿从别的分支拿1个或多个patch合到当前分支
git cherry-pick
git cherry-pick master~4 master~2 拿主线上的最新第5个到第2个commit过来
git cherry-pick --continue
-n 不提交,只改变当前working tree
有冲突可以用git mergetool 解决
git cherry-pick --continue
git cherry-pick feat-a~2 feat-a 拿feat-a的最新3个commit过来
无法复制加载中的内容

分支变基
类似于cherry-pick, 只是把当前分支移动。
无法复制加载中的内容
feat-a分支的历史都变了
每次push到服务器前,都做一次rebase.
如果没有创建个人分支,则push前, git pull --rebase
好处:
主线保持线性历史,没有分叉,每个commit的修改明确
分支上如有cherry-pick的commit, rebase时会消除
历史回溯比较清晰,需要取中间任何一个commit作cherry-pick比较清晰
冲突解决分散在每一个commit中,revert一个commit, 更不容易冲突
适合分叉时间不长的功能分支,bugfix分支,个人本地开发分支
git merge --no-ff
其它技巧
向上游贡献
git format-patch
git am
也可以用于无直接服务器连接的同步
子模块
可以用来管理依赖的项目,比如某个库项目
git submodule add 增加一个依赖的git
git clone --recursive clone时把依赖模块同时clone出来
git submodule init
git submodule update

重接历史
git replace
把一棵树分成两个git, 需要的时候,又能把历史接起来。
大部分人不需要clone一棵全历史树
git remote add
git replace

工作树
如果你想在一台机器上同时在某个git的两个分支上工作, 不需要重复clone一份,节省时间和空间
git worktree add …/mytask
git worktree list

stg 在git外维护一系列patch
stg init
stg uncommit
stg pop
stg series

stg uncommit
stg uncommit
stg pop -a
弹出两个commit
2个commit变成栈里的两个patch

stg push -a
全部又推上去了
用处

  • 在主线外维护一系列patch, 测试并进行bugfix, fix合入对应的patch, 准备upstream
  • 维护一系列debug patch, 需要哪一个时,推哪一个上去
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值