Поєднання декількох комісій в один перед натисканням


130

Це питання стосується не лише того, як виконати це завдання, але й того, чи є це хорошою чи поганою практикою роботи з Git.

Вважайте, що локально я найбільше працюю на головній гілці, але я створив тематичну гілку, яку я називатиму "topical_xFeature". У процесі роботи над "topical_xFeature" і переключення вперед і назад, щоб виконувати інші роботи на головній гілці, виявляється, що я зробив більше одного комітету на гілці "topical_xFeature", але між кожним комітом я не робив жодного поштовх.

По-перше , чи вважаєте ви цю погану практику? Чи не було б розумніше дотримуватися однієї комісії на одну гілку за натиск? У яких випадках було б добре мати кілька філій на гілці перед тим, як здійснити поштовх?

По-друге , як мені найкраще виконати приведення декількох комірок на гілці topical_xFeature у головну гілку для натискання? Неприємно не турбуватися про це і просто робити натискання там, де декілька комірок натискають, або менш прикро, щоб якось об'єднати комісії в одну, а потім натиснути? Знову ж, як це зробити?

Відповіді:


139

У вашому першому запитанні - ні, немає нічого поганого в тому, щоб натиснути кілька комісій одночасно. Багато разів, можливо, ви захочете розбити свою роботу на кілька невеликих логічних завдань, але підштовхуйте їх лише після того, як відчуєте, що вся серія готова. Або ви можете зробити кілька комісій локально під час відключення, і ви натискаєте їх усі, коли ви знову підключитесь. Немає жодних причин обмежувати себе однією фіксацією за поштовх.

Я, як правило, вважаю, що корисно тримати кожне введення єдиної, логічної, цілісної зміни, яка включає все, що потрібно для роботи (так, він не залишає ваш код у порушеному стані). Якщо у вас є два коміти, але вони можуть призвести до порушення коду, якщо ви застосували лише перший, може бути хорошою ідеєю розбити другий коміт на перший. Але якщо у вас є два коміти, де кожен з них робить розумні зміни, натискання на них як окремі коміти - це добре.

Якщо ви хочете зібрати кілька комірок разом, можете скористатися git rebase -i. Якщо ти на гілці topical_xFeature, ти біжиш git rebase -i master. Це відкриє вікно редактора, з купою комітетів, перелічених префіксом pick. Ви можете змінити всі, крім перших squash, що скаже Git зберегти всі ці зміни, але приєднайте їх до першого виконання. Після цього перегляньте masterта об’єднайтеся у своїй функції:

git checkout topical_xFeature
git rebase -i master
git checkout master
git merge topical_xFeature

З іншого боку , якщо ви просто хочете , щоб сквош все в topical_xFeatureв master, ви можете просто зробити наступне:

git checkout master
git merge --squash topical_xFeature
git commit

Кого вибрати, залежить від вас. Як правило, я б не турбувався про наявність декількох менших комітетів, але іноді ви не хочете турбуватися із зайвими незначними комісіями, тому просто розбийте їх на один.


1
Після злиття з --squash я не можу видалити гілку теми git branch -d topic. Чому git не в змозі визначити, що всі зміни об'єднані?
балки

7
@balki Оскільки Git визначає, чи об'єднуються патчі на основі того, чи є вони в історії даної гілки. Сквошинг здійснює зміни їх; вони стають новою фіксацією, і хоча ця нова комісія робить те саме, що й інші, Git не може цього сказати, він може визначити, чи є комітети однаковими, якщо вони мають однаковий ідентифікатор комісії (SHA-1) . Отож, як тільки ви його сквош, вам потрібно сказати git видалити стару гілку, git branch -D topicщоб примусово її видалити.
Брайан Кемпбелл

66

Це, як правило, я дотримуюся комбінування декількох комітетів в одну команду, перш ніж натиснути код.

Для цього я пропоную використовувати концепцію " сквош ", яку надає GIT.

Виконайте наведені нижче дії.

1) git rebase -i master (замість master ви також можете використовувати певну комісію)

відкрийте інтерактивний редактор Rebase, де він покаже всі ваші зобов'язання. В основному там, де вам потрібно визначити комітети, які ви хочете об'єднати в одну комісію.

Уявіть, що це ваші зобов'язання, і щось подібне показали в редакторі.

pick f7f3f6d changed my name a bit    
pick 310154e updated README formatting and added blame   
pick a5f4a0d added cat-file  

Важливо зазначити, що ці комісії перераховані в протилежному порядку, ніж ви зазвичай бачите за допомогою команди журналу. Значить, спочатку відображатиметься старша комісія.

2) Змініть "вибір" на "сквош" для останніх здійснених змін. щось, як показано нижче. У цьому випадку ваші останні 2 комітації будуть об'єднані з першим.

pick f7f3f6d changed my name a bit         
squash 310154e updated README formatting and added blame   
squash a5f4a0d added cat-file

Ви також можете скористатися короткою формою, якщо у вас є багато комісій для комбінування:

p f7f3f6d changed my name a bit         
s 310154e updated README formatting and added blame   
s a5f4a0d added cat-file

для редагування використовуйте "i", це дозволить редактору вставити. Майте на увазі, що більшість (найстаріших) комітетів не можуть бути скороченими, оскільки немає попередніх зобов’язань, з якими слід поєднуватись. Тож його треба вибирати або «р». Використовуйте "Esc" для виходу з режиму вставки.

3) Тепер збережіть редактор за допомогою наступної команди. : wq

Коли ви зберігаєте це, у вас є одна фіксація, яка вносить зміни всіх трьох попередніх комітетів.

Сподіваюся, що це вам допоможе.


