Git使用心得

git reset

1.使用git add .添加了所有修改文件到暂存区之后在commite到本地之前想撤销add操作可以使用

1
git reset HEAD <file>

将某个文件从暂存区拿出来。

2.已经commite了提交到了本地但是还没有push到远端,这时候发现有个文件不能提交到远端可以使用

1
git reset -soft/--mix/--hard <commite id>

会将本地仓库回退到commite id这个版本(可以是上一次commite的版本)。reset后的参数代表了是否保留本地代码的修改,具体可以查询网络。git reset命令的使用

选项 git reset的影响
选项 HEAD 索引(暂存区) 工作目录(源代码)
–soft
–mix
–hard

HEAD:表示当前git指针指向的位置
索引:表示add之后去到的暂存区
工作目录:表示代码文件的改动
提交C1 –> 提交C2
总结就是:soft后git指针会指向C1的提交,而C2修改的文件还是add状态,修改内容不会丢失,对现有的版本改动最小;mix后(git reset默认操作)git指针会指向C1提交,C2修改的文件不是add状态(需要重新add)不在暂存区,文件修改内容不丢失;hard后git指针指向C1提交,C2修改文件不在暂存区,文件修改丢失,完全恢复到C1提交的状态. hard慎用

或者一行一行源码分析清楚+AbstractQueuedSynchronizer+-二-

1
2
git reset HEAD~
git reset HEAD~1

如果你提交了多个commit,那么可以通过修改HEAD~之后的数字,如撤销前3次的commit

1
git reset HEAD~3

下面是一个很有用的后悔药

1
2
# 查询所有git的提交记录,包括详细commite id
git reflog

下图为git reflog的界面

这里面记录了你本地仓库中相关切换和更改的详细描述清单,你可以通过:

1
2
# 可以通过以下命令回到任何一个位置
git reset HEAD@{n}

git add语法

语法 描述
git add -A stages All
git add . stages new and modified, without deleted
git add -u stages modified and deleted, without new

git merge合并

现在最简单的merge模式就是fast-farward merge了,就是从master拉出的分支develop后,master没有再做任何修改,所有的代码都在develop分支上提交,等到最后要合并develop到master上时,可以使用如下命令:

1
2
3
4
# 切换到Master分支
git checkout master
# 对Develop分支进行合并
git merge --no-ff develop

git tag打标签

标签可以针对某一时间点的版本做标记,常用于版本发布。

1.列出标签

1
2
3
4
# 在控制台打印出当前仓库的所有标签
git tag
# 搜索符合模式的标签
git tag -l ‘v0.1.*’

2.打标签

git标签分为两种类型:轻量标签和附注标签。轻量标签是指向提交对象的引用,附注标签则是仓库中的一个独立对象。建议使用附注标签。

1
2
3
4
5
6
# 创建轻量标签
git tag v0.1.2-light
# 创建附注标签
git tag -a v0.1.2 -m "0.1.2版本"
# 针对某个提交打标签
git tag v1.0 <commite id>

3.切换标签

1
git show v0.1.2

4.删除标签

1
2
3
4
5
6
# 删除本地标签
git tag -d v0.1.2
# 删除远程标签
git push origin --delete tag v1.0
# 或者(已验证)
git push origin :refs/tags/V1.2.0

5.标签发布

通常的git push不会将标签对象提交到git服务器,我们需要进行显式的操作:

1
2
3
4
# 将v0.1.2标签提交到git服务器
git push origin v0.1.2
# 将本地所有标签一次性提交到git服务器
git push origin –-tags

git stash

该命令用来保存当前分支上还没commite的修改,使当前分支保持clean状态(git status)

使用场景:执行git stash后,你在dev分支没有提交的修改暂时被“藏”了起来,看起来dev分支是干净的。但是,请一定注意,你还在dev分支!因为你需要切换到master分支去修改bug,因此此时需要切换到master分支(如果不执行git stash就切换到master分支是不行的:git会报告当前dev分支还存在未提交的修改,比如先提交才允许你切换分支,而出于各种原因,你还不能现在提交dev分支的内容(一般也就先提交了,大不了再切回来改就是哦),这就是git stash存在的价值)。

切换到stash分支后的恢复命令

1
2
3
4
5
6
7
8
# 恢复并删除stash内容
git stash pop

