1. 安装git

  • centos7自带git1.8

查看安装过的包:yum list installed,有点慢耐心等待。

1.1 删除自带:sudo yum remove git

1.2 安装前环境配置:

1
sudo yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel asciidoc xmlto perl-devel perl-CPAN autoconf*

还需要gcc

1.3 下载git2.2.1并将git添加到环境变量中

1
2
3
4
5
6
7
8
9
10
wget https://github.com/git/git/archive/v2.2.1.tar.gz
tar -zxvf v2.2.1.tar.gz
cd git-2.2.1
make configure
./configure --prefix=/usr/local/git --with-iconv=/usr/local/libiconv
make all doc
make install install-doc install-html
# 以root用户执行“”内整条语句,因为`>`需要再次授权
sudo sh -c "echo 'export PATH=\$PATH:/usr/local/git/bin' >  /etc/profile.d/git.sh"
source /etc/profile.d/git.sh

概念

暂存区/索引(stage/index)

  • 暂存区是所有分支共享的,checkout到另外的分支,暂存区的内容不变

git rm : 同时从工作区和暂存区中删除文件。即本地的文件也被删除了。

git rm --cached : 从暂存区中删除文件,并且将文件移出版本控制,但是本地文件还存在。

使用git reset也可操作暂存区

git restore --staged <file>...:可以将文件移出暂存区

配置

代码托管网站,主要看email,用email地址来匹配自己的账户名的邮件地址,如果相同,代码托管网站就认为此操作是账户所有者的操作。

1
2
3
git config --get user.name # 查看本地user.name属性,若没有配置则不显示,此时push时使用global属性(?)
git config user.name abc # 设置本地属性,config文件放在.git目录下,该文件有多个段,user.name在user段中
git config --global user.name abc # 设置全局属性,该属性放在。。不清楚

换行符的配置:core.autocrlf

  • true: 提交时转换为 LF,检出时转换为 CRLF
  • false: 提交检出均不转换
  • input: 提交时转换为LF,检出时不转换

忽略大小写配置:core.ignorecase

  • true: 分支名称比较时会忽略大小写
  • false: 分支名称比较时会考虑大小写

代理配置

1
git config --global http.proxy http://127.0.0.1:7890

gitignore

查看文件是否被排除,若被排除会显示出被排除的文件pathname是该文件路径

1
git check-ignore [<options>] <pathname>…

刚开始新建一个项目可能会把.idea/workspace.xml等这种系统文件或编译中间过程的文件都用git add添加到了git版本库中来管理,这样即使后来添加了.gitignore文件也不能忽略掉已经添加到版本库中的文件,这时需要用 git rm [--cache] xxx文件从版本管理库中删除,不再跟踪此文件。加了--cache代表不会删除工作空间中的文件

命令

远程的commit/branch在本地了对应一个只读的远程名/(commit|branch)

  • git add file:同一个文件,第2次会覆盖第1次
  • git diff [--options] [--] [<path>...]:工作空间与暂存区的文件内容区别
  • git log:记录当前的commit及其之前的commit
  • git reflog:记录HEAD的移动记录
  • 在commit时添加-a参数, Git就会自动把所有已经跟踪过
    的文件暂存起来一并提交,从而跳过git add步骤
  • git log --graph --pretty=oneline --abbrev-commit

commit

  • git commit --amend,创建一个当前节点C1的兄弟节点的C2C2C1的的基础上,添加了本次的修改内容。

branch

  • git branch -vv:查看本地分支关联的远程分支
  • git branch --set-upstream-to=origin/master master:设置upstream
  • git branch -f <branch> <destcommit>:将<branch>分支指针指向到<destcommit>
  • git branch <branch> <destcommit>:在destcommit上创建一个branch
  • git branch -u <remote>/<branch> [<branch>]:本地的branch tracking 远程的branch。本地branch不指定默认为当前分支
  • git branch -d <branch>:删除本地分支
  • git push origin -d <branch>:删除远程的分支

