git协同开发常用操作

1. 本地新建仓库

git init

在已有仓库中执行git init是安全的,它不会覆盖已经存在的东西。重新运行git init的主要原因是拾取新添加的模板。

2. 克隆远程仓库

git clone <url> [<local_path>] [--recurse-submodules] [--jobs=<n>]

  • <url>远程仓库的地址
  • <local_path>本地仓库的存储目录。可缺省,缺省值为当前目录
  • --recurse-submodules递归拉取子仓库
  • --jobs=<n>多任务同时进行,以加快速度。<n>表示任务数

例:git clone ssh://pythonSDK.public@192.168.23.98:39418/pythonSDK --recurse-submodules --jobs=12

3. 查看子仓库列表

git submodule

进入到PythonSDK目录,执行结果如下:

 f1a6efe6f3e1689d85b24b224eea1637c8b55389 components/ZBar (heads/master)
 738e7680562ed1f1cfadd9bbd68c3a77ef2ec144 components/jpeg (738e768)
 9384e7da139f6b89d8d07fe8a1ef7346dba1d27a components/lvgl (heads/master)
 523fd7aa21880623b024fb5f2161347b6366c982 components/quecsdk (heads/master)
 b801932b8ed33b3981f031d5709f7d23fc2933c0 components/rtmpdump (b801932)
 ec9910552961feb7f2e8f3c11aa7cbcfb8b52479 services/microPython (ec99105)
 b5db751efbcbf509ff96b392399676e36d7e21c2 system/mbedtls (heads/master)

4. 遍历所有子仓库,并切换到master分支

git submodule foreach git checkout master

该命令用来遍历所有子仓库,并逐个切换到master分支。

命令模板:
git submodule foreach <git_cmd>

git submodule foreach命令用来对所有子仓库做统一的操作。

  • <git_cmd>对子仓库执行的git命令

例:git submodule foreach git status

5. 查看仓库的状态

git status

该命令用于列出当前仓库的状态。

  • 干净的工作区:

git协同开发常用操作

  • 已修改文件,但未加入到暂存区

git协同开发常用操作

  • 已加入到暂存区,但是未提交到本地仓库

git协同开发常用操作

  • 新增的、未被git仓库跟踪管理到的文件

git协同开发常用操作

6. 查看提交日志

git log [--name-only | --name-status]

  • <--name-only>日志中按行显示被修改的文件名称列表
  • <--name-status>日志按行中显示被修改的文件名称列表,且每行的开头显示文件的修改状态。
    A file1新增file1文件
    D file2删除file2文件
    M file3修改file3文件
    Rxxx file4 file5file4文件重命名为file5,其中xxx是一个百分比,表示新旧文件名对应的文件内容的相似度,比如R100 file4 file5,file4和file5的相似度位100%,即完全一样,说明file5确实是file4重命名而来的。

git如何得知新文件是旧文件重命名而来的?
当前检测到旧路径的文件被删除,而增加了新路径的文件,根据两个文件的相似度判断是否可归结为重命名,并记录相似度。

这里提及到旧路径的文件和新路径的文件,git判断是否未重名为时,不仅是在相同目录下的两个文件,只要是绝对路径不同的两个文件,都可以被git判断是否位重命名。比如R90 path1/file4 path2/file5,文件path1/file4重命名为path2/file5,相似度为90%(可能因为修改了文件内容)。

7. 将待提交文件添加到暂存区

git add <file...> [-f]
git add <dir...> [-f]
git add -A [-f]
git add -u [-f]

  • <file...>待添加的文件列表,支持通配符
  • <dir...>待添加的文件夹列表,支持通配符,git add .添加所有修改的和新建的文件到暂存区
  • -A添加所有被删除、被替换、被修改和新增的文件到暂存区
  • -u添加所有被删除和修改的文件到暂存区
  • -f添加被忽略的文件
  • 其它众多的选项

git add后跟上目录参数时,如果有通配符,则将符合通配符的文件添加进来;否则会将所有文件(包括untracked files)添加进来,很有可能会添加不想提交的文件。
所以git add前先使用git status查看一下当前的修改状态,最好再使用git diff命令check下每个文件的修改是否正确。

git add命令执行完后,如果再次修改了其中的文件,需要再次将修改的文件添加进暂存区,否则,本次的修改不会被提交。

