1. ホーム
  2. git

[解決済み】Gitの言う「私たち」とは誰のことで、「彼ら」とは誰のことなのか?

2022-04-13 23:31:49

質問

Git のリベースの後やその他の状況下で、いくつかのファイルに 弊社で削除 の中にある git status を報告します。誰が 私たち Gitによれば、その理由とは?

このブランチに座っている私のことを指しているのでしょうか、そしてそれは私のために働いているのでしょうか?それとも、私自身と、私がリベースしているブランチで作業している人たちを指しているのでしょうか?

解決方法は?

(これは、"git rebaseはどのように動作し、それによって何が起こっているのか、という質問に対する答えでもあります("))

すべての場合において

  1. "私たち" (または "ours" ) = 現在チェックアウトされているコミット ( HEAD ) を実行した時点で、gitはそのアクションを で、これが衝突を引き起こす(これについては後で詳しく説明します)。
  2. 彼ら" (または "theirs" ) = もう一方のコミット、git がチェックアウトしていないもの gitがアクションを起こした瞬間に があり、それがコンフリクトの原因となります(これについては後述します)。

重要です。 HEAD を実行した時点で、衝突を引き起こすアクションは、必ずしも HEAD は、gitコマンドを入力した瞬間のものです。これは理解しておく必要があります。Git はいくつかのチェックアウトを行い HEAD (どのコミットがチェックアウトされたか) を実行する前に衝突が発生し、素人目には "us" と "them" が入れ替わった、あるいは逆に見えることになります。

4つのケースの詳細: マージ、チェリーピック、リベース、リバート。

  1. git merge (直感的)です。
    1. サンプルコマンドです。
      git checkout master
      git merge feature_branch  # merge feature_branch into master
      
      
    2. "us"/"ours"。 = HEAD である。 master ブランチにいたため master を実行した時に git merge feature_branch .
    3. "they"/"theirs"。 = feature_branch にマージするブランチです。 master .
  2. git cherry-pick (直感的な)。
    1. サンプルコマンドです。
      git checkout feature_branch
      git cherry-pick some_commit  # apply some_commit to feature_branch
      
      
    2. "us"/"ours"。 = HEAD である。 feature_branch ブランチにいたため feature_branch を実行した時に git cherry-pick some_commit .
    3. "they"/"theirs"。 = some_commit にチェリーピックしているコミットです。 feature_branch .
  3. git rebase (直感に反しているが、仕組みを理解すれば全く納得がいく)。
    1. サンプルコマンドです。
      git checkout feature_branch
      git rebase master  # rebase feature_branch onto latest master
      
      
    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
      
      
    3. "us"/"ours"。 = HEAD である。 上流ブランチ: 最初は最後の x にコミットする。 master そして、その後、いくつかのNEWコミットが行われます。 y' , cherry-picked そのうえで (これはやっかいだ!)。というのも、あなたが入力したときに git rebase master , git はまず 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 が舞台裏で新しいチェックアウトを行ったため、このようになりました。 HEAD を入力したときにいたブランチではありません。 git rebase master . 代わりに 私たち または HEAD は、最後の x にコミットする。 master の間に競合が発生した場合、最初の cherry-pick または、NEWコミットであれば何でもよい。 y' へのチェリーピックに成功しました。 master は、それ以降のチェリーピック中に競合が発生した場合。 その はもう一方のコミットであり、これはある y からのコミット feature_branch に適用され、この新しい HEAD を順番にチェリーピックして、最初の y へのコミット feature_branch というのは、すぐに git merge-base master feature_branch 最後の y にコミットする。 feature_branch . すぐ下にある "them" の説明も参照してください。
    4. "them"/"theirs" = ある y コミット元 feature_branch に適用され、新しくチェックアウトされた HEAD で、ここで HEAD は、最後の x にコミットしています。 master をリベース中の最初のチェリーピック操作に使うか、あるいは新しく作成されたこれらの y' の上にコミットしています。 master として feature_branch がリベースされるか、あるいは一度に1つのコミットしか取得されない(新しいコミットの文字列に沿って git merge-base master feature_branch の最後のコミットまで feature_branch ) の上に master . すぐ上の"us"の説明も参照。
  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  
      
      
    2. 今回の詳細な低レベルの仕組みについては、以下の下部にある「"結果と結論"」のセクションをご覧ください。 もう一つの回答はこちら と同様です。 torek さんの長くて詳しい回答はこちらです。 .
    3. "us"/"ours"。 = HEAD である。 feature_branch ブランチにいたため feature_branch を実行した時に git revert some_previous_commit . より具体的には "us"/"ours" が表現する変更を含んでいます。 git diff some_previous_commit..HEAD これは、元に戻されたコミットから現在のコミットへの変更点です。
    4. "them"/"theirs" =(その逆)である。 some_previous_commit の上に新しいコミットを作成し、その変更を元に戻す(undo)コミットです。 feature_branch ). つまり "they"/"theirs"。 が表現する変更を含んでいます。 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

以下は、その一部です。 私がよく使うテクニックを紹介します。 上記の2つの例ではなく

# 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 version または path does not have their version ERRORS

もし、このようなことを実行することがあれば

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

また、代わりにこれを行うことで、処理を自動化することができます。

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

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

上記のコマンドの詳しい説明は、こちらの回答をご覧ください。 git checkout --ours ファイル仕様に削除されたファイルが含まれる場合 .

警告 警告 警告!

以下に説明する問題のより詳細な例について。 他の回答はこちら .

