git

  • Commands
    • git config setup
    • git commands
    • Remote collaboration commands
  • Miscellaneous
    • git commit msg rules
    • 合并冲突指示符解释
    • git使用命令行分页器less浏览所有信息,以下是less快捷键
    • 祖先引用
    • Git托管平台的SSH key配置
    • Untrack files already added to git repository based on .gitignore
    • git log aliases in .gitconfig
    • 本地分支完全同步为远程分支
    • 合并特定commits到另一个分支

Commands

git config setup

# 显示当前配置
git config --list
# 设置 Git 用户名
git config --global user.name "<Your-Full-Name>"
# 设置 Git 邮箱
git config --global user.email "<your-email-address>"
# 确保 Git 输出内容带有颜色标记
git config --global color.ui auto
# 对比显示原始状态
git config --global merge.conflictstyle diff3
# 彩色的git输出
git config color.ui true
# 显示历史记录时,每个提交的信息只显示一行
git config format.pretty oneline

# Git与代码编辑器
# Atom Editor设置
git config --global core.editor "atom --wait"
# Sublime Text设置
git config --global core.editor "'/Applications/Sublime Text 3.app/Contents/SharedSupport/bin/subl' -n -w"
# VSCode设置
git config --global core.editor "code --wait"

git commands

gitk #内建的图形化git

git init  
git clone <path-to-repository-to-clone> #可以提供第二个参数,作为该目录的名称
git submodule add git@github.com:azmelanar/hugo-theme-pixyll.git themes/pixyll
git status

#git log后可接SHA以显示特定commmit详情
git log --oneline --decorate --all --graph #显示仓库中的所有分支,以及所有commit
git log --stat #显示被修改的文件添加/删除的行数
git log -p/--patch #显示被修改的文件的具体更改
git shortlog #按作者对commit分组, -s仅显示commit数量而非commit message, -n按数量排序而不是按作者姓名字母顺序
git log --author="" #按作者筛选,显示某个作者所有commit方法
git log --grep="" #根据commit提交信息筛选某词,筛选多个词需要添加引号
git log --name-status #查看文件改变

git show <SHA> #显示commit中包含额外详细信息,同git log -p
git show -stat --patch -w #显示更改文件数,添加/删除的行数及具体更改并忽略空格变化

git add <file1> <file2> … <fileN> / .
git add -u #stage without new file
git add --ignore-removal #ignore delete files
git add -i #交互式添加文件到暂存区

git rm --cached . #只是从暂存区删掉文件(unstage)
git rm -r --cached .idea #配合gitignore清除idea缓存
git commit -m "commit message" #取出暂存区的文件并保存到仓库 

git diff <source_branch> <target_branch> #用来查看已经执行但是尚未commit的更改

# 轻量化标签在Git中不存储任何的信息,只是一个特定提交的引用
# 附注标签储存在Git数据中,且包含标签创建者、电子邮件、日期、标签消息等信息
# 创建的标签总是与commit进行绑定的
git tag # 创建轻量化标签用来标记特定的commit,-d 删除标签
git tag -a v1.0.0 -m "发布新版本v1.0.0" # -a 创建附注标签,
git show v1.0.0 #查看Tag信息
git tag -d <tagname> #删除标签

#stash your changes before switching branch with Git
git stash save "changes"
git stash pop
git stash list
git stash pop "stash@{1}"
git stash pop=(git stash pop "stash@{1}", git stash drop)

git branch -a #查看所有分支
git branch sidebar 5bfe5e7 #向该 commit 添加分支
git checkout -b [分支名] #创建分支并切换到该分支
git branch -d sidebar #删除分支,如果要被删除的分支上有独有的commit,git不会删除该分支

git merge <other-branch> #用来合并git分支
git merge --squash <other-branch> 
git merge --abort #合并时遇到冲突或错误后取消合并
git checkout -- <filename> #替换本地改动,使用HEAD最新内容替换工作目录的文件,已添加到暂存区的改动以及新文件不会受到影响

git revert #用于还原之前的commit:撤消目标commit的更改并创建新的commit来记录这一更改