# 查看现场
git stash list

# 保存现场
git stash

git分支管理

  1. master:主分支,当前分支上的代码随时可以直接发布,并且只能通过Pull Request从其他分支进行合并,而不能直接push修改。当开发告一段落,产生了新的可供发布的代码时,master分支通过Pull Request更新了代码,同时,每一次更新必须添加对应版本号的标签TAG。
  2. develop:开发分支,保存当前最新开发成果的分支,即当一个新功能开发完毕需要先合并到develop分支,这个分支的代码会进行每日的代码持续集成(Daily Build)。所有的开发任务都是从这个分支Checkout新的特性分支进行开发。
  3. feature:特性分支,当开发新的功能时,从develop分支Checkout新的feature分支,这个分支的代码最终要合并回develop分支或者废弃掉(例如预研功能效果不好时)。feature分支最好以功能为单位。
  4. hotfix:紧急修复分支,唯一从master分支派生的分支,当生产环境中发现了异常或者缺陷的时候,从master分支上指定的TAG版本Checkout hotfix分支进行紧急修复工作,当修复完成之后,必须同时合并到master分支和develop分支。合并完代码之后删除hotfix分支。

  5. 新建分支(已feature为例)

    1
    2
    3
    4
    5
    6
    7
    8
    # 切换本地分支到develop分支
    git checkout develop
    # 拉取远程Git仓库中的最新的develop分支的代码
    git pull
    # 创建本地特性分支feature
    git checkout -b feature
    # 推送本地特性分支到远程Git仓库(即创建远程特性分支),-u为追踪远程分支
    git push -u origin feature
  6. 已feature分支为例开发合并全流程

    1
    2
    3
    4
    5
    # 开发代码。以下两步的作用是保证你本地的feature分支的代码为最新,因为有可能你是和别人合作开发的该功能,如果你刚更新过或者你是一个人在开发则可以省略此操作
    # 切换到本地feature分支
    git checkout feature
    # 拉取远程分支代码,--rebase最好加上
    git pull --rebase
1
2
3
4
5
6
7
8
9
# 合并代码
# 切换到本地develop分支
git checkout develop
# 拉取最新的远程origin/develop分支代码,因为可能已经有人提交了代码
git pull --rebase
# 从本地feature-login分支合并代码,--no-ff为禁止fast-farward模式
git merge --no-ff feature-login
# 推送到远程分支
git push
1
2
3
4
5
6
7
# 代码已经合并完,可以删除本地特性分支和远程特性分支
# 删除本地feature-login特性分支
git branch -d feature-login
# 删除远程origin/feature-login特性分支(废除,实验无效)
git branch -r -d origin/feature-login
#在v1.7.0 之后,可以使用这种语法删除远程分支(同删除标签tag类似)
git push origin --delete <branch name>

当你用上面删除远程分支(删除tag)命令时,当你的分支名称和tag名称一样时,会报错,因为git不知道你到底要删除branch还是head。所以可以这样做

1
2
3
4
//删除 dev_test 分支
git push origin :refs/heads/branchName
//删除 dev_test 标签
git push origin :refs/tags/branchName
  1. 本地根据tag创建分支
1
2
3
4
5
# 根据tag创建分支
git branch <new-branch-name> <tag-name>
git branch v2.2-fixbug V2.2
#将新分支推送到远程仓库
git push origin v2.2-fixbug

git push

push到远程分支有https和ssh两种方式,https每次push都会要求输入用户名和密码,而ssh只要在远端注册了ssh key则不需要。
另外,ssh可以上传大文件,https貌似不行。

1
2
# 这个会把本地当前分支的内容push到远端的demo分支,如果远端没有该分支则自动创建
git push -u origin demo

1
2
3
4
# 生成ssh key,该程序在 Linux/Mac 系统上由 SSH 包提供,而在 Windows 上则包含在 MSysGit 包里:
ssh-keygen
# 可以查看远程分支情况
git remote -v

git reset

第一小节有类似操作。

  1. 本地代码回滚
1
2
3
4
# 回滚到commit-id,讲commit-id之后提交的commit都去除
git reset --hard commit-id
# 将最近3次的提交回滚
git reset --hard HEAD~3
  1. 远程代码回滚。应用场景:app已经发布了,发现有问题需要回滚到某个commit,再重新发布。这时需要先将本地分支退回到某个commit,删除远程分支,再重新push本地分支。操作步骤(还没检验)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1
