git 使用 tips

查看配置

$ git config -l
user.name=runsisi@hust.edu.cn
user.email=runsisi@hust.edu.cn
alias.br=branch
alias.st=status
alias.ci=commit
alias.co=checkout
alias.cp=cherry-pick
alias.log1=log --oneline
...

基本配置

$ git config --global user.name runsisi
$ git config --global user.name runsisi@hust.edu.cn
$ git config --global core.editor vim
$ git config --global log.date local
$ git config --global diff.tool vimdiff
$ git config --global merge.tool vimdiff
$ git config --global difftool.prompt false
$ git config --global mergetool.prompt false

终端输出增加彩色显示

$ git config --global color.ui auto

将 color.ui 选项设置成 always, auto, true 将使得终端输出增加彩色显示,这在 git diff 时很有用,如果设置成 never 或者 false,将关闭彩色显示。

忽略文件可执行权限的修改

$ git config core.filemode false

git 命令 alias

$ git config --global alias.br branch
$ git config --global alias.st status
$ git config --global alias.ci commit
$ git config --global alias.co checkout
$ git config --global alias.cp cherry-pick
$ git config --global alias.log1 'log --oneline'

git rebase -i 到第一个 commit

$ git rebase -i --root

提交当前修改并合并到上一个 commit

$ git commit -as --amend --no-edit
[master 1e16cdc] add `load` subcommand
 Author: luo.runbing <runsisi@example.com>
 Date: Fri Apr 12 10:23:14 2019 +0800
 5 files changed, 52 insertions(+), 51 deletions(-)
 create mode 100644 cmd/iptables/examples.d/zds.rules

我一般不加 --no-edit 选项,此时会弹出编辑器界面(我配置的是 vi),在 vi 中保存命令 :wq 似乎比输入 --no-edit 更简单。

修改当前分支最后一个 commit 的 author 信息

$ git log
commit b15c69a7c374fdd4243a003f26f79f52dfba547c (HEAD -> master)
Author: runsisi <runsisi@hust.edu.cn>
Date:   Fri Apr 12 10:22:55 2019

    add `load` subcommand

    Signed-off-by: runsisi <runsisi@hust.edu.cn>

commit 96125fe94aef5e324f5a77df17c60422542b37db
Author: runsisi <runsisi@hust.edu.cn>
Date:   Thu Apr 11 21:49:23 2019

    log to file

    Signed-off-by: runsisi <runsisi@hust.edu.cn>
$ git -c user.name="luo.runbing" -c user.email="runsisi@example.com" commit --amend --reset-author

或者:

$ git commit --amend --author "luo.runbing <runsisi@example.com>"
$ git log
commit 6a50f6cb25b6c9a2322f1d5c4bc106bbe9a0c820 (HEAD -> master)
Author: luo.runbing <runsisi@example.com>
Date:   Fri Apr 12 10:23:14 2019

    add `load` subcommand

    Signed-off-by: runsisi <runsisi@hust.edu.cn>

commit 96125fe94aef5e324f5a77df17c60422542b37db
Author: runsisi <runsisi@hust.edu.cn>
Date:   Thu Apr 11 21:49:23 2019

    log to file

    Signed-off-by: runsisi <runsisi@hust.edu.cn>

修改当前分支指定 commit 的 author 信息

$ git log
commit 1e16cdc42c504215c2c58ca7fe8bc4685b707e05 (HEAD -> master)
Author: luo.runbing <runsisi@example.com>
Date:   Fri Apr 12 10:23:14 2019

    add `load` subcommand

    Signed-off-by: runsisi <runsisi@hust.edu.cn>

commit dff4a0887ee6e3b8a6d20961a82be19cc4db9801
Author: runsisi <runsisi@hust.edu.cn>
Date:   Thu Apr 11 21:49:23 2019

    log to file

    Signed-off-by: runsisi <runsisi@hust.edu.cn>

commit 565c6f6deab43f00daa7944d14c030018df138fc
Author: runsisi <runsisi@hust.edu.cn>
Date:   Thu Apr 11 18:46:52 2019

    strip source and destination

    Signed-off-by: runsisi <runsisi@hust.edu.cn>
$ git rebase -i 565c6f6de
e dff4a08 log to file
e 1e16cdc add `load` subcommand

