Git 命令集合

一、创建、提交、修改,查看

创建本地仓库

使用 git init 后,会创建一个 .git 隐藏文件夹,这个文件夹是我们的版本库

mkdir newFolder
cd newFolder
git init

查看路径:

pwd

添加,提交

添加单个文件:

git add <file/folder>
git commit -m "add a new file"

添加更新的文件:

git add -u

也可以用 commit -am 来仅添加已经跟踪的更新的文件:

git commit -am "msg"  # -a可以让更新的文件添加到库中(新建的未跟踪的文件,不会添加到库中)

添加未跟踪的文件:

git add $(git ls-files -o --exclude-standard)

添加所有文件:

git add . 添加所有未跟踪、修改的文件,并且会根据 .gitignore 过滤 ; git add * 不会根据 .gitignore 过滤(过滤文件不会直接添加进入,但是会有提醒)

git add .
git add *

添加多个文件:

git add f1.txt f2.txt
git commit -m "add two files."

查看当前状态,是否被修改:

git status

对比文件,查看修改的地方:

  1. 查看所有文件的改动。如果改动部分尚未提交到暂存区(尚未 git add .),则默认是用版本库的的版本和当前工作区对比。如果已经使用git add . 命令,则会用暂存区和当前工作区对比,此时如果想要用暂存区和版本库对比,可以加上--cached
git diff [--cached]
  1. 查看某个文件的改动
git diff xx.txt
  1. 查看版本之间的改动
git diff commitID1 commitID2 <file> # file可以省略,则对比两个版本之间的所有不同,加上file,则只对比某个文件的不同之处
  1. 仅查看所有改动的文件名(不显示内容变动)
git diff --name-only <commitID1> <commitID2>

显示文件

现有如下状态的文件改动:

$ git st
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)      # 暂存区中 git add,重命名,删除的文件
        modified:   a
        renamed:    b -> bb
        deleted:    d

Changes not staged for commit:						# 工作区,已修改未add的文件
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   c

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        t/

  1. 从工作区提取所有的修改,重命名的文件。(不管有没有add进暂存区,都会查出来,已经删除的文件不会显示)
$ git ls-files -c
a
bb
c
  1. 提取没有git add 的文件
$ git ls-files -m
c
  1. 提取所有未跟踪的文件
$ git ls-files -o --exclude-standard
t/p/b

二、版本回退

查看提交的历史记录:

git log [-number] # 后面可以接数字:git log -2,查看最近的两次记录。不加 -数字,会显示所有的记录。

回到上一个版本

HEAD表示当前版本,HEAD^ 表示上一个版本,HEAD^^ 表示上上个版本,HEAD~100 表示上100个版本。

git reset --hard HEAD^

reset有三种模式,reset --hard, reset --soft, reset,假设我们当前是版本5,想要回到版本3,它们三个的区别是:

reset --hard 版本3: 会将工作区、暂存区、版本库的内容全部回退到版本3,此时工作区、暂存区清空了。
reset --soft: 会将两个版本之间差异的部分放到暂存区,此时直接git commit,就可以直接回到版本5
reset : 会将两个版本的差异放到工作区。此时如果想要回到版本5,需要git add,然后git commit

查看历史记录

通过git log查看历史记录,使用 commit 号回退:只需要写前几位就行了

git log
git reset --hard 1094a
git reset --hard 10941 <file_name>  # 可以单独回退某个文件

通过reset命令回退到某一版本后,无法查看之前的最新的版本了(未来的版本),可以使用这个查看:

git reflog

工作区和暂存区

你的git仓库正常的文件夹,就是你的工作区。在git仓库中,当你 git init 后,会自动生成一个.git的隐藏文件夹,它是 git 的版本库,库里面有一个叫 stage 的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫 HEAD, 第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

撤销修改的方法

1.撤销工作区的修改,尚未使用add方法。即只在工作区修改,但是尚未提交到暂存区的修改。(如果你使用了add 提交到了暂存区,它只能让你回到暂存区的状态;没有使用add方法,可以让你回到版本库的状态,也就是撤销所有工作区的修改)