checkout

  • git checkout <commit>(~\d|^(\d|))*~2代表commit往上跳两次;^2代表commit往上跳一个,但是上面可能有很多个选择,选第二个。未给出数字代表1

  • git checkout -b [分支名] [远程名]/[分支名]:建立一個新的 branch 並且它會 track remote branch,并checkout到这个branch。

  • git checkout -b [分支名] <commit>:在commit所在位置建立一個新的 branch,并checkout到这个branch。

  • git checkout -- filename:丢弃修改,让这个文件回到最近一次git commit或git add时的状态。

stash

  • git stash list:列出当前所有的stash
  • git stash save [-p] [<message>]:把当前未提交的代码保存为一个stash,并且还原文件到未修改状态。-p 代表进入一个交互式界面,可以决定如何处理每个未提交的文件。message可以给stash添加一个描述信息。
  • git stash (pop|apply) [<stash-name>]:pop会将stash删除并且应用,apply只是应用。stash-name不指定默认代表第一个stash

revert

  • git revert <commit>:将某个commit取消,原理是提交一个修改,改修改的内容是指示此commit被取消

reset

  • git reset -- files:撤消暂存区中的文件

git reset [<option>] <commit>,option默认mixed

  • --soft,仅仅重置当前分支到指定的commit,index和working tree不改变

Does not touch the index file or the working tree at all (but resets the head to , just like all modes do). This leaves all your changed files “Changes to be committed”, as git status would put it.

  • --mixed,重当前分支到指定的commit,还清空(?)了index

Resets the index but not the working tree (i.e., the changed files are preserved but not marked for commit) and reports what has not been updated. This is the default action.

If -N is specified, removed paths are marked as intent-to-add (see git-add(1)).

  • --hard,重置当前分支到指定的commit,还清空(?)了index,并且将working tree的文件都修改为这个commit的状态。

Resets the index and working tree. Any changes to tracked files in the working tree since are discarded.

merge

  • git merge <commit>

rebase

  • git rebase <commit1>:将(当前节点与commit1往上的汇合公共节点(若在同一条路径则没有效果),当前节点]之间所有commit依次复制到commit1下
  • git rebase -i <commit1>:将(当前节点与commit1往上的汇合公共节点(若在同一条路径仍然有效果),当前节点]范围内的commit重排序并选择需要的commit按顺序复制到该commit1下的一个新分支(并不会真的创建一个branch),并将HEAD/当前分支 移动到该分支末尾。
  • ==git rebase 其它参数 <branch>: 先checkout到branch,然后再rebase 其它参数merge而不可以这样==

cherry-pick

  • git cherry-pick <commit>...:将这些commit依次复制到HEAD节点下面

clone

在做 clone 的時候,git 會針對每一個在 remote 上面的 branch 建立一個 branch (例如 o/master),之後它會建立一個 local branch 來追蹤目前在 remote 上面的 active branch,在大部份的情況下,幾乎都是設定 master branch。

一旦 git 完成這個動作,你就只會有一個 local branch ,但是你可以看到所有在 remote 上面的不同的 branch,對於 local 和 remote 來說的話,這樣子是最好的

remote tracking

决定了push的目的地以及pull后合并的目标。

另外一個設定 remote tracking(track的是本地的remote分支) 的方法是使用 git branch -u 這一個指令,執行

1
git branch -u <remote>/<branch> <localBranch>(foo必须存在)

如果你現在已經 checkout 到 localBranch 上面了,你就可以省略掉它:

1
git branch -u <remote>/<branch>

git push

git push origin 表示,将当前分支推送到origin主机的对应分支,如果当前分支只有一个追踪分支,那么主机名都可以省略。

git push -u origin master 上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。

  • git push:推送HEAD所在branch的commit到remote branch,同時对应的本地远程分支 <remote>/<branch> 也一併更新!HEAD必须在branch节点
  • git push <remote> <source>:<destination>:先到我的 repo 中的 sourcecommit(可用~和^),抓下所有的 commit,然後到本地<remote>/<destination>分支所对应的远端分支,檢查 它 的 commit 有沒有跟我的 repo 一致,如果沒有,就更新远端分支,并且更新本地remote分支。若没有destination将会创建
  • git push <remote> <place>:等价于git push <remote> <place>:<place>
  • git push <remote> :<branch>:删除remote的branch分支,同时删除本地对应的remote分支