git reset <reference-to-commit> #用于清除commit(将HEAD和当前分支指针移到引用的commit)
git reset --mixed HEAD^ #--mixed为默认参数,不删除工作空间改动代码,撤销commit,撤销git add .
git reset --soft HEAD^ #--soft不删除工作空间改动代码,撤销commit,不撤销git add .
git reset --hard HEAD^ #--hard删除工作空间改动代码,撤销commit,撤销git add .
git reset --hard origin/master

git commit --amend #用于撤消或更改最近的commit(常用于修改commit注释)

git reflog # git会在完全清除任何内容之前,持续跟踪大约30天,使用该命令调用这些内容 

git rebase -squash #将commit移动到一个新基底(base)上
# 交互式地将 commit 变基到我们当前所在的 commit 向前三个的 commit
git rebase -i HEAD~3
git merge-base feature master #returns the commit ID of the original base, which you can then pass to git rebase

git rebase -i <base> # 交互式 rebase
# 在 commit 的交互式列表中,所有 commit 都以 pick 开头,但你可以使用其他命令(reword、edit、squash、fixup、exec 和 drop)进行变换。
# 使用 p 或 pick – 使 commit 保持原样
# 使用 r 或 reword – 保留 commit 的内容,但修改 commit 说明
# 使用 e 或 edit – 保留 commit 的内容,但先不要执行 commit,以便修改即将 commit 的内容
# 使用 s 或 squash – 将此 commit 的更改结合到之前的 commit 中(列表中位于其上面的 commit )
# 使用 f 或 fixup – 将此 commit 的更改结合到前一个 commit 中,但删除提交说明
# 使用 x 或 exec – 运行 shell 命令
# 使用 d 或 drop – 删除 commit

#Tips
#变基之前创建备份(backup)分支以便能很容易返回到之前的状态。之后如果对变基的结果满意,则可以删除 backup 分支
git checkout feature
git checkout -b temporary-branch
git rebase -i master
# [Clean up the history]
git checkout master
git merge temporary-branch

#何时变基 - 变基时Git会为每个commit创建一个新的SHA。对于Git,SHA为commit的标识符,因此不同的标识符代表着不同的commit,无论内容是否发生了变化。如果你已推送了你想进行变基的commit,则不应变基。如果你在与其他开发者协作,那么他们可能已经在使用你推送的 commit。如果你随后使用 git rebase来进行更改,并强行推送 commit,则其他开发者现在将无法与远程仓库同步。他们需要对自己的 Git 仓库进行一些复杂的手术,使它们的仓库回到工作状态……甚至可能连这一点都做不了;他们可能得抛弃之前的所有工作,使用你新变基过且强制推送的 commit 重新开始。

Remote collaboration commands

git remote #用于连接到多个不同的远程仓库
git remote add #用于添加到新的远程仓库的连接并设置简写名
git remote -v #用于查看远程仓库的详细信息,如完整路径而非简写名
git remove rename origin mine  #重置远程仓库名称
git push `<remote-shortname>` `<branch>` #用于从本地仓库向远程仓库某分支推送commit
git pull `<remote-shortname>` `<branch>` #在本地仓库中拉取远程仓库的更改(fast-forward),复制或合并
# git pull - merge default, force it to integrate the remote branch with a rebase by passing it the --rebase option.
git fetch `<remote-shortname>` `<branch>` #用于从远程仓库分支检索commit ,但不会自动将本地分支与远程跟踪分支合并。

# fork会创建远程仓库的一份新副本到自己的账户中以获取完全控制权
# Pull Request 是让源仓库拉取你的 commit,并融合在其项目中的请求

# git远程分支覆盖本地分支
git fetch --all
git reset --hard origin/master (这里master要修改为对应的分支名)
git pull

Miscellaneous

git commit msg rules

  1. Separate subeject from body with a blank line
  2. Limit the subject line to 50 characters
  3. Capitalize the subject line
  4. Do not end the subject line with a period
  5. Use the imperative mood in the subject line
  6. Wrap the body at 72