git checkout -- xx.txt # 仅撤销某个文件的更改
git checkout . # 撤销所有的更改

2.撤销暂存区的修改,并放回到工作区:使用了add方法,提交到了暂存区,但是没有使用commit方法提交到当前分支。

git reset HEAD <file>        # 先撤销暂存区的修改,放回到工作区
git checkout -- xx.txt       # 再撤销工作区

删除文件

git rm xx.txt  # 从版本库中删除已经跟踪的文件
git rm --cached xx.txt  # 从版本库删除某个跟踪的文件,但是本地不删除它(仅仅取消跟踪)
git clean -fd # 批量删除所有未跟踪的文件
rm xx.txt # 删除某个未跟踪的文件

还原删除的文件

git checkout -- test.txt  # -- 代表不指定版本,也就是从head指针恢复,如果指定 commitId,则可以从某个版本恢复文件

三、分支管理

创建分支并切换

第一种

git checkout -b dev

第二种(个人试了没用,可能和git版本有关)

git switch -c dev

git checkout 加上 -b 代表创建分支,并切换到当前分支,等同于下面的命令:

git branch dev      # 创建分支
git checkout dev    # 切换分支


git switch dev   # 另一种切换分支的方法

查看分支

git branch

合并分支:

将 dev 分支,合并到当前分支上

git merge dev

通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的 commit,这样,从分支历史上就可以看出分支信息。

git merge --no-ff -m "merge with no-ff" dev

删除分支

git branch -d dev   # 如果没有合并分支,可能删除不掉
git branch -D dev  # 强制删除

合并冲突

当两个分支有冲突时,无法自动完成合并,可以手动查看文件,用 vi 命令打开文件并修改冲突部分,然后正常的使用 git add git commit 完成合并。

git使用 <<<<<<<, ======, >>>>>>> 来标记不同分支的内容。

$ cat a.txt
I love my mlllllllla
<<<<<<< HEAD  # HEAD 是当前分支的名称
=======

aaaaaaaaaaaaaaaaaaa
>>>>>>> f1    # f1 是合并进来的分支的名称

<<<<<<<======= 之间的数据,是当前分支的代码。

=======>>>>>>> 之间的数据,是别的分支上的代码。

根据需要,修改代码,并删除 <<<<<<<, ======, >>>>>>> 这三个标识符,即可使用 git add xx、 git commit -m "xx" 完成合并。

查看合并记录:

git log --graph

Bug 分支

假设你当前分支的工作做到一半,还不能提交,但是又需要回到工作区初始的状态来做些别的工作,那可以用 stash 将现场存起来。它可以保存你所做的所有更改,并且将工作区恢复到上次版本的状态(所有未提交的修改,全部清除掉)

  1. 保存现场
git stash [-k] [-u]  # -k,-u,-a是可选项,-k代表保持索引(如果你修改了一个文件,并且已经 git add,那么使用这个参数,可以保持文件已经 git add 的状态,否则,会将工作区恢复到上次版本的状态); -u可以将 untracked 的文件,也保存起来(即从来没有出现在库里的新文件),-a可以保存所有文件,哪怕文件已经在.gitignore中被忽略
  1. 查看stash
$ git stash list
stash@{0}: On master: msg # 序号越小,越新。就像堆栈一样,
stash@{1}: WIP on master: 865ab8f9 update and debug cases
  1. 恢复最近的一次stash,并手动删除
git stash apply
git stash drop
  1. 恢复stash并自动删除
git stash pop [--index] # 如果之前使用了 -k 参数,使用 --index可以恢复git add 的状态。否则git add的文件,会回到工作区,变成未 git add 的状态。
  1. 恢复特定的stash,需要先用git stash list 查看,然后 apply 恢复
git stash apply stash@{0}
  1. 给 stash 加备注
git stash push -m "msg"  # 其实 git stash 和 git stash push 是一个意思,只不过想要使用 -m参数,就需要写全,也就是加上 push。
  1. 查看stash
git stash show [commitID] # 查看stash的变动
  1. 清空所有stash
