Let me provide a slightly watered up supplement of Gratzer's answer.
In the beginning, mathematicians need to study spaces by considering how other spaces cover(*) them. For example, if you have a line and a circle, you can wind up that line around the circle completely. In mathematical terms, you are given $\mathbb R$ and $\mathbb S = \{z\in\mathbb C: |z|=1\}$. You can wind it up with $x\mapsto e^{ix}$. This is good because locally, i.e. in a small area $U$ around each point, this map looks like the projection function $\mathbb Z \times U \xrightarrow{\pi_2}U$.
I'll steal a picture here:
![Covering space](https://cdn.statically.io/img/i.sstatic.net/9pW1A.png)
Note that if you restrict your attention on a small region around one of the black arrows (the space "above" a point in $\mathbb S$), it just looks like $\mathbb Z$ copies of the same thing overlaid on that region.
Now, what's good about it? Generally, we want to study the geometry of the base space $\mathbb S$ by "projecting" down from the total space $\mathbb R$. So we need the covering to be relatively well-behaved. For instance, when we are studying paths, we may want to require the property that, no matter how I walk along the base space, you can follow along in the total space, while keeping yourself strictly above me. As an example (lots of examples!), if I start at $\color{blue}1$, and you start at $\color{red}{-1}$; when I go counterclockwise along $\color{blue}{1 \to i \to -1 \to 1}$, you must follow along. And you can: $\color{red}{-1\to-\frac34\to-\frac12\to0}$.
Actually, a notion that came earlier is fiber bundles, which puts a stricter requirement: If you look at a small enough region, then the whole thing just looks like $F \times B \to B$. This is slightly easier to work with, but it is too restrictive in our use cases.
To formalize the notion of fibration, we can use a continuous function $[0,1]\to B$ to represent a path in $B$. Also, we have a point $*\xrightarrow0 [0, 1]$. (Using an arrow from a singleton space to another space is a common category speak to "pinpoint" a point in space; Here we want to get the point $0$. Also, I use $*$ instead of the categorical $1$, because it clashes with the real number $1$ here.) We start with a path $q:[0, 1]\to B$, and a "covering" $p:E\to B$ (our picture above is a covering $\mathbb R \to \mathbb S$). We also specify our starting point in $E$ with an arrow $*\to E$. This starting point must lie above our starting point of the path $q$ in the base space. So it can be written in a commutative diagram:
$$
\begin{matrix}
*&\to&E\\
\downarrow & & \downarrow\\
[0, 1]&\color{blue}{\xrightarrow q} & B
\end{matrix}
$$
By saying that "you can follow along the path $q$ in $E$", we really mean that you can lift the path into $\hat q : [0, 1]\to E$, and the commutativity of the diagram ensures that this lifted path lies "above" the original one. So:
$$
\begin{matrix}
*&\to&E\\
\downarrow &\color{red}{\nearrow} & \downarrow\\
[0, 1]& \color{blue}{\to}& B
\end{matrix}
$$
In this case, we say that the arrow $p$ lifts against the arrow $*\xrightarrow 0 [0,1]$. But of course, we may
wish to use other arrows than $0$. So in general, if $p$ lifts against a certain set of arrows, we call $p$ a fibration.
On the other hand, we can consider the dual notion. Since fibrations are really good coverings, by reversing the arrows, we get that cofibrations are really good inclusions.
We invert our diagram:
$$
\begin{matrix}
Y&\leftarrow&B\\
\uparrow &\color{red}{\swarrow} & \uparrow\\
X& \color{blue}{\leftarrow}& A
\end{matrix}
$$
Here $X \to Y$ is some other given arrow which we want to "colift" against. This is called an extension property.
The archetypical example is when $X \to Y$ is $S^{[0,1]} \xrightarrow {p_0} S$, which maps each path in the space of paths in $S$ to its starting point. Suppose $A = *$, and $* \to B$ is a point of $B$, then the commutative square gives
$$
\begin{matrix}
S&\leftarrow&B\\
\uparrow &\color{red}{\swarrow} & \uparrow\\
S^{[0,1]}& \color{blue}{\leftarrow}& *
\end{matrix}
$$
- A map $\color{blue}{H : * \to S^{[0,1]}}$, which is equivalent to a path $\color{blue}{[0,1] \to S}$.
- A map $B \to S$, mapping $B$ inside $S$.
The extension property gives the diagonal arrow $\color{red}{B \to S^{[0,1]}} \cong B \times [0,1] \to S$, which describes how $B$ "moves" continuously in $S$. $\color{blue}H$ gives the trajectory of a single point of $B$. So the extension property roughly says that, whenever you have the starting position of $B$, and describe how a single point moves inside $S$, then you can always "drag $B$ along that trajectory". Another way to put it is you can always extend the orbit of the point to the orbit of the whole of $B$.
Of course, extension of a point sounds trivial. But we can immediately create another example: If you replace $A = *$ with $A = 2$, the space with two points, then the extension property says that given the trajectory of two points, you can always extend the trajectory to the whole of $B$.
This is very useful in type theory. Suppose you have proved three equalities:
$$
\begin{matrix}
a&&d\\
\|& & \|\\
b& =& c
\end{matrix}
$$
In cubical type theory, this is represented as three paths, similar to $[0,1] \to X$. To compose them, you invoke a version of the extension property: Let $B$ be the path $b=c$, and you have the trajectory of the two endpoints $b$ and $c$: they move to $a$ and $d$, respectively. Now "dragging $B$ along", you will end up with a path $a = d$. This is how path composition is proved (**).
(*): Covering spaces is a related term, but I don't want to talk too much about that. I'm using this word to represent intuition.
(**): In some flavors of CuTT, at least. There are type theories that try to achieve this with different methods.