Има ли начин да се премахнат редица ангажименти неинтерактивно?

Опитвам се да смачкам набор от ангажименти - HEAD към HEAD~3. Има ли бърз начин да направя това или трябва да използвам rebase --interactive?


person Phillip    schedule 01.09.2011    source източник
comment
Подобен въпрос: stackoverflow.com/questions/5189560/   -  person koppor    schedule 14.07.2012


Отговори (8)


Тогава се уверете, че вашето работно дърво е чисто

git reset --soft HEAD~3
git commit -m 'new commit message'
person wilhelmtell    schedule 01.09.2011
comment
@wilhelmtell: Страхотно! Сега ще мога ли да създам git псевдоним, напр. mysquash 3 "някое съобщение", за да съкратя това до един ред? - person Phillip; 01.09.2011
comment
Ако е само броят редове: git reset --soft HEAD~3 && git commit -m "my message" - person KingCrunch; 02.09.2011
comment
@Phillip: Можете да вградите функция на обвивката в псевдонима на git. git config alias.mysquash '!f(){ git reset --soft HEAD~$1 && git commit ${2:+-m "$2"}; };f'. git mysquash 3 'some message' ще работи, но аз също го промених, така че git musquash 3 ще пропусне изцяло флага -m, така че ще получите интерактивния git commit UI в този случай. - person Lily Ballard; 02.09.2011
comment
@KevinBallard, само за пояснение, мисля, че под mu имате предвид my. - person Acumenus; 22.04.2014
comment
Как да автоматизирам HEAD~3, за да отрази последния изпратен ангажимент? Не искам да пиша 3 и т.н. - person Acumenus; 22.04.2014
comment
Намерих за по-разбираемо да използвам SHA хеша на ангажимента, към който исках да смачкам вместо HEAD~3 - person JuJoDi; 14.05.2014
comment
този отговор води до ! [отхвърлен] главен -› главен (не-бързо напред) грешка... - person sebnukem; 19.03.2015
comment
Само за да стане ясно: не е същото като скуош. Скуош също ще обедини съобщенията за ангажиране. Ако направите меко нулиране, ще загубите всички съобщения от ангажиментите. Ако искате да играете скуош, опитайте stackoverflow.com/a/27697274/974186 - person René Link; 03.08.2015
comment
@sebnukem - Това е, когато се опитваме да натиснем клона и дистанционното е конфигурирано да отхвърля натискания на сила. - person avmohan; 17.02.2016
comment
ако това са ангажименти за сливане, това ще загуби всякаква представа за родители, нали? - person George Mauer; 02.08.2019

Аз лично харесвам решението на wilhelmtell:

git reset --soft HEAD~3
git commit -m 'new commit message'

Направих обаче псевдоним с известна проверка на грешки, за да можете да направите това:

git squash 3 'my commit message'

Препоръчвам да настроите псевдоними, които действително изпълняват скриптове, така че да е по-лесно (а) да кодирате вашите скриптове и (б) да извършвате по-сложна работа с проверка на грешки. По-долу е скрипт, който върши работата на скуош, а отдолу е скрипт за настройка на вашите git псевдоними.

Скрипт за смачкване (squash.sh)

#!/bin/bash
#

#get number of commits to squash
squashCount=$1

#get the commit message
shift
commitMsg=$@

#regular expression to verify that squash number is an integer
regex='^[0-9]+$'

echo "---------------------------------"
echo "Will squash $squashCount commits"
echo "Commit message will be '$commitMsg'"

echo "...validating input"
if ! [[ $squashCount =~ $regex ]]
then
    echo "Squash count must be an integer."
elif [ -z "$commitMsg" ]
then
    echo "Invalid commit message.  Make sure string is not empty"
else
    echo "...input looks good"
    echo "...proceeding to squash"
    git reset --soft HEAD~$squashCount
    git commit -m "$commitMsg"
    echo "...done"
fi

echo
exit 0

След това, за да свържете този squash.sh скрипт към git псевдоним, направете друг скрипт за настройка на вашите git псевдоними по този начин (create_aliases.command или create_aliases.sh ):