git协同开发常用操作

8. 从暂存区撤销误添加的文件

git reset <file...>
git reset <dir...>

  • <file...>待撤销的文件列表,支持通配符
  • <dir...>待撤销的文件夹列表,支持通配符

例:git reset Makefile
该命令撤销了加入到暂存区的Makefile文件,但是文件的内容仍保持之前修改后的状态。

git协同开发常用操作

9. 撤销未加入暂存区的文件的修改

git checkout -- <file...>
git checkout -- <dir...>

  • <file...>待撤销的文件列表,支持通配符
  • <dir...>待撤销的文件夹列表,支持通配符

例:git checkout -- Makefile

git协同开发常用操作

10. 隐藏和恢复不想提交的文件的修改

git stash [save [<msg>]] [--all | --include-untracked] [<file...> | <dir...>]
该命令会将已加入暂存区未加入暂存区的所有已跟踪文件,甚至未跟踪文件的修改隐藏。

  • save表示执行隐藏的动作。可缺省,缺省后,不可携带用户追加的消息。
  • <msg>用户追加的消息字符串,建议加上消息,便于追踪。
  • --all隐藏包含未跟踪文件在内的所有文件。
  • --include-untracked隐藏包含未跟踪文件在内的文件。隐藏已跟踪的哪些文件,由[<file...> | <dir...>]决定,可以为空,同--all

在已有未恢复的隐藏情况下,可多次执行该命令,继续隐藏修改点,类似于数据的入栈。


git stash list
该命令会按行列出所有隐藏修改的记录。第一行为最近隐藏的修改。
格式:stash@{<n>}: <msg>

  • <n>按照隐藏的时间顺序倒序编号,最近一次的编号为0。

git协同开发常用操作


git stash pop [<n>]

  • pop恢复隐藏的修改。
  • <n>恢复指定编号的隐藏修改,最近一次的编号为0。可缺省,缺省时表示恢复当前编号为0的隐藏。

由于操作稍微复杂,培训时再做演示。

11. 提交代码

git commit [-a] [-m <msg>] [--amend]

  • -a自动将未加入暂存区的已跟踪文件加入暂存区。可缺省,缺省后只提交已经使用git add加入暂存区的修改。
  • -m后面跟上提交日志。可缺省,缺省后git会弹出编辑器让用户编写提交日志。
  • <msg>提交日志。
  • --amend重写最近一次提交的日志。

12. 推送至远程仓库

git push [<remote> <local_branch>:<remote_branch>] [-u] [-f]

  • <remote>远程仓库的别名,由git remote add设定,git clone拉取的仓库,该值为origin,可修改。
  • <local_branch>本地分支名
  • <remote_branch>远程分支名
  • -u关联远程分支,用于将自己创建的本地仓库推送到远程仓库。第一次推送时,加上-u,便会将本地仓库和远程仓库关联起来,后续可不用带’-u’。本地仓库和远程仓库不关联,是推送成功的。git clone拉取的仓库,本地仓库已经和远程仓库做了关联,可直接提交。
  • -f强制推送当前的仓库到远程仓库,用以覆盖远程仓库的文件。该选项请勿轻易使用,即使有code review机制。

有code review机制的远程仓库,向其推送修改时,远程分支名为refs/for/<branch>
<branch>为具体的远程分支名,如master、dev等。

例:git push origin HEAD:refs/for/master
将本地HEAD指向分支的修改推送到远程的master分支。HEAD指向当前工作区最新的提交。

13. 拉取远程代码,但是不合入本地

git fetch

需要使用git merge命令合入

14. 代码合并

git merge [<branch> | <commit>]

  • <branch>源分支名,可以是远程或本地的分支
  • <commit>提交的id

git fetch后,跟着git merge,可实现拉取远程代码合入本地

15. 拉取远程代码合入本地

git pull

等于git fetch + git merge
该方式使用较多;也可根据需要选择使用git fetch,而后在必要的时候git merge

git pull --rebase = git fetch + git rebase
将远程代码合入到本地,但是和本地代码产生冲突时,不会向单纯地使用git pull(即git fetch + git merge)一样,产生合并的分叉线(参考19节git rebase命令)。

