我知道的Git操作指北(一):从远端更新本地

特别说明

尽管我们要求使用命令行的形式进行git的操作,但在一些实际的使用或问题场景中,适当的结合Git图形化界面操作工具将更有帮助。

fetch(获取)和pull(拉取)的区别

在讲解本节内容前,你需要了解一个概念FETCH_HEAD

FETCH_HEAD简单来说就是一个存储指向从远端获取到的分支最新的commitid的集合的引用

听这个解释可能比较抽象,其实FETCH_HEAD本质上算是一个文件,它存储在本地仓库.git/FETCH_HEAD

# 进入.git
cd .git

# 列举当前目录下文件
ls -l
total 6496
-rw-r--r--    1 gavin  staff     1857 Mar 26 14:27 COMMIT_EDITMSG
-rw-r--r--    1 gavin  staff     2422 Mar 26 22:02 FETCH_HEAD
-rw-r--r--    1 gavin  staff       34 Mar 26 21:31 HEAD
-rw-r--r--    1 gavin  staff       41 Mar 26 18:53 ORIG_HEAD
-rw-r--r--    1 gavin  staff       41 Mar 26 14:27 REBASE_HEAD
-rw-r--r--    1 gavin  staff      795 Mar 26 21:28 config
-rw-r--r--    1 gavin  staff       73 Feb 23  2021 description
drwxr-xr-x   14 gavin  staff      448 Feb 23  2021 hooks
-rw-r--r--    1 gavin  staff  2940194 Mar 26 21:31 index
drwxr-xr-x    4 gavin  staff      128 Mar 17 13:58 info
drwxr-xr-x    4 gavin  staff      128 Mar 17 13:58 logs
drwxr-xr-x  256 gavin  staff     8192 Mar 26 22:02 objects
-rw-r--r--    1 gavin  staff    14698 Mar 26 21:28 packed-refs
drwxr-xr-x    7 gavin  staff      224 Mar 26 21:08 refs
-rw-r--r--@   1 gavin  staff      309 Jan  6 01:47 sourcetreeconfig

# 使用编辑打开FETCH_HEAD
vim FETCH_HEAD
7d0ee867e02385ab89197f1c803a4b910085fdc2                branch 'dev' of url
2435dd179cf7edd0d7df66878094b1d930686fa1        not-for-merge   branch 'build/nginx-shanghai' of url
d35230737eee391ef001f5210fb51ec2c1846125        not-for-merge   branch 'dev/shanghai' of url
efe637e00924ac99285c2bd59833101ec71b3194        not-for-merge   branch 'feature/shanghai-watermark' of url
c89ed4f0d14973e19a20b3db46ea82c3a25200f1        not-for-merge   branch 'master' of url

# 可以看到此处第一列是各个远端分支最新的commitid
# 之所以这里会有这么多行的原因是,仅执行了git fetch
复制代码

了解以上的FETCH_HEAD之后,我们开始具体讲讲获取(git fetch)和拉取(git pull)的区别

  • 获取(git fetch)更新

    假如在获取操作前是这样的,本地master上只有A<-B两次提交,在执行获取操作后,获取到了远端的两次更新C、D就变成了这样

fetch.png

仅仅是将remote的更新同步至repository,不涉及到workspace

git-4.png

因此当你正在编辑代码的时候,也可以进行获取操作,将不会有任何影响。

食用使用方法:

  1. 默认将remote的更新,全部取回本地:

    # 默认将remote的更新,全部取回本地
    git fetch
    git fetch origin
    复制代码
  2. 获取指定的remote分支更新

    # 获取remote的dev分支更新
    git fetch origin dev/test
    * branch              dev  -> FETCH_HEAD
    # 此时指针FETCH_HEAD中仅包含会指向dev的最新commit-id
    复制代码
  3. 获取指定的remote分支到本地指定分支

    # 获取remote的dev分支更新到本地dev分支
    * [new branch]        dev  -> dev
    # 此时指针FETCH_HEAD中仅包含会指向dev的最新commit-id,并且在本地创建新分支dev
    复制代码
  • 拉取(git pull)更新

    其实拉取操作在前几步与获取是相同的,但是拉取操作会将本地分支合并FETCH_HEAD,多了一个合并的过程。

    从结果看pull = fetch + merge(/rebase)

    拉取下来的更新,最后会被同步到workspace。因此,当你正在编辑代码即workspace“不干净”时,将可能会发生代码冲突或报错。

pull.png

git-3.png

如何安全的拉取更新

在上一个问题中我们了解了拉取(git pull)操作最后会将更新同步至workspace,因此清理workspace的变更内容保证其”干净“的状态就是关键。

在这里通常会有两种做法来“清理”workspace:

