Archives for February, 2019

Use git reflog to split two squashed commits

published on February 08, 2019.

Today I was using interactive git rebase to squash some commits together to clean up the commit history of a git branch. At one point I went a bit overboard with it and squashed together two commits by mistake.

I’ve heard somewhere from someone that in git you pretty much can’t lose code because everything is in the git reflog. Today I decided to put that to the test.

Spoiler alert: git reflog saved the day.

The setup

We start with two separate commits, “Commit 1” and “Commit 2”:

> git hist
* c3fa1d6 -  (HEAD -> reflog-undo-squash) Commit 2 [Robert Basic 4 seconds ago]
* db73960 -  Commit 1 [Robert Basic 56 seconds ago]

Using git rebase -i HEAD~2 we start the interactive rebase for the last two commits:

pick db73960 Commit 1
f c3fa1d6 Commit 2

We choose to fixup “Commit 2” with “Commit 1”, which means that the second commit will be squashed with the first commit, discarding the commit message of the second commit.

Uh oh, that was a mistake, and our commit history now looks like this:

> git hist
* 786865f -  (HEAD -> reflog-undo-squash) Commit 1 [Robert Basic 5 minutes ago]

Our nice little “Commit 2” is now gone and before we start panicking and making more damage, let’s take a look at the git reflog to see what we have there.

Looking at the reflog

The git reflog right after the bad rebase shows us the following:

> git reflog
786865f (HEAD -> reflog-undo-squash) HEAD@{0}: rebase -i (finish): returning to refs/heads/reflog-undo-squash
786865f (HEAD -> reflog-undo-squash) HEAD@{1}: rebase -i (fixup): Commit 1
0a8f291 HEAD@{2}: rebase -i (pick): Commit 1
684d689 HEAD@{3}: rebase -i (pick): Commit 1
5761a21 HEAD@{4}: rebase -i (start): checkout 5761a21b0c0a1f12ab1c60bfef1f1d111ba699c0
c3fa1d6 HEAD@{5}: commit: Commit 2
db73960 HEAD@{6}: commit (initial): Commit 1

The thing at HEAD@{6} was the first thing that happened and the thing at HEAD@{0} is whatever is going on right now.

What we want the current state to be is the state before we started the rebase process, that is the state at HEAD@{5}. To do that we “reset” our state to that point in time:

> git reset HEAD@{5}

And now our git history is back to it’s pre-rebase state:

> git hist
* c3fa1d6 -  (HEAD -> reflog-undo-squash) Commit 2 [Robert Basic 15 minutes ago]
* db73960 -  Commit 1 [Robert Basic 16 minutes ago]

Note that even the commit shas are back to their pre-rebase values, db73960 and c3fa1d6.

The Atlassian git reflog tutorial goes into more detail, so make sure to read that as well.

Happy hackin’!

Tags: git, reflog, squash, rebase.
Categories: Development, Software.

Vue.js reusable components

published on February 04, 2019.

A while ago I started learning bits and pieces about Vue.js by creating a single page application for one of my pet projects that I use to explore Domain-Driven Design. In general I know my way around a Javascript file, but wouldn’t call myself an expert with it. In the past I mostly used jquery, some mootools, and even Dojo. Ah, good old Zend Framework 1 times.

While reading up on Vue.js I came across the part of their documentation that talks about components and how to make them reusable. At the time I just glanced over it, thought “Neat.” to myself and went on with my day. Yesterday when I was done with creating a page that holds a list of tasks, I remembered that section about reusable components and wondered could I use that to clean up a bit of the code I wrote. Turns out, I can!

A simplified version of my initial Vue.js page was something like this:

./assets/vue/components/Journal.vue

<template>
    <div>
        <template v-if="journal.tasks.length !== 0">
            <div v-for="task in journal.tasks">
                <template v-if="task.status === 'todo'">
                    <button @click="markTaskAsDone(task.id)">
                        Mark as done
                    </button>
                    <span>{{ task.description }}</span>
                </template>
                <template v-if="task.status === 'done'">
                    <strong>{{ task.description }}</strong>
                </template>
            </div>
        </template>
    </div>
</template>

<script>
    export default {
        name: 'journal',
        data: function () {
            return {
                journal: {
                    tasks: [
                        {
                            'id': 1,
                            'description': "Task 1",
                            'status': "todo"
                        },
                        {
                            'id': 2,
                            'description': "Task 2",
                            'status': "done"
                        },
                    ],
                }
            }
        },
        methods: function () {
            markTaskAsDone: function(taskId) {
                alert("Marking task as done, ID: " + taskId);
            }
        }
    }
</script>

We check if there are any tasks in the journal and if so, iterate over them. For todo tasks show a button that we can use to mark that task as done and show the description of the task. For done tasks display the task description bolded.

Now, for the case when the journal has no tasks, I decided I want to show the organizer (an organizer is a person who organizes their tasks in that app) an example list of tasks instead of a blank page with a boring “No tasks” message. I’m also learning to make my designs a tiny bit better, courtesy of the Refactoring UI book.