git stash clear

同步分支

你用 master 创建了一个分支 bug0,在 bug0 上把 bug 修复了,然后把 bug0 和 master 合并了,这时 master 是修好的,但是 master 的另一个分支 dev 还没有修复好,那怎么能将 dev 上的 bug 也修好?

bug0分支提交修改时:会有一个commit id :5051635

/Desktop/github (bug0)
$ git commit -m 'bug fixed'
[bug0 5051635] bug fixed
 Committer: Wang <zng@local>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

 1 file changed, 1 insertion(+)

然后切换到 dev 分支,使用 cherry-pick 命令让我们复制一个特定的提交到当前分支:

git cherry-pick <commit>

比如:

/Desktop/github (dev)
$ git cherry-pick 5051635
[dev 424b6ee] bug fixed
 Date: Tue Jun 9 17:40:56 2020 +0800
 Committer: Wang <zhong@cnt01.local>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

 1 file changed, 1 insertion(+)

这时 dev 的bug也修好了。

四、远程仓库

添加远程仓库

根据 github 的提示,添加 github 远程仓库

git remote add origin git@github.com:michaelliao/learngit.git

意思是添加一个远程仓库:origin ,它的地址是 git@github.com:michaelliao/learngit.git, 这里用的是 ssh,你需要生成一个密钥,然后在github中添加进去。

推送到远程仓库

第一次推送,带上-u参数,会将本地的分支推送到远程,并且和远程的分支关联起来

git push -u origin master  # 第一次推送,-u;将本地 master 分支推送到远程 origin 上
git push origin master    # 以后的简化操作

将本地分支和远程分支关联,有两种情况:

第一,本地有 dev 分支,远程仓库没有此分支:

# 两句话意思一样,第一句是第二句的简写
git push -u origin dev
git push --set-upstream origin dev

会在远程仓库创建一个分支 origin/dev 并和本地 dev 关联起来

第二,远程有 dev 分支,本地没有

git checkout -b dev origin/dev  # 创建并克隆远程的dev分支到本地dev分支
git branch --set-upstream-to=origin/dev dev  # 设置 dev 分支和远程 origin/dev 分支连接

查看远程仓库信息

git remote

查看更详细内容

git remote -v

查看远程的分支

git branch -r

克隆远程仓库

默认克隆master

git clone git@github.com:michaelliao/gitskills.git

克隆分支

git checkout -b dev origin/dev  # 创建并克隆远程的dev分支到本地dev分支

设置 dev 分支和远程 origin/dev 分支连接,才能git pull下来

git branch --set-upstream-to=origin/dev dev

多人协作:

  1. 首先,可以试图用git push origin 推送自己的修改;
  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull 拉取下来,然后合并;
  3. 如果合并有冲突,则解决冲突,并在本地提交;
  4. 没有冲突或者解决掉冲突后,再用git push origin 推送就能成功!

如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to origin/<branch-name>