#!/bin/sh
echo '-----------------------'
echo 'adding git aliases....'
echo '-----------------------'
echo
git config --global alias.squash "!bash -c 'bash <path to scripts directory>/squash.sh \$1 \$2' -"
#add your other git aliases setup here
#and here
#etc.
echo '------------------------------------'
echo 'here is your global gitconfig file:'
echo '------------------------------------'
more ~/.gitconfig
echo 
echo
echo '----------------'
echo 'end of script...'
echo '----------------'
person n8tr    schedule 03.06.2014
comment
Можете също да го поставите в $PATH с име git-squash.sh и той автоматично ще бъде псевдоним като git squash. Не промених отговора ви, само в случай, че има причина да използвам скрипта create-aiases.sh, за която не знам. - person ; 12.06.2014
comment
По принцип използвам скрипта create_aliases.command, така че дори нашите PM и дизайнери да могат лесно да се настроят. Просто щракнете двукратно върху скрипта и всички са настроени (особено след като имам скрипта за настройка в нашето репо и относителният път е известен). Тогава дори не е необходимо да рестартират терминала. - person n8tr; 13.06.2014
comment
Опитах това и то чете съобщението ми за ангажиране като брой на скуош и се проваля, защото не е цяло число. - person Minthos; 12.08.2014
comment
Решението беше да се добави - след /squash.sh \$1 \$2' - person Minthos; 12.08.2014
comment
Minthos Да и това вече е в решението по-горе – вижте този ред: git config --global alias.squash !sh -c 'sh ‹път към директория със скриптове›/squash.sh \$1 \$2' - person n8tr; 12.08.2014
comment
Харесва ми идеята за решението, но коментарът по-горе все още не е взет предвид в решението. Между единичните и двойните кавички трябва да има знак минус. - person physicalattraction; 27.10.2015
comment
Ако предишните ангажименти вече са били натиснати, трябва ли да натисна насила създадения комит тук? - person physicalattraction; 27.10.2015
comment
Благодаря, physicalattraction актуализира, че има -. Също така, да, ще трябва да принудите натискането, ако вече сте натиснали предишните несмачкани комити. Препоръчвам да принудите push само към вашите собствени клонове, а не да правите това към главен клон. - person n8tr; 27.10.2015

За да добавя към отговора от wilhelmtell намирам за удобно да нулирам меко до HEAD~2 и след това да променя ангажимента на HEAD~3:

git reset --soft HEAD~2
git commit --all --amend --no-edit    

Това ще обедини всички ангажименти към ангажимента HEAD~3 и ще използва неговото съобщение за ангажимент. Не забравяйте да започнете от чисто работещо дърво.

person harmonious    schedule 20.08.2017
comment
Това е правилният отговор, защото той смачква поредица от ангажименти, водещи до head, и използва съобщението на първия комит. Той е неинтерактивен. - person Landon Kuhn; 29.09.2017
comment
В този сценарий смятам, че параметърът --all в git commit е ненужен, тъй като модифицираните файлове вече са поставени след меко нулиране. Документ за git commit --all - person li ki; 17.06.2021

Използвах:

EDITOR="sed -i '2,/^$/s/^pick\b/s/'" git rebase -i <ref>

Работи доста добре. Просто не се опитвайте да имате дневник на комити с ред, който започва с "pick" :)

person Julien Wajsberg    schedule 20.09.2013
comment
За съжаление това не работи за мен в Windows. Все пак вземете интерактивния редактор. - person abergmeier; 12.11.2014

Използвайте следната команда, за да смачкате последните 4 комита в рамките на последния комит:

git squash 4

С псевдоним:

squash = !"f() { NL=$1; GIT_EDITOR=\"sed -i '2,$NL s/pick/squash/;/# This is the 2nd commit message:/,$ {d}'\"; git rebase -i HEAD~$NL; }; f"
sq = !git squash $1
sqpsf = !git squash $1 && git psf 

От https://github.com/brauliobo/gitconfig/blob/master/configs/.gitconfig

person brauliobo    schedule 01.03.2015
comment
Не сте посочили каква ОС/обвивка се използва тук. Това решение вероятно няма да работи за всички други настолни компютри, които хората използват. - person Rick-777; 11.03.2016
comment
да, трябва да използвате linux/bash|zsh за това - person brauliobo; 12.03.2016

Ето един ред, за да смачкате последните 2 комита. В този пример съобщението за предпоследния ангажимент ще бъде запазено. Можете да промените съобщението, както желаете.

git commit -am "$(git log -1 --skip=1 --pretty=%B | xargs && git reset --soft HEAD~2)"

Тази команда ще бъде много полезна, ако създадете псевдоним за тази команда и използвате псевдонима вместо това.

person Jasir    schedule 28.06.2017

За да смачкате всичко, откакто клонът беше раздвоен от master:

git reset --soft $(git merge-base --fork-point master) \
  && git commit --verbose --reedit-message=HEAD --reset-author
person Andy    schedule 12.02.2018
comment
--reedit-message=HEAD ще използва съобщението от последния комит, който не е част от смачкването. Това вероятно не е това, което искате. За да получите по-скоро съобщението на първия ангажимент, който да бъде включен, или (1) заменете HEAD с хеша на ангажимента, за който искате съобщението, или ( 2) преминете към първия ангажимент за включване и git commit --amend --reedit-message=HEAD. Ето какво прави хармоничният отговор. - person Maëlan; 09.11.2018

Можете да се сближите доста с

git rebase --onto HEAD~4 HEAD~ master

Това предполага, че сте на master с линейна история. Това не е съвсем скуош, защото отхвърля междинните ангажименти. Ще трябва да промените новата HEAD, за да промените съобщението за ангажиране.

person Greg Bacon    schedule 01.09.2011
comment
Благодаря Грег; под „изхвърляне“ имате предвид, че тези междинни ангажименти подлежат на почистване от git gc? - person Phillip; 02.09.2011
comment
@Phillip Да, междинните ангажименти стават боклук, както и старият HEAD, защото е пренаписан, за да има HEAD~4 като родител. - person Greg Bacon; 06.09.2011