diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 329b7ab7..6f10848a 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -1911,7 +1911,7 @@ fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Dir
     let register = cx.register.unwrap_or('/');
     let config = cx.editor.config();
     let scrolloff = config.scrolloff;
-    if let Some(query) = cx.editor.registers.last(register, cx.editor) {
+    if let Some(query) = cx.editor.registers.first(register, cx.editor) {
         let doc = doc!(cx.editor);
         let contents = doc.text().slice(..).to_string();
         let search_config = &config.search;
@@ -1983,7 +1983,7 @@ fn search_selection(cx: &mut Context) {
 
 fn make_search_word_bounded(cx: &mut Context) {
     let register = cx.register.unwrap_or('/');
-    let regex = match cx.editor.registers.last(register, cx.editor) {
+    let regex = match cx.editor.registers.first(register, cx.editor) {
         Some(regex) => regex,
         None => return,
     };
diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs
index 8dc2906a..702a6e67 100644
--- a/helix-term/src/ui/prompt.rs
+++ b/helix-term/src/ui/prompt.rs
@@ -307,7 +307,7 @@ impl Prompt {
     ) {
         (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
         let mut values = match cx.editor.registers.read(register, cx.editor) {
-            Some(values) if values.len() > 0 => values,
+            Some(values) if values.len() > 0 => values.rev(),
             _ => return,
         };
 
@@ -473,7 +473,7 @@ impl Prompt {
             // Show the most recently entered value as a suggestion.
             if let Some(suggestion) = self
                 .history_register
-                .and_then(|reg| cx.editor.registers.last(reg, cx.editor))
+                .and_then(|reg| cx.editor.registers.first(reg, cx.editor))
             {
                 surface.set_string(line_area.x, line_area.y, suggestion, suggestion_color);
             }
@@ -570,7 +570,7 @@ impl Component for Prompt {
                 } else {
                     let last_item = self
                         .history_register
-                        .and_then(|reg| cx.editor.registers.last(reg, cx.editor))
+                        .and_then(|reg| cx.editor.registers.first(reg, cx.editor))
                         .map(|entry| entry.to_string())
                         .unwrap_or_else(|| String::from(""));
 
diff --git a/helix-view/src/register.rs b/helix-view/src/register.rs
index e82051dd..61912378 100644
--- a/helix-view/src/register.rs
+++ b/helix-view/src/register.rs
@@ -23,6 +23,10 @@ use crate::{
 /// * Primary clipboard (`+`)
 #[derive(Debug)]
 pub struct Registers {
+    /// The mapping of register to values.
+    /// Values are stored in reverse order when inserted with `Registers::write`.
+    /// The order is reversed again in `Registers::read`. This allows us to
+    /// efficiently prepend new values in `Registers::push`.
     inner: HashMap<char, Vec<String>>,
     clipboard_provider: Box<dyn ClipboardProvider>,
 }
@@ -77,11 +81,11 @@ impl Registers {
             _ => self
                 .inner
                 .get(&name)
-                .map(|values| RegisterValues::new(values.iter().map(Cow::from))),
+                .map(|values| RegisterValues::new(values.iter().map(Cow::from).rev())),
         }
     }
 
-    pub fn write(&mut self, name: char, values: Vec<String>) -> Result<()> {
+    pub fn write(&mut self, name: char, mut values: Vec<String>) -> Result<()> {
         match name {
             '_' => Ok(()),
             '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support writing")),
@@ -94,17 +98,19 @@ impl Registers {
                         _ => unreachable!(),
                     },
                 )?;
+                values.reverse();
                 self.inner.insert(name, values);
                 Ok(())
             }
             _ => {
+                values.reverse();
                 self.inner.insert(name, values);
                 Ok(())
             }
         }
     }
 
-    pub fn push(&mut self, name: char, value: String) -> Result<()> {
+    pub fn push(&mut self, name: char, mut value: String) -> Result<()> {
         match name {
             '_' => Ok(()),
             '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support pushing")),
@@ -121,11 +127,13 @@ impl Registers {
                     anyhow::bail!("Failed to push to register {name}: clipboard does not match register contents");
                 }
 
-                saved_values.push(value);
-                self.clipboard_provider.set_contents(
-                    saved_values.join(NATIVE_LINE_ENDING.as_str()),
-                    clipboard_type,
-                )?;
+                saved_values.push(value.clone());
+                if !contents.is_empty() {
+                    value.push_str(NATIVE_LINE_ENDING.as_str());
+                }
+                value.push_str(&contents);
+                self.clipboard_provider
+                    .set_contents(value, clipboard_type)?;
 
                 Ok(())
             }
@@ -150,7 +158,7 @@ impl Registers {
             .filter(|(name, _)| !matches!(name, '*' | '+'))
             .map(|(name, values)| {
                 let preview = values
-                    .first()
+                    .last()
                     .and_then(|s| s.lines().next())
                     .unwrap_or("<empty>");
 
@@ -222,7 +230,7 @@ fn read_from_clipboard<'a>(
             let Some(values) = saved_values else { return RegisterValues::new(iter::once(contents.into())) };
 
             if contents_are_saved(values, &contents) {
-                RegisterValues::new(values.iter().map(Cow::from))
+                RegisterValues::new(values.iter().map(Cow::from).rev())
             } else {
                 RegisterValues::new(iter::once(contents.into()))
             }
@@ -243,7 +251,7 @@ fn read_from_clipboard<'a>(
 
 fn contents_are_saved(saved_values: &[String], mut contents: &str) -> bool {
     let line_ending = NATIVE_LINE_ENDING.as_str();
-    let mut values = saved_values.iter();
+    let mut values = saved_values.iter().rev();
 
     match values.next() {
         Some(first) if contents.starts_with(first) => {