# Rebase 565c6f6..1e16cdc onto 565c6f6 (2 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
...

保存并退出,然后逐个进行修改:

$ git -c user.name="luo.runbing" -c user.email="runsisi@example.com" commit --amend --reset-author

或者:

$ git commit --amend --author "luo.runbing <runsisi@example.com>"

每修改完一个之后,然后 continue:

$ git rebase --continue
Stopped at 908de06...  add `load` subcommand
You can amend the commit now, with

  git commit --amend

Once you are satisfied with your changes, run

  git rebase --continue

继续修改下一个 commit:

$ git -c user.name="luo.runbing" -c user.email="runsisi@example.com" commit --amend --reset-author

或者:

$ git commit --amend --author "luo.runbing <runsisi@example.com>"

直至所有 commit 修改完成,即 rebase 完成:

$ git rebase --continue
Successfully rebased and updated refs/heads/master.

最终效果如下:

$ git log
commit 282f4ee2de7448595c8712262da4d6297931c9b3 (HEAD -> master)
Author: luo.runbing <runsisi@example.com>
Date:   Fri Apr 12 10:23:14 2019

    add `load` subcommand

    Signed-off-by: runsisi <runsisi@hust.edu.cn>

commit 3f208714c1c79c83a6bbe31cfccd1e83d8717a68
Author: luo.runbing <runsisi@example.com>
Date:   Thu Apr 11 21:49:23 2019

    log to file

    Signed-off-by: runsisi <runsisi@hust.edu.cn>

commit 565c6f6deab43f00daa7944d14c030018df138fc
Author: runsisi <runsisi@hust.edu.cn>
Date:   Thu Apr 11 18:46:52 2019

    strip source and destination

    Signed-off-by: runsisi <runsisi@hust.edu.cn>

批量修改 author 信息

$ git filter-branch --force --env-filter '
OLD_NAME="runsisi"
NEW_NAME="luo.runbing"
NEW_EMAIL="luo.runbing@example.com"

if [ "$GIT_AUTHOR_NAME" = "$OLD_NAME" ]; then
    GIT_COMMITTER_NAME="$NEW_NAME";
    GIT_COMMITTER_EMAIL="$NEW_EMAIL";
    GIT_AUTHOR_NAME="$NEW_NAME";
    GIT_AUTHOR_EMAIL="$NEW_EMAIL";
fi' -- HEAD~3 HEAD
$ git filter-branch --force --env-filter '
OLD_EMAIL="runsisi@hust.edu.cn"
NEW_NAME="luo.runbing"
NEW_EMAIL="luo.runbing@example.com"

if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]; then
    GIT_COMMITTER_NAME="$NEW_NAME"
    GIT_COMMITTER_EMAIL="$NEW_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]; then
    GIT_AUTHOR_NAME="$NEW_NAME"
    GIT_AUTHOR_EMAIL="$NEW_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

修改 Signed-off-by 信息

Signed-off-by 信息,实际上是 commit 信息的一部分,可以使用修改 author 类似的命令,但在 git commit --amend 时不需要添加 --reset-author--author 信息。

此外,使用 git rebase -i 进行多个 commit 修改的时候使用 reword 会比 edit 更方便一些,因为 reword 不需要每次修改完一个 commit 之后执行 git rebase --continue

# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending

批量修改 Signed-off-by 信息

$ git filter-branch --force --msg-filter '
OLD_SIGNED_OFF="Signed-off-by: runsisi <runsisi@hust.edu.cn>"
NEW_SIGNED_OFF="Signed-off-by: luo.runbing <luo.runbing@example.com>"
sed -e "s#$OLD_SIGNED_OFF#$NEW_SIGNED_OFF#"
' -- --all

查看 committer 信息

$ git log --format=fuller
commit 1575e59f6e2a8f2ebc63368e6fd84d7082bafa67 (HEAD -> master)
Author:     runsisi <runsisi@hust.edu.cn>
AuthorDate: Fri Apr 12 12:09:36 2019
Commit:     runsisi <runsisi@hust.edu.cn>
CommitDate: Fri Apr 12 12:13:23 2019

    add `load` subcommand

    Signed-off-by: runsisi <runsisi@hust.edu.cn>

