根据Git,谁是"我们"谁是"他们"?

dan*_*nza 146 git

在Git rebase之后,在其他情况下,您可以在报告中找到我们标记为已删除的一些文件git status.根据Git,我们是谁?为什么?

它指的是我坐在这个分支上它是否适合我?或者它是指自己和在分支机构工作的人我反对?

SzG*_*SzG 160

当你合并,us是指你融入,而不是分支them,分支合并.

当你变基,us是指上游分支,them是你动一下分支.如果出现变异,这有点违反直觉.

原因是Git使用相同的合并引擎进行rebase,它实际上是将你的东西挑选到上游分支.us= into,them= from.

  • 从*implementation*的角度来看,这是有道理的,因为rebase使用合并机制,其中"我们的"分支是上游分支,而"他们的"分支是被重新分支的分支.但我同意这一点,好吧,"非常无益"似乎是一种礼貌的方式.我更倾向于用"us/ours"和"他/他们"之类的其他单词来标记分支,例如可能通过分支名称:"在master中删除,在功能中修改". (49认同)
  • 将"我们"想象为"[u] p [s] tream"的助记符而不是正常的英语单词"us"可能会有所帮助. (8认同)
  • 在反叛期间做结帐时,我总是倾向于将`--theirs`与`--ours`混淆,这是违反直觉的.我希望他们有一天能解决这个问题. (2认同)

Gab*_*les 38

(这也回答了这个问题:“git rebase 是如何工作的,它到底发生了什么?”)

