web-dev-qa-db-ja.com

Gitサブツリー-サブツリーは最新だがプッシュできない

いくつかの基本コードを共有するために、作業中のいくつかのプロジェクトで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 [email protected]:***
! [rejected]        72a6157733c4e0bf22f72b443e4ad3be0bc555ce -> master (non-fast-forward)
error: failed to Push some refs to '[email protected]:***'
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.

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

78
mateusz

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

「現在のブランチの先端が遅れているため、更新が拒否されました。リモートの変更をマージする(「git pull」など)」問題をプッシュしている場合(何らかの理由で、特にgitの履歴を台無しに) gitコマンドをネストして、Pushをherokuに強制できるようにする必要があります。たとえば、上記の例を考えます:

git Push heroku `git subtree split --prefix pythonapp master`:master --force
87
Eric Woodruff

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
33
Chris Jordan

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

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

[編集:残念ながらsubtree Push--ontoを基礎となるsplitに転送しないため、操作は2つのコマンドで実行する必要があります。これが完了すると、私のコマンドは他の回答の1つと同じであることがわかりますが、説明は異なるので、とにかくここに残しておきます。]

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を使用すると、アップストリームコミットはすべてOKとして記録され、そのまま使用できます。そのため、書き換えプロセスが、書き換えのマージの親の1つとしてそれらに遭遇すると、書き換えを試みる代わりにそれらを保持しますそれらを通常の方法で。

27
entheh

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

git Push Origin `git subtree split --prefix dist master`:gh-pages --force

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

10
Colin D

私も以前にこの問題に遭遇したことがありますが、ここでそれを解決しました。

私が見つけたのは、ローカルマスターブランチに接続されていないブランチがあったことです。このブランチは存在し、そのボイドにぶら下がっています。あなたの場合、おそらくproject-sharedと呼ばれます。これが事実であり、git branchを実行すると、ローカルproject-sharedブランチが表示されると仮定すると、 'append '既存のproject-sharedブランチへの新しいコミット:

git subtree split --prefix=public/shared --onto public-shared --branch public-shared

私が理解した方法は、git subtree--ontoから新しいブランチの作成を開始します。この場合は、ローカルpublic-sharedブランチです。次に、ブランチとは、古いpublic-sharedブランチを置き換えるブランチを作成することを意味します。

これにより、以前のpublic-sharedブランチのSHA)がすべて保持されます。最後に、

git Push project-shared project-shared:master

project-sharedリモートもあると仮定します。これにより、ローカルがvoidにハングし、project-sharedブランチがリモートproject-sharedmasterブランチにプッシュされます。 。

3
snw

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

これがどのように機能するかをよりよく理解するために、例を簡単に再現できます。次の履歴を考慮してください(行の形式は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で分割しています。コミットDはコミットEを取り消すため、_zCは同じツリーBを持つため、B-Cシーケンスは何もしませんdirには変更がありますが。

次に、分割を行います。まず、コミット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

次に、コミットEで分割します。

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

はい、2つのコミットを失いました。これにより、2番目の分割をプッシュしようとするとエラーが発生します。これは、既にOriginに到達した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
2
klimkin

ローカルの変更をリモートのサブツリーリポジトリに強制的にプッシュできます。

git Push subtree_remote_address.git `git subtree split --prefix=subtree_folder`:refs/heads/branch --force
0
FunkyKat

別の[より簡単な]ソリューションは、可能であれば別のコミットを行うことにより、リモートのヘッドを進めることです。この高度なヘッドをローカルサブツリーにプルすると、そこから再びプッシュできるようになります。

0
9swampy

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

与えられた:

#! git subtree Push --prefix=public/shared project-shared master
git Push using:  project-shared master
To [email protected]:***
! [rejected]        72a6157733c4e0bf22f72b443e4ad3be0bc555ce -> master (non-fast-forward)
error: failed to Push some refs to '[email protected]:***'
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」で使用されることに注意してください。

0
Amos

それで、これは@enthehが言ったことに基づいて書いたものです。

for /f "delims=" %%b in ('git subtree split --prefix [name-of-your-directory-on-the-file-system-you-setup] -b [name-of-your-subtree-branch]') do @set token=%%b
git Push [alias-for-your-subtree] %token%:[name-of-your-subtree-branch] --force

pause
0
Demodave

Chris Jordanのソリューションに基づいたWindowsユーザー向けの簡単なPowerShell

$id = git subtree split --prefix pythonapp master
Write-Host "Id is: $id"
Invoke-Expression "git Push heroku $id`:master --force"
0
Rtype

エリック・ウッドラフの答えは私には役に立たなかったが、以下は助けになった:

私は通常、「git subtree pull」と「--squash」オプションを使用します。これにより物事の調整が難しくなったようですので、今回はつぶすことなくサブツリーをプルし、競合を解決してからプッシュする必要がありました。

私は、押しつぶされたプルが競合を明らかにしなかったと付け加えなければなりません、すべてが大丈夫だと私に言いました。

0
Zsolt Szatmari