commit 92af285d2a92802fa7c709b290130a9064a412bf
Author:     runsisi <runsisi@hust.edu.cn>
AuthorDate: Fri Apr 12 12:09:19 2019
Commit:     runsisi <runsisi@hust.edu.cn>
CommitDate: Fri Apr 12 12:13:06 2019

    log to file

    Signed-off-by: runsisi <runsisi@hust.edu.cn>

修改 committer 信息

// 指定 commit hash
git filter-branch --force --env-filter '
COMMIT="7b3cdbdb04535cf7822867bc2e02fc98f020a292"
NEW_NAME="runsisi"
NEW_EMAIL="runsisi@example.com"

if [ "$GIT_COMMIT" = "$COMMIT" ]; then
    GIT_COMMITTER_NAME="$NEW_NAME";
    GIT_COMMITTER_EMAIL="$NEW_EMAIL";
fi' -- HEAD~2 HEAD

// 指定 master 分支 commit 范围
git filter-branch --force --env-filter '
NEW_NAME="luo.runbing"
NEW_EMAIL="luo.runbing@example.com"

GIT_COMMITTER_NAME="$NEW_NAME";
GIT_COMMITTER_EMAIL="$NEW_EMAIL";
' -- HEAD~2 HEAD

// HEAD
git filter-branch --force --env-filter '
NEW_NAME="luo.runbing"
NEW_EMAIL="luo.runbing@example.com"

GIT_COMMITTER_NAME="$NEW_NAME";
GIT_COMMITTER_EMAIL="$NEW_EMAIL";
' -- HEAD

// 指定分支 commit 范围
git filter-branch --force --env-filter '
NEW_NAME="runsisi"
NEW_EMAIL="luo.runbing@example.com"

GIT_COMMITTER_NAME="$NEW_NAME";
GIT_COMMITTER_EMAIL="$NEW_EMAIL";
' -- 5d435b 682e12f master

查看 gpg 签名信息

$ git log --show-signature -1
commit cec84be04851d1c459b140c57e634db90517a2ad (HEAD -> master)
gpg: Signature made Wed 17 Apr 2019 06:53:30 PM CST
gpg:                using RSA key DFD781A7C8334975F2FD0DC7DA3BFDCF8D77F675
gpg: Good signature from "luo.runbing (https://www.example.com/) <luo.runbing@example.com>" [ultimate]
gpg:                 aka "runsisi (https://runsisi.com/) <runsisi@hust.edu.cn>" [ultimate]
Author: luo.runbing <luo.runbing@example.com>
Date:   Wed Apr 17 17:30:58 2019

    simplify rulesets config

    Signed-off-by: luo.runbing <luo.runbing@example.com>

克隆并切换到指定分支

$ git clone -b luminous https://github.com/ceph/ceph.git

仅克隆一个 commit

$ git clone -b luminous --depth 1 https://github.com/ceph/ceph.git

操作远端 git repo

查看

$ git remote -v
origin	https://runsisi@github.com/runsisi/ceph.git (fetch)
origin	https://runsisi@github.com/runsisi/ceph.git (push)
upstream	https://github.com/ceph/ceph.git (fetch)
upstream	https://github.com/ceph/ceph.git (push)

删除

$ git remove rm upstream
$ git remote -v
origin	https://runsisi@github.com/runsisi/ceph.git (fetch)
origin	https://runsisi@github.com/runsisi/ceph.git (push)

添加

$ git remote add upstream https://github.com/ceph/ceph.git
$ git remote -v
origin	https://runsisi@github.com/runsisi/ceph.git (fetch)
origin	https://runsisi@github.com/runsisi/ceph.git (push)
upstream	https://github.com/ceph/ceph.git (fetch)
upstream	https://github.com/ceph/ceph.git (push)

重命名

$ git remote rename upstream gh

修改 url

$ git remote set-url origin git@github.com:runsisi/ceph.git
$ git remote -v
gh	https://github.com/ceph/ceph.git (fetch)
gh	https://github.com/ceph/ceph.git (push)
origin	git@github.com:runsisi/ceph.git (fetch)
origin	git@github.com:runsisi/ceph.git (push)

删除远端分支

$ git push origin :wip-to-rm

拉取 github pull request 到本地