How did I do that? By copy/pasting a bunch of times the HTML for the todo and done tasks.

./assets/vue/components/Journal.vue

<template>
    <div>
        <template v-if="journal.tasks.length !== 0">
            <div v-for="task in journal.tasks">
                <template v-if="task.status === 'todo'">
                    <button @click="markTaskAsDone(task.id)">
                        Mark as done
                    </button>
                    <span>{{ task.description }}</span>
                </template>
                <template v-if="task.status === 'done'">
                    <strong>{{ task.description }}</strong>
                </template>
            </div>
        </template>
        <template v-else>
            <div>
                <button @click="alert('Marking the task as done')">
                    Mark as done
                </button>
                <span>An example of a todo task</span>
            </div>
            <div>
                <strong>An example of a done task</strong>
            </div>
        </template>
    </div>
</template>

Remember, this is a simplified version of the code. Add to that a bunch of more divs, a bunch of CSS classes as I’m using TailwindCSS and what I had before me was a real nightmare. Almost a hundred lines of HTML.

Enter stage left… Reusable components.

What I did was I created two reusable components, one for a todo task, and one for a done task.

The component for the todo task looks something like this:

./assets/vue/components/Tasks/Todo.vue

<template>
    <div>
        <button @click="">
            Mark as done
        </button>
        <span><slot>An empty task</slot></span>
    </div>
</template>
<script>
    export default {
        name: 'todoTask',
    }
</script>

The <slot> element acts like a kind of a placeholder where Vue.js will insert whatever text we pass on later to that component. There are other ways to pass in data from parent to child components, but in this case, this was simple and enough for me. Note that the @click event handler for the button is empty, as at this time I had no idea what to do with it. The export part in the script tag is how we expose the component to be available for use in other components. I think?

The component for the done task is similar:

./assets/vue/components/Tasks/Done.vue

<template>
    <div>
        <strong><slot>An empty task</slot></strong>
    </div>
</template>
<script>
    export default {
        name: 'doneTask',
    }
</script>

To use these components we need to import them and list them under components within our component where we want to use them:

./assets/vue/components/Journal.vue

<script>
    import TodoTask from "./Tasks/Todo";
    import DoneTask from "./Tasks/Done";
    export default {
        name: 'journal',
        components: {
            TodoTask,
            DoneTask,
        },
        // Shortened the rest of it as nothing changed
    }
</script>

We take the name of the components we imported, turn them kebab-case, and use them as HTML tags. What we put between the opening and closing tags of our component will be inserted into the <slot> tag inside:

./assets/vue/components/Journal.vue

<template>
    <div>
        <template v-if="journal.tasks.length !== 0">
            <div v-for="task in journal.tasks">
                <todo-task v-if="task.status === 'todo'">{{ task.description }}</todo-task>

                <done-task v-if="task.status === 'done'">{{ task.description }}</done-task>
            </div>
        </template>
        <template v-else>
            <todo-task>An example of a todo task</todo-task>

            <done-task>An example of a done task</done-task>
        </template>
    </div>
</template>

Vue.js will make sure that we get the proper HTML rendered in the browser.

Events to the rescue

For a while I didn’t know what to do with the Mark as done button. The original implementation of the markTaskAsDone(taskId) method uses other methods local to the Journal component, so if I’d move that to the TodoTask child component, there’d be a mess on my hand real quick. I’ve tried passing in to the TodoTask a function from the parent component and a couple of other things…

Turns out the solution is quite elegant. On the button within the TodoTask we listen for the click event and trigger our own custom clickedToMarkTaskAsDone event:

./assets/vue/components/Tasks/Todo.vue

<template>
    <div>
        <button @click="clickedToMarkTaskAsDone">
            Mark as done
        </button>
        <span><slot>An empty task</slot></span>
    </div>
</template>
<script>
    export default {
        name: 'todoTask',
        methods: {
            clickedToMarkTaskAsDone: function () {
                this.$emit('clickedToMarkTaskAsDone');
            }
        }
    }
</script>

In the parent component where we use this TodoTask component, we create a handler for our custom event using the existing code we have:

./assets/vue/components/Journal.vue

<todo-task v-if="task.status === 'todo'" @clickedToMarkTaskAsDone="markTaskAsDone(task.id)">
    {{ task.description }}
</todo-task>

Nothing within the markTaskAsDone method changed.

The end result is much more nicer and the line count went down from a hundred to 25 lines. Isn’t that great? I think it’s great.

Happy hackin’!

Versions used for examples: Vue 2.5.
Tags: vue.js, reusable, components, javascript.
Categories: Programming, Development.
Robert Basic

Robert Basic

Software engineer, consultant, open source contributor.

Let's work together!

If you require outsourcing or consulting help on your projects, I'm available!

Robert Basic © 2008 — 2019
Get the feed