在所有情况下:

  1. “我们”(或“我们”)=当前被查出来的commit( HEAD目前混帐做的动作导致冲突(以后会更多),以及:
  2. "them" (or "theirs" ) = 另一个提交,在 git 执行导致冲突的操作时没有被 git 检出(稍后会详细介绍)。

重要提示:HEAD此时它执行导致冲突的操作不一定是HEAD您键入 git 命令时的操作。这对理解至关重要。HEAD在运行导致冲突的操作之前,Git 可能会进行一些检出并更改(哪个提交被检出),从而导致“我们”和“他们”在未经训练的眼睛中出现交换或倒退。

4 种情况,详细说明:merge、cherry-pick、rebase、revert:

  1. git merge (直觉的):
    1. 示例命令:
      git checkout master
      git merge feature_branch  # merge feature_branch into master
      
      Run Code Online (Sandbox Code Playgroud)
    2. "us"/"ours" = HEAD也就是说master,因为master你跑的时候在分支上git merge feature_branch
    3. "them"/"theirs" = feature_branch,这是您要合并到的分支master
  2. git cherry-pick (直觉的):
    1. 示例命令:
      git checkout feature_branch
      git cherry-pick some_commit  # apply some_commit to feature_branch
      
      Run Code Online (Sandbox Code Playgroud)
    2. "us"/"ours" = HEAD也就是说feature_branch,因为feature_branch你跑的时候在分支上git cherry-pick some_commit
    3. "them"/"theirs" = some_commit,这是您正在挑选的提交feature_branch
  3. git rebase (违反直觉,但一旦您了解其工作原理就完全有道理):
    1. 示例命令:
      git checkout feature_branch
      git rebase master  # rebase feature_branch onto latest master
      
      Run Code Online (Sandbox Code Playgroud)
    2. 此图(绘制于https://asciiflow.com),最新最新的提交在顶部和/或右侧:
      #             Prior to rebase: feature_branch
      #             received new commits while
      #             master did too
      # 
      #                           master
      #                           x
      #                           |          feature_branch
      #                           x          y
      #                           |          |
      #                           x          y
      #                           |         /
      # git merge-base      ????? x--y--y--y
      # master feature_branch     |
      #                           x
      # 
      # 
      #             After rebase: feature_branch has
      #             been completely cherry-picked onto
      #             the end of master
      # 
      #                                   feature_branch
      #                                   y'
      #                                   |
      #                                   y'
      #                                  /
      #                         y'--y'--y'
      #                         |
      #                  master x
      #                         |
      #                         x
      #                         |
      #                         x
      #                         |
      #                         x
      #                         |
      #                         x
      
      Run Code Online (Sandbox Code Playgroud)
    3. "us"/"ours" = HEAD,这是上游分支:最初是最后一次x提交master,然后是一些新的提交y'cherry-picked在此之上(这个很棘手!)。这是因为当您键入 时git rebase mastergit 首先检出master作为开始挑选您的feature_branch提交到的起点,然后它确定从哪个提交feature_branch到挑选(即:您的哪些feature_branch提交尚未在 上master)。它通过找到merge-base(对feature_branchmaster和都可以找到的提交)来做到这一点git merge-base master feature_branch,然后它开始从第一个提交之后开始挑选提交merge-base然后,一次一个地工作,朝着 上的最后一次提交feature_branch,到 的尖端master,从而y将您添加feature_branch到最新的所有“新”提交“变基” master,作为新y'提交。因此,"us"/"ours" = HEAD,但由于 git 在幕后做了一个新的 checkout 来执行这个 rebase,HEAD这不是你输入时所在的分支git rebase master。相反,usHEAD要么是在第一次发生冲突时的最后一次x提交,要么是最后一次成功挑选的新提交,如果冲突发生在任何后来的挑选中。他们mastercherry-picky'master因此是另一个提交,y提交从feature_branch正在被应用到这个新HEAD通过摘樱桃,按顺序从第一个y承诺上feature_branch,并立即开始后, git merge-base master feature_branch所有到最后的方式y提交的feature_branch另见“他们”的解释,就在下面。
    4. "them"/"theirs" = 一些y提交,feature_branch从中被应用到新签出HEAD,其中HEAD要么是变基期间第一次挑选操作的最后一次x提交,要么master是这些新创建的y'提交之一顶部的masterasfeature_branch是“rebase”,或者是一次精心挑选的一次提交(沿着从git merge-base master feature_branch到最后一次提交的一系列新提交feature_branch)到master. 另请参阅上面对“我们”的解释。
  4. git revert (有点直观):
    1. 示例命令:
      git checkout feature_branch
      # create a new commit to undo the changes from some_previous_commit
      # within feature_branch
      git revert some_previous_commit  
      
      Run Code Online (Sandbox Code Playgroud)
    2. 有关此问题的一些详细的低级机制,请参阅此处其他答案底部的“结果和结论”部分,以及@torek 此处的非常长而详细的答案
    3. "us"/"ours" = HEAD也就是说feature_branch,因为feature_branch你跑的时候在分支上git revert some_previous_commit。更具体地说,“我们”/“我们的”包含由 表示的更改git diff some_previous_commit..HEAD,它们是从提交还原到我们现在正在进行的提交的更改。
    4. "them"/"theirs" = (inverse or reverse of) some_previous_commit,这是您要还原其更改的提交(撤消,通过在 之上创建新提交feature_branch)。换句话说,“他们” /“他们”包含所表达的变化git diff some_previous_commit..some_previous_commit~,其中some_previous_commit~父提交some_previous_commit。这意味着,“他们的” /“他们的”相对some_previous_commit,因为它包含的其变化相反,为了复原some_previous_commit的变化。

示例用例:

合并冲突解决示例:

# 1. Merge `feature_branch` into `master`, accepting ALL of 
# `master`'s (`ours`) changes in the event of 
# any merge conflicts! 
git checkout master
git merge -X ours feature_branch

# 2. Merge `feature_branch` into `master`, accepting ALL of 
# `feature_branch`'s (`theirs`) changes in the event of 
# any merge conflicts! 
git checkout master
git merge -X theirs feature_branch
Run Code Online (Sandbox Code Playgroud)

这里还有一些。这些是我最常用的技术,而不是上面的两个例子。

# 3. Assuming this merge attempt results in merge conflicts in
# these 3 files, but we know all of the changes on the `master`
# branch side are the ones we wish to keep, check out these 3 
# files from `master` (`--ours`) to overwrite the conflicted
# files. Then, add these now-fixed files to stage them for 
# committing, and continue (finish) the merge. 
git checkout master
git merge feature_branch
git checkout --ours -- path/to/somefile1.c path/to/somefile2.c path/to/somefile3.c
git add path/to/somefile1.c path/to/somefile2.c path/to/somefile3.c
git status 
git merge --continue

# 4. Assuming this merge attempt results in merge conflicts in
# these 3 files, but we know all of the changes on the `feature_branch`
# side are the ones we wish to keep, check out these 3 
# files from `feature_branch` (`--theirs`) to overwrite the conflicted
# files. Then, add these now-fixed files to stage them for 
# committing, and continue (finish) the merge. 
git checkout master
git merge feature_branch
git checkout --theirs -- path/to/somefile1.c path/to/somefile2.c path/to/somefile3.c
git add path/to/somefile1.c path/to/somefile2.c path/to/somefile3.c
git status 
git merge --continue
Run Code Online (Sandbox Code Playgroud)

非常有用:如果整个文件夹存在冲突,您还可以指定一次接受来自整个文件夹--ours--theirs分支的所有冲突更改,如下所示!:

**最佳合并冲突解决示例:**

# 5. [BEST EXAMPLE] Assuming this merge attempt results in merge conflicts in
# a bunch of files, some of which are inside `path/to/some/dir`, I can
# choose to accept the changes from one side or the other **for 
# all conflicts within files inside this directory**, like this!:
git checkout master
git merge feature_branch

# Keep `--theirs` for all conflicts within files inside this dir
git checkout --theirs -- path/to/some/dir
# OR: keep `--ours` for all conflicts within files inside this dir
git checkout --ours -- path/to/some/dir

# Add (stage for committing) all changes within files inside this dir 
# all at once
git add path/to/some/dir 
git status 
git merge --continue 
Run Code Online (Sandbox Code Playgroud)

处理path does not have our versionpath does not have their version错误:

如果你曾经运行过这样的事情:

git checkout --ours -- path/to/some/dir
Run Code Online (Sandbox Code Playgroud)

......它没有用!它什么也没做。相反,它输出这些错误:

error: path 'path/to/some/dir/file1.cpp' does not have our version
error: path 'path/to/some/dir/file2.cpp' does not have our version
error: path 'path/to/some/dir/file3.cpp' does not have our version
Run Code Online (Sandbox Code Playgroud)

问题是这些错误的文件是边删除文件our,所以我们必须git rm在运行之前手动手动删除它们git checkout --ours -- path/to/some/dir

git rm path/to/some/dir/file1.cpp path/to/some/dir/file2.cpp \
path/to/some/dir/file3.cpp

# then try again
git checkout --ours -- path/to/some/dir
Run Code Online (Sandbox Code Playgroud)

您也可以只执行此操作来自动化该过程:

git checkout --ours -- path/to/some/dir \
|& gawk '{ print $3 }' | xargs git rm

git checkout --ours -- path/to/some/dir
Run Code Online (Sandbox Code Playgroud)

有关上述命令的详细说明,请在此处查看我的回答:git checkout --ours when file spec 包含已删除的文件

警告 警告 警告!

有关下面描述的问题的更详细示例,请参阅我的其他答案here

不要这样做git checkout -- path/to/some/dir,也不要git checkout some_branch -- path/to/some/dir在解决冲突的过程中(例如在merge上面示例中的冲突期间),除非您打算分别从或 中检查目录中的所有文件,并用这些文件覆盖本地文件FILES,从而只是接受来自一侧或另一侧的冲突更改。HEADsome_branchpath/to/some/dir

换句话说,在解决冲突的过程中,这:

好的:

# GOOD :)
# Accept all conflicts from one side or the other (while still 
# merging changes from both sides into one, in the event of being
# in the middle of a `git merge`).

git checkout --ours -- path/to/some/dir
# OR
git checkout --ours -- path/to/some/file
Run Code Online (Sandbox Code Playgroud)

接受来自 side的更改--ours,如果这是我们想要的,这总是好的和安全的,而这个:

坏的:

# BAD :(
# OVERWRITE all files with these files from `some_branch` instead,
# thereby _losing_ any changes and/or files contained in the other
# side but which are not in `some_branch`.

git checkout some_branch -- path/to/some/dir 
# OR
git checkout some_branch -- path/to/some/file
Run Code Online (Sandbox Code Playgroud)

将完全检出并覆盖指定的整个目录或整个文件,而不仅仅是冲突的更改本身。这意味着你可能会无意中删除从一个侧面或改变其他的做一个完整的结算用git checkout some_branch,而不是冲突的分辨率git checkout --oursgit checkout --theirs出于这个原因,建议使用git checkout --ours -- file_or_dir_pathsgit checkout --theirs -- file_or_dir_paths,不是git checkout some_branch -- file_or_dir_paths只要你是在解决冲突中git mergegit cherry-pickgit rebase,或git revert

但是,如果您git checkout some_branch -- file_or_dir_paths确实运行是因为您了解这种行为并且这就是您想要的,那么您也需要意识到这一点:检查这样的整个目录不会删除该目录中不存在的本地文件some_branch,就像您一样希望它会。相反,如果它们在本地存在但不在some_branch. 因此,您必须手动删除所有这些文件。请记住这一点,否则最终会让您非常困惑。在我的其他答案中阅读更多相关信息(这个答案也有一个很好的解决方案)这里

更进一步/附加说明和提示:

  1. 文件冲突解决的上述例子可以在冲突情况下适用于任何的各种操作(的git mergegit cherry-pickgit rebasegit revert,等),但你需要牢记什么theirs,并ours为每种类型的解决冲突的手段,解释以上。
  2. 您也可以只使用分支名称,例如masterfeature_branch代替-X ours/-X theirs--ours--theirs。警告:传递分支名称可能看起来更容易和更清晰,但对您的更改可能是危险的,因为这样做会执行完整的文件或目录替换,而不是仅针对文件中的冲突的冲突解决方案。请参阅上面的“警告警告”部分。但是,如果您确实想要进行完整的文件替换,而不仅仅是接受来自一侧或另一侧的冲突更改,请执行以下操作:
    # See "WARNING WARNING WARNING" section above.
    git checkout feature_branch -- path/to/somefile1.c path/to/somefile2.c path/to/somefile3.c
    
    Run Code Online (Sandbox Code Playgroud)
  3. 您还可以检出整个目录而不是单独指定文件!见这里这个答案我在这里的答案我在这里的其他答案。我刚刚测试了它。这也有效。但是,再次注意上面的“警告警告”部分。这会进行完整的目录替换,而不仅仅是接受整个文件夹的一侧或另一侧的冲突更改:
    # Check out ALL files from feature_branch which are in
    # directory "path/to/dir". See "WARNING WARNING WARNING"
    # section above.
    git checkout feature_branch -- path/to/dir
    
    Run Code Online (Sandbox Code Playgroud)
  4. 请记住,如果您故意使用git checkout feature_branch -- path/to/dir,期望/希望它会删除目录path/to/dir中不存在的本地文件feature_branch,它不会。在运行该checkout命令之前或之后,您必须在本地文件系统中手动删除这些文件。在我的答案中阅读更多内容:
    1. 所有关于在 git 中检出文件或目录
    2. 如何按路径执行--soft--hardgit reset

参考:

  1. [我的答案,我一直在引用!] “关于在 git 中检出文件或目录的所有内容”:如何从另一个分支只获取一个文件
  2. [我的回答]为什么 git 不能按路径进行硬/软重置?--> 特别是在最后“背景知识”部分中的git 术语和定义
  3. [我自己对“他们”和“我们”在此期间的含义的回答git revert]谁是“git revert ”中的“他们”和“我们”
  4. [@LeGEC 的回答指出“我们的/我们”总是HEAD,而“他们/他们的”总是另一个分支或提交]谁是 `git revert` 中的 `them` 和 `us`?
  5. [关于我对git merge和的理解,我交叉检查的预先存在的答案git rebase]根据 Git,谁是“我们”,谁是“他们”?
  6. 来自man git checkout:“请注意,在 git rebase 和 git pull --rebase 期间,我们和他们的可能会出现交换”:
    --ours, --theirs
        When checking out paths from the index, check out stage #2 (ours) or #3 (theirs) for
        unmerged paths.
    
        Note that during git rebase and git pull --rebase, ours and theirs may appear swapped;
        --ours gives the version from the branch the changes are rebased onto, while --theirs
        gives the version from the branch that holds your work that is being rebased.
    
        This is because rebase is used in a workflow that treats the history at the remote as
        the shared canonical one, and treats the work done on the branch you are rebasing as the
        third-party work to be integrated, and you are temporarily assuming the role of the
        keeper of the canonical history during the rebase. As the keeper of the canonical
        history, you need to view the history from the remote as ours (i.e. "our shared
        canonical history"), while what you did on your side branch as theirs (i.e. "one
        contributor’s work on top of it").
    
    Run Code Online (Sandbox Code Playgroud)
  7. [回答我的问题]:您也可以将目录路径传递给 git 以检出整个目录中的所有文件,而不必单独指定文件:如何仅针对某个目录接受来自“他们”分支的 git 合并冲突?
  8. [我的回答] git checkout --ours 当文件规范包含已删除的文件时
  9. 用于绘制漂亮的 ASCII 图片或图表以放置在代码中:https : //asciiflow.com/

附加研究:

  1. [我仍然需要自己研究这个答案! - 完毕; 截至 2020 年 1 月 7 日,我已经弄清楚并在此处更新了我的答案]谁是“git revert”中的“他们”和“我们”?
  2. [我需要继续学习和阅读本文] git checkout --ours 不会从未合并的文件列表中删除文件

  • 在我看来,错误在于动词“rebase”的奇怪语法。当你说“git merge feature”时,你是在说将功能分支合并到我(无论我是谁)中,但是当你说“git rebase master”时,你是在说将我(无论我是谁)rebase到主分支上。因此,可以说,直接宾语和间接宾语被交换了。我们和他们的逆转直接源于此。 (2认同)
  • 是否可以通过说“我们”是存储库中已有的代码而“他们”是我试图合并的代码来简化这一点?那是对的吗? (2认同)

归档时间:

查看次数:

18334 次

最近记录:

8 年,1 月 前