16. 分支创建和删除

  • 创建分支
    git checkout -b <branch> [<commit>]
    git branch <branch> [<commit>]

    • <branch>新分支名。
    • <commit>基于该commit-id创建新分支,可缺省,缺省后基于当前的HEAD创建新分支。
    • git checkout -b创建新分支并切换过去。
    • git branch仅创建新的分支,不切换过去。

  • 删除分支
    git branch -d <branch>

    • <branch>分支名。不可删除当前分支,需切换到另一个分支,来删除目标分支。

17. 标签

  • 添加标签
    git tag <tag>

    • <tag>标签名。

  • 添加带说明的标签
    git tag -a [-m <msg>] <tag>

    • -a表示要添加标签。
    • -m表示要添加说明信息。
    • <msg>添加的说明信息。如果不携带-m,不需要此项,但是git会打开默认编辑器,让用户添加说明信息。
    • <tag>标签名。

  • 列出标签
    git tag [-l [<match>]]

    • -l按照通配符模式列出相关的标签。例:git tag -l v1.*,表示列出所有v1.x的标签。
      该项可省略,变成git tag,表示列出所有标签。
    • <match>标签的通配符模式。
      该项可省略,变成git tag -l,也表示列出所有标签。

  • 显示指定标签的修改内容
    git show <tag>

    • <tag>标签名。

  • 查看所有的远程标签及commit-id
    git ls-remote --tags origin


  • 推送指定标签到远程仓库
    git push origin <tag>

    • <tag>标签名。

  • 推送所有标签到远程仓库
    git push --tags


  • 删除远程仓库的指定标签
    git push --delete origin <tag>

    • <tag>标签名。
      该命令仅会删除远程仓库的标签,本地的标签依然存在,下次执行git push --tags时依然会推送到远程。
      可根据需要,调用git tag -d <tag>命令来删除本地标签。

  • 删除本地仓库的指定标签
    git tag -d <tag>

    • <tag>标签名。

18. 回退代码

  • 以干净的状态,将HEAD回退到指定的commit-id
    git reset --hard <commit>

    • <commit>指定回退的commit-id。
      该命令执行后,git log查询到的最新的commit-id为<commit>的值。
      工作区的状态:干净的,没有任何未提交的修改。

  • 以脏的状态,将HEAD回退到指定的commit-id
    git reset --mixed <commit>

    • <commit>指定回退的commit-id。
      该命令执行后,git log查询到的最新的commit-id为<commit>的值。
      工作区的状态:脏的,在当前提交的基础上做的修改未加入暂存区

  • 以加入暂存区的状态,将HEAD回退到指定的commit-id
    git reset --soft <commit>

    • <commit>指定回退的commit-id。
      该命令执行后,git log查询到的最新的commit-id为<commit>的值。
      工作区的状态:在当前提交的基础上做的修改加入了暂存区

19. 变基

  • 将多次提交合并为一个,或将提交历史的merge分叉变直
    git rebase -i <start_commit> <end_commit>

    • <start_commit>开始的commit-id,不包含该commit-id
    • <end_commit>结束的commit-id,包含该commit-id

    根据弹出的窗口的提示,填写对应的指令,决定是将多个提交合并为一条,还是做其他的操作。


  • 将某一段提交合并到另一个分支
    git rebase <start_commit> <end_commit> --onto <branch>

    • <start_commit>开始的commit-id,不包含该commit-id
    • <end_commit>结束的commit-id,包含该commit-id
    • <branch>目标分支

  • 合并两个分支
    git rebase <branch>

    • <branch>将分支branch合并到当前分支。
      执行该命令时,会先将当前分支的提交全部取消,并作为patch临时放入.git/rebase目录下。
      接着,会将分支branch的代码合并到当前分支。
      最后,将临时的patch合入到当前分支。

git rebase命令的使用,应遵循以下原则:

git rebase 
while(存在冲突) {
    git status
    找到当前冲突文件,编辑解决冲突
    git add -u
    git rebase --continue
    if( git rebase --abort )
        break; 
}

git merge命令在合入代码时,会在基线上产生merge的分叉效果,有些人会觉得很混乱。
使用git rebase命令可避免该现象,并且还可将历史merge的分叉线变直。

上一篇:git reset、git checkout、和 git revert区分要点


下一篇:git merge 简单的操作流程