Git

git_commands

配置

git config --global user.name "your_username"
git config --global user.email "your_email"

# 查看所有配置
git config -l

初始化

# 初始化指定目录
git init git-demo

# 初始化当前目录
git init

查看状态

git status
git status -s # 简化版

# short format
# ?? file # 文件未追踪
# A file  # 文件已添加
# M file  # 文件被修改
# M file  # 文件被修改且已加入暂存区

标识

  • SHA1标识:f1dfde5930bb26b7e94738481aca2bad6fc74b39
    • 可以使用缩写,只写前4+位
  • HEAD引用:指向当前分支的最新修订
    • HEAD^n:当HEAD或标识存在分支合并时,指向第n个父修订
    • HEAD~m:指向第m个祖先修订
    • HEAD^n~m:指向第n个父修订的第m个祖先修订
    • HEAD@{k}:指向倒数第k个历史操作指向的修订
  • 分支引用:指向所指分支的最后一个修订

查看历史记录

查看提交记录

git log
git log --graph
git --no-pager log # 输出到stdout
git log --oneline # 一行展示

# 查看最近3条记录,-3表示输出不查过3行
git log HEAD -3

# 查看离 e85fe7 最近3条记录
git log e85fe7 -3

# 单行显示
git log --abbrev-commit --pretty=oneline

# 只显示提交备注
git log --pretty=format:'%s'

# 配置alias
git config --global alias.hist 'log --pretty=format:"%h %ad | %s%d [%an]" --date=short'
git hist

git config --global alias.graph 'log --graph'
git graph

git config --global alias.mist 'log --pretty=format:"%s"'
git mist

查看提交

# 查看 e85fe7 的修订记录
git show e85fe7

# 查看倒数第2次记录
# HEAD: 当前修订,等于HEAD~0
# HEAD~1: 前一个修订
# HEAD~2: 前两个修订
git show HEAD~2

查看文件差异

# ckeck difference
git diff
git diff --name-only # 只显示文件名
git diff --stat # 显示统计信息

# 查看倒数第二次修订和当前修订中,file1文件的差异
git diff HEAD~1 HEAD file1

difftool

~/.gitconfig 中写入一下配置

[diff]
    tool = vscode
[difftool "vscode"]
    cmd = code --wait --diff $LOCAL $REMOTE

然后可以在 vscode 中查看 diff 内容

git difftool {{branch you want to check with}}

查看操作记录

git reflog

工作区(working directory)

修改/撤销修改

# 修改文件
echo hello > file1

# 撤销修改
git reset HEAD --hard
git stash # 实际上是将更改存入栈中,需要时可以git stash pop取出来
git clean -fd # 清除所有未提交的修改

# 将未暂存的文件修改丢弃,退回到暂存区/版本库
git checkout -- file1
# or
git restore file1

# 撤销所有修改
git checkout -- .
# or
git restore .

# 修改提交信息
git commit --amend

暂存区(staging area)

加入/撤销暂存区(staging area)

git add 加入暂存区的是对文件的修改而不是文件,因此文件每次修改都要add

# 加入暂存区
git add bugfile
git add featurefile

# 如果只想加入一个文件内的一部分修改,则需要创建hunk
git add -p

# 移出暂存区
git reset featurefile

# 将所有修改移出暂存区
git reset .

提交

git commit -m "update"

# 将所有未暂存的修改暂存然后提交,但是不会暂存未追踪的文件
git commit -m "update" -a

# 撤销提交
git reset HEAD            # HEAD 表示当前commit,将未commit的修改放回工作区,但是不会修改文件内容
git reset HEAD --hard     # HEAD 表示当前commit,丢掉所有未commit的修改,包括工作区和暂存区
git reset HEAD~1          # HEAD~1 表示前一个commit,与当前文件不一致的会放回工作区
git reset HEAD~1 --hard   # HEAD~1 表示前一个commit,立刻让所有文件变为前一个commit的样子


