いくつかの基本コードを共有するために、作業中のいくつかのプロジェクトで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.
この理由は何でしょうか?プッシュが失敗するのはなぜですか?
このブログのコメントで答えを見つけました https://coderwall.com/p/ssxp5q
「現在のブランチの先端が遅れているため、更新が拒否されました。リモートの変更をマージする(「git pull」など)」問題をプッシュしている場合(何らかの理由で、特にgitの履歴を台無しに) gitコマンドをネストして、Pushをherokuに強制できるようにする必要があります。たとえば、上記の例を考えます:
git Push heroku `git subtree split --prefix pythonapp master`:master --force
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
--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つとしてそれらに遭遇すると、書き換えを試みる代わりにそれらを保持しますそれらを通常の方法で。
「GitHubページ」タイプのアプリの場合、「dist」サブツリーをgh-pagesブランチにデプロイすると、ソリューションは次のようになります
git Push Origin `git subtree split --prefix dist master`:gh-pages --force
これは、上記のherokuの例とは少し異なるため、これについて言及します。レポジトリのmasterブランチに「dist」フォルダが存在することがわかります。それを、Originにあるgh-pagesブランチへのサブツリーとしてプッシュします。
私も以前にこの問題に遭遇したことがありますが、ここでそれを解決しました。
私が見つけたのは、ローカルマスターブランチに接続されていないブランチがあったことです。このブランチは存在し、そのボイドにぶら下がっています。あなたの場合、おそらく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-shared
のmaster
ブランチにプッシュされます。 。
これは、元のアルゴリズムの制限によるものです。マージコミットを処理するとき、元のアルゴリズムは、無関係な親を切り離すための単純化された基準を使用します。特に、同じツリーを持つ親が存在するかどうかをチェックします。そのような親が見つかった場合、他の親がサブツリーとは無関係の変更を持っていると仮定して、マージコミットを折りたたんで親コミットを代わりに使用します。場合によっては、これにより履歴の一部が削除され、サブツリーに実際の変更が加えられます。特に、コミットのシーケンスをドロップし、サブツリーに接触しますが、同じサブツリー値になります。
これがどのように機能するかをよりよく理解するために、例を簡単に再現できます。次の履歴を考慮してください(行の形式は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
を取り消すため、_z
とC
は同じツリー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
ローカルの変更をリモートのサブツリーリポジトリに強制的にプッシュできます。
git Push subtree_remote_address.git `git subtree split --prefix=subtree_folder`:refs/heads/branch --force
別の[より簡単な]ソリューションは、可能であれば別のコミットを行うことにより、リモートのヘッドを進めることです。この高度なヘッドをローカルサブツリーにプルすると、そこから再びプッシュできるようになります。
この問題もありました。トップの回答に基づいて、私がしたことは次のとおりです。
与えられた:
#! 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」で使用されることに注意してください。
それで、これは@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
Chris Jordanのソリューションに基づいたWindowsユーザー向けの簡単なPowerShell
$id = git subtree split --prefix pythonapp master
Write-Host "Id is: $id"
Invoke-Expression "git Push heroku $id`:master --force"
エリック・ウッドラフの答えは私には役に立たなかったが、以下は助けになった:
私は通常、「git subtree pull」と「--squash」オプションを使用します。これにより物事の調整が難しくなったようですので、今回はつぶすことなくサブツリーをプルし、競合を解決してからプッシュする必要がありました。
私は、押しつぶされたプルが競合を明らかにしなかったと付け加えなければなりません、すべてが大丈夫だと私に言いました。