93

いくつかの基本コードを共有するために、現在取り組んでいるいくつかのプロジェクトで Git サブツリーを使用しています。基本コードは頻繁に更新され、アップグレードはどのプロジェクトでも発生する可能性があり、最終的にはすべてのプロジェクトが更新されます。

サブツリーが最新であると git が報告しているのに、プッシュが拒否されるという問題に遭遇しました。例えば:

#! git subtree pull --prefix=public/shared project-shared master
From github.com:****
* branch            master     -> FETCH_HEAD
Already up-to-date.

プッシュすると、プッシュするものが何もないというメッセージが表示されるはずです...そうですか?右?:(

#! git subtree push --prefix=public/shared project-shared master
git push using:  project-shared master
To git@github.com:***
! [rejected]        72a6157733c4e0bf22f72b443e4ad3be0bc555ce -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:***'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

この理由は何でしょうか?プッシュが失敗するのはなぜですか?

4

12 に答える 12

103

このブログのコメントで答えを見つけましたhttps://coderwall.com/p/ssxp5q

プッシュ中に「現在のブランチのヒントが遅れているため、更新が拒否されました。リモートの変更をマージしてください (例: 'git pull')」という問題に遭遇した場合 (何らかの理由で、esp が git の履歴をめちゃくちゃにしている)次に、heroku へのプッシュを強制できるように、git コマンドをネストする必要があります。たとえば、上記の例では次のようになります。

git push heroku `git subtree split --prefix pythonapp master`:master --force
于 2013-03-25T19:49:57.383 に答える
46

Windows では、ネストされたコマンドは機能しません。

git push heroku `git subtree split --prefix pythonapp master`:master --force

ネストされたビットを最初に実行できます。

git subtree split --prefix pythonapp master

これは(多くの数字の後)トークンを返します。

157a66d050d7a6188f243243264c765f18bc85fb956

含むコマンドでこれを使用します。

git push heroku 157a66d050d7a6188f243243264c765f18bc85fb956:master --force
于 2015-03-06T17:18:31.260 に答える
29

--onto次のフラグを使用します。

# DOESN'T WORK: git subtree push --prefix=public/shared project-shared master --onto=project-shared/master

[編集: 残念ながら、基になるにsubtree push転送しないため、操作は 2 つのコマンドで実行する必要があります! それが完了すると、私のコマンドは他の回答のいずれかと同じであることがわかりますが、説明が異なるため、とにかくここに残します.]--ontosplit

git push project-shared $(git subtree split --prefix=public/shared --onto=project-shared/master):master

または、bash を使用していない場合:

git subtree split --prefix=public/shared --onto=project-shared/master
# This will print an ID, say 0123456789abcdef0123456789abcdef,
# which you then use as follows:
git push project-shared 01234567:master

私はこれを理解するために git-subtree のソースを何時間も調べました。

subtree pushこれによりsubtree split、コミット履歴がプッシュ可能な形式に書き換えられます。これを行う方法は、public/shared/パスを持つパスの先頭を取り除き、パスを持たないファイルに関する情報を削除することです。つまり、圧縮されていない状態でプルしても、アップストリームのサブリポジトリのコミットはすべて無視されます。これは、ファイルにベア パスで名前が付けられているためです。(以下のファイルに触れないコミットpublic/shared/、または親と同一のマージ コミットも折りたたまれます。[編集: また、私はそれ以来、いくつかのスカッシュ検出を発見したので、今では、非スカッシュをプルした場合のみだと考えています。その後、さらに別の回答で説明されている単純なマージコミットの崩壊は、非スカッシュパスを選択し、押しつぶされたパスを破棄してください。リポジトリ。

ただし、を使用する--ontoと、すべてのアップストリーム コミットが逐語的に使用できるように記録されるため、書き換えプロセスが、書き換えたいマージの親の 1 つとしてそれらに遭遇すると、それらを書き換えようとする代わりにそれらを保持します。通常の方法で。

于 2015-06-08T17:10:54.833 に答える
16

「dist」サブツリーを gh-pages ブランチにデプロイする「GitHub ページ」タイプのアプリの場合、ソリューションは次のようになります。

git push origin `git subtree split --prefix dist master`:gh-pages --force

上記のherokuの例とは少し異なるように見えるので、これについて言及します。私の「dist」フォルダーが私のレポの master ブランチに存在することがわかります。次に、それをサブツリーとして、オリジンにもある gh-pages ブランチにプッシュします。

于 2016-06-23T19:16:23.867 に答える
4

この問題もありました。上位の回答に基づいて、私がしたことは次のとおりです。

与えられた:

#! git subtree push --prefix=public/shared project-shared master
git push using:  project-shared master
To git@github.com:***
! [rejected]        72a6157733c4e0bf22f72b443e4ad3be0bc555ce -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:***'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

これを入力してください:

git push <origin> 72a6157733c4e0bf22f72b443e4ad3be0bc555ce:<branch> --force

「git subtree push」によって出力されるトークンは、「git push」で使用されることに注意してください。

于 2019-03-21T08:52:32.383 に答える
3

これは、独自のアルゴリズムの限界によるものです。マージコミットを処理するとき、元のアルゴリズムは、無関係な親を切り離すために単純化された基準を使用します。特に、同じツリーを持つ親があるかどうかをチェックします。そのような親が見つかった場合、他の親がサブツリーに関係のない変更を行っていると仮定して、マージ コミットを折りたたみ、代わりに親コミットを使用します。場合によっては、これにより、サブツリーに実際の変更が加えられた履歴の一部が削除されることがあります。特に、サブツリーに触れる一連のコミットを削除しますが、同じサブツリー値になります。

これがどのように機能するかをよりよく理解するために、(簡単に再現できる) 例を見てみましょう。次の履歴を考慮してください (行の形式は次のとおりです: commit [tree] subject):

% git log --graph --decorate --pretty=oneline --pretty="%h [%t] %s"
*   E [z] Merge branch 'master' into side-branch
|\
| * D [z] add dir/file2.txt
* | C [y] Revert "change dir/file1.txt"
* | B [x] change dir/file1.txt
|/
*   A [w] add dir/file1.txt

この例では、 で分割していdirます。commitを元に戻す commitがあるため、 commitDEて同じ treezを持ちます。CBB-Cdir

では分割してみましょう。まず commit で分割しCます。

% git log `git subtree split -P dir C` ...
* C' [y'] Revert "change dir/file1.txt"
* B' [x'] change dir/file1.txt
* A' [w'] add dir/file1.txt