rebase(http://gitbook.liuhui998.com/4_2.html)

  1. 合并本地的几个commit记录(最好只合并本地的,未push的记录,如果某个记录已经 push 了,然后本地 rebase 时包含了这个记录,push时会有问题)
git rebase -i HEAD~2  # 合并最近的2条 commit 记录; 
git rebase -i <commitID>  # 从当前HEAD一直合并到某个commitID上。

输入上面的命令后,会出现一个vi编辑文本窗口,注意前两行:pick [commit ID] [commit msg]

按下 i 键,编辑文本,将第二行的 pick 改成 s ,然后 Esc 保存退出::wq, 这样可以将 v3 这条记录,合并到 v2 上。

其实底下的说明文字已经很清楚了:s,代表将此 commit 合并的上一个提交上。

pick 8ee8c5c v2
pick 3d134f7 v3

# Rebase d2f44c9..3d134f7 onto d2f44c9 (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#

保存退出后,会继续出现一个 vi 编辑文本框,因为你之前提交了两次,现在合并成一次,所以现在给你个机会让你修改 commit message,如果不需要修改,可以直接:wq退出,会保留两次 commit msg.

  1. 合并两个分支记录

正常的 merge 操作,可以合并两个分支,但是在使用git log --graph时,可以看出分支分叉,然后合并的操作。如果不想要这个操作,可以这么做:
前提:假设 master 最新的提交是 v3, dev 分支基于 v3 分出来的,然后 dev 前向提交了一次,走到了 v4; master 也提交了一次,走到了 v5.

$ git log
commit 58e90228a37f03b23fb6168efa08849441facd48 (HEAD -> dev)
Author: wztshine <none>
Date:   Fri Oct 8 22:14:50 2021 +0800

    v4

commit 3d134f77cbcce2c09c499c85a6526dd8c058d630
Author: wztshine <none>
Date:   Fri Oct 8 21:40:25 2021 +0800

    v3

commit 8ee8c5c4215ed5da08af8d8c46fd096c9788f07e
Author: wztshine <none>
Date:   Fri Oct 8 21:40:14 2021 +0800

    v2

commit d2f44c928add3708a7897c446f028d75871e5f94
Author: wztshine <none>
Date:   Fri Oct 8 21:40:01 2021 +0800

    v1

==================================

$ git log
commit bd27e9865acab57e505e08807da2b5dd1c398022 (HEAD -> master)
Author: wztshine <none>
Date:   Fri Oct 8 22:15:26 2021 +0800

    v5

commit 3d134f77cbcce2c09c499c85a6526dd8c058d630
Author: wztshine <none>
Date:   Fri Oct 8 21:40:25 2021 +0800

    v3

commit 8ee8c5c4215ed5da08af8d8c46fd096c9788f07e
Author: wztshine <none>
Date:   Fri Oct 8 21:40:14 2021 +0800

    v2

commit d2f44c928add3708a7897c446f028d75871e5f94
Author: wztshine <none>
Date:   Fri Oct 8 21:40:01 2021 +0800

    v1

此时想要合并两个分支,并且 git log --graph 命令中不出现分叉:先切换到 dev,将 master rebase过来,然后切换到master,将dev合并过来。

git checkout dev
git rebase master
git checkout master
git merge dev

假设你基于远程仓库 origin 创建一个新的分支 mywork, 然后你做了几次修改,但是与此同时 origin 也被人修改了,这时你想要合并这两条线。

如果正常合并 merge , 会产生一条合并记录(分叉再汇合),如果使用rebase

$ git checkout mywork
$ git rebase origin

这些命令会把你的"mywork"分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把"mywork"分支更新 到最新的"origin"分支,最后把保存的这些补丁应用到"mywork"分支上。

这样虽然你的分支线断掉了(插入了origin的更新),但是变成了一条线,没有分叉。

在rebase的过程中,也许会出现冲突(conflict). 在这种情况,Git会停止rebase并会让你去解决冲突;在解决完冲突后,用"git-add"命令去更新修改的冲突文件, 然后,你无需执行 git-commit,只要执行:

$ git rebase --continue

这样git会继续应用(apply)余下的补丁。

在任何时候,你可以用--abort参数来终止rebase的行动,并且"mywork" 分支会回到rebase开始前的状态。

$ git rebase --abort

五、标签管理

发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。

标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签。

创建标签

git checkout <branch>  # 切换到分支
git tag v1.0          # 打标签

创建带有说明的标签,用-a指定标签名,-m指定说明文字

git tag -a v0.1 -m "version 0.1 released" 1094adb

列出标签

git tag

查看标签信息

git show <tag name>

通过commit id 打标签

git tag v0.9 f52c633

删除标签

git tag -d v0.1

标签推送到远程

git push origin v1.0

批量推送标签

git push origin --tags

删除远程标签

git tag -d v0.9         # 先删除本地
git push origin :refs/tags/v0.9

六、补丁

git format-patch命令,可以找出两个commit之间的差异部分,然后将差异部分提取成一个补丁。

现有这样一个提交记录:

$ git log
commit 40c728c7951d8c4e4b0b5442c017b6fc81948f02 (HEAD -> master)
Author: watao <exta>
Date:   Wed Jun 30 12:46:37 2021 +0800

    del c

commit bdbdddcb5ff4dd98d00dcfc5979d9085873cbc34
Author: wangzao <exte>
Date:   Wed Jun 30 12:46:25 2021 +0800

    del b

commit 0b2f5b080c1f5f2c379c02f50206a7c8396ffe12
Author: wano <e.cn>
Date:   Wed Jun 30 12:46:14 2021 +0800

    del a

commit c3ffc3f5d93882dbcf288b2174cbf0b7dd25388f
Author: 
Date:   Wed Jun 30 11:08:23 2021 +0800

    a,b,c

1. 生成补丁

  1. 最近两次提交的补丁
$ git format-patch -1 # 生成一个补丁
0001-del-c.patch
  1. 两个commit之间的补丁
$ git format-patch c3ffc3f5d9..40c728c795 # 最初的提交和最后一个提交。'..'两边是commitID
0001-del-a.patch  # 前面的序号越小,代表这个补丁的commit越早
0002-del-b.patch
0003-del-c.patch
  1. 某个commitID之前的n次补丁
$ git format-patch -2 40c728c795
0001-del-b.patch
0002-del-c.patch

2. 打补丁

git apply可以打补丁,git am同样可以打补丁。

  1. 检查补丁能否成功打上
$ git apply --check 0002-del-c.patch
error: c: No such file or directory # 因为当前没有c这个文件,所以这个"del c"的补丁,肯定打不上去

所以我们可以先创建一个c文件,或者将版本撤销到没有删除c文件之前的状态

$ touch c
$ git apply 0002-del-c.patch # 执行完后,发现c文件被删除了,也就是补丁生效了
  1. 补丁冲突失败

当文件有更新,产生冲突时,打补丁会失败,可以通过 --reject参数,生成一个补丁的失败的对比文件,这时候可以根据这个差异文件,手动修改补丁冲突的部分

git apply 0001-edit-a.patch --reject # 失败的话,会生成一个 .rej 后缀的文件,记录了变动

$ cat a.rej
diff a/a b/a    (rejected hunks)
@@ -0,0 +1,6 @@
+./t1/t2/t3/t4/t5/t6
+./t1/t2/t3/t4/t5
+./t1/t2/t3/t4
+./t1/t2/t3
+./t1/t2
+./t1

Windows配置github

  1. 注册github

  2. 安装git到本机

  3. git命令窗口中配置用户名和邮箱:

    1. –global 参数,表示你这台机器上所有的Git仓库都会使用这个配置

    2. git config --global user.name “Your Name”
      git config --global user.email "email@example.com"
      
  4. 创建SSH key,直接三次回车

    1. ssh-keygen -t rsa -C "your_email@youremail.com"
      
  5. 进入.ssh文件夹,里面有两个key, 其中 id_rsa.pub 是公钥,打开它,复制里面的内容,在github的设置里面,找到 SSH and GPG keys,添加就ok了

    1. $ cd ~/.ssh
      $ ls
      id_rsa  id_rsa.pub  known_hosts
      
  6. 测试是否连上

    1. $ ssh -T git@github.com
      Warning: Permanently added the RSA host key for IP address '13.250.177.223' to the list of known hosts.
      Hi wztshine! You've successfully authenticated, but GitHub does not provide shell access.
      

others

重命名文件/文件夹

git mv name1 name2

自定义别名

给git命令起个别名,如 git status = git st ; git reset HEAD = git unstage

git config --global alias.st status
git config --global alias.unstage 'reset HEAD'

配置Git的时候,加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。

每个仓库的Git配置文件都放在.git/config文件中,别名就在[alias]后面,要删除别名,直接把对应的行删掉即可。而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig

[user]
	name = “wztshine
	email = xxxxxxxxx
[core]
	autocrlf = true
[difftool "sourcetree"]
	cmd = '' \"$LOCAL\" \"$REMOTE\"
[mergetool "sourcetree"]
	cmd = "'' "
	trustExitCode = true
[alias]
	co = checkout
	cm = commit

忽略特殊文件

有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status都会显示Untracked files ...,有强迫症的童鞋心里肯定不爽。

好在Git考虑到了大家的感受,这个问题解决起来也很简单,在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。

不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore

eg.

# git
.gitignore

# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini

# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build

# My configurations:
db.ini
deploy_key_rsa

常用过滤规则:

# 开头的是注释
/mtk/   过滤整个文件夹
!/mtk/one.txt    不过滤某文件夹下某文件
*.zip   过滤所有.zip文件
/mtk/do.c   过滤某个具体文件
!*.zip     不过滤zip

最后一步就是把.gitignore也提交到Git,就完成了!当然检验.gitignore的标准是git status命令是不是说working directory clean

使用Windows的童鞋注意了,如果你在资源管理器里新建一个.gitignore文件,它会非常弱智地提示你必须输入文件名,但是在文本编辑器里“保存”或者“另存为”就可以把文件保存为.gitignore了。

有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了:

$ git add App.class
The following paths are ignored by one of your .gitignore files:
App.class
Use -f if you really want to add them.

如果你确实想添加该文件,可以用-f强制添加到Git:

$ git add -f App.class

或者你发现,可能是.gitignore写得有问题,需要找出来到底哪个规则写错了,可以用git check-ignore命令检查:

$ git check-ignore -v App.class
.gitignore:3:*.class	App.class

Git会告诉我们,.gitignore的第3行规则忽略了该文件,于是我们就可以知道应该修订哪个规则。

git pull 和 git fetch 的区别

git fetch 后,本地库并没有变化,git fetch只会将本地库所关联的远程库的commit id更新至最新。
git pull 后,本地库更新至最新,git pull会将本地库更新至远程库的最新状态(最后一次commit id),而本地库所关联的远程库并没有变化。

提取两次commit的修改文件

压缩成一个包

git diff 9e483c619bb74391fb37c466bd0e364edf142685 f912640e943abeee2a3ce6b38aae9e7b2500861d --name-only | xargs tar -zcvf diff.tar.gz

解压

tar -zxvf diff.tar.gz

git commit --amend,补丁

假设这么一个场景:

你修改了一个bug,使用 git add, git commit -m "fixed one bug" 之后,发现之前 add 的时候,漏掉了一个文件 A.py,此时你可能下意识的有两种选择:

  1. 单独对 A.py 进行 git add A.py, git commit -m "add A.py" 的操作。但是这样做不好,因为会有两次commit记录
  2. reset上一次的commit记录,回退到之前的版本,然后对包括 A.py 在内的所有文件,再一次性 add,commit 一遍。缺点是费事,而且需要先把版本回退,再重新编辑修改,麻烦。

那有没有方法,可以直接重新commit一次,而又不出现两次commit记录呢?答案就是:git commit --amend

还是上面的例子,当你 commit 之后,发现漏掉了 A.py ,你可以

git add A.py	# 将A.py添加到暂存区,等待 commit 提交
git commit --amend --no-edit # 提交暂存区的更改,在不改变上次commit信息的前提下,将上次和这次的commit合并,--no-edit意思是不修改上次的commit的信息

举个例子:

  1. 创建一个文件A.py,并提交:
wztshine@DESKTOP-DCBC2US MINGW64 ~/Desktop/PUA (main)
$ touch A.py

wztshine@DESKTOP-DCBC2US MINGW64 ~/Desktop/PUA (main)
$ git add .

wztshine@DESKTOP-DCBC2US MINGW64 ~/Desktop/PUA (main)
$ git commit -m 'create A.py'
[main 2186bcc] create A.py
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 A.py

wztshine@DESKTOP-DCBC2US MINGW64 ~/Desktop/PUA (main)
$ git log -1
commit 2186bccc891b30f321facda9aa27baf67c033afc (HEAD -> main)
Author: “wztshine <2419434353@qq.com>
Date:   Wed May 19 22:33:13 2021 +0800

    create A.py

  1. 发现忘记编辑A.py了,编辑一下A.py,补充提交,你会发现,提交信息还是上次的 “create A.py” ,也就是只有一次commit记录:
wztshine@DESKTOP-DCBC2US MINGW64 ~/Desktop/PUA (main)
$ vi A.py

wztshine@DESKTOP-DCBC2US MINGW64 ~/Desktop/PUA (main)
$ git add .
warning: LF will be replaced by CRLF in A.py.
The file will have its original line endings in your working directory

wztshine@DESKTOP-DCBC2US MINGW64 ~/Desktop/PUA (main)
$ git commit --amend --no-edit
[main 7f1fe06] create A.py
 Date: Wed May 19 22:33:13 2021 +0800
 1 file changed, 1 insertion(+)
 create mode 100644 A.py

wztshine@DESKTOP-DCBC2US MINGW64 ~/Desktop/PUA (main)
$ git log -2
commit 7f1fe06ca533a84b0ce711fce029b3a1c2af6a65 (HEAD -> main)
Author: “wztshine <2419434353@qq.com>
Date:   Wed May 19 22:33:13 2021 +0800

    create A.py

commit 0807084a3a601b4f4c6aa439c639a067898c9319
Author: “wztshine <2419434353@qq.com>
Date:   Wed May 19 22:17:39 2021 +0800

    add test1

补充:不加 --no-edit,会弹出一个 vi 文本的编辑界面,第一行就是上次commit时写的备注,此时你可以修改第一行,来修改之前的备注,此界面操作模式和vi相同,编辑完成 :wq 退出即自动完成commit操作。

create A.py

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Wed May 19 22:33:13 2021 +0800
#
# On branch main
# Your branch is ahead of 'origin/main' by 2 commits.
#   (use "git push" to publish your local commits)
#
# Changes to be committed:
#       new file:   A.py

-m 参数:

git commit --amend -m "new message" # 使用-m,会自动使用后面的 message 来替换之前commit时的备注信息。

给开源软件贡献代码

github 上想要给别人的仓库提交代码,需要:

  1. fork 别人的仓库到自己的仓库
  2. 从自己的仓库拉取修改,然后 push 到远程仓库
  3. 在自己的仓库中,提交 pull reqeust 合并到对方的仓库中

设置 git

怎么设置关联 git 和 github 上的仓库?

我们只能操控自己的远程仓库,如果想要修改别人的仓库,需要在 githubfork 别人的仓库,到自己的账号下,然后拉下来,进行修改,再提交到自己 fork 的仓库里。

免密拉取和提交代码有如下两种方式:

方式一:SSH

  1. 打开 git 命令行窗口,输入如下命令,然后敲击三次回车键,可以生成 ssh:
ssh-keygen -t rsa -C "your_email@youremail.com"
  1. 进入.ssh 文件夹,里面有两个key, 其中 id_rsa.pub 是公钥,打开它,复制文件里面的内容,在 github 账号的 settings 里面,找到 SSH and GPG keys,添加就ok了
$ cd ~/.ssh
$ ls
id_rsa  id_rsa.pub  known_hosts
  1. 然后,当你想要拉取一个仓库的代码时,必须复制使用它的 SSH 链接地址,如:git@github.com:wztshine/learngit.git

方式二:https + token

设置了 ssh ,可以免密拉取和提交代码到远程仓库,如果使用仓库的 https 链接地址,则必须每次提交都需要输入用户名和密码,而 github 又不再支持密码登陆模式了,所以需要设置 token

点击你的 github 账户,选择 Settings -> Developer settings -> Personal access tokens -> Generate new token , 然后输入 token 名字,设置它的过期时间,以及选择这个 token 的权限,就可以生成一个 token 了,然后复制这个 token。拉取 https 地址时这样写:

git clone https://TOKEN@github.com/wztshine/learngit.git

https:// 后面加上你自己刚生成的token字符串, 并紧跟一个 @ 符号。这样你以后 push 或者 pull 的时候,github 就会根据你的 token 以及这个 token 的权限,来决定是否有权利去提交代码。

posted @ 2020-06-16 20:28  wztshine  阅读(265)  评论(0编辑  收藏  举报