合并冲突指示符解释

  • «««< HEAD 此行下方的所有内容(直到下个指示符)显示了当前分支上的行
  • ||||||| merged common ancestors 此行下方的所有内容(直到下个指示符)显示了原始行的内容
  • =======表示原始行内容的结束位置,之后的所有行(直到下个指示符)是被合并的当前分支上的行的内容
  • >>>>>>> heading-update 是要被合并的分支(此例中是 heading-update 分支)上的行结束指示符

git使用命令行分页器less浏览所有信息,以下是less快捷键

  • 上下滚动一行分别使用上下键或k j
  • 上下半屏滚动分别使用d u
  • 上下全屏滚动分别使用f b
  • q键退出日志

祖先引用

HEAD表示你当前的位置(它可以指向多个东西,但通常会指向分支名称或直接指向一个 commit 的 SHA)。通常会用到祖先引用来指代之前的 commit。祖先引用包含: ^ 表示父 commit, ~ 表示第一个父 commit,示例如下:

  • 当前commit的父commit:HEAD^ or HEAD~ or HEAD~1
  • 当前commit的祖父commit:HEAD^^ or HEAD~2
  • 当前commit的曾祖父commit:HEAD^^^ or HEAD~3

^ 和 ~ 的区别主要体现在通过合并而创建的 commit 中。合并 commit 具有两个父级。对于合并 commit,^ 引用用来表示第一个父 commit,而 ^2 表示第二个父 commit。第一个父 commit 是当你运行 git merge 时所处的分支,而第二个父 commit 是被合并的分支。~ 永远表示第一个父 commit。

Git托管平台的SSH key配置

SSH是一种基于密钥(位于服务器端和本地的物理文件)的更安全的身份验证方法。

  • 设置github的user name和email:git config --global user.name "GitHub账号" git config --global user.email "GitHub邮箱"
  • 在本地生成密钥对:ssh-keygen -t rsa -C "your_email@example.com"
  • 将SSH私钥添加到SSH-agent,配置ssh-agent程序使用SSH key
    • 在后台启动 ssh-agent:eval $(ssh-agent -s)
    • 将SSH私钥添加到 ssh-agent:ssh -add /Users/yjwwa/.ssh/id_rsa
  • 将SSH公钥添加到GitHub账户,配置GitHub需要使用SSH key
    • 先复制SSH公钥的完整内容:clip < /Users/yjwwa/.ssh/id_rsa.pub
    • 进入GitHub设置页面选择SSH keys选项并点击add SSH key
    • 取名并将之前复制的公钥内容粘贴到Key中
  • 测试:ssh -T git@github.com

Untrack files already added to git repository based on .gitignore

# Step 1: Commit all your changes
# Step 2: Remove everything from the repository.
# –cached only remove files from the index. Files will still be there.
# `git rm` can be unforgiving. Try with -n or --dry-run to test things out
git rm -r --cached .
# Step 3: Readd everything.
git add .
# Step 4: Commit
git commit -m ".gitignore fix"
# Step 5: Push the changes to your remote

git log aliases in .gitconfig

# One liner with colors
l1 = log --pretty=format:"%C(yellow)%h\\ %ad%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate --date=short
# Graph one liner
l2 = log --graph --oneline --decorate --all
# Search commit name history
l3 = !git log --oneline | grep
# Details about the last commit
l4 = log -p -1
# Get commits for n days before today
l5 = "!f() { \
        git log --after=\"$(date -j -v-$1d +%Y-%m-%d)\" --oneline; \
    }; f"

本地分支完全同步为远程分支

# git fetch 只是下载远程的库的内容,不做任何的合并
git fetch --all  
# git reset 把HEAD指向刚刚下载的最新的版本
git reset --hard origin/master 
git pull

合并特定commits到另一个分支

  • 合并某个分支上的单个commit
# 将feature分支上的commit 62ecb3合并到master分支
git checkout master
git cherry-pick 62ecb3
  • 合并某个分支上的一系列commits
# 将feature分支的commit 76cada~62ecb3 合并到master分支
# 基于feature分支创建一个新的分支,并指明新分支的最后一个commit
git checkout -b newbranch 63ecb3
# rebase这个新分支的commit到master,76cada^ 指明你想从哪个特定的commit开始
git rebase --onto master 76cada^