をしないでください。 git checkout -- path/to/some/dir また git checkout some_branch -- path/to/some/dir のような)競合解消の途中で merge をチェックアウトするつもりでなければ、上記の例のようなコンフリクトは起こりません。 すべて からのファイル HEAD または some_branch で、それぞれディレクトリ path/to/some/dir そして、ローカルファイルをこれらのファイルで上書きし、それによって ない ただ どちらか一方からの矛盾した変更を受け入れること。

言い換えれば 紛争解決中 、これです。

GOODです。

# 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です。

# 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

は、完全に チェックアウトして上書きする ではなく、指定されたディレクトリまたはファイル全体が対象となります。 は、競合する変更そのものだけです。 このことは、以下のような完全なチェックアウトをすることで、不注意にどちらかの変更を削除してしまう可能性があることを意味します。 git checkout some_branch でのコンフリクト解消ではなく git checkout --ours または git checkout --theirs . を使用することが推奨されます。 git checkout --ours -- file_or_dir_paths または git checkout --theirs -- file_or_dir_paths NOT git checkout some_branch -- file_or_dir_paths をするときはいつも などは git merge , git cherry-pick , git rebase または git revert .

しかし、もしあなたが git checkout some_branch -- file_or_dir_paths この動作を理解した上で、それが 欲しい ディレクトリ全体をチェックアウトしても、そのディレクトリに存在しないローカルファイルは some_branch ということです。その代わり、ローカルに存在し、かつ some_branch . そのため、これらのファイルを手動ですべて削除する必要があります。 これを覚えておかないと、最終的に非常に困惑することになります。これについては、私の他の回答で詳しく説明しています。 こちら(この回答にも良い解決策があります) そして こちら .

さらに進む/追加のメモとヒント。

  1. 上記のファイルの競合解消の例は、様々な種類の操作のいずれにおいても競合が発生した場合に適用できます( git merge , git cherry-pick , git rebase , git revert など)を覚えておく必要がある以外は theirsours は、上記で説明したように、それぞれの紛争解決のための手段を意味する。
  2. のようなブランチ名だけを使用することもできます。 master または feature_branch の代わりに -X ours / -X theirs--ours--theirs . 警告: ブランチ名を渡すのは簡単でわかりやすいように思えますが、この方法はあなたの変更にとって危険なものになりえます。 ファイル内のコンフリクトを解決するのではなく、ファイルやディレクトリを完全に置き換える。 . 上記の "WARNING WARNING" のセクションを参照してください。もしあなたが、どちらか一方からの競合する変更を受け入れるのではなく、完全なファイル置換を行いたいのであれば、以下の方法があります。
    # See "WARNING WARNING WARNING" section above.
    git checkout feature_branch -- path/to/somefile1.c path/to/somefile2.c path/to/somefile3.c
    
    
  3. をチェックすることもできます。 ディレクトリ全体 ファイルを個別に指定するのではなく 参照 この回答はこちら 私の答えはこちら そして 私のもう一つの答えはこちら . 今テストしました。これも動作します。ただし、ここでも、上記の "WARNING WARNING" セクションに注意してください。これは、フォルダ全体に対して、どちらか一方からの競合する変更を受け入れるのではなく、ディレクトリ全体の置換を行うものです。
    # 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
    
    
  4. を意図的に使用することを忘れないでください。 git checkout feature_branch -- path/to/dir ディレクトリにあるローカルファイルを削除してくれることを期待する。 path/to/dir には存在しないが feature_branch の場合、それはできません。を実行する前に、または実行した後に、ローカルファイルシステムからそれらのファイルを手動で削除する必要があります。 checkout コマンドを使用します。詳しくはこちらの回答で。
    1. gitでファイルやディレクトリをチェックアウトするためのすべて
    2. を行う方法 --soft または --hard git reset by パス

参考文献

  1. [いつも参考にしている私の答えです!] "gitにおけるファイルやディレクトリのチェックアウトについてのすべて"。 別のブランチから 1 つのファイルだけを取得する方法
  2. [私の答え] なぜgitはパスによるハード/ソフトリセットを行えないのですか? --> 特に git の用語と定義 の中にある 背景知識"。 のセクションをご覧ください。
  3. [私なりの答えですが、quot;they" と "us" は何を意味するのでしょうか? git revert ] git revert` において `them` と `us` は誰ですか?
  4. [LeGEC さんの回答は、quot;ours/us" が常に HEAD そして "them/theirs" は常にもう一方のブランチまたはコミットです] 。 git revert` において `them` と `us` は誰ですか?
  5. [の理解について、既存の答えと照らし合わせてみました。 git mergegit rebase ] Git では、誰が "us" で、誰が "them" なのですか?
  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").
    
    
  7. [私の質問への回答]: ディレクトリのパスもgitに渡せば、ファイルを個別に指定する代わりに、ディレクトリ全体からすべてのファイルをチェックアウトすることができます。 特定のディレクトリのみについて、"their" ブランチからの git merge の競合を受け入れるにはどうすればよいですか?
  8. [私の答え]を git checkout --ours ファイル仕様に削除されたファイルが含まれる場合
  9. ASCIIのきれいな絵や図を描いて、コードの中に配置します。 https://asciiflow.com/ .

追加のスタディ

  1. [ この答えは、まだ自分で勉強する必要がありますね。 -done;私はそれを理解し、2020年1月7日現在、ここに私の答えを更新しました]。 git revert` において、`them` と `us` は誰ですか?
  2. (静流の声) これから勉強して 読まなきゃいけないのに git checkout --ours で、未マージファイル一覧からファイルが削除されない。