git fetch

  • git fetch:更新本地仓库的remote分支,即下载远程分支中新的commit和分支信息,会移动所有本地remote branch,保持本地remote分支和远程仓库的同步。非remote分支不会变化。
  • git fetch <remote> <source>:<destination>:将远端source分支(也可以是commit)更新到本地的destination(没有会创建,但是创建出来的是还未关联远端的),本地destination当前所有的commit必须与远端的前面部分相同。不会更新本地的remote分支。
  • git fetch <remote> <place>:等价于git fetch <remote> <place>:<remote>/<place>,只更新本地的某个remote分支
  • git fetch <remote> :<dest>:在当前节点建立一个叫dest的新本地分支和远端无关联,很没用的命令。

git pull

  • git pull:git pull 其實就是 git fetch 跟 git merge 的循序執行的結果(但是只会更新当前所在分支),而且 merge 的 branch 就是 fetch 所更新的 branch。它也能加fetch的参数。
  • git pull --rebase:把merge换成rebase
  • 例子:git pull origin foo=>git fetch origin foo; git merge fetch的dest=>git fetch origin foo:origin/foo; git merge origin/foo顺序执行(注意merge b是把b merge到当前所在的branch)。

stash

git stash:将工作空间中被track的文件中未add的修改压入栈,操作完成后使用status会显示nothing to commit, working tree clean。这时就可以checkout到其它branch做其它操作,完成之后可以再checkout回来使用git stash pop从栈中弹出栈顶元素,并且恢复工作空间。在A分支stash后在B分支pop stash也是可以的。

tag

  • git tag <tagName> <commit>:创建一个与commit关联的tag,若commit未指定则代表HEAD。

  • git describe <ref>:显示离ref最近的tagref可以是任何可以被解释为commit的位置(tag,commit,branch),ref未给出代表HEAD。指令输出<tag>_<numCommits>_g<hash>numCommits代表tagref有几个commit(起点到终点的跳数),hash表示ref所代表的commit的前7位hash。当ref本身含有标签时,则只输出标签。

解决方案

修改之前提交的某个commit(C1

https://git.mo.mk 4-24-2

使用rebase

  • rebase -i C1^,把C1重排序到最前面
  • 此时基于C1修改之后再commit -amend添加修改到新C1'
  • 然后再rebase -i C1^,把C1'放到最后

或使用cherry-pick

  • checkout C1
  • 此时基于C1修改之后再commit -amend添加修改到新C1'
  • 然后再cherry-pick C1之后所有的commit

合并commit

当前分支后退3个节点,将最新3个提交放到stage,然后提交。当前分支会生成一个新的提交包括了所有的修改。
建议先在本地打一个tag标识再做这个操作,否则操作完可能找不到原先的一个一个的提交记录了。

1
2
3
4
5
6
git reset --soft HEAD~3
-- 下面这个命令可以拼接所有的提交message作为合并后的提交的message.
-- %B表示只显示每个提交的消息内容
-- 在Git中,HEAD@{1}是一个引用,它指向HEAD在一次移动之前所在的位置。这是Git的"引用日志"(reflog)的一部分,它记录了HEAD和其他引用的历史移动。
-- git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"
git commit

删除未跟踪的文件

  • -d:删除未跟踪的目录。
  • -f:强制执行删除操作,即使它会导致数据丢失。
1
git clean -df <dir>

其它操作

  • 修改之前已经提交的记录:https://blog.csdn.net/sodaslay/article/details/72948722
    ,但是commit仍然没被删掉,在本地git仓库中仍然可以checkout到那个commit。但是force push后远程中的commit记录应该就没有了,那么其它人clone下来的也将没有。