# 恢复撤销
# 列出所有操作
git reflog
# 恢复到reflog中的第1个操作时
git reset HEAD@{1}
# --hard表示同时覆盖工作区和暂存区的文件
git reset --hard HEAD@{1}

Tag

# 查看 tag
git tag

# 添加 tag
git tag -a v1.4 -m "my version 1.4"

# 删除 tag
git tag -d v1.4

# checkout tag
git checkout v2.0.0
git checkout tags/v2.0.0

# push tag
git push origin v2.0.0

分支

# 查看分支
git branch
git branch -a # 查看所有分支

# 创建分支
git branch dev

# 切换分支
git checkout dev
git checkout -b dev # 创建并切换分支

# 合并分支
git merge dev # 直接将master的指针指向dev的最后一个commit,同时合并dev之前所有的commit
git merge --no-ff -m "merge with no-ff" dev # 会在dev最后一个commit的基础上,创建一个新的commit
git merge dev --squash # 将分支的所有修改同步到暂存区,但是不commit,需要一次手动commit,好处是dev分支的commit记录并不会同步到master分支

# rebase
git rebase -i HEAD~3 # rebase最近三次commit

# 通过rebase合并分支
git rebase dev
git add --all # 修订完所有conflict后
git rebase --continue

# 删除分支
git branch -d dev
git branch -D dev # 删除还没合并的分支

# 批量删除多个分支
git branch -D $(git --no-pager branch --list 'bugfix*')

# 把当前分支全部修订搬移到指定分支,两个分支的历史合并成一条线
git rebase dev

远程仓库

# 查看远程仓库
git remote
git remote -v

# 给远程仓库取别名,一般是origin
git remote add origin http://git.example.com

# 推送到远程仓库
git push origin master
git push origin dev

# 拉取仓库
git fetch origin

# 在本地创建和远程分支对应的分支
git checkout -b branch-name origin/branch-name

# 建立本地分支和远程分支的关联
git branch --set-upstream branch-name origin/branch-name

# 抓取远程的新提交
git pull
git pull origin dev # 等价于先拉取然后merge => git fetch origin; git merge origin/master dev
git pull -r origin dev # 在pull的时候使用rebase

# 修改远程仓库地址(例如远程仓库换域名了)
git remote set-url origin git@new.host:srv/project

搭建Git服务器

  1. 创建git用户
sudo adduser git
sudo passwd git
  1. 把所有公钥导入到/home/git/.ssh/authorized_keys
  2. 初始化Git仓库
cd /home/git/srv
mkdir sample.git
sudo git init --bare sample.git
sudo chown -R git:git sample.git
  1. 禁用shell登录

/etc/passwd中加上git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell

  1. 克隆远程仓库
git clone git@server:srv/sample.git

Github

Clone from github

git clone https://github.com/cyzlmh/cyzlmh.github.io

# with token

git clone https://cyzlmh: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@github.com/cyzlmh/cyzlmh.github.io

Submit changes

git add --all
git commit -m "some comments"
git push -u origin master

# make quick push alias
alias quick-push='git add --all && git commit -m "update" && git push -u origin master'

Push local dir

git init
git add --all
git commit -m "init"
git remote add origin 'https://github.com/cyzlmh/cyzlmh.github.io'

Utils

Git Ignore

Pattern Example matches Explanation
*.log debug.log 所有文件夹中满足的 pattern 的
logs/ logs/debug.log 所有满足的 pattern 的文件夹中的文件
/debug.log /debug.log 根文件夹中满足的 pattern 的文件

示例

# MacOS
.DS_Store

# logs
*.log
logs/

# binary
bin/

汇总:https://github.com/github/gitignore

自动创建.gitignorehttps://www.toptal.com/developers/gitignore

Git-lfs

github - Git Large File Storage

install

# macos
brew install git-lfs

# ubuntu
sudo apt-get install git-lfs

# centos
sudo yum install git-lfs

清除.DS_Store

find . -name .DS_Store -print0 | xargs -0 git rm -f --ignore-unmatch
echo .DS_Store >> .gitignore
git add .gitignore
git commit -m '.DS_Store banished!'

References