次に commit で分割しEます。

% git log `git subtree split -P dir E` ...
* D' [z'] add dir/file2.txt
* A' [w'] add dir/file1.txt

はい、2 つのコミットを失いました。これにより、2 番目の分割をプッシュしようとするとエラーが発生します。これは、オリジンに既に入っている 2 つのコミットがないためです。

push --force通常、ドロップされたコミットには重要な情報が含まれていないため、通常はを使用してこのエラーを許容できます。長期的には、バグを修正する必要があるため、分割履歴には、dir予想どおり に触れるすべてのコミットが実際に含まれます。この修正には、隠された依存関係の親コミットのより深い分析が含まれることを期待しています。

参考までに、動作を担当する元のコードの一部を次に示します。

copy_or_skip()
  ...
  for parent in $newparents; do
      ptree=$(toptree_for_commit $parent) || exit $?
      [ -z "$ptree" ] && continue
      if [ "$ptree" = "$tree" ]; then
          # an identical parent could be used in place of this rev.
          identical="$parent"
      else
          nonidentical="$parent"
      fi
  ...
  if [ -n "$identical" ]; then
      echo $identical
  else
      copy_commit $rev $tree "$p" || exit $?
  fi
于 2015-02-06T01:11:47.387 に答える
0

Eric Woodruff の答えは役に立ちませんでしたが、次のことは役に立ちました。

私は通常、'--squash' オプションを指定して 'git subtree pull' を実行します。これにより調整が難しくなったようです。そのため、今回は押しつぶさずにサブツリーをプルし、いくつかの競合を解決してからプッシュする必要がありました。

押しつぶされたプルが競合を明らかにしなかったことを付け加えなければなりません。すべてが問題ないと言われました。

于 2015-03-20T15:49:30.663 に答える