Git

入门

  • .git 的隐藏目录是你的本地仓库(Local Repository)
  • git log 查看历史
  • git log -p查看详细历史
  • git log --stat 查看简要统计
  • git show e66666/branch查看指定commit,加文件名看指定文件
  • git diff --staged/--cached查看当前工作目录与暂存区的不同,可以看到即将添加到暂存区的改动内容,git diff HEAD看到当前工作目录与上一个commit的不同
    • commit 的 SHA-1 校验和
      commit 8cf88cf35ce40cb91488e7d9b12cf46463fedc2f
  • git status
    • untracked files (未追踪的文件)
  • 使用 git add git.txt 来开始追踪文件
    • 从 “Untracked files” 变成了 “Changes to be commited”,该文件变成已暂存staged,被记录到 staging area(暂存区)
    • git commit -m "add git.txt"提交代码到本地仓库
  • 缓存GitHub密码,在设置了SSH key后,git config --global credential.helper wincred
  • git push到远端仓库
  • git pull将远端仓库代码同步到本地仓库
  • push冲突,由于 GitHub 的远端仓库上含有本地仓库没有的内容,所以这次 push 被拒绝,解决办法:先用 pull 把远端仓库上的新内容取回到本地和本地合并,合并后的代码会自动提交,然后再把合并后的本地仓库向远端仓库推送

HEAD、master、branch

  • commit 后面括号里的 HEAD -> master, origin/master, origin/HEAD ,是指向这个 commit 的引用,也可以使用SHA-1指代commit
HEAD 当前 commit 的引用
  • 当前工作目录对应的commit,checkout/reset会改变当前commit
branch
  • HEAD 除了可以指向 commit,还可以指向一个 branch,HEAD指向分支master,间接指向对应的commit,当git commit有新的提交时,HEAD会和master一起指向新的commit
  • master 默认的主分支,和其他分支平等,分支可以理解为初始commit到当前分支指向的commit的路径
  • branch 的创建、切换和删除
    • 创建 branch git branch feature1
    • 切换分支git checkout feature1 HEAD 就会指向新建的 branch,执行git checkout -b feature1是上述两个合并执行
    • 删除分支git branch -d feature1,HEAD 指向的 branch 不能删除。如果要删除 HEAD 指向的 branch,需要先用 checkout 把 HEAD 指向其他分支,没有被合并到 master 过的 branch 在删除时会失败,确认删除使用git branch -D feature1

push

  • git push当前master分支,把该分支上的未上传的commit,以及当前master所指向的commit引用一并上传到远端
  • 切换到feature1,执行push,origin feature1参数代表目标仓库和目标分支

    1
    2
    git checkout feature1
    git push origin feature1
  • git config push.default current 推送到与当前分支相同的远端分支,参考git config

  • HEAD指向默认分支master,在git push时,只会上传当前分支的指向,例如push后,本地feature1指向第5个commit,push后远端feature1分支指向第5个commit,而HEAD指向不会切换到feature1的指向,默认指向master分支的commit

    merge

    pull执行了fetch拉取到本地, merge合并远端commit和本地commit
  • git merge branch1 把branch1分支合并到master分支,生成一个新的commit
  • 两个分支修改相同内容,造成合并冲突,可以删除冲突的内容重新合并

    1
    2
    git add git.txt
    git commit
  • 也可以取消合并git merge --abort,回到之前的commit状态

  • 当HEAD领先于branch的commit,在同一路径上,merge 是空操作,不需要创建新的commit
  • 当HEAD落后于目标branch的commit,在同一路径上,merge会直接将HEAD指向目标commit,这个操作即是 fast-forward 快速前移,在本地仓库中commit落后于远端代码,造成本地HEAD落后与目标commit,git pull就会造成fast-forward
  • origin/masterorigin/HEAD 是对远端仓库的 master 和 HEAD 的本地镜像,在 git pull 中的第一步git fetch 下载远端仓库内容时,这两个镜像引用得到了更新,origin/masterorigin/HEAD 移动到了最新的 commit

    Feature Branching

  • 任何新的功能(feature)或 bug 修复全都新建一个 branch
  • branch 写完后,合并到 master,然后删掉这个 branch
  • 开发一个新的功能,创建新的分支

    1
    git checkout -b feature1
  • 功能基本完成后,push到远端分支feature1

    1
    git push origin feature1
  • review 复审代码,通过后合并分支到master

    1
    2
    3
    4
    5
    6
    git pull
    git chekcout feature1
    ···
    git checkout master
    git pull # merge 之前 pull 一下,让 master 更新到和远程仓库同步
    git merge feature1
  • 合并后的结果push到远端仓库,并删除本地和远端分支feature1

    1
    2
    3
    git push
    git branch -d feature1
    git push origin -d feature1
  • 也可以使用pull request,查看commit,然后合并分支

    rebase 变基

  • 重新设置基础点,切换到branch1变基,防止远端仓库的commit被剔除

    1
    2
    git checkout branch1
    git rebase master
  • 回到master,将master移动到最新commit

    提交代码错误

  • 对最新一条 commit 进行修正git commit --amend,替换原来的commit,生成新的一个commit

    交互式 rebase

  • rebase -i:交互式 rebase,是rebase --interactive缩写,指定某个commit进行修改

    1
    git rebase -i HEAD^^
  • 偏移符合^ 一个或多个这个符号往回偏移对应个数的commit

  • 偏移符号~n 向前偏移n个commit
  • 编辑界面,选择commit和对应的操作,将需要编辑的commit的pick改为edit,然后修改需要修改的内容

    1
    2
    edit beeee 修改...
    pick edddd 修改...
  • commit --amend 来把修正应用到当前的 commit

    1
    2
    git add git.txt
    git commit --amend
  • 继续rebase,把后面的commit直接应用上去

    1
    git rebase --continue

