DEV Community

Cover image for Five Git Config Settings Every Dev Needs
Nick Taylor
Nick Taylor Subscriber

Posted on • Originally published at nickyt.co

Five Git Config Settings Every Dev Needs

You've probably added some settings to your Git Configuration, but here are some you might not have configured. If you haven't set these up yet, you're doing more manual work than you need to.

Rebase on pull instead of merge

git config --global pull.rebase true
Enter fullscreen mode Exit fullscreen mode

Every time you pull without this, Git creates a merge commit. Do that a few times a day across a team and your git log turns into a mess of "Merge branch 'main' into main" entries that tell you nothing. With rebase, your commits stay on top of the latest changes and your history actually reads like a coherent timeline.

Bonus: I do this a lot, g pull -r origin main (g is my shell alias for git) to keep my branch up to date with main. You can also add

git config --global branch.main.rebase true
Enter fullscreen mode Exit fullscreen mode

and now I just do g pull origin main. Sure it's only two less characters, but one less thing for me to think about.

Auto set upstream on push

git config --global push.autoSetupRemote true
Enter fullscreen mode Exit fullscreen mode

You create a new branch, do your work, push, and Git hits you with this:

fatal: The current branch my-branch has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin my-branch

To have this happen automatically for branches without a tracking
upstream, see 'push.autoSetupRemote' in 'git help config'.
Enter fullscreen mode Exit fullscreen mode

Every single time. This setting makes that whole thing go away. Git sets the upstream automatically on your first push to a new branch.

Auto prune on fetch

git config --global fetch.prune true
Enter fullscreen mode Exit fullscreen mode

Stale remote branches pile up silently. Someone merged and deleted their branch weeks ago, but your local still shows it when you run git branch -r. This cleans out those dead references every time you fetch so your branch list reflects what actually exists on the remote.

I had this alias in my shell to prune local and remote branches.

rmmerged() {
  git branch --merged | grep -Ev "(\*|master|main)" | xargs -n 1 git branch -d && git remote prune origin
}
Enter fullscreen mode Exit fullscreen mode

Now, it's simplified to only pruning local branches since the fetch prune setting handles remote ones.

rmmerged() {
  git branch --merged | grep -Ev "(\*|master|main)" | xargs -n 1 git branch -d
}
Enter fullscreen mode Exit fullscreen mode

A better diff algorithm

git config --global diff.algorithm histogram
Enter fullscreen mode Exit fullscreen mode

The default diff algorithm works, but histogram produces cleaner diffs when there are lots of similarly structured lines, think repeated return statements, closing braces, or blank lines. The default algorithm can get confused about which identical lines to match and produces diffs that interleave additions and deletions in ways that are hard to follow. Histogram handles that better. The bigger the file and the more repetitive the structure, the more noticeable the improvement. It's a drop-in upgrade with no downside.

Here's a fictitious example since I had a hard time finding a good example in my own recent commits showing the difference.

Myers Algorithm (Default)

