根据Git,谁是“我们”,谁是“他们”?

tv6aics1  于 2023-03-06  发布在  Git
关注(0)|答案(2)|浏览(103)

在Git重定基之后,或者在其他情况下,你可以在git status报告中找到一些标记为 deleted by us 的文件。根据Git,us 是谁?为什么?
它是指我坐在这个分支上,它为我工作吗?还是指它自己和我正在重建的分支上工作的人们?

disho6za

disho6za1#

当您 merge 时,us指的是您要合并到的分支,而them指的是要合并的分支。
当你 rebase 时,us指的是上游分支,them指的是你移动的分支,在rebase的情况下,这有点违反直觉。
原因是Git使用了相同的合并引擎来进行rebase,实际上是在上游分支中挑选你的东西。us = into,them = from。

xdnvmnnf

xdnvmnnf2#

根据Git,谁是"我们"/"我们的"和"他们"/"他们的"?

(This还回答了以下问题:"git rebase是如何工作的,它到底发生了什么?")

在所有情况下:

用外行人的话来说(谢谢,@user20358):
"us"是已经在repo中的代码,"them"是[您]试图合并的代码
更完整的说法是:
1.* "us"(或"ours"**)=当前 checkout 的提交(HEAD 在git执行 * 导致冲突的动作时(稍后会详细介绍),以及:
1.* *"them"(或"their"**)=另一个提交,在git执行引起冲突的动作 * 时 * 没有被git checkout (稍后会详细介绍)。

  • 重要提示:HEAD在它执行引起冲突的动作时不一定是你输入git命令时的HEAD。这一点需要理解。Git可能会执行一些 checkout 操作并更改HEAD(哪个提交被 checkout )在运行引起冲突的动作之前,从而使得"我们"和"他们"对于未经训练的眼睛来说看起来是交换的或反向的。

这4例病例的详细信息:合并、挑选、重定基、还原:

  1. git merge(直观):
    1.示例命令:
git checkout master
git merge feature_branch  # merge feature_branch into master

1.* "us "/" ours"**= HEAD,也就是master,因为在运行git merge feature_branch时,您位于分支master上。
1.
*"them "/" theirs"**= feature_branch,这是要合并到master中的分支。

  1. git cherry-pick(直观):
    1.示例命令:
git checkout feature_branch
git cherry-pick some_commit  # apply some_commit to feature_branch

1.* "us "/" ours"**= HEAD,即feature_branch,因为在运行git cherry-pick some_commit时您位于分支feature_branch上。
1.
*"them "/" theirs"**= some_commit,这是您正在挑选的提交feature_branch

  1. git rebase(违反直觉,但一旦你理解了它的工作原理,就完全有意义了):
    1.示例命令:
git checkout feature_branch
git rebase master  # rebase feature_branch onto latest master

1.这张图(绘制在https://asciiflow.com),* latest * 或 * newest * 提交位于顶部和/或右侧:

#             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

1.* "我们"/"我们的"= HEAD,为上游分行:最初在master上提交最后一个x,然后在此之上提交新的y'cherry-picked这是因为当你输入git rebase master的时候, git首先 checkout master作为开始挑选feature_branch提交到 * 的起点,则它确定从feature_branch中选择哪些提交(即:feature_branch提交中的哪些还没有在master上).它通过查找merge-basefeature_branchmaster共有的提交,并且可以通过git merge-base master feature_branch找到)来完成此操作,然后它从merge-base * 之后 * 的第一个提交开始挑选提交,一次一个地工作,指向feature_branch上的最后一次提交,到master的顶端,从而将所有添加到feature_branch的"新" y提交"重定基"到最新的master上,作为新的y'提交。因此,"us "/" ours"= HEAD,但由于git在后台执行了一个新的 checkout 来执行此重定基,HEAD不是您键入git rebase master时所在的分支。相反,如果在第一个cherry-pick期间发生冲突,则usHEADmaster上的最后一个x提交,或者是任何新提交y',如果冲突发生在任何稍后的挑选期间,则最后一次被成功地挑选到master上。它们因此是另一提交,其是来自x1M51N1x的某个x1M50N1x提交,该提交经由樱桃选择被应用于该新的x1M52N1x,按顺序,从feature_branch上的第一次y提交(紧接 * git merge-base master feature_branch之后)一直到feature_branch上的最后一次y提交。 请参见下面对"它们"的解释。
1.* "them "/" theirs"**=来自feature_branch的正被应用于新检出的HEAD的某个y提交,其中HEAD是用于在变基期间的第一挑选操作的master上的最后x提交,或者这些新创建的y'之一在master之上提交,因为feature_branch被"重定基",还是一次只提交一个(沿着从git merge-base master feature_branchfeature_branch上的最后一次提交的新提交串)到master上。 请参见上面对"us"的解释。*

  1. 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

1.* 关于这个问题的一些详细的低级机制,请参见my other answer herethis very long and detailed answer by @torek here底部的"结果和结论"部分。*
1.* *"us "/" ours"= HEAD,也就是feature_branch,因为在运行git revert some_previous_commit时,您位于分支feature_branch上。更具体地说,"us "/" ours"**包含git diff some_previous_commit..HEAD表示的更改,它们是从正被恢复的提交(some_previous_commit)被提交的点到我们现在正在进行的提交的改变。

1.“他们”/“他们的”=some_previous_commit(的逆或相反值),它是您要还原其更改的提交(撤销,通过在feature_branch之上创建新提交)。换句话说,**“them”/“their”*包含由git diff some_previous_commit..some_previous_commit~表达的改变,其中some_previous_commit~some_previous_commit的 * 父提交 .这意味着“them”/“theirs”**是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

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

# 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

非常有用:如果存在 * 整个文件夹 * 的冲突,您还可以指定接受来自--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

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

如果你运行这样的程序:

git checkout --ours -- path/to/some/dir

......但它不起作用!它什么也没做。相反,它输出了以下错误:

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

问题是这些错误文件是our端的 * 删除 * 文件,因此在运行git checkout --ours -- path/to/some/dir之前,我们必须手动git rm每个文件。

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

您也可以这样做来自动化该过程:

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

git checkout --ours -- path/to/some/dir

有关上述命令的详细说明,请参阅我的回答:git checkout --当文件规范包含已删除文件时我们的。

警告警告!

有关下面描述的问题的更详细示例,请参见see my other answer here
不要在冲突解决过程中执行git checkout -- path/to/some/dirgit checkout some_branch -- path/to/some/dir(例如在merge冲突期间,如上面的示例),除非您打算分别从HEADsome_branch检出目录path/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

只接受来自--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

将完全 * checkout 并覆盖 * 指定的整个目录或整个文件,而不是 * 仅冲突的更改本身。* 这意味着您可能会无意中使用git checkout some_branch执行完全 checkout 而不是使用git checkout --oursgit checkout --theirs执行冲突解决,从而从一端或另一端删除更改。因此,每当您正在解决冲突(例如git mergegit cherry-pickgit rebasegit revert)时,建议使用git checkout --ours -- file_or_dir_pathsgit checkout --theirs -- file_or_dir_paths,而不是git checkout some_branch -- file_or_dir_paths
但是,如果您确实运行git checkout some_branch -- file_or_dir_paths,因为您了解这种行为,并且这正是您所 * 想要 * 的,那么您也需要注意这一点:像这样 checkout 整个目录并不会像您所期望的那样删除该目录中不存在于some_branch的本地文件。相反,如果这些文件存在于本地但不存在于some_branch,则会将它们单独留在本地文件系统中。* 因此,你必须手动删除所有这些文件代替。* 记住这一点,否则它会离开你非常非常困惑,在最后。请在我的其他答案here (this answer has a good solution to that too)here中阅读更多信息。

进一步/附加注解和提示:

1.上述文件冲突解决示例可以应用于各种类型的操作(git mergegit cherry-pickgit rebasegit revert等)中发生冲突的情况,除非您需要记住theirsours对于每种类型的冲突解决的含义,如上所述。
1.您也可以只使用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

1.你也可以 checkout 整个目录,而不是单独指定文件!请参见this answer here和我的答案,以及my other answer here。我刚刚测试过它。这也可以工作。但是,再次注意上面的“警告警告警告”部分。这是一个完整的目录替换,而不是仅仅接受来自一方或另一方对整个文件夹的冲突更改:

# 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

1.请记住,如果您确实有意使用git checkout feature_branch -- path/to/dir,期望/希望它会删除目录path/to/dir中不存在于feature_branch的本地文件,它不会。您必须在运行checkout命令之前或之后手动删除本地文件系统中的这些文件。

  1. All about checking out files or directories in git
  2. How to do a --soft or --hard git reset by path

参考文献:

1.[我的答案,我一直在引用!]“关于在git中 checkout 文件或目录的所有内容”:如何从另一个分支只获取一个文件?
1.[my answer]为什么git不能通过路径进行硬/软重置?--〉请特别参考**“背景知识”**部分中的 *git术语和定义 *!
1.[我自己对git revert期间“them”和“us”的含义的回答]在"git revert“中,”them“和”us“是谁?
1.[@LeGEC的回答指出“ours/us”总是HEAD,“they/their”总是另一个分支或提交]在"git revert“中,”they“和”us“是谁?
1.[关于我对git mergegit rebase的理解,我交叉检查了先前存在的答案]根据Git,谁是“我们”,谁是“他们”?
1.从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").

1.[回答我的问题]:你也可以把目录路径传递给git来 checkout 整个目录中的所有文件,而不必单独指定文件:如何只在某个目录下接受来自“their”分支的git合并冲突?
1.[我的答案] git checkout --当文件规范包含已删除文件时是我们的
1.用于绘制漂亮的ASCII图片或图表以放置在代码中:https://asciiflow.com/ .

附加研究:

1.[我自己还需要研究这个答案!--完成;我已经弄明白了,并在这里更新了我的答案,截至2020年1月7日]在一个'git revert'中,'them'和'us'是谁?
1.[我需要学习和阅读这仍然] git checkout --我们的不删除未合并文件列表中的文件

另请参见:

1.快速链接到我经常引用并认为是“git基本原理”的答案:

  1. Various ways to create a branch in git from another branch
  2. All about checking out files or directories in git
  3. Who is "us" and who is "them" according to Git?

相关问题