丢弃重新提交

  • git reset --hard HEAD^撤销提交的commit,重新回到上一个commit

  • 之前的提交需要丢弃

    1
    2
    git rebase -i HEAD^^ 回到上个commit
    drop 删掉这个commit
  • git rebase 第3个commit 会自动选择分岔点,并将4,5commit提交到3所在的路径

  • rebase --onto额外指定起点,只想把 5 提交到 3 上,不想附带上 4
    1
    git rebase --onto 第3个commit 第4个commit branch1
  • rebase --onto来撤销提交,起点不包含在rebase序列,下面的例子是丢弃HEAD^,branch1的commit
    1
    git rebase --onto HEAD^^ HEAD^ branch1

push到远端仓库的commit错误

  • 出错的commit已经push到远端分支,需要修改或删除掉,重新修改后,push commit时会报错,因为远端包含本地没有的commit,所以需要忽略冲突,强制push

    1
    git push origin branch1 -f
  • 出错的commite已经合并到master,不能修改后强制push,应该直接revert撤销commit,然后再push revert后的代码

    1
    git revert HEAD^

reset

  • 撤销最新提交的commit,其实是重置HEAD,branch的commit位置到父commit

    1
    git reset --hard HEAD^
  • 可以把HEAD,branch移动其他commit

    1
    git reset --hard branch2
  • reset --hard:重置工作目录,工作目录的修改也被撤销,无论是否已add到暂存区

  • reset --soft:保留工作目录改动,并将文件的改动放到暂存区
  • reset 不加参数:工作目录的修改、暂存区的内容以及由 reset 所导致的新的文件差异,都会被放进工作目录
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    修改了 git.txt 和 readme.md,
    并把 git.txt 放进了暂存区
    当前push的commit中新增了文件app.txt
    此时执行
    git reset HEAD^
    工作目录的内容都会保存,暂存区被清空

    git status
    changes not staged:
    modified git.txt
    modified readme.md

    untracked files:
    app.txt

checkout

  • 切换分支git checkout branch1,也可以切换到指定的commit

    1
    2
    3
    4
    5
    6
    git checkout HEAD^^
    git checkout master~3
    git checkout 32d434
    git checkout 32d434^

    checkout -- 文件名 的格式来撤销指定文件的修改
  • reset HEAD和branch一起移动,而checkout不会,HEAD会指向新的commit

    1
    2
    HEAD 和 branch 脱离而不移动 HEAD,HEAD直接指向commit
    git checkout --detach

stash

  • 将当前改动内容保存到本地其他地方,不会被删除或提交,这样就可以把工作目录的改动清空,所有的改动被保存,之后需要还原的statsh之前的内容,执行
    1
    2
    3
    4
    git stash pop

    Git会忽略未被追踪的文件,如果也要stash保存untracked文件,即没有add到缓存区的文件
    git stash -u

reflog(reference log)

  • 误删了branch1,可以查看HEAD的移动历史,找到删除之前的commit,切换回删除之前的commit,重新创建同名分支,注意reflog要及时,因为不再引用或间接指向的commit会被Git回收
    查看其他引用的reflog,git reflog master
    1
    2
    3
    git reflog
    git checkout ccdde32
    git checkout -b branch1

gitignore

忽略不需要被管理的文件

其他

  • tag是一个和 branch 非常相似的概念,它和 branch 最大的区别是:tag 不能移动,tag 被用来在关键版本处打标记用
  • cherry-pick 是一种特殊的合并操作,使用它可以点选一批 commits,按序合并
  • git-docs
  • Pro git
willkernel wechat
关注微信公众号
帅哥美女们,请赐予我力量吧!