diff --git a/tmp/example_before.js b/tmp/example_after.js
index 30d9ab3c..8ec95ef5 100644
--- a/tmp/example_before.js
+++ b/tmp/example_after.js
@@ -8,15 +8,10 @@ function validateUser(user) {
    if (!user.name) {
      return { error: 'Name is required' };
    }
-  return { valid: true };
-}
-
-function processData(data) {
-  const result = transform(data);
-  if (!result) {
-    return { error: 'Transform failed' };
+  if (!user.id) {
+    return { error: 'ID is required' };
    }
-  return result;
+  return { valid: true };
  }

  function validateProduct(product) {
@@ -26,13 +21,28 @@ function validateProduct(product) {
    if (!product.price) {
      return { error: 'Price is required' };
    }
+  if (!product.name) {
+    return { error: 'Name is required' };
+  }
    return { valid: true };
  }

+function processData(data) {
+  const result = transform(data);
+  if (!result) {
+    return { error: 'Transform failed' };
+  }
+  return result;
+}
+
  function saveToDatabase(item) {
    const connection = getConnection();
    if (!connection) {
      return { error: 'Database connection failed' };
    }
+  const validated = validateItem(item);
+  if (!validated) {
+    return { error: 'Validation failed' };
+  }
    return connection.save(item);
  }
Enter fullscreen mode Exit fullscreen mode

Histogram Algorithm

diff --git a/tmp/example_before.js b/tmp/example_after.js
index 30d9ab3c..8ec95ef5 100644
--- a/tmp/example_before.js
+++ b/tmp/example_after.js
@@ -8,6 +8,22 @@ function validateUser(user) {
    if (!user.name) {
      return { error: 'Name is required' };
    }
+  if (!user.id) {
+    return { error: 'ID is required' };
+  }
+  return { valid: true };
+}
+
+function validateProduct(product) {
+  if (!product) {
+    return { error: 'Product is required' };
+  }
+  if (!product.price) {
+    return { error: 'Price is required' };
+  }
+  if (!product.name) {
+    return { error: 'Name is required' };
+  }
    return { valid: true };
  }

@@ -19,20 +35,14 @@ function processData(data) {
    return result;
  }

-function validateProduct(product) {
-  if (!product) {
-    return { error: 'Product is required' };
-  }
-  if (!product.price) {
-    return { error: 'Price is required' };
-  }
-  return { valid: true };
-}
-
  function saveToDatabase(item) {
    const connection = getConnection();
    if (!connection) {
      return { error: 'Database connection failed' };
    }
+  const validated = validateItem(item);
+  if (!validated) {
+    return { error: 'Validation failed' };
+  }
    return connection.save(item);
  }
Enter fullscreen mode Exit fullscreen mode

Rerere

git config --global rerere.enabled true
Enter fullscreen mode Exit fullscreen mode

Rerere stands for "reuse recorded resolution." When you resolve a merge conflict, Git remembers how you resolved it. The next time the same conflict comes up, Git applies your previous resolution automatically. If you've ever rebased a long-lived branch and had to resolve the same conflict over and over, this is the fix. It won't silently merge things for you in a way you can't review. It records your resolutions and replays them so you don't have to redo the same work.

Want to see what you currently have set? Run git config --global --list and see what's missing.

If you enjoy tips like this, I have a newsletter, OneTipAWeek.com. One developer tip a week. Short & valuable. That's it!

If you want to stay in touch, all my socials are on nickyt.online.

Until the next one!

Photo by Yancy Min on Unsplash

Top comments (24)

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

git config --global pull.rebase true

Couldn't agree more with this one. Mergig has its place in git, but when pulling commits before pushing everything, 99% of the time I just want to put my work on top of the existing work.

Collapse
 
nickytonline profile image
Nick Taylor

Stephen Colbert saying Awesome Sauce

Collapse
 
harsh2644 profile image
Harsh

Nick, I've been using Git for over a year and somehow never knew about pull.rebase = true until this post. 😅

Just updated my global config and — wow. Why did no one tell me this sooner? No more random merge commits cluttering my history.

This is why I still read DEV in 2026. Little productivity gems like this. 🙏

Collapse
 
nickytonline profile image
Nick Taylor

Thanks for giving it a read and glad you found it useful! Fun fact. I used to work at DEV!

Geordi Laforge in a sweater saying “No problem”

Collapse
 
nedcodes profile image
Ned C

push.autoSetupRemote is the one that changed my life. I can't believe I spent years typing --set-upstream on every new branch.

One I'd add: git config --global rerere.enabled true. It remembers how you resolved merge conflicts so if you hit the same conflict again (common during long-lived feature branches), Git just auto-resolves it. Saves a surprising amount of time during rebase-heavy workflows.

Collapse
 
nickytonline profile image
Nick Taylor

That one’s in there too at the end! Love rerere!

Collapse
 
nedcodes profile image
Ned C

ha, missed that! rerere is one of those features where once you start using it you can't go back. saved me so many times during long-running rebase sessions.

Collapse
 
trinhcuong-ast profile image
Kai Alder

The histogram diff algorithm is one I don't see talked about enough. Switched to it about 6 months ago and the diffs on larger files are noticeably cleaner — especially when you're moving functions around.

One more I'd throw in: git config --global init.defaultBranch main. Not a productivity thing exactly, but it saves you from that awkward moment when you push a new repo and realize it created a master branch that doesn't match your remote's default.

Collapse
 
nickytonline profile image
Nick Taylor

Thanks for giving it a read! Yeah, much cleaner diffs.

A kangaroo playing an electric guitar

Collapse
 
netnavi profile image
Ahmad Firdaus

wow this is very helpful, sometimes i need to take over some of my team git, the push auto upstream and pull reball help me alot thanks

Collapse
 
nickytonline profile image
Nick Taylor

BB-8 giving a thumbs up

Collapse
 
shitij_bhatnagar_b6d1be72 profile image
Shitij Bhatnagar

Hi, thanks very useful guide here.

Collapse
 
nickytonline profile image
Nick Taylor

Glad you found it helpful!

Hot Rod saying Cool beans!

Collapse
 
shitij_bhatnagar_b6d1be72 profile image
Shitij Bhatnagar

ya, though my personal preference is not to use use 'git config --global push.autoSetupRemote true' to avoid flooding remote repos with feature branches, but I do believe in frequent & meaningful, compilable commits to branches.

Thread Thread
 
nickytonline profile image
Nick Taylor

Kirk and Bones nodding to each other in Star Trek

Collapse
 
andypiper profile image
Andy Piper

Always learning new stuff from you, Nick! Nice tips here.

Collapse
 
nickytonline profile image
Nick Taylor

Thanks for giving it a read Andy! Hope all is well. 😎

BB-8 giving a thumbs up

Collapse
 
0xshubhamsingh profile image
Shubham Singh

useful!

Collapse
 
nickytonline profile image
Nick Taylor

Noice!

Noice!

Collapse
 
javz profile image
Julien Avezou

I painfully remember fixing the same conflict again and again after a big merge. Rerere could have saved me a lot of pain. Good to know!

Collapse
 
nickytonline profile image
Nick Taylor

The More You Know NBC TV campaign video capture

Collapse
 
gabitchov profile image
PASCUAL Gabriel

Awesome config. I didn't think that I could put the prune on fetch by default. Rebase is my life with git like the "squash on merge" for integrating on main branch. Thanks.

Collapse
 
nickytonline profile image
Nick Taylor

Thanks for reading Pascual and glad you found some new additions for your git config!

Captain America saluting

Some comments may only be visible to logged-in visitors. Sign in to view all comments.