2009-03-02 2 views
123

Предположим, у меня есть 5 местных коммитов. Я хочу нажать только 2 из них на централизованное репо (используя рабочий процесс в стиле SVN). Как мне это сделать?Как вы нажимаете только некоторые из ваших местных git-коммитов?

Это не сработало:

git checkout HEAD~3 #set head to three commits ago 
git push #attempt push from that head 

Это заканчивает толкая все 5 местных коммиты.

Я полагаю, что я мог бы выполнить сброс git, чтобы фактически отменить мои коммиты, а затем git stash, а затем git push - но у меня уже есть записанные сообщения и файлы, и я не хочу их переделывать.

Мое ощущение, что какой-то флаг, переданный для нажатия или сброса, будет работать.

Если это помогает, вот мой мерзавец конфигурации

[ramanujan:~/myrepo/.git]$cat config 
[core] 
     repositoryformatversion = 0 
     filemode = true 
     bare = false 
     logallrefupdates = true 
[remote "origin"] 
     url = ssh://server/git/myrepo.git 
     fetch = +refs/heads/*:refs/remotes/origin/* 
[branch "master"] 
     remote = origin 
     merge = refs/heads/master 

ответ

153

Предполагая, что ваши коммиты находятся на главной ветви, и вы хотите, чтобы подтолкнуть их к удаленному мастер филиала:

$ git push origin master~3:master 

Если вы используете ГИТ-SVN:

$ git svn dcommit master~3 

В случае git-svn, вы также можете использовать HEAD ~ 3, так как он ожидает фиксации. В случае прямого git вам нужно использовать имя ветви, потому что HEAD не оценивается должным образом в refspec.

Вы также мог бы принять более длительный подход:

$ git checkout -b tocommit HEAD~3 
$ git push origin tocommit:master 

Если вы делаете привычку такого рода работу потока, вы должны рассмотреть возможность сделать вашу работу в отдельной ветке. Тогда вы можете сделать что-то вроде:

$ git checkout master 
$ git merge working~3 
$ git push origin master:master 

Обратите внимание, что часть «оригинал: мастер», вероятно, является необязательной для вашей установки.

+10

Примечание: вам не нужно использовать 'master ~ 3'. Любая ссылка на требуемую «до» фиксацию одинаково действительна, например «HEAD ~ 3» или «HEAD» ~~~ ', или конкретная SHA, или тег, который присваивает метки. – Kaz

+1

Хороший материал. Предупреждение: эти примеры нажимают на главный хозяин. Если вы копируете и вставляете это решение, вы можете случайно обновить основную ветвь. (Конечно, вы всегда должны быть осторожны и дважды проверять свою команду перед выдачей 'git push' ...) – nofinator

+0

Похоже, что это подталкивает фиксацию, но не добавляет ветку удаленно. – Nateowami

15

Что я делаю, это работа на местном отделении под названием «работа». Эта ветка содержит все временные коммиты (например, обходные пути или частные варианты сборки или что-то еще), которые я не намерен использовать для восходящего репозитория. Я работаю на этой ветке, а затем, когда я хочу совершить переход на главную ветку, вишня-выберите соответствующие коммиты, которые я хочу сделать, а затем нажмите мастер.

После извлечения изменений из верхней части моей основной ветки I git checkout work и git rebase master. Это переписывает все мои локальные изменения в конце истории.

Я фактически использую git svn с этим документооборотом, поэтому моя операция «push» включает в себя git svn dcommit. Я также использую tig, который является хорошим средством просмотра репозитория в режиме текстового режима, чтобы вишневый выбор соответствующих коммитов для освоения.

+0

с git svn dcommit, вы можете указать фиксацию для dcommit до, поэтому желаемый эффект довольно тривиален с git-svn. –

+0

Есть недостатки в этом подходе (см. Здесь http://stackoverflow.com/a/881014/1116674). Хорошей альтернативой является создание филиалов для каждой функции, над которой вы работаете, и ветвь 'work'. Затем вы объединяете определенные ветви в 'master', чтобы не потерять историю на них. При работе с 'work' вы объединяете в нее все свои ветви. Это больше накладных расходов, но в некоторых случаях это может стоить. – Hudon

11

По умолчанию git-push толкает все ветви. Когда вы сделаете это:

git checkout HEAD~3 #set head to three commits ago 
git push #attempt push from that head 

Вы двигаетесь в отдельных HEAD (вы не в любой отрасли), а затем вы нажимаете все ветви, в том числе местного мастера (который до сих пор, где это было) на пульте дистанционного управления мастер.

Руководство решение: (! И опасно)

git push origin HEAD:master 

Если вы нашли поведение по умолчанию толкая все ветви запутанным, добавьте в ваш ~/.gitconfig:

[remote.origin] 
    push = HEAD 

Тогда нажата только ветка, на которой вы находитесь. В вашем примере (отдельностоящие головы), вы бы получили это сообщение об ошибке, а не случайно толкая неправильные фиксации:

error: unable to push to unqualified destination: HEAD 
4

1) Используйте «GIT перебазироваться», чтобы изменить порядок коммитов, если вы хотите.

git rebase -i 

Эта команда покажет что-то вроде этого в редакторе (я использую Vim)

pick 4791291 commitA 
pick a2bdfbd commitB 
pick c3d4961 commitC 
pick aa1cefc commitD 
pick 9781434 commitE 

# Rebase .............. 
# 
# Commands: 
# p, pick = use commit 
# r, reword = use commit, but edit the commit message 
# e, edit = use commit, but stop for amending 
# s, squash = use commit, but meld into previous commit 
# f, fixup = like "squash", but discard this commit's log message 
# x, exec = run command (the rest of the line) using shell 
# 
# These lines can be re-ordered; they are executed from top to bottom. 
# 
# If you remove a line here THAT COMMIT WILL BE LOST. 
# 
# However, if you remove everything, the rebase will be aborted. 
# 
# Note that empty commits are commented out 




^G Get Help   ^O WriteOut   ^R Read File  ^Y Prev Page    ^K Cut Text   ^C Cur Pos 
^X Exit    ^J Justify   ^W Where Is   ^V Next Page   ^U UnCut Text  ^T To Spell 

2) Изменение порядка ваши коммиты по вашему выбору с помощью простого вырезать пасты. Предположим, что новый порядок

выбрать 9781434 commitE

выбор c3d4961 commitC

выбрать 4791291 commitA

выбор aa1cefc commitD

выбор a2bdfbd commitB

сделать эти изменения в редакторе и нажмите ctrl + O (writeOut)

Или вы можете также использовать

git rebase -i HEAD~<commitNumber> 

Вы можете проверить новую последовательность с

git log 

3) Теперь используйте

git push <remoteName> <commit SHA>:<remoteBranchName> 

Если только одна ветвь на пульте дистанционного управления (происхождения) и один на местном (магистральном), просто используйте

git push <commit SHA> 
git push aa1cefc 

Это приведет к фиксации commitB и commitD.

3

Короткий ответ:

git push <latest commit SHA1 until you want commits to be pushed>

Примеры:

git push fc47b2

git push HEAD~2

Длинный ответ:

Фиксации связаны друг с другом как цепочка с родительским/дочерним механизмом.Таким образом, нажатие фиксации фактически также толкает , все родители совершают, чтобы зафиксировать это, если неизвестно удаленному. Это неявно делается, когда вы git push текущей фиксации: все предыдущие коммиты также нажаты, потому что эта команда эквивалентна git push HEAD.

Таким образом, вопрос может быть переписан в . Как нажать конкретную фиксацию, и эта конкретная фиксация может быть, например, HEAD ~ 2.

Если фиксации, которые вы хотите нажать, не являются последовательными, просто переупорядочите их с помощью git rebase -i до конкретного нажатия.

Смежные вопросы