方法一:通过贮藏(stash)

贮藏(stash)会处理工作目录的脏的状态——即跟踪文件的修改与暂存的改动——然后将未完成的修改保存到一个栈上, 而你可以在任何时候重新应用这些改动(甚至在不同的分支上)。

贮藏(git stash)会将当前workspace中所有被git跟踪监听(tracked)的文件保存至栈结构上。

  1. 使用贮藏前先查看当前workspace状态

    # 查看工作区状态
    git status 
    # 一般可能会有以下输出
    On branch dev
    Your branch is up to date with 'origin/dev'.
    
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
    	# 此处列出的是从工作区添加至暂存区的内容,可以被提交。
    
    Changes not staged for commit:
      (use "git add/rm <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
    	# 此处列出的是工作区中已经被tracked的内容,可以通过add添加至index。
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
      # 此处列出的是未被git跟踪监听的文件,一般为新增的文件。需要使用add将其添加至index
      
    复制代码
  2. 使用add将变更添加至index

    # 快速添加所有的变化到index
    git add . 
    # 查看工作区状态
    git status
    
    On branch dev
    Your branch is up to date with 'origin/dev'.
    
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
    	# 此处列出的是从工作区添加至暂存区的内容,可以被提交。
    
    复制代码
  3. 使用stash贮藏

    # 使用贮藏
    git stash 
    Saved working directory and index state WIP on dev: 7d0ee867 test(测试): 贮藏测试
    # 或者在贮藏的时候添加一段备注信息以便于记忆
    git stash push -m '这是一段备注信息'
    Saved working directory and index state On dev: 这是一段备注信息
    
    # 再次查看工作区状态
    git status
    On branch dev
    Your branch is up to date with 'origin/dev'.
    
    nothing to commit, working tree clean
    
    # 此时会提示你workspace干净
    复制代码

    特别注意:

    默认情况下,git stash会缓存下列文件:

    ​ 1.添加到index的修改(staged changes)

    ​ 2.Git跟踪的但并未添加到index的修改(unstaged changes)

    但不会缓存一下文件:

    ​ 1.在workspace中新的文件(untracked files)

    ​ 2.被忽略的文件(ignored files)

    git stash命令提供了参数用于缓存上面两种类型的文件:

    使用-u或者--include-untracked可以stash untracked文件。

    使用-a或者--all命令可以stash当前workspace的所有修改。

  4. 拉取更新(git pull)

    # 执行通常的拉取更新
    git pull
    复制代码
  5. 恢复之前的贮藏

    # 查看当前贮藏栈
    git stash list 
    stash@{0}: On thales-device: 这是一段备注信息
    stash@{1}: WIP on 12.7.4: 2de5796e docs(文档): 更新项目文档
    # 其中类似 stash@{0} 的叫做贮藏单元索引
    
    
    # 应用贮藏
    # 1.快速应用最新的贮藏(栈顶)
    git stash pop
    
    On branch dev
    Your branch is up to date with 'origin/dev'.
    
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
    	# ...
    
    Changes not staged for commit:
      (use "git add/rm <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
    	# ...
    
    Dropped refs/stash@{0} (e571ba7595ea6fda3ea8c17332e1a21b160008ee)
    # 这个命令会直接应用贮藏栈顶单元的内容,并在执行成功后删除该贮藏单元
    # 如果执行结果发生了错误(一般出现在工作区有变更且变更内容与贮藏单元中的发生冲突),会保留该贮藏单元。
    
    # 或者使用下面的方式
    
    # 应用贮藏
    # 2.应用指定的贮藏(通过指定贮藏单元索引)
    git stash apply stash@{0}
    
    On branch dev
    Your branch is up to date with 'origin/dev'.
    
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
    	# ...
    
    Changes not staged for commit:
      (use "git add/rm <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
    	# ...
      
    # 此时不会删除stash@{0}的贮藏单元,需要手动删除
    git stash drop stash@{0}
    
    Dropped stash@{0} (60ef88308ac81900249091f0e6ed394d36db3574)
    
    复制代码

    综上即通过贮藏的方式完成了拉取更新操作。

方法二:通过提交(commit)

我们也可以通过提交的方式,清理workspace。操作过程这里不再赘述。

特别说明:

根据提交规范,一般情况下通过提交(commit)方式清理工作区拉取更新,在开发的下游分支上可以使用,

在上游分支上禁止使用,或者在特殊情况下在非下游开发分支上使用此方法,需要在推送前压缩提交(squash commit)。

方法三:通过手动备份工作区的变更文件(手艺人专用)

大佬必备,我不会。略。

总结

欢迎大佬批评。

猜你喜欢

转载自juejin.im/post/7079434737206444062