5
Можливо, це очевидно для інших, але, коли ви говорите "git rebase -i", вам також потрібно вказати, з якого комітету ви починаєте. Це те, чого я не усвідомлював, намагаючись наслідувати цей приклад. Отже, у цьому прикладі це буде "git rebase -i xxxxx", де xxxxx - це фіксація прямо перед f7f3f6d, хронологічно. Як тільки я зрозумів це, все вийшло точно так, як описано вище.
nukeguy

Це цікаво @nukeguy, у мене не було жодної проблеми, яка б не вказувала конкретний комітет. Це було дефолтом до того, що там було.
JCrooks

Можливо, як @nukeguy, git rebase -i HEAD~2було для мене корисним місцем для початку. Тоді ця відповідь була корисною. Тоді, мій git statusпоказав, що "Ваша гілка та" походження / особливість / xyz "розійшлися та мають 1 та 1 різних доручень відповідно." Тому мені потрібно було git push origin feature/xyz --force-with-leaseпобачити stackoverflow.com/a/59309553/470749 та freecodecamp.org/forum/t/…
Райан

11

По-перше : нічого не говорить про те, що ви маєте лише одну фіксацію за кожну гілку за один натиск: push - це механізм публікації, що дозволяє публікувати локальну історію (тобто колекцію комітетів) на віддаленому репо-репо.

По-друге : a git merge --no-ff topical_xFeatureзаписує на майстер як єдиний фіксатор твоєї теми, перш ніж натискати master.
(Таким чином, ви продовжуєте topical_xFeatureподальші еволюції, на яких ви можете записатись masterяк єдине нове фіксація при наступному злитті - no-ff.
Якщо позбутися topical_xFeature- це мета, то git merge --squashце правильний варіант, докладно описаний у Брайані Кемпбеллі «S відповідь .)


Я думаю, що це --squashне --no-ffте, чого ти хочеш. --no-ffстворив би об'єднання для злиття, але також залишив би всі коміти topical_xFeature.
Брайан Кемпбелл

@Brian: Я погоджуюся і схвалюю вашу відповідь, але спершу я подумав про варіант --no-ff, тому що хотів утримати topical_featureгілку навколо, і просто записати одну фіксацію на masterгілці.
VonC

8

Перейдіть на головну гілку та переконайтесь, що ви в курсі.

git checkout master

git fetch це може знадобитися (залежно від конфігурації git), щоб отримувати оновлення щодо origin / master

git pull

Об’єднайте гілку функції у головну гілку.

git merge feature_branch

Скиньте основну гілку до стану походження.

git reset origin/master

Тепер Git розглядає всі зміни як незмінені зміни. Ми можемо додати ці зміни як одну фіксацію. Додавання. також додасть файли без відстеження.

git add --all

git commit

Посилання: https://makandracards.com/makandra/527-squash-several-git-commits-into-a-single-commit


3
цю відповідь легко прослідкувати і насправді легко уявити.
jokab

6
  1. Спершу вибирайте, яке зобов’язання ви хочете, щоб все було після.

    git reflog
    5976f2b HEAD@{0}: commit: Fix conflicts
    80e85a1 HEAD@{1}: commit: Add feature
    b860ddb HEAD@{2}: commit: Add something
    
  2. Скинути вибрану голову (я вибрав HEAD@{2})

    git reset b860ddb --soft
    
  3. git status (просто щоб бути впевненим)

  4. Додайте нову комісію

    git commit -m "Add new commit"
    

Примітка: HEAD@{0}& HEAD@{1}тепер об'єднані в 1 коміт, це також можна зробити для кількох комітетів.

git reflog знову має відображатися:

git reflog
5976f2b HEAD@{0}: commit: Add new commit
b860ddb HEAD@{1}: commit: Add something

0

Інструмент для автоматизації декількох комісій в один

як каже Кондал Коліпака . Використання "git rebase -i"

Логіка "git rebase"

Під час використання "git rebase -i" git генерує файл git-rebase-todo у поточному каталозі .git / rebase-merge, а потім викликає редактор git, щоб користувачі могли редагувати файл git-rebase-todo для обробки. Отже, інструмент повинен відповідати:

  1. Змініть редактор git до того інструменту, який ми надали;
  2. Інструмент обробляє файл git-rebase-todo.

Змініть редактор git за замовчуванням

git config core.editor #show current default git editor
git config --local --replace-all  core.editor NEW_EDITOR # set the local branch using NEW_EDITOR as git editor

Отже, інструменту потрібно змінити редактор git та обробити файл git-rebase-todo. Інструмент із використанням пітона нижче:

#!/usr/bin/env python3
#encoding: UTF-8

import os
import sys

def change_editor(current_file):
    os.system("git config --local --replace-all  core.editor " + current_file) # Set current_file as git editor
    os.system("git rebase -i") # execute the "git rebase -i" and will invoke the python file later with git-rebase-todo file as argument
    os.system("git config --local --replace-all core.editor vim") # after work reset the git editor to default

def rebase_commits(todo_file):
    with open(todo_file, "r+") as f:
        contents = f.read() # read git-rebase-todo's content
        contents = contents.split("\n")
        first_commit = True
        f.truncate()
        f.seek(0)
        for content in contents:
            if content.startswith("pick"):
                if first_commit:
                    first_commit = False
                else:
                    content = content.replace("pick", "squash") # replace the pick to squash except for the first pick
            f.write(content + "\n")

def main(args):
    if len(args) == 2:
        rebase_commits(args[1]) # process the git-rebase-todo
    else:
        change_editor(os.path.abspath(args[0])) # set git editor

if __name__ == "__main__":
    main(sys.argv)

Посилання: https://liwugang.github.io/2019/12/30/git_commits_en.html


4
Будь ласка, зменшіть рекламу вашого веб-сайту. Дивіться також Як не бути спамером.
трійка
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.