$ git remote add upstream https://github.com/ceph/ceph.git
$ git pull upstream pull/1234/head

拉取 gitlab merge request 到本地

$ git remote add upstream https://gitlab.com/coldnight/ci-test.git
$ git pull upstream merge-requests/3344/head

查看两个 commit 之间修改了哪些文件

$ git diff --name-only HEAD~3 HEAD

diff 显示当前已修改的文件

只包括 Changes not staged for commit

$ git diff
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 08cafaf..802e6de 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
...

只包括 Changes not staged for commit

$ git diff --cached
diff --git a/cmake/modules/FindDtkWm.cmake b/cmake/modules/FindDtkWm.cmake
new file mode 100644
index 0000000..fe7dcc3
...

包括 Changes to be committedChanges not staged for commit,但不包括 Untracked files

$ git diff HEAD
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 08cafaf..802e6de 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
...

查看指定 commit 包含在哪些分支上

$ git branch -a --contains 4873e040
  12.2.12
  remotes/origin/12.2.12
  remotes/origin/HEAD -> origin/12.2.12
  remotes/origin/luminous
  remotes/upstream/luminous

查找删除指定代码的 commit

$ git log -S ceph_rest_api src/pybind/CMakeLists.txt
commit 495742f7dd635a240f39c708233d3bd84c56aa17
Author: Nathan Cutler <ncutler@suse.com>
Date:   Thu Sep 7 02:09:44 2017

    tools: cleanup: rip out ceph-rest-api

    Obsoleted by the mgr REST API.

    Fixes: http://tracker.ceph.com/issues/21264
    Signed-off-by: Nathan Cutler <ncutler@suse.com>

删除远程分支

$ git push origin :wip-jemalloc-operator-new
Password for 'https://runsisi@github.com':
To https://github.com/runsisi/pyleak.git
 - [deleted]         wip-jemalloc-operator-new

针对指定 commit 生成压缩包

$ git archive -o xxx.tar.gz HEAD

打包本地 repo

$ git bundle create test.bd wip-bundle
Counting objects: 54, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (49/49), done.
Writing objects: 100% (54/54), 16.47 KiB | 2.06 MiB/s, done.
Total 54 (delta 21), reused 0 (delta 0)
$ cd ../
$ git clone -b wip-bundle test/test.bd mirror-repo
Cloning into 'mirror-repo'...
Receiving objects: 100% (54/54), 16.47 KiB | 16.47 MiB/s, done.
Resolving deltas: 100% (21/21), done.

git 生成 patch

$ git diff HEAD~1 HEAD > ../patch-p1.diff
$ git diff HEAD > ../patch-p1.diff
$ git diff --no-prefix HEAD > ../patch-p0.diff

使用 git diff 生成的 patch

$ patch -p0 < ../patch-p0.diff
patching file CMakeLists.txt
patching file cmake/modules/FindDtkWm.cmake
patching file src/mainwindow.cpp
$ patch -p1 < ../patch-p1.diff
patching file CMakeLists.txt
patching file cmake/modules/FindDtkWm.cmake
patching file src/mainwindow.cpp
$ git apply -p0 ../patch-p0.diff
$ git apply ../patch-p1.diff

镜像 github 仓库到本地

https://runsisi.com/2019/04/15/git-mirror/

git 使用 http 代理

https://runsisi.com/2019/01/25/git-proxy/

修改 git 日志默认的注释行标识

$ git config core.commentChar ";"

这样就可以在 git 日志中加上 gdb 打印的调用栈。

参考资料

How can I change the author name / email of a commit?

https://www.git-tower.com/learn/git/faq/change-author-name-email

How to change the author and committer name and e-mail of multiple commits in Git?

https://stackoverflow.com/questions/750172/how-to-change-the-author-and-committer-name-and-e-mail-of-multiple-commits-in-gi

How to change the commit author for one specific commit?

https://stackoverflow.com/questions/3042437/how-to-change-the-commit-author-for-one-specific-commit/28845565

How do I “git blame” a deleted line?

https://stackoverflow.com/questions/4404444/how-do-i-git-blame-a-deleted-line

Start a git commit message with a hashmark (#)

https://stackoverflow.com/questions/2788092/start-a-git-commit-message-with-a-hashmark


最后修改于 2019-04-12