git checkout the_branch
# 2
git pull
# 3 备份一下这个分支当前的情况(本地新建分支?)
git branch the_branch_backup
# 4 把the_branch本地回滚到the_commit_id
git reset --hard the_commit_id
# 5 删除远程 the_branch(可以删除远程分支)
git push origin :the_branch
# 6 用回滚后的本地分支重新建立远程分支
git push origin the_branch
# 7 如果前面都成功了,删除这个备份分支
git push origin :the_branch_backup

git remote

多源操作,一般是一个源,但是多源也很有用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 如果想关联另一个远端仓库(加一个源)
git remote add <origin name> git@gitlab.com:demo/demo.git

# 显示全部源
git remote / git remote -v

# rename
git remote rename <origin name> <origin new name>

# deleted
git remote rm <origin name>

# 查看指定源的全部信息
git remote show <origin name>

# 修改远程仓库地址
git remote set-url origin <origin url>

git commit

合并某个分支上的某个commit或者多个commit到master分支上

1
2
3
dd2e86 - 946992 -9143a9 - a6fd86 - 5a6057 [master]
\
76cada - 62ecb3 - b886a0 [feature]

  1. 比如,feature 分支上的commit 62ecb3 非常重要,它含有一个bug的修改,或其他人想访问的内容。无论什么原因,你现在只需要将62ecb3 合并到master,而不合并feature上的其他commits,所以我们用git cherry-pick命令来做:
1
2
3
# 示例
git checkout master
git cherry-pick 62ecb3
  1. 在一些特性情况下,合并单个commit并不够,你需要合并一系列相连的commits。这种情况下就不要选择cherry-pick了,rebase 更适合。还以上例为例,假设你需要合并feature分支的commit76cada ~62ecb3 到master分支。(未实验,要实验一下)
1
2
3
4
# 首先需要基于feature创建一个新的分支,并指明新分支的最后一个commit:
git checkout -bnewbranch 62ecb3
# 然后,rebase这个新分支的commit到master(--ontomaster)。76cada^ 指明你想从哪个特定的commit开始。
git rebase --ontomaster 76cada^

git rebase

1
2
3
4
5
6
7
8
9
10
11
12
13
```


### git detached HEAD
在一些情况下,会出现detached HEAD的情况,(后面分析下原因)。detached head即游离的HEAD,HEAD指向了未知的分支,即不在所有已知的分支范围内。

解决办法:

```git
$ git branch
* (HEAD detached at origin/master)
dev
master

HEAD指向了一个未知的分支,可用git checkout -b基于当前分支创建一个新的临时分支保留代码,合并到合适的分支后删除

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git checkout -b temp
Switched to a new branch 'temp'
$ git branch
dev
master
* temp
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git merge temp
Already up-to-date.
$ git branch -d temp
Deleted branch temp (was 3e74a7a).

git clean -d -fx “{文件名}”

在开发中碰到本地修改了一个文件,远程分支对应文件也有修改。后面忘记先pull代码直接commit了,然后想push到远端仓库,发现会报一个错误如下:

git冲突please move or remove before you can merge

解决方法就是:

1
2
//默认会把这个文件强制更新为远程文件
git clean -d -fx "{文件名}"

git diff

该命令用来比较分支和分支之间的差异

  1. 显示两个分支的差异部分

    1
    git diff branch1 branch2 --start
  2. 显示指定文件的详细差异

    1
    git diff branch1 branch2 具体文件路径
  3. 显示出所有有差异的文件的详细差异

    1
    git diff branch1 branch2

git log

显示git日志的,有时候非常有用

  1. 查看branch1分支有,而branch2分支中没有的log

    1
    git log branch1 ^branch2
  2. 查看branch2中比branch1中多提交了哪些内容

    1
    git log branch1..branch2
  3. 不知道谁提交的多谁提交的少,单纯想知道有什么不一样

    1
    git log branch1...branch2
  4. 在上述情况下,在显示出每个提交是在哪个分支上

    1
    2
    // 打印出的commit中根据命令中left-right,左箭头<表示branch1的,右箭头>表示branch2的
    git log -left-right branch1...branch2